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:
Enable XML-based merge
XML-based merge is an alternative merge driver provided by OrgFlow, that understands the element structure of metadata files and merges them as XML elements rather than as lines of text. Independent changes to different elements can be merged automatically instead of conflicting. The result is significantly fewer unnecessary merge conflicts, and cleaner, easier-to-resolve conflicts when they do occur.
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 and merge driver.
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.
XML-based merge
Most Salesforce metadata is stored as XML, but Git's built-in merge is purely text-based: it compares files line by line and has no understanding of XML structure. XML-based merge is an alternative merge driver provided by OrgFlow, that understands the element structure of metadata files and merges them as XML elements rather than as lines of text. The result is significantly fewer unnecessary merge conflicts, and cleaner, easier-to-resolve conflicts when they do occur.
Experimental feature
XML-based merge is currently an experimental feature. It is disabled by default and can be enabled per stack or per job as described below. Its behavior and defaults may change as the feature matures.
Why XML-based merge?
Text-based merge works well for source code and other unstructured text files, where a line is a meaningful unit of change. It works less well for XML files such as Salesforce metadata files, for a few reasons:
- Unrelated changes collide. When two sources change different parts of the same component, the two changes often touch lines that are close together, or insert new content at the same point in the file. Git simply sees overlapping or adjacent line ranges and raises a conflict, even though the two changes are semantically independent and could be combined safely.
- Conflicts are presented as line-based fragments. When Git does raise a conflict, the resulting conflict regions start and end on arbitrary lines, frequently spanning across XML element boundaries such that the conflict region contains only parts of one or more XML elements. The conflict region is hard to read, and the surrounding XML looks malformed, which makes resolution difficult and error-prone.
- Order and formatting sensitivity. Git's line alignment can pair up unrelated elements simply because they sit at the same line offset, and reformatting (such as an indentation change) can turn an otherwise trivial merge into a noisy one.
OrgFlow already mitigates some of this with metadata normalization, which sorts elements into a deterministic order so that insignificant reordering does not cause "phantom" conflicts. XML-based merge complements normalization by making the merge itself structure-aware.
This provides several benefits:
- Significantly fewer conflicts — independent changes to different elements can be merged automatically instead of conflicting.
- Cleaner conflicts — when a real conflict does occur, the conflict region is aligned to XML element boundaries, so that each side of the conflict is a complete, readable element rather than an arbitrary run of lines. This makes the conflict much easier to read and understand.
- Easier resolution — because conflict regions align with complete XML elements, picking one side or both becomes a single-click operation that doesn't require subsequent manual editing to restore the XML structure.
- More granular conflicts — several adjacent conflicting elements are presented as separate conflict regions, preserving your ability to resolve those elements differently.
- Well-formed output — automatically merged (non-conflicting) changes always result in structurally valid and consistently formatted XML, whereas line-based merge can sometimes produce structurally invalid XML.
Enabling XML-based merge
XML-based merge can be turned on as the default for a stack, and overridden for individual jobs.
To enable XML-based merge at the stack level, in the web app, open Stack settings and switch on XML-based merge. When enabled, new flow in and flow merge jobs in that stack use XML-based merge by default.
You can still override this default on individual jobs or schedules; both flow in and flow merge jobs expose a Use XML-based merge option that overrides the stack default for that job. In the web app, check or uncheck Use XML-based merge when starting or scheduling the job. If left at its default, the option follows the stack-level setting. In the CLI, you can use the --xmlMerge argument on the env:flowin or env:flowmerge commands.
For a flow merge, the setting applies to all merge points of the job (the merge between environment branches as well as the source and target flow in steps).
Conflict strategy and semantic merge still apply
XML-based merge changes which differences cause conflicts and how those conflicts are positioned across the lines of the file. It does not change the conflict strategy options or the resolution workflow. A genuine element-level conflict is still surfaced through the normal interactive resolution flow (or resolved according to your chosen prefer/take strategy), and semantic merge still applies on top.
How XML-based merge differs from text-based merge
XML-based merge aligns and merges at the XML element level. Inserts, deletes and modifications are identified as whole elements, and conflict markers always fall on element boundaries. The sections below describe some example situations where this produces a different result than Git's built-in text-based merge.
In all of the examples below, assume the common ancestor (or base version) of a CustomObject looks like this:
xml
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Account</fullName>
<fields>
<fullName>Status__c</fullName>
<label>Status</label>
<type>Text</type>
</fields>
<fields>
<fullName>Industry__c</fullName>
<label>Industry</label>
<type>Text</type>
</fields>
</CustomObject>Conflicts avoided by XML-based merge
One side changes an element, the other adds one in the same location. One environment changes the Status__c field's <label>, and another adds a new <actionOverrides> element above the Status__c field. XML-based merge combines the modification and the addition with no conflict because they constitute different elements. Text-based merge sees an insertion and a modification affecting the same lines and raises a conflict.
Both sides add different elements at the same location. One environment adds a new <fields> element and another adds a new <listViews> element, both at the end of the object. XML-based merge keeps both elements with no conflict, because they have different element names and are therefore unrelated. Text-based merge sees two insertions affecting the same lines and raises a conflict.
One side modifies an element, the other deletes it. One environment deletes the Industry__c field while another modifies the Status__c field. The deletion and the modification target different elements, so XML-based merge removes one field and keeps the modification to the other, with no conflict. Text-based merge sees a deletion and a modification affecting the same lines and raises a conflict. If instead the same field is modified on one side and deleted on the other, that is a genuine modify-versus-delete and is surfaced as a conflict — just as Git would — rather than silently dropping the modification.
Both sides change different adjacent elements. One environment changes the Status__c field's <label> while another changes its <text>. Because the element names are different, XML-based merge recognizes these as edits to two distinct elements and applies both, with no conflict. Text-based merge is fragile here: because the two changed lines are adjacent, the two lines they occupy will typically be reported as a conflict.
Formatting-only differences. Differences that consist only of insignificant whitespace — indentation changes, line wrapping, blank lines between elements — are not treated as modifications at all. Text content is compared with leading/trailing whitespace trimmed and internal whitespace collapsed, so a side that merely reindented a file does not generate conflicts against a side that changed actual values.
Prefix-only differences. XML-based merge compares namespace-qualified element names, not the literal namespace prefixes used in the file. If two versions use different prefixes that resolve to the same namespace URI, those prefix differences are not treated as element identity changes. Text-based merge can report noisy conflicts in this situation because the tag text differs, even though the XML names are equivalent.
Conflicts improved by XML-based merge
Conflicts are aligned to XML elements boundaries. When both environments change the same element, both merge drivers report a conflict, but the conflict looks different. XML-based merge produces a conflict region that cleanly matches the complete conflicting XML element on each side. Text-based merge produces a conflict that spans whatever text lines it considers to overlap, which might start and end in the middle of different XML elements, making the conflict impossible to resolve cleanly without subsequent manual editing.
Adjacent conflicts of different elements stay separate. Unless they have the same element name, several adjacent conflicting elements are presented as separate conflict regions (for example a <label> conflict immediately followed by a <fields> conflict). This preserves your ability to resolve structurally different conflicts independently. Text-based merge would coalesce this into a single conflict region, making it much more difficult to resolve the the two elements differently.
Conflicts not improved by XML-based merge
Element moves and reordering. XML-based merge does not detect an element being moved among its siblings. A move appears as a deletion at the old position and an unrelated addition at the new position. In certain three-way scenarios this can lead to a duplicated or resurrected element. However, this is no different from Git's standard text-based merge, which also treats a move as an unrelated delete plus add. And in any case, for Salesforce metadata, this type of insignificant reordering is typically mitigated by metadata normalization before it ever reaches the merge, so that only semantically significant reorderings (such as ordered picklist values) are subject to merge.
Heuristics and behavior
XML-based merge follows a small set of observable rules:
- Element identity is local name plus namespace URI. If two elements have different local names or different namespace URIs, they are never considered the same element. Element names are assumed not to mutate — a different name means a different element. Namespace prefix spelling is not part of the element identity; different prefixes that resolve to the same namespace URI are treated as the same XML name.
- Leaf elements versus container elements. A leaf element (has text content, no child elements) is compared by its text content to decide whether it changed. A container element (has child elements, no significant text of its own) is never classified as changed at its own level; instead the merge recurses into it and merges its children. This is why two environments editing different descendants of the same component merge cleanly — the difference is detected and resolved deep at the specific leaf elements that actually changed, not for the whole component.
- Repeated elements are matched by their identifying content. When a parent has several same-named children (for example the many
<objectPermissions>entries in a permission set, or the<layoutAssignments>in a profile), XML-based merge aligns them by identity rather than by position. It does this without needing to be told which field is the "key": for each group of same-named siblings it weighs each element's content by how rare it is among those siblings, so ubiquitous boilerplate (shared flags and structure) is ignored and the distinguishing content (such as the<object>an entry refers to, or a nested identifier) dominates. This is what lets a block of entries inserted on one side and a different block inserted on the other be recognised as independent insertions, instead of being paired up entry-by-entry and reported as a cascade of small conflicts. Identity matching applies wherever there are multiple same-named siblings to tell apart, at any depth, including leaf-value lists (where each value is its own identity) and composite keys spread across more than one field. A single same-named child (for example one<description>) has no such ambiguity and is always matched by name. The--elementSimilarityThresholdoption (default 30) sets the minimum identity overlap required to treat two such siblings as the same element; it rarely needs changing. A consequence is that if an element is so heavily rewritten on one side that it shares almost none of its identifying content with the base version, it may be treated as a delete-plus-add (a replacement) rather than as a recursive in-place merge. - Added elements are matched by identity, not position. When both sides add elements at the same point, the additions are paired up before merging, so insertion order does not cause unrelated additions to be paired together. For repeated elements with an identifying value (such as several
<objectPermissions>or<fields>), two additions are recognized as the same element — and so conflict if they differ — only when they share that identifying value; two sides adding different elements (for example two different fields, or two different object permissions) are both kept without conflicting. This means routine cases where two people each add a different field or permission no longer produce a conflict, while two people adding the same field with different definitions still do (rather than silently producing a duplicate). Additions whose identity is just their own text value (leaf-value lists) are still paired by name, so two different added values at the same point are flagged as a conflict to be safe. - Output is consistently formatted. When a file is merged, it is rewritten as well-formed XML with consistent indentation. The file's original text encoding and its trailing-newline state are preserved. Because output is element-structured rather than line-patched, the merged result does not carry over incidental formatting differences from either side.
- Both versions must be well-formed XML with the same root. XML-based merge requires that the base, local and remote versions of a file are all parseable XML and share the same root element. Supported metadata types satisfy this in practice. If a file selected for XML-based merge cannot be parsed as XML, or the three versions do not share a root element, the merge operation fails.
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.