{"thread":{"id":"12929","subject":"Re: [RFC/PATCH 4/5] Head reduction before selecting merge strategy","startedAt":"2008-03-31T04:30:58Z","lastAt":"2008-03-31T04:30:58Z","messageCount":1,"participants":["Sverre Hvammen Johansen"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"73407","messageId":"402c10cd0803302130g7f511312wa7eb8cdf51780fbc@mail.gmail.com","threadId":"12929","inReplyTo":null,"subject":"Re: [RFC/PATCH 4/5] Head reduction before selecting merge strategy","fromName":"Sverre Hvammen Johansen","fromEmail":"hvammen@gmail.com","sentAt":"2008-03-31T04:30:58Z","receivedAt":"2008-03-31T04:30:58Z","isPatch":true,"sender":{"key":"hvammen@gmail.com","avatar":"https://gravatar.com/avatar/d1fc25ec327eea135af60fe7b56b2a2e21f711aa32167e7f505014ec88aa24bc?d=mp&s=160"},"body":"See the documentation for an explanation of this feature.\n\nSigned-off-by: Sverre Hvammen Johansen <hvammen@gmail.com>\n---\n Documentation/git-merge.txt |   43 ++++++++++++++++++++++++++++++++++++-\n git-merge.sh                |   50 ++++++++++++++++++++++++-------------------\n 2 files changed, 70 insertions(+), 23 deletions(-)\n\ndiff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt\nindex 2af33d8..f6bc96f 100644\n--- a/Documentation/git-merge.txt\n+++ b/Documentation/git-merge.txt\n@@ -36,7 +36,7 @@ include::merge-options.txt[]\n <remote>::\n        Other branch head merged into our branch.  You need at\n        least one <remote>.  Specifying more than one <remote>\n-       obviously means you are trying an Octopus.\n+       usually means you are trying an Octopus.\n\n\n include::fast-forward-options.txt[]\n@@ -133,6 +133,47 @@ merge (which is typically a fraction of the whole\ntree), you can\n have local modifications in your working tree as long as they do\n not overlap with what the merge updates.\n\n+If more than one commit are specified on the command line, git will\n+try to reduce the number of commits used (reduced parents) by\n+eliminating commits than can be reached from other commits.  The\n+commit message will reflect the commits specified on the command line\n+but the merge strategy will be selected based on the reduced parents\n+including `HEAD`.  The reduced parents are the parents recorded in the\n+merge commit object.\n+\n+The following shows master and three topic branches.  topicB is based\n+on topicA, topicA is previously branched off from master, and topicC\n+is based on the tip of the master branch:\n+\n+------------\n+                    o---o---o  topicB\n+                   /\n+          o---o---o  topicA\n+         /\n+    o---o---o---o---o---o  master\n+                         \\\n+                          o---o  topicC\n+------------\n+\n+Merging topicA, B and C to the master branch will select the merge\n+strategy based on the three branches master, topicB, and topicC\n+(topicA is eliminated since it can be reached from topicB).  topicB\n+and topicC are the reduced parents and are therefore the only\n+parents recorded in the merge commit object:\n+\n+------------\n+         $ git checkout master\n+         $ git merge topicA topicB topicC\n+\n+                    o---o---o  topicB\n+                   /         \\\n+          o---o---o  topicA   \\\n+         /                     \\\n+    o---o---o---o---o---o       o  master\n+                         \\     /\n+                          o---o  topicC\n+------------\n+\n When there are conflicts, these things happen:\n\n 1. `HEAD` stays the same.\ndiff --git a/git-merge.sh b/git-merge.sh\nindex 7c34b6c..7c70c56 100755\n--- a/git-merge.sh\n+++ b/git-merge.sh\n@@ -337,11 +337,16 @@ set x $remoteheads ; shift\n\n find_reduced_parents \"$@\"\n\n-actual_parents=$(git rev-parse \"$@\")\n+# ff_head may be included here or later in actual parents\n+if test -n \"$reduced_parents\"\n+then\n+       test $head = $ff_head ||\n+               reduced_parents=\"$ff_head$LF$reduced_parents\"\n+fi\n\n case \"$use_strategies\" in\n '')\n-       case \"$actual_parents\" in\n+       case \"$reduced_parents\" in\n        ?*\"$LF\"?*)\n                var=\"`git config --get pull.octopus`\"\n                if test -n \"$var\"\n@@ -406,17 +411,23 @@ then\n                finish \"$new_head\" \"$msg\" || exit\n                dropsave\n                exit 0\n+       else\n+               reduced_parents=\"$ff_head\"\n+               ff_head=$head\n        fi\n+else\n+       test $head != $ff_head -a $fast_forward = never &&\n+               reduced_parents=\"$ff_head$LF$reduced_parents\"\n fi\n\n-case \"$actual_parents\" in\n+case \"$reduced_parents\" in\n ?*\"$LF\"?*)\n-       # We have more than one actual parent\n-       common=$(git show-branch --merge-base $head $actual_parents)\n+       # We have more than one reduced parent\n+       common=$(git show-branch --merge-base $head $reduced_parents)\n        ;;\n *)\n-       # We have exactly one actual parent\n-       test \"$common\" != not_queried || common=$(git merge-base --all\n$head $actual_parents)\n+       # We have exactly one reduced parent\n+       test \"$common\" != not_queried || common=$(git merge-base --all\n$head $reduced_parents)\n        case \"$common\" in\n        ?*\"$LF\"?*)\n                # We are not doing octopus and not fast forward.  Need a\n@@ -429,13 +440,13 @@ case \"$actual_parents\" in\n                        # See if it is really trivial.\n                        git var GIT_COMMITTER_IDENT >/dev/null || exit\n                        echo \"Trying really trivial in-index merge...\"\n-                       if git read-tree --trivial -m -u -v $common\n$head $actual_parents &&\n+                       if git read-tree --trivial -m -u -v $common\n$head $reduced_parents &&\n                                result_tree=$(git write-tree)\n                        then\n                                echo \"Wonderful.\"\n                                result_commit=$(\n                                        printf '%s\\n' \"$merge_msg\" |\n-                                       git commit-tree $result_tree\n-p HEAD -p $actual_parents\n+                                       git commit-tree $result_tree\n-p HEAD -p $reduced_parents\n                                ) || exit\n                                finish \"$result_commit\" \"In-index merge\"\n                                dropsave\n@@ -484,7 +495,7 @@ do\n     # Remember which strategy left the state in the working tree\n     wt_strategy=$strategy\n\n-    git-merge-$strategy $common -- \"$head_arg\" $actual_parents\n+    git-merge-$strategy $common -- \"$head_arg\" $reduced_parents\n     exit=$?\n     if test \"$no_commit\" = t && test \"$exit\" = 0\n     then\n@@ -520,17 +531,12 @@ done\n # auto resolved the merge cleanly.\n if test '' != \"$result_tree\"\n then\n-    if test $fast_forward = allow\n-    then\n-        parents=$(git show-branch --independent \"$head\" \"$@\")\n-    else\n-        parents=$(git rev-parse \"$head\" \"$@\")\n-    fi\n-    parents=$(echo \"$parents\" | sed -e 's/^/-p /')\n-    result_commit=$(printf '%s\\n' \"$merge_msg\" | git commit-tree\n$result_tree $parents) || exit\n-    finish \"$result_commit\" \"Merge made by $wt_strategy.\"\n-    dropsave\n-    exit 0\n+       test $head = $ff_head && reduced_parents=\"$head$LF$reduced_parents\"\n+       parents=$(echo \"$reduced_parents\" | sed -e 's/^/-p /')\n+       result_commit=$(printf '%s\\n' \"$merge_msg\" | git commit-tree\n$result_tree $parents) || exit\n+       finish \"$result_commit\" \"Merge made by $wt_strategy.\"\n+       dropsave\n+       exit 0\n fi\n\n # Pick the result from the best strategy and have the user fix it up.\n@@ -554,7 +560,7 @@ case \"$best_strategy\" in\n        echo \"Rewinding the tree to pristine...\"\n        restorestate\n        echo \"Using the $best_strategy to prepare resolving by hand.\"\n-       git-merge-$best_strategy $common -- \"$head_arg\" $actual_parents\n+       git-merge-$best_strategy $common -- \"$head_arg\" $reduced_parents\n        ;;\n esac\n-- \nSverre Hvammen Johansen\n"}]}