diff options
author | Russell Belfer <rb@github.com> | 2014-04-18 10:32:35 -0700 |
---|---|---|
committer | Russell Belfer <rb@github.com> | 2014-04-18 10:32:35 -0700 |
commit | 6a0956e504328f6584af971e840c202ecb21b5b6 (patch) | |
tree | 234b3fc25eecccc41a6cafe7c7322eb476b67569 /src | |
parent | 3c69bebc1c18444e9358c33f56c7cfefea4d1a8f (diff) | |
download | libgit2-6a0956e504328f6584af971e840c202ecb21b5b6.tar.gz |
Pop ignore only if whole relative path matches
When traversing the directory structure, the iterator pushes and
pops ignore files using a vector. Some directories don't have
ignore files, so it uses a path comparison to decide when it is
right to actually pop the last ignore file. This was only
comparing directory suffixes, though, so a subdirectory with the
same name as a parent could result in the parent's .gitignore
being popped off the list ignores too early. This changes the
logic to compare the entire relative path of the ignore file.
Diffstat (limited to 'src')
-rw-r--r-- | src/ignore.c | 13 | ||||
-rw-r--r-- | src/ignore.h | 1 | ||||
-rw-r--r-- | src/path.c | 2 |
3 files changed, 10 insertions, 6 deletions
diff --git a/src/ignore.c b/src/ignore.c index deae204f8..b08ff2200 100644 --- a/src/ignore.c +++ b/src/ignore.c @@ -123,7 +123,7 @@ int git_ignore__for_path( int error = 0; const char *workdir = git_repository_workdir(repo); - assert(ignores); + assert(ignores && path); memset(ignores, 0, sizeof(*ignores)); ignores->repo = repo; @@ -140,10 +140,13 @@ int git_ignore__for_path( if (workdir && git_path_root(path) < 0) error = git_path_find_dir(&ignores->dir, path, workdir); else - error = git_buf_sets(&ignores->dir, path); + error = git_buf_joinpath(&ignores->dir, path, ""); if (error < 0) goto cleanup; + if (workdir && !git__prefixcmp(ignores->dir.ptr, workdir)) + ignores->dir_root = strlen(workdir); + /* set up internals */ if ((error = get_internal_ignores(&ignores->ign_internal, repo)) < 0) goto cleanup; @@ -204,10 +207,10 @@ int git_ignore__pop_dir(git_ignores *ign) if ((end = strrchr(start, '/')) != NULL) { size_t dirlen = (end - start) + 1; + const char *relpath = ign->dir.ptr + ign->dir_root; + size_t pathlen = ign->dir.size - ign->dir_root; - if (ign->dir.size >= dirlen && - !memcmp(ign->dir.ptr + ign->dir.size - dirlen, start, dirlen)) - { + if (pathlen == dirlen && !memcmp(relpath, start, dirlen)) { git_vector_pop(&ign->ign_path); git_attr_file__free(file); } diff --git a/src/ignore.h b/src/ignore.h index 46172c72f..ff9369000 100644 --- a/src/ignore.h +++ b/src/ignore.h @@ -28,6 +28,7 @@ typedef struct { git_attr_file *ign_internal; git_vector ign_path; git_vector ign_global; + size_t dir_root; /* offset in dir to repo root */ int ignore_case; int depth; } git_ignores; diff --git a/src/path.c b/src/path.c index 7cad28d45..a990b005f 100644 --- a/src/path.c +++ b/src/path.c @@ -624,7 +624,7 @@ int git_path_find_dir(git_buf *dir, const char *path, const char *base) /* call dirname if this is not a directory */ if (!error) /* && git_path_isdir(dir->ptr) == false) */ - error = git_path_dirname_r(dir, dir->ptr); + error = (git_path_dirname_r(dir, dir->ptr) < 0) ? -1 : 0; if (!error) error = git_path_to_dir(dir); |