Home Explore Blog CI



git

3rd chunk of `Documentation/git-read-tree.adoc`
a8b3915561befe12ca81d11324b47d23361f89611624c2670000000100000fa5
 exists   nothing  remove path from index
     3  nothing             exists   exists,  use M if "initial checkout",
				     H == M   keep index otherwise
				     exists,  fail
				     H != M

        clean I==H  I==M
       ------------------
     4  yes   N/A   N/A     nothing  nothing  keep index
     5  no    N/A   N/A     nothing  nothing  keep index

     6  yes   N/A   yes     nothing  exists   keep index
     7  no    N/A   yes     nothing  exists   keep index
     8  yes   N/A   no      nothing  exists   fail
     9  no    N/A   no      nothing  exists   fail

     10 yes   yes   N/A     exists   nothing  remove path from index
     11 no    yes   N/A     exists   nothing  fail
     12 yes   no    N/A     exists   nothing  fail
     13 no    no    N/A     exists   nothing  fail

	clean (H==M)
       ------
     14 yes                 exists   exists   keep index
     15 no                  exists   exists   keep index

        clean I==H  I==M (H!=M)
       ------------------
     16 yes   no    no      exists   exists   fail
     17 no    no    no      exists   exists   fail
     18 yes   no    yes     exists   exists   keep index
     19 no    no    yes     exists   exists   keep index
     20 yes   yes   no      exists   exists   use M
     21 no    yes   no      exists   exists   fail
....

In all "keep index" cases, the index entry stays as in the
original index file.  If the entry is not up to date,
'git read-tree' keeps the copy in the work tree intact when
operating under the -u flag.

When this form of 'git read-tree' returns successfully, you can
see which of the "local changes" that you made were carried forward by running
`git diff-index --cached $M`.  Note that this does not
necessarily match what `git diff-index --cached $H` would have
produced before such a two tree merge.  This is because of cases
18 and 19 -- if you already had the changes in $M (e.g. maybe
you picked it up via e-mail in a patch form), `git diff-index
--cached $H` would have told you about the change before this
merge, but it would not show in `git diff-index --cached $M`
output after the two-tree merge.

Case 3 is slightly tricky and needs explanation.  The result from this
rule logically should be to remove the path if the user staged the removal
of the path and then switching to a new branch.  That however will prevent
the initial checkout from happening, so the rule is modified to use M (new
tree) only when the content of the index is empty.  Otherwise the removal
of the path is kept as long as $H and $M are the same.

3-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>.

Furthermore, 'git read-tree' has special-case logic that says: if you see
a file that matches in all respects in the following states, it
"collapses" back to "stage0":

   - stage 2 and 3 are the same; take one or the other (it makes no
     difference - the same work has been done on our branch in
     stage 2 and their branch in stage 3)

   - stage 1 and stage 2 are the same and stage 3 is different; take
     stage 3 (our branch in stage 2 did not do anything since the
     ancestor in stage 1 while their branch in stage 3 worked on
     it)

   - stage 1 and stage 3 are the same and stage 2 is different take
     stage 2 (we did something while they did nothing)

The 'git write-tree' command refuses to write a nonsensical

Title: Git Read Tree Merging Rules and 3-Way Merge
Summary
The git read-tree command has specific rules for merging changes from different trees, including removing paths from the index, keeping index entries, and handling local changes, and when performing a 3-way merge, it uses a 'stage' state to track changes from each tree, allowing for the resolution of conflicts and the creation of a new merged index