diff mbox series

[RFC] branch: add "inherit" option for branch.autoSetupMerge

Message ID 9628d145881cb875f8e284967e10f587b9f686f9.1631126999.git.steadmon@google.com (mailing list archive)
State Superseded
Headers show
Series [RFC] branch: add "inherit" option for branch.autoSetupMerge | expand

Commit Message

Josh Steadmon Sept. 8, 2021, 8:15 p.m. UTC
It can be helpful when creating a new branch to use the existing
tracking configuration from the branch point. However, there is
currently not a method to automatically do so.

Teach branch.autoSetupMerge a new "inherit" option. When this is set,
creating a new branch will cause the tracking configuration to default
to the configuration of the branch point, if set.

NEEDS WORK:
* this breaks `git checkout -b new-branch --recurse-submodules`
* add documentation
* add tests
* check corner cases, including whether this plays well with related
  cmd-line options (switch, checkout, branch)

Signed-off-by: Josh Steadmon <steadmon@google.com>
---
I'll be looking into the --recurse-submodules breakage today, and then
I'll work on polishing the patch after that's fixed. But I thought it's
worth getting an idea of how the list feels about the feature in general
while I sort through the issues.

 branch.c | 36 +++++++++++++++++++++++++++++++++++-
 branch.h |  3 ++-
 config.c |  3 +++
 3 files changed, 40 insertions(+), 2 deletions(-)

Comments

Josh Steadmon Sept. 8, 2021, 8:44 p.m. UTC | #1
Actually, this patch probably makes zero sense without [1], an old RFC
patch to use a more repo-like workflow that we've been using internally
at $job. Hopefully I can get a v2 that doesn't depend on this.

[1]: https://lore.kernel.org/git/20180927221603.148025-1-sbeller@google.com/
Glen Choo Oct. 18, 2021, 5:50 p.m. UTC | #2
Josh Steadmon <steadmon@google.com> writes:

> +static int inherit_tracking(struct tracking *tracking, const char *orig_ref)
> +{
> +	struct strbuf key = STRBUF_INIT;
> +	char *remote;
> +	const char *bare_ref;
> +
> +	bare_ref = orig_ref;
> +	skip_prefix(orig_ref, "refs/heads/", &bare_ref);
> +
> +	strbuf_addf(&key, "branch.%s.remote", bare_ref);
> +	if (git_config_get_string(key.buf, &remote)) {
> +		warning("branch.autoSetupMerge=inherit, but could not find %s",
> +			key.buf);
> +		strbuf_release(&key);
> +		return 1;
> +	}
> +	tracking->remote = remote;
> +
> +	strbuf_reset(&key);
> +	strbuf_addf(&key, "branch.%s.merge", bare_ref);
> +	if (git_config_get_string(key.buf, &tracking->src)) {
> +		warning("branch.autoSetupMerge=inherit, but could not find %s",
> +			key.buf);
> +		strbuf_release(&key);
> +		return 1;
> +	}
> +
> +	tracking->matches = 1;
> +	strbuf_release(&key);
> +	return 0;
> +}

I believe that we can get the branch remote via struct branch. Instead
of reading the config, we could do something along the lines of:

   int *explicit;
   struct branch *branch = branch_get();
   char *remote = remote_for_branch(branch, explicit);
   /* Optionally check explicit if we don't want to fall back to
    * "origin" */

I'm not sure which is the idiomatic way to get the branch remote, feel
free to correct me.
Glen Choo Oct. 18, 2021, 6:08 p.m. UTC | #3
Glen Choo <chooglen@google.com> writes:

> I believe that we can get the branch remote via struct branch. Instead
> of reading the config, we could do something along the lines of:
>
>    int *explicit;
>    struct branch *branch = branch_get();
>    char *remote = remote_for_branch(branch, explicit);
>    /* Optionally check explicit if we don't want to fall back to
>     * "origin" */
>
> I'm not sure which is the idiomatic way to get the branch remote, feel
> free to correct me.

Gah, I read and responded to v1 thinking it was v3. Reading v3, it looks
like the feedback is still relevant, so please pretend I responded to
the right email :P
Josh Steadmon Nov. 15, 2021, 9:44 p.m. UTC | #4
On 2021.10.18 10:50, Glen Choo wrote:
> Josh Steadmon <steadmon@google.com> writes:
> 
> > +static int inherit_tracking(struct tracking *tracking, const char *orig_ref)
> > +{
> > +	struct strbuf key = STRBUF_INIT;
> > +	char *remote;
> > +	const char *bare_ref;
> > +
> > +	bare_ref = orig_ref;
> > +	skip_prefix(orig_ref, "refs/heads/", &bare_ref);
> > +
> > +	strbuf_addf(&key, "branch.%s.remote", bare_ref);
> > +	if (git_config_get_string(key.buf, &remote)) {
> > +		warning("branch.autoSetupMerge=inherit, but could not find %s",
> > +			key.buf);
> > +		strbuf_release(&key);
> > +		return 1;
> > +	}
> > +	tracking->remote = remote;
> > +
> > +	strbuf_reset(&key);
> > +	strbuf_addf(&key, "branch.%s.merge", bare_ref);
> > +	if (git_config_get_string(key.buf, &tracking->src)) {
> > +		warning("branch.autoSetupMerge=inherit, but could not find %s",
> > +			key.buf);
> > +		strbuf_release(&key);
> > +		return 1;
> > +	}
> > +
> > +	tracking->matches = 1;
> > +	strbuf_release(&key);
> > +	return 0;
> > +}
> 
> I believe that we can get the branch remote via struct branch. Instead
> of reading the config, we could do something along the lines of:
> 
>    int *explicit;
>    struct branch *branch = branch_get();
>    char *remote = remote_for_branch(branch, explicit);
>    /* Optionally check explicit if we don't want to fall back to
>     * "origin" */
> 
> I'm not sure which is the idiomatic way to get the branch remote, feel
> free to correct me.

Will fix in V4, thanks.
diff mbox series

Patch

diff --git a/branch.c b/branch.c
index 7a88a4861e..17d4cc5128 100644
--- a/branch.c
+++ b/branch.c
@@ -126,6 +126,38 @@  int install_branch_config(int flag, const char *local, const char *origin, const
 	return -1;
 }
 
+static int inherit_tracking(struct tracking *tracking, const char *orig_ref)
+{
+	struct strbuf key = STRBUF_INIT;
+	char *remote;
+	const char *bare_ref;
+
+	bare_ref = orig_ref;
+	skip_prefix(orig_ref, "refs/heads/", &bare_ref);
+
+	strbuf_addf(&key, "branch.%s.remote", bare_ref);
+	if (git_config_get_string(key.buf, &remote)) {
+		warning("branch.autoSetupMerge=inherit, but could not find %s",
+			key.buf);
+		strbuf_release(&key);
+		return 1;
+	}
+	tracking->remote = remote;
+
+	strbuf_reset(&key);
+	strbuf_addf(&key, "branch.%s.merge", bare_ref);
+	if (git_config_get_string(key.buf, &tracking->src)) {
+		warning("branch.autoSetupMerge=inherit, but could not find %s",
+			key.buf);
+		strbuf_release(&key);
+		return 1;
+	}
+
+	tracking->matches = 1;
+	strbuf_release(&key);
+	return 0;
+}
+
 /*
  * This is called when new_ref is branched off of orig_ref, and tries
  * to infer the settings for branch.<new_ref>.{remote,merge} from the
@@ -139,7 +171,9 @@  static void setup_tracking(const char *new_ref, const char *orig_ref,
 
 	memset(&tracking, 0, sizeof(tracking));
 	tracking.spec.dst = (char *)orig_ref;
-	if (for_each_remote(find_tracked_branch, &tracking))
+	if (track == BRANCH_TRACK_INHERIT && inherit_tracking(&tracking, orig_ref))
+		return;
+	else if (for_each_remote(find_tracked_branch, &tracking))
 		return;
 
 	if (!tracking.matches)
diff --git a/branch.h b/branch.h
index df0be61506..6484bda8a2 100644
--- a/branch.h
+++ b/branch.h
@@ -10,7 +10,8 @@  enum branch_track {
 	BRANCH_TRACK_REMOTE,
 	BRANCH_TRACK_ALWAYS,
 	BRANCH_TRACK_EXPLICIT,
-	BRANCH_TRACK_OVERRIDE
+	BRANCH_TRACK_OVERRIDE,
+	BRANCH_TRACK_INHERIT
 };
 
 extern enum branch_track git_branch_track;
diff --git a/config.c b/config.c
index cb4a8058bf..4bd5a18faf 100644
--- a/config.c
+++ b/config.c
@@ -1580,6 +1580,9 @@  static int git_default_branch_config(const char *var, const char *value)
 		if (value && !strcasecmp(value, "always")) {
 			git_branch_track = BRANCH_TRACK_ALWAYS;
 			return 0;
+		} else if (value && !strcasecmp(value, "inherit")) {
+			git_branch_track = BRANCH_TRACK_INHERIT;
+			return 0;
 		}
 		git_branch_track = git_config_bool(var, value);
 		return 0;