From: Elijah Newren <newren@xxxxxxxxx> The --rebase[=...] flags and the various ff flags are incompatible, except that --no-rebase (or --rebase=false) work with any of the ff flags, and --ff works with any of the rebase flags. Both sets of these flags could also be passed via configuration options, namely pull.rebase and pull.ff. As with elsewhere in git: * Make the last flag specified win * Treat command line flags as coming after any configuration options * Do not imply an order between different configuration options; if they conflict, just report an error. Signed-off-by: Elijah Newren <newren@xxxxxxxxx> --- Documentation/config/pull.txt | 3 +- Documentation/git-pull.txt | 3 ++ builtin/pull.c | 12 +++++++ t/t7601-merge-pull-config.sh | 67 +++++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 1 deletion(-) diff --git a/Documentation/config/pull.txt b/Documentation/config/pull.txt index 54048306095..e70ed99e408 100644 --- a/Documentation/config/pull.txt +++ b/Documentation/config/pull.txt @@ -7,12 +7,13 @@ pull.ff:: line). When set to `only`, only such fast-forward merges are allowed (equivalent to giving the `--ff-only` option from the command line). This setting overrides `merge.ff` when pulling. + Incompatible with pull.rebase. pull.rebase:: When true, rebase branches on top of the fetched branch, instead of merging the default branch from the default remote when "git pull" is run. See "branch.<name>.rebase" for setting this on a - per-branch basis. + per-branch basis. Incompatible with pull.ff. + When `merges` (or just 'm'), pass the `--rebase-merges` option to 'git rebase' so that the local merge commits are included in the rebase (see diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt index 5c3fb67c014..03e8694e146 100644 --- a/Documentation/git-pull.txt +++ b/Documentation/git-pull.txt @@ -121,6 +121,9 @@ When false, merge the current branch into the upstream branch. + When `interactive`, enable the interactive mode of rebase. + +Note that these flags are incompatible with --no-ff and --ff-only; if +such incompatible flags are given, the last one will take precedence. ++ See `pull.rebase`, `branch.<name>.rebase` and `branch.autoSetupRebase` in linkgit:git-config[1] if you want to make `git pull` always use `--rebase` instead of merging. diff --git a/builtin/pull.c b/builtin/pull.c index d99719403d0..b355fd38794 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -109,6 +109,11 @@ static int parse_opt_rebase(const struct option *opt, const char *arg, int unset *value = parse_config_rebase("--rebase", arg, 0); else *value = unset ? REBASE_FALSE : REBASE_TRUE; + + /* --rebase overrides earlier --ff-only and --no-ff */ + if (*value != REBASE_FALSE) + opt_ff = "--ff"; + return *value == REBASE_INVALID ? -1 : 0; } @@ -119,6 +124,10 @@ static int parse_opt_ff(const struct option *opt, const char *arg, int unset) else opt_ff = xstrfmt("--%s", opt->long_name); + /* --ff-only and --no-ff override earlier --rebase */ + if (strcmp(opt_ff, "--ff")) + opt_rebase = REBASE_FALSE; + return 0; } @@ -984,6 +993,9 @@ int cmd_pull(int argc, const char **argv, const char *prefix) if (opt_rebase < 0) opt_rebase = config_get_rebase(&rebase_unspecified); + if (opt_rebase != REBASE_FALSE && opt_ff && strcmp(opt_ff, "--ff")) + die(_("pull.rebase and pull.ff are incompatible; please unset one")); + if (read_cache_unmerged()) die_resolve_conflict("pull"); diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh index 52e8ccc933a..73a0dbdf25a 100755 --- a/t/t7601-merge-pull-config.sh +++ b/t/t7601-merge-pull-config.sh @@ -143,6 +143,73 @@ test_expect_success 'pull.rebase not set and --ff-only given (not-fast-forward)' test_i18ngrep ! "Pulling without specifying how to reconcile" err ' +test_does_rebase() { + git reset --hard c2 && + git "$@" . c1 && + # Check that we actually did a rebase + git rev-list --count HEAD >actual && + git rev-list --merges --count HEAD >>actual && + test_write_lines 3 0 >expect && + test_cmp expect actual && + rm actual expect +} + +test_does_merge() { + git reset --hard c2 && + git "$@" . c1 && + # Check that we actually did a merge + git rev-list --count HEAD >actual && + git rev-list --merges --count HEAD >>actual && + test_write_lines 4 1 >expect && + test_cmp expect actual && + rm actual expect +} + +test_attempts_fast_forward() { + git reset --hard c2 && + test_must_fail git "$@" . c1 2>err && + test_i18ngrep "Not possible to fast-forward, aborting" err +} + +test_expect_success 'conflicting options: --ff-only --rebase' ' + test_does_rebase pull --ff-only --rebase +' + +test_expect_success 'conflicting options: --no-ff --rebase' ' + test_does_rebase pull --no-ff --rebase +' + +test_expect_success 'conflicting options: -c pull.ff=false --rebase' ' + test_does_rebase -c pull.ff=false pull --rebase +' + +test_expect_success 'conflicting options: -c pull.ff=only --rebase' ' + test_does_rebase -c pull.ff=only pull --rebase +' + +test_expect_success 'conflicting options: --rebase --ff-only' ' + test_attempts_fast_forward pull --rebase --ff-only +' + +test_expect_success 'conflicting options: --rebase --no-ff' ' + test_does_merge pull --rebase --no-ff +' + +test_expect_success 'conflicting options: -c pull.rebase=true --no-ff' ' + test_does_merge -c pull.rebase=true pull --no-ff +' + +test_expect_success 'conflicting options: -c pull.rebase=true --ff-only' ' + test_attempts_fast_forward -c pull.rebase=true pull --ff-only +' + +test_expect_success 'report conflicting configuration' ' + git reset --hard c2 && + test_must_fail git -c pull.ff=false -c pull.rebase=true pull . c1 2>err && + test_i18ngrep "pull.rebase and pull.ff are incompatible; please unset one" err + +' + test_expect_success 'merge c1 with c2' ' git reset --hard c1 && test -f c0.c && -- gitgitgadget