git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC/PATCH] Additional fast forward strategies.
@ 2008-03-11  3:04 Sverre Hvammen Johansen
  2008-03-11  6:34 ` Junio C Hamano
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Sverre Hvammen Johansen @ 2008-03-11  3:04 UTC (permalink / raw)
  To: git

>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

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [RFC/PATCH] Additional fast forward strategies.
  2008-03-11  3:04 [RFC/PATCH] Additional fast forward strategies Sverre Hvammen Johansen
@ 2008-03-11  6:34 ` Junio C Hamano
  2008-03-11  9:09 ` Jakub Narebski
  2008-03-12  6:03 ` Sverre Hvammen Johansen
  2 siblings, 0 replies; 4+ messages in thread
From: Junio C Hamano @ 2008-03-11  6:34 UTC (permalink / raw)
  To: Sverre Hvammen Johansen; +Cc: git

"Sverre Hvammen Johansen" <hvammen@gmail.com> writes:

>>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.

Ditto..

> New fast forward strategies, common, fork, path, and same
> is introduced.  These new fast forward strategies allows
> additional work flows.

Is it sufficient to say "allows additional work flows" here?  I only see
what they do, and do not see why these are needed/useful anywhere in the
proposed commit log message nor documentation. 

You need to illustrate the motivation after the above three-line paragraph
and before the description of what each of them does below.  "Suppose your
history looks like this, and you and your group's workflow is like this.
Then you would want to only allow these but want to forbid those for such
and such reasons."  Then list what the "FF options" do.  After that, you
can conclude "By using these FF options this way, you can achieve that
control like this..."

Then people might be convinced that "these allow additional work flows".
What you wrote is insufficient, I am afraid.  At least to me.

> +	if test $fast_forward = same
> +	then
> +		for b in "$@"

'in "$@"' is always redundant after "for X".

More seriously, why is the user forced to give more than one "same" thing
to begin with?  The user can give a single thing and be done with it.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFC/PATCH] Additional fast forward strategies.
  2008-03-11  3:04 [RFC/PATCH] Additional fast forward strategies Sverre Hvammen Johansen
  2008-03-11  6:34 ` Junio C Hamano
@ 2008-03-11  9:09 ` Jakub Narebski
  2008-03-12  6:03 ` Sverre Hvammen Johansen
  2 siblings, 0 replies; 4+ messages in thread
From: Jakub Narebski @ 2008-03-11  9:09 UTC (permalink / raw)
  To: Sverre Hvammen Johansen; +Cc: git

"Sverre Hvammen Johansen" <hvammen@gmail.com> writes:

> From: Sverre Hvammen Johansen <hvammen@gmail.com>
> 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.

It would be better (read: greater chance to be accepted) if you had
provided examples of those "additional workflows", best in EXAMPLES
section (or something like that) of fast-forward documentation, and
"see documentation" (or something like that) in commit message.
 
> 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.

Don't you mean "common descendant" here?

> 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.

What is the difference between 'real heads' and 'soecified heads'?
Example, please.

> 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>

It will be easier to understand those descriptions if you have
provided with ASCII-art diagrams (in the documentation, not
necessarily in fast-forward strategies^W options description, but
perhaps somewhere below, above FAST-FORWARD OPTIONS EXAMPLES section).

For example, by default you can fast-forward only when doing single
branch merge.

%%

  A---B---C---D   <--- master <--- HEAD
       \
        \-1---2   <--- a

If you have situation as above, you are on branch 'master',
and you do "git merge a" it would result in merge commit.

  A---B---C---D---M   <--- master <--- HEAD
       \         /
        \-1---2-/     <--- a

%%

  A---B           <--- master <--- HEAD
       \
        \-1---2   <--- a

If you have situation as above, you are on branch 'master',
and you do "git merge a" it would result in fast-forward.

  A---B---1---2   <--- master <--- HEAD
                    
              ^------- a

or

  A---B---1---2   <--- master <--- HEAD
              ^      
               \------ a


%%

  A---B           <--- master <--- HEAD
       \
        \-1---2   <--- a
              
              ^------- b

This I think is 'FF strategy "same"' situation.

%%

  A---B              <--- master <--- HEAD
       \
        \-1---2      <--- a
               \
                \-3  <--- b

This I guess is either 'common' or 'fork' situation.

-- 
Jakub Narebski
Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFC/PATCH] Additional fast forward strategies.
  2008-03-11  3:04 [RFC/PATCH] Additional fast forward strategies Sverre Hvammen Johansen
  2008-03-11  6:34 ` Junio C Hamano
  2008-03-11  9:09 ` Jakub Narebski
@ 2008-03-12  6:03 ` Sverre Hvammen Johansen
  2 siblings, 0 replies; 4+ messages in thread
From: Sverre Hvammen Johansen @ 2008-03-12  6:03 UTC (permalink / raw)
  To: git

I may drop this patch or at least not prioritize it for now.  I don't
need it and implemented it just for fun.  There are other features
that are fare more important.  The other patch I am working on that
implement "--ff=only" is something I need

-- 
Sverre Hvammen Johansen

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2008-03-12  6:04 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-03-11  3:04 [RFC/PATCH] Additional fast forward strategies Sverre Hvammen Johansen
2008-03-11  6:34 ` Junio C Hamano
2008-03-11  9:09 ` Jakub Narebski
2008-03-12  6:03 ` Sverre Hvammen Johansen

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).