5

I have a local branch "master" tracking a remote branch "origin/master".

When I checkout master like this:

git checkout refs/heads/master

I end up with a detached HEAD:

Note: checking out 'refs/heads/master'.

You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout.

Obviously I could just checkout "master", but that happens to be an ambiguous reference. I just want to know what the "git way" to disambiguate a branch name is, without detaching HEAD.

5
  • 1
    possible duplicate of Git: refname 'master' is ambiguous
    – Chris
    Commented Sep 11, 2014 at 14:29
  • 3
    I don't think it's a duplicate. My question is not about the warning itself (that's quite clear). It's just about the detached HEAD state after checking out refs/heads/master. (I'll edit the question to clarify.)
    – Jan
    Commented Sep 11, 2014 at 14:54
  • What do you mean with "disambiguate a branch name without detaching HEAD"?, what is the expected result ?
    – dseminara
    Commented Sep 11, 2014 at 16:48
  • In a really generic context (i.e. you don't know about existing tags or other references that might conflict with the branch name master), how do I checkout the branch master without any ambiguity? I can not checkout refs/heads/master, which would be the most logical thing in my eyes, because that detaches HEAD.
    – Jan
    Commented Sep 12, 2014 at 8:11
  • possible duplicate of Why does `git checkout` with explicit 'refs/heads/branch' give detached HEAD?
    – gunr2171
    Commented Apr 10, 2015 at 13:04

1 Answer 1

3

The documentation for git checkout is silent on how it behaves when master is ambiguous. Looking at the source code (I skimmed quickly so I might be wrong), it looks like git checkout assumes that the provided name (e.g., master) is a branch name until it discovers that there is no ref in refs/heads/* for the given name.

So the proper way to check out a branch when the revision is ambiguous is to leave off the refs/heads/, e.g., git checkout master.

Branch vs. revision

Note that there is a subtle but important difference between specifying a branch and specifying a revision (or other object). For commands and options that take a revision (or general object), specifying master is the same as specifying refs/heads/master unless master is ambiguous. It's also the same as specifying master^0, or the SHA1 that master is pointing to, etc.

For commands and options that take a branch (e.g., git branch, or the --branches option to commands like git log), specifying master is not the same as specifying refs/heads/master. In these cases, the full string refs/heads/master is interpreted as the name of the branch, causing Git to create/examine/update the ref named refs/heads/refs/heads/master instead of refs/heads/master.

The git checkout command is versatile, which is handy but can cause confusion in cases like master vs. refs/heads/master. When you specify master, and a ref named refs/heads/master exists, git checkout assumes you meant the master branch, not the revision that master is pointing to. When you specify refs/heads/master, and a ref named refs/heads/refs/heads/master does not exist, then git checkout assumes you meant the revision that master is pointing to, not a branch named refs/heads/master (thus you get a detached HEAD).

Checking out the non-branch when ambiguous

If you want to check out some other ref whose short name is also master (e.g. a tag named master), you'll have to spell out the full ref name (e.g., git checkout refs/tags/master) or spell the revision in a way that can't be interpreted as a valid branch name (e.g., git checkout master^0). The latter causes git checkout to follow the disambiguation rules described in git help revisions:

When ambiguous, a <refname> is disambiguated by taking the first match in the following rules:

  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.

Of course the result will be a detached HEAD, but that always happens when you check out a non-branch.

3
  • Thanks for clarifying the point about git's behaviour in the ambiguous case. I have no objection to git detaching HEAD when I actually checkout a non-branch, but refs/heads/master is arguably a branch, regardless of how I reference it, isn't it?
    – Jan
    Commented Sep 12, 2014 at 8:07
  • @Jan: I added some paragraphs to hopefully answer your question. Commented Sep 12, 2014 at 18:59
  • This should be in the git documentation. Thanks! Though I think the warning about an ambiguous reference is bogus when you can't actually disambiguate further.
    – Jan
    Commented Sep 14, 2014 at 6:21

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