Last week I observed a rather strange event, more than git usually shows me. It detached my head (not figuratively, but in a git-way).
I work in a project with more than one branch, they have remotes related to each repo user (or user+feature/bug) and each one works in the assigned issues, my project leader created they own branch and made modifications, then I tried to check it out, but, for an strange reason my local copy fell into a detached HEAD state.
Why? Because I referenced the “origin/” prefix. I previously detached my HEAD using the commit reference in checkout commad, but never I detached it using a branch reference. It’s new to me.
Obviously I searched for an answer, I returned to the git manual, it reads I must do a “git fetch” before (I already did it before) and list all the branches (I already did it) but, in the list there’s no branch called “branch_name” *. But there’s a branch called “origin/branch_name”. So when I tried to do a “checkout branch_name”, git said me “There’s no branch called ‘branch_name’”… Then I tried to get the “origin/branch_name” and I get the detached HEAD state.
*Names in this post have been changed to protect the identity and integrity of the branches and commits.
What “detached HEAD” status is
If you has never detached your HEAD, I tell what it is:
Every time you work with git, you have a pointer, it’s your HEAD, the pointer must point to a certain branch, originally your pointer points to master after you cloned a project in a local repo, but working with branches, you can switch where you point your HEAD. If you use the checkout command you can change the branch your pointer points. The detached HEAD is an state showing that you pointer doesn’t point to a certain branch, you can modify your files but it wouldn’t be persisted in any branch (until you create a local branch or switch to a certain one), it’s used for discardable experiments as the git documentation says.
Your local copy can acquire this status when you point your HEAD to a certain commit hash. It’s like go back in time (as in a time machine) to a certain commit to see the file status in that time. Or you can detached your HEAD pointing to a remote branch using the “origin/branch_name” way.
Following with the strange story
As you can see, it’s logic that I detached my HEAD using that command… But what if I tried to list the branches again? Now, I can see the “branch_name” branch and I can checkout it… WHY? I have no answer… Something weird happends, but I don’t know what.
After that moment, everything works as expected, my local branches are ok and the remotes too. And my HEAD points to the right branch.
Foot note about git checkout and switching between branches
Reading the docs again I see a new command called switch (from git v2.27, mid 2020). It command switches (as its name says) between branches and… I readed an exact command that answer my question:
$ git switch origin/branch_name
As I read in docs, when switch is used, the default behaviour is use the guess option:
<branch>is not found but there does exist a tracking branch in exactly one remote (call it
<remote>) with a matching name, treat as equivalent to
$ git switch -c <branch> --track <remote>/<branch>
It creates the “branch_name” locally tracking the remote “branch_name”. Note the track option, it exists in the checkout command but I never used it before, it could solve the strange behaviour (or not).
And about documentation…
Documenting is a task all developer must spend time in. Why? Because developers create tools and tools must to have a manual. And documenting is the only way another developer can learn to avoid break something, and the time (and money) spent in fix something is more than the time spent in learn how to use that.
As I ever say:
Before use a tool for first time, you must know how to use it. And the “how to use the tool” is explained in its documentation. Read it before.
You can learn by listening and trying, but you would read the manual first.