git-checkout.txt: improve detached HEAD documentation
The detached HEAD state is a source of much confusion for users new to git. Here we try to document it better. Reworked from http://article.gmane.org/gmane.comp.version-control.git/138440 Requested-by: Nicolas Pitre <nico@fluxnic.net> Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
5673d695fc
commit
be8ef33c1d
@ -206,41 +206,139 @@ leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
|
|||||||
|
|
||||||
Detached HEAD
|
Detached HEAD
|
||||||
-------------
|
-------------
|
||||||
|
HEAD normally refers to a named branch (e.g. 'master'). Meanwhile, each
|
||||||
It is sometimes useful to be able to 'checkout' a commit that is
|
branch refers to a specific commit. Let's look at a repo with three
|
||||||
not at the tip of one of your branches. The most obvious
|
commits, one of them tagged, and with branch 'master' checked out:
|
||||||
example is to check out the commit at a tagged official release
|
|
||||||
point, like this:
|
|
||||||
|
|
||||||
------------
|
------------
|
||||||
$ git checkout v2.6.18
|
HEAD (refers to branch 'master')
|
||||||
|
|
|
||||||
|
v
|
||||||
|
a---b---c branch 'master' (refers to commit 'c')
|
||||||
|
^
|
||||||
|
|
|
||||||
|
tag 'v2.0' (refers to commit 'b')
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Earlier versions of git did not allow this and asked you to
|
When a commit is created in this state, the branch is updated to refer to
|
||||||
create a temporary branch using the `-b` option, but starting from
|
the new commit. Specifically, 'git commit' creates a new commit 'd', whose
|
||||||
version 1.5.0, the above command 'detaches' your HEAD from the
|
parent is commit 'c', and then updates branch 'master' to refer to new
|
||||||
current branch and directly points at the commit named by the tag
|
commit 'd'. HEAD still refers to branch 'master' and so indirectly now refers
|
||||||
(`v2.6.18` in the example above).
|
to commit 'd':
|
||||||
|
|
||||||
You can use all git commands while in this state. You can use
|
|
||||||
`git reset --hard $othercommit` to further move around, for
|
|
||||||
example. You can make changes and create a new commit on top of
|
|
||||||
a detached HEAD. You can even create a merge by using `git
|
|
||||||
merge $othercommit`.
|
|
||||||
|
|
||||||
The state you are in while your HEAD is detached is not recorded
|
|
||||||
by any branch (which is natural --- you are not on any branch).
|
|
||||||
What this means is that you can discard your temporary commits
|
|
||||||
and merges by switching back to an existing branch (e.g. `git
|
|
||||||
checkout master`), and a later `git prune` or `git gc` would
|
|
||||||
garbage-collect them. If you did this by mistake, you can ask
|
|
||||||
the reflog for HEAD where you were, e.g.
|
|
||||||
|
|
||||||
------------
|
------------
|
||||||
|
$ edit; git add; git commit
|
||||||
|
|
||||||
|
HEAD (refers to branch 'master')
|
||||||
|
|
|
||||||
|
v
|
||||||
|
a---b---c---d branch 'master' (refers to commit 'd')
|
||||||
|
^
|
||||||
|
|
|
||||||
|
tag 'v2.0' (refers to commit 'b')
|
||||||
|
------------
|
||||||
|
|
||||||
|
It is sometimes useful to be able to checkout a commit that is not at
|
||||||
|
the tip of any named branch, or even to create a new commit that is not
|
||||||
|
referenced by a named branch. Let's look at what happens when we
|
||||||
|
checkout commit 'b' (here we show two ways this may be done):
|
||||||
|
|
||||||
|
------------
|
||||||
|
$ git checkout v2.0 # or
|
||||||
|
$ git checkout master^^
|
||||||
|
|
||||||
|
HEAD (refers to commit 'b')
|
||||||
|
|
|
||||||
|
v
|
||||||
|
a---b---c---d branch 'master' (refers to commit 'd')
|
||||||
|
^
|
||||||
|
|
|
||||||
|
tag 'v2.0' (refers to commit 'b')
|
||||||
|
------------
|
||||||
|
|
||||||
|
Notice that regardless of which checkout command we use, HEAD now refers
|
||||||
|
directly to commit 'b'. This is known as being in detached HEAD state.
|
||||||
|
It means simply that HEAD refers to a specific commit, as opposed to
|
||||||
|
referring to a named branch. Let's see what happens when we create a commit:
|
||||||
|
|
||||||
|
------------
|
||||||
|
$ edit; git add; git commit
|
||||||
|
|
||||||
|
HEAD (refers to commit 'e')
|
||||||
|
|
|
||||||
|
v
|
||||||
|
e
|
||||||
|
/
|
||||||
|
a---b---c---d branch 'master' (refers to commit 'd')
|
||||||
|
^
|
||||||
|
|
|
||||||
|
tag 'v2.0' (refers to commit 'b')
|
||||||
|
------------
|
||||||
|
|
||||||
|
There is now a new commit 'e', but it is referenced only by HEAD. We can
|
||||||
|
of course add yet another commit in this state:
|
||||||
|
|
||||||
|
------------
|
||||||
|
$ edit; git add; git commit
|
||||||
|
|
||||||
|
HEAD (refers to commit 'f')
|
||||||
|
|
|
||||||
|
v
|
||||||
|
e---f
|
||||||
|
/
|
||||||
|
a---b---c---d branch 'master' (refers to commit 'd')
|
||||||
|
^
|
||||||
|
|
|
||||||
|
tag 'v2.0' (refers to commit 'b')
|
||||||
|
------------
|
||||||
|
|
||||||
|
In fact, we can perform all the normal git operations. But, let's look
|
||||||
|
at what happens when we then checkout master:
|
||||||
|
|
||||||
|
------------
|
||||||
|
$ git checkout master
|
||||||
|
|
||||||
|
HEAD (refers to branch 'master')
|
||||||
|
e---f |
|
||||||
|
/ v
|
||||||
|
a---b---c---d branch 'master' (refers to commit 'd')
|
||||||
|
^
|
||||||
|
|
|
||||||
|
tag 'v2.0' (refers to commit 'b')
|
||||||
|
------------
|
||||||
|
|
||||||
|
It is important to realize that at this point nothing refers to commit
|
||||||
|
'f'. Eventually commit 'f' (and by extension commit 'e') will be deleted
|
||||||
|
by the routine git garbage collection process, unless we create a reference
|
||||||
|
before that happens. If we have not yet moved away from commit 'f',
|
||||||
|
any of these will create a reference to it:
|
||||||
|
|
||||||
|
------------
|
||||||
|
$ git checkout -b foo <1>
|
||||||
|
$ git branch foo <2>
|
||||||
|
$ git tag foo <3>
|
||||||
|
------------
|
||||||
|
|
||||||
|
<1> creates a new branch 'foo', which refers to commit 'f', and then
|
||||||
|
updates HEAD to refer to branch 'foo'. In other words, we'll no longer
|
||||||
|
be in detached HEAD state after this command.
|
||||||
|
|
||||||
|
<2> similarly creates a new branch 'foo', which refers to commit 'f',
|
||||||
|
but leaves HEAD detached.
|
||||||
|
|
||||||
|
<3> creates a new tag 'foo', which refers to commit 'f',
|
||||||
|
leaving HEAD detached.
|
||||||
|
|
||||||
|
If we have moved away from commit 'f', then we must first recover its object
|
||||||
|
name (typically by using git reflog), and then we can create a reference to
|
||||||
|
it. For example, to see the last two commits to which HEAD referred, we
|
||||||
|
can use either of these commands:
|
||||||
|
|
||||||
|
------------
|
||||||
|
$ git reflog -2 HEAD # or
|
||||||
$ git log -g -2 HEAD
|
$ git log -g -2 HEAD
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|
||||||
EXAMPLES
|
EXAMPLES
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user