Diving into what it takes to smoothly merge work across Salesforce orgs
This blog post is #2 in our series of Git+Salesforce blog posts. If you haven’t read our previous release, check-out why Salesforce DevOps is more than just hooking up a git repo to a Salesforce org .
Overwriting a colleague’s work is the last thing you want to happen when deploying on Salesforce. Yet the reality so far is that with Change Sets alone and even with most Salesforce DevOps tools, you’re still very much exposed to that risk. While integrating Git with Salesforce is a step in the right direction, it takes more than that to truly avoid such pitfalls. Merging is key, and it’s a tough problem. So let’s dive into concrete examples of what merging can look like in Salesforce environments, and highlight what it really takes to solve this.
Git merging comes into action whenever one file is changed from multiple sources (or git branches). We’ll talk Salesforce metadata later on, and for now let’s start with a simple scenario: Apex code, which Charlie and Elliot are separately working on.
The code below is from Trailhead’s dreamhouse app. SlackOpportunityPublisher.cls sends a heads-up about modified opportunities on a Slack channel. On their sandbox, Charlie is adding a feature to that class (adding the new stage of the modified opportunity):
Elliot is also working on that class. They’re editing it directly on UAT to clarify something ambiguous in the Slack notification (it only tells about the first opportunity modified, while there may be more):
Because Elliot has directly changed UAT, Charlie is now lagging behind. They, and their sandbox, are not aware of that modification. Whenever Charlie would deploy their code to UAT, Elliot’s change might get silently overwritten. That is, unless some kind of Merge Conflict Detection would be in place in both Charlie’s and Elliot’s tooling.
Now it’s easy to think of conflicting changes on the same line as being the one obvious thing to catch (spoiler: it’s not that simple, without the notion of a ‘common ancestor’). But before we address that, let’s consider a slightly different scenario.
Changing a single line is one thing, but day-to-day scenarios would usually involve changes across different files or across multiple lines of the same file. Considering this from a Salesforce deployment perspective:
Change Sets fall short on any of those questions. They’d blindly deploy the whole file without any such consideration. We can illustrate this by going back to SlackOpportunityPublisher.cls:
In a traditional Salesforce deployment, the sequence of events would go like:
This is why merging is so essential to teams working together. And why we believe detecting merge conflicts is a must for any DevOps tooling to strive in the Salesforce ecosystem. But now think of it from a tooling perspective:
Not only does answering these questions require precise Git versioning (see our previous post on the topic), it also means diligently tracking the relationship between each orgs. In git terminology this is known as tracking the ‘common ancestor’ (think of branches forking and re-uniting):
As an example, here is what Blue Canvas invites the user to do in such a case:
There are actually multiple bits of information in that screenshot:
Specifics aside, what’s important here is that developers gain power and control 💪 Clear awareness that the end result is not going to look exactly like what they have worked on (because the changes occurred on the destination org too), clear control into the next steps (instead of blind deployments and risks of erasing other work). And it’s not just about Apex code, Salesforce admins deserve that same power and control when they work on Salesforce Metadata. Let’s see an example of that.
With Salesforce’s low-code approach, it might seem harder to grasp what a merge conflict can look like in real life. But actually the same concept applies, and suffice to look at the underlying data representation.
Code below is from the Nebula Logger app (a generic logger for Salesforce), which exposes a field called ‘Environment Type’ (Picklist Field). In their sandbox, Charlie adds a new possible value (‘UAT’) to that field. Under the hood, the change actually live in an XML file:
On their end, Elliot is also working on adding another Environment Type , called ‘Pre-production’:
With the underlying data structure revealed, we can now explicitly see how this is going to lead to a merge conflict as well. Which new picklist value is the right one? Or should they both be added? Should they be the same (with one agreed-upon name)? All open questions that the team has to figure out. And for that, it at least needs to be aware of that underlying conflict.
Ultimately the reasoning is now the same as for Apex examples above: diligent source tracking and awareness of common ancestors is what it takes to merge Salesforce sandboxes into one common org. Now you’d probably love to have that fully automated, but let’s think about that twice actually.
Looking back at the examples, it’s tempting to hope for magical solutions that would automatically detect and resolve any potential harm. At Blue Canvas we know that there is no such silver bullet. Think of the key takeaways from each of the previous examples:
More fundamentally, if just like us you are a firm believer in Git, you can simply refer to git-merge’s documentation itself:
After seeing a conflict, you can do two things. [1] Decide not to merge. [2] Resolve the conflicts. Git will mark the conflicts in the working tree. Edit the files into shape and git add them to the index
This means the ball is in your court to solve any conflict(s). Git is there to detect them and eventually handle any obvious scenario (e.g. changes in different files). But anytime there’s no de-facto solution, the developer’s in charge.
Our team’s mission is to offer awesome git-fueled Salesforce Deployers, and we are very much aware that this means going after the merge conflict problem. Our community of users and customers have also clearly shown their strong interest in getting help with this. This is why we are writing this series of Salesforce+Git blog posts, so we can all first share a common definition of the problem we are solving. And at the same time, our engineers are baking awesome features to help with this!
As illustrated by some of the screenshots in this post, we are currently rolling out our first version of Merge Conflict Detection. It’s available in public beta already and is gradually being rolled out to all existing accounts. We believe this functionality will be another game changer and we are eager to receive more feedback. And check-in for our next blog post, with a comprehensive walkthrough of the feature.