Raw
1 #!/bin/sh
2
3 test_description='git mv in subdirs'
4
5 . ./test-lib.sh
6 . "$TEST_DIRECTORY"/lib-diff-data.sh
7
8 index_at_path () {
9 git ls-files --format='%(objectmode) %(objectname) %(stage)' "$@"
10 }
11
12 test_expect_success 'mv -f refreshes updated index entry' '
13 echo test >bar &&
14 git add bar &&
15 git commit -m test &&
16
17 echo foo >foo &&
18 git add foo &&
19
20 # Wait one second to ensure ctime of rename will differ from original
21 # file creation ctime.
22 sleep 1 &&
23 git mv -f foo bar &&
24 git reset --merge HEAD &&
25
26 # Verify the index has been reset
27 git diff-files >out &&
28 test_must_be_empty out
29 '
30
31 test_expect_success 'prepare reference tree' '
32 mkdir path0 path1 &&
33 COPYING_test_data >path0/COPYING &&
34 git add path0/COPYING &&
35 git commit -m add -a
36 '
37
38 test_expect_success 'moving the file out of subdirectory' '
39 git -C path0 mv COPYING ../path1/COPYING
40 '
41
42 # in path0 currently
43 test_expect_success 'commiting the change' '
44 git commit -m move-out -a
45 '
46
47 test_expect_success 'checking the commit' '
48 git diff-tree -r -M --name-status HEAD^ HEAD >actual &&
49 test_grep "^R100..*path0/COPYING..*path1/COPYING" actual
50 '
51
52 test_expect_success 'moving the file back into subdirectory' '
53 git -C path0 mv ../path1/COPYING COPYING
54 '
55
56 # in path0 currently
57 test_expect_success 'commiting the change' '
58 git commit -m move-in -a
59 '
60
61 test_expect_success 'checking the commit' '
62 git diff-tree -r -M --name-status HEAD^ HEAD >actual &&
63 test_grep "^R100..*path1/COPYING..*path0/COPYING" actual
64 '
65
66 test_expect_success 'mv --dry-run does not move file' '
67 git mv -n path0/COPYING MOVED &&
68 test_path_is_file path0/COPYING &&
69 test_path_is_missing MOVED
70 '
71
72 test_expect_success 'checking -k on non-existing file' '
73 git mv -k idontexist path0
74 '
75
76 test_expect_success 'checking -k on untracked file' '
77 >untracked1 &&
78 git mv -k untracked1 path0 &&
79 test_path_is_file untracked1 &&
80 test_path_is_missing path0/untracked1
81 '
82
83 test_expect_success 'checking -k on multiple untracked files' '
84 >untracked2 &&
85 git mv -k untracked1 untracked2 path0 &&
86 test_path_is_file untracked1 &&
87 test_path_is_file untracked2 &&
88 test_path_is_missing path0/untracked1 &&
89 test_path_is_missing path0/untracked2
90 '
91
92 test_expect_success 'checking -f on untracked file with existing target' '
93 >path0/untracked1 &&
94 test_must_fail git mv -f untracked1 path0 &&
95 test_path_is_missing .git/index.lock &&
96 test_path_is_file untracked1 &&
97 test_path_is_file path0/untracked1
98 '
99
100 # clean up the mess in case bad things happen
101 rm -f idontexist untracked1 untracked2 \
102 path0/idontexist path0/untracked1 path0/untracked2 \
103 .git/index.lock
104 rmdir path1
105
106 test_expect_success 'moving to absent target with trailing slash' '
107 test_must_fail git mv path0/COPYING no-such-dir/ &&
108 test_must_fail git mv path0/COPYING no-such-dir// &&
109 git mv path0/ no-such-dir/ &&
110 test_path_is_dir no-such-dir
111 '
112
113 test_expect_success 'clean up' '
114 git reset --hard
115 '
116
117 test_expect_success 'moving to non-existent destination parent directory' '
118 git reset --hard &&
119 mkdir -p from &&
120 echo content >from/file &&
121 git add from/file &&
122 test_must_fail git mv from/file no-such-dir/file 2>actual &&
123 test_grep "destination directory does not exist" actual
124 '
125
126 test_expect_success 'mv --dry-run detects non-existent destination parent directory' '
127 test_must_fail git mv -n from/file no-such-dir/file 2>actual &&
128 test_grep "destination directory does not exist" actual
129 '
130
131 test_expect_success 'moving to existing untracked target with trailing slash' '
132 mkdir path1 &&
133 git mv path0/ path1/ &&
134 test_path_is_dir path1/path0/
135 '
136
137 test_expect_success 'moving to existing tracked target with trailing slash' '
138 mkdir path2 &&
139 >path2/file && git add path2/file &&
140 git mv path1/path0/ path2/ &&
141 test_path_is_dir path2/path0/
142 '
143
144 test_expect_success 'clean up' '
145 git reset --hard
146 '
147
148 test_expect_success 'adding another file' '
149 COPYING_test_data | tr A-Za-z N-ZA-Mn-za-m >path0/README &&
150 git add path0/README &&
151 git commit -m add2 -a
152 '
153
154 test_expect_success 'moving whole subdirectory' '
155 git mv path0 path2
156 '
157
158 test_expect_success 'commiting the change' '
159 git commit -m dir-move -a
160 '
161
162 test_expect_success 'checking the commit' '
163 git diff-tree -r -M --name-status HEAD^ HEAD >actual &&
164 test_grep "^R100..*path0/COPYING..*path2/COPYING" actual &&
165 test_grep "^R100..*path0/README..*path2/README" actual
166 '
167
168 test_expect_success 'succeed when source is a prefix of destination' '
169 git mv path2/COPYING path2/COPYING-renamed
170 '
171
172 test_expect_success 'moving whole subdirectory into subdirectory' '
173 git mv path2 path1
174 '
175
176 test_expect_success 'commiting the change' '
177 git commit -m dir-move -a
178 '
179
180 test_expect_success 'checking the commit' '
181 git diff-tree -r -M --name-status HEAD^ HEAD >actual &&
182 test_grep "^R100..*path2/COPYING..*path1/path2/COPYING" actual &&
183 test_grep "^R100..*path2/README..*path1/path2/README" actual
184 '
185
186 test_expect_success 'do not move directory over existing directory' '
187 mkdir path0 &&
188 mkdir path0/path2 &&
189 test_must_fail git mv path2 path0
190 '
191
192 test_expect_success 'rename directory to non-existing directory' '
193 mkdir dir-a &&
194 >dir-a/f &&
195 git add dir-a &&
196 git mv dir-a non-existing-dir
197 '
198
199 test_expect_success 'move into "."' '
200 git mv path1/path2/ .
201 '
202
203 test_expect_success "Michael Cassar's test case" '
204 rm -fr .git papers partA &&
205 git init &&
206 mkdir -p papers/unsorted papers/all-papers partA &&
207 echo a >papers/unsorted/Thesis.pdf &&
208 echo b >partA/outline.txt &&
209 echo c >papers/unsorted/_another &&
210 git add papers partA &&
211 T1=$(git write-tree) &&
212
213 git mv papers/unsorted/Thesis.pdf papers/all-papers/moo-blah.pdf &&
214
215 T=$(git write-tree) &&
216 git ls-tree -r $T >out &&
217 test_grep partA/outline.txt out
218 '
219
220 rm -fr papers partA path?
221
222 test_expect_success "Sergey Vlasov's test case" '
223 rm -fr .git &&
224 git init &&
225 mkdir ab &&
226 date >ab.c &&
227 date >ab/d &&
228 git add ab.c ab &&
229 git commit -m "initial" &&
230 git mv ab a
231 '
232
233 test_expect_success 'absolute pathname' '
234 (
235 rm -fr mine &&
236 mkdir mine &&
237 cd mine &&
238 test_create_repo one &&
239 cd one &&
240 mkdir sub &&
241 >sub/file &&
242 git add sub/file &&
243
244 git mv sub "$(pwd)/in" &&
245 test_path_is_missing sub &&
246 test_path_is_dir in &&
247 git ls-files --error-unmatch in/file
248 )
249 '
250
251 test_expect_success 'absolute pathname outside should fail' '
252 (
253 rm -fr mine &&
254 mkdir mine &&
255 cd mine &&
256 out=$(pwd) &&
257 test_create_repo one &&
258 cd one &&
259 mkdir sub &&
260 >sub/file &&
261 git add sub/file &&
262
263 test_must_fail git mv sub "$out/out" &&
264 test_path_is_dir sub &&
265 test_path_is_missing ../in &&
266 git ls-files --error-unmatch sub/file
267 )
268 '
269
270 test_expect_success 'git mv to move multiple sources into a directory' '
271 rm -fr .git && git init &&
272 mkdir dir other &&
273 >dir/a.txt &&
274 >dir/b.txt &&
275 git add dir/?.txt &&
276 git mv dir/a.txt dir/b.txt other &&
277 git ls-files >actual &&
278 cat >expect <<-\EOF &&
279 other/a.txt
280 other/b.txt
281 EOF
282 test_cmp expect actual
283 '
284
285 test_expect_success 'git mv should not change sha1 of moved cache entry' '
286 rm -fr .git &&
287 git init &&
288 echo 1 >dirty &&
289 git add dirty &&
290 entry="$(index_at_path dirty)" &&
291 git mv dirty dirty2 &&
292 test "$entry" = "$(index_at_path dirty2)" &&
293 echo 2 >dirty2 &&
294 git mv dirty2 dirty &&
295 test "$entry" = "$(index_at_path dirty)"
296 '
297
298 rm -f dirty dirty2
299
300 # NB: This test is about the error message
301 # as well as the failure.
302 test_expect_success 'git mv error on conflicted file' '
303 rm -fr .git &&
304 git init &&
305 >conflict &&
306 test_when_finished "rm -f conflict" &&
307 cfhash=$(git hash-object -w conflict) &&
308 q_to_tab <<-EOF | git update-index --index-info &&
309 0 $cfhash 0Qconflict
310 100644 $cfhash 1Qconflict
311 EOF
312
313 test_must_fail git mv conflict newname 2>actual &&
314 test_grep "conflicted" actual
315 '
316
317 test_expect_success 'git mv should overwrite symlink to a file' '
318 rm -fr .git &&
319 git init &&
320 echo 1 >moved &&
321 test_ln_s_add moved symlink &&
322 git add moved &&
323 test_must_fail git mv moved symlink &&
324 git mv -f moved symlink &&
325 test_path_is_missing moved &&
326 test_path_is_file symlink &&
327 test "$(cat symlink)" = 1 &&
328 git update-index --refresh &&
329 git diff-files --quiet
330 '
331
332 rm -f moved symlink
333
334 test_expect_success 'git mv should overwrite file with a symlink' '
335 rm -fr .git &&
336 git init &&
337 echo 1 >moved &&
338 test_ln_s_add moved symlink &&
339 git add moved &&
340 test_must_fail git mv symlink moved &&
341 git mv -f symlink moved &&
342 test_path_is_missing symlink &&
343 git update-index --refresh &&
344 git diff-files --quiet
345 '
346
347 test_expect_success SYMLINKS 'check moved symlink' '
348 test_path_is_symlink moved
349 '
350
351 rm -f moved symlink
352
353 test_expect_success 'setup submodule' '
354 test_config_global protocol.file.allow always &&
355 git commit -m initial &&
356 git reset --hard &&
357 git submodule add ./. sub &&
358 echo content >file &&
359 git add file &&
360 git commit -m "added sub and file" &&
361 mkdir -p deep/directory/hierarchy &&
362 git submodule add ./. deep/directory/hierarchy/sub &&
363 git commit -m "added another submodule" &&
364 git branch submodule
365 '
366
367 test_expect_success 'git mv cannot move a submodule in a file' '
368 test_must_fail git mv sub file
369 '
370
371 test_expect_success 'git mv moves a submodule with a .git directory and no .gitmodules' '
372 entry="$(index_at_path sub)" &&
373 git rm .gitmodules &&
374 (
375 cd sub &&
376 rm -f .git &&
377 cp -R -P -p ../.git/modules/sub .git &&
378 GIT_WORK_TREE=. git config --unset core.worktree
379 ) &&
380 mkdir mod &&
381 git mv sub mod/sub &&
382 test_path_is_missing sub &&
383 test "$entry" = "$(index_at_path mod/sub)" &&
384 git -C mod/sub status &&
385 git update-index --refresh &&
386 git diff-files --quiet
387 '
388
389 test_expect_success 'git mv moves a submodule with a .git directory and .gitmodules' '
390 rm -rf mod &&
391 git reset --hard &&
392 git submodule update &&
393 entry="$(index_at_path sub)" &&
394 (
395 cd sub &&
396 rm -f .git &&
397 cp -R -P -p ../.git/modules/sub .git &&
398 GIT_WORK_TREE=. git config --unset core.worktree
399 ) &&
400 mkdir mod &&
401 git mv sub mod/sub &&
402 test_path_is_missing sub &&
403 test "$entry" = "$(index_at_path mod/sub)" &&
404 git -C mod/sub status &&
405 echo mod/sub >expected &&
406 git config -f .gitmodules submodule.sub.path >actual &&
407 test_cmp expected actual &&
408 git update-index --refresh &&
409 git diff-files --quiet
410 '
411
412 test_expect_success 'git mv moves a submodule with gitfile' '
413 rm -rf mod &&
414 git reset --hard &&
415 git submodule update &&
416 entry="$(index_at_path sub)" &&
417 mkdir mod &&
418 git -C mod mv ../sub/ . &&
419 test_path_is_missing sub &&
420 test "$entry" = "$(index_at_path mod/sub)" &&
421 git -C mod/sub status &&
422 echo mod/sub >expected &&
423 git config -f .gitmodules submodule.sub.path >actual &&
424 test_cmp expected actual &&
425 git update-index --refresh &&
426 git diff-files --quiet
427 '
428
429 test_expect_success 'mv does not complain when no .gitmodules file is found' '
430 rm -rf mod &&
431 git reset --hard &&
432 git submodule update &&
433 git rm .gitmodules &&
434 entry="$(index_at_path sub)" &&
435 mkdir mod &&
436 git mv sub mod/sub 2>actual.err &&
437 test_must_be_empty actual.err &&
438 test_path_is_missing sub &&
439 test "$entry" = "$(index_at_path mod/sub)" &&
440 git -C mod/sub status &&
441 git update-index --refresh &&
442 git diff-files --quiet
443 '
444
445 test_expect_success 'mv will error out on a modified .gitmodules file unless staged' '
446 rm -rf mod &&
447 git reset --hard &&
448 git submodule update &&
449 git config -f .gitmodules foo.bar true &&
450 entry="$(index_at_path sub)" &&
451 mkdir mod &&
452 test_must_fail git mv sub mod/sub 2>actual.err &&
453 test_file_not_empty actual.err &&
454 test_path_exists sub &&
455 git diff-files --quiet -- sub &&
456 git add .gitmodules &&
457 git mv sub mod/sub 2>actual.err &&
458 test_must_be_empty actual.err &&
459 test_path_is_missing sub &&
460 test "$entry" = "$(index_at_path mod/sub)" &&
461 git -C mod/sub status &&
462 git update-index --refresh &&
463 git diff-files --quiet
464 '
465
466 test_expect_success 'mv issues a warning when section is not found in .gitmodules' '
467 rm -rf mod &&
468 git reset --hard &&
469 git submodule update &&
470 git config -f .gitmodules --remove-section submodule.sub &&
471 git add .gitmodules &&
472 entry="$(index_at_path sub)" &&
473 echo "warning: Could not find section in .gitmodules where path=sub" >expect.err &&
474 mkdir mod &&
475 git mv sub mod/sub 2>actual.err &&
476 test_cmp expect.err actual.err &&
477 test_path_is_missing sub &&
478 test "$entry" = "$(index_at_path mod/sub)" &&
479 git -C mod/sub status &&
480 git update-index --refresh &&
481 git diff-files --quiet
482 '
483
484 test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' '
485 rm -rf mod &&
486 git reset --hard &&
487 git submodule update &&
488 mkdir mod &&
489 git mv -n sub mod/sub 2>actual.err &&
490 test_path_is_file sub/.git &&
491 git diff-index --exit-code HEAD &&
492 git update-index --refresh &&
493 git diff-files --quiet -- sub .gitmodules
494 '
495
496 test_expect_success 'checking out a commit before submodule moved needs manual updates' '
497 git mv sub sub2 &&
498 git commit -m "moved sub to sub2" &&
499 git checkout -q HEAD^ 2>actual &&
500 test_grep "^warning: unable to rmdir '\''sub2'\'':" actual &&
501 git status -s sub2 >actual &&
502 echo "?? sub2/" >expected &&
503 test_cmp expected actual &&
504 test_path_is_missing sub/.git &&
505 test_path_is_file sub2/.git &&
506 git submodule update &&
507 test_path_is_file sub/.git &&
508 rm -rf sub2 &&
509 git diff-index --exit-code HEAD &&
510 git update-index --refresh &&
511 git diff-files --quiet -- sub .gitmodules &&
512 git status -s sub2 >actual &&
513 test_must_be_empty actual
514 '
515
516 test_expect_success 'mv -k does not accidentally destroy submodules' '
517 git checkout submodule &&
518 mkdir dummy dest &&
519 git mv -k dummy sub dest &&
520 git status --porcelain >actual &&
521 test_grep "^R sub -> dest/sub" actual &&
522 git reset --hard &&
523 git checkout .
524 '
525
526 test_expect_success 'moving a submodule in nested directories' '
527 (
528 cd deep &&
529 git mv directory ../ &&
530 # git status would fail if the update of linking git dir to
531 # work dir of the submodule failed.
532 git status &&
533 git config -f ../.gitmodules submodule.deep/directory/hierarchy/sub.path >../actual &&
534 echo "directory/hierarchy/sub" >../expect
535 ) &&
536 test_cmp expect actual
537 '
538
539 test_expect_success 'moving nested submodules' '
540 test_config_global protocol.file.allow always &&
541 git commit -am "cleanup commit" &&
542 mkdir sub_nested_nested &&
543 (
544 cd sub_nested_nested &&
545 >nested_level2 &&
546 git init &&
547 git add . &&
548 git commit -m "nested level 2"
549 ) &&
550 mkdir sub_nested &&
551 (
552 cd sub_nested &&
553 >nested_level1 &&
554 git init &&
555 git add . &&
556 git commit -m "nested level 1" &&
557 git submodule add ../sub_nested_nested &&
558 git commit -m "add nested level 2"
559 ) &&
560 git submodule add ./sub_nested nested_move &&
561 git commit -m "add nested_move" &&
562 git submodule update --init --recursive &&
563 git mv nested_move sub_nested_moved &&
564 git status
565 '
566
567 test_expect_success 'moving file and its parent directory at the same time fails' '
568 test_when_finished git reset --hard HEAD &&
569 git reset --hard HEAD &&
570 mkdir -p a &&
571 mkdir -p b &&
572 >a/a.txt &&
573 git add a/a.txt &&
574 cat >expect <<-EOF &&
575 fatal: cannot move both ${SQ}a/a.txt${SQ} and its parent directory ${SQ}a${SQ}
576 EOF
577 test_must_fail git mv a/a.txt a b 2>err &&
578 test_cmp expect err
579 '
580
581 test_expect_success 'moving nested directory and its parent directory at the same time fails' '
582 test_when_finished git reset --hard HEAD &&
583 git reset --hard HEAD &&
584 mkdir -p a/b/c &&
585 >a/b/c/file.txt &&
586 git add a &&
587 mkdir target &&
588 cat >expect <<-EOF &&
589 fatal: cannot move both ${SQ}a/b/c${SQ} and its parent directory ${SQ}a${SQ}
590 EOF
591 test_must_fail git mv a/b/c a target 2>err &&
592 test_cmp expect err
593 '
594
595 test_done