From: "Sverre Hvammen Johansen" <hvammen@gmail.com>
To: "Junio C Hamano" <gitster@pobox.com>
Cc: git@vger.kernel.org
Subject: Re: [RFC/PATCH 3/4] Head reduction before selecting merge strategy
Date: Tue, 25 Mar 2008 19:58:26 -0800 [thread overview]
Message-ID: <402c10cd0803252058k2f35b33fr99ec7446235eeb6e@mail.gmail.com> (raw)
See the documentation for an explanation of this feature.
Signed-off-by: Sverre Hvammen Johansen <hvammen@gmail.com>
---
Documentation/git-merge.txt | 43 +++++++++++++++++++++++-
git-merge.sh | 76 +++++++++++++++++++++++++++++--------------
2 files changed, 93 insertions(+), 26 deletions(-)
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 2af33d8..e94d26b 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -36,7 +36,7 @@ include::merge-options.txt[]
<remote>::
Other branch head merged into our branch. You need at
least one <remote>. Specifying more than one <remote>
- obviously means you are trying an Octopus.
+ usually means you are trying an Octopus.
include::fast-forward-options.txt[]
@@ -133,6 +133,47 @@ merge (which is typically a fraction of the whole
tree), you can
have local modifications in your working tree as long as they do
not overlap with what the merge updates.
+If more than one commit are specified for the merge, git will try to
+reduce the number of commits (real parents) by eliminating commits
+than can be reached from other commits. The commit message will
+reflect the actual commits specified but the merge strategy will be
+selected based on the real parents, but always including `HEAD`. The
+real parents (only including `HEAD` if it is real) are the parents
+recorded in the merge commit object.
+
+The following shows master and three topic branches. topicB is based
+on topicA, topicA is previously branched off from master, and topicC
+is based on the current `HEAD` of master:
+
+------------
+ o---o---o topicB
+ /
+ o---o---o topicA
+ /
+ o---o---o---o---o---o master
+ \
+ o---o topicC
+------------
+
+A merger of master with topicA, topicB, and topicC will select the
+merge strategy based on the three branches master, topicB, and topicC
+(topicA is eliminated since it can be reached from topicB). topicB
+and topicC are the only real parents and are therefore the only
+parents recorded in the merge commit object:
+
+------------
+ % git checkout master
+ % git merge topicA topicB topicC
+
+ o---o---o topicB
+ / \
+ o---o---o topicA \
+ / \
+ o---o---o---o---o---o o master
+ \ /
+ o---o topicC
+------------
+
When there are conflicts, these things happen:
1. `HEAD` stays the same.
diff --git a/git-merge.sh b/git-merge.sh
index 2acd2cc..5398606 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -209,24 +209,41 @@ parse_config () {
# Find real parents
# Set the following variables as followd:
-# real_parents: The parents specified on the command line
+# real_parents: The real parents except fast forward of head
# common: All common ancestors or not_queried
# ff_head: Fast forward of head
find_real_parents () {
- real_parents=$(git rev-parse "$@")
- real_parents=${real_parents#$LF}
- if test $# = 1
+ if test $fast_forward = never
then
- common=$(git merge-base --all $head "$@")
- if test "$common" = $head
+ real_parents=$(git rev-parse "$@")
+ ff_head=$head
+ common=not_queried
+ else
+ if test $# = 1
then
- ff_head=$1
+ common=$(git merge-base --all $head "$1")
+ if test "$common" = $head
+ then
+ real_parents=
+ ff_head=$1
+ elif test "$common" = "$1"
+ then
+ real_parents=
+ ff_head=$head
+ else
+ real_parents=$1
+ ff_head=$head
+
+ fi
else
- ff_head=$head
+ real_parents=$(git show-branch --independent $head "$@")
+ # Here we may actually lie about which bransh
is ff of head.
+ # This will preserve the order the user gave.
+ ff_head=${real_parents%%$LF*}
+ real_parents=${real_parents#$ff_head}
+ real_parents=${real_parents#$LF}
+ common=not_queried
fi
- else
- common=not_queried
- ff_head=$head
fi
}
@@ -319,6 +336,12 @@ set x $remoteheads ; shift
find_real_parents "$@"
+if test -n "$real_parents"
+then
+ test $head = $ff_head ||
+ real_parents="$ff_head$LF$real_parents"
+fi
+
case "$use_strategies" in
'')
case "$real_parents" in
@@ -366,13 +389,13 @@ done
echo "$head" >"$GIT_DIR/ORIG_HEAD"
-if true
+if test -z "$real_parents"
then
- if test $head = $ff_head -a "$common" = "$real_parents"
+ if test $head = $ff_head
then
finish_up_to_date "Already up-to-date."
exit 0
- elif test $fast_forward != never -a $ff_head = "$real_parents"
+ elif test $fast_forward != never
then
echo "Updating $(git rev-parse --short $head)..$(git
rev-parse --short $ff_head)"
git update-index --refresh 2>/dev/null
@@ -386,6 +409,14 @@ then
finish "$new_head" "$msg" || exit
dropsave
exit 0
+ else
+ real_parents="$ff_head"
+ ff_head=$head
+ fi
+else
+ if test $head != $ff_head -a $fast_forward = never
+ then
+ real_parents="$ff_head$LF$real_parents"
fi
fi
@@ -500,17 +531,12 @@ done
# auto resolved the merge cleanly.
if test '' != "$result_tree"
then
- if test $fast_forward = allow
- then
- parents=$(git show-branch --independent "$head" "$@")
- else
- parents=$(git rev-parse "$head" "$@")
- fi
- parents=$(echo "$parents" | sed -e 's/^/-p /')
- result_commit=$(printf '%s\n' "$merge_msg" | git commit-tree
$result_tree $parents) || exit
- finish "$result_commit" "Merge made by $wt_strategy."
- dropsave
- exit 0
+ test $head = $ff_head && real_parents="$head$LF$real_parents"
+ parents=$(echo "$real_parents" | sed -e 's/^/-p /')
+ result_commit=$(printf '%s\n' "$merge_msg" | git commit-tree
$result_tree $parents) || exit
+ finish "$result_commit" "Merge made by $wt_strategy."
+ dropsave
+ exit 0
fi
# Pick the result from the best strategy and have the user fix it up.
--
Sverre Hvammen Johansen
next reply other threads:[~2008-03-26 3:59 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-03-26 3:58 Sverre Hvammen Johansen [this message]
2008-03-26 12:50 ` [RFC/PATCH 3/4] Head reduction before selecting merge strategy Jakub Narebski
2008-03-26 16:17 ` Junio C Hamano
2008-03-27 3:10 ` Sverre Hvammen Johansen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=402c10cd0803252058k2f35b33fr99ec7446235eeb6e@mail.gmail.com \
--to=hvammen@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).