Merge branch 'ah/rebase-merges-config'
Streamline --rebase-merges command line option handling and introduce rebase.merges configuration variable. * ah/rebase-merges-config: rebase: add a config option for --rebase-merges rebase: deprecate --rebase-merges="" rebase: add documentation and test for --no-rebase-merges
This commit is contained in:
commit
9142fce9b0
@ -67,3 +67,13 @@ rebase.rescheduleFailedExec::
|
||||
|
||||
rebase.forkPoint::
|
||||
If set to false set `--no-fork-point` option by default.
|
||||
|
||||
rebase.rebaseMerges::
|
||||
Whether and how to set the `--rebase-merges` option by default. Can
|
||||
be `rebase-cousins`, `no-rebase-cousins`, or a boolean. Setting to
|
||||
true or to `no-rebase-cousins` is equivalent to
|
||||
`--rebase-merges=no-rebase-cousins`, setting to `rebase-cousins` is
|
||||
equivalent to `--rebase-merges=rebase-cousins`, and setting to false is
|
||||
equivalent to `--no-rebase-merges`. Passing `--rebase-merges` on the
|
||||
command line, with or without an argument, overrides any
|
||||
`rebase.rebaseMerges` configuration.
|
||||
|
@ -529,20 +529,25 @@ See also INCOMPATIBLE OPTIONS below.
|
||||
|
||||
-r::
|
||||
--rebase-merges[=(rebase-cousins|no-rebase-cousins)]::
|
||||
--no-rebase-merges::
|
||||
By default, a rebase will simply drop merge commits from the todo
|
||||
list, and put the rebased commits into a single, linear branch.
|
||||
With `--rebase-merges`, the rebase will instead try to preserve
|
||||
the branching structure within the commits that are to be rebased,
|
||||
by recreating the merge commits. Any resolved merge conflicts or
|
||||
manual amendments in these merge commits will have to be
|
||||
resolved/re-applied manually.
|
||||
resolved/re-applied manually. `--no-rebase-merges` can be used to
|
||||
countermand both the `rebase.rebaseMerges` config option and a previous
|
||||
`--rebase-merges`.
|
||||
+
|
||||
By default, or when `no-rebase-cousins` was specified, commits which do not
|
||||
have `<upstream>` as direct ancestor will keep their original branch point,
|
||||
i.e. commits that would be excluded by linkgit:git-log[1]'s
|
||||
`--ancestry-path` option will keep their original ancestry by default. If
|
||||
the `rebase-cousins` mode is turned on, such commits are instead rebased
|
||||
onto `<upstream>` (or `<onto>`, if specified).
|
||||
When rebasing merges, there are two modes: `rebase-cousins` and
|
||||
`no-rebase-cousins`. If the mode is not specified, it defaults to
|
||||
`no-rebase-cousins`. In `no-rebase-cousins` mode, commits which do not have
|
||||
`<upstream>` as direct ancestor will keep their original branch point, i.e.
|
||||
commits that would be excluded by linkgit:git-log[1]'s `--ancestry-path`
|
||||
option will keep their original ancestry by default. In `rebase-cousins` mode,
|
||||
such commits are instead rebased onto `<upstream>` (or `<onto>`, if
|
||||
specified).
|
||||
+
|
||||
It is currently only possible to recreate the merge commits using the
|
||||
`ort` merge strategy; different merge strategies can be used only via
|
||||
|
@ -124,6 +124,7 @@ struct rebase_options {
|
||||
int fork_point;
|
||||
int update_refs;
|
||||
int config_autosquash;
|
||||
int config_rebase_merges;
|
||||
int config_update_refs;
|
||||
};
|
||||
|
||||
@ -141,6 +142,8 @@ struct rebase_options {
|
||||
.allow_empty_message = 1, \
|
||||
.autosquash = -1, \
|
||||
.config_autosquash = -1, \
|
||||
.rebase_merges = -1, \
|
||||
.config_rebase_merges = -1, \
|
||||
.update_refs = -1, \
|
||||
.config_update_refs = -1, \
|
||||
}
|
||||
@ -772,6 +775,16 @@ static int run_specific_rebase(struct rebase_options *opts)
|
||||
return status ? -1 : 0;
|
||||
}
|
||||
|
||||
static void parse_rebase_merges_value(struct rebase_options *options, const char *value)
|
||||
{
|
||||
if (!strcmp("no-rebase-cousins", value))
|
||||
options->rebase_cousins = 0;
|
||||
else if (!strcmp("rebase-cousins", value))
|
||||
options->rebase_cousins = 1;
|
||||
else
|
||||
die(_("Unknown rebase-merges mode: %s"), value);
|
||||
}
|
||||
|
||||
static int rebase_config(const char *var, const char *value, void *data)
|
||||
{
|
||||
struct rebase_options *opts = data;
|
||||
@ -801,6 +814,17 @@ static int rebase_config(const char *var, const char *value, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "rebase.rebasemerges")) {
|
||||
opts->config_rebase_merges = git_parse_maybe_bool(value);
|
||||
if (opts->config_rebase_merges < 0) {
|
||||
opts->config_rebase_merges = 1;
|
||||
parse_rebase_merges_value(opts, value);
|
||||
} else {
|
||||
opts->rebase_cousins = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "rebase.updaterefs")) {
|
||||
opts->config_update_refs = git_config_bool(var, value);
|
||||
return 0;
|
||||
@ -981,6 +1005,28 @@ static int parse_opt_empty(const struct option *opt, const char *arg, int unset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_opt_rebase_merges(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct rebase_options *options = opt->value;
|
||||
|
||||
options->rebase_merges = !unset;
|
||||
options->rebase_cousins = 0;
|
||||
|
||||
if (arg) {
|
||||
if (!*arg) {
|
||||
warning(_("--rebase-merges with an empty string "
|
||||
"argument is deprecated and will stop "
|
||||
"working in a future version of Git. Use "
|
||||
"--rebase-merges without an argument "
|
||||
"instead, which does the same thing."));
|
||||
return 0;
|
||||
}
|
||||
parse_rebase_merges_value(options, arg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void NORETURN error_on_missing_default_upstream(void)
|
||||
{
|
||||
struct branch *current_branch = branch_get(NULL);
|
||||
@ -1036,7 +1082,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
|
||||
struct object_id branch_base;
|
||||
int ignore_whitespace = 0;
|
||||
const char *gpg_sign = NULL;
|
||||
const char *rebase_merges = NULL;
|
||||
struct string_list strategy_options = STRING_LIST_INIT_NODUP;
|
||||
struct object_id squash_onto;
|
||||
char *squash_onto_name = NULL;
|
||||
@ -1138,10 +1183,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
|
||||
&options.allow_empty_message,
|
||||
N_("allow rebasing commits with empty messages"),
|
||||
PARSE_OPT_HIDDEN),
|
||||
{OPTION_STRING, 'r', "rebase-merges", &rebase_merges,
|
||||
N_("mode"),
|
||||
OPT_CALLBACK_F('r', "rebase-merges", &options, N_("mode"),
|
||||
N_("try to rebase merges instead of skipping them"),
|
||||
PARSE_OPT_OPTARG, NULL, (intptr_t)""},
|
||||
PARSE_OPT_OPTARG, parse_opt_rebase_merges),
|
||||
OPT_BOOL(0, "fork-point", &options.fork_point,
|
||||
N_("use 'merge-base --fork-point' to refine upstream")),
|
||||
OPT_STRING('s', "strategy", &options.strategy,
|
||||
@ -1437,17 +1481,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
|
||||
if (options.exec.nr)
|
||||
imply_merge(&options, "--exec");
|
||||
|
||||
if (rebase_merges) {
|
||||
if (!*rebase_merges)
|
||||
; /* default mode; do nothing */
|
||||
else if (!strcmp("rebase-cousins", rebase_merges))
|
||||
options.rebase_cousins = 1;
|
||||
else if (strcmp("no-rebase-cousins", rebase_merges))
|
||||
die(_("Unknown mode: %s"), rebase_merges);
|
||||
options.rebase_merges = 1;
|
||||
imply_merge(&options, "--rebase-merges");
|
||||
}
|
||||
|
||||
if (options.type == REBASE_APPLY) {
|
||||
if (ignore_whitespace)
|
||||
strvec_push(&options.git_am_opts,
|
||||
@ -1515,6 +1548,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
|
||||
"cannot be used together"));
|
||||
else if (options.autosquash == -1 && options.config_autosquash == 1)
|
||||
die(_("apply options are incompatible with rebase.autoSquash. Consider adding --no-autosquash"));
|
||||
else if (options.rebase_merges == -1 && options.config_rebase_merges == 1)
|
||||
die(_("apply options are incompatible with rebase.rebaseMerges. Consider adding --no-rebase-merges"));
|
||||
else if (options.update_refs == -1 && options.config_update_refs == 1)
|
||||
die(_("apply options are incompatible with rebase.updateRefs. Consider adding --no-update-refs"));
|
||||
else
|
||||
@ -1527,6 +1562,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
|
||||
options.update_refs = (options.update_refs >= 0) ? options.update_refs :
|
||||
((options.config_update_refs >= 0) ? options.config_update_refs : 0);
|
||||
|
||||
if (options.rebase_merges == 1)
|
||||
imply_merge(&options, "--rebase-merges");
|
||||
options.rebase_merges = (options.rebase_merges >= 0) ? options.rebase_merges :
|
||||
((options.config_rebase_merges >= 0) ? options.config_rebase_merges : 0);
|
||||
|
||||
if (options.autosquash == 1)
|
||||
imply_merge(&options, "--autosquash");
|
||||
options.autosquash = (options.autosquash >= 0) ? options.autosquash :
|
||||
|
@ -85,6 +85,11 @@ test_rebase_am_only () {
|
||||
test_must_fail git rebase $opt --reapply-cherry-picks A
|
||||
"
|
||||
|
||||
test_expect_success "$opt incompatible with --rebase-merges" "
|
||||
git checkout B^0 &&
|
||||
test_must_fail git rebase $opt --rebase-merges A
|
||||
"
|
||||
|
||||
test_expect_success "$opt incompatible with --update-refs" "
|
||||
git checkout B^0 &&
|
||||
test_must_fail git rebase $opt --update-refs A
|
||||
@ -101,6 +106,12 @@ test_rebase_am_only () {
|
||||
grep -e --no-autosquash err
|
||||
"
|
||||
|
||||
test_expect_success "$opt incompatible with rebase.rebaseMerges" "
|
||||
git checkout B^0 &&
|
||||
test_must_fail git -c rebase.rebaseMerges=true rebase $opt A 2>err &&
|
||||
grep -e --no-rebase-merges err
|
||||
"
|
||||
|
||||
test_expect_success "$opt incompatible with rebase.updateRefs" "
|
||||
git checkout B^0 &&
|
||||
test_must_fail git -c rebase.updateRefs=true rebase $opt A 2>err &&
|
||||
@ -113,6 +124,12 @@ test_rebase_am_only () {
|
||||
git -c rebase.autosquash=true rebase --no-autosquash $opt A
|
||||
"
|
||||
|
||||
test_expect_success "$opt okay with overridden rebase.rebaseMerges" "
|
||||
test_when_finished \"git reset --hard B^0\" &&
|
||||
git checkout B^0 &&
|
||||
git -c rebase.rebaseMerges=true rebase --no-rebase-merges $opt A
|
||||
"
|
||||
|
||||
test_expect_success "$opt okay with overridden rebase.updateRefs" "
|
||||
test_when_finished \"git reset --hard B^0\" &&
|
||||
git checkout B^0 &&
|
||||
|
@ -250,6 +250,16 @@ test_expect_success 'with a branch tip that was cherry-picked already' '
|
||||
EOF
|
||||
'
|
||||
|
||||
test_expect_success '--no-rebase-merges countermands --rebase-merges' '
|
||||
git checkout -b no-rebase-merges E &&
|
||||
git rebase --rebase-merges --no-rebase-merges C &&
|
||||
test_cmp_graph C.. <<-\EOF
|
||||
* B
|
||||
* D
|
||||
o C
|
||||
EOF
|
||||
'
|
||||
|
||||
test_expect_success 'do not rebase cousins unless asked for' '
|
||||
git checkout -b cousins main &&
|
||||
before="$(git rev-parse --verify HEAD)" &&
|
||||
@ -268,6 +278,40 @@ test_expect_success 'do not rebase cousins unless asked for' '
|
||||
EOF
|
||||
'
|
||||
|
||||
test_expect_success 'rebase.rebaseMerges=rebase-cousins is equivalent to --rebase-merges=rebase-cousins' '
|
||||
test_config rebase.rebaseMerges rebase-cousins &&
|
||||
git checkout -b config-rebase-cousins main &&
|
||||
git rebase HEAD^ &&
|
||||
test_cmp_graph HEAD^.. <<-\EOF
|
||||
* Merge the topic branch '\''onebranch'\''
|
||||
|\
|
||||
| * D
|
||||
| * G
|
||||
|/
|
||||
o H
|
||||
EOF
|
||||
'
|
||||
|
||||
test_expect_success '--no-rebase-merges overrides rebase.rebaseMerges=no-rebase-cousins' '
|
||||
test_config rebase.rebaseMerges no-rebase-cousins &&
|
||||
git checkout -b override-config-no-rebase-cousins E &&
|
||||
git rebase --no-rebase-merges C &&
|
||||
test_cmp_graph C.. <<-\EOF
|
||||
* B
|
||||
* D
|
||||
o C
|
||||
EOF
|
||||
'
|
||||
|
||||
test_expect_success '--rebase-merges overrides rebase.rebaseMerges=rebase-cousins' '
|
||||
test_config rebase.rebaseMerges rebase-cousins &&
|
||||
git checkout -b override-config-rebase-cousins E &&
|
||||
before="$(git rev-parse --verify HEAD)" &&
|
||||
test_tick &&
|
||||
git rebase --rebase-merges C &&
|
||||
test_cmp_rev HEAD $before
|
||||
'
|
||||
|
||||
test_expect_success 'refs/rewritten/* is worktree-local' '
|
||||
git worktree add wt &&
|
||||
cat >wt/script-from-scratch <<-\EOF &&
|
||||
|
Loading…
Reference in New Issue
Block a user