[RFC/PATCH] Additional fast forward strategies.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>From 779142c6b22f032c877f550733e1bccc99aca761 Mon Sep 17 00:00:00 2001
From: Sverre Hvammen Johansen <hvammen@xxxxxxxxx>
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@xxxxxxxxxxx>
---
 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
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux