Skip to contentSkip to conversation

Add -e/--exclude to git-clean.

PATCH In review Jared Hance 2 participants 7 messages Jun 15, 2016 Documentation

lore
Share & tools
lore
#0 lore raw

cover Add -e/--exclude to git-clean.

Changes:
- Use -e multiple times instead of using a separator

I'm starting a new thread since the code change is rather major. I've incorporated Julio's changes, touched up on them a bit, and updated the test suite so that it uses multiple instances of -e rather than using a separator in them.

Thanks to Julio and all that helped.

Jared Hance (2):
Add -e/--exclude to git-clean.
Add test for git clean -e.

 Documentation/git-clean.txt |    8 +++++++-
 builtin/clean.c             |   17 ++++++++++++++++-
 t/t7300-clean.sh            |   16 ++++++++++++++++
 3 files changed, 39 insertions(+), 2 deletions(-)
#2 lore raw

PATCH 1/2 Add -e/--exclude to git-clean.

In reply to Jared Hance

With the -e/--exclude option for git-clean, a user can specify files that they haven't yet told git about, but either need for a short amount of time or plan to tell git about them later. This allows one to still use git-clean while these files are around without losing data.

---
 Documentation/git-clean.txt |    8 +++++++-
 builtin/clean.c             |   17 ++++++++++++++++-
 2 files changed, 23 insertions(+), 2 deletions(-)
Documentation/git-clean.txt +7 -1
index a81cb6c..60e38e6 100644
@@ -8,7 +8,7 @@ git-clean - Remove untracked files from the working tree
 SYNOPSIS
 --------
 [verse]
-'git clean' [-d] [-f] [-n] [-q] [-x | -X] [--] <path>...
+'git clean' [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <path>...
 
 DESCRIPTION
 -----------
@@ -45,6 +45,12 @@ OPTIONS
 	Be quiet, only report errors, but not the files that are
 	successfully removed.
 
+-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.
+
 -x::
 	Don't use the ignore rules.  This allows removing all untracked
 	files, including build products.  This can be used (possibly in
builtin/clean.c +16 -1
index fac64e6..841ac26 100644
@@ -10,12 +10,13 @@
 #include "cache.h"
 #include "dir.h"
 #include "parse-options.h"
+#include "string-list.h"
 #include "quote.h"
 
 static int force = -1; /* unset */
 
 static const char *const builtin_clean_usage[] = {
-	"git clean [-d] [-f] [-n] [-q] [-x | -X] [--] <paths>...",
+	"git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>...",
 	NULL
 };
 
@@ -26,6 +27,13 @@ static int git_clean_config(const char *var, const char *value, void *cb)
 	return git_default_config(var, value, cb);
 }
 
+static int exclude_cb(const struct option *opt, const char *arg, int unset)
+{
+	struct string_list *exclude_list = (struct string_list *)opt->value;
+	string_list_append(exclude_list, arg);
+	return 0;
+}
+
 int cmd_clean(int argc, const char **argv, const char *prefix)
 {
 	int i;
@@ -36,6 +44,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 	struct dir_struct dir;
 	static const char **pathspec;
 	struct strbuf buf = STRBUF_INIT;
+	struct string_list exclude_list = { NULL, 0, 0, 0 };
 	const char *qname;
 	char *seen = NULL;
 	struct option options[] = {
@@ -44,6 +53,8 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 		OPT_BOOLEAN('f', "force", &force, "force"),
 		OPT_BOOLEAN('d', NULL, &remove_directories,
 				"remove whole directories"),
+		{ OPTION_CALLBACK, 'e', "exclude", &exclude_list, "pattern",
+		  "exclude <pattern>", PARSE_OPT_NONEG, exclude_cb },
 		OPT_BOOLEAN('x', NULL, &ignored, "remove ignored files, too"),
 		OPT_BOOLEAN('X', NULL, &ignored_only,
 				"remove only ignored files"),
@@ -81,6 +92,9 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 	if (!ignored)
 		setup_standard_excludes(&dir);
 
+	for (i = 0; i < exclude_list.nr; i++)
+		add_exclude(exclude_list.items[i].string, "", 0, dir.exclude_list);
+
 	pathspec = get_pathspec(prefix, argv);
 
 	fill_directory(&dir, pathspec);
@@ -167,5 +181,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 	free(seen);
 
 	strbuf_release(&directory);
+	string_list_clear(&exclude_list, 0);
 	return (errors != 0);
 }
Signature · 1 line
1.7.1.1
#3 lore raw
Quoted 6 lines · Jared Hance

With the -e/--exclude option for git-clean, a user can specify files that they haven't yet told git about, but either need for a short amount of time or plan to tell git about them later. This allows one to still use git-clean while these files are around without losing data.

Thanks.

builtin/clean.c static int git_clean_config(const char *var, const char *value, void *cb) · line 32

Quoted 3 lines
builtin/clean.c +3 -0
+static int exclude_cb(const struct option *opt, const char *arg, int unset)
+{
+	struct string_list *exclude_list = (struct string_list *)opt->value;

Unnecessary cast, as opt->value is of type (void *).

builtin/clean.c int cmd_clean(int argc, const char **argv, const char *prefix) · line 47

Quoted 5 lines
builtin/clean.c +1 -0
@@ -36,6 +44,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 	struct dir_struct dir;
 	static const char **pathspec;
 	struct strbuf buf = STRBUF_INIT;
+	struct string_list exclude_list = { NULL, 0, 0, 0 };

Mental note to myself. We should convert this to use STRING_LIST_INIT after the next release when Thiago's patch graduates to 'master'.

#4 lore raw

PATCH 2/2 Add test for git clean -e.

In reply to Jared Hance
---
 t/t7300-clean.sh |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)
t/t7300-clean.sh +16 -0
index 7d8ed68..3a43571 100755
@@ -438,4 +438,20 @@ test_expect_success 'force removal of nested git work tree' '
 	! test -d bar
 '
 
+test_expect_success 'git clean -e' '
+	rm -fr repo &&
+	mkdir repo &&
+	(
+		cd repo &&
+		git init &&
+		touch 1 2 3 known &&
+		git add known &&
+		git clean -f -e 1 -e 2 &&
+		test -e 1 &&
+		test -e 2 &&
+		! (test -e 3) &&
+		test -e known
+	)
+'
+
 test_done
Signature · 1 line
1.7.1.1
#5 lore raw

Re: [PATCH 2/2] Add test for git clean -e.

Quoted 18 lines · Jared Hance
---
 t/t7300-clean.sh |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)
t/t7300-clean.sh +5 -0
index 7d8ed68..3a43571 100755
@@ -438,4 +438,20 @@ test_expect_success 'force removal of nested git work tree' '
 	! test -d bar
 '
 
+test_expect_success 'git clean -e' '
+	rm -fr repo &&
+	mkdir repo &&
+	(
+		cd repo &&

t/t7300-clean.sh test_expect_success 'force removal of nested git work tree' ' · line 455

Quoted 10 lines
t/t7300-clean.sh +10 -0
+		git init &&
+		touch 1 2 3 known &&
+		git add known &&
+		git clean -f -e 1 -e 2 &&
+		test -e 1 &&
+		test -e 2 &&
+		! (test -e 3) &&
+		test -e known
+	)
+'

This is a good start but it doesn't seem to test possible interactions with entries in .gitignore file(s) in the working tree. Do we care?

What should happen when a path "path":

(1) is marked to be ignored in .gitignore and -e "path" is also given;

(2) is marked not to be ignored (i.e. "!path") in .gitignore but -e

    "path" is given;

(3) is marked to be ignored in .gitignore but -e "!path" is given;

(4) is marked not to be ignored in .gitignore and -e "!path" is also

     given;

(5) perhaps other combinations like "!path" in a/.gitignore, and -e "a/path" from the command line.

What does the code actually do?

#6 lore raw

Re: [PATCH 2/2] Add test for git clean -e.

Quoted 2 lines · Junio C Hamano

This is a good start but it doesn't seem to test possible interactions with entries in .gitignore file(s) in the working tree. Do we care?

Honestly, I'm not sure that we do care.

Quoted 4 lines

What should happen when a path "path":

(1) is marked to be ignored in .gitignore and -e "path" is also given;

It is excluded.

Quoted 2 lines

(2) is marked not to be ignored (i.e. "!path") in .gitignore but -e

    "path" is given;

I think it would be good for "!path" to cause -e path to have no effect because of globbing issues.

Currently, -e works as normal.

Quoted 1 line

(3) is marked to be ignored in .gitignore but -e "!path" is given;

Again, I'm not sure and am definately open to debate here. Personally, I think that -e "!path" is completely abusing the use of -e, because it is using -e to NOT exclude something.

Currently, -e has no effect.

Quoted 2 lines

(4) is marked not to be ignored in .gitignore and -e "!path" is also

     given;

No effect happens. Again, this is abuse of -e in my opinion, as its goal to allow one to do a clean and save one or two files.

Quoted 2 lines

(5) perhaps other combinations like "!path" in a/.gitignore, and -e "a/path" from the command line.

Judging by (2), -e will work as normal.