Merge branch 'jk/stash-require-clean-index'
[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 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         git branch submodule
296 '
297
298 test_expect_success 'git mv cannot move a submodule in a file' '
299         test_must_fail git mv sub file
300 '
301
302 test_expect_success 'git mv moves a submodule with a .git directory and no .gitmodules' '
303         entry="$(git ls-files --stage sub | cut -f 1)" &&
304         git rm .gitmodules &&
305         (
306                 cd sub &&
307                 rm -f .git &&
308                 cp -R -P -p ../.git/modules/sub .git &&
309                 GIT_WORK_TREE=. git config --unset core.worktree
310         ) &&
311         mkdir mod &&
312         git mv sub mod/sub &&
313         ! test -e sub &&
314         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
315         (
316                 cd mod/sub &&
317                 git status
318         ) &&
319         git update-index --refresh &&
320         git diff-files --quiet
321 '
322
323 test_expect_success 'git mv moves a submodule with a .git directory and .gitmodules' '
324         rm -rf mod &&
325         git reset --hard &&
326         git submodule update &&
327         entry="$(git ls-files --stage sub | cut -f 1)" &&
328         (
329                 cd sub &&
330                 rm -f .git &&
331                 cp -R -P -p ../.git/modules/sub .git &&
332                 GIT_WORK_TREE=. git config --unset core.worktree
333         ) &&
334         mkdir mod &&
335         git mv sub mod/sub &&
336         ! test -e sub &&
337         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
338         (
339                 cd mod/sub &&
340                 git status
341         ) &&
342         echo mod/sub >expected &&
343         git config -f .gitmodules submodule.sub.path >actual &&
344         test_cmp expected actual &&
345         git update-index --refresh &&
346         git diff-files --quiet
347 '
348
349 test_expect_success 'git mv moves a submodule with gitfile' '
350         rm -rf mod &&
351         git reset --hard &&
352         git submodule update &&
353         entry="$(git ls-files --stage sub | cut -f 1)" &&
354         mkdir mod &&
355         (
356                 cd mod &&
357                 git mv ../sub/ .
358         ) &&
359         ! test -e sub &&
360         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
361         (
362                 cd mod/sub &&
363                 git status
364         ) &&
365         echo mod/sub >expected &&
366         git config -f .gitmodules submodule.sub.path >actual &&
367         test_cmp expected actual &&
368         git update-index --refresh &&
369         git diff-files --quiet
370 '
371
372 test_expect_success 'mv does not complain when no .gitmodules file is found' '
373         rm -rf mod &&
374         git reset --hard &&
375         git submodule update &&
376         git rm .gitmodules &&
377         entry="$(git ls-files --stage sub | cut -f 1)" &&
378         mkdir mod &&
379         git mv sub mod/sub 2>actual.err &&
380         ! test -s actual.err &&
381         ! test -e sub &&
382         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
383         (
384                 cd mod/sub &&
385                 git status
386         ) &&
387         git update-index --refresh &&
388         git diff-files --quiet
389 '
390
391 test_expect_success 'mv will error out on a modified .gitmodules file unless staged' '
392         rm -rf mod &&
393         git reset --hard &&
394         git submodule update &&
395         git config -f .gitmodules foo.bar true &&
396         entry="$(git ls-files --stage sub | cut -f 1)" &&
397         mkdir mod &&
398         test_must_fail git mv sub mod/sub 2>actual.err &&
399         test -s actual.err &&
400         test -e sub &&
401         git diff-files --quiet -- sub &&
402         git add .gitmodules &&
403         git mv sub mod/sub 2>actual.err &&
404         ! test -s 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 issues a warning when section is not found in .gitmodules' '
416         rm -rf mod &&
417         git reset --hard &&
418         git submodule update &&
419         git config -f .gitmodules --remove-section submodule.sub &&
420         git add .gitmodules &&
421         entry="$(git ls-files --stage sub | cut -f 1)" &&
422         echo "warning: Could not find section in .gitmodules where path=sub" >expect.err &&
423         mkdir mod &&
424         git mv sub mod/sub 2>actual.err &&
425         test_i18ncmp expect.err actual.err &&
426         ! test -e sub &&
427         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
428         (
429                 cd mod/sub &&
430                 git status
431         ) &&
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 -s 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_done