40

Yesterday, I created a branch from a branch, pushed it to origin, and merged it back into master. You can see that here:

$ history |less
 8358  git co master
 8359   commit # shortcut that adds all and commits
 8360  push # shortcut that `git push`'s
 8361  git lg # shortcut that logs my output
 8362  git co 1600
 8363  git co -b 1601
 8364  npm run test
 8365  npm run test
 8366  npm run test
 8367  npm run test
 8368  npm run test
 8369  npm run test
 8370  npm run test
 8371  npm run test
 8372  npm run test
 8373  npm run test
 8374  npm run test
 8375  npm run test
 8376  npm run test
 8377  ./release.sh
 8378  ./release.sh
 8379  commit
 8380  push
 8381      git push --set-upstream origin 1601
 8382  git lg
 8383  git co master
 8384  git merge --no-ff -
 8385  git st
 8386  commit 
 8387  push 

I'm including irrelevant stuff in this list so I don't accidentally cut out something that is relevant; as you can see, all of this history is sequential. Here is everything in my history that refers to 1601:

$ history | grep 1601
 1601  npm run test
 8363  git co -b 1601
 8381      git push --set-upstream origin 1601
 8438  git co 1601
 8445  git co 1601
 8446  git show-ref 1601
 8447  history | grep 1601
 8449  git show-ref | grep 1601
 8458  git show-ref --heads --tags | grep 1601
 8460  history | grep 1601
 8461  history | grep (1601|merge)
 8462  history | grep -p (1601|merge)
 8464  history | grep -E (1601|merge)
 8466  history | grep -E -e (1601|merge)
 8467  history | grep -E -e \(1601|merge\)
 8468  history | grep -E -e '(1601|merge)'
 8469  history | grep -E -e '(1601|merge|master)'
 8470  history | grep -E -e '(1601|1601|merge|master)'
 8472  history | grep -E -e '(1601|1601|merge|master)'
 8474  history | grep -E -e '(1601|1601|merge|master)'
 8480  history | grep 1601

Somehow, after these steps, whenever I git co 1601, it gives me this warning:

$ git co 1601
warning: refname '1601' is ambiguous.
Already on '1601'
Your branch is up to date with 'origin/1601'.

I've been googling for a while, looking for others that have had this issue, but none of them seem to have the same situation. Here is what I've looked at that hasn't helped:

  1. Git warning: refname 'xxx' is ambiguous
  2. Git: refname 'master' is ambiguous
  3. git refname 'origin/master' is ambiguous
  4. http://thesimplesynthesis.com/post/git-error-warning-refname-originbranch-name-is-ambiguous

The following output is to help with troubleshooting:

$ git show-ref | grep 1601
137b74c8ff6807f07bb32ba0d2f76a3ba287e981 refs/heads/1601
137b74c8ff6807f07bb32ba0d2f76a3ba287e981 refs/remotes/origin/1601
$ git tag -l

$ git show-ref --heads --tags | grep 1601
137b74c8ff6807f07bb32ba0d2f76a3ba287e981 refs/heads/1601
cat .git/config
# this is the only place where it mentions 1601
[branch "1601"]
        remote = origin
        merge = refs/heads/1601

$ cat .git/config | grep 1601
[branch "1601"]
        merge = refs/heads/1601

$ git checkout 1601 --
warning: refname '1601' is ambiguous.
Already on '1601'
Your branch is up to date with 'origin/1601'.
$ git ls-remote . \*1601*
beea6ee68d6fe6b4f5222c0efe0e206e23af993c        refs/heads/1601
beea6ee68d6fe6b4f5222c0efe0e206e23af993c        refs/remotes/origin/1601
$ git show 1601 # this only shows one log message
warning: refname '1601' is ambiguous.
commit beea6ee68d6fe6b4f5222c0efe0e206e23af993c (HEAD -> 1601, origin/1601)
...
$ git --version
git version 2.31.1
$ type git
git is hashed (/usr/bin/git)

FWIW, I am using cygwin on Windows.

Why am I getting this warning, how do I get rid of it, and how do I prevent it in the future?

4
  • Try git checkout 1601 --. If you've got a file or directory named 1601 that'll fix the ambiguity.
    – jthill
    Commented Jun 13, 2021 at 1:36
  • @jthill that didn't have any effect. I put the command and output in the OP Commented Jun 13, 2021 at 2:09
  • So it's not ambiguous with some inadvertently-added path, the brute-force refs matcher is git ls-remote . \*1601*.
    – jthill
    Commented Jun 13, 2021 at 3:24
  • The last possibility I can think of is, 1601 matches the prefix of one or more id's for objects in the repo. say heads/1601 or refs/heads/1601 to eliminate that possibility, and I think git show has the most helpful info dump in response to ambiguity, try git show 1601 and see if it lists all the things it thinks you might have been asking for..
    – jthill
    Commented Jun 13, 2021 at 4:35

4 Answers 4

51

I can get this behavior by giving a branch a name that matches the SHA1 prefix of a commit.

$ git rev-list @ | egrep '^[0-9]{4}'
7802d6937673dbff4d26dc906c714a054c9e883e
81070af68e1b254c7f36eccb1261050a5a4a133a
7537dac08fd165845b6300f32c19a52fc7fa7299
$ git branch 7802
$ git branch 9999
$ git checkout 7802
warning: refname '7802' is ambiguous.
Switched to branch '7802'
$ git checkout 9999
Switched to branch '9999'
$

Since object id prefixes at least four digits long are legitimate ways of referring to objects, making a ref name that's also a four-or-more-long hex string is likely to produce this kind of ambiguity. So, don't do that. If you want to number something, include a type marker, like bugfix/1601 or something.

4
  • 2
    Wow! thank you for all the effort you put into this. Why am I getting this warning, how do I get rid of it, and how do I prevent it in the future? I now understand why, is the only way to get rid of it to rename my branches and put a character in it that isn't valid in a sha? Commented Jun 13, 2021 at 5:39
  • 7
    @DanielKaplan I think yes, or, you could also shorten your branch names to 3 numbers instead of 4, since you need at least 4 characters to reference a commit ID. I generally prefer more descriptive branch names anyway, but in your case, even something like test-1600, build-1600, z1600, or whatever makes sense there, would alleviate the problem.
    – TTT
    Commented Jun 13, 2021 at 5:52
  • 1
    I really want to accept this answer since you put in so much work. Mind updating it? Commented Jun 13, 2021 at 7:56
  • Just my two cent on the branch-name. I prefer a suffix instead of a prefix, because autocomplete works better with it. For my branch-names I use the following pattern <issue_number>-few_words_describing_the_issue. (I assume that 1600 is an issue number or something similar.)
    – gillesB
    Commented Jun 18, 2021 at 4:56
15

Why am I getting this warning ...

As you figured out via jthill's answer, it is because 1601 matches some suitable object's hash.

There are some other ways to get the same error, including making a branch and tag name that have the same spelling (e.g., git branch abc; git tag abc).

how do I get rid of it ...

Use unambiguous names. For branch-vs-tag, that means don't use the same name as a branch and tag name; for branch-or-tag vs commit hash, that means avoid commit-hash names that might occur here. As TTT commented, commit hash abbreviations must contain at least four characters, so abc is OK as a branch or tag name even though all three characters in abc are legitimate in hash IDs.

To see if a branch name might potentially collide with a hash ID, check whether it consists entirely of characters from the set [0-9][a-f][A-F] and is at least four characters long. If so, add some character that is outside the set, or shorten the name. A quick:

egrep '^[a-f]{4,}$' /usr/share/dict/words

turns up some interesting branch names to avoid, such as accede, aface, beaded, deed, and facade. (These are of course the sources of various fake hash IDs I like to use as examples, such as feedc0ffee, deadbeef, cafedad, and so on—some require a bit of 11ce45e1 with the spelling.)

and how do I prevent it in the future?

A really handy system is to systematize your branch names to include / or - or something: for instance, feature/c0ffee never runs into any issues like this.


1"License", in something vaguely resembling 1337-5p34k.

8

If you know that a ref-name is a branch or a tag you can prefix the id with either heads/ or tags/. So this works:

git checkout heads/1601

Given <refname> Git searches a list of locations. This is the list according to the git help revisions page:

  1. If $GIT_DIR/<refname> exists, that is what you mean (this is usually useful only for HEAD, FETCH_HEAD, ORIG_HEAD, MERGE_HEAD and CHERRY_PICK_HEAD);

  2. otherwise, refs/<refname> if it exists;

  3. otherwise, refs/tags/<refname> if it exists;

  4. otherwise, refs/heads/<refname> if it exists;

  5. otherwise, refs/remotes/<refname> if it exists;

  6. otherwise, refs/remotes/<refname>/HEAD if it exists.

So even if you have a branch with the name tags/1601 the ambiguity can be resolved by saying refs/heads/tags/1601.

3
  • 1
    I suggest that checkout is replaced with recommended switch command
    – maoizm
    Commented Jun 19, 2021 at 11:04
  • 2
    The question is about checkout, not switch. Moving this goalpost doesn't help anyone because someone might think that switch is part of the solution. But both checkout and switch have the same problem.
    – A.H.
    Commented Jun 20, 2021 at 21:59
  • oh, well. now it makes sense for me
    – maoizm
    Commented Jun 21, 2021 at 13:25
6

Why am I getting this warning, how do I get rid of it, and how do I prevent it in the future?

First, make sure to use git switch, not the old obsolete and confusing git checkout command.

Second, even with git switch, you will get that warning (even if you are already on that branch!):

vonc@vclp MINGW64 ~/git/test (29876e)
$ git switch -- 29876e
warning: refname '29876e' is ambiguous.
Already on '29876e'

But setting core.warnAmbiguousRefs to false would actually squash that warning.

$ git -c core.warnAmbiguousRefs=false switch 29876e
Already on '29876e' 
2
  • 7
    Switch is just an alternative, it's not obsolete nor deprecated and most likely not present in any of older manuals/articles/tutorials + has zero benefit for this problem. Commented Jun 13, 2021 at 9:09
  • 1
    @PeterBadida I agree, but I always try and promote the new switch/restore commands over checkout (which consider both branches and files).
    – VonC
    Commented Jun 13, 2021 at 9:15

Not the answer you're looking for? Browse other questions tagged or ask your own question.