diff options
author | Junio C Hamano <gitster@pobox.com> | 2022-03-09 22:38:23 +0100 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2022-03-09 22:38:23 +0100 |
commit | 82386b44963f127d6dbe25d48889bde3149e177c (patch) | |
tree | 56659c554f71478bd7ab0635fc23438faa760f91 /sparse-index.c | |
parent | The ninth batch (diff) | |
parent | repo_read_index: add config to expect files outside sparse patterns (diff) | |
download | git-82386b44963f127d6dbe25d48889bde3149e177c.tar.xz git-82386b44963f127d6dbe25d48889bde3149e177c.zip |
Merge branch 'en/present-despite-skipped'
In sparse-checkouts, files mis-marked as missing from the working tree
could lead to later problems. Such files were hard to discover, and
harder to correct. Automatically detecting and correcting the marking
of such files has been added to avoid these problems.
* en/present-despite-skipped:
repo_read_index: add config to expect files outside sparse patterns
Accelerate clear_skip_worktree_from_present_files() by caching
Update documentation related to sparsity and the skip-worktree bit
repo_read_index: clear SKIP_WORKTREE bit from files present in worktree
unpack-trees: fix accidental loss of user changes
t1011: add testcase demonstrating accidental loss of user modifications
Diffstat (limited to 'sparse-index.c')
-rw-r--r-- | sparse-index.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/sparse-index.c b/sparse-index.c index fdbe97b976..8636af72de 100644 --- a/sparse-index.c +++ b/sparse-index.c @@ -337,6 +337,80 @@ void ensure_correct_sparsity(struct index_state *istate) ensure_full_index(istate); } +static int path_found(const char *path, const char **dirname, size_t *dir_len, + int *dir_found) +{ + struct stat st; + char *newdir; + char *tmp; + + /* + * If dirname corresponds to a directory that doesn't exist, and this + * path starts with dirname, then path can't exist. + */ + if (!*dir_found && !memcmp(path, *dirname, *dir_len)) + return 0; + + /* + * If path itself exists, return 1. + */ + if (!lstat(path, &st)) + return 1; + + /* + * Otherwise, path does not exist so we'll return 0...but we'll first + * determine some info about its parent directory so we can avoid + * lstat calls for future cache entries. + */ + newdir = strrchr(path, '/'); + if (!newdir) + return 0; /* Didn't find a parent dir; just return 0 now. */ + + /* + * If path starts with directory (which we already lstat'ed and found), + * then no need to lstat parent directory again. + */ + if (*dir_found && *dirname && memcmp(path, *dirname, *dir_len)) + return 0; + + /* Free previous dirname, and cache path's dirname */ + *dirname = path; + *dir_len = newdir - path + 1; + + tmp = xstrndup(path, *dir_len); + *dir_found = !lstat(tmp, &st); + free(tmp); + + return 0; +} + +void clear_skip_worktree_from_present_files(struct index_state *istate) +{ + const char *last_dirname = NULL; + size_t dir_len = 0; + int dir_found = 1; + + int i; + + if (!core_apply_sparse_checkout || + sparse_expect_files_outside_of_patterns) + return; + +restart: + for (i = 0; i < istate->cache_nr; i++) { + struct cache_entry *ce = istate->cache[i]; + + if (ce_skip_worktree(ce) && + path_found(ce->name, &last_dirname, &dir_len, &dir_found)) { + if (S_ISSPARSEDIR(ce->ce_mode)) { + ensure_full_index(istate); + goto restart; + } + ce->ce_flags &= ~CE_SKIP_WORKTREE; + } + } +} + /* * This static global helps avoid infinite recursion between * expand_to_path() and index_file_exists(). |