fetch-pack: refactor parsing in get_ack
[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 | grep partA/outline.txt || {
165                 git ls-tree -r $T
166                 (exit 1)
167         }
168 '
169
170 rm -fr papers partA path?
171
172 test_expect_success "Sergey Vlasov's test case" '
173         rm -fr .git &&
174         git init &&
175         mkdir ab &&
176         date >ab.c &&
177         date >ab/d &&
178         git add ab.c ab &&
179         git commit -m 'initial' &&
180         git mv ab a
181 '
182
183 test_expect_success 'absolute pathname' '(
184
185         rm -fr mine &&
186         mkdir mine &&
187         cd mine &&
188         test_create_repo one &&
189         cd one &&
190         mkdir sub &&
191         >sub/file &&
192         git add sub/file &&
193
194         git mv sub "$(pwd)/in" &&
195         ! test -d sub &&
196         test -d in &&
197         git ls-files --error-unmatch in/file
198
199
200 )'
201
202 test_expect_success 'absolute pathname outside should fail' '(
203
204         rm -fr mine &&
205         mkdir mine &&
206         cd mine &&
207         out=$(pwd) &&
208         test_create_repo one &&
209         cd one &&
210         mkdir sub &&
211         >sub/file &&
212         git add sub/file &&
213
214         test_must_fail git mv sub "$out/out" &&
215         test -d sub &&
216         ! test -d ../in &&
217         git ls-files --error-unmatch sub/file
218
219 )'
220
221 test_expect_success 'git mv to move multiple sources into a directory' '
222         rm -fr .git && git init &&
223         mkdir dir other &&
224         >dir/a.txt &&
225         >dir/b.txt &&
226         git add dir/?.txt &&
227         git mv dir/a.txt dir/b.txt other &&
228         git ls-files >actual &&
229         { echo other/a.txt; echo other/b.txt; } >expect &&
230         test_cmp expect actual
231 '
232
233 test_expect_success 'git mv should not change sha1 of moved cache entry' '
234
235         rm -fr .git &&
236         git init &&
237         echo 1 >dirty &&
238         git add dirty &&
239         entry="$(git ls-files --stage dirty | cut -f 1)" &&
240         git mv dirty dirty2 &&
241         [ "$entry" = "$(git ls-files --stage dirty2 | cut -f 1)" ] &&
242         echo 2 >dirty2 &&
243         git mv dirty2 dirty &&
244         [ "$entry" = "$(git ls-files --stage dirty | cut -f 1)" ]
245
246 '
247
248 rm -f dirty dirty2
249
250 test_expect_success 'git mv should overwrite symlink to a file' '
251
252         rm -fr .git &&
253         git init &&
254         echo 1 >moved &&
255         test_ln_s_add moved symlink &&
256         git add moved &&
257         test_must_fail git mv moved symlink &&
258         git mv -f moved symlink &&
259         ! test -e moved &&
260         test -f symlink &&
261         test "$(cat symlink)" = 1 &&
262         git update-index --refresh &&
263         git diff-files --quiet
264
265 '
266
267 rm -f moved symlink
268
269 test_expect_success 'git mv should overwrite file with a symlink' '
270
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 symlink moved &&
277         git mv -f symlink moved &&
278         ! test -e symlink &&
279         git update-index --refresh &&
280         git diff-files --quiet
281
282 '
283
284 test_expect_success SYMLINKS 'check moved symlink' '
285
286         test -h moved
287 '
288
289 rm -f moved symlink
290
291 test_expect_success 'setup submodule' '
292         git commit -m initial &&
293         git reset --hard &&
294         git submodule add ./. sub &&
295         echo content >file &&
296         git add file &&
297         git commit -m "added sub and file" &&
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/sub &&
354         git reset --hard &&
355         git submodule update &&
356         entry="$(git ls-files --stage sub | cut -f 1)" &&
357         (
358                 cd mod &&
359                 git mv ../sub/ .
360         ) &&
361         ! test -e sub &&
362         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
363         (
364                 cd mod/sub &&
365                 git status
366         ) &&
367         echo mod/sub >expected &&
368         git config -f .gitmodules submodule.sub.path >actual &&
369         test_cmp expected actual &&
370         git update-index --refresh &&
371         git diff-files --quiet
372 '
373
374 test_expect_success 'mv does not complain when no .gitmodules file is found' '
375         rm -rf mod/sub &&
376         git reset --hard &&
377         git submodule update &&
378         git rm .gitmodules &&
379         entry="$(git ls-files --stage sub | cut -f 1)" &&
380         git mv sub mod/sub 2>actual.err &&
381         ! test -s actual.err &&
382         ! test -e sub &&
383         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
384         (
385                 cd mod/sub &&
386                 git status
387         ) &&
388         git update-index --refresh &&
389         git diff-files --quiet
390 '
391
392 test_expect_success 'mv will error out on a modified .gitmodules file unless staged' '
393         rm -rf mod/sub &&
394         git reset --hard &&
395         git submodule update &&
396         git config -f .gitmodules foo.bar true &&
397         entry="$(git ls-files --stage sub | cut -f 1)" &&
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/sub &&
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         git mv sub mod/sub 2>actual.err &&
424         test_i18ncmp expect.err actual.err &&
425         ! test -e sub &&
426         [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
427         (
428                 cd mod/sub &&
429                 git status
430         ) &&
431         git update-index --refresh &&
432         git diff-files --quiet
433 '
434
435 test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' '
436         rm -rf mod/sub &&
437         git reset --hard &&
438         git submodule update &&
439         git mv -n sub mod/sub 2>actual.err &&
440         test -f sub/.git &&
441         git diff-index --exit-code HEAD &&
442         git update-index --refresh &&
443         git diff-files --quiet -- sub .gitmodules
444 '
445
446 test_expect_success 'checking out a commit before submodule moved needs manual updates' '
447         git mv sub sub2 &&
448         git commit -m "moved sub to sub2" &&
449         git checkout -q HEAD^ 2>actual &&
450         test_i18ngrep "^warning: unable to rmdir sub2:" actual &&
451         git status -s sub2 >actual &&
452         echo "?? sub2/" >expected &&
453         test_cmp expected actual &&
454         ! test -f sub/.git &&
455         test -f sub2/.git &&
456         git submodule update &&
457         test -f sub/.git &&
458         rm -rf sub2 &&
459         git diff-index --exit-code HEAD &&
460         git update-index --refresh &&
461         git diff-files --quiet -- sub .gitmodules &&
462         git status -s sub2 >actual &&
463         ! test -s actual
464 '
465
466 test_expect_success 'mv -k does not accidentally destroy submodules' '
467         git checkout submodule &&
468         mkdir dummy dest &&
469         git mv -k dummy sub dest &&
470         git status --porcelain >actual &&
471         grep "^R  sub -> dest/sub" actual &&
472         git reset --hard &&
473         git checkout .
474 '
475
476 test_done