Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions Documentation/detached-head.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
`HEAD` is where Git stores your current branch. `HEAD` can either be:

1. A branch, which is your current branch.
2. A commit ID, when you don't have a current branch.
This is called "detached HEAD state".

It can sometimes be useful for `HEAD` to be a commit ID.
For example, it lets you look at an old version of your code
(with `git checkout COMMIT_ID`).

The only problem is that if you create new commits while in detached
HEAD state, those commits won't be on a branch. This makes those new
commits much harder to find later. Also, Git considers commits that
aren't on any branch (or a tag or other reference) to be garbage.
Git will eventually permanently delete those "garbage" commits during
garbage collection.

There are 3 main ways you can end up in detached HEAD state
unintentionally:

1. `git checkout COMMIT_ID`, where `COMMIT_ID` is a commit ID
2. `git checkout v1.3`, where v1.3 is a tag name
3. `git checkout origin/main`, where `origin/main` is
a remote-tracking branch

Checking out a tag puts you in detached HEAD state because `HEAD` can
only be a branch or a commit, not a tag or any other reference.
So `git checkout TAG` will set HEAD to the commit for that tag.

The easiest way to avoid accidentally ending up in detached HEAD state
is to use linkgit:git-switch[1] instead of linkgit:git-checkout[1] to
switch branches. `git switch` won't let you detach unless you explicitly
pass the `--detach` argument.

To get back onto a branch, you can:

1. Switch to the branch you want to be on, with `git switch BRANCHNAME`.
2. Create a new branch at the current commit, with `git switch -c BRANCHNAME`.
You might want to do this if you've created new commits, so that you can
find the commit later and so that it won't be garbage collected.

If you create commits in detached HEAD state that aren't on a branch,
you can find them later using linkgit:git-reflog[1].
129 changes: 1 addition & 128 deletions Documentation/git-checkout.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -376,135 +376,8 @@ For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
[[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:

------------
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 # or "git switch -c 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
------------
include::detached-head.adoc[]

[[ARGUMENT_DISAMBIGUATION]]
ARGUMENT DISAMBIGUATION
Expand Down
14 changes: 14 additions & 0 deletions Documentation/gitdetachedhead.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
gitdetachedhead(7)
===============

NAME
----
gitdetachedhead - How detached HEAD state works

DESCRIPTION
-----------
include::detached-head.adoc[]

GIT
---
Part of the linkgit:git[1] suite
1 change: 1 addition & 0 deletions advice.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ void detach_advice(const char *new_name)
"\n"
" git switch -\n"
"\n"
"Run `git help detachedhead` to learn more.\n"
"Turn off this advice by setting config variable advice.detachedHead to false\n\n");

fprintf(stderr, fmt, new_name);
Expand Down
1 change: 1 addition & 0 deletions command-list.txt
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ gitcore-tutorial guide
gitcredentials guide
gitcvs-migration guide
gitdatamodel guide
gitdetachedhead guide
gitdiffcore guide
giteveryday guide
gitfaq guide
Expand Down
Loading