3

How does git get the list of unmerged paths?

My understanding of git is that when merging it incorporates changes into a file and then adds it to index. If a merge conflict occurs, a file is not added to the index and is left in the working tree with conflict markers. If I run git status it shows me unmerged paths for the conflicted files.

How does git get the list of these files? If I run git add for a conflicted file with markers still in place, it will not be shown as conflicted anymore, so perhaps markers are not identifiers?

Rob Bednark
  • 25,981
  • 23
  • 80
  • 125
Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488

1 Answers1

3

If merge conflict occurs a file is not added in index and left in working tree with conflict markers.

It is in the index: see git ls-files:

For an unmerged path, instead of recording a single mode/SHA-1 pair, the index records up to three such pairs; one from tree O in stage 1, A in stage 2, and B in stage 3.

git read-tree details the 2 way merge:

Each "index" entry has two bits worth of "stage" state.
stage 0 is the normal one, and is the only one you’d see in any kind of normal use.

However, when you do git read-tree with three trees, the "stage" starts out at 1.

This means that you can do

git read-tree -m <tree1> <tree2> <tree3>

and you will end up with an index with all of the <tree1> entries in "stage1", all of the <tree2> entries in "stage2" and all of the <tree3> entries in "stage3".
When performing a merge of another branch into the current branch, we use the common ancestor tree as <tree1>, the current branch head as <tree2>, and the other branch head as <tree3>.

See also "How do I force git to think a file is unmerged?".

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • I'm reading through `git read tree` and it appears that merge is done internally and only then index and working tree are updated, not the other way around (merge in working directory -> update index). Is it correct? – Max Koretskyi Feb 28 '15 at 11:24
  • @Maximus no, it uses the index to perform the merge, which is why it "will refuse to run if your index file has unmerged entries, indicating that you have not finished previous merge you started." – VonC Feb 28 '15 at 11:47
  • Hmm, does it use working directory also to perform a merge? Or does it update the working directory from index when merge is done in index? I probably don't quite understand what you mean by `it uses the index to perform the merge`. – Max Koretskyi Feb 28 '15 at 11:58
  • 1
    @Maximus I see what you mean. See http://git-scm.com/docs/git-merge#_true_merge: it will uses the working tree as the place where the result of the merge is stored, merging HEAD and MERGE_HEAD, and, for conflicting path, recording in the index file up to three versions: stage 1 stores the version from the common ancestor, stage 2 from HEAD, and stage 3 from MERGE_HEAD (you can inspect the stages with git ls-files -u). The working tree files contain the result of the "merge" program. So yes, working tree and index are updated according to the result of the merge. – VonC Feb 28 '15 at 12:10
  • Got you, thanks! I'm going to read more about `read-tree` as this seems to be the best description of what magic happens when merging. Best! – Max Koretskyi Feb 28 '15 at 12:15
  • Just read `read-tree` page... so it seems that `git status` under `unmerged paths` shows paths that do not have `stage 0` bit set, correct? – Max Koretskyi Feb 28 '15 at 20:03
  • @Maximus I didn't see that in the read-tree page. I only saw that "the `git write-tree` command refuses to write a nonsensical tree, and it will complain about unmerged entries if it sees a single entry that is not stage 0". – VonC Feb 28 '15 at 22:25
  • Yeah, the documentation doesn't specifically state that, it's my guess. – Max Koretskyi Mar 01 '15 at 07:11
  • can you please take a look at [this](http://stackoverflow.com/questions/29094303/git-diff-extended-header-index-2nd-hash-corresponds-to-what) and [this](http://stackoverflow.com/questions/29242382/what-are-the-mechanics-of-git-revert-command) my questions when you have time. Thanks in advance! – Max Koretskyi Mar 25 '15 at 08:35