Search code examples
gitrebasegit-merge-conflictgithub-desktop

Git rebase appears to use an old version of a file, causing conflicts


I am using GitHub Desktop on a Mac with Beanstalk as my remote git repository server.

I have a project with Main, Dev, and Dev-phpunit-baseline branches. Main is production-ready, Dev is branched from Main, and Dev-phpunit-baseline is branched from Dev. I work solo in Dev-phpunit-baseline while my team works in Dev (and doesn't modify any PHPUnit code). My team has merged Dev-phpunit-baseline to Dev a couple of times without incident.

I had 4 files with incorrect @author attributions that I committed to Dev-phpunit-baseline and then merged to Dev. I fixed the attributions, committed to Dev-phpunit-baseline, and merged to Dev to correct the errors. The updated @author lines are now part of Dev-phpunit-baseline and Dev branches (and Main, but that is irrelevant).

Subsequent to that corrected merge, my teammates have updated Dev. I want to apply Dev's changes to Dev-phpunit-baseline; because of the separation of duties, a rebase sounds appropriate.

I check out Dev-phpunit-baseline. I select "Rebase current branch" from the Branch menu, then select Dev. The merge conflict window appears showing all 4 files with the original author instead of the current author. merge conflicts

Here is an example of one of the conflicted files (all others are similar): enter image description here

When I checkout Dev, those files show the updated author. Both branches (Dev & Dev-phpunit-baseline) in the remote Beanstalk repository show the updated author in all 4 files. The files in my local folder for Dev-phpunit-baseline show the updated author.

I have checked out Dev, copied the files in question to a temp directory, checked out Dev-phpunit-baseline, then moved the files from the temp directory to the correct location, overwriting the existing files. I still get the conflict.

I checked out Dev, deleted my local files, then reloaded them from Beanstalk origin. Still the same problem.

I deleted my entire local repository folder (including the .git folder), then re-cloned from Beanstalk. Still the same problem.

This problem also happens from the command line (so it's not a GitHub Desktop isolated issue).

This can't be a whitespace or line-ending problem (see Github Merge Conflict Despite Identical Lines In File or Why does git show a conflict between two apparently identical added files?) because the merge conflict shows different lines, not identical ones.

All of the following questions are essentially, "how to fix this?" Where is Git getting the older version of the file? Why doesn't Git pull the correct file from the local Dev branch? What else can I try to resolve this?

Thanks in advance for any hints or solutions.


Solution

  • Where is Git getting the older version of the file?

    When you have a conflict you can inspect the low level state of affair (aka plumbing) by running the command git ls-files -u to show unmerged files in the output.

    The command then gives some lines with file mode value, blob id, a stage value and file name. E.g. something like the following:

    $ git ls-files -u
    100644 ad5e6cfb620eb3086a399bd8dd63f039fa120358 1       .gitignore
    100644 73dab4ca75450b2aeb048a5e5632011d95064e58 2       .gitignore
    100644 12c32798081dd59a51295275ce1119f5d1662422 3       .gitignore
    $
    

    The stage values are (details in git-read-tree(1)):

    0 Normal, no conflict
    1 Common ancestor
    2 Current branch (version merged on to)
    3 The other branch (version merged from)
    

    So given the blob id, you can then use git cat-file blob to retrieve the corresponding file content, e.g.

    $ git cat-file blob ad5e6cfb620eb3086a399bd8dd63f039fa120358 > .gitignore.common-base
    $
    

    The above is the basis of operation for my script git-resolve-conflict-using-kdiff3 which does the above automatically and presents you with a choice to launch KDiff3 for each conflicted file.


    And you really, really, really, really need to use a proper, full 3-way merge tool to resolve conflicts with! Anything else is next to useless. To be clear - a proper 3-way merge tool is a tool that displays 4 panes, typically something like

      ╔═══════╦═══════╦═══════╗
      ║       ║       ║       ║
      ║   A   ║   B   ║   C   ║
      ║       ║       ║       ║
      ╠═══════╩═══════╩═══════╣
      ║                       ║
      ║         MERGED        ║
      ║                       ║
      ╚═══════════════════════╝
    

    If you want to use something other than kdiff3, that's ok but the tool must support 4 panes like that. I don't care how much someone is paying you to use GitHub Desktop or whatever other tool that just displays those horrible embedded conflict markers with only two versions. You should immediately stop using it for conflict resolution (it might be ok to use for other stuff, but not for merge conflicts).

    Sure, you could maybe dig up your garden with a small plastic toy spade, but why would you not use a proper sized metal spade?