diff options
author | Russell Belfer <rb@github.com> | 2013-01-03 14:08:53 -0800 |
---|---|---|
committer | Russell Belfer <rb@github.com> | 2013-01-04 15:47:44 -0800 |
commit | d8889d2b64a0a28f33a189216e1d63669b9be206 (patch) | |
tree | e6f7deafb92f9c260c1ebdff94409438b8934a77 /src/checkout.c | |
parent | dde7602ae633a557acdb74c8027335bb2584aa77 (diff) | |
download | libgit2-d8889d2b64a0a28f33a189216e1d63669b9be206.tar.gz |
Fix checkout bug rmv untracked trees from index
When checking out with the GIT_CHECKOUT_REMOVE_UNTRACKED option
and there was an entire tree in the working directory and in the
index that is not in the baseline nor target commit, the tree was
correctly(?) removed from the working directory but was not
successfully removed from the index. This fixes that and adds a
test of the functionality.
Diffstat (limited to 'src/checkout.c')
-rw-r--r-- | src/checkout.c | 47 |
1 files changed, 33 insertions, 14 deletions
diff --git a/src/checkout.c b/src/checkout.c index a10507aaf..261dee112 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -418,6 +418,8 @@ static int checkout_action_with_wd_dir( return checkout_action_common(data, action, delta, wd); } +#define EXPAND_DIRS_FOR_STRATEGY (GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED | GIT_CHECKOUT_REMOVE_IGNORED) + static int checkout_action( checkout_data *data, git_diff_delta *delta, @@ -429,6 +431,7 @@ static int checkout_action( int cmp = -1, act; int (*strcomp)(const char *, const char *) = data->diff->strcomp; int (*pfxcomp)(const char *str, const char *pfx) = data->diff->pfxcomp; + bool expand_dirs = (data->strategy & EXPAND_DIRS_FOR_STRATEGY) != 0; /* move workdir iterator to follow along with deltas */ @@ -449,14 +452,14 @@ static int checkout_action( if (cmp < 0) { cmp = pfxcomp(delta->old_file.path, wd->path); - if (cmp == 0) { - if (wd->mode == GIT_FILEMODE_TREE) { - /* case 2 - descend in wd */ - if (git_iterator_advance_into_directory(workdir, &wd) < 0) - goto fail; - continue; - } + if (wd->mode == GIT_FILEMODE_TREE && (cmp == 0 || expand_dirs)) { + /* case 2 or untracked wd item that might need removal */ + if (git_iterator_advance_into_directory(workdir, &wd) < 0) + goto fail; + continue; + } + if (cmp == 0) { /* case 3 - wd contains non-dir where dir expected */ act = checkout_action_with_wd_blocker(data, delta, wd); *wditem_ptr = git_iterator_advance(workdir, &wd) ? NULL : wd; @@ -519,6 +522,26 @@ fail: return -1; } +static int checkout_remaining_wd_items( + checkout_data *data, + git_iterator *workdir, + const git_index_entry *wd, + git_vector *spec) +{ + int error = 0; + bool expand_dirs = (data->strategy & EXPAND_DIRS_FOR_STRATEGY) != 0; + + while (wd && !error) { + if (wd->mode == GIT_FILEMODE_TREE && expand_dirs) + error = git_iterator_advance_into_directory(workdir, &wd); + + else if (!(error = checkout_action_wd_only(data, workdir, wd, spec))) + error = git_iterator_advance(workdir, &wd); + } + + return error; +} + static int checkout_get_actions( uint32_t **actions_ptr, size_t **counts_ptr, @@ -570,13 +593,9 @@ static int checkout_get_actions( counts[CHECKOUT_ACTION__CONFLICT]++; } - while (wditem != NULL) { - error = checkout_action_wd_only(data, workdir, wditem, &pathspec); - if (!error) - error = git_iterator_advance(workdir, &wditem); - if (error < 0) - goto fail; - } + error = checkout_remaining_wd_items(data, workdir, wditem, &pathspec); + if (error < 0) + goto fail; counts[CHECKOUT_ACTION__REMOVE] += data->removes.length; |