Re: git branch --set-upstream regression in master
From: Junio C Hamano <hidden>
Date: 2016-06-15 22:52:03
Subsystem:
the rest · Maintainer:
Linus Torvalds
Possibly related (same subject, not in this thread)
- 2016-06-15 · git branch --set-upstream regression in master · Jay Soffian <hidden>
- 2016-06-15 · Re: git branch --set-upstream regression in master · Junio C Hamano <hidden>
- 2016-06-15 · Re: git branch --set-upstream regression in master · Junio C Hamano <hidden>
- 2016-06-15 · Re: git branch --set-upstream regression in master · Jay Soffian <hidden>
Junio C Hamano [off-list ref] 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); }