If you have a massive Salesforce project that is in metadata format and tracked in git, you have a lot of valuable history in that project. You cannot merely do a bulk convert on that project to the new source format and lose complete access to that history. It is a little work, but it is possible to do the conversion and maintain your git history.

First, I’ll explain the reason this isn’t working. When you rename a file in git usually it is pretty good about detecting the changes. However, the problem arises when there is an enormous amount of changes at one time. Git has built in limits, and it will fail to figure out what renames occurred because there is too much going on.

The solution on the surface is simple. Do the convert in smaller chunks. However, there are a few caveats to be aware. Below I will walk through the steps used for converting an application (in this case dreamhouse in metadata form).

First, start with your project in metadata format. It would look something like the below structure with all of the code in metadata format in the ./metadata folder.

├── README.md
└─── metadata
    ├── objectTranslations
    ├── objects
    │   ├── Bot_Command__c.object
    │   └── ...
    ├── package.xml
    ├── pages
    ├── pathAssistants
    ├── permissionsets
    ├── quickActions
    ├── remoteSiteSettings
    ├── reports
    ├── staticresources
    │   ├── leaflet.resource
    │   ├── leaflet.resource-meta.xml
    │   └── ...
    ├── tabs
    ├── triggers
    └── workflows

The first thing to do is create a temporary SFDX project outside of the git repo.

$ sfdx force:project:create -n tempproj

Next, convert the project in metadata into the temporary project.

$ sfdx force:mdapi:convert --rootdir ./project/metadata --outputdir ./tempproj

After this runs you will have two copies of your application. One in the origional location and one in the new temproj directory.

The first thing to do is move over the sfdx-project.json file and config folder and commit them to the repo.

$ mv ./tempproj/sfdx-project.json ./project/sfdx-project.json
$ mv ./tempproj/confg ./project/config
$ git add -A
$ git commit -m "Created sfdx-project.json and config"

Next, create the new folder structure.

$ mkdir ./project/force-app
$ mkdir ./project/force-app/main
$ mkdir ./project/force-app/main/default

Now is when you can start converting to the metadata format. For most metadata types this is reasonably straightforward. If the type is just composed of one or two files (a source file and a metadata.xml file or just the single xml file) you can simply copy these over. For these types, you should be able to copy entire folders of the converted source to its new location, delete the old metadata, and do a git commit. Everything should be detected correctly. If it isn’t you may need to split the changes to be less than a whole folder - you may have too many files.

For example, moving Triggers would look like this.

$ mv ./tempproj/force-app/main/default/triggers ./project/force-app/main/default/triggers
$ rm -rf ./project/metadata/triggers
$ git add -A
$ git commit -m "Converted triggers to source format"

You repeat this process for every file/folder that contains the simple metadata format.

The tricky part comes when the new format of source uses what we call expanded source. Expanded source is when a single metadata item is split into multiple files. An example of this is Custom Objects. What I have found best, in this case, is to move the single -meta.xml file first, commit the change, then move the rest of the expanded files. Performing the move in these two steps will preserve the history with the -meta.xml file.

To do the convert with Custom Objects you would run the following.

$ mkdir ./project/force-app/main/default/objects
$ mkdir ./project/force-app/main/default/objects/MyObject__c
$ mv ./tempproj/force-app/main/default/objects/MyObject__c/MyObject__c.object-meta.xml /
$ rm ./project/metadata/objects/MyObject__c.object
$ git add -A
$ git commit -m "Converted MyObject to source format"

Next, copy over the other parts of the expanded source.

$ mv ./tempproj/force-app/main/default/objects/MyObject__c ./project/force-app/main/default/objects/MyObject__c
$ git add -A
$ git commit -m "Added MyObject expanded source files"

You should be able to repeat either of these two processes for everything in your project to maintain the source history after your move to the new source format.

Let me know if you run into any issues or have any suggestions: @ntotten.