Merge branch 'jc/calloc-fix'
[git] / t / t2400-worktree-add.sh
1 #!/bin/sh
2
3 test_description='test git worktree add'
4
5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
7
8 . ./test-lib.sh
9
10 . "$TEST_DIRECTORY"/lib-rebase.sh
11
12 test_expect_success 'setup' '
13         test_commit init
14 '
15
16 test_expect_success '"add" an existing worktree' '
17         mkdir -p existing/subtree &&
18         test_must_fail git worktree add --detach existing main
19 '
20
21 test_expect_success '"add" an existing empty worktree' '
22         mkdir existing_empty &&
23         git worktree add --detach existing_empty main
24 '
25
26 test_expect_success '"add" using shorthand - fails when no previous branch' '
27         test_must_fail git worktree add existing_short -
28 '
29
30 test_expect_success '"add" using - shorthand' '
31         git checkout -b newbranch &&
32         echo hello >myworld &&
33         git add myworld &&
34         git commit -m myworld &&
35         git checkout main &&
36         git worktree add short-hand - &&
37         echo refs/heads/newbranch >expect &&
38         git -C short-hand rev-parse --symbolic-full-name HEAD >actual &&
39         test_cmp expect actual
40 '
41
42 test_expect_success '"add" refuses to checkout locked branch' '
43         test_must_fail git worktree add zere main &&
44         ! test -d zere &&
45         ! test -d .git/worktrees/zere
46 '
47
48 test_expect_success 'checking out paths not complaining about linked checkouts' '
49         (
50         cd existing_empty &&
51         echo dirty >>init.t &&
52         git checkout main -- init.t
53         )
54 '
55
56 test_expect_success '"add" worktree' '
57         git rev-parse HEAD >expect &&
58         git worktree add --detach here main &&
59         (
60                 cd here &&
61                 test_cmp ../init.t init.t &&
62                 test_must_fail git symbolic-ref HEAD &&
63                 git rev-parse HEAD >actual &&
64                 test_cmp ../expect actual &&
65                 git fsck
66         )
67 '
68
69 test_expect_success '"add" worktree with lock' '
70         git rev-parse HEAD >expect &&
71         git worktree add --detach --lock here-with-lock main &&
72         test -f .git/worktrees/here-with-lock/locked
73 '
74
75 test_expect_success '"add" worktree from a subdir' '
76         (
77                 mkdir sub &&
78                 cd sub &&
79                 git worktree add --detach here main &&
80                 cd here &&
81                 test_cmp ../../init.t init.t
82         )
83 '
84
85 test_expect_success '"add" from a linked checkout' '
86         (
87                 cd here &&
88                 git worktree add --detach nested-here main &&
89                 cd nested-here &&
90                 git fsck
91         )
92 '
93
94 test_expect_success '"add" worktree creating new branch' '
95         git worktree add -b newmain there main &&
96         (
97                 cd there &&
98                 test_cmp ../init.t init.t &&
99                 git symbolic-ref HEAD >actual &&
100                 echo refs/heads/newmain >expect &&
101                 test_cmp expect actual &&
102                 git fsck
103         )
104 '
105
106 test_expect_success 'die the same branch is already checked out' '
107         (
108                 cd here &&
109                 test_must_fail git checkout newmain
110         )
111 '
112
113 test_expect_success SYMLINKS 'die the same branch is already checked out (symlink)' '
114         head=$(git -C there rev-parse --git-path HEAD) &&
115         ref=$(git -C there symbolic-ref HEAD) &&
116         rm "$head" &&
117         ln -s "$ref" "$head" &&
118         test_must_fail git -C here checkout newmain
119 '
120
121 test_expect_success 'not die the same branch is already checked out' '
122         (
123                 cd here &&
124                 git worktree add --force anothernewmain newmain
125         )
126 '
127
128 test_expect_success 'not die on re-checking out current branch' '
129         (
130                 cd there &&
131                 git checkout newmain
132         )
133 '
134
135 test_expect_success '"add" from a bare repo' '
136         (
137                 git clone --bare . bare &&
138                 cd bare &&
139                 git worktree add -b bare-main ../there2 main
140         )
141 '
142
143 test_expect_success 'checkout from a bare repo without "add"' '
144         (
145                 cd bare &&
146                 test_must_fail git checkout main
147         )
148 '
149
150 test_expect_success '"add" default branch of a bare repo' '
151         (
152                 git clone --bare . bare2 &&
153                 cd bare2 &&
154                 git worktree add ../there3 main
155         )
156 '
157
158 test_expect_success 'checkout with grafts' '
159         test_when_finished rm .git/info/grafts &&
160         test_commit abc &&
161         SHA1=$(git rev-parse HEAD) &&
162         test_commit def &&
163         test_commit xyz &&
164         echo "$(git rev-parse HEAD) $SHA1" >.git/info/grafts &&
165         cat >expected <<-\EOF &&
166         xyz
167         abc
168         EOF
169         git log --format=%s -2 >actual &&
170         test_cmp expected actual &&
171         git worktree add --detach grafted main &&
172         git --git-dir=grafted/.git log --format=%s -2 >actual &&
173         test_cmp expected actual
174 '
175
176 test_expect_success '"add" from relative HEAD' '
177         test_commit a &&
178         test_commit b &&
179         test_commit c &&
180         git rev-parse HEAD~1 >expected &&
181         git worktree add relhead HEAD~1 &&
182         git -C relhead rev-parse HEAD >actual &&
183         test_cmp expected actual
184 '
185
186 test_expect_success '"add -b" with <branch> omitted' '
187         git worktree add -b burble flornk &&
188         test_cmp_rev HEAD burble
189 '
190
191 test_expect_success '"add --detach" with <branch> omitted' '
192         git worktree add --detach fishhook &&
193         git rev-parse HEAD >expected &&
194         git -C fishhook rev-parse HEAD >actual &&
195         test_cmp expected actual &&
196         test_must_fail git -C fishhook symbolic-ref HEAD
197 '
198
199 test_expect_success '"add" with <branch> omitted' '
200         git worktree add wiffle/bat &&
201         test_cmp_rev HEAD bat
202 '
203
204 test_expect_success '"add" checks out existing branch of dwimd name' '
205         git branch dwim HEAD~1 &&
206         git worktree add dwim &&
207         test_cmp_rev HEAD~1 dwim &&
208         (
209                 cd dwim &&
210                 test_cmp_rev HEAD dwim
211         )
212 '
213
214 test_expect_success '"add <path>" dwim fails with checked out branch' '
215         git checkout -b test-branch &&
216         test_must_fail git worktree add test-branch &&
217         test_path_is_missing test-branch
218 '
219
220 test_expect_success '"add --force" with existing dwimd name doesnt die' '
221         git checkout test-branch &&
222         git worktree add --force test-branch
223 '
224
225 test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' '
226         git worktree add --detach mish/mash &&
227         test_must_fail git rev-parse mash -- &&
228         test_must_fail git -C mish/mash symbolic-ref HEAD
229 '
230
231 test_expect_success '"add" -b/-B mutually exclusive' '
232         test_must_fail git worktree add -b poodle -B poodle bamboo main
233 '
234
235 test_expect_success '"add" -b/--detach mutually exclusive' '
236         test_must_fail git worktree add -b poodle --detach bamboo main
237 '
238
239 test_expect_success '"add" -B/--detach mutually exclusive' '
240         test_must_fail git worktree add -B poodle --detach bamboo main
241 '
242
243 test_expect_success '"add -B" fails if the branch is checked out' '
244         git rev-parse newmain >before &&
245         test_must_fail git worktree add -B newmain bamboo main &&
246         git rev-parse newmain >after &&
247         test_cmp before after
248 '
249
250 test_expect_success 'add -B' '
251         git worktree add -B poodle bamboo2 main^ &&
252         git -C bamboo2 symbolic-ref HEAD >actual &&
253         echo refs/heads/poodle >expected &&
254         test_cmp expected actual &&
255         test_cmp_rev main^ poodle
256 '
257
258 test_expect_success 'add --quiet' '
259         git worktree add --quiet another-worktree main 2>actual &&
260         test_must_be_empty actual
261 '
262
263 test_expect_success 'local clone from linked checkout' '
264         git clone --local here here-clone &&
265         ( cd here-clone && git fsck )
266 '
267
268 test_expect_success 'local clone --shared from linked checkout' '
269         git -C bare worktree add --detach ../baretree &&
270         git clone --local --shared baretree bare-clone &&
271         grep /bare/ bare-clone/.git/objects/info/alternates
272 '
273
274 test_expect_success '"add" worktree with --no-checkout' '
275         git worktree add --no-checkout -b swamp swamp &&
276         ! test -e swamp/init.t &&
277         git -C swamp reset --hard &&
278         test_cmp init.t swamp/init.t
279 '
280
281 test_expect_success '"add" worktree with --checkout' '
282         git worktree add --checkout -b swmap2 swamp2 &&
283         test_cmp init.t swamp2/init.t
284 '
285
286 test_expect_success 'put a worktree under rebase' '
287         git worktree add under-rebase &&
288         (
289                 cd under-rebase &&
290                 set_fake_editor &&
291                 FAKE_LINES="edit 1" git rebase -i HEAD^ &&
292                 git worktree list | grep "under-rebase.*detached HEAD"
293         )
294 '
295
296 test_expect_success 'add a worktree, checking out a rebased branch' '
297         test_must_fail git worktree add new-rebase under-rebase &&
298         ! test -d new-rebase
299 '
300
301 test_expect_success 'checking out a rebased branch from another worktree' '
302         git worktree add new-place &&
303         test_must_fail git -C new-place checkout under-rebase
304 '
305
306 test_expect_success 'not allow to delete a branch under rebase' '
307         (
308                 cd under-rebase &&
309                 test_must_fail git branch -D under-rebase
310         )
311 '
312
313 test_expect_success 'rename a branch under rebase not allowed' '
314         test_must_fail git branch -M under-rebase rebase-with-new-name
315 '
316
317 test_expect_success 'check out from current worktree branch ok' '
318         (
319                 cd under-rebase &&
320                 git checkout under-rebase &&
321                 git checkout - &&
322                 git rebase --abort
323         )
324 '
325
326 test_expect_success 'checkout a branch under bisect' '
327         git worktree add under-bisect &&
328         (
329                 cd under-bisect &&
330                 git bisect start &&
331                 git bisect bad &&
332                 git bisect good HEAD~2 &&
333                 git worktree list | grep "under-bisect.*detached HEAD" &&
334                 test_must_fail git worktree add new-bisect under-bisect &&
335                 ! test -d new-bisect
336         )
337 '
338
339 test_expect_success 'rename a branch under bisect not allowed' '
340         test_must_fail git branch -M under-bisect bisect-with-new-name
341 '
342 # Is branch "refs/heads/$1" set to pull from "$2/$3"?
343 test_branch_upstream () {
344         printf "%s\n" "$2" "refs/heads/$3" >expect.upstream &&
345         {
346                 git config "branch.$1.remote" &&
347                 git config "branch.$1.merge"
348         } >actual.upstream &&
349         test_cmp expect.upstream actual.upstream
350 }
351
352 test_expect_success '--track sets up tracking' '
353         test_when_finished rm -rf track &&
354         git worktree add --track -b track track main &&
355         test_branch_upstream track . main
356 '
357
358 # setup remote repository $1 and repository $2 with $1 set up as
359 # remote.  The remote has two branches, main and foo.
360 setup_remote_repo () {
361         git init $1 &&
362         (
363                 cd $1 &&
364                 test_commit $1_main &&
365                 git checkout -b foo &&
366                 test_commit upstream_foo
367         ) &&
368         git init $2 &&
369         (
370                 cd $2 &&
371                 test_commit $2_main &&
372                 git remote add $1 ../$1 &&
373                 git config remote.$1.fetch \
374                         "refs/heads/*:refs/remotes/$1/*" &&
375                 git fetch --all
376         )
377 }
378
379 test_expect_success '--no-track avoids setting up tracking' '
380         test_when_finished rm -rf repo_upstream repo_local foo &&
381         setup_remote_repo repo_upstream repo_local &&
382         (
383                 cd repo_local &&
384                 git worktree add --no-track -b foo ../foo repo_upstream/foo
385         ) &&
386         (
387                 cd foo &&
388                 test_must_fail git config "branch.foo.remote" &&
389                 test_must_fail git config "branch.foo.merge" &&
390                 test_cmp_rev refs/remotes/repo_upstream/foo refs/heads/foo
391         )
392 '
393
394 test_expect_success '"add" <path> <non-existent-branch> fails' '
395         test_must_fail git worktree add foo non-existent
396 '
397
398 test_expect_success '"add" <path> <branch> dwims' '
399         test_when_finished rm -rf repo_upstream repo_dwim foo &&
400         setup_remote_repo repo_upstream repo_dwim &&
401         git init repo_dwim &&
402         (
403                 cd repo_dwim &&
404                 git worktree add ../foo foo
405         ) &&
406         (
407                 cd foo &&
408                 test_branch_upstream foo repo_upstream foo &&
409                 test_cmp_rev refs/remotes/repo_upstream/foo refs/heads/foo
410         )
411 '
412
413 test_expect_success '"add" <path> <branch> dwims with checkout.defaultRemote' '
414         test_when_finished rm -rf repo_upstream repo_dwim foo &&
415         setup_remote_repo repo_upstream repo_dwim &&
416         git init repo_dwim &&
417         (
418                 cd repo_dwim &&
419                 git remote add repo_upstream2 ../repo_upstream &&
420                 git fetch repo_upstream2 &&
421                 test_must_fail git worktree add ../foo foo &&
422                 git -c checkout.defaultRemote=repo_upstream worktree add ../foo foo &&
423                 git status -uno --porcelain >status.actual &&
424                 test_must_be_empty status.actual
425         ) &&
426         (
427                 cd foo &&
428                 test_branch_upstream foo repo_upstream foo &&
429                 test_cmp_rev refs/remotes/repo_upstream/foo refs/heads/foo
430         )
431 '
432
433 test_expect_success 'git worktree add does not match remote' '
434         test_when_finished rm -rf repo_a repo_b foo &&
435         setup_remote_repo repo_a repo_b &&
436         (
437                 cd repo_b &&
438                 git worktree add ../foo
439         ) &&
440         (
441                 cd foo &&
442                 test_must_fail git config "branch.foo.remote" &&
443                 test_must_fail git config "branch.foo.merge" &&
444                 test_cmp_rev ! refs/remotes/repo_a/foo refs/heads/foo
445         )
446 '
447
448 test_expect_success 'git worktree add --guess-remote sets up tracking' '
449         test_when_finished rm -rf repo_a repo_b foo &&
450         setup_remote_repo repo_a repo_b &&
451         (
452                 cd repo_b &&
453                 git worktree add --guess-remote ../foo
454         ) &&
455         (
456                 cd foo &&
457                 test_branch_upstream foo repo_a foo &&
458                 test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
459         )
460 '
461
462 test_expect_success 'git worktree add with worktree.guessRemote sets up tracking' '
463         test_when_finished rm -rf repo_a repo_b foo &&
464         setup_remote_repo repo_a repo_b &&
465         (
466                 cd repo_b &&
467                 git config worktree.guessRemote true &&
468                 git worktree add ../foo
469         ) &&
470         (
471                 cd foo &&
472                 test_branch_upstream foo repo_a foo &&
473                 test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
474         )
475 '
476
477 test_expect_success 'git worktree --no-guess-remote option overrides config' '
478         test_when_finished rm -rf repo_a repo_b foo &&
479         setup_remote_repo repo_a repo_b &&
480         (
481                 cd repo_b &&
482                 git config worktree.guessRemote true &&
483                 git worktree add --no-guess-remote ../foo
484         ) &&
485         (
486                 cd foo &&
487                 test_must_fail git config "branch.foo.remote" &&
488                 test_must_fail git config "branch.foo.merge" &&
489                 test_cmp_rev ! refs/remotes/repo_a/foo refs/heads/foo
490         )
491 '
492
493 post_checkout_hook () {
494         gitdir=${1:-.git}
495         test_when_finished "rm -f $gitdir/hooks/post-checkout" &&
496         mkdir -p $gitdir/hooks &&
497         write_script $gitdir/hooks/post-checkout <<-\EOF
498         {
499                 echo $*
500                 git rev-parse --git-dir --show-toplevel
501         } >hook.actual
502         EOF
503 }
504
505 test_expect_success '"add" invokes post-checkout hook (branch)' '
506         post_checkout_hook &&
507         {
508                 echo $ZERO_OID $(git rev-parse HEAD) 1 &&
509                 echo $(pwd)/.git/worktrees/gumby &&
510                 echo $(pwd)/gumby
511         } >hook.expect &&
512         git worktree add gumby &&
513         test_cmp hook.expect gumby/hook.actual
514 '
515
516 test_expect_success '"add" invokes post-checkout hook (detached)' '
517         post_checkout_hook &&
518         {
519                 echo $ZERO_OID $(git rev-parse HEAD) 1 &&
520                 echo $(pwd)/.git/worktrees/grumpy &&
521                 echo $(pwd)/grumpy
522         } >hook.expect &&
523         git worktree add --detach grumpy &&
524         test_cmp hook.expect grumpy/hook.actual
525 '
526
527 test_expect_success '"add --no-checkout" suppresses post-checkout hook' '
528         post_checkout_hook &&
529         rm -f hook.actual &&
530         git worktree add --no-checkout gloopy &&
531         test_path_is_missing gloopy/hook.actual
532 '
533
534 test_expect_success '"add" in other worktree invokes post-checkout hook' '
535         post_checkout_hook &&
536         {
537                 echo $ZERO_OID $(git rev-parse HEAD) 1 &&
538                 echo $(pwd)/.git/worktrees/guppy &&
539                 echo $(pwd)/guppy
540         } >hook.expect &&
541         git -C gloopy worktree add --detach ../guppy &&
542         test_cmp hook.expect guppy/hook.actual
543 '
544
545 test_expect_success '"add" in bare repo invokes post-checkout hook' '
546         rm -rf bare &&
547         git clone --bare . bare &&
548         {
549                 echo $ZERO_OID $(git --git-dir=bare rev-parse HEAD) 1 &&
550                 echo $(pwd)/bare/worktrees/goozy &&
551                 echo $(pwd)/goozy
552         } >hook.expect &&
553         post_checkout_hook bare &&
554         git -C bare worktree add --detach ../goozy &&
555         test_cmp hook.expect goozy/hook.actual
556 '
557
558 test_expect_success '"add" an existing but missing worktree' '
559         git worktree add --detach pneu &&
560         test_must_fail git worktree add --detach pneu &&
561         rm -fr pneu &&
562         test_must_fail git worktree add --detach pneu &&
563         git worktree add --force --detach pneu
564 '
565
566 test_expect_success '"add" an existing locked but missing worktree' '
567         git worktree add --detach gnoo &&
568         git worktree lock gnoo &&
569         test_when_finished "git worktree unlock gnoo || :" &&
570         rm -fr gnoo &&
571         test_must_fail git worktree add --detach gnoo &&
572         test_must_fail git worktree add --force --detach gnoo &&
573         git worktree add --force --force --detach gnoo
574 '
575
576 test_expect_success '"add" not tripped up by magic worktree matching"' '
577         # if worktree "sub1/bar" exists, "git worktree add bar" in distinct
578         # directory `sub2` should not mistakenly complain that `bar` is an
579         # already-registered worktree
580         mkdir sub1 sub2 &&
581         git -C sub1 --git-dir=../.git worktree add --detach bozo &&
582         git -C sub2 --git-dir=../.git worktree add --detach bozo
583 '
584
585 test_expect_success FUNNYNAMES 'sanitize generated worktree name' '
586         git worktree add --detach ".  weird*..?.lock.lock" &&
587         test -d .git/worktrees/---weird-.-
588 '
589
590 test_expect_success '"add" should not fail because of another bad worktree' '
591         git init add-fail &&
592         (
593                 cd add-fail &&
594                 test_commit first &&
595                 mkdir sub &&
596                 git worktree add sub/to-be-deleted &&
597                 rm -rf sub &&
598                 git worktree add second
599         )
600 '
601
602 test_expect_success '"add" with uninitialized submodule, with submodule.recurse unset' '
603         test_create_repo submodule &&
604         test_commit -C submodule first &&
605         test_create_repo project &&
606         git -C project submodule add ../submodule &&
607         git -C project add submodule &&
608         test_tick &&
609         git -C project commit -m add_sub &&
610         git clone project project-clone &&
611         git -C project-clone worktree add ../project-2
612 '
613 test_expect_success '"add" with uninitialized submodule, with submodule.recurse set' '
614         git -C project-clone -c submodule.recurse worktree add ../project-3
615 '
616
617 test_expect_success '"add" with initialized submodule, with submodule.recurse unset' '
618         git -C project-clone submodule update --init &&
619         git -C project-clone worktree add ../project-4
620 '
621
622 test_expect_success '"add" with initialized submodule, with submodule.recurse set' '
623         git -C project-clone -c submodule.recurse worktree add ../project-5
624 '
625
626 test_done