From: "Sverre Hvammen Johansen" <hvammen@gmail.com>
To: git@vger.kernel.org
Subject: [RFC/PATCH] Additional fast forward strategies.
Date: Mon, 10 Mar 2008 19:04:38 -0800 [thread overview]
Message-ID: <402c10cd0803102004x7892f01cledfef6f277fba26a@mail.gmail.com> (raw)
>From 779142c6b22f032c877f550733e1bccc99aca761 Mon Sep 17 00:00:00 2001
From: Sverre Hvammen Johansen <hvammen@gmail.com>
Date: Sun, 9 Mar 2008 21:16:03 -0800
Subject: [PATCH] Additional fast forward strategies.
New fast forward strategies, common, fork, path, and same
is introduced. These new fast forward strategies allows
additional work flows.
FF strategy "common" does a fast-forward to the common ancestor
of the specified heads. The merge will fail unless HEAD is the
common ancestor or HEAD can be fast-forwarded to the common ancestor.
FF strategy "fork" does a fast-forward to the common ancestor
of the real heads. The merge will fail unless HEAD is the
common ancestor of these heads or HEAD can be fast-forwarded
to the common ancestor of the real heads.
FF strategy "path" does a fast-forward to the first possible
branch that no other branches are ahead of. HEAD will be
fast-forwarded to such a branch if it exist. If no such branch
exist, HEAD is considered to be up to date.
FF strategy "same" does a fast forward where all branches are
required to point to the same commit. HEAD will be
fast-forwarded to this branch unless it is up to date.
Signed-off-by: Sverre Hvammen Johansen <sj@black.local>
---
Documentation/fast-forward-strategies.txt | 25 ++
git-merge.sh | 53 ++++-
t/t7601-merge-ff-strategies.sh | 373 +++++++++++++++++++++++++++++
3 files changed, 446 insertions(+), 5 deletions(-)
diff --git a/Documentation/fast-forward-strategies.txt
b/Documentation/fast-forward-strategies.txt
index 1d6da26..be94cfc 100644
--- a/Documentation/fast-forward-strategies.txt
+++ b/Documentation/fast-forward-strategies.txt
@@ -14,3 +14,28 @@ only::
Only allow a fast-forward. The merge will fail
unless HEAD is up to date or the merge resolved as
a fast-forward.
+
+common::
+ Fast-forward to the common ancestor of the specified
+ branches if possible. The merge will fail unless
+ HEAD is the common ancestor or HEAD can be
+ fast-forwarded to the common ancestor.
+
+fork::
+ Fast-forward to the earliest fork if possible.
+ The earliest fork is defined as the common ancestor
+ of the real branches. The merge will fail unless
+ HEAD is the earliest fork or HEAD can be
+ fast-forwarded to the earliest fork.
+
+path::
+ Fast-forward to the first possible branch that
+ no other branches are ahead of. HEAD will be
+ fast-forwarded to such a branch if it exist.
+ If no such branch exist, HEAD is considered to be
+ up to date.
+
+same::
+ The merge will fail unless HEAD is up to date or
+ the merge resolved as a fast-forward and each
+ branch is pointing to the same commit.
diff --git a/git-merge.sh b/git-merge.sh
index 873e4cb..d474f03 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -164,21 +164,21 @@ parse_config () {
no_commit=t ;;
--ff)
case "$2" in
- allow|never|only)
+ allow|never|only|common|fork|path|same)
fast_forward=$2 squash= no_commit= ; shift ;;
-*)
fast_forward=allow squash= no_commit= ;;
*)
- die "available fast-forward strategies are: allow, newer, and only" ;;
+ die "available fast-forward strategies are: allow, newer, only,
common, path" ;;
esac
;;
--ff=*)
fast_forward=$(echo $1 |cut -d = -f 2) squash= no_commit=
case $fast_forward in
- allow|never|only)
+ allow|never|only|common|fork|path|same)
;;
*)
- die "available fast-forward strategies are: allow, newer, and only" ;;
+ die "available fast-forward strategies are: allow, newer, only,
common, path" ;;
esac
;;
--no-ff)
@@ -374,12 +374,22 @@ find_real_parents () {
done
}
-if test $fast_forward = never -o
+if test $fast_forward = never -o $fast_forward = common
then
real_parents="$@"
ff_head=$head
else
find_real_parents "$@"
+ if test $fast_forward = same
+ then
+ for b in "$@"
+ do
+ if test "$b" != "$1"
+ then
+ die "Fast forward strategy same requires all heads to be the same"
+ fi
+ done
+ fi
fi
if test -n "$real_parents"
@@ -387,6 +397,39 @@ then
case $fast_forward in
only)
die "Fast forward strategy only can only handle one real parent" ;;
+ same)
+ die "Fast forward strategy same have unexpected parents" ;;
+ path)
+ echo "Ignoring branches $real_parents"
+ real_parents=
+ ;;
+ common|fork)
+ if test $fast_forward = fork
+ then
+ common=$(git show-branch --merge-base $ff_head $real_parents)
+ else
+ common=$(git show-branch --merge-base $real_parents)
+ fi
+ if test -n "$common"
+ then
+ common_h=$(git show-branch --merge-base $common $head)
+ if test "$common_h" = $head
+ then
+ if test $common = $head
+ then
+ echo "Ignoring all branches"
+ else
+ echo "Ignoring all branches except for $common"
+ fi
+ ff_head=$common
+ else
+ die "HEAD is ahead of the common anchestor"
+ fi
+ else
+ die "The specified branches does not have any common anchestor"
+ fi
+ real_parents=
+ ;;
never|allow)
if test $head != $ff_head
then
diff --git a/t/t7601-merge-ff-strategies.sh b/t/t7601-merge-ff-strategies.sh
index 6c0a91a..43cbe81 100755
--- a/t/t7601-merge-ff-strategies.sh
+++ b/t/t7601-merge-ff-strategies.sh
@@ -546,4 +546,377 @@ test_expect_success 'merge x0 with y2, c3, and c0' '
test_debug 'gitk --all'
+test_expect_success 'merge y2 with x0, c3, and c0 (--ff=path)' '
+ git reset --hard y2 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=path x0 c3 c0 &&
+ verify_merge file result.1-5-13 &&
+ verify_head $y2
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge x0 with y2, c3, and c0 (--ff=path)' '
+ git reset --hard x0 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=path y2 c3 c0 &&
+ verify_merge file result.1-5-13 &&
+ verify_head $y2
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with x0, c3, and c0 (--ff=path)' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=path x0 c3 c0 &&
+ verify_merge file result.1-5 &&
+ verify_head $x0
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with y2, c3, and c0 (--ff=path)' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=path y2 c3 c0 &&
+ verify_merge file result.1-5-13 &&
+ verify_head $y2
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with x0, y3, and c0 (--ff=path)' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=path x0 y3 c0 &&
+ verify_merge file result.1-5-13 &&
+ verify_head $y3
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with x0, c3, and y3 (--ff=path)' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=path x0 c3 y3 &&
+ verify_merge file result.1-5-13 &&
+ verify_head $y3
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with y1, y2, and y3 (--ff=path)' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=path y1 y2 y3 &&
+ verify_merge file result.1-5-13 &&
+ verify_head $y3
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with y1 (--ff=common)' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=common y1 &&
+ verify_merge file result.1-5-13 &&
+ verify_head $y1
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with y1, y2, and y3 (--ff=common)' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=common y1 y2 y3 &&
+ verify_merge file result.1-5 &&
+ verify_head $x0
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with c1 and c2 (--ff=common)' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=common c1 c2 &&
+ verify_merge file result.0 &&
+ verify_head $c0;
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with y1 and y2 (--ff=common)' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=common y1 y2 &&
+ verify_merge file result.1-5 &&
+ verify_head $x0;
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with y1 and y2 (--ff=common)' '
+ git reset --hard c1 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=common y1 y2 &&
+ verify_merge file result.1-5 &&
+ verify_head $x0;
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with y1 and y2 c0 (--ff=common)' '
+ git reset --hard c1 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ if git merge --ff=common y1 y2 c0
+ then
+ false
+ else
+ verify_merge file result.1 &&
+ verify_head $c1;
+ fi
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with x1 and c2 (--ff=common)' '
+ git reset --hard c1 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ if git merge --ff=common x1 c2
+ then
+ false
+ else
+ verify_merge file result.1 &&
+ verify_head $c1
+ fi
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with x0 (--ff=fork)' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=fork x0 &&
+ verify_merge file result.1-5 &&
+ verify_head $x0
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with y1, y2, and y3 (--ff=fork)' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=fork y1 y2 y3 &&
+ verify_merge file result.1-5-13 &&
+ verify_head $y3
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with c1 and c2 (--ff=fork)' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=fork c1 c2 &&
+ verify_merge file result.0 &&
+ verify_head $c0;
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with y1 and y2 (--ff=fork)' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=fork y1 y2 &&
+ verify_merge file result.1-5 &&
+ verify_head $x0;
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with y1 and y2 (--ff=fork)' '
+ git reset --hard c1 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=fork y1 y2 &&
+ verify_merge file result.1-5 &&
+ verify_head $x0;
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with y1 and y2 c0 (--ff=fork)' '
+ git reset --hard c1 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=fork y1 y2 c0 &&
+ verify_merge file result.1-5 &&
+ verify_head $x0;
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with x1 and c2 (--ff=fork)' '
+ git reset --hard c1 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ if git merge --ff=fork x1 c2
+ then
+ false
+ else
+ verify_merge file result.1 &&
+ verify_head $c1
+ fi
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with x1 (pull --ff=only)' '
+ git reset --hard c1 &&
+ test_tick &&
+ git pull --ff=only clone refs/heads/master &&
+ verify_merge file result.1-13 &&
+ verify_head $x1
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge x2 with x1 (pull --ff=only)' '
+ git reset --hard x2 &&
+ test_tick &&
+ if git pull --ff=only clone refs/heads/master
+ then
+ false
+ else
+ verify_merge file result.5-13 &&
+ verify_head $x2
+ fi
+'
+
+test_debug 'gitk --all'
+
+
+
+test_expect_success 'merge c1 with new repository (pull --ff=only)' '
+ git reset --hard c1 &&
+ test_tick &&
+ if git pull --ff=only new refs/heads/master
+ then
+ false
+ else
+ verify_merge file result.1 &&
+ verify_head $c1
+ fi
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with new repository (pull --ff=common)' '
+ git reset --hard c1 &&
+ test_tick &&
+ if git pull --ff=common new refs/heads/master
+ then
+ false
+ else
+ verify_merge file result.1 &&
+ verify_head $c1
+ fi
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with new repository (pull --ff=fork)' '
+ git reset --hard c1 &&
+ test_tick &&
+ if git pull --ff=fork new refs/heads/master
+ then
+ false
+ else
+ verify_merge file result.1 &&
+ verify_head $c1
+ fi
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with new repository (pull --ff=path)' '
+ git reset --hard c1 &&
+ test_tick &&
+ git pull --ff=path new refs/heads/master &&
+ verify_merge file result.1 &&
+ verify_head $c1
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with y1 and y1 (--ff=same)' '
+ git reset --hard c1 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=same y1 y1 &&
+ verify_merge file result.1-5-13 &&
+ verify_head $y1
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with c0 and c0 (--ff=same)' '
+ git reset --hard c1 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge --ff=same c0 c0 &&
+ verify_merge file result.1 &&
+ verify_head $c1
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge x1 with c2 and c2 (--ff=same)' '
+ git reset --hard x1 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ if git merge --ff=same c2 c2
+ then
+ false
+ else
+ verify_merge file result.1-13 &&
+ verify_head $x1
+ fi
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge y1 with c1 and x1 (--ff=same)' '
+ git reset --hard y1 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ if git merge --ff=same c1 x1
+ then
+ false
+ else
+ verify_merge file result.1-5-13 &&
+ verify_head $y1
+ fi
+'
+
+test_debug 'gitk --all'
+
test_done
--
1.5.3.3
--
Sverre Hvammen Johansen
next reply other threads:[~2008-03-11 3:05 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-03-11 3:04 Sverre Hvammen Johansen [this message]
2008-03-11 6:34 ` [RFC/PATCH] Additional fast forward strategies Junio C Hamano
2008-03-11 9:09 ` Jakub Narebski
2008-03-12 6:03 ` 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=402c10cd0803102004x7892f01cledfef6f277fba26a@mail.gmail.com \
--to=hvammen@gmail.com \
--cc=git@vger.kernel.org \
/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).