Merge branch 'il/branch-set-upstream'

* il/branch-set-upstream:
  branch: warn and refuse to set a branch as a tracking branch of itself.
  Add branch --set-upstream
This commit is contained in:
Junio C Hamano 2010-01-22 16:08:05 -08:00
commit 1a545d0b5f
5 changed files with 64 additions and 13 deletions

View File

@ -11,7 +11,7 @@ SYNOPSIS
'git branch' [--color | --no-color] [-r | -a] 'git branch' [--color | --no-color] [-r | -a]
[-v [--abbrev=<length> | --no-abbrev]] [-v [--abbrev=<length> | --no-abbrev]]
[(--merged | --no-merged | --contains) [<commit>]] [(--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' (-m | -M) [<oldbranch>] <newbranch>
'git branch' (-d | -D) [-r] <branchname>... '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 Do not set up "upstream" configuration, even if the
branch.autosetupmerge configuration variable is true. 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>:: --contains <commit>::
Only list branches which contain the specified commit. Only list branches which contain the specified commit.

View File

@ -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) 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; struct strbuf key = STRBUF_INIT;
int rebasing = should_setup_rebase(origin); 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); strbuf_addf(&key, "branch.%s.remote", local);
git_config_set(key.buf, origin ? origin : "."); 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"); strbuf_addstr(&key, origin ? "remote" : "local");
/* Are we tracking a proper "branch"? */ /* Are we tracking a proper "branch"? */
if (!prefixcmp(remote, "refs/heads/")) { if (remote_is_branch) {
strbuf_addf(&key, " branch %s", remote + 11); strbuf_addf(&key, " branch %s", shortname);
if (origin) if (origin)
strbuf_addf(&key, " from %s", origin); strbuf_addf(&key, " from %s", origin);
} }
@ -108,6 +118,7 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
switch (track) { switch (track) {
case BRANCH_TRACK_ALWAYS: case BRANCH_TRACK_ALWAYS:
case BRANCH_TRACK_EXPLICIT: case BRANCH_TRACK_EXPLICIT:
case BRANCH_TRACK_OVERRIDE:
break; break;
default: default:
return 1; return 1;
@ -128,18 +139,25 @@ void create_branch(const char *head,
const char *name, const char *start_name, const char *name, const char *start_name,
int force, int reflog, enum branch_track track) int force, int reflog, enum branch_track track)
{ {
struct ref_lock *lock; struct ref_lock *lock = NULL;
struct commit *commit; struct commit *commit;
unsigned char sha1[20]; unsigned char sha1[20];
char *real_ref, msg[PATH_MAX + 20]; char *real_ref, msg[PATH_MAX + 20];
struct strbuf ref = STRBUF_INIT; struct strbuf ref = STRBUF_INIT;
int forcing = 0; 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)) if (strbuf_check_branch_ref(&ref, name))
die("'%s' is not a valid branch name.", name); die("'%s' is not a valid branch name.", name);
if (resolve_ref(ref.buf, sha1, 1, NULL)) { 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); die("A branch named '%s' already exists.", name);
else if (!is_bare_repository() && !strcmp(head, name)) else if (!is_bare_repository() && !strcmp(head, name))
die("Cannot force update the current branch."); die("Cannot force update the current branch.");
@ -153,12 +171,12 @@ void create_branch(const char *head,
switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) { switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {
case 0: case 0:
/* Not branching from any existing branch */ /* 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."); die("Cannot setup tracking information; starting point is not a branch.");
break; break;
case 1: case 1:
/* Unique completion -- good, only if it is a real ref */ /* 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."); die("Cannot setup tracking information; starting point is not a branch.");
break; break;
default: default:
@ -170,9 +188,11 @@ void create_branch(const char *head,
die("Not a valid branch point: '%s'.", start_name); die("Not a valid branch point: '%s'.", start_name);
hashcpy(sha1, commit->object.sha1); hashcpy(sha1, commit->object.sha1);
if (!dont_change_ref) {
lock = lock_any_ref_for_update(ref.buf, NULL, 0); lock = lock_any_ref_for_update(ref.buf, NULL, 0);
if (!lock) if (!lock)
die_errno("Failed to lock ref for update"); die_errno("Failed to lock ref for update");
}
if (reflog) if (reflog)
log_all_ref_updates = 1; log_all_ref_updates = 1;
@ -180,13 +200,14 @@ void create_branch(const char *head,
if (forcing) if (forcing)
snprintf(msg, sizeof msg, "branch: Reset from %s", snprintf(msg, sizeof msg, "branch: Reset from %s",
start_name); start_name);
else else if (!dont_change_ref)
snprintf(msg, sizeof msg, "branch: Created from %s", snprintf(msg, sizeof msg, "branch: Created from %s",
start_name); start_name);
if (real_ref && track) if (real_ref && track)
setup_tracking(name, real_ref, track); setup_tracking(name, real_ref, track);
if (!dont_change_ref)
if (write_ref_sha1(lock, sha1, msg) < 0) if (write_ref_sha1(lock, sha1, msg) < 0)
die_errno("Failed to write ref"); die_errno("Failed to write ref");

View File

@ -564,6 +564,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT__VERBOSE(&verbose), OPT__VERBOSE(&verbose),
OPT_SET_INT('t', "track", &track, "set up tracking mode (see git-pull(1))", OPT_SET_INT('t', "track", &track, "set up tracking mode (see git-pull(1))",
BRANCH_TRACK_EXPLICIT), 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_BOOLEAN( 0 , "color", &branch_use_color, "use colored output"),
OPT_SET_INT('r', NULL, &kinds, "act on remote-tracking branches", OPT_SET_INT('r', NULL, &kinds, "act on remote-tracking branches",
REF_REMOTE_BRANCH), REF_REMOTE_BRANCH),

View File

@ -553,6 +553,7 @@ enum branch_track {
BRANCH_TRACK_REMOTE, BRANCH_TRACK_REMOTE,
BRANCH_TRACK_ALWAYS, BRANCH_TRACK_ALWAYS,
BRANCH_TRACK_EXPLICIT, BRANCH_TRACK_EXPLICIT,
BRANCH_TRACK_OVERRIDE,
}; };
enum rebase_setup_type { enum rebase_setup_type {

View File

@ -89,4 +89,25 @@ test_expect_success 'status when tracking annotated tags' '
grep "set up to track" actual && grep "set up to track" actual &&
git checkout heavytrack 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 test_done