Home Explore Blog CI



git

4th chunk of `Documentation/git-read-tree.adoc`
ebc00eb4a175274dfe02b411607c758aa1a50b30ff1228a80000000100000f69
 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 tree, and it
will complain about unmerged entries if it sees a single entry that is not
stage 0.

OK, this all sounds like a collection of totally nonsensical rules,
but it's actually exactly what you want in order to do a fast
merge. The different stages represent the "result tree" (stage 0, aka
"merged"), the original tree (stage 1, aka "orig"), and the two trees
you are trying to merge (stage 2 and 3 respectively).

The order of stages 1, 2 and 3 (hence the order of three
<tree-ish> command-line arguments) are significant when you
start a 3-way merge with an index file that is already
populated.  Here is an outline of how the algorithm works:

- if a file exists in identical format in all three trees, it will
  automatically collapse to "merged" state by 'git read-tree'.

- a file that has _any_ difference what-so-ever in the three trees
  will stay as separate entries in the index. It's up to "porcelain
  policy" to determine how to remove the non-0 stages, and insert a
  merged version.

- the index file saves and restores with all this information, so you
  can merge things incrementally, but as long as it has entries in
  stages 1/2/3 (i.e., "unmerged entries") you can't write the result. So
  now the merge algorithm ends up being really simple:

  * you walk the index in order, and ignore all entries of stage 0,
    since they've already been done.

  * if you find a "stage1", but no matching "stage2" or "stage3", you
    know it's been removed from both trees (it only existed in the
    original tree), and you remove that entry.

  * if you find a matching "stage2" and "stage3" tree, you remove one
    of them, and turn the other into a "stage0" entry. Remove any
    matching "stage1" entry if it exists too.  .. all the normal
    trivial rules ..

You would normally use 'git merge-index' with supplied
'git merge-one-file' to do this last step.  The script updates
the files in the working tree as it merges each path and at the
end of a successful merge.

When you start a 3-way merge with an index file that is already
populated, it is assumed that it represents the state of the
files in your work tree, and you can even have files with
changes unrecorded in the index file.  It is further assumed
that this state is "derived" from the stage 2 tree.  The 3-way
merge refuses to run if it finds an entry in the original index
file that does not match stage 2.

This is done to prevent you from losing your work-in-progress
changes, and mixing your random changes in an unrelated merge
commit.  To illustrate, suppose you start from what has been
committed last to your repository:

----------------
$ JC=`git rev-parse --verify "HEAD^0"`
$ git checkout-index -f -u -a $JC
----------------

You do random edits, without running 'git update-index'.  And then
you notice that the tip of your "upstream" tree has advanced
since you pulled from him:

----------------
$ git fetch git://.... linus
$ LT=`git

Title: Git 3-Way Merge Algorithm
Summary
The Git 3-way merge algorithm uses stages to track changes from the original tree, the current branch, and the other branch, allowing for fast and incremental merges, and it relies on commands like 'git read-tree' and 'git merge-index' to resolve conflicts and update the index and working tree