Are you an LLM? You can read better optimized documentation at /docs/devops/merge-conflicts.md for this page in Markdown format
Merge conflicts
When you use OrgFlow to flow metadata changes between Salesforce environments, you are fundamentally using Git's merge capabilities under the hood. This means that merge conflicts — a normal and well-understood part of any version control workflow — can and do occur. This topic explains what merge conflicts are, when they happen in OrgFlow, and how to resolve them.
What are merge conflicts?
A merge conflict occurs when Git attempts to combine changes from two different sources and finds that the same lines in the same file have been modified in different, incompatible ways. In such cases Git cannot automatically determine which version is correct, so it raises a conflict and asks a human to decide.
In a typical software development workflow, merge conflicts arise when two developers change the same lines of the same file in two different branches, and someone then tries to merge those branches together. Only overlapping changes produce conflicts — if two developers change different lines of the same file, or change different files entirely, Git merges those changes automatically without any conflict.
Merge conflicts in Salesforce DevOps
In Salesforce DevOps, merge conflicts arise from the same underlying cause, but the changes are not always introduced by developers committing code changes in the traditional sense. Instead, changes can come from a multitude of sources:
- Admins configuring metadata directly in production or in a sandbox
- Developers writing Apex, Lightning components or other code in a sandbox
- Automated tools or managed packages updating metadata in an org
- Commits pushed directly to a Git branch
When two such sources of change modify the same lines of the same metadata component, and those changes are merged together — whether during a flow in, a flow merge, or an external Git merge — a merge conflict occurs.
Because Salesforce metadata is stored as XML, merge conflicts in Salesforce metadata look a bit different from conflicts in typical programming languages. A conflict might involve two environments having changed the <description> and <label> elements of the same custom field, or two environments having added different fields to the same field set.
Merge conflicts are a good thing
It might seem counterintuitive, but merge conflicts are actually a good thing. Every merge conflict represents a situation where two different changes to the same lines would have otherwise silently overwritten each other. Without conflict detection, one side's change would simply be lost — this is known as clobbering.
Every conflict is an avoided clobber. Instead of silently discarding one side's work, Git raises a flag and asks you to decide which version to keep — or whether to combine them in a way that preserves intent from both sides. This is fundamentally safer than any workflow that copies metadata from one org to another without considering what has changed on both sides.
In Salesforce DevOps, where multiple people and automated processes can make changes across multiple orgs at any time, this safety net is especially valuable. Teams that embrace merge conflicts rather than fear them tend to achieve more reliable and predictable releases.
Minimizing unnecessary merge conflicts
While merge conflicts themselves are a safety feature, nobody wants to deal with more of them than necessary. Here are some strategies to minimize unnecessary or avoidable merge conflicts:
Keep sandboxes short-lived and focused
The longer a sandbox lives, the more it drifts from production and other environments. The further environments drift apart, the higher the chance of overlapping changes and resulting conflicts. Keep sandboxes focused on a single feature or user story, and delete them once they've been merged downstream. See the sandbox environment recommendations for more guidance.
Back-promote changes regularly
Regularly back-promoting changes from production (or other downstream environments) into upstream sandboxes keeps environments aligned and reduces drift. OrgFlow makes this easy with scheduled upstream merges. The more frequently you back-promote, the smaller each merge will be, and the less likely you are to encounter conflicts.
Be selective with included metadata
Including only the metadata you need in your stack reduces the surface area for conflicts. Metadata types that change frequently but are not part of your development workflow (such as dashboards, reports or certain administrative settings) can be a source of unnecessary conflicts if included.
Keep element ordering deterministic
OrgFlow's metadata normalization sorts XML elements into a deterministic order before committing them to Git. This prevents "phantom" conflicts caused by Salesforce returning the same metadata with elements in a different order on different retrieves.
Merge frequently and in smaller batches
The smaller the delta between two branches, the less likely a conflict is. Flowing changes frequently (e.g. nightly retrieves plus regular merges) is far less conflict-prone than infrequent large bulk merges.
When do merge conflicts occur?
Merge conflicts can occur during two types of OrgFlow operations:
During flow in
A flow in retrieves metadata from a Salesforce org and commits it to a Git branch. If the Git branch has advanced since the last flow in (for example because a merge from another environment added new commits to it), the incoming metadata changes from the org need to be merged with the existing changes in the branch. If both sides changed the same lines of the same component, a merge conflict occurs.
This scenario is common when you back-promote changes into a sandbox environment's branch and then flow in the sandbox's metadata on top of those changes.
During flow merge
A flow merge merges changes from a source environment into a target environment. The merge step in this process merges the source environment's Git branch into the target environment's Git branch. If both branches contain changes to overlapping lines in the same components, a merge conflict occurs.
This is the most typical scenario for merge conflicts and is analogous to merging two feature branches in traditional software development.
Flow merge involves multiple merges
A flow merge actually involves up to three merge points: the source flow in, the target flow in and the branch merge itself. Merge conflicts can occur at any of these points. OrgFlow lets you configure how to handle conflicts at each point independently.
Preserving conflict resolution work in large merges
When a flow merge involves many conflicted files that require manual resolution, it can be frustrating if the subsequent target flow out (deployment) phase fails — because the merge result has not yet been committed and pushed, meaning all your conflict resolution work could be lost if the job fails.
To mitigate this, consider running the flow merge with the "no target flow out" option. This way, the merge result is committed and pushed to the target branch first, without attempting to deploy. You can then run a separate flow out job to deploy the merged changes, and iterate on any deployment issues without risking loss of your conflict resolutions.
Understanding local and remote
When a merge conflict occurs, the two sides of the conflict are referred to as local and remote:
| Context | Local | Remote |
|---|---|---|
| Flow in | The environment's Git branch | The Salesforce org |
| Flow merge (branch merge) | The target environment | The source environment |
| Flow merge (source flow in) | The source environment's Git branch | The source Salesforce org |
| Flow merge (target flow in) | The target environment's Git branch | The target Salesforce org |
Understanding which side is "local" and which is "remote" is important when choosing a resolution strategy, because the resolution options are expressed in terms of these sides.
Merge conflict options
Both flow in and flow merge jobs provide options for controlling how merge conflicts are handled. These options determine what happens when conflicts are detected during the job.
Conflict strategy
The merge conflicts option controls the overall behavior when conflicts are detected:
| Strategy | Description |
|---|---|
| Resolve interactively | Pause the job and wait for a user to resolve the conflicted files (typically using our web-based conflict editor). |
| Prefer local | Automatically resolve all conflicts by preferring the local side's changes in conflicted sections, while keeping non-conflicted changes from both sides |
| Prefer remote | Automatically resolve all conflicts by preferring the remote side's changes in conflicted sections, while keeping non-conflicted changes from both sides |
| Take local files | Automatically resolve all conflicts by taking the entire local version of each conflicted file, discarding all remote changes (including non-conflicted ones) |
| Take remote files | Automatically resolve all conflicts by taking the entire remote version of each conflicted file, discarding all local changes (including non-conflicted ones) |
| Abort | Cancel the operation if any merge conflicts are encountered |
"Resolve interactively" is the default, and is the recommended option for most scenarios. It pauses the job and gives you time to examine each conflict and make an informed decision.
The "prefer" strategies are a good middle ground — they let non-conflicted changes from both sides through, and only apply the preference where actual conflicts exist. The "take file" strategies are more aggressive and discard all changes from the other side for any conflicted file.
Prefer vs. take
The distinction between "prefer" and "take" is important. Prefer local resolves only the conflicted sections in favor of the local side, while keeping non-conflicted changes from both sides intact. Take local file takes the entire local version of the file, which means non-conflicted changes made on the remote side are also discarded. Use "prefer" when you want to keep as many changes as possible; use "take" when you want a clean one-sided result.
Semantic merge
The use semantic merge option enables metadata-aware merge logic that can automatically resolve certain types of conflicts that occur specifically because of how Salesforce structures its metadata.
Currently, semantic merge handles approval process ordering conflicts. When multiple approval processes on the same object have their processOrder values changed in both environments, Git detects a conflict because the same lines were changed on both sides. However, because OrgFlow understands the semantics of this metadata, it knows that the remote order values are always authoritative, and can resolve the conflict automatically.
With semantic merge enabled (the default), such conflicts are resolved automatically without user intervention. With semantic merge disabled, they are handled like any other conflict according to the selected conflict strategy.
Flow merge has multiple conflict settings
Because a flow merge job involves up to three merge points, you can configure the conflict strategy and semantic merge settings independently for each:
| Setting | Applies to |
|---|---|
| Merge conflicts | The branch merge between source and target |
| Source flow in conflicts | The source environment's flow in (if included) |
| Target flow in conflicts | The target environment's flow in (if included) |
This gives you fine-grained control. For example, you might use "resolve interactively" for the main branch merge, but "prefer remote" for the source and target flow in steps, because conflicts during flow in tend to be less contentious.
Resolving conflicts in OrgFlow Web
When a managed worker job detects merge conflicts and the conflict strategy is set to "resolve interactively", the job pauses and creates an inquiry. The inquiry appears on the job timeline in the web app, and any user with sufficient permissions can respond to it. An email notification is also sent to the user who started the job after 10 minutes without a response.
Opening the conflict resolution page
Click the link in the merge conflict inquiry on the job timeline to open the conflict resolution page. This page shows:
- A flow diagram indicating the local and remote sides (showing environment names or branch/org names depending on the context)
- A progress bar showing how many of the conflicted files have been resolved
- A table listing all conflicted files, including their file paths and the type of conflict (e.g. modified in both, deleted in one and modified in the other)
Resolving files
Each conflicted file must have a resolution before you can continue the job. You can resolve files using the resolution buttons in the table, either individually for each file or in bulk for multiple selected files:
| Button | Resolution | Description |
|---|---|---|
| << | Take local | Take the entire local version of the file |
| < | Prefer local | Merge changes from both sides, preferring local where lines conflict |
| > | Prefer remote | Merge changes from both sides, preferring remote where lines conflict |
| >> | Take remote | Take the entire remote version of the file |
For files where you need more control, you can expand a file to open the merge editor. The merge editor shows the conflicted file with syntax highlighting and displays the differences between versions. You can review the conflict markers, make manual edits to produce the desired result, and save your changes. This is equivalent to the "manual" resolution and gives you full control over the final content of the file.
Bulk operations
You can select multiple files using the checkboxes in the file list and then apply a resolution to all selected files at once using the bulk resolution buttons in the toolbar. This is useful when you have many conflicted files that should all be resolved the same way.
Filtering and searching
The conflict resolution page supports filtering by file path and a "hide resolved" toggle that hides files that have already been resolved, so you can focus on the files that still need attention.
Resetting resolutions
If you change your mind about a resolution, you can use the reset button to undo a resolution and return the file to its unresolved state. You can reset individual files or all files at once.
Continuing or aborting
Once all files have been resolved, the Continue button becomes active. Clicking it submits your resolutions and allows the job to proceed with the resolved files.
If you decide that the merge should not proceed, you can click Abort to cancel the operation. The job will end without applying any of the merged changes.
Inquiry timeout
If no user responds to a merge conflict inquiry within 4 hours, the inquiry times out and the job fails (this timeout is a cost control measure and can be configured in your workspace billing settings).
Resolving conflicts in OrgFlow CLI
When the CLI detects merge conflicts during a flow operation and the conflict strategy is set to "prompt" (the default), it pauses execution and presents an interactive prompt with several resolution options.
Interactive prompt
The CLI displays the list of conflicted files along with the type of conflict for each file, then asks how you want to resolve them:
- Run git-mergetool — launches whatever merge tool you have configured in your local Git installation (e.g. VS Code, Beyond Compare, Meld, etc.)
- Open repository directory — opens the working directory in your file explorer so you can resolve conflicts using your preferred tools
- Prefer local changes — resolves all conflicts by preferring the local side where lines conflict, keeping non-conflicted changes from both sides
- Prefer remote changes — resolves all conflicts by preferring the remote side where lines conflict, keeping non-conflicted changes from both sides
- Take entire local files — resolves all conflicts by taking the complete local version of each conflicted file
- Take entire remote files — resolves all conflicts by taking the complete remote version of each conflicted file
- Let me choose for each file — prompts individually for each conflicted file
- Retry — re-checks for conflicts (useful after resolving conflicts externally with git-mergetool or another tool)
- Abort — aborts the operation
Options 1 and 2 give you access to the full repository working directory while the CLI waits, so you can use any Git-compatible merge tool to resolve the conflicts, then select "Retry" to let the CLI re-check whether all conflicts have been resolved.
Per-file resolution
If you select "Let me choose for each file", the CLI prompts for each conflicted file individually, offering the resolution options that are applicable to that file's conflict type. For example, "prefer" options are not offered for files where one side has been deleted, since there are no line-level sections to prefer — only "take" options are applicable in that case.
Pre-selecting a strategy
Instead of being prompted interactively, you can pre-select a conflict strategy using CLI arguments. This is especially useful in CI/CD pipelines and scripts where interactive prompting is not possible.
For env:flowin:
orgflow env:flowin --conflicts=<strategy>For env:flowmerge:
orgflow env:flowmerge --conflicts=<strategy> --sourceInConflicts=<strategy> --targetInConflicts=<strategy>Available strategy values: Prompt, PreferLocal, PreferRemote, TakeLocalFile, TakeRemoteFile, AskForEach, GitMergetool, Abort.
When running in a non-interactive context (e.g. in a CI/CD pipeline where standard input is redirected), the CLI automatically falls back to "abort" if the strategy is set to "prompt", because prompting is not possible.
Semantic merge in the CLI
The --semanticMerge argument controls the semantic merge behavior. Available values are Auto (prompt if possible, otherwise apply), Prompt (always prompt), ApplyAll (always apply) and SkipAll (never apply semantic merge). For flow merge, you can also use --sourceInSemanticMerge and --targetInSemanticMerge to control semantic merge for the source and target flow in steps independently.
Handling merge conflicts outside of OrgFlow
Because OrgFlow uses standard Git repositories, you are not limited to resolving merge conflicts within OrgFlow itself. You can also merge branches and resolve conflicts using:
- Your Git provider's web UI (e.g. GitHub, GitLab, Azure Repos) — most providers offer a browser-based conflict resolution experience as part of their pull request workflow
- Desktop Git clients (e.g. VS Code, GitKraken, Sourcetree, Fork) — most desktop clients include visual merge conflict resolution tools
- Command-line Git — using
git merge,git mergetooland manual editing of conflict markers - Dedicated merge tools (e.g. Beyond Compare, Meld, KDiff3) — specialized tools designed for comparing and merging files
When resolving conflicts outside of OrgFlow, you merge the branches and push the result to your remote repository. Then, the next time you run a flow operation in OrgFlow, it will pick up from where the branches are, including any merged commits. This can be a viable workflow especially for teams that are already familiar with Git-based merge conflict resolution.
However, be aware that when you merge outside of OrgFlow, some OrgFlow features that help prevent and resolve conflicts are not available:
- Semantic merge does not apply. Conflicts that OrgFlow would have resolved automatically (such as approval process ordering conflicts) will need to be resolved manually.
- Post-resolution normalization does not apply. When OrgFlow resolves conflicts, it normalizes the resulting metadata (sorting XML elements into a deterministic order, stripping insignificant whitespace, etc.) before committing. When you merge outside of OrgFlow, the committed result may contain denormalized XML, which can lead to noisy diffs and an increased risk of future "phantom" conflicts. The metadata will be re-normalized the next time an OrgFlow flow in is run on the environment, but until then the denormalized state will be present in the branch.
Check-only flow merge
If you want to discover potential merge conflicts before committing to the merge, run a check-only flow merge. This performs a dry run that detects conflicts and other issues without actually changing the state of any environment, branch or org.