git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Alex Henrie <alexhenrie24@gmail.com>
To: git@vger.kernel.org, tao@klerks.biz, gitster@pobox.com,
	newren@gmail.com, phillip.wood123@gmail.com,
	Johannes.Schindelin@gmx.de, sorganov@gmail.com,
	chooglen@google.com, calvinwan@google.com,
	jonathantanmy@google.com
Cc: Alex Henrie <alexhenrie24@gmail.com>
Subject: [PATCH v7 3/3] rebase: add a config option for --rebase-merges
Date: Sun, 12 Mar 2023 15:04:56 -0600	[thread overview]
Message-ID: <20230312210456.92364-4-alexhenrie24@gmail.com> (raw)
In-Reply-To: <20230312210456.92364-1-alexhenrie24@gmail.com>

The purpose of the new option is to accommodate users who would like
--rebase-merges to be on by default and to facilitate turning on
--rebase-merges by default without configuration in a future version of
Git.

Name the new option rebase.rebaseMerges, even though it is a little
redundant, for consistency with the name of the command line option and
to be clear when scrolling through values in the [rebase] section of
.gitconfig.

In the future, the default rebase-merges mode may change from
no-rebase-cousins to some other mode that doesn't exist yet. Support
setting rebase.rebaseMerges to the nonspecific value "true" for users
who do not need or want to care about the default changing in the
future. Similarly, for users who have --rebase-merges in an alias and
want to get the future behavior now, use the specific rebase-merges mode
from the config if a specific mode is not given on the command line.

Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
---
 Documentation/config/rebase.txt        | 11 ++++
 Documentation/git-rebase.txt           | 18 +++---
 builtin/rebase.c                       | 80 ++++++++++++++++++--------
 t/t3422-rebase-incompatible-options.sh | 17 ++++++
 t/t3430-rebase-merges.sh               | 48 ++++++++++++++++
 5 files changed, 143 insertions(+), 31 deletions(-)

diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
index f19bd0e040..98e8f193d4 100644
--- a/Documentation/config/rebase.txt
+++ b/Documentation/config/rebase.txt
@@ -67,3 +67,14 @@ 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 without an argument overrides a `rebase.rebaseMerges=false`
+	configuration, but the absence of a specific rebase-merges mode on the
+	command line does not counteract a specific mode set in the configuration.
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 4e57a87624..7ff02f474b 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -537,16 +537,18 @@ See also INCOMPATIBLE OPTIONS below.
 	by recreating the merge commits. Any resolved merge conflicts or
 	manual amendments in these merge commits will have to be
 	resolved/re-applied manually. `--no-rebase-merges` can be used to
-	countermand a previous `--rebase-merges`.
+	countermand both the `rebase.rebaseMerges` config option and a previous
+	`--rebase-merges`.
 +
 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).
+`no-rebase-cousins`. If the mode is not specified on the command line or in
+the `rebase.rebaseMerges` config option (see linkgit:git-config[1] or
+"CONFIGURATION" below), 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
diff --git a/builtin/rebase.c b/builtin/rebase.c
index c36ddc0050..593db9e53f 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -123,6 +123,7 @@ struct rebase_options {
 	int fork_point;
 	int update_refs;
 	int config_autosquash;
+	int config_rebase_merges;
 	int config_update_refs;
 };
 
@@ -140,6 +141,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,               \
 	}
@@ -771,6 +774,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;
@@ -800,6 +813,16 @@ 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;
@@ -980,6 +1003,27 @@ 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;
+
+	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);
@@ -1035,7 +1079,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;
@@ -1137,10 +1180,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)"no-rebase-cousins"},
+			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,
@@ -1436,21 +1478,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)
-			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."));
-		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,
@@ -1513,13 +1540,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 				break;
 
 		if (i >= 0 || options.type == REBASE_APPLY) {
-			if (is_merge(&options))
-				die(_("apply options and merge options "
-					  "cannot be used together"));
-			else if (options.autosquash == -1 && options.config_autosquash == 1)
+			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 if (is_merge(&options))
+				die(_("apply options and merge options "
+					  "cannot be used together"));
 			else
 				options.type = REBASE_APPLY;
 		}
@@ -1530,6 +1559,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 :
diff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh
index 4711b37a28..2eba00bdf5 100755
--- a/t/t3422-rebase-incompatible-options.sh
+++ b/t/t3422-rebase-incompatible-options.sh
@@ -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 &&
diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh
index d46d9545f2..a8d9297224 100755
--- a/t/t3430-rebase-merges.sh
+++ b/t/t3430-rebase-merges.sh
@@ -278,6 +278,54 @@ 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=false' '
+	test_config rebase.rebaseMerges false &&
+	git checkout -b override-config-merges-false E &&
+	before="$(git rev-parse --verify HEAD)" &&
+	test_tick &&
+	git rebase --rebase-merges C &&
+	test_cmp_rev HEAD $before
+'
+
+test_expect_success '--rebase-merges does not override rebase.rebaseMerges=rebase-cousins' '
+	test_config rebase.rebaseMerges rebase-cousins &&
+	git checkout -b no-override-config-rebase-cousins main &&
+	git rebase --rebase-merges HEAD^ &&
+	test_cmp_graph HEAD^.. <<-\EOF
+	*   Merge the topic branch '\''onebranch'\''
+	|\
+	| * D
+	| * G
+	|/
+	o H
+	EOF
+'
+
 test_expect_success 'refs/rewritten/* is worktree-local' '
 	git worktree add wt &&
 	cat >wt/script-from-scratch <<-\EOF &&
-- 
2.39.2


  parent reply	other threads:[~2023-03-12 21:07 UTC|newest]

Thread overview: 96+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-23  5:34 [PATCH v4 1/3] rebase: add documentation and test for --no-rebase-merges Alex Henrie
2023-02-23  5:34 ` [PATCH v4 2/3] rebase: stop accepting --rebase-merges="" Alex Henrie
2023-02-24 13:54   ` Johannes Schindelin
2023-02-24 17:20     ` Junio C Hamano
2023-02-24 17:50       ` Alex Henrie
2023-02-24 18:08         ` Junio C Hamano
2023-02-24 18:23           ` Alex Henrie
2023-02-24 18:40             ` Junio C Hamano
2023-02-24 18:55               ` Alex Henrie
2023-02-24 19:13                 ` Junio C Hamano
2023-02-24 19:24                   ` Alex Henrie
2023-02-24 19:24                   ` Phillip Wood
2023-02-24 19:56                     ` Alex Henrie
2023-02-23  5:34 ` [PATCH v4 3/3] rebase: add a config option for --rebase-merges Alex Henrie
2023-02-24 13:53   ` Johannes Schindelin
2023-02-24 17:49     ` Alex Henrie
2023-02-24 14:55   ` Phillip Wood
2023-02-24 17:51     ` Alex Henrie
2023-02-23 17:28 ` [PATCH v4 1/3] rebase: add documentation and test for --no-rebase-merges Junio C Hamano
2023-02-24 13:57   ` Johannes Schindelin
2023-02-24 19:16     ` Junio C Hamano
2023-02-25 18:09     ` Alex Henrie
2023-02-25 18:03 ` [PATCH v5 0/3] rebase: add a config option for --rebase-merges Alex Henrie
2023-02-25 18:03   ` [PATCH v5 1/3] rebase: add documentation and test for --no-rebase-merges Alex Henrie
2023-03-01 23:23     ` Glen Choo
2023-02-25 18:03   ` [PATCH v5 2/3] rebase: deprecate --rebase-merges="" Alex Henrie
2023-03-01 23:46     ` Glen Choo
2023-03-02 10:07     ` Phillip Wood
2023-03-02 18:02     ` Calvin Wan
2023-02-25 18:03   ` [PATCH v5 3/3] rebase: add a config option for --rebase-merges Alex Henrie
2023-03-01 23:43     ` Glen Choo
2023-03-02  9:37     ` Phillip Wood
2023-03-04 23:24       ` Alex Henrie
2023-03-07 16:23         ` Phillip Wood
2023-03-12 20:57           ` Alex Henrie
2023-03-13 14:20             ` Phillip Wood
2023-03-13 16:12               ` Felipe Contreras
2023-03-13 19:46             ` Junio C Hamano
2023-03-24 14:47             ` About replaying "evil" merges... " Johannes Schindelin
2023-03-02 18:02     ` Calvin Wan
2023-03-04 23:24       ` Alex Henrie
2023-03-01 23:14   ` [PATCH v5 0/3] " Glen Choo
2023-03-02  5:02     ` Alex Henrie
2023-03-02  5:09       ` Alex Henrie
2023-03-05  5:07   ` [PATCH v6 0/3] rebase: document, clean up, and introduce " Alex Henrie
2023-03-05  5:07     ` [PATCH v6 1/3] rebase: add documentation and test for --no-rebase-merges Alex Henrie
2023-03-08 22:25       ` Sergey Organov
2023-03-05  5:07     ` [PATCH v6 2/3] rebase: deprecate --rebase-merges="" Alex Henrie
2023-03-07 14:59       ` Phillip Wood
2023-03-05  5:07     ` [PATCH v6 3/3] rebase: add a config option for --rebase-merges Alex Henrie
2023-03-07 14:56       ` Phillip Wood
2023-03-07 18:32         ` Junio C Hamano
2023-03-12 21:01           ` Alex Henrie
2023-03-08  0:09         ` Glen Choo
2023-03-08  0:02       ` Glen Choo
2023-03-12 21:03         ` Alex Henrie
2023-03-15  2:52         ` Alex Henrie
2023-03-16 17:32           ` Glen Choo
2023-03-16 18:11             ` Felipe Contreras
2023-03-16 22:46               ` Glen Choo
2023-03-16 23:48                 ` Felipe Contreras
2023-03-16 20:27             ` Alex Henrie
2023-03-16 22:39               ` Glen Choo
2023-03-18  5:59                 ` Alex Henrie
2023-03-24 15:05               ` Johannes Schindelin
2023-03-25 16:59               ` Sergey Organov
2023-03-05 12:22     ` [PATCH v6 0/3] rebase: document, clean up, and introduce " Sergey Organov
2023-03-05 21:33       ` Alex Henrie
2023-03-05 22:54         ` Sergey Organov
2023-03-06  0:02           ` Alex Henrie
2023-03-06 13:23             ` Sergey Organov
2023-03-06 19:08             ` Junio C Hamano
2023-03-06 17:19           ` Junio C Hamano
2023-03-06 16:24     ` Phillip Wood
2023-03-06 17:36       ` Alex Henrie
2023-03-07 15:07         ` Phillip Wood
2023-03-08  0:13     ` Glen Choo
2023-03-12 21:04     ` [PATCH v7 " Alex Henrie
2023-03-12 21:04       ` [PATCH v7 1/3] rebase: add documentation and test for --no-rebase-merges Alex Henrie
2023-03-12 21:04       ` [PATCH v7 2/3] rebase: deprecate --rebase-merges="" Alex Henrie
2023-03-12 21:04       ` Alex Henrie [this message]
2023-03-20  5:59       ` [PATCH v8 0/3] rebase: document, clean up, and introduce a config option for --rebase-merges Alex Henrie
2023-03-20  5:59         ` [PATCH v8 1/3] rebase: add documentation and test for --no-rebase-merges Alex Henrie
2023-03-20  5:59         ` [PATCH v8 2/3] rebase: deprecate --rebase-merges="" Alex Henrie
2023-03-20  5:59         ` [PATCH v8 3/3] rebase: add a config option for --rebase-merges Alex Henrie
2023-03-22 16:54           ` Phillip Wood
2023-03-23 18:45             ` Junio C Hamano
2023-03-24 14:52               ` Phillip Wood
2023-03-25  5:23               ` Alex Henrie
2023-03-25  5:21             ` Alex Henrie
2023-03-26  3:06         ` [PATCH v9 0/3] rebase: document, clean up, and introduce " Alex Henrie
2023-03-26  3:06           ` [PATCH v9 1/3] rebase: add documentation and test for --no-rebase-merges Alex Henrie
2023-03-26  3:06           ` [PATCH v9 2/3] rebase: deprecate --rebase-merges="" Alex Henrie
2023-03-26  3:06           ` [PATCH v9 3/3] rebase: add a config option for --rebase-merges Alex Henrie
2023-03-26 15:12           ` [PATCH v9 0/3] rebase: document, clean up, and introduce " Phillip Wood
2023-03-27 16:33             ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230312210456.92364-4-alexhenrie24@gmail.com \
    --to=alexhenrie24@gmail.com \
    --cc=Johannes.Schindelin@gmx.de \
    --cc=calvinwan@google.com \
    --cc=chooglen@google.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=jonathantanmy@google.com \
    --cc=newren@gmail.com \
    --cc=phillip.wood123@gmail.com \
    --cc=sorganov@gmail.com \
    --cc=tao@klerks.biz \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).