Merge branch 'jc/test-must-be-empty'
[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     'mv --dry-run does not move file' \
43     'git mv -n path0/COPYING MOVED &&
44      test -f path0/COPYING &&
45      test ! -f MOVED'
46
47 test_expect_success \
48     'checking -k on non-existing file' \
49     'git mv -k idontexist path0'
50
51 test_expect_success \
52     'checking -k on untracked file' \
53     'touch untracked1 &&
54      git mv -k untracked1 path0 &&
55      test -f untracked1 &&
56      test ! -f path0/untracked1'
57
58 test_expect_success \
59     'checking -k on multiple untracked files' \
60     'touch untracked2 &&
61      git mv -k untracked1 untracked2 path0 &&
62      test -f untracked1 &&
63      test -f untracked2 &&
64      test ! -f path0/untracked1 &&
65      test ! -f path0/untracked2'
66
67 test_expect_success \
68     'checking -f on untracked file with existing target' \
69     'touch path0/untracked1 &&
70      test_must_fail git mv -f untracked1 path0 &&
71      test ! -f .git/index.lock &&
72      test -f untracked1 &&
73      test -f path0/untracked1'
74
75 # clean up the mess in case bad things happen
76 rm -f idontexist untracked1 untracked2 \
77      path0/idontexist path0/untracked1 path0/untracked2 \
78      .git/index.lock
79 rmdir path1
80
81 test_expect_success \
82     'moving to absent target with trailing slash' \
83     'test_must_fail git mv path0/COPYING no-such-dir/ &&
84      test_must_fail git mv path0/COPYING no-such-dir// &&
85      git mv path0/ no-such-dir/ &&
86      test_path_is_dir no-such-dir'
87
88 test_expect_success \
89     'clean up' \
90     'git reset --hard'
91
92 test_expect_success \
93     'moving to existing untracked target with trailing slash' \
94     'mkdir path1 &&
95      git mv path0/ path1/ &&
96      test_path_is_dir path1/path0/'
97
98 test_expect_success \
99     'moving to existing tracked target with trailing slash' \
100     'mkdir path2 &&
101      >path2/file && git add path2/file &&
102      git mv path1/path0/ path2/ &&
103      test_path_is_dir path2/path0/'
104
105 test_expect_success \
106     'clean up' \
107     'git reset --hard'
108
109 test_expect_success \
110     'adding another file' \
111     'cp "$TEST_DIRECTORY"/../README.md path0/README &&
112      git add path0/README &&
113      git commit -m add2 -a'
114
115 test_expect_success \
116     'moving whole subdirectory' \
117     'git mv path0 path2'
118
119 test_expect_success \
120     'commiting the change' \
121     'git commit -m dir-move -a'
122
123 test_expect_success \
124     'checking the commit' \
125     'git diff-tree -r -M --name-status  HEAD^ HEAD | \
126      grep "^R100..*path0/COPYING..*path2/COPYING" &&
127      git diff-tree -r -M --name-status  HEAD^ HEAD | \
128      grep "^R100..*path0/README..*path2/README"'
129
130 test_expect_success \
131     'succeed when source is a prefix of destination' \
132     'git mv path2/COPYING path2/COPYING-renamed'
133
134 test_expect_success \
135     'moving whole subdirectory into subdirectory' \
136     'git mv path2 path1'
137
138 test_expect_success \
139     'commiting the change' \
140     'git commit -m dir-move -a'
141
142 test_expect_success \
143     'checking the commit' \
144     'git diff-tree -r -M --name-status  HEAD^ HEAD | \
145      grep "^R100..*path2/COPYING..*path1/path2/COPYING" &&
146      git diff-tree -r -M --name-status  HEAD^ HEAD | \
147      grep "^R100..*path2/README..*path1/path2/README"'
148
149 test_expect_success \
150     'do not move directory over existing directory' \
151     'mkdir path0 && mkdir path0/path2 && test_must_fail git mv path2 path0'
152
153 test_expect_success \
154     'move into "."' \
155     'git mv path1/path2/ .'
156
157 test_expect_success "Michael Cassar's test case" '
158         rm -fr .git papers partA &&
159         git init &&
160         mkdir -p papers/unsorted papers/all-papers partA &&
161         echo a > papers/unsorted/Thesis.pdf &&
162         echo b > partA/outline.txt &&
163         echo c > papers/unsorted/_another &&
164         git add papers partA &&
165         T1=$(git write-tree) &&
166
167         git mv papers/unsorted/Thesis.pdf papers/all-papers/moo-blah.pdf &&
168
169         T=$(git write-tree) &&
170         git ls-tree -r $T | verbose grep partA/outline.txt
171 '
172
173 rm -fr papers partA path?
174
175 test_expect_success "Sergey Vlasov's test case" '
176         rm -fr .git &&
177         git init &&
178         mkdir ab &&
179         date >ab.c &&
180         date >ab/d &&
181         git add ab.c ab &&
182         git commit -m 'initial' &&
183         git mv ab a
184 '
185
186 test_expect_success 'absolute pathname' '(
187
188         rm -fr mine &&
189         mkdir mine &&
190         cd mine &&
191         test_create_repo one &&
192         cd one &&
193         mkdir sub &&
194         >sub/file &&
195         git add sub/file &&
196
197         git mv sub "$(pwd)/in" &&
198         ! test -d sub &&
199         test -d in &&
200         git ls-files --error-unmatch in/file
201
202
203 )'
204
205 test_expect_success 'absolute pathname outside should fail' '(
206
207         rm -fr mine &&
208         mkdir mine &&
209         cd mine &&
210         out=$(pwd) &&
211         test_create_repo one &&
212         cd one &&
213         mkdir sub &&
214         >sub/file &&
215         git add sub/file &&
216
217         test_must_fail git mv sub "$out/out" &&
218         test -d sub &&
219         ! test -d ../in &&
220         git ls-files --error-unmatch sub/file
221
222 )'
223
224 test_expect_success 'git mv to move multiple sources into a directory' '
225         rm -fr .git && git init &&
226         mkdir dir other &&
227         >dir/a.txt &&
228         >dir/b.txt &&
229         git add dir/?.txt &&
230         git mv dir/a.txt dir/b.txt other &&
231         git ls-files >actual &&
232         { echo other/a.txt; echo other/b.txt; } >expect &&
233         test_cmp expect actual
234 '
235
236 test_expect_success 'git mv should not change sha1 of moved cache entry' '
237
238         rm -fr .git &&
239         git init &&
240         echo 1 >dirty &&
241         git add dirty &&
242         entry="$(git ls-files --stage dirty | cut -f 1)" &&
243         git mv dirty dirty2 &&
244         [ "$entry" = "$(git ls-files --stage dirty2 | cut -f 1)" ] &&
245         echo 2 >dirty2 &&
246         git mv dirty2 dirty &&
247         [ "$entry" = "$(git ls-files --stage dirty | cut -f 1)" ]
248
249 '
250
251 rm -f dirty dirty2
252
253 test_expect_success 'git mv should overwrite symlink to a file' '
254
255         rm -fr .git &&
256         git init &&
257         echo 1 >moved &&
258         test_ln_s_add moved symlink &&
259         git add moved &&
260         test_must_fail git mv moved symlink &&
261         git mv -f moved symlink &&
262         ! test -e moved &&
263         test -f symlink &&
264         test "$(cat symlink)" = 1 &&
265         git update-index --refresh &&
266         git diff-files --quiet
267
268 '
269
270 rm -f moved symlink
271
272 test_expect_success 'git mv should overwrite file with a symlink' '
273
274         rm -fr .git &&
275         git init &&
276         echo 1 >moved &&
277         test_ln_s_add moved symlink &&
278         git add moved &&
279         test_must_fail git mv symlink moved &&
280         git mv -f symlink moved &&
281         ! test -e symlink &&
282         git update-index --refresh &&
283         git diff-files --quiet
284
285 '
286
287 test_expect_success SYMLINKS 'check moved symlink' '
288
289         test -h moved
290 '
291
292 rm -f moved symlink
293
294 test_expect_success 'setup submodule' '
295         git commit -m initial &&
296         git reset --hard &&
297         git submodule add ./. sub &&
298         echo content >file &&
299         git add file &&
300         git commit -m "added sub and file" &&
301         mkdir -p deep/directory/hierarchy &&
302         git submodule add ./. deep/directory/hierarchy/sub &&
303         git commit -m "added another submodule" &&
304         git branch submodule
305 '
306
307 test_expect_success 'git mv cannot move a submodule in a file' '
308         test_must_fail git mv sub file
309 '
310
311 test_expect_success 'git mv moves a submodule with a .git directory and no .gitmodules' '
312         entry="$(git ls-files --stage sub | cut -f 1)" &&
313         git rm .gitmodules &&
314         (
315                 cd sub &&
316                 rm -f .git &&
317                 cp -R -P -p ../.git/modules/sub .git &&
318                 GIT_WORK_TREE=. git config --unset core.worktree
319         ) &&
320         mkdir mod &&
321         git mv sub mod/sub &&
322         ! test -e sub &&
323         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
324         (
325                 cd mod/sub &&
326                 git status
327         ) &&
328         git update-index --refresh &&
329         git diff-files --quiet
330 '
331
332 test_expect_success 'git mv moves a submodule with a .git directory and .gitmodules' '
333         rm -rf mod &&
334         git reset --hard &&
335         git submodule update &&
336         entry="$(git ls-files --stage sub | cut -f 1)" &&
337         (
338                 cd sub &&
339                 rm -f .git &&
340                 cp -R -P -p ../.git/modules/sub .git &&
341                 GIT_WORK_TREE=. git config --unset core.worktree
342         ) &&
343         mkdir mod &&
344         git mv sub mod/sub &&
345         ! test -e sub &&
346         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
347         (
348                 cd mod/sub &&
349                 git status
350         ) &&
351         echo mod/sub >expected &&
352         git config -f .gitmodules submodule.sub.path >actual &&
353         test_cmp expected actual &&
354         git update-index --refresh &&
355         git diff-files --quiet
356 '
357
358 test_expect_success 'git mv moves a submodule with gitfile' '
359         rm -rf mod &&
360         git reset --hard &&
361         git submodule update &&
362         entry="$(git ls-files --stage sub | cut -f 1)" &&
363         mkdir mod &&
364         (
365                 cd mod &&
366                 git mv ../sub/ .
367         ) &&
368         ! test -e sub &&
369         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
370         (
371                 cd mod/sub &&
372                 git status
373         ) &&
374         echo mod/sub >expected &&
375         git config -f .gitmodules submodule.sub.path >actual &&
376         test_cmp expected actual &&
377         git update-index --refresh &&
378         git diff-files --quiet
379 '
380
381 test_expect_success 'mv does not complain when no .gitmodules file is found' '
382         rm -rf mod &&
383         git reset --hard &&
384         git submodule update &&
385         git rm .gitmodules &&
386         entry="$(git ls-files --stage sub | cut -f 1)" &&
387         mkdir mod &&
388         git mv sub mod/sub 2>actual.err &&
389         ! test -s actual.err &&
390         ! test -e sub &&
391         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
392         (
393                 cd mod/sub &&
394                 git status
395         ) &&
396         git update-index --refresh &&
397         git diff-files --quiet
398 '
399
400 test_expect_success 'mv will error out on a modified .gitmodules file unless staged' '
401         rm -rf mod &&
402         git reset --hard &&
403         git submodule update &&
404         git config -f .gitmodules foo.bar true &&
405         entry="$(git ls-files --stage sub | cut -f 1)" &&
406         mkdir mod &&
407         test_must_fail git mv sub mod/sub 2>actual.err &&
408         test -s actual.err &&
409         test -e sub &&
410         git diff-files --quiet -- sub &&
411         git add .gitmodules &&
412         git mv sub mod/sub 2>actual.err &&
413         ! test -s actual.err &&
414         ! test -e sub &&
415         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
416         (
417                 cd mod/sub &&
418                 git status
419         ) &&
420         git update-index --refresh &&
421         git diff-files --quiet
422 '
423
424 test_expect_success 'mv issues a warning when section is not found in .gitmodules' '
425         rm -rf mod &&
426         git reset --hard &&
427         git submodule update &&
428         git config -f .gitmodules --remove-section submodule.sub &&
429         git add .gitmodules &&
430         entry="$(git ls-files --stage sub | cut -f 1)" &&
431         echo "warning: Could not find section in .gitmodules where path=sub" >expect.err &&
432         mkdir mod &&
433         git mv sub mod/sub 2>actual.err &&
434         test_i18ncmp expect.err actual.err &&
435         ! test -e sub &&
436         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
437         (
438                 cd mod/sub &&
439                 git status
440         ) &&
441         git update-index --refresh &&
442         git diff-files --quiet
443 '
444
445 test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' '
446         rm -rf mod &&
447         git reset --hard &&
448         git submodule update &&
449         mkdir mod &&
450         git mv -n sub mod/sub 2>actual.err &&
451         test -f sub/.git &&
452         git diff-index --exit-code HEAD &&
453         git update-index --refresh &&
454         git diff-files --quiet -- sub .gitmodules
455 '
456
457 test_expect_success 'checking out a commit before submodule moved needs manual updates' '
458         git mv sub sub2 &&
459         git commit -m "moved sub to sub2" &&
460         git checkout -q HEAD^ 2>actual &&
461         test_i18ngrep "^warning: unable to rmdir '\''sub2'\'':" actual &&
462         git status -s sub2 >actual &&
463         echo "?? sub2/" >expected &&
464         test_cmp expected actual &&
465         ! test -f sub/.git &&
466         test -f sub2/.git &&
467         git submodule update &&
468         test -f sub/.git &&
469         rm -rf sub2 &&
470         git diff-index --exit-code HEAD &&
471         git update-index --refresh &&
472         git diff-files --quiet -- sub .gitmodules &&
473         git status -s sub2 >actual &&
474         ! test -s actual
475 '
476
477 test_expect_success 'mv -k does not accidentally destroy submodules' '
478         git checkout submodule &&
479         mkdir dummy dest &&
480         git mv -k dummy sub dest &&
481         git status --porcelain >actual &&
482         grep "^R  sub -> dest/sub" actual &&
483         git reset --hard &&
484         git checkout .
485 '
486
487 test_expect_success 'moving a submodule in nested directories' '
488         (
489                 cd deep &&
490                 git mv directory ../ &&
491                 # git status would fail if the update of linking git dir to
492                 # work dir of the submodule failed.
493                 git status &&
494                 git config -f ../.gitmodules submodule.deep/directory/hierarchy/sub.path >../actual &&
495                 echo "directory/hierarchy/sub" >../expect
496         ) &&
497         test_cmp expect actual
498 '
499
500 test_expect_failure 'moving nested submodules' '
501         git commit -am "cleanup commit" &&
502         mkdir sub_nested_nested &&
503         (cd sub_nested_nested &&
504                 touch nested_level2 &&
505                 git init &&
506                 git add . &&
507                 git commit -m "nested level 2"
508         ) &&
509         mkdir sub_nested &&
510         (cd sub_nested &&
511                 touch nested_level1 &&
512                 git init &&
513                 git add . &&
514                 git commit -m "nested level 1"
515                 git submodule add ../sub_nested_nested &&
516                 git commit -m "add nested level 2"
517         ) &&
518         git submodule add ./sub_nested nested_move &&
519         git commit -m "add nested_move" &&
520         git submodule update --init --recursive &&
521         git mv nested_move sub_nested_moved &&
522         git status
523 '
524
525 test_done