3 test_description
='test git worktree move, remove, lock and unlock'
5 TEST_PASSES_SANITIZE_LEAK
=true
8 test_expect_success
'setup' '
10 git worktree add source &&
11 git worktree list --porcelain >out &&
12 grep "^worktree" out >actual &&
13 cat <<-EOF >expected &&
15 worktree $(pwd)/source
17 test_cmp expected actual
20 test_expect_success
'lock main worktree' '
21 test_must_fail git worktree lock .
24 test_expect_success
'lock linked worktree' '
25 git worktree lock --reason hahaha source &&
26 echo hahaha >expected &&
27 test_cmp expected .git/worktrees/source/locked
30 test_expect_success
'lock linked worktree from another worktree' '
31 rm .git/worktrees/source/locked &&
32 git worktree add elsewhere &&
33 git -C elsewhere worktree lock --reason hahaha ../source &&
34 echo hahaha >expected &&
35 test_cmp expected .git/worktrees/source/locked
38 test_expect_success
'lock worktree twice' '
39 test_must_fail git worktree lock source &&
40 echo hahaha >expected &&
41 test_cmp expected .git/worktrees/source/locked
44 test_expect_success
'lock worktree twice (from the locked worktree)' '
45 test_must_fail git -C source worktree lock . &&
46 echo hahaha >expected &&
47 test_cmp expected .git/worktrees/source/locked
50 test_expect_success
'unlock main worktree' '
51 test_must_fail git worktree unlock .
54 test_expect_success
'unlock linked worktree' '
55 git worktree unlock source &&
56 test_path_is_missing .git/worktrees/source/locked
59 test_expect_success
'unlock worktree twice' '
60 test_must_fail git worktree unlock source &&
61 test_path_is_missing .git/worktrees/source/locked
64 test_expect_success
'move non-worktree' '
66 test_must_fail git worktree move abc def
69 test_expect_success
'move locked worktree' '
70 git worktree lock source &&
71 test_when_finished "git worktree unlock source" &&
72 test_must_fail git worktree move source destination
75 test_expect_success
'move worktree' '
76 git worktree move source destination &&
77 test_path_is_missing source &&
78 git worktree list --porcelain >out &&
79 grep "^worktree.*/destination$" out &&
80 ! grep "^worktree.*/source$" out &&
81 git -C destination log --format=%s >actual2 &&
82 echo init >expected2 &&
83 test_cmp expected2 actual2
86 test_expect_success
'move main worktree' '
87 test_must_fail git worktree move . def
90 test_expect_success
'move worktree to another dir' '
92 git worktree move destination some-dir &&
93 test_when_finished "git worktree move some-dir/destination destination" &&
94 test_path_is_missing destination &&
95 git worktree list --porcelain >out &&
96 grep "^worktree.*/some-dir/destination$" out &&
97 git -C some-dir/destination log --format=%s >actual2 &&
98 echo init >expected2 &&
99 test_cmp expected2 actual2
102 test_expect_success
'move locked worktree (force)' '
104 git worktree unlock flump || :
105 git worktree remove flump || :
106 git worktree unlock ploof || :
107 git worktree remove ploof || :
109 git worktree add --detach flump &&
110 git worktree lock flump &&
111 test_must_fail git worktree move flump ploof" &&
112 test_must_fail git worktree move --force flump ploof" &&
113 git worktree move --force --force flump ploof
116 test_expect_success
'refuse to move worktree atop existing path' '
118 git worktree add --detach beeble &&
119 test_must_fail git worktree move beeble bobble
122 test_expect_success
'move atop existing but missing worktree' '
123 git worktree add --detach gnoo &&
124 git worktree add --detach pneu &&
126 test_must_fail git worktree move gnoo pneu &&
127 git worktree move --force gnoo pneu &&
129 git worktree add --detach nu &&
130 git worktree lock nu &&
132 test_must_fail git worktree move pneu nu &&
133 test_must_fail git worktree --force move pneu nu &&
134 git worktree move --force --force pneu nu
137 test_expect_success
'move a repo with uninitialized submodule' '
141 test_commit initial &&
142 git submodule add "$PWD"/.git sub &&
143 git commit -m withsub &&
144 git worktree add second HEAD &&
145 git worktree move second third
149 test_expect_success
'not move a repo with initialized submodule' '
152 git -C third submodule update &&
153 test_must_fail git worktree move third forth
157 test_expect_success
'remove main worktree' '
158 test_must_fail git worktree remove .
161 test_expect_success
'remove locked worktree' '
162 git worktree lock destination &&
163 test_when_finished "git worktree unlock destination" &&
164 test_must_fail git worktree remove destination
167 test_expect_success
'remove worktree with dirty tracked file' '
168 echo dirty >>destination/init.t &&
169 test_when_finished "git -C destination checkout init.t" &&
170 test_must_fail git worktree remove destination
173 test_expect_success
'remove worktree with untracked file' '
174 : >destination/untracked &&
175 test_must_fail git worktree remove destination
178 test_expect_success
'force remove worktree with untracked file' '
179 git worktree remove --force destination &&
180 test_path_is_missing destination
183 test_expect_success
'remove missing worktree' '
184 git worktree add to-be-gone &&
185 test -d .git/worktrees/to-be-gone &&
186 mv to-be-gone gone &&
187 git worktree remove to-be-gone &&
188 test_path_is_missing .git/worktrees/to-be-gone
191 test_expect_success
'NOT remove missing-but-locked worktree' '
192 git worktree add gone-but-locked &&
193 git worktree lock gone-but-locked &&
194 test -d .git/worktrees/gone-but-locked &&
195 mv gone-but-locked really-gone-now &&
196 test_must_fail git worktree remove gone-but-locked &&
197 test_path_is_dir .git/worktrees/gone-but-locked
200 test_expect_success
'proper error when worktree not found' '
201 for i in noodle noodle/bork
203 test_must_fail git worktree lock $i 2>err &&
204 test_i18ngrep "not a working tree" err || return 1
208 test_expect_success
'remove locked worktree (force)' '
209 git worktree add --detach gumby &&
210 test_when_finished "git worktree remove gumby || :" &&
211 git worktree lock gumby &&
212 test_when_finished "git worktree unlock gumby || :" &&
213 test_must_fail git worktree remove gumby &&
214 test_must_fail git worktree remove --force gumby &&
215 git worktree remove --force --force gumby
218 test_expect_success
'remove cleans up .git/worktrees when empty' '
223 git worktree add --detach goom &&
224 test_path_exists .git/worktrees &&
225 git worktree remove goom &&
226 test_path_is_missing .git/worktrees
230 test_expect_success
'remove a repo with uninitialized submodule' '
233 git worktree add to-remove HEAD &&
234 git worktree remove to-remove
238 test_expect_success
'not remove a repo with initialized submodule' '
241 git worktree add to-remove HEAD &&
242 git -C to-remove submodule update &&
243 test_must_fail git worktree remove to-remove