From ccef66b55a6a2eb2c5f6a9dd29a86b181df21af9 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 7 Jun 2005 14:35:43 -0700 Subject: [PATCH] [PATCH] read-tree: update documentation for 3-way merge. This explains the new merge world order that formally assigns specific meaning to each of three tree-ish command line arguments. It also mentions -u option Signed-off-by: Junio C Hamano Signed-off-by: Linus Torvalds --- Documentation/git-read-tree.txt | 90 ++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 24 deletions(-) diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt index 6440c4b41..7665946f8 100644 --- a/Documentation/git-read-tree.txt +++ b/Documentation/git-read-tree.txt @@ -9,16 +9,19 @@ git-read-tree - Reads tree information into the directory cache SYNOPSIS -------- -'git-read-tree' ( | -m [ ])" +'git-read-tree' ( | [-m [-u]] [ []]) + DESCRIPTION ----------- -Reads the tree information given by into the directory cache, +Reads the tree information given by into the directory cache, but does not actually *update* any of the files it "caches". (see: git-checkout-cache) -Optionally, it can merge a tree into the cache or perform a 3-way -merge. +Optionally, it can merge a tree into the cache, perform a +fast-forward (i.e. 2-way) merge, or a 3-way merge, with the -m +flag. When used with -m, the -u flag causes it to also update +the files in the work tree with the result of the merge. Trivial merges are done by "git-read-tree" itself. Only conflicting paths will be in unmerged state when "git-read-tree" returns. @@ -26,7 +29,11 @@ will be in unmerged state when "git-read-tree" returns. OPTIONS ------- -m:: - Perform a merge, not just a read + Perform a merge, not just a read. + +-u:: + After a successful merge, update the files in the work + tree with the result of the merge. :: The id of the tree object(s) to be read/merged. @@ -34,10 +41,12 @@ OPTIONS Merging ------- -If '-m' is specified, "git-read-tree" performs 2 kinds of merge, a single tree -merge if only 1 tree is given or a 3-way merge if 3 trees are +If '-m' is specified, "git-read-tree" can performs 3 kinds of +merge, a single tree merge if only 1 tree is given, a +fast-forward merge with 2 trees, or a 3-way merge if 3 trees are provided. + Single Tree Merge ~~~~~~~~~~~~~~~~~ If only 1 tree is specified, git-read-tree operates as if the user did not @@ -47,7 +56,7 @@ being read, the stat info from the cache is used. (In other words, the cache's stat()s take precedence over the merged tree's) That means that if you do a "git-read-tree -m " followed by a -"git-checkout-cache -f -a", the "git-checkout-cache" only checks out +"git-checkout-cache -f -u -a", the "git-checkout-cache" only checks out the stuff that really changed. This is used to avoid unnecessary false hits when "git-diff-files" is @@ -166,23 +175,18 @@ 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). -In fact, the way "git-read-tree" works, it's entirely agnostic about how -you assign the stages, and you could really assign them any which way, -and the above is just a suggested way to do it (except since -"git-write-tree" refuses to write anything but stage0 entries, it makes -sense to always consider stage 0 to be the "full merge" state). - -So what happens? Try it out. Select the original tree, and two trees -to merge, and look how it works: +The order of stages 1, 2 and 3 (hence the order of three + 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 the new git-read-tree. + 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 "script policy" to determine how to remove the non-0 stages, and insert a - merged version. But since the index is always sorted, they're easy - to find: they'll be clustered together. + 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 @@ -201,11 +205,49 @@ to merge, and look how it works: matching "stage1" entry if it exists too. .. all the normal trivial rules .. -Incidentally - it also means that you don't even have to have a -separate subdirectory for this. All the information literally is in -the index file, which is a temporary thing anyway. There is no need to -worry about what is in the working directory, since it is never shown -and never used. +You would normally use "git-merge-cache" with supplied +"git-merge-one-file-script" to do this last step. The script +does not touch the files in the work tree, and the entire merge +happens in the index file. In other words, there is no need to +worry about what is in the working directory, since it is never +shown and never used. + +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. To illustrate, suppose you start from what has been +commited last to your repository: + + $ JC=`cat .git/HEAD` + $ git-checkout-cache -f -u -a $JC + +You do random edits, without running git-update-cache. And then +you notice that the tip of your "upstream" tree has advanced +since you pulled from him: + + $ git-fetch-script rsync://.... linus + $ LT=`cat .git/MERGE_HEAD` + +Your work tree is still based on your HEAD ($JC), but you have +some edits since. Three-way merge makes sure that you have not +added or modified cache entries since $JC, and if you haven't, +then does the right thing. So with the following sequence: + + $ git-read-tree -m -u `git-merge-base $JC $LT` $JC $LT + $ git-merge-cache git-merge-one-file-script -a + $ echo "Merge with Linus" | \ + git-commit-tree `git-write-tree` -p $JC -p $LT + +what you would commit is a pure merge between $JC and LT without +your work-in-progress changes, and your work tree would be +updated to the result of the merge. + See Also -------- -- 2.30.2