# [PATCH 0/2] Branch --set-upstream

4 messages from 2010-01-18 to 2010-01-19. Participants: Ilari Liusvaara, Matthieu Moy.
Thread: https://gitlist.dev/t/22272

## Ilari Liusvaara, 2010-01-18 20:44

Subject: [PATCH 0/2] Branch --set-upstream
Message-ID: <1263847452-29634-1-git-send-email-ilari.liusvaara@elisanet.fi>
URL: https://gitlist.dev/e/1263847452-29634-1-git-send-email-ilari.liusvaara%40elisanet.fi

```
This adds new switch --set-upstream that can set upstream information
on existing branch branch without changing where the branch points
to.

push --set-upstream doesn't help if user doesn't have push priviledges
or if user is not up to date with upstream. Forcing branch recreate
is not possible if user has own patches appiled to the branch.

This series is edited version of Matthieu Moy's branch --track patch
series. The first patch is edited, the second is resent as-is.

Ilari Liusvaara (1):
  Add branch --set-upstream

Matthieu Moy (1):
  branch: warn and refuse to set a branch as a tracking branch of
    itself.

 Documentation/git-branch.txt |    8 ++++++-
 branch.c                     |   45 ++++++++++++++++++++++++++++++-----------
 builtin-branch.c             |    2 +
 cache.h                      |    1 +
 t/t6040-tracking-info.sh     |   21 +++++++++++++++++++
 5 files changed, 64 insertions(+), 13 deletions(-)

```

## Ilari Liusvaara, 2010-01-18 20:44

Subject: [PATCH 1/2] Add branch --set-upstream
Message-ID: <1263847452-29634-2-git-send-email-ilari.liusvaara@elisanet.fi>
URL: https://gitlist.dev/e/1263847452-29634-2-git-send-email-ilari.liusvaara%40elisanet.fi
In-Reply-To: <1263847452-29634-1-git-send-email-ilari.liusvaara@elisanet.fi>

```
Add --set-upstream option to branch that works like --track, except that
when branch exists already, its upstream info is changed without changing
the ref value.

Based-on-patch-from: Matthieu Moy <Matthieu.Moy@imag.fr>
Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
---
 Documentation/git-branch.txt |    8 +++++++-
 branch.c                     |   31 +++++++++++++++++++++----------
 builtin-branch.c             |    2 ++
 cache.h                      |    1 +
 t/t6040-tracking-info.sh     |   21 +++++++++++++++++++++
 5 files changed, 52 insertions(+), 11 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 0e83680..a0d6a7a 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -11,7 +11,7 @@ SYNOPSIS
 'git branch' [--color | --no-color] [-r | -a]
 	[-v [--abbrev=<length> | --no-abbrev]]
 	[(--merged | --no-merged | --contains) [<commit>]]
-'git branch' [--track | --no-track] [-l] [-f] <branchname> [<start-point>]
+'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
 'git branch' (-m | -M) [<oldbranch>] <newbranch>
 'git branch' (-d | -D) [-r] <branchname>...
 
@@ -129,6 +129,12 @@ start-point is either a local or remote branch.
 	Do not set up "upstream" configuration, even if the
 	branch.autosetupmerge configuration variable is true.
 
+--set-upstream::
+	If specified branch does not exist yet or if '--force' has been
+	given, acts exactly like '--track'. Otherwise sets up configuration
+	like '--track' would when creating the branch, except that where
+	branch points to is not changed.
+
 --contains <commit>::
 	Only list branches which contain the specified commit.
 
diff --git a/branch.c b/branch.c
index 05ef3f5..40d3c45 100644
--- a/branch.c
+++ b/branch.c
@@ -108,6 +108,7 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
 		switch (track) {
 		case BRANCH_TRACK_ALWAYS:
 		case BRANCH_TRACK_EXPLICIT:
+		case BRANCH_TRACK_OVERRIDE:
 			break;
 		default:
 			return 1;
@@ -128,18 +129,25 @@ void create_branch(const char *head,
 		   const char *name, const char *start_name,
 		   int force, int reflog, enum branch_track track)
 {
-	struct ref_lock *lock;
+	struct ref_lock *lock = NULL;
 	struct commit *commit;
 	unsigned char sha1[20];
 	char *real_ref, msg[PATH_MAX + 20];
 	struct strbuf ref = STRBUF_INIT;
 	int forcing = 0;
+	int dont_change_ref = 0;
+	int explicit_tracking = 0;
+
+	if (track == BRANCH_TRACK_EXPLICIT || track == BRANCH_TRACK_OVERRIDE)
+		explicit_tracking = 1;
 
 	if (strbuf_check_branch_ref(&ref, name))
 		die("'%s' is not a valid branch name.", name);
 
 	if (resolve_ref(ref.buf, sha1, 1, NULL)) {
-		if (!force)
+		if (!force && track == BRANCH_TRACK_OVERRIDE)
+			dont_change_ref = 1;
+		else if (!force)
 			die("A branch named '%s' already exists.", name);
 		else if (!is_bare_repository() && !strcmp(head, name))
 			die("Cannot force update the current branch.");
@@ -153,12 +161,12 @@ void create_branch(const char *head,
 	switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {
 	case 0:
 		/* Not branching from any existing branch */
-		if (track == BRANCH_TRACK_EXPLICIT)
+		if (explicit_tracking)
 			die("Cannot setup tracking information; starting point is not a branch.");
 		break;
 	case 1:
 		/* Unique completion -- good, only if it is a real ref */
-		if (track == BRANCH_TRACK_EXPLICIT && !strcmp(real_ref, "HEAD"))
+		if (explicit_tracking && !strcmp(real_ref, "HEAD"))
 			die("Cannot setup tracking information; starting point is not a branch.");
 		break;
 	default:
@@ -170,9 +178,11 @@ void create_branch(const char *head,
 		die("Not a valid branch point: '%s'.", start_name);
 	hashcpy(sha1, commit->object.sha1);
 
-	lock = lock_any_ref_for_update(ref.buf, NULL, 0);
-	if (!lock)
-		die_errno("Failed to lock ref for update");
+	if (!dont_change_ref) {
+		lock = lock_any_ref_for_update(ref.buf, NULL, 0);
+		if (!lock)
+			die_errno("Failed to lock ref for update");
+	}
 
 	if (reflog)
 		log_all_ref_updates = 1;
@@ -180,15 +190,16 @@ void create_branch(const char *head,
 	if (forcing)
 		snprintf(msg, sizeof msg, "branch: Reset from %s",
 			 start_name);
-	else
+	else if (!dont_change_ref)
 		snprintf(msg, sizeof msg, "branch: Created from %s",
 			 start_name);
 
 	if (real_ref && track)
 		setup_tracking(name, real_ref, track);
 
-	if (write_ref_sha1(lock, sha1, msg) < 0)
-		die_errno("Failed to write ref");
+	if (!dont_change_ref)
+		if (write_ref_sha1(lock, sha1, msg) < 0)
+			die_errno("Failed to write ref");
 
 	strbuf_release(&ref);
 	free(real_ref);
diff --git a/builtin-branch.c b/builtin-branch.c
index ddc9f2d..970cf31 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -564,6 +564,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 		OPT__VERBOSE(&verbose),
 		OPT_SET_INT('t', "track",  &track, "set up tracking mode (see git-pull(1))",
 			BRANCH_TRACK_EXPLICIT),
+		OPT_SET_INT( 0, "set-upstream",  &track, "change upstream info",
+			BRANCH_TRACK_OVERRIDE),
 		OPT_BOOLEAN( 0 , "color",  &branch_use_color, "use colored output"),
 		OPT_SET_INT('r', NULL,     &kinds, "act on remote-tracking branches",
 			REF_REMOTE_BRANCH),
diff --git a/cache.h b/cache.h
index cf36c81..e9ec537 100644
--- a/cache.h
+++ b/cache.h
@@ -553,6 +553,7 @@ enum branch_track {
 	BRANCH_TRACK_REMOTE,
 	BRANCH_TRACK_ALWAYS,
 	BRANCH_TRACK_EXPLICIT,
+	BRANCH_TRACK_OVERRIDE,
 };
 
 enum rebase_setup_type {
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index 664b0f8..1785e17 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -89,4 +89,25 @@ test_expect_success 'status when tracking annotated tags' '
 	grep "set up to track" actual &&
 	git checkout heavytrack
 '
+
+test_expect_success 'setup tracking with branch --set-upstream on existing branch' '
+	git branch from-master master &&
+	test_must_fail git config branch.from-master.merge > actual &&
+	git branch --set-upstream from-master master &&
+	git config branch.from-master.merge > actual &&
+	grep -q "^refs/heads/master$" actual
+'
+
+test_expect_success '--set-upstream does not change branch' '
+	git branch from-master2 master &&
+	test_must_fail git config branch.from-master2.merge > actual &&
+	git rev-list from-master2 &&
+	git update-ref refs/heads/from-master2 from-master2^ &&
+	git rev-parse from-master2 >expect2 &&
+	git branch --set-upstream from-master2 master &&
+	git config branch.from-master.merge > actual &&
+	git rev-parse from-master2 >actual2 &&
+	grep -q "^refs/heads/master$" actual &&
+	cmp expect2 actual2
+'
 test_done
-- 
1.6.6.199.gff4b0

```

## Ilari Liusvaara, 2010-01-18 20:44

Subject: [PATCH 2/2] branch: warn and refuse to set a branch as a tracking branch of itself.
Message-ID: <1263847452-29634-3-git-send-email-ilari.liusvaara@elisanet.fi>
URL: https://gitlist.dev/e/1263847452-29634-3-git-send-email-ilari.liusvaara%40elisanet.fi
In-Reply-To: <1263847452-29634-1-git-send-email-ilari.liusvaara@elisanet.fi>

```
From: Matthieu Moy <Matthieu.Moy@imag.fr>

Previous patch allows commands like "git branch foo foo --track", which
doesn't make much sense. Warn the user and don't change the configuration
in this case. Don't die to let the caller finish its job in such case.

Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
---
 branch.c |   14 ++++++++++++--
 1 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/branch.c b/branch.c
index 40d3c45..9e1f63e 100644
--- a/branch.c
+++ b/branch.c
@@ -49,9 +49,19 @@ static int should_setup_rebase(const char *origin)
 
 void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
 {
+	const char *shortname = remote + 11;
+	int remote_is_branch = !prefixcmp(remote, "refs/heads/");
 	struct strbuf key = STRBUF_INIT;
 	int rebasing = should_setup_rebase(origin);
 
+	if (remote_is_branch
+	    && !strcmp(local, shortname)
+	    && !origin) {
+		warning("Not setting branch %s as its own upstream.",
+			local);
+		return;
+	}
+
 	strbuf_addf(&key, "branch.%s.remote", local);
 	git_config_set(key.buf, origin ? origin : ".");
 
@@ -71,8 +81,8 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
 		strbuf_addstr(&key, origin ? "remote" : "local");
 
 		/* Are we tracking a proper "branch"? */
-		if (!prefixcmp(remote, "refs/heads/")) {
-			strbuf_addf(&key, " branch %s", remote + 11);
+		if (remote_is_branch) {
+			strbuf_addf(&key, " branch %s", shortname);
 			if (origin)
 				strbuf_addf(&key, " from %s", origin);
 		}
-- 
1.6.6.199.gff4b0

```

## Matthieu Moy, 2010-01-19 07:22

Subject: Re: [PATCH 1/2] Add branch --set-upstream
Message-ID: <vpqy6juy2x9.fsf@bauges.imag.fr>
URL: https://gitlist.dev/e/vpqy6juy2x9.fsf%40bauges.imag.fr
In-Reply-To: <1263847452-29634-2-git-send-email-ilari.liusvaara@elisanet.fi>

```
Ilari Liusvaara <ilari.liusvaara@elisanet.fi> writes:

> Add --set-upstream option to branch that works like --track, except that
> when branch exists already, its upstream info is changed without changing
> the ref value.
>
> Based-on-patch-from: Matthieu Moy <Matthieu.Moy@imag.fr>
> Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>

I'm short on Git time budget, so I happily let you take over on this
patch.

I'm a bit worried about the vocabulary: my understanding is that
"--track" is considered confusing, and should have been called
"--set-upstream" since the beginning.

With your patch, we have both --set-upstream and --track, with
different meanings. Should we consider --track as semi-deprecated, and
--set-upstream as "--track done right"? If so, you can consider
squashing this to promote your option instead of --track, and perhaps
reword git-branch.txt so that --track says it does like
--set-upstream, and not the other way around.

diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index b169836..4c66f19 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -2114,12 +2114,12 @@ linkgit:git-fetch[1] to keep them up-to-date; see
 
 Now create the branches in which you are going to work; these start out
 at the current tip of origin/master branch, and should be set up (using
-the --track option to linkgit:git-branch[1]) to merge changes in from
+the --set-upstream option to linkgit:git-branch[1]) to merge changes in from
 Linus by default.
 
 -------------------------------------------------
-$ git branch --track test origin/master
-$ git branch --track release origin/master
+$ git branch --set-upstream test origin/master
+$ git branch --set-upstream release origin/master
 -------------------------------------------------
 
 These can be easily kept up to date using linkgit:git-pull[1].


-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

```
