Skip to content

Commit 88e36e4

Browse files
committed
doc: checkout: rewrite detached HEAD state explanation
The current explanation has the following issues: - Says detached HEAD state is useful but doesn't explain why - Takes many paragraphs before explaining what detached HEAD state is - It's common for users to accidentally end up in detached HEAD state, but it doesn't explain why that might happen - One of the UI improvements in `git switch` is to make it harder to detach accidentally, but that isn't advertised. See 7968bef (switch: only allow explicit detached HEAD, 2019-03-29) - Too many confusing diagrams Write a new explanation addressing these issues, and put it in a standalone guide so that we can easily reference it from advice ("see `git help detachedhead`"). The result is a shorter guide that covers more material. The framing that "Git considers commits that aren't on a branch/other reference to be garbage" is taken from Steve Klabnik's tutorial https://steveklabnik.github.io/jujutsu-tutorial/branching-merging-and-conflicts/anonymous-branches.html. It's funny and it's consistent with the way Git uses the term "garbage collection". Signed-off-by: Julia Evans <julia@jvns.ca>
1 parent 5a7d1e8 commit 88e36e4

5 files changed

Lines changed: 54 additions & 128 deletions

File tree

‎Documentation/detached-head.adoc‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
`HEAD` is where Git stores your current branch. `HEAD` can either be:
2+
3+
1. A branch, which is your current branch (the normal case)
4+
2. A commit ID (this is called "detached HEAD state")
5+
6+
It can be useful for `HEAD` to be a commit ID. For example, it lets you
7+
look at an old version of your code (with `git checkout COMMIT_ID`).
8+
9+
The only problem is that if you create new commits while in detached
10+
HEAD state, those commits won't be on a branch. This makes those new
11+
commits much harder to find later. Also, Git considers commits that
12+
aren't on any branch (or a tag or other reference) to be garbage.
13+
Git will eventually permanently delete those "garbage" commits during
14+
garbage collection.
15+
16+
There are 3 main ways you can end up in detached HEAD state
17+
unintentionally:
18+
19+
1. `git checkout COMMIT_ID`, where `COMMIT_ID` is a commit ID
20+
2. `git checkout v1.3`, where v1.3 is a tag name
21+
3. `git checkout origin/main`, where `origin/main` is
22+
a remote-tracking branch
23+
24+
The easiest way to avoid accidentally ending up in detached HEAD state
25+
is to use linkgit:git-switch[1] instead of linkgit:git-checkout[1] to
26+
switch branches. `git switch` won't let you detach unless you explicitly
27+
pass the `--detach` argument.
28+
29+
To get back onto a branch, you can:
30+
31+
1. Switch to the branch you want to be on, with `git switch BRANCHNAME`.
32+
2. Create a new branch at the current commit, with `git switch -c BRANCHNAME`.
33+
You might want to do this if you've created new commits, so that you can
34+
find the commit later and so that it won't be garbage collected.
35+
36+
If you create commits in detached HEAD state that aren't on a branch,
37+
you can find them later using linkgit:git-reflog[1].

‎Documentation/git-checkout.adoc‎

Lines changed: 1 addition & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -376,135 +376,8 @@ For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
376376
[[DETACHED_HEAD]]
377377
DETACHED HEAD
378378
-------------
379-
`HEAD` normally refers to a named branch (e.g. `master`). Meanwhile, each
380-
branch refers to a specific commit. Let's look at a repo with three
381-
commits, one of them tagged, and with branch `master` checked out:
382379
383-
------------
384-
HEAD (refers to branch 'master')
385-
|
386-
v
387-
a---b---c branch 'master' (refers to commit 'c')
388-
^
389-
|
390-
tag 'v2.0' (refers to commit 'b')
391-
------------
392-
393-
When a commit is created in this state, the branch is updated to refer to
394-
the new commit. Specifically, `git commit` creates a new commit `d`, whose
395-
parent is commit `c`, and then updates branch `master` to refer to new
396-
commit `d`. `HEAD` still refers to branch `master` and so indirectly now refers
397-
to commit `d`:
398-
399-
------------
400-
$ edit; git add; git commit
401-
402-
HEAD (refers to branch 'master')
403-
|
404-
v
405-
a---b---c---d branch 'master' (refers to commit 'd')
406-
^
407-
|
408-
tag 'v2.0' (refers to commit 'b')
409-
------------
410-
411-
It is sometimes useful to be able to checkout a commit that is not at
412-
the tip of any named branch, or even to create a new commit that is not
413-
referenced by a named branch. Let's look at what happens when we
414-
checkout commit `b` (here we show two ways this may be done):
415-
416-
------------
417-
$ git checkout v2.0 # or
418-
$ git checkout master^^
419-
420-
HEAD (refers to commit 'b')
421-
|
422-
v
423-
a---b---c---d branch 'master' (refers to commit 'd')
424-
^
425-
|
426-
tag 'v2.0' (refers to commit 'b')
427-
------------
428-
429-
Notice that regardless of which checkout command we use, `HEAD` now refers
430-
directly to commit `b`. This is known as being in detached `HEAD` state.
431-
It means simply that `HEAD` refers to a specific commit, as opposed to
432-
referring to a named branch. Let's see what happens when we create a commit:
433-
434-
------------
435-
$ edit; git add; git commit
436-
437-
HEAD (refers to commit 'e')
438-
|
439-
v
440-
e
441-
/
442-
a---b---c---d branch 'master' (refers to commit 'd')
443-
^
444-
|
445-
tag 'v2.0' (refers to commit 'b')
446-
------------
447-
448-
There is now a new commit `e`, but it is referenced only by `HEAD`. We can
449-
of course add yet another commit in this state:
450-
451-
------------
452-
$ edit; git add; git commit
453-
454-
HEAD (refers to commit 'f')
455-
|
456-
v
457-
e---f
458-
/
459-
a---b---c---d branch 'master' (refers to commit 'd')
460-
^
461-
|
462-
tag 'v2.0' (refers to commit 'b')
463-
------------
464-
465-
In fact, we can perform all the normal Git operations. But, let's look
466-
at what happens when we then checkout `master`:
467-
468-
------------
469-
$ git checkout master
470-
471-
HEAD (refers to branch 'master')
472-
e---f |
473-
/ v
474-
a---b---c---d branch 'master' (refers to commit 'd')
475-
^
476-
|
477-
tag 'v2.0' (refers to commit 'b')
478-
------------
479-
480-
It is important to realize that at this point nothing refers to commit
481-
`f`. Eventually commit `f` (and by extension commit `e`) will be deleted
482-
by the routine Git garbage collection process, unless we create a reference
483-
before that happens. If we have not yet moved away from commit `f`,
484-
any of these will create a reference to it:
485-
486-
------------
487-
$ git checkout -b foo # or "git switch -c foo" <1>
488-
$ git branch foo <2>
489-
$ git tag foo <3>
490-
------------
491-
<1> creates a new branch `foo`, which refers to commit `f`, and then
492-
updates `HEAD` to refer to branch `foo`. In other words, we'll no longer
493-
be in detached `HEAD` state after this command.
494-
<2> similarly creates a new branch `foo`, which refers to commit `f`,
495-
but leaves `HEAD` detached.
496-
<3> creates a new tag `foo`, which refers to commit `f`,
497-
leaving `HEAD` detached.
498-
499-
If we have moved away from commit `f`, then we must first recover its object
500-
name (typically by using git reflog), and then we can create a reference to
501-
it. For example, to see the last two commits to which `HEAD` referred, we
502-
can use either of these commands:
503-
504-
------------
505-
$ git reflog -2 HEAD # or
506-
$ git log -g -2 HEAD
507-
------------
380+
include::detached-head.adoc[]
508381
509382
[[ARGUMENT_DISAMBIGUATION]]
510383
ARGUMENT DISAMBIGUATION

‎Documentation/gitdetachedhead.adoc‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
gitdetachedhead(7)
2+
===============
3+
4+
NAME
5+
----
6+
gitdetachedhead - How detached HEAD state works
7+
8+
DESCRIPTION
9+
-----------
10+
include::detached-head.adoc[]
11+
12+
GIT
13+
---
14+
Part of the linkgit:git[1] suite

‎advice.c‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ void detach_advice(const char *new_name)
291291
"\n"
292292
" git switch -\n"
293293
"\n"
294+
"Run `git help detachedhead` to learn more.\n"
294295
"Turn off this advice by setting config variable advice.detachedHead to false\n\n");
295296

296297
fprintf(stderr, fmt, new_name);

‎command-list.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ gitcore-tutorial guide
218218
gitcredentials guide
219219
gitcvs-migration guide
220220
gitdatamodel guide
221+
gitdetachedhead guide
221222
gitdiffcore guide
222223
giteveryday guide
223224
gitfaq guide

0 commit comments

Comments
 (0)