Discussion:
Unexpected "clean -Xd" behavior
Pete Harlan
2012-01-16 02:00:14 UTC
Permalink
Hi,

When a directory contains nothing but an ignored subdirectory, that
subdirectory does not get removed by "git clean -Xdf".

For example, in a new directory:

# git init
Initialized empty Git repository in /tmp/foo/.git/
# echo a/ >.gitignore
# git add .gitignore
# git commit -m "Initial commit"
[master (root-commit) c3af24c] Initial commit
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 .gitignore
# mkdir -p foo/a
# touch foo/a/junk.o
# git status
# On branch master
nothing to commit (working directory clean)
# git clean -Xdn # <--- DOES NOT MENTION foo/a
# touch foo/x.c
# git clean -Xdn # <--- DITTO WITH UNTRACKED IN foo
# git add foo/x.c
# git clean -Xdn # <--- WITH TRACKED IN foo, WILL REMOVE a/
Would remove foo/a/
#

Is this intentional? It's interfering with my using "git clean" to
remove built objects, which happen to be in a dedicated temporary
subdirectory.

Thanks,

--Pete Harlan
***@pcharlan.com
Jonathan Nieder
2012-01-19 00:29:04 UTC
Permalink
(+cc: Duy, Shawn)
Hi,
Post by Pete Harlan
When a directory contains nothing but an ignored subdirectory, that
subdirectory does not get removed by "git clean -Xdf".
# git init
Initialized empty Git repository in /tmp/foo/.git/
# echo a/ >.gitignore
# git add .gitignore
# git commit -m "Initial commit"
[master (root-commit) c3af24c] Initial commit
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 .gitignore
# mkdir -p foo/a
# touch foo/a/junk.o
# git status
# On branch master
nothing to commit (working directory clean)
# git clean -Xdn # <--- DOES NOT MENTION foo/a
# touch foo/x.c
# git clean -Xdn # <--- DITTO WITH UNTRACKED IN foo
# git add foo/x.c
# git clean -Xdn # <--- WITH TRACKED IN foo, WILL REMOVE a/
Would remove foo/a/
#
Is this intentional? It's interfering with my using "git clean" to
remove built objects, which happen to be in a dedicated temporary
subdirectory.
Sounds like a bug. Duy, Shawn, any hints?

Thanks,
Jonathan
Nguyen Thai Ngoc Duy
2012-01-19 07:31:32 UTC
Permalink
Post by Pete Harlan
When a directory contains nothing but an ignored subdirectory, that
subdirectory does not get removed by "git clean -Xdf".
# git init
Initialized empty Git repository in /tmp/foo/.git/
# echo a/ >.gitignore
# git add .gitignore
# git commit -m "Initial commit"
[master (root-commit) c3af24c] Initial commit
=C2=A01 files changed, 1 insertions(+), 0 deletions(-)
=C2=A0create mode 100644 .gitignore
# mkdir -p foo/a
# touch foo/a/junk.o
# git status
# On branch master
nothing to commit (working directory clean)
# git clean -Xdn =C2=A0# <--- DOES NOT MENTION foo/a
-X is to remove ignored files _only_ (DIR_SHOW_IGNORED flag). And
"foo" is not ignored according to .gitignore, so it cuts short there
and never gets to "foo/a". -x works. May be intentional, may be not
(we hit a corner case). I don't know. Commit message b991625 might
help:

dir.c: Omit non-excluded directories with dir->show_ignored

This makes "git-ls-files --others --directory --ignored" behave
as documented and consequently also fixes "git-clean -d -X".
Previously, git-clean would remove non-excluded directories
even when using the -X option.
--=20
Duy
Jonathan Nieder
2012-01-19 10:03:42 UTC
Permalink
Post by Nguyen Thai Ngoc Duy
-X is to remove ignored files _only_ (DIR_SHOW_IGNORED flag). And
"foo" is not ignored according to .gitignore, so it cuts short there
and never gets to "foo/a". -x works.
Makes sense.

I guess the internal logic is that "git clean -fdX" cleans up files
that "git clean -fd" would miss, and this is not such a file ("git
clean -fd" removes it). But as Pete mentioned, in this edge case the
behavior renders "git clean -fdX" less effective than expected at its
primary task as poor man's "make clean".

I'd be happy to see a patch that moves to a different set of semantics
or an addition to t/t7300-clean.sh and BUGS section in
Documentation/git-clean.txt explaining the current limitations, if
someone wants to work on that.

Thanks, both.
Jonathan
p***@pcharlan.com
2012-01-19 22:12:18 UTC
Permalink
Thank you very much for looking at this.
Post by Nguyen Thai Ngoc Duy
Post by Pete Harlan
When a directory contains nothing but an ignored subdirectory, that
subdirectory does not get removed by "git clean -Xdf".
# git init
Initialized empty Git repository in /tmp/foo/.git/
# echo a/ >.gitignore
# git add .gitignore
# git commit -m "Initial commit"
[master (root-commit) c3af24c] Initial commit
=C2=A01 files changed, 1 insertions(+), 0 deletions(-)
=C2=A0create mode 100644 .gitignore
# mkdir -p foo/a
# touch foo/a/junk.o
# git status
# On branch master
nothing to commit (working directory clean)
# git clean -Xdn =C2=A0# <--- DOES NOT MENTION foo/a
-X is to remove ignored files _only_ (DIR_SHOW_IGNORED flag). And
"foo" is not ignored according to .gitignore, so it cuts short there
and never gets to "foo/a". -x works.
But the presence of a tracked file in foo makes it not cut short there,=
so
the logic seems a bit off. (If we're interested in removing ignored fi=
les
only, then the ignored files (not a tracked file) should trigger us
looking into foo. I don't know Git internals but I'm guessing it's not
quite that simple.)
Post by Nguyen Thai Ngoc Duy
May be intentional, may be not
(we hit a corner case). I don't know. Commit message b991625 might
dir.c: Omit non-excluded directories with dir->show_ignored
This makes "git-ls-files --others --directory --ignored" behave
as documented and consequently also fixes "git-clean -d -X".
Previously, git-clean would remove non-excluded directories
even when using the -X option.
It can (and does) leave foo behind (because it's not ignored), but it
would conform better to the -X documentation if the ignored files were
removed.

BTW the above commit doesn't affect the behavior in this example.

If a fix isn't desirable then as Jonathan said updating the documentati=
on
makes sense. (And those of us using it as a poor man's "make clean" ca=
n
just fix our Makefiles instead...)

Thanks,

--Pete

Continue reading on narkive:
Loading...