Commit 219c89d1 by Russell Belfer

Treat ignored, empty, and untracked dirs different

In the iterator, distinguish between ignores and empty directories
so that diff and status can ignore empty directories, but checkout
and stash can treat them as untracked items.
parent 37da3685
...@@ -336,22 +336,22 @@ static int checkout_action_wd_only( ...@@ -336,22 +336,22 @@ static int checkout_action_wd_only(
error = git_iterator_advance(wditem, workdir); error = git_iterator_advance(wditem, workdir);
} else { } else {
/* untracked or ignored - can't know which until we advance through */ /* untracked or ignored - can't know which until we advance through */
bool ignored, over = false; bool over = false, removable = wd_item_is_removable(workdir, wd);
bool removable = wd_item_is_removable(workdir, wd); git_iterator_status_t untracked_state;
/* copy the entry for issuing notification callback later */ /* copy the entry for issuing notification callback later */
git_index_entry saved_wd = *wd; git_index_entry saved_wd = *wd;
git_buf_sets(&data->tmp, wd->path); git_buf_sets(&data->tmp, wd->path);
saved_wd.path = data->tmp.ptr; saved_wd.path = data->tmp.ptr;
error = git_iterator_advance_over_and_check_ignored( error = git_iterator_advance_over_with_status(
wditem, &ignored, workdir); wditem, &untracked_state, workdir);
if (error == GIT_ITEROVER) if (error == GIT_ITEROVER)
over = true; over = true;
else if (error < 0) else if (error < 0)
return error; return error;
if (ignored) { if (untracked_state == GIT_ITERATOR_STATUS_IGNORED) {
notify = GIT_CHECKOUT_NOTIFY_IGNORED; notify = GIT_CHECKOUT_NOTIFY_IGNORED;
remove = ((data->strategy & GIT_CHECKOUT_REMOVE_IGNORED) != 0); remove = ((data->strategy & GIT_CHECKOUT_REMOVE_IGNORED) != 0);
} else { } else {
......
...@@ -839,7 +839,7 @@ static int handle_unmatched_new_item( ...@@ -839,7 +839,7 @@ static int handle_unmatched_new_item(
DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS)) DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS))
{ {
git_diff_delta *last; git_diff_delta *last;
bool ignored; git_iterator_status_t untracked_state;
/* attempt to insert record for this directory */ /* attempt to insert record for this directory */
if ((error = diff_delta__from_one(diff, delta_type, nitem)) != 0) if ((error = diff_delta__from_one(diff, delta_type, nitem)) != 0)
...@@ -851,13 +851,14 @@ static int handle_unmatched_new_item( ...@@ -851,13 +851,14 @@ static int handle_unmatched_new_item(
return git_iterator_advance(&info->nitem, info->new_iter); return git_iterator_advance(&info->nitem, info->new_iter);
/* iterate into dir looking for an actual untracked file */ /* iterate into dir looking for an actual untracked file */
if ((error = git_iterator_advance_over_and_check_ignored( if ((error = git_iterator_advance_over_with_status(
&info->nitem, &ignored, info->new_iter)) < 0 && &info->nitem, &untracked_state, info->new_iter)) < 0 &&
error != GIT_ITEROVER) error != GIT_ITEROVER)
return error; return error;
/* it iteration only found ignored items, update the record */ /* if we found nothing or just ignored items, update the record */
if (ignored) { if (untracked_state == GIT_ITERATOR_STATUS_IGNORED ||
untracked_state == GIT_ITERATOR_STATUS_EMPTY) {
last->status = GIT_DELTA_IGNORED; last->status = GIT_DELTA_IGNORED;
/* remove the record if we don't want ignored records */ /* remove the record if we don't want ignored records */
......
...@@ -1529,15 +1529,17 @@ int git_iterator_current_workdir_path(git_buf **path, git_iterator *iter) ...@@ -1529,15 +1529,17 @@ int git_iterator_current_workdir_path(git_buf **path, git_iterator *iter)
return 0; return 0;
} }
int git_iterator_advance_over_and_check_ignored( int git_iterator_advance_over_with_status(
const git_index_entry **entryptr, bool *ignored, git_iterator *iter) const git_index_entry **entryptr,
git_iterator_status_t *status,
git_iterator *iter)
{ {
int error = 0; int error = 0;
workdir_iterator *wi = (workdir_iterator *)iter; workdir_iterator *wi = (workdir_iterator *)iter;
char *base = NULL; char *base = NULL;
const git_index_entry *entry; const git_index_entry *entry;
*ignored = false; *status = GIT_ITERATOR_STATUS_NORMAL;
if (iter->type != GIT_ITERATOR_TYPE_WORKDIR) if (iter->type != GIT_ITERATOR_TYPE_WORKDIR)
return git_iterator_advance(entryptr, iter); return git_iterator_advance(entryptr, iter);
...@@ -1548,11 +1550,12 @@ int git_iterator_advance_over_and_check_ignored( ...@@ -1548,11 +1550,12 @@ int git_iterator_advance_over_and_check_ignored(
if (git_ignore__lookup( if (git_ignore__lookup(
&wi->ignores, wi->fi.entry.path, &wi->is_ignored) < 0) &wi->ignores, wi->fi.entry.path, &wi->is_ignored) < 0)
wi->is_ignored = true; wi->is_ignored = true;
*ignored = wi->is_ignored; if (wi->is_ignored)
*status = GIT_ITERATOR_STATUS_IGNORED;
return git_iterator_advance(entryptr, iter); return git_iterator_advance(entryptr, iter);
} }
*ignored = true; *status = GIT_ITERATOR_STATUS_EMPTY;
base = git__strdup(entry->path); base = git__strdup(entry->path);
GITERR_CHECK_ALLOC(base); GITERR_CHECK_ALLOC(base);
...@@ -1577,9 +1580,11 @@ int git_iterator_advance_over_and_check_ignored( ...@@ -1577,9 +1580,11 @@ int git_iterator_advance_over_and_check_ignored(
/* if we found a non-ignored item, treat parent as untracked */ /* if we found a non-ignored item, treat parent as untracked */
if (!wi->is_ignored) { if (!wi->is_ignored) {
*ignored = false; *status = GIT_ITERATOR_STATUS_NORMAL;
break; break;
} }
if (entry && !S_ISDIR(entry->mode))
*status = GIT_ITERATOR_STATUS_IGNORED;
if ((error = git_iterator_advance(&entry, iter)) < 0) if ((error = git_iterator_advance(&entry, iter)) < 0)
break; break;
......
...@@ -258,12 +258,23 @@ extern int git_iterator_current_workdir_path( ...@@ -258,12 +258,23 @@ extern int git_iterator_current_workdir_path(
/* Return index pointer if index iterator, else NULL */ /* Return index pointer if index iterator, else NULL */
extern git_index *git_iterator_get_index(git_iterator *iter); extern git_index *git_iterator_get_index(git_iterator *iter);
/* Special type of advance that can be called when looking at a tree in typedef enum {
* the working directory that leaves the iterator on the next item after GIT_ITERATOR_STATUS_NORMAL = 0,
* the tree, but also scans the tree contents looking for any items that GIT_ITERATOR_STATUS_IGNORED = 1,
* are not ignored. GIT_ITERATOR_STATUS_EMPTY = 2
} git_iterator_status_t;
/* Advance over a directory and check if it contains no files or just
* ignored files.
*
* In a tree or the index, all directories will contain files, but in the
* working directory it is possible to have an empty directory tree or a
* tree that only contains ignored files. Many Git operations treat these
* cases specially. This advances over a directory (presumably an
* untracked directory) but checks during the scan if there are any files
* and any non-ignored files.
*/ */
extern int git_iterator_advance_over_and_check_ignored( extern int git_iterator_advance_over_with_status(
const git_index_entry **entry, bool *ignored, git_iterator *iter); const git_index_entry **entry, git_iterator_status_t *status, git_iterator *iter);
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment