Skip to content

Commit

Permalink
Merge pull request #374: Integrate with git status
Browse files Browse the repository at this point in the history
Replaces #367, which used the upstream commits directly. This instead includes a merge commit onto `vfs-2.32.0` so we can move forward even if the upstream version is modified.

This integrates the sparse-index with `git status`. There is a LOT of code here, and much of it makes future changes (#361 and #364) much simpler than they would be otherwise.

This merges into `features/sparse-index` which is intended to be released as an experimental release. The goal of reviewing this PR is to find "good enough for a limited release to dogfooders" and not the same scrutiny of upstream.

In particular, I am currently looking for an issue with directory/file conflicts at the sparse-checkout boundary. They don't reveal themselves until `git checkout`, and only in very rare cases that won't affect our dogfooders.
  • Loading branch information
derrickstolee authored Jun 21, 2021
2 parents b4032c0 + 87a3a29 commit 47cf534
Show file tree
Hide file tree
Showing 10 changed files with 461 additions and 32 deletions.
3 changes: 3 additions & 0 deletions builtin/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -1669,6 +1669,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
16 changes: 16 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,17 @@ static int show_modified(struct rev_info *revs,
unsigned dirty_submodule = 0;
struct index_state *istate = revs->diffopt.repo->index;

/*
* If both are sparse directory entries, then expand the
* modifications to the file level.
*/
if (old_entry && new_entry &&
S_ISSPARSEDIR(old_entry->ce_mode) &&
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
17 changes: 15 additions & 2 deletions dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1452,14 +1452,27 @@ 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.buf + parent_pathname.len - 1;
strbuf_add(&parent_pathname, "-", 1);
} else {
slash_pos = strrchr(parent_pathname.buf, '/');
}

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) {
/* include every file in root */
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 @@ -1598,8 +1598,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 @@ -1614,6 +1613,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
29 changes: 27 additions & 2 deletions 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 @@ -239,7 +261,7 @@ void ensure_full_index(struct index_state *istate)
warning(_("index entry is a directory, but not sparse (%08x)"),
ce->ce_flags);

/* recursively walk into cd->name */
/* recursively walk into ce->name */
tree = lookup_tree(istate->repo, &ce->oid);

memset(&ps, 0, sizeof(ps));
Expand All @@ -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 47cf534

Please sign in to comment.