1

I just cloned a repo and tried to checkout a branch. The branch is checked out in detached head mode! I don't understand why it should do that. I just cloned the repository.

$ git checkout PATCH_branch
Note: checking out 'PATCH_branch'.

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.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

git checkout -b <new-branch-name>

HEAD is now at 896c259... xxxxxxxxxxxxxxxxxxxxxxxxxxx

I figured perhaps I can create a local branch and make it track the remote. So I did:

$ git checkout -b PATCH_branch origin/PATCH_branch
fatal: Cannot update paths and switch to branch 'PATCH_branch' at the same time.
Did you intend to checkout 'origin/PATCH_branch' which can not be resolved as commit?

Could someone please explain what the last bit means? Or why I can't checkout a branch without being detached? I know under certain circumstances I might end up with a detached HEAD, but this isn't one of them.

3 Answers 3

10

There is no origin/PATCH_branch. Instead, there is a tag that is very poorly named, and in your clone, you have checked out that tag, resulting in the detached HEAD.

Why this happened

If you consult the gitrevisions documentation, you will see a sequenced list of possibilities for resolving a symbolic reference name:

<refname>, e.g. master, heads/master, refs/heads/master

A symbolic ref name. E.g. master typically means the commit object referenced by refs/heads/master. If you happen to have both heads/master and tags/master, you can explicitly say heads/master to tell Git which one you mean. 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;

In this particular case, the name PATCH_branch is not in fact ambiguous, but the rules (especially the parts I put in bold text) still apply: if there is a tag named PATCH_branch, and neither rule #1 nor rule #2 are able to resolve the name to a commit hash but the tag can, Git can check out the tag, so we don't need to go on to look at rules 4, 5, and 6; but here they are anyway:

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

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

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

Of these six rules, only one—specifically rule 4—will not give you a "detached HEAD" checkout. Since you did get a detached HEAD, clearly rule 4 did not apply.

Special rules for git checkout

Now, git checkout has its own additional "rule 4.5", where it will create refs/heads/refname in some situations. That extra git checkout rule is the rule you were expecting to experience here, I believe.

Specifically, git checkout will, even before trying rules 1, 2, and 3, try rule 4. If this fails, git checkout will then see if it can create a local branch based on the existence of exactly one matching remote-tracking branch. In either of these two cases, rule 4 then applies and git checkout does not give you a "detached HEAD". Otherwise git checkout goes back and starts over at rule 1.

Clones initially have only remote-tracking branches and tags

You mentioned that this is a new clone, and in new clones, there is one (and only one) remote and by default, you get all of its branches as remote-tracking branches. If the remote is named origin (as it usually is), these remote-tracking branches live in the refs/remotes/origin/ part of your repository's name-space. You also, by default, get all of the remote's tags, which live in your refs/tags/ name-space.

The last step of git clone is git checkout

When you run:

$ git clone <url>

or:

$ git clone <url> <destination>

Git will connect to the given URL, verify that there is a Git repository there, ask that remote for a list of all branches and tags, and then create a clone repository for you in the given destination directory (or use the last part of the URL to make a default destination name). In that repository, Git will add a remote named origin (or whatever name you specify with -o). It will copy all of their tags to your tags, and copy their branches to your refs/remotes/origin/ remote-tracking branches (if you specify a different -o, modify these names as appropriate). The resulting repository has no local branches at all.

However, at this point, git clone invokes git checkout, to check out some branch—the one you told it to (git clone -b) or, by default, the one your Git got from the remote, usually master. Of course, you don't have a local master branch, and this is where what I called "rule 4.5" comes in: git checkout looks to see if there is an origin/master, and of course there is, so your Git makes a new local branch named master that tracks remote-tracking branch origin/master.1 This is, in fact, how you get your master branch!

When you ran git checkout PATCH_branch you no doubt expected Git to follow this same pattern: there should be an origin/PATCH_branch, and your Git should create a new (regular, ordinary, local) branch named PATCH_branch based on origin/PATCH_branch (which is really refs/remotes/origin/PATCH_branch).

But instead, what you have is a tag, refs/tags/PATCH_branch. So the special "create local branch from remote-tracking branch" rule does not apply, and the "early application of rule 4" does not apply either, and we're left with rules 1 and 2 (which do not apply) and then rule 3, and that got you the "detached HEAD" checkout.

You can create a local branch, but be careful!

Look back over the six rules. Suppose you have both refs/heads/PATCH_branch and refs/tags/PATCH_branch. Note that rule 3 normally applies before rule 4: most Git commands will treat PATCH_branch as the tag.

Because git checkout is special, and applies rule 4 first (instead of after rule 3), you will be able to check out the local branch. But other Git commands will behave in ways you won't expect, as they will apply rule 3 first.

The tag is poorly named

Tag names should probably not contain the word "branch". Whether you can or should fix this is an administrative question more than a technical one. Find out who created the tag and why, and see if you can get everyone on your project to agree that this is a bad name and thus to delete it.


1The names here are admittedly terribly confusing. The local branch master is not a "(remote-)tracking branch", but it is "tracking" another branch. The remote-tracking branch origin/master is something your Git stores locally; it's just automatically updated from whatever your Git sees on origin, whenever your Git talks with their Git. So your branch—your master—is "tracking" a remote-tracking branch, origin/master. All that really means is that your master has origin/master set as its upstream, which is a newer, somewhat better term. Older Git documentation (pre-version-1.8 or so) does not define upstream quite this carefully, though.

1
  • 1
    What an explanation! Thank you. That's exactly what it was. A tag.
    – Amir Keibi
    Commented Jul 19, 2016 at 20:16
5

Typically, when you git clone a repository, it will only contain a single branch (usually master, but in can be different depending on what HEAD refers to in the origin repository). It will also have remote references for the branches the origin repository has (these will be named like refs/remotes/origin/branchname). If you then do git checkout branchname, it will check out the commit found in refs/remotes/origin/branchname, but since that is not a branch (which would be named refs/heads/branchname), you get a detached HEAD - you're no longer looking at a branch.

To resolve that, you can follow the advice given in the message that git showed you git checkout -b <branchname>, essentially creating a new branch at the commit you have checked out, or run the command you attempted in your second listing. The caveat with the second command is that you need to get back on a branch first (e.g. git checkout master) before that command will succeed. If you had run git checkout -b <branchname> origin/<branchname> first, it would have been successful. That will also set up the new branch to "track" the origin branch, so you can do git push, git pull, etc. with it.

2
  • he can also check git remote -v and git fetch origin, and that he's pulled the remote branches, too with `git branch -avv Commented Jul 19, 2016 at 19:26
  • This would normally be true, but assuming the OP's sequencing is correct, he has a tag named PATCH_branch which he got during the clone.
    – torek
    Commented Jul 19, 2016 at 19:41
0

you are using checkout instead of clone to get the repository (tho you could simply be skipping the cloning part for your question).

It would seem that your repo doesn't hold any remote repository to check out to. What's the output of git remote -v ?

It should probably the same remote repository called origin, once for fetching and once for pushing. If you don't have any, you should git remote add <remoteRepo>

1
  • I'm not using checkout instead of clone. My remotes are fine.
    – Amir Keibi
    Commented Jul 19, 2016 at 20:00

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