#!/bin/sh global test_description := ''test git worktree add'' source ./test-lib.sh source "$TEST_DIRECTORY"/lib-rebase.sh test_expect_success 'setup' ' test_commit init ' test_expect_success '"add" an existing worktree' ' mkdir -p existing/subtree && test_must_fail git worktree add --detach existing master ' test_expect_success '"add" an existing empty worktree' ' mkdir existing_empty && git worktree add --detach existing_empty master ' test_expect_success '"add" using shorthand - fails when no previous branch' ' test_must_fail git worktree add existing_short - ' test_expect_success '"add" using - shorthand' ' git checkout -b newbranch && echo hello >myworld && git add myworld && git commit -m myworld && git checkout master && git worktree add short-hand - && echo refs/heads/newbranch >expect && git -C short-hand rev-parse --symbolic-full-name HEAD >actual && test_cmp expect actual ' test_expect_success '"add" refuses to checkout locked branch' ' test_must_fail git worktree add zere master && ! test -d zere && ! test -d .git/worktrees/zere ' test_expect_success 'checking out paths not complaining about linked checkouts' ' ( cd existing_empty && echo dirty >>init.t && git checkout master -- init.t ) ' test_expect_success '"add" worktree' ' git rev-parse HEAD >expect && git worktree add --detach here master && ( cd here && test_cmp ../init.t init.t && test_must_fail git symbolic-ref HEAD && git rev-parse HEAD >actual && test_cmp ../expect actual && git fsck ) ' test_expect_success '"add" worktree from a subdir' ' ( mkdir sub && cd sub && git worktree add --detach here master && cd here && test_cmp ../../init.t init.t ) ' test_expect_success '"add" from a linked checkout' ' ( cd here && git worktree add --detach nested-here master && cd nested-here && git fsck ) ' test_expect_success '"add" worktree creating new branch' ' git worktree add -b newmaster there master && ( cd there && test_cmp ../init.t init.t && git symbolic-ref HEAD >actual && echo refs/heads/newmaster >expect && test_cmp expect actual && git fsck ) ' test_expect_success 'die the same branch is already checked out' ' ( cd here && test_must_fail git checkout newmaster ) ' test_expect_success SYMLINKS 'die the same branch is already checked out (symlink)' ' head=$(git -C there rev-parse --git-path HEAD) && ref=$(git -C there symbolic-ref HEAD) && rm "$head" && ln -s "$ref" "$head" && test_must_fail git -C here checkout newmaster ' test_expect_success 'not die the same branch is already checked out' ' ( cd here && git worktree add --force anothernewmaster newmaster ) ' test_expect_success 'not die on re-checking out current branch' ' ( cd there && git checkout newmaster ) ' test_expect_success '"add" from a bare repo' ' ( git clone --bare . bare && cd bare && git worktree add -b bare-master ../there2 master ) ' test_expect_success 'checkout from a bare repo without "add"' ' ( cd bare && test_must_fail git checkout master ) ' test_expect_success '"add" default branch of a bare repo' ' ( git clone --bare . bare2 && cd bare2 && git worktree add ../there3 master ) ' test_expect_success 'checkout with grafts' ' test_when_finished rm .git/info/grafts && test_commit abc && SHA1=$(git rev-parse HEAD) && test_commit def && test_commit xyz && echo "$(git rev-parse HEAD) $SHA1" >.git/info/grafts && cat >expected <<-\EOF && xyz abc EOF git log --format=%s -2 >actual && test_cmp expected actual && git worktree add --detach grafted master && git --git-dir=grafted/.git log --format=%s -2 >actual && test_cmp expected actual ' test_expect_success '"add" from relative HEAD' ' test_commit a && test_commit b && test_commit c && git rev-parse HEAD~1 >expected && git worktree add relhead HEAD~1 && git -C relhead rev-parse HEAD >actual && test_cmp expected actual ' test_expect_success '"add -b" with omitted' ' git worktree add -b burble flornk && test_cmp_rev HEAD burble ' test_expect_success '"add --detach" with omitted' ' git worktree add --detach fishhook && git rev-parse HEAD >expected && git -C fishhook rev-parse HEAD >actual && test_cmp expected actual && test_must_fail git -C fishhook symbolic-ref HEAD ' test_expect_success '"add" with omitted' ' git worktree add wiffle/bat && test_cmp_rev HEAD bat ' test_expect_success '"add" auto-vivify does not clobber existing branch' ' test_commit c1 && test_commit c2 && git branch precious HEAD~1 && test_must_fail git worktree add precious && test_cmp_rev HEAD~1 precious && test_path_is_missing precious ' test_expect_success '"add" no auto-vivify with --detach and omitted' ' git worktree add --detach mish/mash && test_must_fail git rev-parse mash -- && test_must_fail git -C mish/mash symbolic-ref HEAD ' test_expect_success '"add" -b/-B mutually exclusive' ' test_must_fail git worktree add -b poodle -B poodle bamboo master ' test_expect_success '"add" -b/--detach mutually exclusive' ' test_must_fail git worktree add -b poodle --detach bamboo master ' test_expect_success '"add" -B/--detach mutually exclusive' ' test_must_fail git worktree add -B poodle --detach bamboo master ' test_expect_success '"add -B" fails if the branch is checked out' ' git rev-parse newmaster >before && test_must_fail git worktree add -B newmaster bamboo master && git rev-parse newmaster >after && test_cmp before after ' test_expect_success 'add -B' ' git worktree add -B poodle bamboo2 master^ && git -C bamboo2 symbolic-ref HEAD >actual && echo refs/heads/poodle >expected && test_cmp expected actual && test_cmp_rev master^ poodle ' test_expect_success 'local clone from linked checkout' ' git clone --local here here-clone && ( cd here-clone && git fsck ) ' test_expect_success '"add" worktree with --no-checkout' ' git worktree add --no-checkout -b swamp swamp && ! test -e swamp/init.t && git -C swamp reset --hard && test_cmp init.t swamp/init.t ' test_expect_success '"add" worktree with --checkout' ' git worktree add --checkout -b swmap2 swamp2 && test_cmp init.t swamp2/init.t ' test_expect_success 'put a worktree under rebase' ' git worktree add under-rebase && ( cd under-rebase && set_fake_editor && FAKE_LINES="edit 1" git rebase -i HEAD^ && git worktree list | grep "under-rebase.*detached HEAD" ) ' test_expect_success 'add a worktree, checking out a rebased branch' ' test_must_fail git worktree add new-rebase under-rebase && ! test -d new-rebase ' test_expect_success 'checking out a rebased branch from another worktree' ' git worktree add new-place && test_must_fail git -C new-place checkout under-rebase ' test_expect_success 'not allow to delete a branch under rebase' ' ( cd under-rebase && test_must_fail git branch -D under-rebase ) ' test_expect_success 'rename a branch under rebase not allowed' ' test_must_fail git branch -M under-rebase rebase-with-new-name ' test_expect_success 'check out from current worktree branch ok' ' ( cd under-rebase && git checkout under-rebase && git checkout - && git rebase --abort ) ' test_expect_success 'checkout a branch under bisect' ' git worktree add under-bisect && ( cd under-bisect && git bisect start && git bisect bad && git bisect good HEAD~2 && git worktree list | grep "under-bisect.*detached HEAD" && test_must_fail git worktree add new-bisect under-bisect && ! test -d new-bisect ) ' test_expect_success 'rename a branch under bisect not allowed' ' test_must_fail git branch -M under-bisect bisect-with-new-name ' test_done (CommandList children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:test_description) op: Equal rhs: {(SQ <"test git worktree add">)} spids: [4] ) ] spids: [4] ) (C {(.)} {(./test-lib.sh)}) (C {(.)} {(DQ ($ VSub_Name "$TEST_DIRECTORY")) (/lib-rebase.sh)}) (C {(test_expect_success)} {(SQ )} {(SQ <"\n"> <"\ttest_commit init\n">)}) (C {(test_expect_success)} {(SQ <"\"add\" an existing worktree">)} { (SQ <"\n"> <"\tmkdir -p existing/subtree &&\n"> <"\ttest_must_fail git worktree add --detach existing master\n"> ) } ) (C {(test_expect_success)} {(SQ <"\"add\" an existing empty worktree">)} { (SQ <"\n"> <"\tmkdir existing_empty &&\n"> <"\tgit worktree add --detach existing_empty master\n"> ) } ) (C {(test_expect_success)} {(SQ <"\"add\" using shorthand - fails when no previous branch">)} {(SQ <"\n"> <"\ttest_must_fail git worktree add existing_short -\n">)} ) (C {(test_expect_success)} {(SQ <"\"add\" using - shorthand">)} { (SQ <"\n"> <"\tgit checkout -b newbranch &&\n"> <"\techo hello >myworld &&\n"> <"\tgit add myworld &&\n"> <"\tgit commit -m myworld &&\n"> <"\tgit checkout master &&\n"> <"\tgit worktree add short-hand - &&\n"> <"\techo refs/heads/newbranch >expect &&\n"> <"\tgit -C short-hand rev-parse --symbolic-full-name HEAD >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"\"add\" refuses to checkout locked branch">)} { (SQ <"\n"> <"\ttest_must_fail git worktree add zere master &&\n"> <"\t! test -d zere &&\n"> <"\t! test -d .git/worktrees/zere\n"> ) } ) (C {(test_expect_success)} {(SQ <"checking out paths not complaining about linked checkouts">)} { (SQ <"\n"> <"\t(\n"> <"\tcd existing_empty &&\n"> <"\techo dirty >>init.t &&\n"> <"\tgit checkout master -- init.t\n"> <"\t)\n"> ) } ) (C {(test_expect_success)} {(SQ <"\"add\" worktree">)} { (SQ <"\n"> <"\tgit rev-parse HEAD >expect &&\n"> <"\tgit worktree add --detach here master &&\n"> <"\t(\n"> <"\t\tcd here &&\n"> <"\t\ttest_cmp ../init.t init.t &&\n"> <"\t\ttest_must_fail git symbolic-ref HEAD &&\n"> <"\t\tgit rev-parse HEAD >actual &&\n"> <"\t\ttest_cmp ../expect actual &&\n"> <"\t\tgit fsck\n"> <"\t)\n"> ) } ) (C {(test_expect_success)} {(SQ <"\"add\" worktree from a subdir">)} { (SQ <"\n"> <"\t(\n"> <"\t\tmkdir sub &&\n"> <"\t\tcd sub &&\n"> <"\t\tgit worktree add --detach here master &&\n"> <"\t\tcd here &&\n"> <"\t\ttest_cmp ../../init.t init.t\n"> <"\t)\n"> ) } ) (C {(test_expect_success)} {(SQ <"\"add\" from a linked checkout">)} { (SQ <"\n"> <"\t(\n"> <"\t\tcd here &&\n"> <"\t\tgit worktree add --detach nested-here master &&\n"> <"\t\tcd nested-here &&\n"> <"\t\tgit fsck\n"> <"\t)\n"> ) } ) (C {(test_expect_success)} {(SQ <"\"add\" worktree creating new branch">)} { (SQ <"\n"> <"\tgit worktree add -b newmaster there master &&\n"> <"\t(\n"> <"\t\tcd there &&\n"> <"\t\ttest_cmp ../init.t init.t &&\n"> <"\t\tgit symbolic-ref HEAD >actual &&\n"> <"\t\techo refs/heads/newmaster >expect &&\n"> <"\t\ttest_cmp expect actual &&\n"> <"\t\tgit fsck\n"> <"\t)\n"> ) } ) (C {(test_expect_success)} {(SQ <"die the same branch is already checked out">)} { (SQ <"\n"> <"\t(\n"> <"\t\tcd here &&\n"> <"\t\ttest_must_fail git checkout newmaster\n"> <"\t)\n"> ) } ) (C {(test_expect_success)} {(SYMLINKS)} {(SQ <"die the same branch is already checked out (symlink)">)} { (SQ <"\n"> <"\thead=$(git -C there rev-parse --git-path HEAD) &&\n"> <"\tref=$(git -C there symbolic-ref HEAD) &&\n"> <"\trm \"$head\" &&\n"> <"\tln -s \"$ref\" \"$head\" &&\n"> <"\ttest_must_fail git -C here checkout newmaster\n"> ) } ) (C {(test_expect_success)} {(SQ <"not die the same branch is already checked out">)} { (SQ <"\n"> <"\t(\n"> <"\t\tcd here &&\n"> <"\t\tgit worktree add --force anothernewmaster newmaster\n"> <"\t)\n"> ) } ) (C {(test_expect_success)} {(SQ <"not die on re-checking out current branch">)} {(SQ <"\n"> <"\t(\n"> <"\t\tcd there &&\n"> <"\t\tgit checkout newmaster\n"> <"\t)\n">)} ) (C {(test_expect_success)} {(SQ <"\"add\" from a bare repo">)} { (SQ <"\n"> <"\t(\n"> <"\t\tgit clone --bare . bare &&\n"> <"\t\tcd bare &&\n"> <"\t\tgit worktree add -b bare-master ../there2 master\n"> <"\t)\n"> ) } ) (C {(test_expect_success)} {(SQ <"checkout from a bare repo without \"add\"">)} { (SQ <"\n"> <"\t(\n"> <"\t\tcd bare &&\n"> <"\t\ttest_must_fail git checkout master\n"> <"\t)\n">) } ) (C {(test_expect_success)} {(SQ <"\"add\" default branch of a bare repo">)} { (SQ <"\n"> <"\t(\n"> <"\t\tgit clone --bare . bare2 &&\n"> <"\t\tcd bare2 &&\n"> <"\t\tgit worktree add ../there3 master\n"> <"\t)\n"> ) } ) (C {(test_expect_success)} {(SQ <"checkout with grafts">)} { (SQ <"\n"> <"\ttest_when_finished rm .git/info/grafts &&\n"> <"\ttest_commit abc &&\n"> <"\tSHA1=$(git rev-parse HEAD) &&\n"> <"\ttest_commit def &&\n"> <"\ttest_commit xyz &&\n"> <"\techo \"$(git rev-parse HEAD) $SHA1\" >.git/info/grafts &&\n"> <"\tcat >expected <<-\\EOF &&\n"> <"\txyz\n"> <"\tabc\n"> <"\tEOF\n"> <"\tgit log --format=%s -2 >actual &&\n"> <"\ttest_cmp expected actual &&\n"> <"\tgit worktree add --detach grafted master &&\n"> <"\tgit --git-dir=grafted/.git log --format=%s -2 >actual &&\n"> <"\ttest_cmp expected actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"\"add\" from relative HEAD">)} { (SQ <"\n"> <"\ttest_commit a &&\n"> <"\ttest_commit b &&\n"> <"\ttest_commit c &&\n"> <"\tgit rev-parse HEAD~1 >expected &&\n"> <"\tgit worktree add relhead HEAD~1 &&\n"> <"\tgit -C relhead rev-parse HEAD >actual &&\n"> <"\ttest_cmp expected actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"\"add -b\" with omitted">)} {(SQ <"\n"> <"\tgit worktree add -b burble flornk &&\n"> <"\ttest_cmp_rev HEAD burble\n">)} ) (C {(test_expect_success)} {(SQ <"\"add --detach\" with omitted">)} { (SQ <"\n"> <"\tgit worktree add --detach fishhook &&\n"> <"\tgit rev-parse HEAD >expected &&\n"> <"\tgit -C fishhook rev-parse HEAD >actual &&\n"> <"\ttest_cmp expected actual &&\n"> <"\ttest_must_fail git -C fishhook symbolic-ref HEAD\n"> ) } ) (C {(test_expect_success)} {(SQ <"\"add\" with omitted">)} {(SQ <"\n"> <"\tgit worktree add wiffle/bat &&\n"> <"\ttest_cmp_rev HEAD bat\n">)} ) (C {(test_expect_success)} {(SQ <"\"add\" auto-vivify does not clobber existing branch">)} { (SQ <"\n"> <"\ttest_commit c1 &&\n"> <"\ttest_commit c2 &&\n"> <"\tgit branch precious HEAD~1 &&\n"> <"\ttest_must_fail git worktree add precious &&\n"> <"\ttest_cmp_rev HEAD~1 precious &&\n"> <"\ttest_path_is_missing precious\n"> ) } ) (C {(test_expect_success)} {(SQ <"\"add\" no auto-vivify with --detach and omitted">)} { (SQ <"\n"> <"\tgit worktree add --detach mish/mash &&\n"> <"\ttest_must_fail git rev-parse mash -- &&\n"> <"\ttest_must_fail git -C mish/mash symbolic-ref HEAD\n"> ) } ) (C {(test_expect_success)} {(SQ <"\"add\" -b/-B mutually exclusive">)} {(SQ <"\n"> <"\ttest_must_fail git worktree add -b poodle -B poodle bamboo master\n">)} ) (C {(test_expect_success)} {(SQ <"\"add\" -b/--detach mutually exclusive">)} {(SQ <"\n"> <"\ttest_must_fail git worktree add -b poodle --detach bamboo master\n">)} ) (C {(test_expect_success)} {(SQ <"\"add\" -B/--detach mutually exclusive">)} {(SQ <"\n"> <"\ttest_must_fail git worktree add -B poodle --detach bamboo master\n">)} ) (C {(test_expect_success)} {(SQ <"\"add -B\" fails if the branch is checked out">)} { (SQ <"\n"> <"\tgit rev-parse newmaster >before &&\n"> <"\ttest_must_fail git worktree add -B newmaster bamboo master &&\n"> <"\tgit rev-parse newmaster >after &&\n"> <"\ttest_cmp before after\n"> ) } ) (C {(test_expect_success)} {(SQ <"add -B">)} { (SQ <"\n"> <"\tgit worktree add -B poodle bamboo2 master^ &&\n"> <"\tgit -C bamboo2 symbolic-ref HEAD >actual &&\n"> <"\techo refs/heads/poodle >expected &&\n"> <"\ttest_cmp expected actual &&\n"> <"\ttest_cmp_rev master^ poodle\n"> ) } ) (C {(test_expect_success)} {(SQ <"local clone from linked checkout">)} { (SQ <"\n"> <"\tgit clone --local here here-clone &&\n"> <"\t( cd here-clone && git fsck )\n">) } ) (C {(test_expect_success)} {(SQ <"\"add\" worktree with --no-checkout">)} { (SQ <"\n"> <"\tgit worktree add --no-checkout -b swamp swamp &&\n"> <"\t! test -e swamp/init.t &&\n"> <"\tgit -C swamp reset --hard &&\n"> <"\ttest_cmp init.t swamp/init.t\n"> ) } ) (C {(test_expect_success)} {(SQ <"\"add\" worktree with --checkout">)} { (SQ <"\n"> <"\tgit worktree add --checkout -b swmap2 swamp2 &&\n"> <"\ttest_cmp init.t swamp2/init.t\n"> ) } ) (C {(test_expect_success)} {(SQ <"put a worktree under rebase">)} { (SQ <"\n"> <"\tgit worktree add under-rebase &&\n"> <"\t(\n"> <"\t\tcd under-rebase &&\n"> <"\t\tset_fake_editor &&\n"> <"\t\tFAKE_LINES=\"edit 1\" git rebase -i HEAD^ &&\n"> <"\t\tgit worktree list | grep \"under-rebase.*detached HEAD\"\n"> <"\t)\n"> ) } ) (C {(test_expect_success)} {(SQ <"add a worktree, checking out a rebased branch">)} { (SQ <"\n"> <"\ttest_must_fail git worktree add new-rebase under-rebase &&\n"> <"\t! test -d new-rebase\n"> ) } ) (C {(test_expect_success)} {(SQ <"checking out a rebased branch from another worktree">)} { (SQ <"\n"> <"\tgit worktree add new-place &&\n"> <"\ttest_must_fail git -C new-place checkout under-rebase\n"> ) } ) (C {(test_expect_success)} {(SQ <"not allow to delete a branch under rebase">)} { (SQ <"\n"> <"\t(\n"> <"\t\tcd under-rebase &&\n"> <"\t\ttest_must_fail git branch -D under-rebase\n"> <"\t)\n"> ) } ) (C {(test_expect_success)} {(SQ <"rename a branch under rebase not allowed">)} {(SQ <"\n"> <"\ttest_must_fail git branch -M under-rebase rebase-with-new-name\n">)} ) (C {(test_expect_success)} {(SQ <"check out from current worktree branch ok">)} { (SQ <"\n"> <"\t(\n"> <"\t\tcd under-rebase &&\n"> <"\t\tgit checkout under-rebase &&\n"> <"\t\tgit checkout - &&\n"> <"\t\tgit rebase --abort\n"> <"\t)\n"> ) } ) (C {(test_expect_success)} {(SQ <"checkout a branch under bisect">)} { (SQ <"\n"> <"\tgit worktree add under-bisect &&\n"> <"\t(\n"> <"\t\tcd under-bisect &&\n"> <"\t\tgit bisect start &&\n"> <"\t\tgit bisect bad &&\n"> <"\t\tgit bisect good HEAD~2 &&\n"> <"\t\tgit worktree list | grep \"under-bisect.*detached HEAD\" &&\n"> <"\t\ttest_must_fail git worktree add new-bisect under-bisect &&\n"> <"\t\t! test -d new-bisect\n"> <"\t)\n"> ) } ) (C {(test_expect_success)} {(SQ <"rename a branch under bisect not allowed">)} {(SQ <"\n"> <"\ttest_must_fail git branch -M under-bisect bisect-with-new-name\n">)} ) (C {(test_done)}) ] )