config: unify code paths to get global config paths
[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 'prepare reference tree' '
7         mkdir path0 path1 &&
8         cp "$TEST_DIRECTORY"/../COPYING path0/COPYING &&
9         git add path0/COPYING &&
10         git commit -m add -a
11 '
12
13 test_expect_success 'moving the file out of subdirectory' '
14         git -C path0 mv COPYING ../path1/COPYING
15 '
16
17 # in path0 currently
18 test_expect_success 'commiting the change' '
19         git commit -m move-out -a
20 '
21
22 test_expect_success 'checking the commit' '
23         git diff-tree -r -M --name-status  HEAD^ HEAD >actual &&
24         grep "^R100..*path0/COPYING..*path1/COPYING" actual
25 '
26
27 test_expect_success 'moving the file back into subdirectory' '
28         git -C path0 mv ../path1/COPYING COPYING
29 '
30
31 # in path0 currently
32 test_expect_success 'commiting the change' '
33         git commit -m move-in -a
34 '
35
36 test_expect_success 'checking the commit' '
37         git diff-tree -r -M --name-status  HEAD^ HEAD >actual &&
38         grep "^R100..*path1/COPYING..*path0/COPYING" actual
39 '
40
41 test_expect_success 'mv --dry-run does not move file' '
42         git mv -n path0/COPYING MOVED &&
43         test -f path0/COPYING &&
44         test ! -f MOVED
45 '
46
47 test_expect_success 'checking -k on non-existing file' '
48         git mv -k idontexist path0
49 '
50
51 test_expect_success 'checking -k on untracked file' '
52         >untracked1 &&
53         git mv -k untracked1 path0 &&
54         test -f untracked1 &&
55         test ! -f path0/untracked1
56 '
57
58 test_expect_success 'checking -k on multiple untracked files' '
59         >untracked2 &&
60         git mv -k untracked1 untracked2 path0 &&
61         test -f untracked1 &&
62         test -f untracked2 &&
63         test ! -f path0/untracked1 &&
64         test ! -f path0/untracked2
65 '
66
67 test_expect_success 'checking -f on untracked file with existing target' '
68         >path0/untracked1 &&
69         test_must_fail git mv -f untracked1 path0 &&
70         test ! -f .git/index.lock &&
71         test -f untracked1 &&
72         test -f path0/untracked1
73 '
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 'moving to absent target with trailing slash' '
82         test_must_fail git mv path0/COPYING no-such-dir/ &&
83         test_must_fail git mv path0/COPYING no-such-dir// &&
84         git mv path0/ no-such-dir/ &&
85         test_path_is_dir no-such-dir
86 '
87
88 test_expect_success 'clean up' '
89         git reset --hard
90 '
91
92 test_expect_success 'moving to existing untracked target with trailing slash' '
93         mkdir path1 &&
94         git mv path0/ path1/ &&
95         test_path_is_dir path1/path0/
96 '
97
98 test_expect_success 'moving to existing tracked target with trailing slash' '
99         mkdir path2 &&
100         >path2/file && git add path2/file &&
101         git mv path1/path0/ path2/ &&
102         test_path_is_dir path2/path0/
103 '
104
105 test_expect_success 'clean up' '
106         git reset --hard
107 '
108
109 test_expect_success 'adding another file' '
110         cp "$TEST_DIRECTORY"/../README.md path0/README &&
111         git add path0/README &&
112         git commit -m add2 -a
113 '
114
115 test_expect_success 'moving whole subdirectory' '
116         git mv path0 path2
117 '
118
119 test_expect_success 'commiting the change' '
120         git commit -m dir-move -a
121 '
122
123 test_expect_success 'checking the commit' '
124         git diff-tree -r -M --name-status  HEAD^ HEAD >actual &&
125         grep "^R100..*path0/COPYING..*path2/COPYING" actual &&
126         grep "^R100..*path0/README..*path2/README" actual
127 '
128
129 test_expect_success 'succeed when source is a prefix of destination' '
130         git mv path2/COPYING path2/COPYING-renamed
131 '
132
133 test_expect_success 'moving whole subdirectory into subdirectory' '
134         git mv path2 path1
135 '
136
137 test_expect_success 'commiting the change' '
138         git commit -m dir-move -a
139 '
140
141 test_expect_success 'checking the commit' '
142         git diff-tree -r -M --name-status  HEAD^ HEAD >actual &&
143         grep "^R100..*path2/COPYING..*path1/path2/COPYING" actual &&
144         grep "^R100..*path2/README..*path1/path2/README" actual
145 '
146
147 test_expect_success 'do not move directory over existing directory' '
148         mkdir path0 &&
149         mkdir path0/path2 &&
150         test_must_fail git mv path2 path0
151 '
152
153 test_expect_success 'move into "."' '
154         git mv path1/path2/ .
155 '
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 test_expect_success 'absolute pathname outside should fail' '
205         (
206                 rm -fr mine &&
207                 mkdir mine &&
208                 cd mine &&
209                 out=$(pwd) &&
210                 test_create_repo one &&
211                 cd one &&
212                 mkdir sub &&
213                 >sub/file &&
214                 git add sub/file &&
215
216                 test_must_fail git mv sub "$out/out" &&
217                 test -d sub &&
218                 ! test -d ../in &&
219                 git ls-files --error-unmatch sub/file
220         )
221 '
222
223 test_expect_success 'git mv to move multiple sources into a directory' '
224         rm -fr .git && git init &&
225         mkdir dir other &&
226         >dir/a.txt &&
227         >dir/b.txt &&
228         git add dir/?.txt &&
229         git mv dir/a.txt dir/b.txt other &&
230         git ls-files >actual &&
231         cat >expect <<-\EOF &&
232         other/a.txt
233         other/b.txt
234         EOF
235         test_cmp expect actual
236 '
237
238 test_expect_success 'git mv should not change sha1 of moved cache entry' '
239         rm -fr .git &&
240         git init &&
241         echo 1 >dirty &&
242         git add dirty &&
243         entry="$(git ls-files --stage dirty | cut -f 1)" &&
244         git mv dirty dirty2 &&
245         test "$entry" = "$(git ls-files --stage dirty2 | cut -f 1)" &&
246         echo 2 >dirty2 &&
247         git mv dirty2 dirty &&
248         test "$entry" = "$(git ls-files --stage dirty | cut -f 1)"
249 '
250
251 rm -f dirty dirty2
252
253 # NB: This test is about the error message
254 # as well as the failure.
255 test_expect_success 'git mv error on conflicted file' '
256         rm -fr .git &&
257         git init &&
258         >conflict &&
259         test_when_finished "rm -f conflict" &&
260         cfhash=$(git hash-object -w conflict) &&
261         q_to_tab <<-EOF | git update-index --index-info &&
262         0 $cfhash 0Qconflict
263         100644 $cfhash 1Qconflict
264         EOF
265
266         test_must_fail git mv conflict newname 2>actual &&
267         test_i18ngrep "conflicted" actual
268 '
269
270 test_expect_success 'git mv should overwrite symlink to a file' '
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 moved symlink &&
277         git mv -f moved symlink &&
278         ! test -e moved &&
279         test -f symlink &&
280         test "$(cat symlink)" = 1 &&
281         git update-index --refresh &&
282         git diff-files --quiet
283 '
284
285 rm -f moved symlink
286
287 test_expect_success 'git mv should overwrite file with a symlink' '
288         rm -fr .git &&
289         git init &&
290         echo 1 >moved &&
291         test_ln_s_add moved symlink &&
292         git add moved &&
293         test_must_fail git mv symlink moved &&
294         git mv -f symlink moved &&
295         ! test -e symlink &&
296         git update-index --refresh &&
297         git diff-files --quiet
298 '
299
300 test_expect_success SYMLINKS 'check moved symlink' '
301         test -h moved
302 '
303
304 rm -f moved symlink
305
306 test_expect_success 'setup submodule' '
307         git commit -m initial &&
308         git reset --hard &&
309         git submodule add ./. sub &&
310         echo content >file &&
311         git add file &&
312         git commit -m "added sub and file" &&
313         mkdir -p deep/directory/hierarchy &&
314         git submodule add ./. deep/directory/hierarchy/sub &&
315         git commit -m "added another submodule" &&
316         git branch submodule
317 '
318
319 test_expect_success 'git mv cannot move a submodule in a file' '
320         test_must_fail git mv sub file
321 '
322
323 test_expect_success 'git mv moves a submodule with a .git directory and no .gitmodules' '
324         entry="$(git ls-files --stage sub | cut -f 1)" &&
325         git rm .gitmodules &&
326         (
327                 cd sub &&
328                 rm -f .git &&
329                 cp -R -P -p ../.git/modules/sub .git &&
330                 GIT_WORK_TREE=. git config --unset core.worktree
331         ) &&
332         mkdir mod &&
333         git mv sub mod/sub &&
334         ! test -e sub &&
335         test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
336         git -C mod/sub status &&
337         git update-index --refresh &&
338         git diff-files --quiet
339 '
340
341 test_expect_success 'git mv moves a submodule with a .git directory and .gitmodules' '
342         rm -rf mod &&
343         git reset --hard &&
344         git submodule update &&
345         entry="$(git ls-files --stage sub | cut -f 1)" &&
346         (
347                 cd sub &&
348                 rm -f .git &&
349                 cp -R -P -p ../.git/modules/sub .git &&
350                 GIT_WORK_TREE=. git config --unset core.worktree
351         ) &&
352         mkdir mod &&
353         git mv sub mod/sub &&
354         ! test -e sub &&
355         test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
356         git -C mod/sub status &&
357         echo mod/sub >expected &&
358         git config -f .gitmodules submodule.sub.path >actual &&
359         test_cmp expected actual &&
360         git update-index --refresh &&
361         git diff-files --quiet
362 '
363
364 test_expect_success 'git mv moves a submodule with gitfile' '
365         rm -rf mod &&
366         git reset --hard &&
367         git submodule update &&
368         entry="$(git ls-files --stage sub | cut -f 1)" &&
369         mkdir mod &&
370         git -C mod mv ../sub/ . &&
371         ! test -e sub &&
372         test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
373         git -C mod/sub status &&
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_must_be_empty actual.err &&
390         ! test -e sub &&
391         test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
392         git -C mod/sub status &&
393         git update-index --refresh &&
394         git diff-files --quiet
395 '
396
397 test_expect_success 'mv will error out on a modified .gitmodules file unless staged' '
398         rm -rf mod &&
399         git reset --hard &&
400         git submodule update &&
401         git config -f .gitmodules foo.bar true &&
402         entry="$(git ls-files --stage sub | cut -f 1)" &&
403         mkdir mod &&
404         test_must_fail git mv sub mod/sub 2>actual.err &&
405         test -s actual.err &&
406         test -e sub &&
407         git diff-files --quiet -- sub &&
408         git add .gitmodules &&
409         git mv sub mod/sub 2>actual.err &&
410         test_must_be_empty actual.err &&
411         ! test -e sub &&
412         test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
413         git -C mod/sub status &&
414         git update-index --refresh &&
415         git diff-files --quiet
416 '
417
418 test_expect_success 'mv issues a warning when section is not found in .gitmodules' '
419         rm -rf mod &&
420         git reset --hard &&
421         git submodule update &&
422         git config -f .gitmodules --remove-section submodule.sub &&
423         git add .gitmodules &&
424         entry="$(git ls-files --stage sub | cut -f 1)" &&
425         echo "warning: Could not find section in .gitmodules where path=sub" >expect.err &&
426         mkdir mod &&
427         git mv sub mod/sub 2>actual.err &&
428         test_cmp expect.err actual.err &&
429         ! test -e sub &&
430         test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
431         git -C mod/sub status &&
432         git update-index --refresh &&
433         git diff-files --quiet
434 '
435
436 test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' '
437         rm -rf mod &&
438         git reset --hard &&
439         git submodule update &&
440         mkdir mod &&
441         git mv -n sub mod/sub 2>actual.err &&
442         test -f sub/.git &&
443         git diff-index --exit-code HEAD &&
444         git update-index --refresh &&
445         git diff-files --quiet -- sub .gitmodules
446 '
447
448 test_expect_success 'checking out a commit before submodule moved needs manual updates' '
449         git mv sub sub2 &&
450         git commit -m "moved sub to sub2" &&
451         git checkout -q HEAD^ 2>actual &&
452         test_i18ngrep "^warning: unable to rmdir '\''sub2'\'':" actual &&
453         git status -s sub2 >actual &&
454         echo "?? sub2/" >expected &&
455         test_cmp expected actual &&
456         ! test -f sub/.git &&
457         test -f sub2/.git &&
458         git submodule update &&
459         test -f sub/.git &&
460         rm -rf sub2 &&
461         git diff-index --exit-code HEAD &&
462         git update-index --refresh &&
463         git diff-files --quiet -- sub .gitmodules &&
464         git status -s sub2 >actual &&
465         test_must_be_empty actual
466 '
467
468 test_expect_success 'mv -k does not accidentally destroy submodules' '
469         git checkout submodule &&
470         mkdir dummy dest &&
471         git mv -k dummy sub dest &&
472         git status --porcelain >actual &&
473         grep "^R  sub -> dest/sub" actual &&
474         git reset --hard &&
475         git checkout .
476 '
477
478 test_expect_success 'moving a submodule in nested directories' '
479         (
480                 cd deep &&
481                 git mv directory ../ &&
482                 # git status would fail if the update of linking git dir to
483                 # work dir of the submodule failed.
484                 git status &&
485                 git config -f ../.gitmodules submodule.deep/directory/hierarchy/sub.path >../actual &&
486                 echo "directory/hierarchy/sub" >../expect
487         ) &&
488         test_cmp expect actual
489 '
490
491 test_expect_success 'moving nested submodules' '
492         git commit -am "cleanup commit" &&
493         mkdir sub_nested_nested &&
494         (
495                 cd sub_nested_nested &&
496                 >nested_level2 &&
497                 git init &&
498                 git add . &&
499                 git commit -m "nested level 2"
500         ) &&
501         mkdir sub_nested &&
502         (
503                 cd sub_nested &&
504                 >nested_level1 &&
505                 git init &&
506                 git add . &&
507                 git commit -m "nested level 1" &&
508                 git submodule add ../sub_nested_nested &&
509                 git commit -m "add nested level 2"
510         ) &&
511         git submodule add ./sub_nested nested_move &&
512         git commit -m "add nested_move" &&
513         git submodule update --init --recursive &&
514         git mv nested_move sub_nested_moved &&
515         git status
516 '
517
518 test_done