pull: accept --rebase=merges to recreate the branch topology

Similar to the `preserve` mode simply passing the `--preserve-merges`
option to the `rebase` command, the `merges` mode simply passes the
`--rebase-merges` option.

This will allow users to conveniently rebase non-trivial commit
topologies when pulling new commits, without flattening them.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Johannes Schindelin 2018-04-25 14:29:38 +02:00 committed by Junio C Hamano
parent 7ccdf65b63
commit 1131ec9818
5 changed files with 38 additions and 10 deletions

View File

@ -1058,6 +1058,10 @@ branch.<name>.rebase::
"git pull" is run. See "pull.rebase" for doing this in a non "git pull" is run. See "pull.rebase" for doing this in a non
branch-specific manner. branch-specific manner.
+ +
When `merges`, pass the `--rebase-merges` option to 'git rebase'
so that the local merge commits are included in the rebase (see
linkgit:git-rebase[1] for details).
+
When preserve, also pass `--preserve-merges` along to 'git rebase' When preserve, also pass `--preserve-merges` along to 'git rebase'
so that locally committed merge commits will not be flattened so that locally committed merge commits will not be flattened
by running 'git pull'. by running 'git pull'.
@ -2617,6 +2621,10 @@ pull.rebase::
pull" is run. See "branch.<name>.rebase" for setting this on a pull" is run. See "branch.<name>.rebase" for setting this on a
per-branch basis. per-branch basis.
+ +
When `merges`, pass the `--rebase-merges` option to 'git rebase'
so that the local merge commits are included in the rebase (see
linkgit:git-rebase[1] for details).
+
When preserve, also pass `--preserve-merges` along to 'git rebase' When preserve, also pass `--preserve-merges` along to 'git rebase'
so that locally committed merge commits will not be flattened so that locally committed merge commits will not be flattened
by running 'git pull'. by running 'git pull'.

View File

@ -101,13 +101,17 @@ Options related to merging
include::merge-options.txt[] include::merge-options.txt[]
-r:: -r::
--rebase[=false|true|preserve|interactive]:: --rebase[=false|true|merges|preserve|interactive]::
When true, rebase the current branch on top of the upstream When true, rebase the current branch on top of the upstream
branch after fetching. If there is a remote-tracking branch branch after fetching. If there is a remote-tracking branch
corresponding to the upstream branch and the upstream branch corresponding to the upstream branch and the upstream branch
was rebased since last fetched, the rebase uses that information was rebased since last fetched, the rebase uses that information
to avoid rebasing non-local changes. to avoid rebasing non-local changes.
+ +
When set to `merges`, rebase using `git rebase --rebase-merges` so that
the local merge commits are included in the rebase (see
linkgit:git-rebase[1] for details).
+
When set to preserve, rebase with the `--preserve-merges` option passed When set to preserve, rebase with the `--preserve-merges` option passed
to `git rebase` so that locally created merge commits will not be flattened. to `git rebase` so that locally created merge commits will not be flattened.
+ +

View File

@ -27,14 +27,16 @@ enum rebase_type {
REBASE_FALSE = 0, REBASE_FALSE = 0,
REBASE_TRUE, REBASE_TRUE,
REBASE_PRESERVE, REBASE_PRESERVE,
REBASE_MERGES,
REBASE_INTERACTIVE REBASE_INTERACTIVE
}; };
/** /**
* Parses the value of --rebase. If value is a false value, returns * Parses the value of --rebase. If value is a false value, returns
* REBASE_FALSE. If value is a true value, returns REBASE_TRUE. If value is * REBASE_FALSE. If value is a true value, returns REBASE_TRUE. If value is
* "preserve", returns REBASE_PRESERVE. If value is a invalid value, dies with * "merges", returns REBASE_MERGES. If value is "preserve", returns
* a fatal error if fatal is true, otherwise returns REBASE_INVALID. * REBASE_PRESERVE. If value is a invalid value, dies with a fatal error if
* fatal is true, otherwise returns REBASE_INVALID.
*/ */
static enum rebase_type parse_config_rebase(const char *key, const char *value, static enum rebase_type parse_config_rebase(const char *key, const char *value,
int fatal) int fatal)
@ -47,6 +49,8 @@ static enum rebase_type parse_config_rebase(const char *key, const char *value,
return REBASE_TRUE; return REBASE_TRUE;
else if (!strcmp(value, "preserve")) else if (!strcmp(value, "preserve"))
return REBASE_PRESERVE; return REBASE_PRESERVE;
else if (!strcmp(value, "merges"))
return REBASE_MERGES;
else if (!strcmp(value, "interactive")) else if (!strcmp(value, "interactive"))
return REBASE_INTERACTIVE; return REBASE_INTERACTIVE;
@ -130,7 +134,7 @@ static struct option pull_options[] = {
/* Options passed to git-merge or git-rebase */ /* Options passed to git-merge or git-rebase */
OPT_GROUP(N_("Options related to merging")), OPT_GROUP(N_("Options related to merging")),
{ OPTION_CALLBACK, 'r', "rebase", &opt_rebase, { OPTION_CALLBACK, 'r', "rebase", &opt_rebase,
"false|true|preserve|interactive", "false|true|merges|preserve|interactive",
N_("incorporate changes by rebasing rather than merging"), N_("incorporate changes by rebasing rather than merging"),
PARSE_OPT_OPTARG, parse_opt_rebase }, PARSE_OPT_OPTARG, parse_opt_rebase },
OPT_PASSTHRU('n', NULL, &opt_diffstat, NULL, OPT_PASSTHRU('n', NULL, &opt_diffstat, NULL,
@ -800,7 +804,9 @@ static int run_rebase(const struct object_id *curr_head,
argv_push_verbosity(&args); argv_push_verbosity(&args);
/* Options passed to git-rebase */ /* Options passed to git-rebase */
if (opt_rebase == REBASE_PRESERVE) if (opt_rebase == REBASE_MERGES)
argv_array_push(&args, "--rebase-merges");
else if (opt_rebase == REBASE_PRESERVE)
argv_array_push(&args, "--preserve-merges"); argv_array_push(&args, "--preserve-merges");
else if (opt_rebase == REBASE_INTERACTIVE) else if (opt_rebase == REBASE_INTERACTIVE)
argv_array_push(&args, "--interactive"); argv_array_push(&args, "--interactive");

View File

@ -245,7 +245,9 @@ static int add(int argc, const char **argv)
struct branch_info { struct branch_info {
char *remote_name; char *remote_name;
struct string_list merge; struct string_list merge;
enum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase; enum {
NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE, REBASE_MERGES
} rebase;
}; };
static struct string_list branch_list = STRING_LIST_INIT_NODUP; static struct string_list branch_list = STRING_LIST_INIT_NODUP;
@ -306,6 +308,8 @@ static int config_read_branches(const char *key, const char *value, void *cb)
info->rebase = v; info->rebase = v;
else if (!strcmp(value, "preserve")) else if (!strcmp(value, "preserve"))
info->rebase = NORMAL_REBASE; info->rebase = NORMAL_REBASE;
else if (!strcmp(value, "merges"))
info->rebase = REBASE_MERGES;
else if (!strcmp(value, "interactive")) else if (!strcmp(value, "interactive"))
info->rebase = INTERACTIVE_REBASE; info->rebase = INTERACTIVE_REBASE;
} }
@ -963,9 +967,15 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
printf(" %-*s ", show_info->width, item->string); printf(" %-*s ", show_info->width, item->string);
if (branch_info->rebase) { if (branch_info->rebase) {
printf_ln(branch_info->rebase == INTERACTIVE_REBASE const char *msg;
? _("rebases interactively onto remote %s") if (branch_info->rebase == INTERACTIVE_REBASE)
: _("rebases onto remote %s"), merge->items[0].string); msg = _("rebases interactively onto remote %s");
else if (branch_info->rebase == REBASE_MERGES)
msg = _("rebases interactively (with merges) onto "
"remote %s");
else
msg = _("rebases onto remote %s");
printf_ln(msg, merge->items[0].string);
return 0; return 0;
} else if (show_info->any_rebase) { } else if (show_info->any_rebase) {
printf_ln(_(" merges with remote %s"), merge->items[0].string); printf_ln(_(" merges with remote %s"), merge->items[0].string);

View File

@ -2115,7 +2115,7 @@ _git_config ()
return return
;; ;;
branch.*.rebase) branch.*.rebase)
__gitcomp "false true preserve interactive" __gitcomp "false true merges preserve interactive"
return return
;; ;;
remote.pushdefault) remote.pushdefault)