Reputation: 2144
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.
Upvotes: 1
Views: 7615
Reputation: 488183
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.
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:
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);
otherwise, refs/<refname> if it exists;
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:
otherwise, refs/heads/<refname> if it exists;
otherwise, refs/remotes/<refname> if it exists;
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.
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.
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.
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.
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.
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.
Upvotes: 10
Reputation: 62379
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.
Upvotes: 5
Reputation: 783
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>
Upvotes: 0