diff options
Diffstat (limited to 'unpack-trees.c')
-rw-r--r-- | unpack-trees.c | 203 |
1 files changed, 93 insertions, 110 deletions
diff --git a/unpack-trees.c b/unpack-trees.c index 149bc5d358..f0ac24b9f5 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -16,7 +16,7 @@ * 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.", @@ -102,21 +102,28 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts, opts->unpack_rejects[i].strdup_strings = 1; } -static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce, - unsigned int set, unsigned int clear) +static void do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce, + unsigned int set, unsigned int clear) { - unsigned int size = ce_size(ce); - struct cache_entry *new = xmalloc(size); - clear |= CE_HASHED | CE_UNHASHED; if (set & CE_REMOVE) set |= CE_WT_REMOVE; + ce->next = NULL; + ce->ce_flags = (ce->ce_flags & ~clear) | set; + add_index_entry(&o->result, ce, + ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE); +} + +static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce, + unsigned int set, unsigned int clear) +{ + unsigned int size = ce_size(ce); + struct cache_entry *new = xmalloc(size); + memcpy(new, ce, size); - new->next = NULL; - new->ce_flags = (new->ce_flags & ~clear) | set; - add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); + do_add_entry(o, new, set, clear); } /* @@ -159,7 +166,7 @@ static void display_error_msgs(struct unpack_trees_options *o) string_list_clear(rejects, 0); } if (something_displayed) - printf("Aborting\n"); + fprintf(stderr, "Aborting\n"); } /* @@ -203,7 +210,7 @@ static int check_updates(struct unpack_trees_options *o) if (ce->ce_flags & CE_WT_REMOVE) { display_progress(progress, ++cnt); - if (o->update) + if (o->update && !o->dry_run) unlink_entry(ce); continue; } @@ -217,7 +224,7 @@ static int check_updates(struct unpack_trees_options *o) 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); } } @@ -427,10 +434,6 @@ static int switch_cache_bottom(struct traverse_info *info) return ret; } -static int fast_forward_merge(int n, unsigned long dirmask, - 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, @@ -442,19 +445,15 @@ static int traverse_trees_recursive(int n, unsigned long dirmask, struct traverse_info newinfo; struct name_entry *p; - if (!df_conflicts) { - int status = fast_forward_merge(n, dirmask, names, info); - if (status) - return status; - } p = names; while (!p->mode) p++; newinfo = *info; newinfo.prev = info; + newinfo.pathspec = info->pathspec; newinfo.name = *p; - newinfo.pathlen += tree_entry_len(p->path, p->sha1) + 1; + newinfo.pathlen += tree_entry_len(p) + 1; newinfo.conflicts |= df_conflicts; for (i = 0; i < n; i++, dirmask >>= 1) { @@ -503,7 +502,7 @@ static int do_compare_entry(const struct cache_entry *ce, const struct traverse_ ce_len -= pathlen; ce_name = ce->name + pathlen; - len = tree_entry_len(n->path, n->sha1); + len = tree_entry_len(n); return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode); } @@ -595,14 +594,14 @@ static int unpack_nondirectories(int n, unsigned long mask, for (i = 0; i < n; i++) if (src[i] && src[i] != o->df_conflict_entry) - add_entry(o, src[i], 0, 0); + do_add_entry(o, src[i], 0, 0); return 0; } static int unpack_failed(struct unpack_trees_options *o, const char *message) { discard_index(&o->result); - if (!o->gently) { + if (!o->gently && !o->exiting_early) { if (message) return error("%s", message); return -1; @@ -634,7 +633,7 @@ static int find_cache_pos(struct traverse_info *info, struct unpack_trees_options *o = info->data; struct index_state *index = o->src_index; int pfxlen = info->pathlen; - int p_len = tree_entry_len(p->path, p->sha1); + int p_len = tree_entry_len(p); for (pos = o->cache_bottom; pos < index->cache_nr; pos++) { struct cache_entry *ce = index->cache[pos]; @@ -694,53 +693,6 @@ static struct cache_entry *find_cache_entry(struct traverse_info *info, return NULL; } -static int fast_forward_merge(int n, unsigned long dirmask, - struct name_entry *names, - struct traverse_info *info) -{ - int i; - struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, }; - struct unpack_trees_options *o = info->data; - - /* merging two or more trees with an identical subdirectory? */ - if ((n < 2) || ((1UL << n) - 1) != dirmask || - !o->merge || o->reset || o->initial_checkout) - return 0; - for (i = 1; i < n; i++) - if (hashcmp(names[i-1].sha1, names[i].sha1)) - return 0; - - /* - * Instead of descending into the directory, keep the contents - * of the current index. - */ - while (1) { - struct cache_entry *ce; - ce = next_cache_entry(o); - if (!ce) - break; - /* Is the entry still in that directory? */ - if (do_compare_entry(ce, info, names)) - break; - /* - * Note: we do not just run unpack_index_entry() here, - * as the callback may want to compare what is in the - * index with what are from the HEAD and the other tree - * and reject the merge. We pretend that ancestors, the - * HEAD and the other tree all have the same contents as - * the current index, which is a lie, but it works. - */ - for (i = 0; i < n + 1; i++) - src[i] = ce; - mark_ce_used(ce, o); - if (call_unpack_fn(src, o) < 0) - return unpack_failed(o, NULL); - if (ce_stage(ce)) - mark_ce_used_same_name(ce, o); - } - return dirmask; -} - static void debug_path(struct traverse_info *info) { if (info->prev) { @@ -827,7 +779,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str if (unpack_nondirectories(n, mask, dirmask, src, names, info) < 0) return -1; - if (src[0]) { + if (o->merge && src[0]) { if (ce_stage(src[0])) mark_ce_used_same_name(src[0], o); else @@ -870,43 +822,45 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str 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); } /* @@ -927,7 +881,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr, 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; @@ -938,7 +892,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int 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++; @@ -967,7 +921,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr, 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) { @@ -978,13 +932,16 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr, 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++; } @@ -999,7 +956,7 @@ static int clear_ce_flags(struct cache_entry **cache, int nr, return clear_ce_flags_1(cache, nr, prefix, 0, select_mask, clear_mask, - el); + el, 0); } /* @@ -1091,6 +1048,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options info.fn = unpack_callback; info.data = o; info.show_all_errors = o->show_all_errors; + info.pathspec = o->pathspec; if (o->prefix) { /* @@ -1140,6 +1098,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options */ mark_new_skip_worktree(o->el, &o->result, CE_ADDED, CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE); + ret = 0; for (i = 0; i < o->result.cache_nr; i++) { struct cache_entry *ce = o->result.cache[i]; @@ -1152,19 +1111,30 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options * correct CE_NEW_SKIP_WORKTREE */ if (ce->ce_flags & CE_ADDED && - verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o)) - return -1; + verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o)) { + if (!o->show_all_errors) + goto return_failed; + ret = -1; + } if (apply_sparse_checkout(ce, o)) { + if (!o->show_all_errors) + goto return_failed; ret = -1; - goto done; } if (!ce_skip_worktree(ce)) empty_worktree = 0; } + if (ret < 0) + goto return_failed; + /* + * Sparse checkout is meant to narrow down checkout area + * but it does not make sense to narrow down to empty working + * tree. This is usually a mistake in sparse checkout rules. + * Do not allow users to do that. + */ 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; } @@ -1184,6 +1154,8 @@ return_failed: display_error_msgs(o); mark_all_ce_unused(o->src_index); ret = unpack_failed(o, NULL); + if (o->exiting_early) + ret = 0; goto done; } @@ -1217,16 +1189,27 @@ static int verify_uptodate_1(struct cache_entry *ce, { 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; /* * NEEDSWORK: the current default policy is to allow - * submodule to be out of sync wrt the supermodule + * submodule to be out of sync wrt the superproject * index. This needs to be tightened later for * submodules that are marked to be automatically * checked out. |