Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git Conflict Markers showing a different file update

We are merging Master into Feature Branch and suddenly, we observed some files where conflicts appeared.

  1. These files were never moved to Master
  2. Conflict marker in files were showing Head in correct part but Master markers showing content from a completely different file.

Not sure how 2. is possible? we are truly scared now.

<?xml version="1.0" encoding="UTF-8"?>
<ApexPage xmlns=http://soap.sforce.com/2006/04/metadata>
<<<<<<<< HEAD:salesforce_sfdx/force-app/main/default/pages/xyz.page-meta.xml
    <apiVersion>53.0</apiVersion>
    <label>xyz</label>
========
    <apiVersion>55.0</apiVersion>
    <label>abc</label>
>>>>>>>> development:salesforce_sfdx/force-app/main/default/pages/abc.page-meta.xml
</ApexPage>
like image 286
Oxycash Avatar asked Oct 24 '25 18:10

Oxycash


2 Answers

I'm adding an answer here, with a potential work around inspired by @torek's answer.

It's clear already that the problem is due to Git (incorrectly) inferring that a rename happened, and deciding to act accordingly. It's not clear yet why, but torek's suggestion to use git diff --find-renames for troubleshooting lead me to read the manual and discover two options that might help you:

  1. You can tell Git to be strict when it's looking for renames, considering only identical files as renames:

     git merge --find-renames=100% <rest of your merge command>
    
  2. You can tell Git to turn off rename detection altogether:

     git merge --no-renames <rest of your merge command>
    

The thing you need to know for all this to make sense is that Git only stores snapshots of your whole project tree in each commit. A commit is not actually stored as a change set, but as a full new snapshot. So whenever you merge, cherry pick, view the log, do a diff, all of that is done by diff'ing these snapshots. Renames are no exceptions: the fact that you did git mv in a commit is not stored, it's inferred by the diff with the previous commit, or possible between merge bases when there's more than one. And sometimes that inference makes mistakes.

like image 105
joanis Avatar answered Oct 27 '25 08:10

joanis


(Note: this isn't really an answer, at least not yet.)

What we have in the merge conflict is this information, which I have taken from the two markers:

HEAD:salesforce_sfdx/force-app/main/default/pages/xyz.page-meta.xml
development:salesforce_sfdx/force-app/main/default/pages/abc.page-meta.xml

This tells us that index slot #2 (--ours) has, for this file, the contents taken from salesforce_sfdx/force-app/main/default/pages/xyz.page-meta.xml in the HEAD commit, and index slot #3 (--theirs) has the contents taken from salesforce_sfdx/force-app/main/default/pages/xyz.page-meta.xml in the development commit. The file must therefore exist in both commits, and there must be a merge base version of that file, which will be in index slot #1.

Several more things would be useful here. In particular, merge.conflictStyle is clearly set to merge here. This hides some information; if it were set to diff3 we'd get more information. We can reconstruct this information though.

First, we'd like to know which commit(s) is/are the source of the merge base version of this merge base version. To find out, run:

git merge-base --all HEAD MERGE_HEAD

This will spit out a single commit hash ID, if things are ideal, or multiple hash IDs if things are less than ideal.

Second, we'd like to know what's actually in the corresponding lines in the file in index slot #1. That's easy to obtain: git show :1:salesforce_sfdx/force-app/main/default/pages/xyz.page-meta.xml should extract the entire file, which we can then inspect.

If the git merge-base command shows multiple commits, it's possible that the merge base is a "virtual commit" (made by git merge-recursive or git merge-ort, or whichever strategy is being used here). In this case the merge base itself may contain a merge conflict.

In any case, there are definitely three input files. If there's only a single merge base, we're in much better shape because we can figure out what those three files are in all three commits using git diff --find-renames. Simply take the merge base hash ID and run:

git diff --find-renames <hash> HEAD > /tmp/ours
git diff --find-renames <hash> MERGE_HEAD > /tmp/theirs

The two /tmp files now contain the diff results, including any detected renames. The HEAD and development commits' names for the two output files are the same (salesforce_sfdx/force-app/main/default/pages/xyz.page-meta.xml) so the only real question here is what, if anything, was the name of the merge base copy of the file.

Given this additional information, we can then proceed to see why there is a merge conflict here, and whether this represents some sort of Git bug.

like image 41
torek Avatar answered Oct 27 '25 09:10

torek



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!