Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2014-04-23 08:51:54 +0400
committerRussell Belfer <rb@github.com>2014-04-23 08:51:54 +0400
commit37da368545b28157e625212e8009ec041cc4a4ea (patch)
tree9fac6b09448e10224191507e764263374ed36083 /src/iterator.c
parent3c1aa4c110d2d4c8c3d941b0e4ba66357172da2e (diff)
Make checkout match diff for untracked/ignored dir
When diff finds an untracked directory, it emulates Git behavior by looking inside the directory to see if there are any untracked items inside it. If there are only ignored items inside the dir, then diff considers it ignored, even if there is no direct ignore rule for it. Checkout was not copying this behavior - when it found an untracked directory, it just treated it as untracked. Unfortunately, when combined with GIT_CHECKOUT_REMOVE_UNTRACKED, this made is seem that checkout (and stash, which uses checkout) was removing ignored items when you had only asked it to remove untracked ones. This commit moves the logic for advancing past an untracked dir while scanning for non-ignored items into an iterator helper fn, and uses that for both diff and checkout.
Diffstat (limited to 'src/iterator.c')
-rw-r--r--src/iterator.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/src/iterator.c b/src/iterator.c
index 63c14f962..1a24dad10 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -1528,3 +1528,71 @@ int git_iterator_current_workdir_path(git_buf **path, git_iterator *iter)
return 0;
}
+
+int git_iterator_advance_over_and_check_ignored(
+ const git_index_entry **entryptr, bool *ignored, git_iterator *iter)
+{
+ int error = 0;
+ workdir_iterator *wi = (workdir_iterator *)iter;
+ char *base = NULL;
+ const git_index_entry *entry;
+
+ *ignored = false;
+
+ if (iter->type != GIT_ITERATOR_TYPE_WORKDIR)
+ return git_iterator_advance(entryptr, iter);
+ if ((error = git_iterator_current(&entry, iter)) < 0)
+ return error;
+
+ if (!S_ISDIR(entry->mode)) {
+ if (git_ignore__lookup(
+ &wi->ignores, wi->fi.entry.path, &wi->is_ignored) < 0)
+ wi->is_ignored = true;
+ *ignored = wi->is_ignored;
+ return git_iterator_advance(entryptr, iter);
+ }
+
+ *ignored = true;
+
+ base = git__strdup(entry->path);
+ GITERR_CHECK_ALLOC(base);
+
+ /* scan inside directory looking for a non-ignored item */
+ while (entry && !iter->prefixcomp(entry->path, base)) {
+ if (git_ignore__lookup(
+ &wi->ignores, wi->fi.entry.path, &wi->is_ignored) < 0)
+ wi->is_ignored = true;
+
+ if (!wi->is_ignored && S_ISDIR(entry->mode)) {
+ error = git_iterator_advance_into(&entry, iter);
+
+ if (!error)
+ continue;
+ else if (error == GIT_ENOTFOUND) {
+ error = 0;
+ wi->is_ignored = true; /* treat empty directories as ignored */
+ } else
+ break; /* real error, stop here */
+ }
+
+ /* if we found a non-ignored item, treat parent as untracked */
+ if (!wi->is_ignored) {
+ *ignored = false;
+ break;
+ }
+
+ if ((error = git_iterator_advance(&entry, iter)) < 0)
+ break;
+ }
+
+ /* wrap up scan back to base directory */
+ while (entry && !iter->prefixcomp(entry->path, base))
+ if ((error = git_iterator_advance(&entry, iter)) < 0)
+ break;
+
+ *entryptr = entry;
+ git__free(base);
+
+ return error;
+}
+