threads / rfc / 12123

RFC patch, 2 partsgit-branch: allow --track to work w/local branches

Subject: [RFC PATCH 1/2] git-branch: allow --track to work w/local branches

## tl;dr

6 messages between Feb 16, 2008 and Feb 17, 2008. Diffs are folded; open one to read it.

replies: 5people: 3as markdown or json

Jay Soffian· Feb 16, 2008, 03:45 UTC · lore

When given --track (or if branch.autosetupmerge is true) and basing off a local branch, set branch.<newbranch>.remote to "." and branch.<newbranch>.merge to the local branch. This allows us to use "git pull" (w/o options) on the new branch.

Previously --track was silently ignored when basing off a local branch.
Signed-off-by: Jay Soffian <jaysoffian@gmail.com>
---
 builtin-branch.c |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)
Show changes to builtin-branch.c +10 −0
diff --git a/builtin-branch.c b/builtin-branch.c
index e414c88..94ab195 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -402,6 +402,16 @@ static int setup_tracking(const char *new_ref, const char *orig_ref)
 		return error("Tracking not set up: name too long: %s",
 				new_ref);
 
+	if (!prefixcmp(orig_ref, "refs/heads/")) {
+		sprintf(key, "branch.%s.remote", new_ref);
+		git_config_set(key, ".");
+		sprintf(key, "branch.%s.merge", new_ref);
+		git_config_set(key, orig_ref);
+		printf("Branch %s set up to track local branch %s.\n",
+			       new_ref, orig_ref);
+		return 0;
+	}
+
 	memset(&tracking, 0, sizeof(tracking));
 	tracking.spec.dst = (char *)orig_ref;
 	if (for_each_remote(find_tracked_branch, &tracking) ||
-- 
1.5.4.1.1281.g75df
Jay Soffian· Feb 16, 2008, 03:45 UTC · re: Jay Soffian · lore

[RFC PATCH 2/2] new --rebase option to set branch.*.rebase for new branches

Add a --rebase option to git-branch and git-checkout. If given, it implies --track but additionally sets branch.<newbranch>.rebase to true.

Signed-off-by: Jay Soffian <jaysoffian@gmail.com>
---
 builtin-branch.c |   18 ++++++++++++++----
 git-checkout.sh  |   11 ++++++++---
 2 files changed, 22 insertions(+), 7 deletions(-)
Show changes to 2 files +22 −7

builtin-branch.c, git-checkout.sh

diff --git a/builtin-branch.c b/builtin-branch.c
index 94ab195..1404d8b 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -393,7 +393,7 @@ static int find_tracked_branch(struct remote *remote, void *priv)
  * to infer the settings for branch.<new_ref>.{remote,merge} from the
  * config.
  */
-static int setup_tracking(const char *new_ref, const char *orig_ref)
+static int setup_tracking(const char *new_ref, const char *orig_ref, int rebase)
 {
 	char key[1024];
 	struct tracking tracking;
@@ -407,6 +407,10 @@ static int setup_tracking(const char *new_ref, const char *orig_ref)
 		git_config_set(key, ".");
 		sprintf(key, "branch.%s.merge", new_ref);
 		git_config_set(key, orig_ref);
+		if (rebase) {
+			sprintf(key, "branch.%s.rebase", new_ref);
+			git_config_set(key, "true");
+		}
 		printf("Branch %s set up to track local branch %s.\n",
 			       new_ref, orig_ref);
 		return 0;
@@ -428,6 +432,10 @@ static int setup_tracking(const char *new_ref, const char *orig_ref)
 		sprintf(key, "branch.%s.merge", new_ref);
 		git_config_set(key, tracking.src);
 		free(tracking.src);
+		if (rebase) {
+			sprintf(key, "branch.%s.rebase", new_ref);
+			git_config_set(key, "true");
+		}
 		printf("Branch %s set up to track remote branch %s.\n",
 			       new_ref, orig_ref);
 	}
@@ -436,7 +444,7 @@ static int setup_tracking(const char *new_ref, const char *orig_ref)
 }
 
 static void create_branch(const char *name, const char *start_name,
-			  int force, int reflog, int track)
+			  int force, int reflog, int track, int rebase)
 {
 	struct ref_lock *lock;
 	struct commit *commit;
@@ -495,7 +503,7 @@ static void create_branch(const char *name, const char *start_name,
 	   automatically merges from there.  So far, this is only done for
 	   remotes registered via .git/config.  */
 	if (real_ref && track)
-		setup_tracking(name, real_ref);
+		setup_tracking(name, real_ref, rebase);
 
 	if (write_ref_sha1(lock, sha1, msg) < 0)
 		die("Failed to write ref: %s.", strerror(errno));
@@ -566,12 +574,14 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	int verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0;
 	int reflog = 0, track;
 	int kinds = REF_LOCAL_BRANCH;
+	int rebase = 0;
 	struct commit_list *with_commit = NULL;
 
 	struct option options[] = {
 		OPT_GROUP("Generic options"),
 		OPT__VERBOSE(&verbose),
 		OPT_BOOLEAN( 0 , "track",  &track, "set up tracking mode (see git-pull(1))"),
+		OPT_BOOLEAN( 0 , "rebase",  &rebase, "set up branch to rebase (see git-pull(1))"),
 		OPT_BOOLEAN( 0 , "color",  &branch_use_color, "use colored output"),
 		OPT_SET_INT('r', NULL,     &kinds, "act on remote-tracking branches",
 			REF_REMOTE_BRANCH),
@@ -625,7 +635,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 		rename_branch(argv[0], argv[1], rename > 1);
 	else if (argc <= 2)
 		create_branch(argv[0], (argc == 2) ? argv[1] : head,
-			      force_create, reflog, track);
+			      force_create, reflog, track, rebase);
 	else
 		usage_with_options(builtin_branch_usage, options);
 
diff --git a/git-checkout.sh b/git-checkout.sh
index bd74d70..569e29c 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -7,6 +7,7 @@ git-checkout [options] [<branch>] [<paths>...]
 b=          create a new branch started at <branch>
 l           create the new branch's reflog
 track       arrange that the new branch tracks the remote branch
+rebase      arrange that the new branch rebases
 f           proceed even if the index or working tree is not HEAD
 m           merge local modifications into the new branch
 q,quiet     be quiet
@@ -23,6 +24,7 @@ new_name=
 force=
 branch=
 track=
+rebase=
 newbranch=
 newbranch_log=
 merge=
@@ -49,6 +51,9 @@ while test $# != 0; do
 	--track|--no-track)
 		track="$1"
 		;;
+	--rebase)
+		rebase="$1"
+		;;
 	-f)
 		force=1
 		;;
@@ -92,9 +97,9 @@ then
 fi
 [ "$1" = "--" ] && shift
 
-case "$newbranch,$track" in
+case "$newbranch,$track,$rebase" in
 ,--*)
-	die "git checkout: --track and --no-track require -b"
+	die "git checkout: --track, --no-track and --rebase require -b"
 esac
 
 case "$force$merge" in
@@ -261,7 +266,7 @@ fi
 #
 if [ "$?" -eq 0 ]; then
 	if [ "$newbranch" ]; then
-		git branch $track $newbranch_log "$newbranch" "$new_name" || exit
+		git branch $track $rebase $newbranch_log "$newbranch" "$new_name" || exit
 		branch="$newbranch"
 	fi
 	if test -n "$branch"
-- 
1.5.4.1.1281.g75df
Junio C Hamano· Feb 16, 2008, 05:10 UTC · re: Jay Soffian · lore

Re: [RFC PATCH 1/2] git-branch: allow --track to work w/local branches

Jay Soffian <jaysoffian@gmail.com> writes:
Show 21 quoted lines
> diff --git a/builtin-branch.c b/builtin-branch.c
> index e414c88..94ab195 100644
> --- a/builtin-branch.c
> +++ b/builtin-branch.c
> @@ -402,6 +402,16 @@ static int setup_tracking(const char *new_ref, const char *orig_ref)
>  		return error("Tracking not set up: name too long: %s",
>  				new_ref);
>  
> +	if (!prefixcmp(orig_ref, "refs/heads/")) {
> +		sprintf(key, "branch.%s.remote", new_ref);
> +		git_config_set(key, ".");
> +		sprintf(key, "branch.%s.merge", new_ref);
> +		git_config_set(key, orig_ref);
> +		printf("Branch %s set up to track local branch %s.\n",
> +			       new_ref, orig_ref);
> +		return 0;
> +	}
> +
>  	memset(&tracking, 0, sizeof(tracking));
>  	tracking.spec.dst = (char *)orig_ref;
>  	if (for_each_remote(find_tracked_branch, &tracking) ||

Although I am not so familiar with this area, the patch somehow did not feel right, so I ended up doing a bit of digging.

After the context of the patch, we have this:
	if (tracking.matches == 1) {
		sprintf(key, "branch.%s.remote", new_ref);
		git_config_set(key, tracking.remote ?  tracking.remote : ".");
		sprintf(key, "branch.%s.merge", new_ref);
		git_config_set(key, tracking.src);

So it looks to me that the code already has intention to set the "branch.*.remote" variable to "." when certain condition is met. And the condition is "when tracking.remote is NULL, or it is already a dot".

for_each_remote() iterates thru the remotes and find_tracked_branch() does this:

        static int find_tracked_branch(struct remote *remote, void *priv)
        {
                struct tracking *tracking = priv;
                if (!remote_find_tracking(remote, &tracking->spec)) {
                        if (++tracking->matches == 1) {
                                tracking->src = tracking->spec.src;
                                tracking->remote = remote->name;
                        } else {
                                free(tracking->spec.src);
                                if (tracking->src) {
                                        free(tracking->src);
                                        tracking->src = NULL;
                                }
                        }
                        tracking->spec.src = NULL;
                }
                return 0;
        }

So if there is a remote whose name is "." (or NULL, but I do not know when that can happen --- remote.c::make_remote() does not allow creating such a remote as far as I can tell), that would be found without the added extra code, wouldn't it?

I did a bit of experiment and with this in .git/config:
	[remote "."]
                fetch = refs/*:refs/*

it turns out that you do not have to patch the code at all. The above manual configuration feels somewhat like an ugly hack but perhaps we should make the above two lines implied? This area was last cleaned up in 6f084a5 (branch --track: code cleanup and saner handling of local branches). I do not know if the original intention of the code was to allow a hack like this to work, or it is just an unintended accident that it happens to work. Dscho, any ideas?

Jay Soffian· Feb 16, 2008, 07:07 UTC · re: Junio C Hamano · lore

Re: [RFC PATCH 1/2] git-branch: allow --track to work w/local branches

On Feb 16, 2008 12:10 AM, Junio C Hamano <gitster@pobox.com> wrote:
Show 15 quoted lines
> Although I am not so familiar with this area, the patch somehow
> did not feel right, so I ended up doing a bit of digging.
>
> After the context of the patch, we have this:
>
>         if (tracking.matches == 1) {
>                 sprintf(key, "branch.%s.remote", new_ref);
>                 git_config_set(key, tracking.remote ?  tracking.remote : ".");
>                 sprintf(key, "branch.%s.merge", new_ref);
>                 git_config_set(key, tracking.src);
>
> So it looks to me that the code already has intention to set the
> "branch.*.remote" variable to "." when certain condition is met.
> And the condition is "when tracking.remote is NULL, or it is
> already a dot".

I was confused by the use of the ternary operator. I couldn't figure out how tracking.remote could be NULL. I chalked it up to bit-rot but them forget to mention that in my email. I'm glad you took another look, but I still don't understand how tracking.remote can be NULL and tracking.matches == 1.

Show 13 quoted lines
> So if there is a remote whose name is "." (or NULL, but I do not
> know when that can happen --- remote.c::make_remote() does not
> allow creating such a remote as far as I can tell), that would
> be found without the added extra code, wouldn't it?
>
> I did a bit of experiment and with this in .git/config:
>
>         [remote "."]
>                 fetch = refs/*:refs/*
>
> it turns out that you do not have to patch the code at all.  The
> above manual configuration feels somewhat like an ugly hack but
> perhaps we should make the above two lines implied?

Hmm, that just causes tracking.remote to be set to ".", not to NULL? Right?

j.
Johannes Schindelin· Feb 16, 2008, 11:45 UTC · re: Junio C Hamano · lore

Re: [RFC PATCH 1/2] git-branch: allow --track to work w/local branches

Hi,
On Fri, 15 Feb 2008, Junio C Hamano wrote:
> This area was last cleaned up in 6f084a5 (branch --track: code cleanup 
> and saner handling of local branches).  I do not know if the original 
> intention of the code was to allow a hack like this to work, or it is 
> just an unintended accident that it happens to work.  Dscho, any ideas?

AFAIR the problem was that you were (rightfully) annoyed when you were setting up your local branches, and all of a sudden, they were set up with loads of tracking information, cluttering your config.

Basically, that is the reason why we disallowed tracking information to be set up for local branching.

Ciao, Dscho

Jay Soffian· Feb 17, 2008, 18:05 UTC · re: Johannes Schindelin · lore

Re: [RFC PATCH 1/2] git-branch: allow --track to work w/local branches

On Feb 16, 2008 6:45 AM, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
Show 6 quoted lines
> AFAIR the problem was that you were (rightfully) annoyed when you were
> setting up your local branches, and all of a sudden, they were set up with
> loads of tracking information, cluttering your config.
>
> Basically, that is the reason why we disallowed tracking information to be
> set up for local branching.

Hrmm, I was annoyed that when setting up my local branches, they *don't* get tracking information. Otherwise I can't use "git pull" with them, which I'd like to. So maybe something like:

 * Using --track or --notrack adds (or doesn't) the information, because
  well, I specified it explicitly.
 * Otherwise (if neither --track nor --notrack) is specified, check the
  setting of branch.autosetupmerge. Currently it's a boolean, but
  perhaps it can take on a new setting and have:
 - false
 - true
 - always ; new setting which means to setup tracking information for
          ; both local and remote branches
?
j.

← back to recent threads