summaryrefslogtreecommitdiff
path: root/unpack-trees.c
diff options
context:
space:
mode:
Diffstat (limited to 'unpack-trees.c')
-rw-r--r--unpack-trees.c128
1 files changed, 89 insertions, 39 deletions
diff --git a/unpack-trees.c b/unpack-trees.c
index 2de6368b06..70247aa331 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -275,9 +275,9 @@ static int check_submodule_move_head(const struct cache_entry *ce,
}
/*
- * Preform the loading of the repository's gitmodules file. This function is
+ * Perform the loading of the repository's gitmodules file. This function is
* used by 'check_update()' to perform loading of the gitmodules file in two
- * differnt situations:
+ * different situations:
* (1) before removing entries from the working tree if the gitmodules file has
* been marked for removal. This situation is specified by 'state' == NULL.
* (2) before checking out entries to the working tree if the gitmodules file
@@ -694,9 +694,11 @@ static int index_pos_by_traverse_info(struct name_entry *names,
if (pos >= 0)
BUG("This is a directory and should not exist in index");
pos = -pos - 1;
- if (!starts_with(o->src_index->cache[pos]->name, name.buf) ||
+ if (pos >= o->src_index->cache_nr ||
+ !starts_with(o->src_index->cache[pos]->name, name.buf) ||
(pos > 0 && starts_with(o->src_index->cache[pos-1]->name, name.buf)))
- BUG("pos must point at the first entry in this directory");
+ BUG("pos %d doesn't point to the first entry of %s in index",
+ pos, name.buf);
strbuf_release(&name);
return pos;
}
@@ -1269,7 +1271,8 @@ static int clear_ce_flags_1(struct index_state *istate,
struct strbuf *prefix,
int select_mask, int clear_mask,
struct pattern_list *pl,
- enum pattern_match_result default_match);
+ enum pattern_match_result default_match,
+ int progress_nr);
/* Whole directory matching */
static int clear_ce_flags_dir(struct index_state *istate,
@@ -1278,20 +1281,23 @@ static int clear_ce_flags_dir(struct index_state *istate,
char *basename,
int select_mask, int clear_mask,
struct pattern_list *pl,
- enum pattern_match_result default_match)
+ enum pattern_match_result default_match,
+ int progress_nr)
{
struct cache_entry **cache_end;
int dtype = DT_DIR;
int rc;
- enum pattern_match_result ret;
- ret = path_matches_pattern_list(prefix->buf, prefix->len,
- basename, &dtype, pl, istate);
+ enum pattern_match_result ret, orig_ret;
+ orig_ret = path_matches_pattern_list(prefix->buf, prefix->len,
+ basename, &dtype, pl, istate);
strbuf_addch(prefix, '/');
/* If undecided, use matching result of parent dir in defval */
- if (ret == UNDECIDED)
+ if (orig_ret == UNDECIDED)
ret = default_match;
+ else
+ ret = orig_ret;
for (cache_end = cache; cache_end != cache + nr; cache_end++) {
struct cache_entry *ce = *cache_end;
@@ -1299,17 +1305,24 @@ static int clear_ce_flags_dir(struct index_state *istate,
break;
}
- /*
- * TODO: check pl, 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 path_matches_pattern_list() on every entry.
- */
- rc = clear_ce_flags_1(istate, cache, cache_end - cache,
- prefix,
- select_mask, clear_mask,
- pl, ret);
+ if (pl->use_cone_patterns && orig_ret == MATCHED_RECURSIVE) {
+ struct cache_entry **ce = cache;
+ rc = cache_end - cache;
+
+ while (ce < cache_end) {
+ (*ce)->ce_flags &= ~clear_mask;
+ ce++;
+ }
+ } else if (pl->use_cone_patterns && orig_ret == NOT_MATCHED) {
+ rc = cache_end - cache;
+ } else {
+ rc = clear_ce_flags_1(istate, cache, cache_end - cache,
+ prefix,
+ select_mask, clear_mask,
+ pl, ret,
+ progress_nr);
+ }
+
strbuf_setlen(prefix, prefix->len - 1);
return rc;
}
@@ -1334,9 +1347,10 @@ static int clear_ce_flags_1(struct index_state *istate,
struct strbuf *prefix,
int select_mask, int clear_mask,
struct pattern_list *pl,
- enum pattern_match_result default_match)
+ enum pattern_match_result default_match,
+ int progress_nr)
{
- struct cache_entry **cache_end = cache + nr;
+ struct cache_entry **cache_end = nr ? cache + nr : cache;
/*
* Process all entries that have the given prefix and meet
@@ -1348,8 +1362,11 @@ static int clear_ce_flags_1(struct index_state *istate,
int len, dtype;
enum pattern_match_result ret;
+ display_progress(istate->progress, progress_nr);
+
if (select_mask && !(ce->ce_flags & select_mask)) {
cache++;
+ progress_nr++;
continue;
}
@@ -1370,20 +1387,26 @@ static int clear_ce_flags_1(struct index_state *istate,
prefix,
prefix->buf + prefix->len - len,
select_mask, clear_mask,
- pl, default_match);
+ pl, default_match,
+ progress_nr);
/* clear_c_f_dir eats a whole dir already? */
if (processed) {
cache += processed;
+ progress_nr += processed;
strbuf_setlen(prefix, prefix->len - len);
continue;
}
strbuf_addch(prefix, '/');
- cache += clear_ce_flags_1(istate, cache, cache_end - cache,
- prefix,
- select_mask, clear_mask, pl,
- default_match);
+ processed = clear_ce_flags_1(istate, cache, cache_end - cache,
+ prefix,
+ select_mask, clear_mask, pl,
+ default_match, progress_nr);
+
+ cache += processed;
+ progress_nr += processed;
+
strbuf_setlen(prefix, prefix->len - len - 1);
continue;
}
@@ -1398,24 +1421,41 @@ static int clear_ce_flags_1(struct index_state *istate,
if (ret == MATCHED)
ce->ce_flags &= ~clear_mask;
cache++;
+ progress_nr++;
}
+
+ display_progress(istate->progress, progress_nr);
return nr - (cache_end - cache);
}
static int clear_ce_flags(struct index_state *istate,
int select_mask, int clear_mask,
- struct pattern_list *pl)
+ struct pattern_list *pl,
+ int show_progress)
{
static struct strbuf prefix = STRBUF_INIT;
+ char label[100];
+ int rval;
strbuf_reset(&prefix);
-
- return clear_ce_flags_1(istate,
+ if (show_progress)
+ istate->progress = start_delayed_progress(
+ _("Updating index flags"),
+ istate->cache_nr);
+
+ xsnprintf(label, sizeof(label), "clear_ce_flags(0x%08lx,0x%08lx)",
+ (unsigned long)select_mask, (unsigned long)clear_mask);
+ trace2_region_enter("unpack_trees", label, the_repository);
+ rval = clear_ce_flags_1(istate,
istate->cache,
istate->cache_nr,
&prefix,
select_mask, clear_mask,
- pl, 0);
+ pl, 0, 0);
+ trace2_region_leave("unpack_trees", label, the_repository);
+
+ stop_progress(&istate->progress);
+ return rval;
}
/*
@@ -1423,7 +1463,8 @@ static int clear_ce_flags(struct index_state *istate,
*/
static void mark_new_skip_worktree(struct pattern_list *pl,
struct index_state *istate,
- int select_flag, int skip_wt_flag)
+ int select_flag, int skip_wt_flag,
+ int show_progress)
{
int i;
@@ -1447,7 +1488,7 @@ static void mark_new_skip_worktree(struct pattern_list *pl,
* 2. Widen worktree according to sparse-checkout file.
* Matched entries will have skip_wt_flag cleared (i.e. "in")
*/
- clear_ce_flags(istate, select_flag, skip_wt_flag, pl);
+ clear_ce_flags(istate, select_flag, skip_wt_flag, pl, show_progress);
}
static int verify_absent(const struct cache_entry *,
@@ -1472,8 +1513,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
memset(&pl, 0, sizeof(pl));
if (!core_apply_sparse_checkout || !o->update)
o->skip_sparse_checkout = 1;
- if (!o->skip_sparse_checkout) {
+ if (!o->skip_sparse_checkout && !o->pl) {
char *sparse = git_pathdup("info/sparse-checkout");
+ pl.use_cone_patterns = core_sparse_checkout_cone;
if (add_patterns_from_file_to_list(sparse, "", 0, &pl, NULL) < 0)
o->skip_sparse_checkout = 1;
else
@@ -1504,11 +1546,15 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
o->merge_size = len;
mark_all_ce_unused(o->src_index);
+ if (o->src_index->fsmonitor_last_update)
+ o->result.fsmonitor_last_update = o->src_index->fsmonitor_last_update;
+
/*
* Sparse checkout loop #1: set NEW_SKIP_WORKTREE on existing entries
*/
if (!o->skip_sparse_checkout)
- mark_new_skip_worktree(o->pl, o->src_index, 0, CE_NEW_SKIP_WORKTREE);
+ mark_new_skip_worktree(o->pl, o->src_index, 0,
+ CE_NEW_SKIP_WORKTREE, o->verbose_update);
if (!dfc)
dfc = xcalloc(1, cache_entry_size(0));
@@ -1573,7 +1619,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
* If the will have NEW_SKIP_WORKTREE, also set CE_SKIP_WORKTREE
* so apply_sparse_checkout() won't attempt to remove it from worktree
*/
- mark_new_skip_worktree(o->pl, &o->result, CE_ADDED, CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
+ mark_new_skip_worktree(o->pl, &o->result,
+ CE_ADDED, CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE,
+ o->verbose_update);
ret = 0;
for (i = 0; i < o->result.cache_nr; i++) {
@@ -1641,7 +1689,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
done:
trace_performance_leave("unpack_trees");
- clear_pattern_list(&pl);
+ if (!o->keep_pattern_list)
+ clear_pattern_list(&pl);
return ret;
return_failed:
@@ -2385,7 +2434,8 @@ int oneway_merge(const struct cache_entry * const *src,
if (old && same(old, a)) {
int update = 0;
- if (o->reset && o->update && !ce_uptodate(old) && !ce_skip_worktree(old)) {
+ if (o->reset && o->update && !ce_uptodate(old) && !ce_skip_worktree(old) &&
+ !(old->ce_flags & CE_FSMONITOR_VALID)) {
struct stat st;
if (lstat(old->name, &st) ||
ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE))