Skip to content

Commit

Permalink
Merge branch 'ds/status-with-sparse-index'
Browse files Browse the repository at this point in the history
"git status" codepath learned to work with sparsely populated index
without hydrating it fully.

* ds/status-with-sparse-index:
  t1092: document bad sparse-checkout behavior
  fsmonitor: integrate with sparse index
  wt-status: expand added sparse directory entries
  status: use sparse-index throughout
  status: skip sparse-checkout percentage with sparse-index
  diff-lib: handle index diffs with sparse dirs
  dir.c: accept a directory as part of cone-mode patterns
  unpack-trees: unpack sparse directory entries
  unpack-trees: rename unpack_nondirectories()
  unpack-trees: compare sparse directories correctly
  unpack-trees: preserve cache_bottom
  t1092: add tests for status/add and sparse files
  t1092: expand repository data shape
  t1092: replace incorrect 'echo' with 'cat'
  sparse-index: include EXTENDED flag when expanding
  sparse-index: skip indexes with unmerged entries
  • Loading branch information
gitster committed Jul 28, 2021
2 parents 6d56fb2 + e5ca291 commit b271a30
Show file tree
Hide file tree
Showing 10 changed files with 470 additions and 38 deletions.
3 changes: 3 additions & 0 deletions builtin/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -1517,6 +1517,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_status_usage, builtin_status_options);

prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;

status_init_config(&s, git_status_config);
argc = parse_options(argc, argv, prefix,
builtin_status_options,
Expand Down
19 changes: 19 additions & 0 deletions diff-lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,11 @@ static void show_new_file(struct rev_info *revs,
unsigned dirty_submodule = 0;
struct index_state *istate = revs->diffopt.repo->index;

if (new_file && S_ISSPARSEDIR(new_file->ce_mode)) {
diff_tree_oid(NULL, &new_file->oid, new_file->name, &revs->diffopt);
return;
}

/*
* New file in the index: it might actually be different in
* the working tree.
Expand All @@ -347,6 +352,20 @@ static int show_modified(struct rev_info *revs,
unsigned dirty_submodule = 0;
struct index_state *istate = revs->diffopt.repo->index;

assert(S_ISSPARSEDIR(old_entry->ce_mode) ==
S_ISSPARSEDIR(new_entry->ce_mode));

/*
* If both are sparse directory entries, then expand the
* modifications to the file level. If only one was a sparse
* directory, then they appear as an add and delete instead of
* a modification.
*/
if (S_ISSPARSEDIR(new_entry->ce_mode)) {
diff_tree_oid(&old_entry->oid, &new_entry->oid, new_entry->name, &revs->diffopt);
return 0;
}

if (get_stat_data(istate, new_entry, &oid, &mode, cached, match_missing,
&dirty_submodule, &revs->diffopt) < 0) {
if (report_missing)
Expand Down
24 changes: 19 additions & 5 deletions dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1380,7 +1380,7 @@ enum pattern_match_result path_matches_pattern_list(
struct path_pattern *pattern;
struct strbuf parent_pathname = STRBUF_INIT;
int result = NOT_MATCHED;
const char *slash_pos;
size_t slash_pos;

if (!pl->use_cone_patterns) {
pattern = last_matching_pattern_from_list(pathname, pathlen, basename,
Expand All @@ -1401,21 +1401,35 @@ enum pattern_match_result path_matches_pattern_list(
strbuf_addch(&parent_pathname, '/');
strbuf_add(&parent_pathname, pathname, pathlen);

/*
* Directory entries are matched if and only if a file
* contained immediately within them is matched. For the
* case of a directory entry, modify the path to create
* a fake filename within this directory, allowing us to
* use the file-base matching logic in an equivalent way.
*/
if (parent_pathname.len > 0 &&
parent_pathname.buf[parent_pathname.len - 1] == '/') {
slash_pos = parent_pathname.len - 1;
strbuf_add(&parent_pathname, "-", 1);
} else {
const char *slash_ptr = strrchr(parent_pathname.buf, '/');
slash_pos = slash_ptr ? slash_ptr - parent_pathname.buf : 0;
}

if (hashmap_contains_path(&pl->recursive_hashmap,
&parent_pathname)) {
result = MATCHED_RECURSIVE;
goto done;
}

slash_pos = strrchr(parent_pathname.buf, '/');

if (slash_pos == parent_pathname.buf) {
if (!slash_pos) {
/* include every file in root */
result = MATCHED;
goto done;
}

strbuf_setlen(&parent_pathname, slash_pos - parent_pathname.buf);
strbuf_setlen(&parent_pathname, slash_pos);

if (hashmap_contains_path(&pl->parent_hashmap, &parent_pathname)) {
result = MATCHED;
Expand Down
10 changes: 8 additions & 2 deletions read-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -1585,8 +1585,7 @@ int refresh_index(struct index_state *istate, unsigned int flags,
*/
preload_index(istate, pathspec, 0);
trace2_region_enter("index", "refresh", NULL);
/* TODO: audit for interaction with sparse-index. */
ensure_full_index(istate);

for (i = 0; i < istate->cache_nr; i++) {
struct cache_entry *ce, *new_entry;
int cache_errno = 0;
Expand All @@ -1601,6 +1600,13 @@ int refresh_index(struct index_state *istate, unsigned int flags,
if (ignore_skip_worktree && ce_skip_worktree(ce))
continue;

/*
* If this entry is a sparse directory, then there isn't
* any stat() information to update. Ignore the entry.
*/
if (S_ISSPARSEDIR(ce->ce_mode))
continue;

if (pathspec && !ce_path_match(istate, ce, pathspec, seen))
filtered = 1;

Expand Down
27 changes: 26 additions & 1 deletion sparse-index.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,17 @@ int set_sparse_index_config(struct repository *repo, int enable)
return res;
}

static int index_has_unmerged_entries(struct index_state *istate)
{
int i;
for (i = 0; i < istate->cache_nr; i++) {
if (ce_stage(istate->cache[i]))
return 1;
}

return 0;
}

int convert_to_sparse(struct index_state *istate)
{
int test_env;
Expand Down Expand Up @@ -152,6 +163,13 @@ int convert_to_sparse(struct index_state *istate)
return -1;
}

/*
* NEEDSWORK: If we have unmerged entries, then stay full.
* Unmerged entries prevent the cache-tree extension from working.
*/
if (index_has_unmerged_entries(istate))
return 0;

if (cache_tree_update(istate, 0)) {
warning(_("unable to update cache-tree, staying full"));
return -1;
Expand All @@ -168,6 +186,10 @@ int convert_to_sparse(struct index_state *istate)
cache_tree_free(&istate->cache_tree);
cache_tree_update(istate, 0);

istate->fsmonitor_has_run_once = 0;
FREE_AND_NULL(istate->fsmonitor_dirty);
FREE_AND_NULL(istate->fsmonitor_last_update);

istate->sparse_index = 1;
trace2_region_leave("index", "convert_to_sparse", istate->repo);
return 0;
Expand Down Expand Up @@ -195,7 +217,7 @@ static int add_path_to_index(const struct object_id *oid,
strbuf_addstr(base, path);

ce = make_cache_entry(istate, mode, oid, base->buf, 0, 0);
ce->ce_flags |= CE_SKIP_WORKTREE;
ce->ce_flags |= CE_SKIP_WORKTREE | CE_EXTENDED;
set_index_entry(istate, istate->cache_nr++, ce);

strbuf_setlen(base, len);
Expand Down Expand Up @@ -264,6 +286,9 @@ void ensure_full_index(struct index_state *istate)
istate->cache = full->cache;
istate->cache_nr = full->cache_nr;
istate->cache_alloc = full->cache_alloc;
istate->fsmonitor_has_run_once = 0;
FREE_AND_NULL(istate->fsmonitor_dirty);
FREE_AND_NULL(istate->fsmonitor_last_update);

strbuf_release(&base);
free(full);
Expand Down
Loading

0 comments on commit b271a30

Please sign in to comment.