2

Here's the setup:

git init
echo "foo/**" > .gitignore
mkdir foo && touch foo/bar
git status --ignored

The printed status says:

...
Ignored files:
  (use "git add -f <file>..." to include in what will be committed)
    foo/

Now,

git clean -fdX

... and it does nothing. foo/bar is still there.

Note that if I change the .gitignore rule from foo/** to just foo/ the -fdX command works as expected - it deletes the foo/ folder.

Tested with git version 2.29.1

Stefan Dragnev
  • 14,143
  • 6
  • 48
  • 52
  • 2
    This is probably a bug. It's not entirely clear to me what the intended behavior is with `**` and `git clean -X`, but you should send this example to the Git mailing list. – torek Dec 18 '20 at 14:38

2 Answers2

2

I tested it with Git for Windows, and a first issue comes from the double-quotes:

echo "foo/**" > .gitignore

That will give you a .gitignore file with:

"foo/**"

That is enough to ignore the foo folder but not its content:
a git check-ignore -v -- foo\bar would return nothing.

As described in "How do you strip quotes out of an ECHO'ed string in a Windows batch file?", use:

echo|set /p="foo/**" > .gitignore

That way, you have a .gitignore with:

foo/**

And git check-ignore -v -- foo\bar does work.

$ git check-ignore -v foo/bar
.gitignore:1:foo/       foo/bar

In both cases though, git clean -nfdX does not remove anything.

Only by mentioning the file directly would git clean propose to do anything:

vonc@vonc MINGW64 /d/git/tests/ign/foo (master)
$ git clean -nX

vonc@vonc MINGW64 /d/git/tests/ign/foo (master)
$ git clean -nX bar
Would remove bar

To really make it work, your rule should not use '**'

echo|set /p="foo/" > .gitignore

Then git clean -ndX would work.

D:\git\tests\ign>git clean -ndX
Would remove foo/
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
2

tl;dr: here's a workaround for an apparent bug in git clean -X:

git ls-files -oi --exclude-standard -z | xargs -0 rm

which without the -z | xargs -0 rm is git clean -nX and with it is git clean -fX. To delete (recursively-)empty directories, find * -depth -type d -empty -delete.


On linux, after

mkdir t1 t2 t3
touch t1/a1 t2/a2 t3/a3
printf %s\\n 't1/**' 't2/*' 't3' >.git/info/exclude

the next two commands list different results:

git ls-files -oc|git check-ignore --stdin
git clean -nX

but then

touch t1/c1 t2/c2 t3/c3
git add -f t?/c?
git clean -nX

and git clean picks up the t?/a? trash. So clean isn't recursing into wholly-ignored directories for -X.

edit: worse, replacing t3 with a3 in the ignore list and rerunning with the c? files gone or untracked leaves a3 still untouched. So it's not even "wholly-ignored" directories, it's "directories with no tracked content".

Yah, something needs fixing here.

jthill
  • 55,082
  • 5
  • 77
  • 137