Путеводитель по Руководству Linux

  User  |  Syst  |  Libr  |  Device  |  Files  |  Other  |  Admin  |  Head  |



   git-checkout    ( 1 )

смена ветвей или восстановление файлов рабочего дерева (Switch branches or restore working tree files)

  Name  |  Synopsis  |  Description  |  Options  |    Detached head    |  Argument disambiguation  |  Examples  |  See also  |

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:

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:

$ 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