3 # Copyright (c) 2007 Michael Spang
6 test_description
='git clean basic tests'
8 TEST_PASSES_SANITIZE_LEAK
=true
11 git config clean.requireForce no
13 test_expect_success
'setup' '
16 touch src/part1.c Makefile &&
17 echo build >.gitignore &&
18 echo \*.o >>.gitignore &&
20 git commit -m setup &&
21 touch src/part2.c README &&
26 test_expect_success
'git clean with skip-worktree .gitignore' '
27 git update-index --skip-worktree .gitignore &&
29 mkdir -p build docs &&
30 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
32 test_path_is_file Makefile &&
33 test_path_is_file README &&
34 test_path_is_file src/part1.c &&
35 test_path_is_file src/part2.c &&
36 test_path_is_missing a.out &&
37 test_path_is_missing src/part3.c &&
38 test_path_is_file docs/manual.txt &&
39 test_path_is_file obj.o &&
40 test_path_is_file build/lib.so &&
41 git update-index --no-skip-worktree .gitignore &&
42 git checkout .gitignore
45 test_expect_success
'git clean' '
47 mkdir -p build docs &&
48 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
50 test_path_is_file Makefile &&
51 test_path_is_file README &&
52 test_path_is_file src/part1.c &&
53 test_path_is_file src/part2.c &&
54 test_path_is_missing a.out &&
55 test_path_is_missing src/part3.c &&
56 test_path_is_file docs/manual.txt &&
57 test_path_is_file obj.o &&
58 test_path_is_file build/lib.so
62 test_expect_success
'git clean src/' '
64 mkdir -p build docs &&
65 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
67 test_path_is_file Makefile &&
68 test_path_is_file README &&
69 test_path_is_file src/part1.c &&
70 test_path_is_file src/part2.c &&
71 test_path_is_file a.out &&
72 test_path_is_missing src/part3.c &&
73 test_path_is_file docs/manual.txt &&
74 test_path_is_file obj.o &&
75 test_path_is_file build/lib.so
79 test_expect_success
'git clean src/ src/' '
81 mkdir -p build docs &&
82 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
83 git clean src/ src/ &&
84 test_path_is_file Makefile &&
85 test_path_is_file README &&
86 test_path_is_file src/part1.c &&
87 test_path_is_file src/part2.c &&
88 test_path_is_file a.out &&
89 test_path_is_missing src/part3.c &&
90 test_path_is_file docs/manual.txt &&
91 test_path_is_file obj.o &&
92 test_path_is_file build/lib.so
96 test_expect_success
'git clean with prefix' '
98 mkdir -p build docs src/test &&
99 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so src/test/1.c &&
100 (cd src/ && git clean) &&
101 test_path_is_file Makefile &&
102 test_path_is_file README &&
103 test_path_is_file src/part1.c &&
104 test_path_is_file src/part2.c &&
105 test_path_is_file a.out &&
106 test_path_is_missing src/part3.c &&
107 test_path_is_file src/test/1.c &&
108 test_path_is_file docs/manual.txt &&
109 test_path_is_file obj.o &&
110 test_path_is_file build/lib.so
114 test_expect_success
'git clean with relative prefix' '
116 mkdir -p build docs &&
117 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
120 git clean -n ../src |
122 sed -n -e "s|^Would remove ||p"
124 test "$would_clean" = ../src/part3.c
127 test_expect_success
'git clean with absolute path' '
129 mkdir -p build docs &&
130 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
133 git clean -n "$(pwd)/../src" |
135 sed -n -e "s|^Would remove ||p"
137 test "$would_clean" = ../src/part3.c
140 test_expect_success
'git clean with out of work tree relative path' '
142 mkdir -p build docs &&
143 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
146 test_must_fail git clean -n ../..
150 test_expect_success
'git clean with out of work tree absolute path' '
152 mkdir -p build docs &&
153 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
154 dd=$(cd .. && pwd) &&
157 test_must_fail git clean -n $dd
161 test_expect_success
'git clean -d with prefix and path' '
163 mkdir -p build docs src/feature &&
164 touch a.out src/part3.c src/feature/file.c docs/manual.txt obj.o build/lib.so &&
165 (cd src/ && git clean -d feature/) &&
166 test_path_is_file Makefile &&
167 test_path_is_file README &&
168 test_path_is_file src/part1.c &&
169 test_path_is_file src/part2.c &&
170 test_path_is_file a.out &&
171 test_path_is_file src/part3.c &&
172 test_path_is_missing src/feature/file.c &&
173 test_path_is_file docs/manual.txt &&
174 test_path_is_file obj.o &&
175 test_path_is_file build/lib.so
179 test_expect_success SYMLINKS
'git clean symbolic link' '
181 mkdir -p build docs &&
182 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
183 ln -s docs/manual.txt src/part4.c &&
185 test_path_is_file Makefile &&
186 test_path_is_file README &&
187 test_path_is_file src/part1.c &&
188 test_path_is_file src/part2.c &&
189 test_path_is_missing a.out &&
190 test_path_is_missing src/part3.c &&
191 test_path_is_missing src/part4.c &&
192 test_path_is_file docs/manual.txt &&
193 test_path_is_file obj.o &&
194 test_path_is_file build/lib.so
198 test_expect_success
'git clean with wildcard' '
200 touch a.clean b.clean other.c &&
201 git clean "*.clean" &&
202 test_path_is_file Makefile &&
203 test_path_is_file README &&
204 test_path_is_file src/part1.c &&
205 test_path_is_file src/part2.c &&
206 test_path_is_missing a.clean &&
207 test_path_is_missing b.clean &&
208 test_path_is_file other.c
212 test_expect_success
'git clean -n' '
214 mkdir -p build docs &&
215 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
217 test_path_is_file Makefile &&
218 test_path_is_file README &&
219 test_path_is_file src/part1.c &&
220 test_path_is_file src/part2.c &&
221 test_path_is_file a.out &&
222 test_path_is_file src/part3.c &&
223 test_path_is_file docs/manual.txt &&
224 test_path_is_file obj.o &&
225 test_path_is_file build/lib.so
229 test_expect_success
'git clean -d' '
231 mkdir -p build docs &&
232 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
234 test_path_is_file Makefile &&
235 test_path_is_file README &&
236 test_path_is_file src/part1.c &&
237 test_path_is_file src/part2.c &&
238 test_path_is_missing a.out &&
239 test_path_is_missing src/part3.c &&
240 test_path_is_missing docs &&
241 test_path_is_file obj.o &&
242 test_path_is_file build/lib.so
246 test_expect_success
'git clean -d src/ examples/' '
248 mkdir -p build docs examples &&
249 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so examples/1.c &&
250 git clean -d src/ examples/ &&
251 test_path_is_file Makefile &&
252 test_path_is_file README &&
253 test_path_is_file src/part1.c &&
254 test_path_is_file src/part2.c &&
255 test_path_is_file a.out &&
256 test_path_is_missing src/part3.c &&
257 test_path_is_missing examples/1.c &&
258 test_path_is_file docs/manual.txt &&
259 test_path_is_file obj.o &&
260 test_path_is_file build/lib.so
264 test_expect_success
'git clean -x' '
266 mkdir -p build docs &&
267 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
269 test_path_is_file Makefile &&
270 test_path_is_file README &&
271 test_path_is_file src/part1.c &&
272 test_path_is_file src/part2.c &&
273 test_path_is_missing a.out &&
274 test_path_is_missing src/part3.c &&
275 test_path_is_file docs/manual.txt &&
276 test_path_is_missing obj.o &&
277 test_path_is_file build/lib.so
281 test_expect_success
'git clean -d -x' '
283 mkdir -p build docs &&
284 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
286 test_path_is_file Makefile &&
287 test_path_is_file README &&
288 test_path_is_file src/part1.c &&
289 test_path_is_file src/part2.c &&
290 test_path_is_missing a.out &&
291 test_path_is_missing src/part3.c &&
292 test_path_is_missing docs &&
293 test_path_is_missing obj.o &&
294 test_path_is_missing build
298 test_expect_success
'git clean -d -x with ignored tracked directory' '
300 mkdir -p build docs &&
301 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
302 git clean -d -x -e src &&
303 test_path_is_file Makefile &&
304 test_path_is_file README &&
305 test_path_is_file src/part1.c &&
306 test_path_is_file src/part2.c &&
307 test_path_is_missing a.out &&
308 test_path_is_file src/part3.c &&
309 test_path_is_missing docs &&
310 test_path_is_missing obj.o &&
311 test_path_is_missing build
315 test_expect_success
'git clean -X' '
317 mkdir -p build docs &&
318 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
320 test_path_is_file Makefile &&
321 test_path_is_file README &&
322 test_path_is_file src/part1.c &&
323 test_path_is_file src/part2.c &&
324 test_path_is_file a.out &&
325 test_path_is_file src/part3.c &&
326 test_path_is_file docs/manual.txt &&
327 test_path_is_missing obj.o &&
328 test_path_is_file build/lib.so
332 test_expect_success
'git clean -d -X' '
334 mkdir -p build docs &&
335 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
337 test_path_is_file Makefile &&
338 test_path_is_file README &&
339 test_path_is_file src/part1.c &&
340 test_path_is_file src/part2.c &&
341 test_path_is_file a.out &&
342 test_path_is_file src/part3.c &&
343 test_path_is_file docs/manual.txt &&
344 test_path_is_missing obj.o &&
345 test_path_is_missing build
349 test_expect_success
'git clean -d -X with ignored tracked directory' '
351 mkdir -p build docs &&
352 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
353 git clean -d -X -e src &&
354 test_path_is_file Makefile &&
355 test_path_is_file README &&
356 test_path_is_file src/part1.c &&
357 test_path_is_file src/part2.c &&
358 test_path_is_file a.out &&
359 test_path_is_missing src/part3.c &&
360 test_path_is_file docs/manual.txt &&
361 test_path_is_missing obj.o &&
362 test_path_is_missing build
366 test_expect_success
'clean.requireForce defaults to true' '
368 git config --unset clean.requireForce &&
369 test_must_fail git clean
373 test_expect_success
'clean.requireForce' '
375 git config clean.requireForce true &&
376 test_must_fail git clean
380 test_expect_success
'clean.requireForce and -n' '
382 mkdir -p build docs &&
383 touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
385 test_path_is_file Makefile &&
386 test_path_is_file README &&
387 test_path_is_file src/part1.c &&
388 test_path_is_file src/part2.c &&
389 test_path_is_file a.out &&
390 test_path_is_file src/part3.c &&
391 test_path_is_file docs/manual.txt &&
392 test_path_is_file obj.o &&
393 test_path_is_file build/lib.so
397 test_expect_success
'clean.requireForce and -f' '
400 test_path_is_file README &&
401 test_path_is_file src/part1.c &&
402 test_path_is_file src/part2.c &&
403 test_path_is_missing a.out &&
404 test_path_is_missing src/part3.c &&
405 test_path_is_file docs/manual.txt &&
406 test_path_is_file obj.o &&
407 test_path_is_file build/lib.so
411 test_expect_success
'clean.requireForce and --interactive' '
412 git clean --interactive </dev/null >output 2>error &&
413 test_grep ! "requireForce is true and" error &&
414 test_grep "\*\*\* Commands \*\*\*" output
417 test_expect_success
'core.excludesfile' '
419 echo excludes >excludes &&
420 echo included >included &&
421 git config core.excludesfile excludes &&
422 output=$(git clean -n excludes included 2>&1) &&
423 expr "$output" : ".*included" >/dev/null &&
424 ! expr "$output" : ".*excludes" >/dev/null
428 test_expect_success SANITY
'removal failure' '
432 test_when_finished "chmod 755 foo" &&
435 test_must_fail git clean -f -d)
438 test_expect_success
'nested git work tree' '
439 rm -fr foo bar baz &&
440 mkdir -p foo bar baz/boo &&
444 test_commit nested hello.world
453 test_commit deeply.nested deeper.world
456 test_path_is_file foo/.git/index &&
457 test_path_is_file foo/hello.world &&
458 test_path_is_file baz/boo/.git/index &&
459 test_path_is_file baz/boo/deeper.world &&
460 test_path_is_missing bar
463 test_expect_success
'should clean things that almost look like git but are not' '
464 rm -fr almost_git almost_bare_git almost_submodule &&
465 mkdir -p almost_git/.git/objects &&
466 mkdir -p almost_git/.git/refs &&
467 cat >almost_git/.git/HEAD <<-\EOF &&
470 cp -r almost_git/.git/ almost_bare_git &&
471 mkdir almost_submodule/ &&
472 cat >almost_submodule/.git <<-\EOF &&
475 test_when_finished "rm -rf almost_*" &&
477 test_path_is_missing almost_git &&
478 test_path_is_missing almost_bare_git &&
479 test_path_is_missing almost_submodule
482 test_expect_success
'should not clean submodules' '
483 rm -fr repo to_clean sub1 sub2 &&
484 mkdir repo to_clean &&
488 test_commit msg hello.world
490 test_config_global protocol.file.allow always &&
491 git submodule add ./repo/.git sub1 &&
492 git commit -m "sub1" &&
493 git branch before_sub2 &&
494 git submodule add ./repo/.git sub2 &&
495 git commit -m "sub2" &&
496 git checkout before_sub2 &&
497 >to_clean/should_clean.this &&
499 test_path_is_file repo/.git/index &&
500 test_path_is_file repo/hello.world &&
501 test_path_is_file sub1/.git &&
502 test_path_is_file sub1/hello.world &&
503 test_path_is_file sub2/.git &&
504 test_path_is_file sub2/hello.world &&
505 test_path_is_missing to_clean
508 test_expect_success POSIXPERM
,SANITY
'should avoid cleaning possible submodules' '
509 rm -fr to_clean possible_sub1 &&
510 mkdir to_clean possible_sub1 &&
511 test_when_finished "rm -rf possible_sub*" &&
512 echo "gitdir: foo" >possible_sub1/.git &&
513 >possible_sub1/hello.world &&
514 chmod 0 possible_sub1/.git &&
515 >to_clean/should_clean.this &&
517 test_path_is_file possible_sub1/.git &&
518 test_path_is_file possible_sub1/hello.world &&
519 test_path_is_missing to_clean
522 test_expect_success
'nested (empty) git should be kept' '
523 rm -fr empty_repo to_clean &&
524 git init empty_repo &&
526 >to_clean/should_clean.this &&
527 # Note that we put the expect file in the .git directory so that it
528 # does not get cleaned.
529 find empty_repo | sort >.git/expect &&
531 find empty_repo | sort >actual &&
532 test_cmp .git/expect actual &&
533 test_path_is_missing to_clean
536 test_expect_success
'nested bare repositories should be cleaned' '
537 rm -fr bare1 bare2 subdir &&
538 git init --bare bare1 &&
539 git clone --local --bare . bare2 &&
541 cp -r bare2 subdir/bare3 &&
543 test_path_is_missing bare1 &&
544 test_path_is_missing bare2 &&
545 test_path_is_missing subdir
548 test_expect_failure
'nested (empty) bare repositories should be cleaned even when in .git' '
549 rm -fr strange_bare &&
550 mkdir strange_bare &&
551 git init --bare strange_bare/.git &&
553 test_path_is_missing strange_bare
556 test_expect_failure
'nested (non-empty) bare repositories should be cleaned even when in .git' '
557 rm -fr strange_bare &&
558 mkdir strange_bare &&
559 git clone --local --bare . strange_bare/.git &&
561 test_path_is_missing strange_bare
564 test_expect_success
'giving path in nested git work tree will NOT remove it' '
571 test_commit msg bar/baz/hello.world
573 find repo | sort >expect &&
574 git clean -f -d repo/bar/baz &&
575 find repo | sort >actual &&
576 test_cmp expect actual
579 test_expect_success
'giving path to nested .git will not remove it' '
581 mkdir repo untracked &&
585 test_commit msg hello.world
587 find repo | sort >expect &&
588 git clean -f -d repo/.git &&
589 find repo | sort >actual &&
590 test_cmp expect actual &&
591 test_path_is_dir untracked/
594 test_expect_success
'giving path to nested .git/ will NOT remove contents' '
595 rm -fr repo untracked &&
596 mkdir repo untracked &&
600 test_commit msg hello.world
602 find repo | sort >expect &&
603 git clean -f -d repo/.git/ &&
604 find repo | sort >actual &&
605 test_cmp expect actual &&
606 test_path_is_dir untracked/
609 test_expect_success
'force removal of nested git work tree' '
610 rm -fr foo bar baz &&
611 mkdir -p foo bar baz/boo &&
615 test_commit nested hello.world
624 test_commit deeply.nested deeper.world
626 git clean -f -f -d &&
627 test_path_is_missing foo &&
628 test_path_is_missing bar &&
629 test_path_is_missing baz
632 test_expect_success
'git clean -e' '
640 git clean -f -e 1 -e 2 &&
641 test_path_exists 1 &&
642 test_path_exists 2 &&
643 test_path_is_missing 3 &&
644 test_path_exists known
648 test_expect_success SANITY
'git clean -d with an unreadable empty directory' '
651 git clean -dfx foo &&
652 test_path_is_missing foo
655 test_expect_success
'git clean -d respects pathspecs (dir is prefix of pathspec)' '
658 git clean -df foobar &&
659 test_path_is_dir foo &&
660 test_path_is_missing foobar
663 test_expect_success
'git clean -d respects pathspecs (pathspec is prefix of dir)' '
667 test_path_is_missing foo &&
668 test_path_is_dir foobar
671 test_expect_success
'git clean -d skips untracked dirs containing ignored files' '
672 echo /foo/bar >.gitignore &&
673 echo ignoreme >>.gitignore &&
675 mkdir -p foo/a/aa/aaa foo/b/bb/bbb &&
676 touch foo/bar foo/baz foo/a/aa/ignoreme foo/b/ignoreme foo/b/bb/1 foo/b/bb/2 &&
678 test_path_is_dir foo &&
679 test_path_is_file foo/bar &&
680 test_path_is_missing foo/baz &&
681 test_path_is_file foo/a/aa/ignoreme &&
682 test_path_is_missing foo/a/aa/aaa &&
683 test_path_is_file foo/b/ignoreme &&
684 test_path_is_missing foo/b/bb
687 test_expect_success
'git clean -d skips nested repo containing ignored files' '
688 test_when_finished "rm -rf nested-repo-with-ignored-file" &&
690 git init nested-repo-with-ignored-file &&
692 cd nested-repo-with-ignored-file &&
695 git commit -m Initial &&
697 # This file is ignored by a .gitignore rule in the outer repo
698 # added in the previous test.
704 test_path_is_file nested-repo-with-ignored-file/.git/index &&
705 test_path_is_file nested-repo-with-ignored-file/ignoreme &&
706 test_path_is_file nested-repo-with-ignored-file/file
709 test_expect_success
'git clean handles being told what to clean' '
713 test_path_is_missing d1/ut &&
714 test_path_is_missing d2/ut
717 test_expect_success
'git clean handles being told what to clean, with -d' '
720 git clean -ffd */ut &&
721 test_path_is_missing d1/ut &&
722 test_path_is_missing d2/ut
725 test_expect_success
'git clean works if a glob is passed without -d' '
728 git clean -f "*ut" &&
729 test_path_is_missing d1/ut &&
730 test_path_is_missing d2/ut
733 test_expect_success
'git clean works if a glob is passed with -d' '
736 git clean -ffd "*ut" &&
737 test_path_is_missing d1/ut &&
738 test_path_is_missing d2/ut
741 test_expect_success MINGW
'handle clean & core.longpaths = false nicely' '
742 test_config core.longpaths false &&
743 a50=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
744 mkdir -p $a50$a50/$a50$a50/$a50$a50 &&
745 : >"$a50$a50/test.txt" 2>"$a50$a50/$a50$a50/$a50$a50/test.txt" &&
746 # create a temporary outside the working tree to hide from "git clean"
747 test_must_fail git clean -xdf 2>.git/err &&
748 # grepping for a strerror string is unportable but it is OK here with
750 test_grep -e "too long" -e "No such file or directory" .git/err
753 test_expect_success
'clean untracked paths by pathspec' '
754 git init untracked &&
755 mkdir untracked/dir &&
756 echo >untracked/dir/file.txt &&
757 git -C untracked clean -f dir/file.txt &&
758 ls untracked/dir >actual &&
759 test_must_be_empty actual
762 test_expect_success
'avoid traversing into ignored directories' '
763 test_when_finished rm -f output error trace.* &&
764 test_create_repo avoid-traversing-deep-hierarchy &&
766 cd avoid-traversing-deep-hierarchy &&
768 mkdir -p untracked/subdir/with/a &&
769 >untracked/subdir/with/a/random-file.txt &&
771 GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \
772 git clean -ffdxn -e untracked
775 # Make sure we only visited into the top-level directory, and did
776 # not traverse into the "untracked" subdirectory since it was excluded
777 grep data.*read_directo.*directories-visited trace.output |
778 cut -d "|" -f 9 >trace.relevant &&
779 cat >trace.expect <<-EOF &&
780 ..directories-visited:1
782 test_cmp trace.expect trace.relevant
785 test_expect_success
'traverse into directories that may have ignored entries' '
786 test_when_finished rm -f output &&
787 test_create_repo need-to-traverse-into-hierarchy &&
789 cd need-to-traverse-into-hierarchy &&
790 mkdir -p modules/foobar/src/generated &&
791 > modules/foobar/src/generated/code.c &&
792 > modules/foobar/Makefile &&
793 echo "/modules/**/src/generated/" >.gitignore &&
795 git clean -fX modules/foobar >../output &&
797 grep Removing ../output &&
799 test_path_is_missing modules/foobar/src/generated/code.c &&
800 test_path_is_file modules/foobar/Makefile