From: Sverre Hvammen Johansen <hvammen@gmail.com>
This commit introduces fast forward option 'only'. With --ff=only
merge succeeds only if it resolves to fast-forward merge.
This feature is useful for cases where a rebase is desired
instead of a real merge. This option can then be used to
avoid an accidental merge.
See the documentation for further details.
Signed-off-by: Sverre Hvammen Johansen <hvammen@gmail.com>
---
Documentation/fast-forward-options.txt | 9 ++
git-merge.sh | 12 +-
git-pull.sh | 2 +-
t/t7601-merge-ff-options.sh | 214 ++++++++++++++++++++++++++++++++
4 files changed, 231 insertions(+), 6 deletions(-)
diff --git a/Documentation/fast-forward-options.txt b/Documentation/fast-forward-options.txt
index 9374aa9..41580ea 100644
--- a/Documentation/fast-forward-options.txt
+++ b/Documentation/fast-forward-options.txt
@@ -12,6 +12,10 @@ never::
Generate a merge commit even if the merge resolves as a
fast-forward. This option is equivalent of '--no-ff'.
+only::
+ Only allow a fast-forward. The merge will fail unless HEAD is
+ up to date or the merge resolves as a fast-forward.
+
If your workflow is always to branch from the special branch
("master") when working on a topic and merge that back to "master", if
you happen to have worked only on a single topic and the "master" was
@@ -42,3 +46,8 @@ The first merge of topicA or the only merge of topicB would have
resulted in a fast forward without '--ff=never'. Topic A consist of
those commits that can be reached from master^2 without passing
through any of the first-parent ancestries of master.
+
+However, if the workflow require that the branch you are merging with
+is based on the current HEAD you can use "only fast forward" policy to
+enforce fast forward or a failure. The last merge of topicA in
+the example above would have failed with '--ff=only'.
diff --git a/git-merge.sh b/git-merge.sh
index 775dae7..b87e125 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -168,21 +168,21 @@ parse_config () {
no_commit=t ;;
--ff)
case "$2" in
- allow|never)
+ allow|never|only)
fast_forward=$2; shift ;;
-*)
fast_forward=allow ;;
*)
- die "Available fast-forward options are: allow and newer" ;;
+ die "Available fast-forward options are: allow, newer, and only" ;;
esac
;;
--ff=*)
fast_forward=${1#--ff=}
case "$fast_forward" in
- allow|never)
+ allow|never|only)
;;
*)
- die "Available fast-forward options are: allow and newer" ;;
+ die "Available fast-forward options are: allow, newer, and only" ;;
esac
;;
--no-ff)
@@ -209,7 +209,7 @@ parse_config () {
shift
done
test "$fast_forward" = allow -o "$squash" = "" ||
- die "You cannot combine --squash with --ff=never"
+ die "You cannot combine --squash with --ff=never or --ff=only."
args_left=$#
}
@@ -347,6 +347,8 @@ find_reduced_parents "$@"
# ff_head may be included here or later in actual parents
if test -n "$reduced_parents"
then
+ test $fast_forward = only &&
+ die "--ff=only can not handle more than one real parent"
test $head = $ff_head ||
reduced_parents="$ff_head$LF$reduced_parents"
fi
diff --git a/git-pull.sh b/git-pull.sh
index 9e91e75..c5fa1ee 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -41,7 +41,7 @@ do
no_ff=--ff ;;
--no-ff)
no_ff=--no-ff ;;
- --ff=allow|--ff=never)
+ --ff=allow|--ff=only|--ff=never)
no_ff=$1 ;;
-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
--strateg=*|--strategy=*|\
diff --git a/t/t7601-merge-ff-options.sh b/t/t7601-merge-ff-options.sh
index c7c6d14..56e8370 100755
--- a/t/t7601-merge-ff-options.sh
+++ b/t/t7601-merge-ff-options.sh
@@ -662,4 +662,218 @@ test_expect_success 'merge c1 with new repository (pull --ff=never)' '
test_debug 'gitk --all'
+test_expect_success 'merge c0 with c1 (--ff=only overrides --no-ff)' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions "--no-ff" &&
+ git merge --ff=only c1 &&
+ verify_merge file result.1 &&
+ verify_head $c1
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with c1 (--ff=only in config)' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions "--ff=only" &&
+ git merge c1 &&
+ test_tick &&
+ verify_merge file result.1 &&
+ verify_head $c1
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with c0 (--ff=only in config)' '
+ git reset --hard c1 &&
+ git config branch.master.mergeoptions "--ff=only" &&
+ git merge c0 &&
+ verify_merge file result.1 &&
+ verify_head $c1
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with c2 (--ff=only in config)' '
+ git reset --hard c1 &&
+ test_tick &&
+ git config branch.master.mergeoptions "--ff=only" &&
+ test_must_fail git merge c2 &&
+ verify_merge file result.1 &&
+ verify_head $c1
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with c1 (--ff=only)' '
+ git reset --hard c0 &&
+ test_tick &&
+ git merge --ff=only c1 &&
+ verify_merge file result.1 &&
+ verify_head $c1
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with c0 (--ff=only)' '
+ git reset --hard c1 &&
+ test_tick &&
+ git merge --ff=only c0 &&
+ verify_merge file result.1 &&
+ verify_head $c1
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with c1 and c2 (--ff=only)' '
+ git reset --hard c0 &&
+ test_must_fail git merge --ff=only c1 c2 &&
+ verify_merge file result.0 &&
+ verify_head $c0
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with c0 (--ff=only)' '
+ git reset --hard c1 &&
+ test_tick &&
+ git merge --ff=only c0 &&
+ verify_merge file result.1 &&
+ verify_head $c1
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with c2 (--ff=only overrides --no-ff)' '
+ git reset --hard c1 &&
+ git config branch.master.mergeoptions "--no-ff" &&
+ test_tick &&
+ test_must_fail git merge c2 --ff=only &&
+ verify_merge file result.1 &&
+ verify_head $c1
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c0 with c1 (--no-ff overrides --ff=only)' '
+ git reset --hard c0 &&
+ git config branch.master.mergeoptions "--ff=only" &&
+ test_tick &&
+ git merge --no-ff c1 &&
+ verify_merge file result.1 &&
+ verify_parents $c0 $c1
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with c2 (--ff owerrides --ff=only)' '
+ git reset --hard c1 &&
+ git config branch.master.mergeoptions "--ff=only" &&
+ test_tick &&
+ git merge --ff c2 &&
+ verify_merge file result.1-5 &&
+ verify_parents $c1 $c2
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with x0 (--squash combined with --ff=only)' '
+ git reset --hard c1 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ test_must_fail git merge x0 --squash --ff=only &&
+ verify_merge file result.1 &&
+ verify_head $c1
+'
+
+test_debug 'gitk --all'
+
+
+test_expect_success 'merge x0 with c1 (--squash combined with --ff=only)' '
+ git reset --hard x0 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ test_must_fail git merge c1 --squash --ff=only &&
+ verify_merge file result.1-5 &&
+ verify_head $x0
+'
+
+test_debug 'gitk --all'
+
+
+test_expect_success 'merge c1 with c2 (--squash combined with --ff=only)' '
+ git reset --hard c1 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ test_must_fail git merge c2 --squash --ff=only &&
+ verify_merge file result.1 &&
+ verify_head $c1
+'
+
+test_debug 'gitk --all'
+
+
+test_expect_success 'merge c1 with x0 (--no-commit combined with --ff=only)' '
+ git reset --hard c1 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge x0 --no-commit --ff=only &&
+ verify_merge file result.1-5 &&
+ verify_head $x0
+'
+
+test_debug 'gitk --all'
+
+
+test_expect_success 'merge x0 with c1 (--no-commit combined with --ff=only)' '
+ git reset --hard x0 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ git merge c1 --no-commit --ff=only &&
+ verify_merge file result.1-5 &&
+ verify_head $x0
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with c2 (--no-commit combined with --ff=only)' '
+ git reset --hard c1 &&
+ git config branch.master.mergeoptions "" &&
+ test_tick &&
+ test_must_fail git merge c2 --no-commit --ff=only &&
+ verify_merge file result.1 &&
+ verify_head $c1
+'
+
+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 &&
+ test_must_fail git pull --ff=only clone refs/heads/master &&
+ verify_merge file result.5-13 &&
+ verify_head $x2
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'merge c1 with new repository (pull --ff=only)' '
+ git reset --hard c1 &&
+ test_tick &&
+ test_must_fail git pull --ff=only new refs/heads/master &&
+ verify_merge file result.1 &&
+ verify_head $c1
+'
+
+test_debug 'gitk --all'
+
test_done
--
1.5.5.1.499.g878b8
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
| Mike Travis | [RFC 00/15] x86_64: Optimize percpu accesses |
| Nick Piggin | Re: [PATCH 0 of 4] Generic AIO by scheduling stacks |
| Trent Piepho | [PATCH] [POWERPC] Improve (in|out)_beXX() asm code |
| Bart Van Assche | Integration of SCST in the mainstream Linux kernel |
git: | |
| Kevin Ballard | Re: git on MacOSX and files with decomposed utf-8 file names |
| Jon Smirl | ! [rejected] master -> master (non-fast forward) |
| Linus Torvalds | Re: kernel.org mirroring (Re: [GIT PULL] MMC update) |
| Nguyen Thai Ngoc Duy | Re: VCS comparison table |
| Leon Dippenaar | New tcp stack attack |
| Richard Stallman | Real men don't attack straw men |
| Kevin Neff | Patching a SSH 'Weakness' |
| Chris | sudo & wheel group |
| David Miller | [GIT]: Networking |
| Wang Chen | [PATCH 2/15] netdevice 82596: Convert directly reference of netdev->priv to net... |
| Valentine Barshak | [PATCH] USB: net: Fix asix read transfer buffer allocations. |
| Natalie Protasevich | [BUG] New Kernel Bugs |
