3 test_description='checkout into detached HEAD state'
4 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
5 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
10 test_must_fail git symbolic-ref -q HEAD >/dev/null
13 check_not_detached () {
14 git symbolic-ref -q HEAD >/dev/null
17 PREV_HEAD_DESC='Previous HEAD position was'
18 check_orphan_warning() {
19 test_i18ngrep "you are leaving $2 behind" "$1" &&
20 test_i18ngrep ! "$PREV_HEAD_DESC" "$1"
22 check_no_orphan_warning() {
23 test_i18ngrep ! "you are leaving .* commit.*behind" "$1" &&
24 test_i18ngrep "$PREV_HEAD_DESC" "$1"
32 test_expect_success 'setup' '
35 test_commit three && git tag -d three &&
36 test_commit four && git tag -d four &&
41 test_expect_success 'checkout branch does not detach' '
43 git checkout branch &&
47 test_expect_success 'checkout tag detaches' '
53 test_expect_success 'checkout branch by full name detaches' '
55 git checkout refs/heads/branch &&
59 test_expect_success 'checkout non-ref detaches' '
61 git checkout branch^ &&
65 test_expect_success 'checkout ref^0 detaches' '
67 git checkout branch^0 &&
71 test_expect_success 'checkout --detach detaches' '
73 git checkout --detach branch &&
77 test_expect_success 'checkout --detach without branch name' '
79 git checkout --detach &&
83 test_expect_success 'checkout --detach errors out for non-commit' '
85 test_must_fail git checkout --detach one^{tree} &&
89 test_expect_success 'checkout --detach errors out for extra argument' '
92 test_must_fail git checkout --detach tag one.t &&
96 test_expect_success 'checkout --detached and -b are incompatible' '
98 test_must_fail git checkout --detach -b newbranch tag &&
102 test_expect_success 'checkout --detach moves HEAD' '
105 git checkout --detach two &&
106 git diff --exit-code HEAD &&
107 git diff --exit-code two
110 test_expect_success 'checkout warns on orphan commits' '
112 git checkout --detach two &&
113 echo content >orphan &&
115 git commit -a -m orphan1 &&
116 echo new content >orphan &&
117 git commit -a -m orphan2 &&
118 orphan2=$(git rev-parse HEAD) &&
119 git checkout main 2>stderr
122 test_expect_success 'checkout warns on orphan commits: output' '
123 check_orphan_warning stderr "2 commits"
126 test_expect_success 'checkout warns orphaning 1 of 2 commits' '
127 git checkout "$orphan2" &&
128 git checkout HEAD^ 2>stderr
131 test_expect_success 'checkout warns orphaning 1 of 2 commits: output' '
132 check_orphan_warning stderr "1 commit"
135 test_expect_success 'checkout does not warn leaving ref tip' '
137 git checkout --detach two &&
138 git checkout main 2>stderr
141 test_expect_success 'checkout does not warn leaving ref tip' '
142 check_no_orphan_warning stderr
145 test_expect_success 'checkout does not warn leaving reachable commit' '
147 git checkout --detach HEAD^ &&
148 git checkout main 2>stderr
151 test_expect_success 'checkout does not warn leaving reachable commit' '
152 check_no_orphan_warning stderr
156 Your branch is behind 'main' by 1 commit, and can be fast-forwarded.
157 (use "git pull" to update your local branch)
159 test_expect_success 'tracking count is accurate after orphan check' '
161 git branch child main^ &&
162 git config branch.child.remote . &&
163 git config branch.child.merge refs/heads/main &&
164 git checkout child^ &&
165 git checkout child >stdout &&
166 test_i18ncmp expect stdout
169 test_expect_success 'no advice given for explicit detached head state' '
171 test_config advice.detachedHead true &&
172 git checkout child && git checkout HEAD^0 >expect.advice 2>&1 &&
173 test_config advice.detachedHead false &&
174 git checkout child && git checkout HEAD^0 >expect.no-advice 2>&1 &&
175 test_unconfig advice.detachedHead &&
176 # without configuration, the advice.* variables default to true
177 git checkout child && git checkout HEAD^0 >actual 2>&1 &&
178 test_cmp expect.advice actual &&
180 # with explicit --detach
182 test_unconfig advice.detachedHead &&
183 git checkout child && git checkout --detach HEAD^0 >actual 2>&1 &&
184 test_cmp expect.no-advice actual &&
186 # explicitly decline advice
187 test_config advice.detachedHead false &&
188 git checkout child && git checkout --detach HEAD^0 >actual 2>&1 &&
189 test_cmp expect.no-advice actual
192 # Detached HEAD tests for GIT_PRINT_SHA1_ELLIPSIS (new format)
193 test_expect_success 'describe_detached_head prints no SHA-1 ellipsis when not asked to' "
195 commit=$(git rev-parse --short=12 main^) &&
196 commit2=$(git rev-parse --short=12 main~2) &&
197 commit3=$(git rev-parse --short=12 main~3) &&
199 # The first detach operation is more chatty than the following ones.
200 cat >1st_detach <<-EOF &&
201 Note: switching to 'HEAD^'.
203 You are in 'detached HEAD' state. You can look around, make experimental
204 changes and commit them, and you can discard any commits you make in this
205 state without impacting any branches by switching back to a branch.
207 If you want to create a new branch to retain commits you create, you may
208 do so (now or later) by using -c with the switch command. Example:
210 git switch -c <new-branch-name>
212 Or undo this operation with:
216 Turn off this advice by setting config variable advice.detachedHead to false
218 HEAD is now at \$commit three
221 # The remaining ones just show info about previous and current HEADs.
222 cat >2nd_detach <<-EOF &&
223 Previous HEAD position was \$commit three
224 HEAD is now at \$commit2 two
227 cat >3rd_detach <<-EOF &&
228 Previous HEAD position was \$commit2 two
229 HEAD is now at \$commit3 one
233 check_not_detached &&
235 # Various ways of *not* asking for ellipses
237 sane_unset GIT_PRINT_SHA1_ELLIPSIS &&
238 git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
240 test_i18ncmp 1st_detach actual &&
242 GIT_PRINT_SHA1_ELLIPSIS="no" git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
244 test_i18ncmp 2nd_detach actual &&
246 GIT_PRINT_SHA1_ELLIPSIS= git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
248 test_i18ncmp 3rd_detach actual &&
250 sane_unset GIT_PRINT_SHA1_ELLIPSIS &&
252 # We only have four commits, but we can re-use them
254 check_not_detached &&
256 # Make no mention of the env var at all
257 git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
259 test_i18ncmp 1st_detach actual &&
261 GIT_PRINT_SHA1_ELLIPSIS='nope' &&
262 git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
264 test_i18ncmp 2nd_detach actual &&
266 GIT_PRINT_SHA1_ELLIPSIS=nein &&
267 git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
269 test_i18ncmp 3rd_detach actual &&
274 # Detached HEAD tests for GIT_PRINT_SHA1_ELLIPSIS (old format)
275 test_expect_success 'describe_detached_head does print SHA-1 ellipsis when asked to' "
277 commit=$(git rev-parse --short=12 main^) &&
278 commit2=$(git rev-parse --short=12 main~2) &&
279 commit3=$(git rev-parse --short=12 main~3) &&
281 # The first detach operation is more chatty than the following ones.
282 cat >1st_detach <<-EOF &&
283 Note: switching to 'HEAD^'.
285 You are in 'detached HEAD' state. You can look around, make experimental
286 changes and commit them, and you can discard any commits you make in this
287 state without impacting any branches by switching back to a branch.
289 If you want to create a new branch to retain commits you create, you may
290 do so (now or later) by using -c with the switch command. Example:
292 git switch -c <new-branch-name>
294 Or undo this operation with:
298 Turn off this advice by setting config variable advice.detachedHead to false
300 HEAD is now at \$commit... three
303 # The remaining ones just show info about previous and current HEADs.
304 cat >2nd_detach <<-EOF &&
305 Previous HEAD position was \$commit... three
306 HEAD is now at \$commit2... two
309 cat >3rd_detach <<-EOF &&
310 Previous HEAD position was \$commit2... two
311 HEAD is now at \$commit3... one
315 check_not_detached &&
317 # Various ways of asking for ellipses...
318 # The user can just use any kind of quoting (including none).
320 GIT_PRINT_SHA1_ELLIPSIS=yes git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
322 test_i18ncmp 1st_detach actual &&
324 GIT_PRINT_SHA1_ELLIPSIS=Yes git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
326 test_i18ncmp 2nd_detach actual &&
328 GIT_PRINT_SHA1_ELLIPSIS=YES git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 &&
330 test_i18ncmp 3rd_detach actual &&