From: Junio C Hamano Date: Mon, 28 Feb 2011 05:58:30 +0000 (-0800) Subject: Merge branch 'js/detach-doc' X-Git-Tag: v1.7.5-rc0~114 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=99f45c2a5db46c1397a80b0ab282456006b40cb1;p=git.git Merge branch 'js/detach-doc' * js/detach-doc: git-checkout.txt: improve detached HEAD documentation --- 99f45c2a5db46c1397a80b0ab282456006b40cb1 diff --cc Documentation/git-checkout.txt index 87863fcad,ca8b7d1ba..396f4cc15 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@@ -213,42 -204,140 +213,140 @@@ leave out at most one of `A` and `B`, i -Detached HEAD +DETACHED HEAD ------------- + HEAD normally refers to a named branch (e.g. 'master'). Meanwhile, each + branch refers to a specific commit. Let's look at a repo with three + commits, one of them tagged, and with branch 'master' checked out: - It is sometimes useful to be able to 'checkout' a commit that is - not at the tip of one of your branches. The most obvious - example is to check out the commit at a tagged official release - point, like this: + ------------ + HEAD (refers to branch 'master') + | + v + a---b---c branch 'master' (refers to commit 'c') + ^ + | + tag 'v2.0' (refers to commit 'b') + ------------ + + When a commit is created in this state, the branch is updated to refer to + the new commit. Specifically, 'git commit' creates a new commit 'd', whose + parent is commit 'c', and then updates branch 'master' to refer to new + commit 'd'. HEAD still refers to branch 'master' and so indirectly now refers + to commit 'd': ------------ - $ git checkout v2.6.18 + $ 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') ------------ - Earlier versions of git did not allow this and asked you to - create a temporary branch using the `-b` option, but starting from - version 1.5.0, the above command 'detaches' your HEAD from the - current branch and directly points at the commit named by the tag - (`v2.6.18` in the example above). - - 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. + 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 log -g -2 HEAD + $ 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 + ------------ EXAMPLES --------