commit-graph: when incompatible with graphs, indicate why
[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 >actual &&
25     grep "^R100..*path0/COPYING..*path1/COPYING" actual'
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 >actual &&
39     grep "^R100..*path1/COPYING..*path0/COPYING" actual'
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 >actual &&
126      grep "^R100..*path0/COPYING..*path2/COPYING" actual &&
127      grep "^R100..*path0/README..*path2/README" actual'
128
129 test_expect_success \
130     'succeed when source is a prefix of destination' \
131     'git mv path2/COPYING path2/COPYING-renamed'
132
133 test_expect_success \
134     'moving whole subdirectory into subdirectory' \
135     'git mv path2 path1'
136
137 test_expect_success \
138     'commiting the change' \
139     'git commit -m dir-move -a'
140
141 test_expect_success \
142     'checking the commit' \
143     'git diff-tree -r -M --name-status  HEAD^ HEAD >actual &&
144      grep "^R100..*path2/COPYING..*path1/path2/COPYING" actual &&
145      grep "^R100..*path2/README..*path1/path2/README" actual'
146
147 test_expect_success \
148     'do not move directory over existing directory' \
149     'mkdir path0 && mkdir path0/path2 && test_must_fail git mv path2 path0'
150
151 test_expect_success \
152     'move into "."' \
153     'git mv path1/path2/ .'
154
155 test_expect_success "Michael Cassar's test case" '
156         rm -fr .git papers partA &&
157         git init &&
158         mkdir -p papers/unsorted papers/all-papers partA &&
159         echo a > papers/unsorted/Thesis.pdf &&
160         echo b > partA/outline.txt &&
161         echo c > papers/unsorted/_another &&
162         git add papers partA &&
163         T1=$(git write-tree) &&
164
165         git mv papers/unsorted/Thesis.pdf papers/all-papers/moo-blah.pdf &&
166
167         T=$(git write-tree) &&
168         git ls-tree -r $T | verbose grep partA/outline.txt
169 '
170
171 rm -fr papers partA path?
172
173 test_expect_success "Sergey Vlasov's test case" '
174         rm -fr .git &&
175         git init &&
176         mkdir ab &&
177         date >ab.c &&
178         date >ab/d &&
179         git add ab.c ab &&
180         git commit -m "initial" &&
181         git mv ab a
182 '
183
184 test_expect_success 'absolute pathname' '(
185
186         rm -fr mine &&
187         mkdir mine &&
188         cd mine &&
189         test_create_repo one &&
190         cd one &&
191         mkdir sub &&
192         >sub/file &&
193         git add sub/file &&
194
195         git mv sub "$(pwd)/in" &&
196         ! test -d sub &&
197         test -d in &&
198         git ls-files --error-unmatch in/file
199
200
201 )'
202
203 test_expect_success 'absolute pathname outside should fail' '(
204
205         rm -fr mine &&
206         mkdir mine &&
207         cd mine &&
208         out=$(pwd) &&
209         test_create_repo one &&
210         cd one &&
211         mkdir sub &&
212         >sub/file &&
213         git add sub/file &&
214
215         test_must_fail git mv sub "$out/out" &&
216         test -d sub &&
217         ! test -d ../in &&
218         git ls-files --error-unmatch sub/file
219
220 )'
221
222 test_expect_success 'git mv to move multiple sources into a directory' '
223         rm -fr .git && git init &&
224         mkdir dir other &&
225         >dir/a.txt &&
226         >dir/b.txt &&
227         git add dir/?.txt &&
228         git mv dir/a.txt dir/b.txt other &&
229         git ls-files >actual &&
230         { echo other/a.txt; echo other/b.txt; } >expect &&
231         test_cmp expect actual
232 '
233
234 test_expect_success 'git mv should not change sha1 of moved cache entry' '
235
236         rm -fr .git &&
237         git init &&
238         echo 1 >dirty &&
239         git add dirty &&
240         entry="$(git ls-files --stage dirty | cut -f 1)" &&
241         git mv dirty dirty2 &&
242         [ "$entry" = "$(git ls-files --stage dirty2 | cut -f 1)" ] &&
243         echo 2 >dirty2 &&
244         git mv dirty2 dirty &&
245         [ "$entry" = "$(git ls-files --stage dirty | cut -f 1)" ]
246
247 '
248
249 rm -f dirty dirty2
250
251 # NB: This test is about the error message
252 # as well as the failure.
253 test_expect_success 'git mv error on conflicted file' '
254         rm -fr .git &&
255         git init &&
256         >conflict &&
257         test_when_finished "rm -f conflict" &&
258         cfhash=$(git hash-object -w conflict) &&
259         q_to_tab <<-EOF | git update-index --index-info &&
260         0 $cfhash 0Qconflict
261         100644 $cfhash 1Qconflict
262         EOF
263
264         test_must_fail git mv conflict newname 2>actual &&
265         test_i18ngrep "conflicted" actual
266 '
267
268 test_expect_success 'git mv should overwrite symlink to a file' '
269
270         rm -fr .git &&
271         git init &&
272         echo 1 >moved &&
273         test_ln_s_add moved symlink &&
274         git add moved &&
275         test_must_fail git mv moved symlink &&
276         git mv -f moved symlink &&
277         ! test -e moved &&
278         test -f symlink &&
279         test "$(cat symlink)" = 1 &&
280         git update-index --refresh &&
281         git diff-files --quiet
282
283 '
284
285 rm -f moved symlink
286
287 test_expect_success 'git mv should overwrite file with a symlink' '
288
289         rm -fr .git &&
290         git init &&
291         echo 1 >moved &&
292         test_ln_s_add moved symlink &&
293         git add moved &&
294         test_must_fail git mv symlink moved &&
295         git mv -f symlink moved &&
296         ! test -e symlink &&
297         git update-index --refresh &&
298         git diff-files --quiet
299
300 '
301
302 test_expect_success SYMLINKS 'check moved symlink' '
303
304         test -h moved
305 '
306
307 rm -f moved symlink
308
309 test_expect_success 'setup submodule' '
310         git commit -m initial &&
311         git reset --hard &&
312         git submodule add ./. sub &&
313         echo content >file &&
314         git add file &&
315         git commit -m "added sub and file" &&
316         mkdir -p deep/directory/hierarchy &&
317         git submodule add ./. deep/directory/hierarchy/sub &&
318         git commit -m "added another submodule" &&
319         git branch submodule
320 '
321
322 test_expect_success 'git mv cannot move a submodule in a file' '
323         test_must_fail git mv sub file
324 '
325
326 test_expect_success 'git mv moves a submodule with a .git directory and no .gitmodules' '
327         entry="$(git ls-files --stage sub | cut -f 1)" &&
328         git rm .gitmodules &&
329         (
330                 cd sub &&
331                 rm -f .git &&
332                 cp -R -P -p ../.git/modules/sub .git &&
333                 GIT_WORK_TREE=. git config --unset core.worktree
334         ) &&
335         mkdir mod &&
336         git mv sub mod/sub &&
337         ! test -e sub &&
338         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
339         (
340                 cd mod/sub &&
341                 git status
342         ) &&
343         git update-index --refresh &&
344         git diff-files --quiet
345 '
346
347 test_expect_success 'git mv moves a submodule with a .git directory and .gitmodules' '
348         rm -rf mod &&
349         git reset --hard &&
350         git submodule update &&
351         entry="$(git ls-files --stage sub | cut -f 1)" &&
352         (
353                 cd sub &&
354                 rm -f .git &&
355                 cp -R -P -p ../.git/modules/sub .git &&
356                 GIT_WORK_TREE=. git config --unset core.worktree
357         ) &&
358         mkdir mod &&
359         git mv sub mod/sub &&
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 'git mv moves a submodule with gitfile' '
374         rm -rf mod &&
375         git reset --hard &&
376         git submodule update &&
377         entry="$(git ls-files --stage sub | cut -f 1)" &&
378         mkdir mod &&
379         (
380                 cd mod &&
381                 git mv ../sub/ .
382         ) &&
383         ! test -e sub &&
384         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
385         (
386                 cd mod/sub &&
387                 git status
388         ) &&
389         echo mod/sub >expected &&
390         git config -f .gitmodules submodule.sub.path >actual &&
391         test_cmp expected actual &&
392         git update-index --refresh &&
393         git diff-files --quiet
394 '
395
396 test_expect_success 'mv does not complain when no .gitmodules file is found' '
397         rm -rf mod &&
398         git reset --hard &&
399         git submodule update &&
400         git rm .gitmodules &&
401         entry="$(git ls-files --stage sub | cut -f 1)" &&
402         mkdir mod &&
403         git mv sub mod/sub 2>actual.err &&
404         test_must_be_empty actual.err &&
405         ! test -e sub &&
406         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
407         (
408                 cd mod/sub &&
409                 git status
410         ) &&
411         git update-index --refresh &&
412         git diff-files --quiet
413 '
414
415 test_expect_success 'mv will error out on a modified .gitmodules file unless staged' '
416         rm -rf mod &&
417         git reset --hard &&
418         git submodule update &&
419         git config -f .gitmodules foo.bar true &&
420         entry="$(git ls-files --stage sub | cut -f 1)" &&
421         mkdir mod &&
422         test_must_fail git mv sub mod/sub 2>actual.err &&
423         test -s actual.err &&
424         test -e sub &&
425         git diff-files --quiet -- sub &&
426         git add .gitmodules &&
427         git mv sub mod/sub 2>actual.err &&
428         test_must_be_empty actual.err &&
429         ! test -e sub &&
430         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
431         (
432                 cd mod/sub &&
433                 git status
434         ) &&
435         git update-index --refresh &&
436         git diff-files --quiet
437 '
438
439 test_expect_success 'mv issues a warning when section is not found in .gitmodules' '
440         rm -rf mod &&
441         git reset --hard &&
442         git submodule update &&
443         git config -f .gitmodules --remove-section submodule.sub &&
444         git add .gitmodules &&
445         entry="$(git ls-files --stage sub | cut -f 1)" &&
446         echo "warning: Could not find section in .gitmodules where path=sub" >expect.err &&
447         mkdir mod &&
448         git mv sub mod/sub 2>actual.err &&
449         test_i18ncmp expect.err actual.err &&
450         ! test -e sub &&
451         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
452         (
453                 cd mod/sub &&
454                 git status
455         ) &&
456         git update-index --refresh &&
457         git diff-files --quiet
458 '
459
460 test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' '
461         rm -rf mod &&
462         git reset --hard &&
463         git submodule update &&
464         mkdir mod &&
465         git mv -n sub mod/sub 2>actual.err &&
466         test -f sub/.git &&
467         git diff-index --exit-code HEAD &&
468         git update-index --refresh &&
469         git diff-files --quiet -- sub .gitmodules
470 '
471
472 test_expect_success 'checking out a commit before submodule moved needs manual updates' '
473         git mv sub sub2 &&
474         git commit -m "moved sub to sub2" &&
475         git checkout -q HEAD^ 2>actual &&
476         test_i18ngrep "^warning: unable to rmdir '\''sub2'\'':" actual &&
477         git status -s sub2 >actual &&
478         echo "?? sub2/" >expected &&
479         test_cmp expected actual &&
480         ! test -f sub/.git &&
481         test -f sub2/.git &&
482         git submodule update &&
483         test -f sub/.git &&
484         rm -rf sub2 &&
485         git diff-index --exit-code HEAD &&
486         git update-index --refresh &&
487         git diff-files --quiet -- sub .gitmodules &&
488         git status -s sub2 >actual &&
489         test_must_be_empty actual
490 '
491
492 test_expect_success 'mv -k does not accidentally destroy submodules' '
493         git checkout submodule &&
494         mkdir dummy dest &&
495         git mv -k dummy sub dest &&
496         git status --porcelain >actual &&
497         grep "^R  sub -> dest/sub" actual &&
498         git reset --hard &&
499         git checkout .
500 '
501
502 test_expect_success 'moving a submodule in nested directories' '
503         (
504                 cd deep &&
505                 git mv directory ../ &&
506                 # git status would fail if the update of linking git dir to
507                 # work dir of the submodule failed.
508                 git status &&
509                 git config -f ../.gitmodules submodule.deep/directory/hierarchy/sub.path >../actual &&
510                 echo "directory/hierarchy/sub" >../expect
511         ) &&
512         test_cmp expect actual
513 '
514
515 test_expect_success 'moving nested submodules' '
516         git commit -am "cleanup commit" &&
517         mkdir sub_nested_nested &&
518         (cd sub_nested_nested &&
519                 touch nested_level2 &&
520                 git init &&
521                 git add . &&
522                 git commit -m "nested level 2"
523         ) &&
524         mkdir sub_nested &&
525         (cd sub_nested &&
526                 touch nested_level1 &&
527                 git init &&
528                 git add . &&
529                 git commit -m "nested level 1" &&
530                 git submodule add ../sub_nested_nested &&
531                 git commit -m "add nested level 2"
532         ) &&
533         git submodule add ./sub_nested nested_move &&
534         git commit -m "add nested_move" &&
535         git submodule update --init --recursive &&
536         git mv nested_move sub_nested_moved &&
537         git status
538 '
539
540 test_done