Best Practices

5 Lessons Learned in 5 Years with Salesforce and Git

What we've learned going deeper with Salesforce and Git than we ever imagined.

Last Update:
Published:
February 11, 2021

Table of Contents

Five years into our journey with Salesforce and Git, we have learned a ton about both technologies. Our initial vision was that by bringing the Git protocol to more Salesforce teams we could help them solve a lot of the challenges we had seen working with Salesforce ourselves. Tools like Ant and change sets are useful, but didn't seem to reflect the full breadth of change in the developer ecosystem over the past decade.

https://tiffanystone.files.wordpress.com/2014/05/devops-market-map-tiffany-stone.jpg
Credit: Tiffany Stone: https://tiffanydstone.com/2014/05/23/devops-market-map/

In our experience Git was the perfect tool for solving so many of the frustrations we had with Salesforce. (For example, Git is amazing at handling merging in large, complex codebases.) Ultimately, a source driven approach to development would allow Salesforce teams to release faster while maintaining the confidence that their code has been tested, reviewed and can be rolled back in the absolute worst case.

But getting Salesforce to play nicely with Git was no walk in the park! Presumably if it was, more teams would have done it. If you're considering taking the plunge and moving your Salesforce team to a more Git oriented approach, here are a few things that we learned that you might want to look out for.

One does not simply implement Git and Salesforce

1. Adventures in XML re-ordering and Salesforce

The first thing we built in 2016 was a simple connector that would keep a Git branch in sync with a Salesforce environment, allowing a reference branch to be instantiated for each sandbox and production environment in an ORG. This simple connector was a surprising hit and resonated with developers who had heretofore been backing up their sandboxes in an ad-hoc and manual way. (Basically if you remembered to fire off an Ant script before you left on Friday you had a copy of everything, otherwise you didn't.)

While building this reference branch connector, we noticed that the XML files Salesforce was returning to us were a bit, shall we say, unwieldy. We noticed a strange behavior that we called "flapping". Flapping occurred whenever the Salesforce metadata API would offer inconsistent results. One minute it would say that a recordType had been deleted, the next, it would claim that it was re-added. No user was actually making those changes but they would show up in diffs at in opportune times.

When we launched the ability to deploy to Salesforce with CI/CD in 2017, we noticed an even more nefarious issue: the ordering of objects in an XML file was not consistent across environments. Often, two environments would have identical functionality on a given metadata component, but Git flagged a diff because the ordering of the XML was different. This created messy diffs that were confusing to developers.

We had to fix this by customizing an XML diff tool to handle these types of reordering. It was a pain, but we are now able to correctly identify diffs from the end user or admins perspective - even if the underlying XML structure is not the same.

2. Merging in an org driven world

Possibly the most difficult challenge associated with using Git and Salesforce was solving merge conflicts. In a typical development environment, all changes are source driven and done with feature branches. But as we observed Salesforce admins (and many developers) we noticed that despite their best efforts to work in a source driven way, they would often treat their sandbox as an IDE - preferring to make changes to an Object directly in the org rather than through something like VS Code. (And who can blame them? This is precisely the value of a clicks not code development platform like Salesforce!)

However, this reality meant that orgs were frequently out of sync with the Git repo. Thus, Git's traditional merge algorithm was turning up a lot of false positives and false negatives for us. (We'll do a whole write up someday on how we solved this).

We didn't want to make admins work in an inconvenient way, but we did want to leverage Git to reduce the number of conflicts. After many iterations, we stumbled upon an elegant solution: use Git hunks.

By establishing two reference branches that were kept continuously in sync with each environment, we could always ensure that we had accurate branches to compare. We could then allow users to compare and cherrypick the files that they wanted to include in their deployment branch. Then we were able to layer in the ability to cherry pick "Git hunks" that are present in each diff. This allowed users to select from within a given file without overwriting other parts of the file that they may not have yet merged into their own branch. Now a developer could merge his update to a method on an Apex class without worrying about clobbering other changes to that same class.

Merging using Git hunks and Salesforce.
Merging using Git hunks in Blue Canvas.

This simple and elegant solution allowed our users to eliminate merge conflicts on important files without having to add a lot of additional overhead and training around Git branching.

3. A rational format for XML makes a world of difference

Prior to Salesforce DX, all custom objects and object translations were stored in a single, messy XML file. This made merging nearly impossible and a source of major frustration for all devs leveraging the Ant deployment tool. Updating a single field or record type required great care and attention to detail or would result in unexpected deletions and removals within an object.

With DX, objects and object translations now exist in a new "source shape" that breaks these larger objects into smaller chunks called the Salesforce DX source format. Each object and object translation now has subdirectories that are more rational. Each field now lives in a `fields/` subdirectory. RecordTypes live in `recordTypes/` and so on.

rational subdirectories in the DX source format.
Rational subdirectories in the new DX source format.

Converting to this format takes some doing, particularly for legacy orgs. But we believe it is worth it! The new format makes merging much less cumbersome and allows your team to work on different parts of the same Object without clobbering each other. Git can be helpful in managing conflicts too, but if you're not using the most modern directory format, you're only getting a fraction of Git's efficacy in doing so. We automatically convert all of our customers to the Salesforce DX source format and we recommend that all Salesforce teams do the same. The long term payoffs are immense.

4. Comparisons in Git are really really fast

Comparing environments is a pain in Salesforce. Using Ant scripts or the metadata API can be quite slow and painful depending on how Salesforce is feeling at that moment. For some teams, it can frequently take 5-10 minutes to compare two environments (and sometimes as much as 20 or 30 when Salesforce is feeling overwhelmed). We were pleasantly surprised to learn that one of Git's great strengths is fast and performant diffing - even when the diff is massive.

At Blue Canvas we manage over 100 million lines of Salesforce code and metadata and we find that the average comparison can be done in about 10 seconds. These are full org comparisons, not targeted selections mind you. Moving to Git will vastly increase the speed of your developer team. Shaving off 5-10 minutes every time you want to merge something can save hours a week for each of your admins and developers.

5. Pull requests and team culture

Git is fundamentally a collaboration tool. It's designed to allow different developers to merge their code into a shared code base safely. One of the most popular idioms in Git is the "pull request" - emphasis on "request". When we got started with Git we were thinking of all the ways it could help us as individual developers. What we learned though was just how much of an effect it had on team culture.

When deploying with change sets or Ant scripts, you can see what files are being deployed and little else. Maybe you pick through the package.xml a bit for some more context. But Git provides a much richer experience for teamwork. With pull requests you can see diffs and comment directly on code. This visibility encourages more people to comment which creates a literal feedback loop in which everyone on the team is commenting and sharing their knowledge as part of your release process.

We find that teams that use code reviews with Salesforce regularly see a major decrease in production issues - largely because they have more eyes on each release. We also find that code reviews and approvals make teams less susceptible to information silos and dangerous bus factors.

Is Git overkill for a Salesforce team?

We are often asked, "Is Git overkill for most Salesforce teams? Do I really need to invest and train my Salesforce admins and BAs to use the command line and the Git protocol?" It's definitely an investment. But it doesn't have to be impossibly daunting. There are tools that allow you to interact with Git through GUIs rather than the command line (e.g. SourceTree, GitHub Desktop, Blue Canvas).

Git allows you to move faster without breaking things. Speedy comparisons, rollback capabilities, and code reviews allow teams to move faster than ever before and feel confident that they will hit their deadlines for their business stakeholders.

We expect that more and more teams will appreciate this reality as Salesforce becomes more of a hub for low-code development. An investment in developer tooling will be necessary as more teams build more incredible solutions using Salesforce.

More like this