* situation better. See how "git checkout" and "git merge" replaces
* them using setup_unpack_trees_porcelain(), for example.
*/
-const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
+static const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
/* ERROR_WOULD_OVERWRITE */
"Entry '%s' would be overwritten by merge. Cannot merge.",
if (ce->ce_flags & CE_WT_REMOVE) {
display_progress(progress, ++cnt);
- if (o->update)
+ if (o->update && !o->dry_run)
unlink_entry(ce);
continue;
}
if (ce->ce_flags & CE_UPDATE) {
display_progress(progress, ++cnt);
ce->ce_flags &= ~CE_UPDATE;
- if (o->update) {
+ if (o->update && !o->dry_run) {
errs |= checkout_entry(ce, &state, NULL);
}
}
static int unpack_index_entry(struct cache_entry *ce,
struct unpack_trees_options *o)
{
- struct cache_entry *src[5] = { NULL };
+ struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, };
int ret;
src[0] = ce;
return ret;
}
-static int traverse_trees_recursive(int n, unsigned long dirmask, unsigned long df_conflicts, struct name_entry *names, struct traverse_info *info)
+static int traverse_trees_recursive(int n, unsigned long dirmask,
+ unsigned long df_conflicts,
+ struct name_entry *names,
+ struct traverse_info *info)
{
int i, ret, bottom;
struct tree_desc t[MAX_UNPACK_TREES];
return mask;
}
+static int clear_ce_flags_1(struct cache_entry **cache, int nr,
+ char *prefix, int prefix_len,
+ int select_mask, int clear_mask,
+ struct exclude_list *el, int defval);
+
/* Whole directory matching */
static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
char *prefix, int prefix_len,
char *basename,
int select_mask, int clear_mask,
- struct exclude_list *el)
+ struct exclude_list *el, int defval)
{
- struct cache_entry **cache_end = cache + nr;
+ struct cache_entry **cache_end;
int dtype = DT_DIR;
int ret = excluded_from_list(prefix, prefix_len, basename, &dtype, el);
prefix[prefix_len++] = '/';
- /* included, no clearing for any entries under this directory */
- if (!ret) {
- for (; cache != cache_end; cache++) {
- struct cache_entry *ce = *cache;
- if (strncmp(ce->name, prefix, prefix_len))
- break;
- }
- return nr - (cache_end - cache);
- }
+ /* If undecided, use matching result of parent dir in defval */
+ if (ret < 0)
+ ret = defval;
- /* excluded, clear all selected entries under this directory. */
- if (ret == 1) {
- for (; cache != cache_end; cache++) {
- struct cache_entry *ce = *cache;
- if (select_mask && !(ce->ce_flags & select_mask))
- continue;
- if (strncmp(ce->name, prefix, prefix_len))
- break;
- ce->ce_flags &= ~clear_mask;
- }
- return nr - (cache_end - cache);
+ for (cache_end = cache; cache_end != cache + nr; cache_end++) {
+ struct cache_entry *ce = *cache_end;
+ if (strncmp(ce->name, prefix, prefix_len))
+ break;
}
- return 0;
+ /*
+ * TODO: check el, if there are no patterns that may conflict
+ * with ret (iow, we know in advance the incl/excl
+ * decision for the entire directory), clear flag here without
+ * calling clear_ce_flags_1(). That function will call
+ * the expensive excluded_from_list() on every entry.
+ */
+ return clear_ce_flags_1(cache, cache_end - cache,
+ prefix, prefix_len,
+ select_mask, clear_mask,
+ el, ret);
}
/*
static int clear_ce_flags_1(struct cache_entry **cache, int nr,
char *prefix, int prefix_len,
int select_mask, int clear_mask,
- struct exclude_list *el)
+ struct exclude_list *el, int defval)
{
struct cache_entry **cache_end = cache + nr;
while(cache != cache_end) {
struct cache_entry *ce = *cache;
const char *name, *slash;
- int len, dtype;
+ int len, dtype, ret;
if (select_mask && !(ce->ce_flags & select_mask)) {
cache++;
prefix, prefix_len + len,
prefix + prefix_len,
select_mask, clear_mask,
- el);
+ el, defval);
/* clear_c_f_dir eats a whole dir already? */
if (processed) {
prefix[prefix_len + len++] = '/';
cache += clear_ce_flags_1(cache, cache_end - cache,
prefix, prefix_len + len,
- select_mask, clear_mask, el);
+ select_mask, clear_mask, el, defval);
continue;
}
/* Non-directory */
dtype = ce_to_dtype(ce);
- if (excluded_from_list(ce->name, ce_namelen(ce), name, &dtype, el) > 0)
+ ret = excluded_from_list(ce->name, ce_namelen(ce), name, &dtype, el);
+ if (ret < 0)
+ ret = defval;
+ if (ret > 0)
ce->ce_flags &= ~clear_mask;
cache++;
}
return clear_ce_flags_1(cache, nr,
prefix, 0,
select_mask, clear_mask,
- el);
+ el, 0);
}
/*
}
if (o->result.cache_nr && empty_worktree) {
+ /* dubious---why should this fail??? */
ret = unpack_failed(o, "Sparse checkout leaves no entry on working directory");
goto done;
}
{
struct stat st;
- if (o->index_only || (!((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) && (o->reset || ce_uptodate(ce))))
+ if (o->index_only)
+ return 0;
+
+ /*
+ * CE_VALID and CE_SKIP_WORKTREE cheat, we better check again
+ * if this entry is truly up-to-date because this file may be
+ * overwritten.
+ */
+ if ((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce))
+ ; /* keep checking */
+ else if (o->reset || ce_uptodate(ce))
return 0;
if (!lstat(ce->name, &st)) {
- unsigned changed = ie_match_stat(o->src_index, ce, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
+ int flags = CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE;
+ unsigned changed = ie_match_stat(o->src_index, ce, &st, flags);
if (!changed)
return 0;
/*
char path[PATH_MAX + 1];
memcpy(path, ce->name, len);
path[len] = 0;
- lstat(path, &st);
+ if (lstat(path, &st))
+ return error("cannot stat '%s': %s", path,
+ strerror(errno));
return check_ok_to_remove(path, len, DT_UNKNOWN, NULL, &st,
error_type, o);
- } else if (!lstat(ce->name, &st))
+ } else if (lstat(ce->name, &st)) {
+ if (errno != ENOENT)
+ return error("cannot stat '%s': %s", ce->name,
+ strerror(errno));
+ return 0;
+ } else {
return check_ok_to_remove(ce->name, ce_namelen(ce),
- ce_to_dtype(ce), ce, &st,
- error_type, o);
-
- return 0;
+ ce_to_dtype(ce), ce, &st,
+ error_type, o);
+ }
}
static int verify_absent(struct cache_entry *ce,