1#!/bin/sh 2 3test_description='checkout into detached HEAD state' 4GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 5export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 6 7. ./test-lib.sh 8 9check_detached () { 10 test_must_fail git symbolic-ref -q HEAD >/dev/null 11} 12 13check_not_detached () { 14 git symbolic-ref -q HEAD >/dev/null 15} 16 17PREV_HEAD_DESC='Previous HEAD position was' 18check_orphan_warning() { 19 test_i18ngrep "you are leaving $2 behind" "$1" && 20 test_i18ngrep ! "$PREV_HEAD_DESC" "$1" 21} 22check_no_orphan_warning() { 23 test_i18ngrep ! "you are leaving .* commit.*behind" "$1" && 24 test_i18ngrep "$PREV_HEAD_DESC" "$1" 25} 26 27reset () { 28 git checkout main && 29 check_not_detached 30} 31 32test_expect_success 'setup' ' 33 test_commit one && 34 test_commit two && 35 test_commit three && git tag -d three && 36 test_commit four && git tag -d four && 37 git branch branch && 38 git tag tag 39' 40 41test_expect_success 'checkout branch does not detach' ' 42 reset && 43 git checkout branch && 44 check_not_detached 45' 46 47test_expect_success 'checkout tag detaches' ' 48 reset && 49 git checkout tag && 50 check_detached 51' 52 53test_expect_success 'checkout branch by full name detaches' ' 54 reset && 55 git checkout refs/heads/branch && 56 check_detached 57' 58 59test_expect_success 'checkout non-ref detaches' ' 60 reset && 61 git checkout branch^ && 62 check_detached 63' 64 65test_expect_success 'checkout ref^0 detaches' ' 66 reset && 67 git checkout branch^0 && 68 check_detached 69' 70 71test_expect_success 'checkout --detach detaches' ' 72 reset && 73 git checkout --detach branch && 74 check_detached 75' 76 77test_expect_success 'checkout --detach without branch name' ' 78 reset && 79 git checkout --detach && 80 check_detached 81' 82 83test_expect_success 'checkout --detach errors out for non-commit' ' 84 reset && 85 test_must_fail git checkout --detach one^{tree} && 86 check_not_detached 87' 88 89test_expect_success 'checkout --detach errors out for extra argument' ' 90 reset && 91 git checkout main && 92 test_must_fail git checkout --detach tag one.t && 93 check_not_detached 94' 95 96test_expect_success 'checkout --detached and -b are incompatible' ' 97 reset && 98 test_must_fail git checkout --detach -b newbranch tag && 99 check_not_detached 100' 101 102test_expect_success 'checkout --detach moves HEAD' ' 103 reset && 104 git checkout one && 105 git checkout --detach two && 106 git diff --exit-code HEAD && 107 git diff --exit-code two 108' 109 110test_expect_success 'checkout warns on orphan commits' ' 111 reset && 112 git checkout --detach two && 113 echo content >orphan && 114 git add 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 120' 121 122test_expect_success 'checkout warns on orphan commits: output' ' 123 check_orphan_warning stderr "2 commits" 124' 125 126test_expect_success 'checkout warns orphaning 1 of 2 commits' ' 127 git checkout "$orphan2" && 128 git checkout HEAD^ 2>stderr 129' 130 131test_expect_success 'checkout warns orphaning 1 of 2 commits: output' ' 132 check_orphan_warning stderr "1 commit" 133' 134 135test_expect_success 'checkout does not warn leaving ref tip' ' 136 reset && 137 git checkout --detach two && 138 git checkout main 2>stderr 139' 140 141test_expect_success 'checkout does not warn leaving ref tip' ' 142 check_no_orphan_warning stderr 143' 144 145test_expect_success 'checkout does not warn leaving reachable commit' ' 146 reset && 147 git checkout --detach HEAD^ && 148 git checkout main 2>stderr 149' 150 151test_expect_success 'checkout does not warn leaving reachable commit' ' 152 check_no_orphan_warning stderr 153' 154 155cat >expect <<'EOF' 156Your branch is behind 'main' by 1 commit, and can be fast-forwarded. 157 (use "git pull" to update your local branch) 158EOF 159test_expect_success 'tracking count is accurate after orphan check' ' 160 reset && 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_cmp expect stdout 167' 168 169test_expect_success 'no advice given for explicit detached head state' ' 170 # baseline 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 && 179 180 # with explicit --detach 181 # no configuration 182 test_unconfig advice.detachedHead && 183 git checkout child && git checkout --detach HEAD^0 >actual 2>&1 && 184 test_cmp expect.no-advice actual && 185 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 190' 191 192# Detached HEAD tests for GIT_PRINT_SHA1_ELLIPSIS (new format) 193test_expect_success 'describe_detached_head prints no SHA-1 ellipsis when not asked to' " 194 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) && 198 199 # The first detach operation is more chatty than the following ones. 200 cat >1st_detach <<-EOF && 201 Note: switching to 'HEAD^'. 202 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. 206 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: 209 210 git switch -c <new-branch-name> 211 212 Or undo this operation with: 213 214 git switch - 215 216 Turn off this advice by setting config variable advice.detachedHead to false 217 218 HEAD is now at \$commit three 219 EOF 220 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 225 EOF 226 227 cat >3rd_detach <<-EOF && 228 Previous HEAD position was \$commit2 two 229 HEAD is now at \$commit3 one 230 EOF 231 232 reset && 233 check_not_detached && 234 235 # Various ways of *not* asking for ellipses 236 237 sane_unset GIT_PRINT_SHA1_ELLIPSIS && 238 git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 && 239 check_detached && 240 test_cmp 1st_detach actual && 241 242 GIT_PRINT_SHA1_ELLIPSIS="no" git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 && 243 check_detached && 244 test_cmp 2nd_detach actual && 245 246 GIT_PRINT_SHA1_ELLIPSIS= git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 && 247 check_detached && 248 test_cmp 3rd_detach actual && 249 250 sane_unset GIT_PRINT_SHA1_ELLIPSIS && 251 252 # We only have four commits, but we can re-use them 253 reset && 254 check_not_detached && 255 256 # Make no mention of the env var at all 257 git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 && 258 check_detached && 259 test_cmp 1st_detach actual && 260 261 GIT_PRINT_SHA1_ELLIPSIS='nope' && 262 git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 && 263 check_detached && 264 test_cmp 2nd_detach actual && 265 266 GIT_PRINT_SHA1_ELLIPSIS=nein && 267 git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 && 268 check_detached && 269 test_cmp 3rd_detach actual && 270 271 true 272" 273 274# Detached HEAD tests for GIT_PRINT_SHA1_ELLIPSIS (old format) 275test_expect_success 'describe_detached_head does print SHA-1 ellipsis when asked to' " 276 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) && 280 281 # The first detach operation is more chatty than the following ones. 282 cat >1st_detach <<-EOF && 283 Note: switching to 'HEAD^'. 284 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. 288 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: 291 292 git switch -c <new-branch-name> 293 294 Or undo this operation with: 295 296 git switch - 297 298 Turn off this advice by setting config variable advice.detachedHead to false 299 300 HEAD is now at \$commit... three 301 EOF 302 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 307 EOF 308 309 cat >3rd_detach <<-EOF && 310 Previous HEAD position was \$commit2... two 311 HEAD is now at \$commit3... one 312 EOF 313 314 reset && 315 check_not_detached && 316 317 # Various ways of asking for ellipses... 318 # The user can just use any kind of quoting (including none). 319 320 GIT_PRINT_SHA1_ELLIPSIS=yes git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 && 321 check_detached && 322 test_cmp 1st_detach actual && 323 324 GIT_PRINT_SHA1_ELLIPSIS=Yes git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 && 325 check_detached && 326 test_cmp 2nd_detach actual && 327 328 GIT_PRINT_SHA1_ELLIPSIS=YES git -c 'core.abbrev=12' checkout HEAD^ >actual 2>&1 && 329 check_detached && 330 test_cmp 3rd_detach actual && 331 332 true 333" 334 335test_done 336