Junio C Hamano <gitster@xxxxxxxxx> writes: > I took a brief look at --set-upstream codepath, and I have to say that the > implementation is totally broken with respect to an existing branch. > > Given > > $ git branch master --set-upstream origin/master > > it passes the exact same codepath as > > $ git branch master origin/master > > uses, only with a different "track" flag, no? That is, it calls a > function that is meant to _create_ branch "master" from given branch point > "origin/master", namely create_branch(). And then create_branch(), > contrary to its name, is littered with "dont_change_ref" special case to > work it around, depending on the value of "track". So here is a quick-and-dirty patch, which may or may not compile or pass tests. branch.c | 21 ++++++++++++--------- branch.h | 12 +++++++++++- builtin/branch.c | 2 +- builtin/checkout.c | 3 ++- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/branch.c b/branch.c index 478d825..fecedd3 100644 --- a/branch.c +++ b/branch.c @@ -135,23 +135,25 @@ static int setup_tracking(const char *new_ref, const char *orig_ref, return 0; } -int validate_new_branchname(const char *name, struct strbuf *ref, int force) +int validate_new_branchname(const char *name, struct strbuf *ref, + int force, int attr_only) { - const char *head; - unsigned char sha1[20]; - if (strbuf_check_branch_ref(ref, name)) die("'%s' is not a valid branch name.", name); if (!ref_exists(ref->buf)) return 0; - else if (!force) + else if (!force && !attr_only) die("A branch named '%s' already exists.", ref->buf + strlen("refs/heads/")); - head = resolve_ref("HEAD", sha1, 0, NULL); - if (!is_bare_repository() && head && !strcmp(head, ref->buf)) - die("Cannot force update the current branch."); + if (!attr_only) { + const char *head; + unsigned char sha1[20]; + head = resolve_ref("HEAD", sha1, 0, NULL); + if (!is_bare_repository() && head && !strcmp(head, ref->buf)) + die("Cannot force update the current branch."); + } return 1; } @@ -171,7 +173,8 @@ void create_branch(const char *head, if (track == BRANCH_TRACK_EXPLICIT || track == BRANCH_TRACK_OVERRIDE) explicit_tracking = 1; - if (validate_new_branchname(name, &ref, force || track == BRANCH_TRACK_OVERRIDE)) { + if (validate_new_branchname(name, &ref, force, + track == BRANCH_TRACK_OVERRIDE)) { if (!force) dont_change_ref = 1; else diff --git a/branch.h b/branch.h index 01544e2..1285158 100644 --- a/branch.h +++ b/branch.h @@ -20,8 +20,18 @@ void create_branch(const char *head, const char *name, const char *start_name, * interpreted ref in ref, force indicates whether (non-head) branches * may be overwritten. A non-zero return value indicates that the force * parameter was non-zero and the branch already exists. + * + * Contrary to all of the above, when attr_only is 1, the caller is + * not interested in verifying if it is Ok to update the named + * branch to point at a potentially different commit. It is merely + * asking if it is OK to change some attribute for the named branch + * (e.g. tracking upstream). + * + * NEEDSWORK: This needs to be split into two separate functions in the + * longer run for sanity. + * */ -int validate_new_branchname(const char *name, struct strbuf *ref, int force); +int validate_new_branchname(const char *name, struct strbuf *ref, int force, int attr_only); /* * Remove information about the state of working on the current diff --git a/builtin/branch.c b/builtin/branch.c index aa705a0..f49596f 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -566,7 +566,7 @@ static void rename_branch(const char *oldname, const char *newname, int force) die(_("Invalid branch name: '%s'"), oldname); } - validate_new_branchname(newname, &newref, force); + validate_new_branchname(newname, &newref, force, 0); strbuf_addf(&logmsg, "Branch: renamed %s to %s", oldref.buf, newref.buf); diff --git a/builtin/checkout.c b/builtin/checkout.c index 3bb6525..5e356a6 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -1073,7 +1073,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) if (opts.new_branch) { struct strbuf buf = STRBUF_INIT; - opts.branch_exists = validate_new_branchname(opts.new_branch, &buf, !!opts.new_branch_force); + opts.branch_exists = validate_new_branchname(opts.new_branch, &buf, + !!opts.new_branch_force, 0); strbuf_release(&buf); } -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html