Re: git clean --exclude broken?
From: Junio C Hamano <hidden>
Date: 2016-06-15 22:51:54
Junio C Hamano [off-list ref] writes:
Todd Rinaldo [off-list ref] writes:quoted
I think I have found a new bug in 1.7.5:My quick check indicates 1.7.3 behaves the same way, and 1.7.2.5 didn't have --exclude option, so this does not seem to be anything particularly new in the 1.7.5 release.quoted
# The problem (Why is foo/ removed?) $>git clean -dXf --exclude=/foo Removing bar/ Removing foo/Why is this command line giving -X that tells us not to use the ignore rules, and --exclude option at the same time?
The documentation and the implementation of "git clean" is quite confused.
Here is what is said about "-e":
-e <pattern>::
--exclude=<pattern>::
Specify special exceptions to not be cleaned. Each <pattern> is
the same form as in $GIT_DIR/info/excludes and this option can be
given multiple times.
But in reality, it is not about "not be cleaned" at all. A better
description to reflect what the implementation actually does is probably
this:
In addition to what are found in usual places like .gitignore (per
directory) and $GIT_DIR/info/exclude, consider these patterns to
be in the ignore rules.
This mirrors what --exclude parameter to "ls-files" does [*1*].
I can however see a use case where the user wants to say something like
this which is quite different:
I know "git clean" (or "git clean -x" or "git clean -X") will try
to remove paths A, B and C. I want it remove them except for this
particular path C by adding --except=C option to the command line.
And the current documentation does look like it is describing such an
option. But that is not what --exclude option is about.
One solution might be to say "I know the usual rules stored in .gitignore
and the like tell us to that 'foo' is ignored (and to be cleaned), but for
this invocation only, please treat 'foo' is _not_ ignored.", and there
indeed is a way to do so:
$ git clean -d -X -e \!foo
(the backslash before '!' is to avoid history substitution in some shells).
[Footnote]
*1* This part in builtin/clean.c looks a bit distasteful:
for (i = 0; i < exclude_list.nr; i++)
add_exclude(exclude_list.items[i].string, "", 0, dir.exclude_list);
The last parameter should be &dir.exclude_list[EXC_CMDL] because we are
adding exclude patterns from the command line. It works by accident
only because EXC_CMDL happens to be defined as 0.