Teach 'git merge' and 'git pull' the option --ff-only
PATCH 1/1 Teach 'git merge' and 'git pull' the option --ff-only
For convenience in scripts and aliases, add the option --ff-only to only allow fast-forwards (and up-to-date, despite the name).
Disallow combining --ff-only and --no-ff, since they flatly contradict each other.
Allow all other options to be combined with --ff-only (i.e. do not add any code to handle them specially), including the following options:
* --strategy (one or more): As long as the chosen merge strategy results in up-to-date or fast-forward, the command will succeed.
* --squash: I cannot imagine why anyone would want to squash commits only if fast-forward is possible, but I also see no reason why it should not be allowed.
* --message: The message will always be ignored, but I see no need to explicitly disallow providing a redundant message.
Acknowledgements: I did look at Yuval Kogman's earlier patch (107768 in gmane), mainly as shortcut to find my way in the code, but I did not copy anything directly.
---
Here is a re-roll of my previous patch with improvements suggested by Junio's review. Compared to the previous version, I have changed the following:
* The documentation now clearly states that up-to-date is also allowed.
* The redundant and incorrect test to reject merge strategies that do not allow fast-forward has been removed (along with the corresponding test case).
* I have added some background on the design decisions to the commit message.
* I have added two test cases to test --squash in combination with --ff-only.
Documentation/merge-options.txt | 5 ++++ builtin-merge.c | 11 +++++++++- git-pull.sh | 7 ++++- t/t7600-merge.sh | 41 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 3 deletions(-)
Documentation/merge-options.txt +5 -0
@@ -60,6 +60,11 @@ a fast-forward, only update the branch pointer. This is the default behavior of git-merge. +--ff-only:: + Refuse to merge and exit with a non-zero status unless the + current `HEAD` is already up-to-date or the merge can be + resolved as a fast-forward. + -s <strategy>:: --strategy=<strategy>:: Use the given merge strategy; can be supplied more than
builtin-merge.c +10 -1
@@ -43,6 +43,7 @@ static const char * const builtin_merge_usage[] = {static int show_diffstat =1 , option_log, squash;static int option_commit =1 , allow_fast_forward =1 ; +static int fast_forward_only;static int allow_trivial =1 , have_message;static struct strbuf merge_msg;static struct commit_list *remoteheads;
@@ -167,6 +168,8 @@ static struct option builtin_merge_options[] = { "perform a commit if the merge succeeds (default)"),OPT_BOOLEAN (0 ,"ff" , &allow_fast_forward,"allow fast forward (default)" ), +OPT_BOOLEAN (0 ,"ff-only" , &fast_forward_only, +"abort if fast forward is not possible" ),OPT_CALLBACK ('s' ,"strategy" , &use_strategies,"strategy" ,"merge strategy to use" , option_parse_strategy), OPT_CALLBACK('m', "message", &merge_msg, "message",
@@ -874,6 +877,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix) option_commit =0 ; } +if (!allow_fast_forward && fast_forward_only) +die ("You cannot combine --no-ff with --ff-only." ); +if (!argc)usage_with_options (builtin_merge_usage, builtin_merge_options);
@@ -1040,7 +1046,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)* only one common. */ refresh_cache (REFRESH_QUIET ); -if (allow_trivial) { +if (allow_trivial && !fast_forward_only) {/* See if it is really trivial. */ git_committer_info (IDENT_ERROR_ON_NO_NAME );printf ("Trying really trivial in-index merge...\n" );
@@ -1079,6 +1085,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix) } } +if (fast_forward_only) +die ("Not possible to fast forward, aborting." ); +/* We are going to make a new commit. */ git_committer_info (IDENT_ERROR_ON_NO_NAME );
git-pull.sh +5 -2
@@ -16,7 +16,8 @@ cd_to_toplevel test -z "$(git ls-files -u)" || die "You are in the middle of a conflicted merge." -strategy_args= diffstat= no_commit= squash= no_ff= log_arg= verbosity= +strategy_args= diffstat= no_commit= squash= no_ff= ff_only= +log_arg= verbosity= curr_branch=$(git symbolic-ref -q HEAD) curr_branch_short=$(echo "$curr_branch" | sed "s|refs/heads/||") rebase=$(git config --bool branch.$curr_branch_short.rebase)
@@ -45,6 +46,8 @@ do no_ff=--ff ;; --no-ff) no_ff=--no-ff ;; + --ff-only) + ff_only=--ff-only ;; -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\ --strateg=*|--strategy=*|\ -s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy)
@@ -215,5 +218,5 @@ merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit test true = "$rebase" && exec git-rebase $diffstat $strategy_args --onto $merge_head \ ${oldremoteref:-$merge_head} -exec git-merge $diffstat $no_commit $squash $no_ff $log_arg $strategy_args \ +exec git-merge $diffstat $no_commit $squash $no_ff $ff_only $log_arg $strategy_args \ "$merge_name" HEAD $merge_head $verbosity
t/t7600-merge.sh +41 -0
71 lines not on this page · raw message
Signature · 1 line
1.6.5.1.69.g36942