diff options
Diffstat (limited to 'third_party/git/unpack-trees.c')
-rw-r--r-- | third_party/git/unpack-trees.c | 269 |
1 files changed, 103 insertions, 166 deletions
diff --git a/third_party/git/unpack-trees.c b/third_party/git/unpack-trees.c index 1ecdab330408..62276d4fef5f 100644 --- a/third_party/git/unpack-trees.c +++ b/third_party/git/unpack-trees.c @@ -11,11 +11,12 @@ #include "refs.h" #include "attr.h" #include "split-index.h" +#include "dir.h" #include "submodule.h" #include "submodule-config.h" #include "fsmonitor.h" #include "object-store.h" -#include "promisor-remote.h" +#include "fetch-object.h" /* * Error messages expected by scripts out of plumbing commands such as @@ -275,9 +276,9 @@ static int check_submodule_move_head(const struct cache_entry *ce, } /* - * Perform the loading of the repository's gitmodules file. This function is + * Preform the loading of the repository's gitmodules file. This function is * used by 'check_update()' to perform loading of the gitmodules file in two - * different situations: + * differnt 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 @@ -291,11 +292,11 @@ static void load_gitmodules_file(struct index_state *index, if (pos >= 0) { struct cache_entry *ce = index->cache[pos]; if (!state && ce->ce_flags & CE_WT_REMOVE) { - repo_read_gitmodules(the_repository, 0); + repo_read_gitmodules(the_repository); } else if (state && (ce->ce_flags & CE_UPDATE)) { submodule_free(the_repository); checkout_entry(ce, state, NULL, NULL); - repo_read_gitmodules(the_repository, 0); + repo_read_gitmodules(the_repository); } } } @@ -372,20 +373,15 @@ static int check_updates(struct unpack_trees_options *o) state.refresh_cache = 1; state.istate = index; - if (!o->update || o->dry_run) { - remove_marked_cache_entries(index, 0); - trace_performance_leave("check_updates"); - return 0; - } - if (o->clone) setup_collided_checkout_detection(&state, index); progress = get_progress(o); - git_attr_set_direction(GIT_ATTR_CHECKOUT); + if (o->update) + git_attr_set_direction(GIT_ATTR_CHECKOUT); - if (should_update_submodules()) + if (should_update_submodules() && o->update && !o->dry_run) load_gitmodules_file(index, NULL); for (i = 0; i < index->cache_nr; i++) { @@ -393,18 +389,18 @@ static int check_updates(struct unpack_trees_options *o) if (ce->ce_flags & CE_WT_REMOVE) { display_progress(progress, ++cnt); - unlink_entry(ce); + if (o->update && !o->dry_run) + unlink_entry(ce); } } - remove_marked_cache_entries(index, 0); remove_scheduled_dirs(); - if (should_update_submodules()) + if (should_update_submodules() && o->update && !o->dry_run) load_gitmodules_file(index, &state); enable_delayed_checkout(&state); - if (has_promisor_remote()) { + if (repository_format_partial_clone && o->update && !o->dry_run) { /* * Prefetch the objects that are to be checked out in the loop * below. @@ -423,8 +419,8 @@ static int check_updates(struct unpack_trees_options *o) oid_array_append(&to_fetch, &ce->oid); } if (to_fetch.nr) - promisor_remote_get_direct(the_repository, - to_fetch.oid, to_fetch.nr); + fetch_objects(repository_format_partial_clone, + to_fetch.oid, to_fetch.nr); oid_array_clear(&to_fetch); } for (i = 0; i < index->cache_nr; i++) { @@ -436,12 +432,15 @@ static int check_updates(struct unpack_trees_options *o) ce->name); display_progress(progress, ++cnt); ce->ce_flags &= ~CE_UPDATE; - errs |= checkout_entry(ce, &state, NULL, NULL); + if (o->update && !o->dry_run) { + errs |= checkout_entry(ce, &state, NULL, NULL); + } } } stop_progress(&progress); errs |= finish_delayed_checkout(&state, NULL); - git_attr_set_direction(GIT_ATTR_CHECKIN); + if (o->update) + git_attr_set_direction(GIT_ATTR_CHECKIN); if (o->clone) report_collided_checkout(index); @@ -633,7 +632,7 @@ static int unpack_index_entry(struct cache_entry *ce, return ret; } -static int find_cache_pos(struct traverse_info *, const char *p, size_t len); +static int find_cache_pos(struct traverse_info *, const struct name_entry *); static void restore_cache_bottom(struct traverse_info *info, int bottom) { @@ -652,7 +651,7 @@ static int switch_cache_bottom(struct traverse_info *info) if (o->diff_index_cached) return 0; ret = o->cache_bottom; - pos = find_cache_pos(info->prev, info->name, info->namelen); + pos = find_cache_pos(info->prev, &info->name); if (pos < -1) o->cache_bottom = -2 - pos; @@ -687,21 +686,21 @@ static int index_pos_by_traverse_info(struct name_entry *names, struct traverse_info *info) { struct unpack_trees_options *o = info->data; - struct strbuf name = STRBUF_INIT; + int len = traverse_path_len(info, names); + char *name = xmalloc(len + 1 /* slash */ + 1 /* NUL */); int pos; - strbuf_make_traverse_path(&name, info, names->path, names->pathlen); - strbuf_addch(&name, '/'); - pos = index_name_pos(o->src_index, name.buf, name.len); + make_traverse_path(name, info, names); + name[len++] = '/'; + name[len] = '\0'; + pos = index_name_pos(o->src_index, name, len); if (pos >= 0) BUG("This is a directory and should not exist in index"); pos = -pos - 1; - 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 %d doesn't point to the first entry of %s in index", - pos, name.buf); - strbuf_release(&name); + if (!starts_with(o->src_index->cache[pos]->name, name) || + (pos > 0 && starts_with(o->src_index->cache[pos-1]->name, name))) + BUG("pos must point at the first entry in this directory"); + free(name); return pos; } @@ -812,10 +811,8 @@ static int traverse_trees_recursive(int n, unsigned long dirmask, newinfo = *info; newinfo.prev = info; newinfo.pathspec = info->pathspec; - newinfo.name = p->path; - newinfo.namelen = p->pathlen; - newinfo.mode = p->mode; - newinfo.pathlen = st_add3(newinfo.pathlen, tree_entry_len(p), 1); + newinfo.name = *p; + newinfo.pathlen += tree_entry_len(p) + 1; newinfo.df_conflicts |= df_conflicts; /* @@ -866,18 +863,14 @@ static int traverse_trees_recursive(int n, unsigned long dirmask, * itself - the caller needs to do the final check for the cache * entry having more data at the end! */ -static int do_compare_entry_piecewise(const struct cache_entry *ce, - const struct traverse_info *info, - const char *name, size_t namelen, - unsigned mode) +static int do_compare_entry_piecewise(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n) { - int pathlen, ce_len; + int len, pathlen, ce_len; const char *ce_name; if (info->prev) { int cmp = do_compare_entry_piecewise(ce, info->prev, - info->name, info->namelen, - info->mode); + &info->name); if (cmp) return cmp; } @@ -891,15 +884,15 @@ static int do_compare_entry_piecewise(const struct cache_entry *ce, ce_len -= pathlen; ce_name = ce->name + pathlen; - return df_name_compare(ce_name, ce_len, S_IFREG, name, namelen, mode); + len = tree_entry_len(n); + return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode); } static int do_compare_entry(const struct cache_entry *ce, const struct traverse_info *info, - const char *name, size_t namelen, - unsigned mode) + const struct name_entry *n) { - int pathlen, ce_len; + int len, pathlen, ce_len; const char *ce_name; int cmp; @@ -909,7 +902,7 @@ static int do_compare_entry(const struct cache_entry *ce, * it is quicker to use the precomputed version. */ if (!info->traverse_path) - return do_compare_entry_piecewise(ce, info, name, namelen, mode); + return do_compare_entry_piecewise(ce, info, n); cmp = strncmp(ce->name, info->traverse_path, info->pathlen); if (cmp) @@ -924,12 +917,13 @@ static int do_compare_entry(const struct cache_entry *ce, ce_len -= pathlen; ce_name = ce->name + pathlen; - return df_name_compare(ce_name, ce_len, S_IFREG, name, namelen, mode); + len = tree_entry_len(n); + return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode); } static int compare_entry(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n) { - int cmp = do_compare_entry(ce, info, n->path, n->pathlen, n->mode); + int cmp = do_compare_entry(ce, info, n); if (cmp) return cmp; @@ -937,7 +931,7 @@ static int compare_entry(const struct cache_entry *ce, const struct traverse_inf * Even if the beginning compared identically, the ce should * compare as bigger than a directory leading up to it! */ - return ce_namelen(ce) > traverse_path_len(info, tree_entry_len(n)); + return ce_namelen(ce) > traverse_path_len(info, n); } static int ce_in_traverse_path(const struct cache_entry *ce, @@ -945,8 +939,7 @@ static int ce_in_traverse_path(const struct cache_entry *ce, { if (!info->prev) return 1; - if (do_compare_entry(ce, info->prev, - info->name, info->namelen, info->mode)) + if (do_compare_entry(ce, info->prev, &info->name)) return 0; /* * If ce (blob) is the same name as the path (which is a tree @@ -961,7 +954,7 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info, struct index_state *istate, int is_transient) { - size_t len = traverse_path_len(info, tree_entry_len(n)); + int len = traverse_path_len(info, n); struct cache_entry *ce = is_transient ? make_empty_transient_cache_entry(len) : @@ -971,8 +964,7 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info, ce->ce_flags = create_ce_flags(stage); ce->ce_namelen = len; oidcpy(&ce->oid, &n->oid); - /* len+1 because the cache_entry allocates space for NUL */ - make_traverse_path(ce->name, len + 1, info, n->path, n->pathlen); + make_traverse_path(ce->name, info, n); return ce; } @@ -1065,12 +1057,13 @@ static int unpack_failed(struct unpack_trees_options *o, const char *message) * the directory. */ static int find_cache_pos(struct traverse_info *info, - const char *p, size_t p_len) + const struct name_entry *p) { int pos; 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); for (pos = o->cache_bottom; pos < index->cache_nr; pos++) { const struct cache_entry *ce = index->cache[pos]; @@ -1106,7 +1099,7 @@ static int find_cache_pos(struct traverse_info *info, ce_len = ce_slash - ce_name; else ce_len = ce_namelen(ce) - pfxlen; - cmp = name_compare(p, p_len, ce_name, ce_len); + cmp = name_compare(p->path, p_len, ce_name, ce_len); /* * Exact match; if we have a directory we need to * delay returning it. @@ -1121,7 +1114,7 @@ static int find_cache_pos(struct traverse_info *info, * E.g. ce_name == "t-i", and p->path == "t"; we may * have "t/a" in the index. */ - if (p_len < ce_len && !memcmp(ce_name, p, p_len) && + if (p_len < ce_len && !memcmp(ce_name, p->path, p_len) && ce_name[p_len] < '/') continue; /* keep looking */ break; @@ -1132,7 +1125,7 @@ static int find_cache_pos(struct traverse_info *info, static struct cache_entry *find_cache_entry(struct traverse_info *info, const struct name_entry *p) { - int pos = find_cache_pos(info, p->path, p->pathlen); + int pos = find_cache_pos(info, p); struct unpack_trees_options *o = info->data; if (0 <= pos) @@ -1145,10 +1138,10 @@ static void debug_path(struct traverse_info *info) { if (info->prev) { debug_path(info->prev); - if (*info->prev->name) + if (*info->prev->name.path) putchar('/'); } - printf("%s", info->name); + printf("%s", info->name.path); } static void debug_name_entry(int i, struct name_entry *n) @@ -1272,9 +1265,7 @@ static int clear_ce_flags_1(struct index_state *istate, struct cache_entry **cache, int nr, struct strbuf *prefix, int select_mask, int clear_mask, - struct pattern_list *pl, - enum pattern_match_result default_match, - int progress_nr); + struct exclude_list *el, int defval); /* Whole directory matching */ static int clear_ce_flags_dir(struct index_state *istate, @@ -1282,24 +1273,19 @@ static int clear_ce_flags_dir(struct index_state *istate, struct strbuf *prefix, char *basename, int select_mask, int clear_mask, - struct pattern_list *pl, - enum pattern_match_result default_match, - int progress_nr) + struct exclude_list *el, int defval) { struct cache_entry **cache_end; int dtype = DT_DIR; + int ret = is_excluded_from_list(prefix->buf, prefix->len, + basename, &dtype, el, istate); int rc; - 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 (orig_ret == UNDECIDED) - ret = default_match; - else - ret = orig_ret; + if (ret < 0) + ret = defval; for (cache_end = cache; cache_end != cache + nr; cache_end++) { struct cache_entry *ce = *cache_end; @@ -1307,31 +1293,24 @@ static int clear_ce_flags_dir(struct index_state *istate, break; } - 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); - } - + /* + * 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 is_excluded_from_list() on every entry. + */ + rc = clear_ce_flags_1(istate, cache, cache_end - cache, + prefix, + select_mask, clear_mask, + el, ret); strbuf_setlen(prefix, prefix->len - 1); return rc; } /* * Traverse the index, find every entry that matches according to - * o->pl. Do "ce_flags &= ~clear_mask" on those entries. Return the + * o->el. Do "ce_flags &= ~clear_mask" on those entries. Return the * number of traversed entries. * * If select_mask is non-zero, only entries whose ce_flags has on of @@ -1348,11 +1327,9 @@ static int clear_ce_flags_1(struct index_state *istate, struct cache_entry **cache, int nr, struct strbuf *prefix, int select_mask, int clear_mask, - struct pattern_list *pl, - enum pattern_match_result default_match, - int progress_nr) + struct exclude_list *el, int defval) { - struct cache_entry **cache_end = nr ? cache + nr : cache; + struct cache_entry **cache_end = cache + nr; /* * Process all entries that have the given prefix and meet @@ -1361,14 +1338,10 @@ static int clear_ce_flags_1(struct index_state *istate, while(cache != cache_end) { struct cache_entry *ce = *cache; const char *name, *slash; - int len, dtype; - enum pattern_match_result ret; - - display_progress(istate->progress, progress_nr); + int len, dtype, ret; if (select_mask && !(ce->ce_flags & select_mask)) { cache++; - progress_nr++; continue; } @@ -1389,84 +1362,58 @@ static int clear_ce_flags_1(struct index_state *istate, prefix, prefix->buf + prefix->len - len, select_mask, clear_mask, - pl, default_match, - progress_nr); + el, defval); /* 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, '/'); - 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; - + cache += clear_ce_flags_1(istate, cache, cache_end - cache, + prefix, + select_mask, clear_mask, el, defval); strbuf_setlen(prefix, prefix->len - len - 1); continue; } /* Non-directory */ dtype = ce_to_dtype(ce); - ret = path_matches_pattern_list(ce->name, - ce_namelen(ce), - name, &dtype, pl, istate); - if (ret == UNDECIDED) - ret = default_match; - if (ret == MATCHED || ret == MATCHED_RECURSIVE) + ret = is_excluded_from_list(ce->name, ce_namelen(ce), + name, &dtype, el, istate); + if (ret < 0) + ret = defval; + if (ret > 0) 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, - int show_progress) + struct exclude_list *el) { static struct strbuf prefix = STRBUF_INIT; - char label[100]; - int rval; strbuf_reset(&prefix); - 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, + + return clear_ce_flags_1(istate, istate->cache, istate->cache_nr, &prefix, select_mask, clear_mask, - pl, 0, 0); - trace2_region_leave("unpack_trees", label, the_repository); - - stop_progress(&istate->progress); - return rval; + el, 0); } /* * Set/Clear CE_NEW_SKIP_WORKTREE according to $GIT_DIR/info/sparse-checkout */ -static void mark_new_skip_worktree(struct pattern_list *pl, +static void mark_new_skip_worktree(struct exclude_list *el, struct index_state *istate, - int select_flag, int skip_wt_flag, - int show_progress) + int select_flag, int skip_wt_flag) { int i; @@ -1490,7 +1437,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, show_progress); + clear_ce_flags(istate, select_flag, skip_wt_flag, el); } static int verify_absent(const struct cache_entry *, @@ -1506,22 +1453,21 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options { int i, ret; static struct cache_entry *dfc; - struct pattern_list pl; + struct exclude_list el; if (len > MAX_UNPACK_TREES) die("unpack_trees takes at most %d trees", MAX_UNPACK_TREES); trace_performance_enter(); - memset(&pl, 0, sizeof(pl)); + memset(&el, 0, sizeof(el)); if (!core_apply_sparse_checkout || !o->update) o->skip_sparse_checkout = 1; - if (!o->skip_sparse_checkout && !o->pl) { + if (!o->skip_sparse_checkout) { 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) + if (add_excludes_from_file_to_list(sparse, "", 0, &el, NULL) < 0) o->skip_sparse_checkout = 1; else - o->pl = &pl; + o->el = ⪙ free(sparse); } @@ -1548,15 +1494,11 @@ 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, o->verbose_update); + mark_new_skip_worktree(o->el, o->src_index, 0, CE_NEW_SKIP_WORKTREE); if (!dfc) dfc = xcalloc(1, cache_entry_size(0)); @@ -1621,9 +1563,7 @@ 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, - o->verbose_update); + 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++) { @@ -1691,8 +1631,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options done: trace_performance_leave("unpack_trees"); - if (!o->keep_pattern_list) - clear_pattern_list(&pl); + clear_exclude_list(&el); return ret; return_failed: @@ -2111,8 +2050,7 @@ static int merged_entry(const struct cache_entry *ce, invalidate_ce_path(old, o); } - if (do_add_entry(o, merge, update, CE_STAGEMASK) < 0) - return -1; + do_add_entry(o, merge, update, CE_STAGEMASK); return 1; } @@ -2436,8 +2374,7 @@ 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) && - !(old->ce_flags & CE_FSMONITOR_VALID)) { + if (o->reset && o->update && !ce_uptodate(old) && !ce_skip_worktree(old)) { 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)) |