All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Alex Reed via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Alex Reed <acreed4@gmail.com>, Alex Reed <acreed4@gmail.com>
Subject: [PATCH] branch, config:  teach branch.autosetuprebase about 'merges' mode
Date: Wed, 20 Jan 2021 00:20:09 +0000	[thread overview]
Message-ID: <pull.948.git.git.1611102010142.gitgitgadget@gmail.com> (raw)

From: Alex Reed <acreed4@gmail.com>

branch.autoSetupRebase now honors the 'merges' flag, allowing tracking branches
to be auto-populated with 'branch.<name>.rebase = merges'.  This allows complex
workflows to more easily retain non-trivial merges while rebasing branches on
pull operations.  Seeding new branches with 'branch.<name>.rebase = true' is not
always sufficient (read: not project default) and requiring developers to
manually reconfigure every new branch is cumbersome and error-prone.

Signed-off-by: Alex Reed <acreed4@gmail.com>
---
    branch, config: teach branch.autosetuprebase about 'merges' mode
    
    branch.autoSetupRebase now honors the 'merges' flag, allowing tracking
    branches to be auto-populated with 'branch..rebase = merges'. This
    allows complex workflows to more easily retain non-trivial merges while
    rebasing branches on pull operations. Seeding new branches with
    'branch..rebase = true' is not always sufficient (read: not project
    default) and requiring developers to manually reconfigure every new
    branch is cumbersome and error-prone.

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-948%2Facr4%2Fautosetuprebase-merges-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-948/acr4/autosetuprebase-merges-v1
Pull-Request: https://github.com/git/git/pull/948

 Documentation/config/branch.txt |  2 +
 branch.c                        | 70 ++++++++++++++++++++-------------
 cache.h                         |  3 +-
 config.c                        |  2 +
 t/t3200-branch.sh               | 45 +++++++++++++++++++++
 t/t5601-clone.sh                | 14 ++++++-
 6 files changed, 107 insertions(+), 29 deletions(-)

diff --git a/Documentation/config/branch.txt b/Documentation/config/branch.txt
index cc5f3249fc5..98410bf003f 100644
--- a/Documentation/config/branch.txt
+++ b/Documentation/config/branch.txt
@@ -21,6 +21,8 @@ branch.autoSetupRebase::
 	remote-tracking branches.
 	When `always`, rebase will be set to true for all tracking
 	branches.
+	When `merges`, rebase will be set to `merges` for all tracking
+	branches.
 	See "branch.autoSetupMerge" for details on how to set up a
 	branch to track another branch.
 	This option defaults to never.
diff --git a/branch.c b/branch.c
index 9c9dae1eae3..b197fe0bbb3 100644
--- a/branch.c
+++ b/branch.c
@@ -34,17 +34,25 @@ static int find_tracked_branch(struct remote *remote, void *priv)
 	return 0;
 }
 
-static int should_setup_rebase(const char *origin)
+typedef enum {
+	REBASE_FALSE,
+	REBASE_TRUE,
+	REBASE_MERGES
+} rebase_type;
+
+static rebase_type should_setup_rebase(const char *origin)
 {
 	switch (autorebase) {
 	case AUTOREBASE_NEVER:
-		return 0;
+		return REBASE_FALSE;
 	case AUTOREBASE_LOCAL:
-		return origin == NULL;
+		return origin == NULL ? REBASE_TRUE : REBASE_FALSE;
 	case AUTOREBASE_REMOTE:
-		return origin != NULL;
+		return origin != NULL ? REBASE_TRUE : REBASE_FALSE;
 	case AUTOREBASE_ALWAYS:
-		return 1;
+		return REBASE_TRUE;
+	case AUTOREBASE_MERGES:
+		return REBASE_MERGES;
 	}
 	return 0;
 }
@@ -59,7 +67,8 @@ int install_branch_config(int flag, const char *local, const char *origin, const
 {
 	const char *shortname = NULL;
 	struct strbuf key = STRBUF_INIT;
-	int rebasing = should_setup_rebase(origin);
+	rebase_type rebasing = should_setup_rebase(origin);
+	struct strbuf method = STRBUF_INIT;
 
 	if (skip_prefix(remote, "refs/heads/", &shortname)
 	    && !strcmp(local, shortname)
@@ -78,44 +87,51 @@ int install_branch_config(int flag, const char *local, const char *origin, const
 	if (git_config_set_gently(key.buf, remote) < 0)
 		goto out_err;
 
-	if (rebasing) {
-		strbuf_reset(&key);
-		strbuf_addf(&key, "branch.%s.rebase", local);
-		if (git_config_set_gently(key.buf, "true") < 0)
-			goto out_err;
+	strbuf_reset(&key);
+	strbuf_addf(&key, "branch.%s.rebase", local);
+	switch(rebasing) {
+		case REBASE_TRUE:
+			strbuf_addstr(&method, " by rebasing");
+			if(git_config_set_gently(key.buf, "true") < 0)
+				goto out_err;
+			break;
+		case REBASE_MERGES:
+			strbuf_addstr(&method, " by rebasing while preserving merges");
+			if (git_config_set_gently(key.buf, "merges") < 0)
+				goto out_err;
+			break;
+    default:;
 	}
 	strbuf_release(&key);
 
 	if (flag & BRANCH_CONFIG_VERBOSE) {
 		if (shortname) {
 			if (origin)
-				printf_ln(rebasing ?
-					  _("Branch '%s' set up to track remote branch '%s' from '%s' by rebasing.") :
-					  _("Branch '%s' set up to track remote branch '%s' from '%s'."),
-					  local, shortname, origin);
+				printf_ln(
+					_("Branch '%s' set up to track remote branch '%s' from '%s'%s."),
+					local, shortname, origin, method.buf);
 			else
-				printf_ln(rebasing ?
-					  _("Branch '%s' set up to track local branch '%s' by rebasing.") :
-					  _("Branch '%s' set up to track local branch '%s'."),
-					  local, shortname);
+				printf_ln(
+					_("Branch '%s' set up to track local branch '%s'%s."),
+					local, shortname, method.buf);
 		} else {
 			if (origin)
-				printf_ln(rebasing ?
-					  _("Branch '%s' set up to track remote ref '%s' by rebasing.") :
-					  _("Branch '%s' set up to track remote ref '%s'."),
-					  local, remote);
+				printf_ln(
+					_("Branch '%s' set up to track remote ref '%s'%s."),
+					local, remote, method.buf);
 			else
-				printf_ln(rebasing ?
-					  _("Branch '%s' set up to track local ref '%s' by rebasing.") :
-					  _("Branch '%s' set up to track local ref '%s'."),
-					  local, remote);
+				printf_ln(
+					_("Branch '%s' set up to track local ref '%s'%s."),
+					local, remote, method.buf);
 		}
 	}
 
+	strbuf_release(&method);
 	return 0;
 
 out_err:
 	strbuf_release(&key);
+	strbuf_release(&method);
 	error(_("Unable to write upstream branch configuration"));
 
 	advise(_(tracking_advice),
diff --git a/cache.h b/cache.h
index eefa93b08f8..5a378bcd534 100644
--- a/cache.h
+++ b/cache.h
@@ -995,7 +995,8 @@ enum rebase_setup_type {
 	AUTOREBASE_NEVER = 0,
 	AUTOREBASE_LOCAL,
 	AUTOREBASE_REMOTE,
-	AUTOREBASE_ALWAYS
+	AUTOREBASE_ALWAYS,
+	AUTOREBASE_MERGES
 };
 
 enum push_default_type {
diff --git a/config.c b/config.c
index 4c0cf3a1c15..28d813f2595 100644
--- a/config.c
+++ b/config.c
@@ -1443,6 +1443,8 @@ static int git_default_branch_config(const char *var, const char *value)
 			autorebase = AUTOREBASE_REMOTE;
 		else if (!strcmp(value, "always"))
 			autorebase = AUTOREBASE_ALWAYS;
+		else if (!strcmp(value, "merges"))
+			autorebase = AUTOREBASE_MERGES;
 		else
 			return error(_("malformed value for %s"), var);
 		return 0;
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 0af3b85d172..056192f72c5 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -1222,6 +1222,51 @@ test_expect_success 'autosetuprebase always on an untracked remote branch' '
 	test "z$(git config branch.myr20.rebase)" = z
 '
 
+test_expect_success 'autosetuprebase merges on a tracked local branch' '
+	git config branch.autosetuprebase merges &&
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/o || git fetch local) &&
+	git branch mybase21 &&
+	git branch --track myr21 mybase3 &&
+	test "$(git config branch.myr21.remote)" = . &&
+	test "$(git config branch.myr21.merge)" = refs/heads/mybase3 &&
+	test "$(git config branch.myr21.rebase)" = merges
+'
+
+test_expect_success 'autosetuprebase merges on a tracked remote branch' '
+	git config branch.autosetuprebase merges &&
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/main || git fetch local) &&
+	git branch --track myr22 local/main &&
+	test "$(git config branch.myr22.remote)" = local &&
+	test "$(git config branch.myr22.merge)" = refs/heads/main &&
+	test "$(git config branch.myr22.rebase)" = merges
+'
+
+test_expect_success 'autosetuprebase merges on an untracked local branch' '
+	git config branch.autosetuprebase merges &&
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/main || git fetch local) &&
+	git branch --no-track myr23 mybase2 &&
+	test "z$(git config branch.myr23.remote)" = z &&
+	test "z$(git config branch.myr23.merge)" = z &&
+	test "z$(git config branch.myr23.rebase)" = z
+'
+
+test_expect_success 'autosetuprebase merges on an untracked remote branch' '
+	git config branch.autosetuprebase merges &&
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/main || git fetch local) &&
+	git branch --no-track myr24 local/main &&
+	test "z$(git config branch.myr24.remote)" = z &&
+	test "z$(git config branch.myr24.merge)" = z &&
+	test "z$(git config branch.myr24.rebase)" = z
+'
+
 test_expect_success 'autosetuprebase always on detached HEAD' '
 	git config branch.autosetupmerge always &&
 	test_when_finished git checkout main &&
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 7df3c5373ae..10983191439 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -210,7 +210,7 @@ test_expect_success 'clone a void' '
 	test_cmp target-6/.git/config target-7/.git/config
 '
 
-test_expect_success 'clone respects global branch.autosetuprebase' '
+test_expect_success 'clone respects global branch.autosetuprebase remote' '
 	(
 		test_config="$HOME/.gitconfig" &&
 		git config -f "$test_config" branch.autosetuprebase remote &&
@@ -222,6 +222,18 @@ test_expect_success 'clone respects global branch.autosetuprebase' '
 	)
 '
 
+test_expect_success 'clone respects global branch.autosetuprebase merges' '
+	(
+		test_config="$HOME/.gitconfig" &&
+		git config -f "$test_config" branch.autosetuprebase merges &&
+		rm -fr dst &&
+		git clone src dst &&
+		cd dst &&
+		actual="z$(git config branch.master.rebase)" &&
+		test zmerges = $actual
+	)
+'
+
 test_expect_success 'respect url-encoding of file://' '
 	git init x+y &&
 	git clone "file://$PWD/x+y" xy-url-1 &&

base-commit: 66e871b6647ffea61a77a0f82c7ef3415f1ee79c
-- 
gitgitgadget

                 reply	other threads:[~2021-01-20  0:21 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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

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

  git send-email \
    --in-reply-to=pull.948.git.git.1611102010142.gitgitgadget@gmail.com \
    --to=gitgitgadget@gmail.com \
    --cc=acreed4@gmail.com \
    --cc=git@vger.kernel.org \
    /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.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.