Best Practices

How to Solve Merge Conflicts in Salesforce

Unlock solutions to Salesforce merge conflicts and code clobbering. Learn the root causes, practical examples, and effective ways to prevent these problems.

Last Update:
May 23, 2023
Published:
February 27, 2020

In this article, we'll demystify the common issues of merge conflicts and code clobbering that Salesforce teams often face, even when using Git. We'll explore the root causes, practical examples, and effective solutions to these problems, including a unique approach known as 'cherry picking' lines of metadata and code.

Here are our 5 key takeaways:

  • "Code clobbering" and "merge conflicts" are major challenges for Salesforce teams, which occur when different developers' changes to the same code conflict.
  • Source-driven development solutions, like Salesforce DX, aim to help manage merge conflicts, but they often fall short due to inherent issues with Salesforce's structure.
  • Git’s traditional merge conflict algorithm has difficulty handling Salesforce, leading to problems with merge conflict detection and resolution.
  • Cherry-picking specific lines of code based on the diff has emerged as an effective solution for avoiding code clobbering and merge conflicts in Salesforce.
  • Establishing an Integration environment where every developer is responsible for merging their changes is another effective approach to manage merge conflicts and code clobbering in Salesforce.

Table of Contents

Merge conflicts and code clobbering are one of the biggest challenges for Salesforce teams. Whether you’re using change sets, Ant scripts, Salesforce DX, or a commercial tool, there just aren’t many good ways to deal with “code clobbering”. Even if you’re using Git, you’re probably not properly catching merge conflicts (for reasons that we’ll explain in detail below).

One of the biggest promises of Salesforce DX is that using source driven development will help Salesforce teams work through merge conflicts and implement merging the way most software teams do.

What is “code clobbering”?

GitLab’s friendly merge conflict GUI.

Code clobbering is a simple, but devastatingly common occurrence for many Salesforce teams.

Let’s say Joe is working on an Apex class: classOne.cls. The class has 100 methods. Joe is only working on methodB(). Susie is also working on classOne.cls. But she is working on methodC() and methodD(). Code clobbering is when Joe pushes changes to classOne.cls that wipe out or “clobber” Susie’s changes. This happens a lot in Salesforce on all types of metadata: Apex classes, Objects, Fields, RecordTypes, etc.

To illustrate a bit further, classOne.cls on Joe’s sandbox does not include Susie’s addition of methodC() and methodD() because he hasn’t pulled her changes into his branch or org:

classOne.cls sitting in the Integration environment includes Susie’s changes:

Code clobbering is what would happen if Joe pushed his changes to Integration via a change set or Ant script. Susie’s changes would be lost and there would cascading effects.

What is a merge conflict in Salesforce? 

A merge conflict is what should happen in the above scenario if Joe and Susie were using Git in the traditional manner. Rather than letting Joe blindly overwrite Susie’s changes, Git would notify Joe that his changes were in conflict and suggest how he might be able to fix the conflict gracefully. Importantly, he’d be blocked from pushing his changes in a way that would overwrite Susie’s hard work. This prevents bugs and the need to rollback.

Unfortunately, many Salesforce admins and developers do not get this type of merge conflict warning because change sets and Ant scripts provide no merging mechanism - they blindly overwrite the target with whatever is in the source org. Git should help, but it’s notoriously difficult to use Git with Salesforce. And even if you are, you’ll find that merge conflicts are an extra special pain.

Why Git’s traditional merge conflict algorithm doesn’t work for Salesforce

Even the most sophisticated Salesforce development shops struggle with merge conflicts, even when they are using Git.

Here’s an example from a sales call this week (anonymized of course):

A javascript developer at Acme Inc. got excited about a project to bring CI/CD to the Salesforce team. So they created a Circle CI implementation with Ant scripts. The team uses a traditional Git flow to commit changes that they make in Salesforce into branches in a GitHub repo. They use pull requests to merge into upstream branches dedicated to UAT, staging or production. A nightly CI job picks up the changes from the branch and deploys it to the target environment that evening - a fairly typical CI setup.

But this setup isn’t catching merge conflicts and “code clobbering” in the way that they expected.

First, the team had to drop a lot of metadata from their Git repo because they couldn’t get declarative metadata to play nicely with Git. This left big holes in what Git could even warn them about when it did catch conflicts.

Second, though Acme’s developers understood the concept of branching, the admin and BA team found it confusing. Each time they created a branch, they would interrupt a developer to ask them for help.

Third (and biggest of all), the sandbox style of development so common to Salesforce teams doesn’t work well with Git flow. XML is notoriously difficult for Git to handle and all declarative metadata in Salesforce is XML.

Furthermore, cherrypicking is difficult in Git. When an admin or developer does successfully get changes into a branch, there are often many other changes that show up in the diff (environments are often wildly out of sync). This leads to false positives and a long list of potential conflicts and a very difficult pull request to merge.  An admin or developer has little ability to know what is okay to deploy and what isn’t.

(Note: these same conditions can occur if you’re using Salesforce DX instead of Ant scripts).

Initial attempts to address these gaps

At Blue Canvas, we solved the first two issues by tightly coupling orgs to branches in Git. We automatically commit changes to Git branches so that all metadata (including declarative) lives in the repo in real time. Now we had no more gaps in metadata, especially for declarative changes. We created a simple, Lightning Design System based GUI for creating pull requests and cherry picking files that allowed admins and BAs to avoid having to get too bogged down in branching strategies and worked with the traditional sandbox-based development strategy that most teams used.

But, we ran into a new problem: establishing a clear baseline for when to detect the merge conflict.

In most Salesforce orgs, there is seldom a common history between Git branches. Sandboxes are refreshed at various intervals creating massive differences between orgs. These massive differences led to two problems:

  1. Pull requests between branches would often have thousands of differences which led to many irrelevant false positives in the merge conflict stage
  1. It was difficult to establish a clear baseline from which to filter these into a smaller, more actionable list.


Seeing that this wasn’t going to work we went down a more experimental path, leveraging Darcs (a fairly academic source control tool that was initially a potential improvement over SVN alongside Git before Git emerged as the preferred choice of most developers). But Darcs was still very much an academic project and wasn’t performant enough for large Salesforce implementations.


Line by line editing in Blue Canvas UI.

Cherry picking lines of metadata and code

The answer to this challenge ended up being simple: allow admins and developers to cherry pick specific lines based on the diff.

Returning to our example with Joe and Susie, now Joe could safely select just the lines of methodB() while ignoring the other lines of classOne.cls - notably the deletion of methodC() and methodD(). Now Joe’s update can move upstream without jeopardizing Susie’s work.

Extending the cherry picking solution was the simplest, most performant and most effective solution for avoiding code clobbering and merge conflicts in the first place. We found it intuitively made sense to Salesforce developers.

We established an Integration environment (sandbox) and branch where every developer is responsible for merging their changes before they can be promoted to upstream environments. Each developer is expected to carefully select their specific changes and put them into the Integration branch. Release managers or other team members should always feel comfortable pushing from Integration upstream to UAT, staging, QA or production branches.

Ideal set up for solving merge conflicts in Salesforce

In summary, what we learned were that the following pieces needed to be in place in order to stop code clobbering and handle merge conflicts in a way that intuitively worked for Salesforce admins and developers.

  • Use automation to keep the sandbox/environment in as close to real-time sync with the branch as possible (tools: Ant scripts, Salesforce DX, CircleCI, Jenkins, TravisCI, Blue Canvas)
  • Track ALL metadata (or as much as you can)
  • Allow users to cherrypick files between branches rather than attempt to merge the whole branch (tools: Eclipse, Source Tree, Blue Canvas)
  • Allow users to cherrypick lines within each file to avoid code clobbering and merge conflicts (tools: Eclipse, Source Tree, Blue Canvas)

Setting up a system like this with Git and Salesforce allows me to safely deploy without causing massive cascading effects of clobbering the changes of my other colleagues. And having that safety allows me to move faster without breaking things, which is the point of CI/CD after all.

Blue Canvas: Your Partner in Resolving and Preventing Merge Conflicts

Our latest Merge Conflict Resolution functionality lets you tackle merge conflicts and code clobbering head-on, with tools designed for developers, by developers

Leverage our unique cherry-picking lines approach to keep your code clean and your team in sync. Start your journey with Blue Canvas today. You won't just resolve conflicts, you'll avoid them altogether!

--------

FAQs 

What are "code clobbering" and "merge conflicts"?

  • Code clobbering is when one developer's changes to a codebase overwrite or "clobber" another's. This can happen when different developers are working on the same sections of code. A merge conflict, on the other hand, occurs when Git is unable to automatically resolve differences in code between two commits.

Why do these issues occur in Salesforce, even when using Git?

  • The issues occur because Salesforce's development structure is different from that of a typical software project. Salesforce uses a lot of XML for declarative metadata which Git has trouble handling. This often leads to mismanagement of merge conflicts and consequently, code clobbering.

How do source-driven development solutions, like Salesforce DX, handle merge conflicts?

  • Salesforce DX aims to help manage merge conflicts by using a source-driven development approach. However, it often falls short due to the complex nature of Salesforce's structure and metadata, which makes traditional merge conflict detection and resolution challenging.

What is cherry-picking lines of code and metadata, and how does it help with merge conflicts and code clobbering?

  • Cherry-picking involves selecting specific changes from one branch and applying them to another without merging the entire branches. This can be particularly effective in managing merge conflicts and avoiding code clobbering, as developers can selectively pick and choose which parts of the code they want to merge, reducing the risk of overwriting someone else's code.

What is the ideal set up for solving merge conflicts in Salesforce?

  • The ideal setup involves every sandbox having a dedicated Git branch, with automated sync between the sandbox and branch. The use of Salesforce DX metadata directory format is recommended for breaking XML files into smaller components. The setup should also allow for tracking of all metadata and users to cherrypick both files between branches and lines within each file.

Why doesn't Git’s traditional merge conflict algorithm work well with Salesforce?

  • Git’s traditional merge conflict algorithm struggles with Salesforce because Salesforce uses a lot of XML for declarative metadata which Git has difficulty handling. Also, in Salesforce, sandboxes are often refreshed at various intervals creating significant differences between orgs, making it hard to establish a common history between Git branches.

How does Blue Canvas address these issues related to merge conflicts and code clobbering in Salesforce?

  • Blue Canvas tightly couples orgs to branches in Git, automatically committing changes to Git branches so that all metadata lives in the repo in real time. It has a simple UI for creating pull requests and cherry picking files. It also allows for line-by-line cherry picking, enabling users to select only their specific changes for merging, thereby avoiding code clobbering and merge conflicts.

What is an Integration environment in Salesforce and how does it help manage merge conflicts?

  • An Integration environment in Salesforce is a sandbox and branch where every developer is responsible for merging their changes before they can be promoted to upstream environments. This setup ensures that each developer takes responsibility for their changes and reduces the risk of code clobbering and merge conflicts.

What limitations or challenges can be encountered while using traditional Git flow with Salesforce?

  • Using a traditional Git flow with Salesforce can lead to difficulties in handling declarative metadata due to its XML nature. It can also create confusion among developers not familiar with the concept of branching. Furthermore, the sandbox style of development commonly used in Salesforce does not align well with Git flow.

How can one avoid false positives and difficult pull requests while using Git with Salesforce?

  • One can avoid false positives and difficult pull requests by using cherry picking to select specific changes for merging, rather than attempting to merge entire branches. This ensures only the relevant changes are included, thereby reducing the likelihood of false positives.

More like this