00a6d4d1d2
Uninitialized submodules have nothing valueable for us to be worried about. They are just SHA-1. Let "worktree remove" and "worktree move" continue in this case so that people can still use multiple worktrees on repos with optional submodules that are never populated, like sha1collisiondetection in git.git when checked out by doc-diff script. Note that for "worktree remove", it is possible that a user initializes a submodule (*), makes some commits (but not push), then deinitializes it. At that point, the submodule is unpopulated, but the precious new commits are still in $GIT_COMMON_DIR/worktrees/<worktree>/modules/<submodule> directory and we should not allow removing the worktree or we lose those commits forever. The new directory check is added to prevent this. (*) yes they are screwed anyway by doing this since "git submodule" would add submodule.* in $GIT_COMMON_DIR/config, which is shared across multiple worktrees. But it does not mean we let them be screwed even more. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
226 lines
6.0 KiB
Bash
Executable File
226 lines
6.0 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
test_description='test git worktree move, remove, lock and unlock'
|
|
|
|
. ./test-lib.sh
|
|
|
|
test_expect_success 'setup' '
|
|
test_commit init &&
|
|
git worktree add source &&
|
|
git worktree list --porcelain >out &&
|
|
grep "^worktree" out >actual &&
|
|
cat <<-EOF >expected &&
|
|
worktree $(pwd)
|
|
worktree $(pwd)/source
|
|
EOF
|
|
test_cmp expected actual
|
|
'
|
|
|
|
test_expect_success 'lock main worktree' '
|
|
test_must_fail git worktree lock .
|
|
'
|
|
|
|
test_expect_success 'lock linked worktree' '
|
|
git worktree lock --reason hahaha source &&
|
|
echo hahaha >expected &&
|
|
test_cmp expected .git/worktrees/source/locked
|
|
'
|
|
|
|
test_expect_success 'lock linked worktree from another worktree' '
|
|
rm .git/worktrees/source/locked &&
|
|
git worktree add elsewhere &&
|
|
git -C elsewhere worktree lock --reason hahaha ../source &&
|
|
echo hahaha >expected &&
|
|
test_cmp expected .git/worktrees/source/locked
|
|
'
|
|
|
|
test_expect_success 'lock worktree twice' '
|
|
test_must_fail git worktree lock source &&
|
|
echo hahaha >expected &&
|
|
test_cmp expected .git/worktrees/source/locked
|
|
'
|
|
|
|
test_expect_success 'lock worktree twice (from the locked worktree)' '
|
|
test_must_fail git -C source worktree lock . &&
|
|
echo hahaha >expected &&
|
|
test_cmp expected .git/worktrees/source/locked
|
|
'
|
|
|
|
test_expect_success 'unlock main worktree' '
|
|
test_must_fail git worktree unlock .
|
|
'
|
|
|
|
test_expect_success 'unlock linked worktree' '
|
|
git worktree unlock source &&
|
|
test_path_is_missing .git/worktrees/source/locked
|
|
'
|
|
|
|
test_expect_success 'unlock worktree twice' '
|
|
test_must_fail git worktree unlock source &&
|
|
test_path_is_missing .git/worktrees/source/locked
|
|
'
|
|
|
|
test_expect_success 'move non-worktree' '
|
|
mkdir abc &&
|
|
test_must_fail git worktree move abc def
|
|
'
|
|
|
|
test_expect_success 'move locked worktree' '
|
|
git worktree lock source &&
|
|
test_when_finished "git worktree unlock source" &&
|
|
test_must_fail git worktree move source destination
|
|
'
|
|
|
|
test_expect_success 'move worktree' '
|
|
git worktree move source destination &&
|
|
test_path_is_missing source &&
|
|
git worktree list --porcelain >out &&
|
|
grep "^worktree.*/destination$" out &&
|
|
! grep "^worktree.*/source$" out &&
|
|
git -C destination log --format=%s >actual2 &&
|
|
echo init >expected2 &&
|
|
test_cmp expected2 actual2
|
|
'
|
|
|
|
test_expect_success 'move main worktree' '
|
|
test_must_fail git worktree move . def
|
|
'
|
|
|
|
test_expect_success 'move worktree to another dir' '
|
|
mkdir some-dir &&
|
|
git worktree move destination some-dir &&
|
|
test_when_finished "git worktree move some-dir/destination destination" &&
|
|
test_path_is_missing destination &&
|
|
git worktree list --porcelain >out &&
|
|
grep "^worktree.*/some-dir/destination$" out &&
|
|
git -C some-dir/destination log --format=%s >actual2 &&
|
|
echo init >expected2 &&
|
|
test_cmp expected2 actual2
|
|
'
|
|
|
|
test_expect_success 'move locked worktree (force)' '
|
|
test_when_finished "
|
|
git worktree unlock flump || :
|
|
git worktree remove flump || :
|
|
git worktree unlock ploof || :
|
|
git worktree remove ploof || :
|
|
" &&
|
|
git worktree add --detach flump &&
|
|
git worktree lock flump &&
|
|
test_must_fail git worktree move flump ploof" &&
|
|
test_must_fail git worktree move --force flump ploof" &&
|
|
git worktree move --force --force flump ploof
|
|
'
|
|
|
|
test_expect_success 'move a repo with uninitialized submodule' '
|
|
git init withsub &&
|
|
(
|
|
cd withsub &&
|
|
test_commit initial &&
|
|
git submodule add "$PWD"/.git sub &&
|
|
git commit -m withsub &&
|
|
git worktree add second HEAD &&
|
|
git worktree move second third
|
|
)
|
|
'
|
|
|
|
test_expect_success 'not move a repo with initialized submodule' '
|
|
(
|
|
cd withsub &&
|
|
git -C third submodule update &&
|
|
test_must_fail git worktree move third forth
|
|
)
|
|
'
|
|
|
|
test_expect_success 'remove main worktree' '
|
|
test_must_fail git worktree remove .
|
|
'
|
|
|
|
test_expect_success 'remove locked worktree' '
|
|
git worktree lock destination &&
|
|
test_when_finished "git worktree unlock destination" &&
|
|
test_must_fail git worktree remove destination
|
|
'
|
|
|
|
test_expect_success 'remove worktree with dirty tracked file' '
|
|
echo dirty >>destination/init.t &&
|
|
test_when_finished "git -C destination checkout init.t" &&
|
|
test_must_fail git worktree remove destination
|
|
'
|
|
|
|
test_expect_success 'remove worktree with untracked file' '
|
|
: >destination/untracked &&
|
|
test_must_fail git worktree remove destination
|
|
'
|
|
|
|
test_expect_success 'force remove worktree with untracked file' '
|
|
git worktree remove --force destination &&
|
|
test_path_is_missing destination
|
|
'
|
|
|
|
test_expect_success 'remove missing worktree' '
|
|
git worktree add to-be-gone &&
|
|
test -d .git/worktrees/to-be-gone &&
|
|
mv to-be-gone gone &&
|
|
git worktree remove to-be-gone &&
|
|
test_path_is_missing .git/worktrees/to-be-gone
|
|
'
|
|
|
|
test_expect_success 'NOT remove missing-but-locked worktree' '
|
|
git worktree add gone-but-locked &&
|
|
git worktree lock gone-but-locked &&
|
|
test -d .git/worktrees/gone-but-locked &&
|
|
mv gone-but-locked really-gone-now &&
|
|
test_must_fail git worktree remove gone-but-locked &&
|
|
test_path_is_dir .git/worktrees/gone-but-locked
|
|
'
|
|
|
|
test_expect_success 'proper error when worktree not found' '
|
|
for i in noodle noodle/bork
|
|
do
|
|
test_must_fail git worktree lock $i 2>err &&
|
|
test_i18ngrep "not a working tree" err || return 1
|
|
done
|
|
'
|
|
|
|
test_expect_success 'remove locked worktree (force)' '
|
|
git worktree add --detach gumby &&
|
|
test_when_finished "git worktree remove gumby || :" &&
|
|
git worktree lock gumby &&
|
|
test_when_finished "git worktree unlock gumby || :" &&
|
|
test_must_fail git worktree remove gumby &&
|
|
test_must_fail git worktree remove --force gumby &&
|
|
git worktree remove --force --force gumby
|
|
'
|
|
|
|
test_expect_success 'remove cleans up .git/worktrees when empty' '
|
|
git init moog &&
|
|
(
|
|
cd moog &&
|
|
test_commit bim &&
|
|
git worktree add --detach goom &&
|
|
test_path_exists .git/worktrees &&
|
|
git worktree remove goom &&
|
|
test_path_is_missing .git/worktrees
|
|
)
|
|
'
|
|
|
|
test_expect_success 'remove a repo with uninitialized submodule' '
|
|
(
|
|
cd withsub &&
|
|
git worktree add to-remove HEAD &&
|
|
git worktree remove to-remove
|
|
)
|
|
'
|
|
|
|
test_expect_success 'not remove a repo with initialized submodule' '
|
|
(
|
|
cd withsub &&
|
|
git worktree add to-remove HEAD &&
|
|
git -C to-remove submodule update &&
|
|
test_must_fail git worktree remove to-remove
|
|
)
|
|
'
|
|
|
|
test_done
|