git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 10/10] clean: support cleaning sparse checkout with -S

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Nov 15, 2010, 10:36 UTC
Message-ID
<1289817410-32470-11-git-send-email-pclouds@gmail.com>
In-Reply-To
<1289817410-32470-1-git-send-email-pclouds@gmail.com>

Those files that are managed by git, but out of working directory due to sparse-checkout file are subjected to be cleaned by "-S". Files that match the index exactly will be cleaned without "-f". Otherwise '-f' is needed.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-clean.txt |    6 ++-
 builtin/clean.c             |   70 ++++++++++++++++++++++++++++++++
 t/t7301-clean-sparse.sh     |   92 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 167 insertions(+), 1 deletions(-)
 create mode 100755 t/t7301-clean-sparse.sh
diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt
index 60e38e6..e0c95b1 100644
--- a/Documentation/git-clean.txt
+++ b/Documentation/git-clean.txt
@@ -8,7 +8,7 @@ git-clean - Remove untracked files from the working tree
 SYNOPSIS
 --------
 [verse]
-'git clean' [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <path>...
+'git clean' [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X | -S] [--] <path>...
 
 DESCRIPTION
 -----------
@@ -61,6 +61,10 @@ OPTIONS
 	Remove only files ignored by git.  This may be useful to rebuild
 	everything from scratch, but keep manually created files.
 
+-S::
+	Remove files tracked by git but are outside of sparse checkout.
+	Files that match the index exactly will be removed even when
+	'-f' is not given and clean.requireForce is no.
 
 Author
 ------
diff --git a/builtin/clean.c b/builtin/clean.c
index c8798f5..5827993 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -34,11 +34,71 @@ static int exclude_cb(const struct option *opt, const char *arg, int unset)
 	return 0;
 }
 
+static int clean_sparse_checkout(const char *prefix, const char **pathspec,
+				 int show_only, int quiet, int force)
+{
+	struct stat st;
+	int i, errors = 0;
+	unsigned char sha1[20];
+	const char *qname;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (read_cache() < 0)
+		die("index file corrupt");
+	for (i = 0; i < the_index.cache_nr; i++) {
+		struct cache_entry *ce = the_index.cache[i];
+
+		if (!ce_skip_worktree(ce))
+			continue;
+		if (pathspec && !match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL))
+			continue;
+
+		if (stat(ce->name, &st) < 0)
+			continue;
+		qname = quote_path_relative(ce->name, ce_namelen(ce), &buf, prefix);
+		if (index_path(sha1, ce->name, &st, 0) < 0) {
+			warning("failed to hash %s", qname);
+			errors++;
+			continue;
+		}
+		if (!hashcmp(sha1, ce->sha1)) {
+			if (show_only) {
+				printf("Would remove %s\n", qname);
+				continue;
+			}
+			if (!quiet)
+				printf("Removing %s\n", qname);
+			if (unlink(ce->name) != 0) {
+				warning("failed to remove %s", qname);
+				errors++;
+			}
+			continue;
+		}
+		if (force) {
+			if (show_only) {
+				printf("Would remove %s\n", qname);
+				continue;
+			}
+			if (!quiet)
+				printf("Removing %s\n", qname);
+			if (unlink(ce->name) != 0) {
+				warning("failed to remove %s", qname);
+				errors++;
+			}
+			continue;
+		}
+		if (show_only)
+			printf("Would not remove %s\n", qname);
+	}
+	return errors != 0;
+}
+
 int cmd_clean(int argc, const char **argv, const char *prefix)
 {
 	int i;
 	int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0;
 	int ignored_only = 0, baselen = 0, config_set = 0, errors = 0;
+	int sparse = 0;
 	int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
 	struct strbuf directory = STRBUF_INIT;
 	struct dir_struct dir;
@@ -55,6 +115,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 				"remove whole directories"),
 		{ OPTION_CALLBACK, 'e', "exclude", &exclude_list, "pattern",
 		  "exclude <pattern>", PARSE_OPT_NONEG, exclude_cb },
+		OPT_BOOLEAN('S', NULL, &sparse, "remove tracked files outside sparse checkout"),
 		OPT_BOOLEAN('x', NULL, &ignored, "remove ignored files, too"),
 		OPT_BOOLEAN('X', NULL, &ignored_only,
 				"remove only ignored files"),
@@ -70,6 +131,15 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 	argc = parse_options(argc, argv, prefix, options, builtin_clean_usage,
 			     0);
 
+	if (sparse) {
+		if (ignored || ignored_only)
+			die("-S, -x and -X cannot be used together");
+		if (exclude_list.nr)
+			die("-S and -e cannot be used together (yet)");
+		pathspec = get_pathspec(prefix, argv);
+		return clean_sparse_checkout(prefix, pathspec, show_only, quiet, force);
+	}
+
 	memset(&dir, 0, sizeof(dir));
 	if (ignored_only)
 		dir.flags |= DIR_SHOW_IGNORED;
diff --git a/t/t7301-clean-sparse.sh b/t/t7301-clean-sparse.sh
new file mode 100755
index 0000000..3ac0b0a
--- /dev/null
+++ b/t/t7301-clean-sparse.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+
+test_description='git clean -S basic tests'
+
+. ./test-lib.sh
+
+git config clean.requireForce yes
+
+test_expect_success 'setup' '
+	mkdir src &&
+	touch file1 file2 &&
+	touch src/file1 src/file2 &&
+	git add . &&
+	git update-index --skip-worktree file1 src/file1
+'
+
+test_expect_success 'clean -x -S does not work' '
+	test_must_fail git clean -x -S &&
+	test_must_fail git clean -X -S
+'
+
+test_expect_success 'clean -n -S' '
+	cat >expected <<\EOF
+Would remove file1
+Would remove src/file1
+EOF
+	git clean -n -S >result &&
+	test_cmp expected result
+'
+
+test_expect_success 'clean -n -S src' '
+	cat >expected <<\EOF
+Would remove src/file1
+EOF
+	git clean -n -S src >result &&
+	test_cmp expected result
+'
+
+test_expect_success '[src] clean -n -S .' '
+	(
+	cd src
+	cat >expected <<\EOF
+Would remove file1
+EOF
+	git clean -n -S . >result &&
+	test_cmp expected result
+	)
+'
+
+test_expect_success '[src] clean -n -S ../file1' '
+	(
+	cd src
+	cat >expected <<\EOF
+Would remove ../file1
+EOF
+	git clean -n -S ../file1 >result &&
+	test_cmp expected result
+	)
+'
+
+test_expect_success 'clean -n -S with dirty worktree' '
+	echo dirty >file1 &&
+	cat >expected <<\EOF
+Would not remove file1
+Would remove src/file1
+EOF
+	git clean -n -S >result &&
+	test_cmp expected result
+'
+
+test_expect_success 'clean -f -n -S with dirty worktree' '
+	echo dirty >file1 &&
+	cat >expected <<\EOF
+Would remove file1
+Would remove src/file1
+EOF
+	git clean -f -n -S >result &&
+	test_cmp expected result
+'
+
+test_expect_success 'clean -S with dirty worktree' '
+	git clean -S &&
+	grep dirty file1 &&
+	test ! -f src/file1
+'
+
+test_expect_success 'clean -f -S with dirty worktree' '
+	git clean -f -S &&
+	test ! -f file1
+'
+
+test_done
-- 
1.7.3.2.210.g045198
Previous: Nguyễn Thái Ngọc DuyNext: Jonathan Nieder
Message 31 of 34 in “Sparse checkout fixes and improvements”
  1. 00/10 Sparse checkout fixes and improvementsNguyễn Thái Ngọc Duy, Nov 15, 2010
  2. 01/10 add: do not rely on dtype being NULL behaviorNguyễn Thái Ngọc Duy, Nov 15, 2010
  3. Jonathan NiederNov 15, 2010
  4. Nguyen Thai Ngoc DuyNov 16, 2010
  5. Jonathan NiederNov 16, 2010
  6. Junio C HamanoNov 16, 2010
  7. Nguyen Thai Ngoc DuyNov 17, 2010
  8. 02/10 unpack-trees: move all skip-worktree check back to unpack_trees()Nguyễn Thái Ngọc Duy, Nov 15, 2010
  9. Thiago FarinaNov 15, 2010
  10. Nguyen Thai Ngoc DuyNov 16, 2010
  11. Jonathan NiederNov 15, 2010
  12. Nguyen Thai Ngoc DuyNov 16, 2010
  13. 03/10 unpack-trees: add function to update ce_flags based on sparse patternsNguyễn Thái Ngọc Duy, Nov 15, 2010
  14. Jonathan NiederNov 15, 2010
  15. Jonathan NiederNov 15, 2010
  16. 04/10 unpack-trees: fix sparse checkout's "unable to match directories" faultNguyễn Thái Ngọc Duy, Nov 15, 2010
  17. Jonathan NiederNov 15, 2010
  18. Nguyen Thai Ngoc DuyNov 16, 2010
  19. 05/10 unpack-trees: optimize full checkout caseNguyễn Thái Ngọc Duy, Nov 15, 2010
  20. Jonathan NiederNov 15, 2010
  21. 06/10 templates: add info/sparse-checkoutNguyễn Thái Ngọc Duy, Nov 15, 2010
  22. 07/10 checkout: add -S to update sparse checkoutNguyễn Thái Ngọc Duy, Nov 15, 2010
  23. Jonathan NiederNov 15, 2010
  24. Miles BaderNov 15, 2010
  25. Nguyen Thai Ngoc DuyNov 17, 2010
  26. Nguyen Thai Ngoc DuyNov 16, 2010
  27. 08/10 checkout: add --full to fully populate working directoryNguyễn Thái Ngọc Duy, Nov 15, 2010
  28. Jonathan NiederNov 15, 2010
  29. Nguyen Thai Ngoc DuyNov 16, 2010
  30. 09/10 git-checkout.txt: mention of sparse checkoutNguyễn Thái Ngọc Duy, Nov 15, 2010
  31. 10/10 clean: support cleaning sparse checkout with -SNguyễn Thái Ngọc Duy, Nov 15, 2010
  32. Jonathan NiederNov 15, 2010
  33. Nguyen Thai Ngoc DuyNov 16, 2010
  34. Jonathan NiederNov 16, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.