Merge branch 'sb/wt-status-cleanup'
[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.md 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 | verbose grep partA/outline.txt
165 '
166
167 rm -fr papers partA path?
168
169 test_expect_success "Sergey Vlasov's test case" '
170         rm -fr .git &&
171         git init &&
172         mkdir ab &&
173         date >ab.c &&
174         date >ab/d &&
175         git add ab.c ab &&
176         git commit -m 'initial' &&
177         git mv ab a
178 '
179
180 test_expect_success 'absolute pathname' '(
181
182         rm -fr mine &&
183         mkdir mine &&
184         cd mine &&
185         test_create_repo one &&
186         cd one &&
187         mkdir sub &&
188         >sub/file &&
189         git add sub/file &&
190
191         git mv sub "$(pwd)/in" &&
192         ! test -d sub &&
193         test -d in &&
194         git ls-files --error-unmatch in/file
195
196
197 )'
198
199 test_expect_success 'absolute pathname outside should fail' '(
200
201         rm -fr mine &&
202         mkdir mine &&
203         cd mine &&
204         out=$(pwd) &&
205         test_create_repo one &&
206         cd one &&
207         mkdir sub &&
208         >sub/file &&
209         git add sub/file &&
210
211         test_must_fail git mv sub "$out/out" &&
212         test -d sub &&
213         ! test -d ../in &&
214         git ls-files --error-unmatch sub/file
215
216 )'
217
218 test_expect_success 'git mv to move multiple sources into a directory' '
219         rm -fr .git && git init &&
220         mkdir dir other &&
221         >dir/a.txt &&
222         >dir/b.txt &&
223         git add dir/?.txt &&
224         git mv dir/a.txt dir/b.txt other &&
225         git ls-files >actual &&
226         { echo other/a.txt; echo other/b.txt; } >expect &&
227         test_cmp expect actual
228 '
229
230 test_expect_success 'git mv should not change sha1 of moved cache entry' '
231
232         rm -fr .git &&
233         git init &&
234         echo 1 >dirty &&
235         git add dirty &&
236         entry="$(git ls-files --stage dirty | cut -f 1)" &&
237         git mv dirty dirty2 &&
238         [ "$entry" = "$(git ls-files --stage dirty2 | cut -f 1)" ] &&
239         echo 2 >dirty2 &&
240         git mv dirty2 dirty &&
241         [ "$entry" = "$(git ls-files --stage dirty | cut -f 1)" ]
242
243 '
244
245 rm -f dirty dirty2
246
247 test_expect_success 'git mv should overwrite symlink to a file' '
248
249         rm -fr .git &&
250         git init &&
251         echo 1 >moved &&
252         test_ln_s_add moved symlink &&
253         git add moved &&
254         test_must_fail git mv moved symlink &&
255         git mv -f moved symlink &&
256         ! test -e moved &&
257         test -f symlink &&
258         test "$(cat symlink)" = 1 &&
259         git update-index --refresh &&
260         git diff-files --quiet
261
262 '
263
264 rm -f moved symlink
265
266 test_expect_success 'git mv should overwrite file with a symlink' '
267
268         rm -fr .git &&
269         git init &&
270         echo 1 >moved &&
271         test_ln_s_add moved symlink &&
272         git add moved &&
273         test_must_fail git mv symlink moved &&
274         git mv -f symlink moved &&
275         ! test -e symlink &&
276         git update-index --refresh &&
277         git diff-files --quiet
278
279 '
280
281 test_expect_success SYMLINKS 'check moved symlink' '
282
283         test -h moved
284 '
285
286 rm -f moved symlink
287
288 test_expect_success 'setup submodule' '
289         git commit -m initial &&
290         git reset --hard &&
291         git submodule add ./. sub &&
292         echo content >file &&
293         git add file &&
294         git commit -m "added sub and file" &&
295         mkdir -p deep/directory/hierarchy &&
296         git submodule add ./. deep/directory/hierarchy/sub &&
297         git commit -m "added another submodule" &&
298         git branch submodule
299 '
300
301 test_expect_success 'git mv cannot move a submodule in a file' '
302         test_must_fail git mv sub file
303 '
304
305 test_expect_success 'git mv moves a submodule with a .git directory and no .gitmodules' '
306         entry="$(git ls-files --stage sub | cut -f 1)" &&
307         git rm .gitmodules &&
308         (
309                 cd sub &&
310                 rm -f .git &&
311                 cp -R -P -p ../.git/modules/sub .git &&
312                 GIT_WORK_TREE=. git config --unset core.worktree
313         ) &&
314         mkdir mod &&
315         git mv sub mod/sub &&
316         ! test -e sub &&
317         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
318         (
319                 cd mod/sub &&
320                 git status
321         ) &&
322         git update-index --refresh &&
323         git diff-files --quiet
324 '
325
326 test_expect_success 'git mv moves a submodule with a .git directory and .gitmodules' '
327         rm -rf mod &&
328         git reset --hard &&
329         git submodule update &&
330         entry="$(git ls-files --stage sub | cut -f 1)" &&
331         (
332                 cd sub &&
333                 rm -f .git &&
334                 cp -R -P -p ../.git/modules/sub .git &&
335                 GIT_WORK_TREE=. git config --unset core.worktree
336         ) &&
337         mkdir mod &&
338         git mv sub mod/sub &&
339         ! test -e sub &&
340         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
341         (
342                 cd mod/sub &&
343                 git status
344         ) &&
345         echo mod/sub >expected &&
346         git config -f .gitmodules submodule.sub.path >actual &&
347         test_cmp expected actual &&
348         git update-index --refresh &&
349         git diff-files --quiet
350 '
351
352 test_expect_success 'git mv moves a submodule with gitfile' '
353         rm -rf mod &&
354         git reset --hard &&
355         git submodule update &&
356         entry="$(git ls-files --stage sub | cut -f 1)" &&
357         mkdir mod &&
358         (
359                 cd mod &&
360                 git mv ../sub/ .
361         ) &&
362         ! test -e sub &&
363         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
364         (
365                 cd mod/sub &&
366                 git status
367         ) &&
368         echo mod/sub >expected &&
369         git config -f .gitmodules submodule.sub.path >actual &&
370         test_cmp expected actual &&
371         git update-index --refresh &&
372         git diff-files --quiet
373 '
374
375 test_expect_success 'mv does not complain when no .gitmodules file is found' '
376         rm -rf mod &&
377         git reset --hard &&
378         git submodule update &&
379         git rm .gitmodules &&
380         entry="$(git ls-files --stage sub | cut -f 1)" &&
381         mkdir mod &&
382         git mv sub mod/sub 2>actual.err &&
383         ! test -s actual.err &&
384         ! test -e sub &&
385         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
386         (
387                 cd mod/sub &&
388                 git status
389         ) &&
390         git update-index --refresh &&
391         git diff-files --quiet
392 '
393
394 test_expect_success 'mv will error out on a modified .gitmodules file unless staged' '
395         rm -rf mod &&
396         git reset --hard &&
397         git submodule update &&
398         git config -f .gitmodules foo.bar true &&
399         entry="$(git ls-files --stage sub | cut -f 1)" &&
400         mkdir mod &&
401         test_must_fail git mv sub mod/sub 2>actual.err &&
402         test -s actual.err &&
403         test -e sub &&
404         git diff-files --quiet -- sub &&
405         git add .gitmodules &&
406         git mv sub mod/sub 2>actual.err &&
407         ! test -s actual.err &&
408         ! test -e sub &&
409         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
410         (
411                 cd mod/sub &&
412                 git status
413         ) &&
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_i18ncmp expect.err 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 --dry-run does not touch the submodule or .gitmodules' '
440         rm -rf mod &&
441         git reset --hard &&
442         git submodule update &&
443         mkdir mod &&
444         git mv -n sub mod/sub 2>actual.err &&
445         test -f sub/.git &&
446         git diff-index --exit-code HEAD &&
447         git update-index --refresh &&
448         git diff-files --quiet -- sub .gitmodules
449 '
450
451 test_expect_success 'checking out a commit before submodule moved needs manual updates' '
452         git mv sub sub2 &&
453         git commit -m "moved sub to sub2" &&
454         git checkout -q HEAD^ 2>actual &&
455         test_i18ngrep "^warning: unable to rmdir sub2:" actual &&
456         git status -s sub2 >actual &&
457         echo "?? sub2/" >expected &&
458         test_cmp expected actual &&
459         ! test -f sub/.git &&
460         test -f sub2/.git &&
461         git submodule update &&
462         test -f sub/.git &&
463         rm -rf sub2 &&
464         git diff-index --exit-code HEAD &&
465         git update-index --refresh &&
466         git diff-files --quiet -- sub .gitmodules &&
467         git status -s sub2 >actual &&
468         ! test -s actual
469 '
470
471 test_expect_success 'mv -k does not accidentally destroy submodules' '
472         git checkout submodule &&
473         mkdir dummy dest &&
474         git mv -k dummy sub dest &&
475         git status --porcelain >actual &&
476         grep "^R  sub -> dest/sub" actual &&
477         git reset --hard &&
478         git checkout .
479 '
480
481 test_expect_success 'moving a submodule in nested directories' '
482         (
483                 cd deep &&
484                 git mv directory ../ &&
485                 # git status would fail if the update of linking git dir to
486                 # work dir of the submodule failed.
487                 git status &&
488                 git config -f ../.gitmodules submodule.deep/directory/hierarchy/sub.path >../actual &&
489                 echo "directory/hierarchy/sub" >../expect
490         ) &&
491         test_cmp actual expect
492 '
493
494 test_done