Commit 02df42ddbf87820011aa4ccba9adfde52670e5e2

Russell Belfer 2012-11-19T16:33:30

Set up default internal ignores This adds "." ".." and ".git" to the internal ignores list by default - asking about paths with these files will always say that they are ignored.

diff --git a/include/git2/ignore.h b/include/git2/ignore.h
index e18615e..592c96e 100644
--- a/include/git2/ignore.h
+++ b/include/git2/ignore.h
@@ -41,9 +41,10 @@ GIT_EXTERN(int) git_ignore_add_rule(
 /**
  * Clear ignore rules that were explicitly added.
  *
- * Clears the internal ignore rules that have been set up.  This will not
- * turn off the rules in .gitignore files that actually exist in the
- * filesystem.
+ * Resets to the default internal ignore rules.  This will not turn off
+ * rules in .gitignore files that actually exist in the filesystem.
+ *
+ * The default internal ignores ignore ".", ".." and ".git" entries.
  *
  * @param repo The repository to remove ignore rules from.
  * @return 0 on success
diff --git a/src/ignore.c b/src/ignore.c
index 6a377e6..5edc5b6 100644
--- a/src/ignore.c
+++ b/src/ignore.c
@@ -7,6 +7,8 @@
 #define GIT_IGNORE_FILE_INREPO	"info/exclude"
 #define GIT_IGNORE_FILE			".gitignore"
 
+#define GIT_IGNORE_DEFAULT_RULES ".\n..\n.git\n"
+
 static int parse_ignore_file(
 	git_repository *repo, void *parsedata, const char *buffer, git_attr_file *ignores)
 {
@@ -88,6 +90,19 @@ static int push_one_ignore(void *ref, git_buf *path)
 	return push_ignore_file(ign->repo, ign, &ign->ign_path, path->ptr, GIT_IGNORE_FILE);
 }
 
+static int get_internal_ignores(git_attr_file **ign, git_repository *repo)
+{
+	int error;
+
+	if (!(error = git_attr_cache__init(repo)))
+		error = git_attr_cache__internal_file(repo, GIT_IGNORE_INTERNAL, ign);
+
+	if (!error && !(*ign)->rules.length)
+		error = parse_ignore_file(repo, NULL, GIT_IGNORE_DEFAULT_RULES, *ign);
+
+	return error;
+}
+
 int git_ignore__for_path(
 	git_repository *repo,
 	const char *path,
@@ -129,8 +144,7 @@ int git_ignore__for_path(
 		goto cleanup;
 
 	/* set up internals */
-	error = git_attr_cache__internal_file(
-		repo, GIT_IGNORE_INTERNAL, &ignores->ign_internal);
+	error = get_internal_ignores(&ignores->ign_internal, repo);
 	if (error < 0)
 		goto cleanup;
 
@@ -239,16 +253,6 @@ cleanup:
 	return 0;
 }
 
-static int get_internal_ignores(git_attr_file **ign, git_repository *repo)
-{
-	int error;
-
-	if (!(error = git_attr_cache__init(repo)))
-		error = git_attr_cache__internal_file(repo, GIT_IGNORE_INTERNAL, ign);
-
-	return error;
-}
-
 int git_ignore_add_rule(
 	git_repository *repo,
 	const char *rules)
@@ -268,9 +272,13 @@ int git_ignore_clear_internal_rules(
 	int error;
 	git_attr_file *ign_internal;
 
-	if (!(error = get_internal_ignores(&ign_internal, repo)))
+	if (!(error = get_internal_ignores(&ign_internal, repo))) {
 		git_attr_file__clear_rules(ign_internal);
 
+		return parse_ignore_file(
+			repo, NULL, GIT_IGNORE_DEFAULT_RULES, ign_internal);
+	}
+
 	return error;
 }
 
diff --git a/tests-clar/status/ignore.c b/tests-clar/status/ignore.c
index ddd0b3d..27f9d85 100644
--- a/tests-clar/status/ignore.c
+++ b/tests-clar/status/ignore.c
@@ -341,3 +341,41 @@ void test_status_ignore__internal_ignores_inside_deep_paths(void)
 	cl_git_pass(git_status_should_ignore(&ignored, g_repo, "xthis/is/deep"));
 	cl_assert(!ignored);
 }
+
+void test_status_ignore__automatically_ignore_bad_files(void)
+{
+	int ignored;
+
+	g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+	cl_git_pass(git_status_should_ignore(&ignored, g_repo, ".git"));
+	cl_assert(ignored);
+	cl_git_pass(git_status_should_ignore(&ignored, g_repo, "this/file/."));
+	cl_assert(ignored);
+	cl_git_pass(git_status_should_ignore(&ignored, g_repo, "path/../funky"));
+	cl_assert(ignored);
+	cl_git_pass(git_status_should_ignore(&ignored, g_repo, "path/whatever.c"));
+	cl_assert(!ignored);
+
+	cl_git_pass(git_ignore_add_rule(g_repo, "*.c\n"));
+
+	cl_git_pass(git_status_should_ignore(&ignored, g_repo, ".git"));
+	cl_assert(ignored);
+	cl_git_pass(git_status_should_ignore(&ignored, g_repo, "this/file/."));
+	cl_assert(ignored);
+	cl_git_pass(git_status_should_ignore(&ignored, g_repo, "path/../funky"));
+	cl_assert(ignored);
+	cl_git_pass(git_status_should_ignore(&ignored, g_repo, "path/whatever.c"));
+	cl_assert(ignored);
+
+	cl_git_pass(git_ignore_clear_internal_rules(g_repo));
+
+	cl_git_pass(git_status_should_ignore(&ignored, g_repo, ".git"));
+	cl_assert(ignored);
+	cl_git_pass(git_status_should_ignore(&ignored, g_repo, "this/file/."));
+	cl_assert(ignored);
+	cl_git_pass(git_status_should_ignore(&ignored, g_repo, "path/../funky"));
+	cl_assert(ignored);
+	cl_git_pass(git_status_should_ignore(&ignored, g_repo, "path/whatever.c"));
+	cl_assert(!ignored);
+}