Commit 1f9e41ee865ac3a9c60d39c7db212478c04bf86d

Russell Belfer 2013-05-10T07:50:53

Improve ignore handling in git_status_file The git_status_file API was doing a hack to deal with files that are inside ignored directories. The status scan was not reporting any file in this case, so git_status_file would attempt a final "stat()" call, and return IGNORED if the file actually existed. On case-insensitive filesystems where core.ignorecase is set incorrectly, this magic check can "succeed" and report a file as ignored when it should actually return ENOTFOUND. Now that we have the GIT_STATUS_OPT_RECURSE_IGNORED_DIRS, we can use that flag to make sure that git_status_file() will look into ignored directories and eliminate the hack completely, so we give the correct error.

diff --git a/src/status.c b/src/status.c
index 73472ab..89f3eed 100644
--- a/src/status.c
+++ b/src/status.c
@@ -266,6 +266,7 @@ int git_status_file(
 
 	opts.show  = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
 	opts.flags = GIT_STATUS_OPT_INCLUDE_IGNORED |
+		GIT_STATUS_OPT_RECURSE_IGNORED_DIRS |
 		GIT_STATUS_OPT_INCLUDE_UNTRACKED |
 		GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS |
 		GIT_STATUS_OPT_INCLUDE_UNMODIFIED;
@@ -281,22 +282,9 @@ int git_status_file(
 	}
 
 	if (!error && !sfi.count) {
-		git_buf full = GIT_BUF_INIT;
-
-		/* if the file actually exists and we still did not get a callback
-		 * for it, then it must be contained inside an ignored directory, so
-		 * mark it as such instead of generating an error.
-		 */
-		if (!git_buf_joinpath(&full, git_repository_workdir(repo), path) &&
-			git_path_exists(full.ptr))
-			sfi.status = GIT_STATUS_IGNORED;
-		else {
-			giterr_set(GITERR_INVALID,
-				"Attempt to get status of nonexistent file '%s'", path);
-			error = GIT_ENOTFOUND;
-		}
-
-		git_buf_free(&full);
+		giterr_set(GITERR_INVALID,
+			"Attempt to get status of nonexistent file '%s'", path);
+		error = GIT_ENOTFOUND;
 	}
 
 	*status_flags = sfi.status;
diff --git a/tests-clar/clar_libgit2.c b/tests-clar/clar_libgit2.c
index 68d1716..de0e41b 100644
--- a/tests-clar/clar_libgit2.c
+++ b/tests-clar/clar_libgit2.c
@@ -190,6 +190,18 @@ git_repository *cl_git_sandbox_init(const char *sandbox)
 	return _cl_repo;
 }
 
+git_repository *cl_git_sandbox_reopen(void)
+{
+	if (_cl_repo) {
+		git_repository_free(_cl_repo);
+		_cl_repo = NULL;
+
+		cl_git_pass(git_repository_open(&_cl_repo, _cl_sandbox));
+	}
+
+	return _cl_repo;
+}
+
 void cl_git_sandbox_cleanup(void)
 {
 	if (_cl_repo) {
diff --git a/tests-clar/clar_libgit2.h b/tests-clar/clar_libgit2.h
index 93909d8..3fcf45a 100644
--- a/tests-clar/clar_libgit2.h
+++ b/tests-clar/clar_libgit2.h
@@ -60,6 +60,7 @@ int cl_rename(const char *source, const char *dest);
 
 git_repository *cl_git_sandbox_init(const char *sandbox);
 void cl_git_sandbox_cleanup(void);
+git_repository *cl_git_sandbox_reopen(void);
 
 /* Local-repo url helpers */
 const char* cl_git_fixture_url(const char *fixturename);
diff --git a/tests-clar/status/worktree.c b/tests-clar/status/worktree.c
index 0138b17..062a09a 100644
--- a/tests-clar/status/worktree.c
+++ b/tests-clar/status/worktree.c
@@ -672,3 +672,26 @@ void test_status_worktree__file_status_honors_core_ignorecase_false(void)
 {
 	assert_ignore_case(false, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_NEW);
 }
+
+void test_status_worktree__file_status_honors_case_ignorecase_regarding_untracked_files(void)
+{
+    git_repository *repo = cl_git_sandbox_init("status");
+    unsigned int status;
+    git_index *index;
+
+    cl_repo_set_bool(repo, "core.ignorecase", false);
+
+	repo = cl_git_sandbox_reopen();
+
+    /* Actually returns GIT_STATUS_IGNORED on Windows */
+    cl_git_fail_with(git_status_file(&status, repo, "NEW_FILE"), GIT_ENOTFOUND);
+
+    cl_git_pass(git_repository_index(&index, repo));
+
+    cl_git_pass(git_index_add_bypath(index, "new_file"));
+    cl_git_pass(git_index_write(index));
+    git_index_free(index);
+
+    /* Actually returns GIT_STATUS_IGNORED on Windows */
+    cl_git_fail_with(git_status_file(&status, repo, "NEW_FILE"), GIT_ENOTFOUND);
+}