Interesting.
This is because "git checkout -b <name>" tries to make sure that
"refs/heads/<name>" does not exist, and the way it does it to pass it
to get_sha1() and make sure it fails.
It almost always works, except when that string is passed from get_sha1()
to get_describe_name(), which takes "ANYTHING-g<hexstring>" and as long as
hexstring names an existing object, it says "Yup, I found one."
I think the right fix is to make sure that "refs/heads/<name>" does not
exist by checking exactly that.
Perhaps something like this. I am not sure if we want to use the "yield
non zero to signal not an error but an early return" trick like I did in
this patch, though.
---
builtin/checkout.c | 2 +-
refs.c | 14 ++++++++++++++
refs.h | 1 +
3 files changed, 16 insertions(+), 1 deletions(-)
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 28cdc51..af1e7b5 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1071,7 +1071,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
if (strbuf_check_branch_ref(&buf, opts.new_branch))
die(_("git checkout: we do not like '%s' as a branch name."),
opts.new_branch);
- if (!get_sha1(buf.buf, rev)) {
+ if (ref_exists(buf.buf)) {
opts.branch_exists = 1;
if (!opts.new_branch_force)
die(_("git checkout: branch %s already exists"),diff --git a/refs.c b/refs.c
index e3c0511..138b1a0 100644
--- a/refs.c
+++ b/refs.c
@@ -1826,6 +1826,20 @@ int update_ref(const char *action, const char *refname,
return 0;
}
+static int compare_ref_name(const char *refname,
+ const unsigned char *sha1, int flag,
+ void *cb_data)
+{
+ if (!strcmp(cb_data, refname))
+ return -1; /* early return */
+ return 0;
+}
+
+int ref_exists(char *refname)
+{
+ return for_each_ref(compare_ref_name, refname) != 0;
+}
+
struct ref *find_ref_by_name(const struct ref *list, const char *name)
{
for ( ; list; list = list->next)diff --git a/refs.h b/refs.h
index 5e7a9a5..5839487 100644
--- a/refs.h
+++ b/refs.h
@@ -35,6 +35,7 @@ extern int for_each_ref_in_submodule(const char *submodule, const char *prefix,
extern int for_each_tag_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);
extern int for_each_branch_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);
extern int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);
+extern int ref_exists(char *);
static inline const char *has_glob_specials(const char *pattern)
{