clean: respect pathspecs with "-d"
[git] / t / t7001-mv.sh
1 #!/bin/sh
2
3 test_description='git mv in subdirs'
4 . ./test-lib.sh
5
6 test_expect_success \
7     'prepare reference tree' \
8     'mkdir path0 path1 &&
9      cp "$TEST_DIRECTORY"/../COPYING path0/COPYING &&
10      git add path0/COPYING &&
11      git commit -m add -a'
12
13 test_expect_success \
14     'moving the file out of subdirectory' \
15     'cd path0 && git mv COPYING ../path1/COPYING'
16
17 # in path0 currently
18 test_expect_success \
19     'commiting the change' \
20     'cd .. && git commit -m move-out -a'
21
22 test_expect_success \
23     'checking the commit' \
24     'git diff-tree -r -M --name-status  HEAD^ HEAD | \
25     grep "^R100..*path0/COPYING..*path1/COPYING"'
26
27 test_expect_success \
28     'moving the file back into subdirectory' \
29     'cd path0 && git mv ../path1/COPYING COPYING'
30
31 # in path0 currently
32 test_expect_success \
33     'commiting the change' \
34     'cd .. && git commit -m move-in -a'
35
36 test_expect_success \
37     'checking the commit' \
38     'git diff-tree -r -M --name-status  HEAD^ HEAD | \
39     grep "^R100..*path1/COPYING..*path0/COPYING"'
40
41 test_expect_success \
42     'checking -k on non-existing file' \
43     'git mv -k idontexist path0'
44
45 test_expect_success \
46     'checking -k on untracked file' \
47     'touch untracked1 &&
48      git mv -k untracked1 path0 &&
49      test -f untracked1 &&
50      test ! -f path0/untracked1'
51
52 test_expect_success \
53     'checking -k on multiple untracked files' \
54     'touch untracked2 &&
55      git mv -k untracked1 untracked2 path0 &&
56      test -f untracked1 &&
57      test -f untracked2 &&
58      test ! -f path0/untracked1 &&
59      test ! -f path0/untracked2'
60
61 test_expect_success \
62     'checking -f on untracked file with existing target' \
63     'touch path0/untracked1 &&
64      test_must_fail git mv -f untracked1 path0 &&
65      test ! -f .git/index.lock &&
66      test -f untracked1 &&
67      test -f path0/untracked1'
68
69 # clean up the mess in case bad things happen
70 rm -f idontexist untracked1 untracked2 \
71      path0/idontexist path0/untracked1 path0/untracked2 \
72      .git/index.lock
73 rmdir path1
74
75 test_expect_success \
76     'moving to absent target with trailing slash' \
77     'test_must_fail git mv path0/COPYING no-such-dir/ &&
78      test_must_fail git mv path0/COPYING no-such-dir// &&
79      git mv path0/ no-such-dir/ &&
80      test_path_is_dir no-such-dir'
81
82 test_expect_success \
83     'clean up' \
84     'git reset --hard'
85
86 test_expect_success \
87     'moving to existing untracked target with trailing slash' \
88     'mkdir path1 &&
89      git mv path0/ path1/ &&
90      test_path_is_dir path1/path0/'
91
92 test_expect_success \
93     'moving to existing tracked target with trailing slash' \
94     'mkdir path2 &&
95      >path2/file && git add path2/file &&
96      git mv path1/path0/ path2/ &&
97      test_path_is_dir path2/path0/'
98
99 test_expect_success \
100     'clean up' \
101     'git reset --hard'
102
103 test_expect_success \
104     'adding another file' \
105     'cp "$TEST_DIRECTORY"/../README path0/README &&
106      git add path0/README &&
107      git commit -m add2 -a'
108
109 test_expect_success \
110     'moving whole subdirectory' \
111     'git mv path0 path2'
112
113 test_expect_success \
114     'commiting the change' \
115     'git commit -m dir-move -a'
116
117 test_expect_success \
118     'checking the commit' \
119     'git diff-tree -r -M --name-status  HEAD^ HEAD | \
120      grep "^R100..*path0/COPYING..*path2/COPYING" &&
121      git diff-tree -r -M --name-status  HEAD^ HEAD | \
122      grep "^R100..*path0/README..*path2/README"'
123
124 test_expect_success \
125     'succeed when source is a prefix of destination' \
126     'git mv path2/COPYING path2/COPYING-renamed'
127
128 test_expect_success \
129     'moving whole subdirectory into subdirectory' \
130     'git mv path2 path1'
131
132 test_expect_success \
133     'commiting the change' \
134     'git commit -m dir-move -a'
135
136 test_expect_success \
137     'checking the commit' \
138     'git diff-tree -r -M --name-status  HEAD^ HEAD | \
139      grep "^R100..*path2/COPYING..*path1/path2/COPYING" &&
140      git diff-tree -r -M --name-status  HEAD^ HEAD | \
141      grep "^R100..*path2/README..*path1/path2/README"'
142
143 test_expect_success \
144     'do not move directory over existing directory' \
145     'mkdir path0 && mkdir path0/path2 && test_must_fail git mv path2 path0'
146
147 test_expect_success \
148     'move into "."' \
149     'git mv path1/path2/ .'
150
151 test_expect_success "Michael Cassar's test case" '
152         rm -fr .git papers partA &&
153         git init &&
154         mkdir -p papers/unsorted papers/all-papers partA &&
155         echo a > papers/unsorted/Thesis.pdf &&
156         echo b > partA/outline.txt &&
157         echo c > papers/unsorted/_another &&
158         git add papers partA &&
159         T1=`git write-tree` &&
160
161         git mv papers/unsorted/Thesis.pdf papers/all-papers/moo-blah.pdf &&
162
163         T=`git write-tree` &&
164         git ls-tree -r $T | grep partA/outline.txt || {
165                 git ls-tree -r $T
166                 (exit 1)
167         }
168 '
169
170 rm -fr papers partA path?
171
172 test_expect_success "Sergey Vlasov's test case" '
173         rm -fr .git &&
174         git init &&
175         mkdir ab &&
176         date >ab.c &&
177         date >ab/d &&
178         git add ab.c ab &&
179         git commit -m 'initial' &&
180         git mv ab a
181 '
182
183 test_expect_success 'absolute pathname' '(
184
185         rm -fr mine &&
186         mkdir mine &&
187         cd mine &&
188         test_create_repo one &&
189         cd one &&
190         mkdir sub &&
191         >sub/file &&
192         git add sub/file &&
193
194         git mv sub "$(pwd)/in" &&
195         ! test -d sub &&
196         test -d in &&
197         git ls-files --error-unmatch in/file
198
199
200 )'
201
202 test_expect_success 'absolute pathname outside should fail' '(
203
204         rm -fr mine &&
205         mkdir mine &&
206         cd mine &&
207         out=$(pwd) &&
208         test_create_repo one &&
209         cd one &&
210         mkdir sub &&
211         >sub/file &&
212         git add sub/file &&
213
214         test_must_fail git mv sub "$out/out" &&
215         test -d sub &&
216         ! test -d ../in &&
217         git ls-files --error-unmatch sub/file
218
219 )'
220
221 test_expect_success 'git mv to move multiple sources into a directory' '
222         rm -fr .git && git init &&
223         mkdir dir other &&
224         >dir/a.txt &&
225         >dir/b.txt &&
226         git add dir/?.txt &&
227         git mv dir/a.txt dir/b.txt other &&
228         git ls-files >actual &&
229         { echo other/a.txt; echo other/b.txt; } >expect &&
230         test_cmp expect actual
231 '
232
233 test_expect_success 'git mv should not change sha1 of moved cache entry' '
234
235         rm -fr .git &&
236         git init &&
237         echo 1 >dirty &&
238         git add dirty &&
239         entry="$(git ls-files --stage dirty | cut -f 1)" &&
240         git mv dirty dirty2 &&
241         [ "$entry" = "$(git ls-files --stage dirty2 | cut -f 1)" ] &&
242         echo 2 >dirty2 &&
243         git mv dirty2 dirty &&
244         [ "$entry" = "$(git ls-files --stage dirty | cut -f 1)" ]
245
246 '
247
248 rm -f dirty dirty2
249
250 test_expect_success 'git mv should overwrite symlink to a file' '
251
252         rm -fr .git &&
253         git init &&
254         echo 1 >moved &&
255         test_ln_s_add moved symlink &&
256         git add moved &&
257         test_must_fail git mv moved symlink &&
258         git mv -f moved symlink &&
259         ! test -e moved &&
260         test -f symlink &&
261         test "$(cat symlink)" = 1 &&
262         git update-index --refresh &&
263         git diff-files --quiet
264
265 '
266
267 rm -f moved symlink
268
269 test_expect_success 'git mv should overwrite file with a symlink' '
270
271         rm -fr .git &&
272         git init &&
273         echo 1 >moved &&
274         test_ln_s_add moved symlink &&
275         git add moved &&
276         test_must_fail git mv symlink moved &&
277         git mv -f symlink moved &&
278         ! test -e symlink &&
279         git update-index --refresh &&
280         git diff-files --quiet
281
282 '
283
284 test_expect_success SYMLINKS 'check moved symlink' '
285
286         test -h moved
287 '
288
289 rm -f moved symlink
290
291 test_expect_success 'setup submodule' '
292         git commit -m initial &&
293         git reset --hard &&
294         git submodule add ./. sub &&
295         echo content >file &&
296         git add file &&
297         git commit -m "added sub and file"
298 '
299
300 test_expect_success 'git mv cannot move a submodule in a file' '
301         test_must_fail git mv sub file
302 '
303
304 test_expect_success 'git mv moves a submodule with a .git directory and no .gitmodules' '
305         entry="$(git ls-files --stage sub | cut -f 1)" &&
306         git rm .gitmodules &&
307         (
308                 cd sub &&
309                 rm -f .git &&
310                 cp -a ../.git/modules/sub .git &&
311                 GIT_WORK_TREE=. git config --unset core.worktree
312         ) &&
313         mkdir mod &&
314         git mv sub mod/sub &&
315         ! test -e sub &&
316         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
317         (
318                 cd mod/sub &&
319                 git status
320         ) &&
321         git update-index --refresh &&
322         git diff-files --quiet
323 '
324
325 test_expect_success 'git mv moves a submodule with a .git directory and .gitmodules' '
326         rm -rf mod &&
327         git reset --hard &&
328         git submodule update &&
329         entry="$(git ls-files --stage sub | cut -f 1)" &&
330         (
331                 cd sub &&
332                 rm -f .git &&
333                 cp -a ../.git/modules/sub .git &&
334                 GIT_WORK_TREE=. git config --unset core.worktree
335         ) &&
336         mkdir mod &&
337         git mv sub mod/sub &&
338         ! test -e sub &&
339         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
340         (
341                 cd mod/sub &&
342                 git status
343         ) &&
344         echo mod/sub >expected &&
345         git config -f .gitmodules submodule.sub.path >actual &&
346         test_cmp expected actual &&
347         git update-index --refresh &&
348         git diff-files --quiet
349 '
350
351 test_expect_success 'git mv moves a submodule with gitfile' '
352         rm -rf mod/sub &&
353         git reset --hard &&
354         git submodule update &&
355         entry="$(git ls-files --stage sub | cut -f 1)" &&
356         (
357                 cd mod &&
358                 git mv ../sub/ .
359         ) &&
360         ! test -e sub &&
361         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
362         (
363                 cd mod/sub &&
364                 git status
365         ) &&
366         echo mod/sub >expected &&
367         git config -f .gitmodules submodule.sub.path >actual &&
368         test_cmp expected actual &&
369         git update-index --refresh &&
370         git diff-files --quiet
371 '
372
373 test_expect_success 'mv does not complain when no .gitmodules file is found' '
374         rm -rf mod/sub &&
375         git reset --hard &&
376         git submodule update &&
377         git rm .gitmodules &&
378         entry="$(git ls-files --stage sub | cut -f 1)" &&
379         git mv sub mod/sub 2>actual.err &&
380         ! test -s actual.err &&
381         ! test -e sub &&
382         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
383         (
384                 cd mod/sub &&
385                 git status
386         ) &&
387         git update-index --refresh &&
388         git diff-files --quiet
389 '
390
391 test_expect_success 'mv will error out on a modified .gitmodules file unless staged' '
392         rm -rf mod/sub &&
393         git reset --hard &&
394         git submodule update &&
395         git config -f .gitmodules foo.bar true &&
396         entry="$(git ls-files --stage sub | cut -f 1)" &&
397         test_must_fail git mv sub mod/sub 2>actual.err &&
398         test -s actual.err &&
399         test -e sub &&
400         git diff-files --quiet -- sub &&
401         git add .gitmodules &&
402         git mv sub mod/sub 2>actual.err &&
403         ! test -s actual.err &&
404         ! test -e sub &&
405         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
406         (
407                 cd mod/sub &&
408                 git status
409         ) &&
410         git update-index --refresh &&
411         git diff-files --quiet
412 '
413
414 test_expect_success 'mv issues a warning when section is not found in .gitmodules' '
415         rm -rf mod/sub &&
416         git reset --hard &&
417         git submodule update &&
418         git config -f .gitmodules --remove-section submodule.sub &&
419         git add .gitmodules &&
420         entry="$(git ls-files --stage sub | cut -f 1)" &&
421         echo "warning: Could not find section in .gitmodules where path=sub" >expect.err &&
422         git mv sub mod/sub 2>actual.err &&
423         test_i18ncmp expect.err actual.err &&
424         ! test -e sub &&
425         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
426         (
427                 cd mod/sub &&
428                 git status
429         ) &&
430         git update-index --refresh &&
431         git diff-files --quiet
432 '
433
434 test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' '
435         rm -rf mod/sub &&
436         git reset --hard &&
437         git submodule update &&
438         git mv -n sub mod/sub 2>actual.err &&
439         test -f sub/.git &&
440         git diff-index --exit-code HEAD &&
441         git update-index --refresh &&
442         git diff-files --quiet -- sub .gitmodules
443 '
444
445 test_done