From recent work in devops, it seems as though there are "two ways" to check out a branch in git: using the plain branch name, e.g. dev
, or using the branch name prefixed with refs/heads/
, e.g. refs/heads/dev
.
What is the difference between the two?
Certain HTTP POST content in the Bitbucket webhook to Jenkins gives the "refs/head
" version of the branch. Other POST content gives the "basename" branch.
E.g. using (what I think is) Jenkins syntax to fetch POST content from a pull-request Bitbucket event, $.pullRequest.fromRef.id
== /refs/heads/dev
...
and $.pullRequest.fromRef.displayId
== dev
In a cloned repository, checking out refs/heads/dev
and dev
resolves to the same SHAID, but their respective stdout
s differ:
$ git checkout refs/heads/dev
Note: checking out 'refs/heads/dev'.
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 c320fd1... wip
$ git checkout dev
Switched to branch 'dev'
Your branch is up-to-date with 'origin/dev'.
$ git log --oneline -n 1
c320fd1 wip
The stdout
of the former looks the same as when you check out a SHAID.
Names are resolved to revision id's early, according to the rules in the docs.
When the ref you give is resolved by (just) adding a refs/heads/
prefix, Git's convenience machinery kicks in, git checkout
will make HEAD
be an alias for the branch tip, so all the convenience commands that rely on HEAD
will be referring to and updating the branch tip ref.
So when you say git checkout dev
, you're using Git's convenience machinery and it does the convenience thing for you, it wires HEAD
to be a symbolic reference to refs/heads/dev
and git commit
's HEAD
update will be redirected to that branch tip.
But if you bypass the convenience logic by taking explicit steps yourself, that doesn't happen. That's really the sole difference. If you want, you can
git checkout refs/heads/dev
git symbolic-ref HEAD refs/heads/dev
and now you've done Git's convenience processing yourself.