When I execute
git checkout remotes/origin/test_branch
my HEAD goes in a detached state. Below is output:
C:\..\git_test>git checkout remotes/origin/test_branch
Note: checking out 'remotes/origin/test_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 4590fa2 Test branch commit
M src/test/resources/**
C:\..\git_test>git branch -a
* (HEAD detached at origin/test_branch)
test_branch
master
remotes/origin/HEAD -> origin/master
remotes/origin/test_branch
remotes/origin/master
And if I execute
git checkout test_branch
on the same branch then I am no more in a detached state.
C:\..\git_test>git checkout test_branch
Switched to branch 'test_branch'
M src/test/resources/**
Your branch is up to date with 'origin/test_branch'.
C:\..\git_test>git branch -a
* test_branch
master
remotes/origin/HEAD -> origin/master
remotes/origin/test_branch
remotes/origin/master
Please can anyone explain what is the difference and why it is going to the detached state while the branch is same?
Unlike traditional version control systems, Git does not habitually talk to a central server. You have a complete copy of the repository and all its history. All commands are happening locally except a handful like git pull
, git push
, and git fetch
.
Instead, Git keeps track of the state of remote repositories with "remote tracking branches". These are just like normal branches, except they mark the last place it saw a branch on a remote server, and you can't commit to them. These are updated when you do git fetch
which happens as part of a git pull
.
(One of the important things to know is that a Git "branch" is nothing more than a label pointing at a commit.)
test_branch
is a local branch in your repository. remotes/origin/test_branch
, usually referred to as origin/test_branch
, is the location of a branch called test_branch
on the remote called origin
the last time you did a git fetch
. If they're related, test_branch
will have origin/test_branch
as its upstream.
When you git checkout test_branch
git checks out the commit test_branch
is pointing at, moves HEAD
to that commit (HEAD
tracks the currently checked out commit), and marks you as being on the test_branch
.
If you git commit
you advance HEAD
and test_branch
.
git checkout master
[HEAD]
A - B - C - D [master]
\
E - F [test_branch]
git checkout test_branch
A - B - C - D [master]
\
E - F [test_branch]
[HEAD]
git commit -a
A - B - C - D [master]
\
E - F - G [test_branch]
[HEAD]
When you git checkout origin/test_branch
git checks out the commit origin/test_branch
is pointing at, moves HEAD
to that commit (HEAD
tracks the currently checked out commit)... and because its a remote tracking branch that's it. You are no longer on a branch, you are in a "detached HEAD" state.
If you git commit
you advance HEAD
, but origin/test_branch
remains where it was.
git checkout master
[HEAD]
A - B - C - D [master]
\
E - F [origin/test_branch]
git checkout origin/test_branch
A - B - C - D [master]
\
E - F [origin/test_branch]
[HEAD]
git commit -a
A - B - C - D [master]
\
E - F [origin/test_branch]
\
G [HEAD]
With no associated branch there is nothing referring to this new commit. If you were to git checkout master
then G
would be dangling, effectively lost, though it can be found using git reflog
.
git checkout master
[HEAD]
A - B - C - D [master]
\
E - F [origin/test_branch]
\
G
See Working with Remotes for more.