summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/attr_file.h8
-rw-r--r--src/ignore.c69
-rw-r--r--src/status.c23
3 files changed, 89 insertions, 11 deletions
diff --git a/src/attr_file.h b/src/attr_file.h
index b28d8a02b..877daf306 100644
--- a/src/attr_file.h
+++ b/src/attr_file.h
@@ -71,10 +71,10 @@ typedef struct {
} git_attr_file;
typedef struct {
- git_buf full;
- const char *path;
- const char *basename;
- int is_dir;
+ git_buf full;
+ char *path;
+ char *basename;
+ int is_dir;
} git_attr_path;
typedef enum {
diff --git a/src/ignore.c b/src/ignore.c
index e711be206..6a377e60d 100644
--- a/src/ignore.c
+++ b/src/ignore.c
@@ -277,15 +277,76 @@ int git_ignore_clear_internal_rules(
int git_ignore_path_is_ignored(
int *ignored,
git_repository *repo,
- const char *path)
+ const char *pathname)
{
int error;
+ const char *workdir;
+ git_attr_path path;
+ char *tail, *end;
+ bool full_is_dir;
git_ignores ignores;
+ unsigned int i;
+ git_attr_file *file;
- if (git_ignore__for_path(repo, path, &ignores) < 0)
- return -1;
+ assert(ignored && pathname);
+
+ workdir = repo ? git_repository_workdir(repo) : NULL;
+
+ if ((error = git_attr_path__init(&path, pathname, workdir)) < 0)
+ return error;
+
+ tail = path.path;
+ end = &path.full.ptr[path.full.size];
+ full_is_dir = path.is_dir;
- error = git_ignore__lookup(&ignores, path, ignored);
+ while (1) {
+ /* advance to next component of path */
+ path.basename = tail;
+
+ while (tail < end && *tail != '/') tail++;
+ *tail = '\0';
+
+ path.full.size = (tail - path.full.ptr);
+ path.is_dir = (tail == end) ? full_is_dir : true;
+
+ /* update ignores for new path fragment */
+ if (path.basename == path.path)
+ error = git_ignore__for_path(repo, path.path, &ignores);
+ else
+ error = git_ignore__push_dir(&ignores, path.basename);
+ if (error < 0)
+ break;
+
+ /* first process builtins - success means path was found */
+ if (ignore_lookup_in_rules(
+ &ignores.ign_internal->rules, &path, ignored))
+ goto cleanup;
+
+ /* next process files in the path */
+ git_vector_foreach(&ignores.ign_path, i, file) {
+ if (ignore_lookup_in_rules(&file->rules, &path, ignored))
+ goto cleanup;
+ }
+
+ /* last process global ignores */
+ git_vector_foreach(&ignores.ign_global, i, file) {
+ if (ignore_lookup_in_rules(&file->rules, &path, ignored))
+ goto cleanup;
+ }
+
+ /* if we found no rules before reaching the end, we're done */
+ if (tail == end)
+ break;
+
+ /* reinstate divider in path */
+ *tail = '/';
+ while (*tail == '/') tail++;
+ }
+
+ *ignored = 0;
+
+cleanup:
+ git_attr_path__free(&path);
git_ignore__free(&ignores);
return error;
}
diff --git a/src/status.c b/src/status.c
index 3a0ed075f..a37653db4 100644
--- a/src/status.c
+++ b/src/status.c
@@ -86,6 +86,10 @@ int git_status_foreach_ext(
assert(show <= GIT_STATUS_SHOW_INDEX_THEN_WORKDIR);
+ if (show != GIT_STATUS_SHOW_INDEX_ONLY &&
+ (err = git_repository__ensure_not_bare(repo, "status")) < 0)
+ return err;
+
if ((err = git_repository_head_tree(&head, repo)) < 0)
return err;
@@ -245,9 +249,22 @@ int git_status_file(
error = GIT_EAMBIGUOUS;
if (!error && !sfi.count) {
- giterr_set(GITERR_INVALID,
- "Attempt to get status of nonexistent file '%s'", path);
- error = GIT_ENOTFOUND;
+ 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);
}
*status_flags = sfi.status;