Skip to content

Commit 596b5ac

Browse files
committed
Update features/sparse-index with vfs-2.32.0
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
2 parents 01e0fe8 + be0f3ff commit 596b5ac

18 files changed

+598
-77
lines changed

builtin/add.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
528528
add_new_files = !take_worktree_changes && !refresh_only && !add_renormalize;
529529
require_pathspec = !(take_worktree_changes || (0 < addremove_explicit));
530530

531+
prepare_repo_settings(the_repository);
532+
the_repository->settings.command_requires_full_index = 0;
533+
531534
hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
532535

533536
/*

builtin/checkout.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -379,9 +379,6 @@ static int checkout_worktree(const struct checkout_opts *opts,
379379
if (pc_workers > 1)
380380
init_parallel_checkout();
381381

382-
/* TODO: audit for interaction with sparse-index. */
383-
ensure_full_index(&the_index);
384-
385382
enable_fscache(active_nr);
386383
for (pos = 0; pos < active_nr; pos++) {
387384
struct cache_entry *ce = active_cache[pos];
@@ -533,8 +530,6 @@ static int checkout_paths(const struct checkout_opts *opts,
533530
* Make sure all pathspecs participated in locating the paths
534531
* to be checked out.
535532
*/
536-
/* TODO: audit for interaction with sparse-index. */
537-
ensure_full_index(&the_index);
538533
for (pos = 0; pos < active_nr; pos++)
539534
if (opts->overlay_mode)
540535
mark_ce_for_checkout_overlay(active_cache[pos],
@@ -1604,6 +1599,9 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
16041599

16051600
git_config(git_checkout_config, opts);
16061601

1602+
prepare_repo_settings(the_repository);
1603+
the_repository->settings.command_requires_full_index = 0;
1604+
16071605
opts->track = BRANCH_TRACK_UNSPECIFIED;
16081606

16091607
if (!opts->accept_pathspec && !opts->accept_ref)

builtin/commit.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,6 +1669,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
16691669
if (argc == 2 && !strcmp(argv[1], "-h"))
16701670
usage_with_options(builtin_status_usage, builtin_status_options);
16711671

1672+
prepare_repo_settings(the_repository);
1673+
the_repository->settings.command_requires_full_index = 0;
1674+
16721675
status_init_config(&s, git_status_config);
16731676
argc = parse_options(argc, argv, prefix,
16741677
builtin_status_options,
@@ -1937,6 +1940,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
19371940
if (argc == 2 && !strcmp(argv[1], "-h"))
19381941
usage_with_options(builtin_commit_usage, builtin_commit_options);
19391942

1943+
prepare_repo_settings(the_repository);
1944+
the_repository->settings.command_requires_full_index = 0;
1945+
19401946
status_init_config(&s, git_commit_config);
19411947
s.commit_template = 1;
19421948
status_format = STATUS_FORMAT_NONE; /* Ignore status.short */

cache-tree.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -496,8 +496,6 @@ int cache_tree_update(struct index_state *istate, int flags)
496496
if (i)
497497
return i;
498498

499-
ensure_full_index(istate);
500-
501499
if (!istate->cache_tree)
502500
istate->cache_tree = cache_tree();
503501

diff-lib.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,11 @@ static void show_new_file(struct rev_info *revs,
325325
unsigned dirty_submodule = 0;
326326
struct index_state *istate = revs->diffopt.repo->index;
327327

328+
if (new_file && S_ISSPARSEDIR(new_file->ce_mode)) {
329+
diff_tree_oid(NULL, &new_file->oid, new_file->name, &revs->diffopt);
330+
return;
331+
}
332+
328333
/*
329334
* New file in the index: it might actually be different in
330335
* the working tree.
@@ -347,6 +352,17 @@ static int show_modified(struct rev_info *revs,
347352
unsigned dirty_submodule = 0;
348353
struct index_state *istate = revs->diffopt.repo->index;
349354

355+
/*
356+
* If both are sparse directory entries, then expand the
357+
* modifications to the file level.
358+
*/
359+
if (old_entry && new_entry &&
360+
S_ISSPARSEDIR(old_entry->ce_mode) &&
361+
S_ISSPARSEDIR(new_entry->ce_mode)) {
362+
diff_tree_oid(&old_entry->oid, &new_entry->oid, new_entry->name, &revs->diffopt);
363+
return 0;
364+
}
365+
350366
if (get_stat_data(istate, new_entry, &oid, &mode, cached, match_missing,
351367
&dirty_submodule, &revs->diffopt) < 0) {
352368
if (report_missing)

dir.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,7 +1420,7 @@ enum pattern_match_result path_matches_pattern_list(
14201420
struct path_pattern *pattern;
14211421
struct strbuf parent_pathname = STRBUF_INIT;
14221422
int result = NOT_MATCHED;
1423-
const char *slash_pos;
1423+
size_t slash_pos;
14241424

14251425
/*
14261426
* The virtual file system data is used to prevent git from traversing
@@ -1452,21 +1452,35 @@ enum pattern_match_result path_matches_pattern_list(
14521452
strbuf_addch(&parent_pathname, '/');
14531453
strbuf_add(&parent_pathname, pathname, pathlen);
14541454

1455+
/*
1456+
* Directory entries are matched if and only if a file
1457+
* contained immediately within them is matched. For the
1458+
* case of a directory entry, modify the path to create
1459+
* a fake filename within this directory, allowing us to
1460+
* use the file-base matching logic in an equivalent way.
1461+
*/
1462+
if (parent_pathname.len > 0 &&
1463+
parent_pathname.buf[parent_pathname.len - 1] == '/') {
1464+
slash_pos = parent_pathname.len - 1;
1465+
strbuf_add(&parent_pathname, "-", 1);
1466+
} else {
1467+
const char *slash_ptr = strrchr(parent_pathname.buf, '/');
1468+
slash_pos = slash_ptr ? slash_ptr - parent_pathname.buf : 0;
1469+
}
1470+
14551471
if (hashmap_contains_path(&pl->recursive_hashmap,
14561472
&parent_pathname)) {
14571473
result = MATCHED_RECURSIVE;
14581474
goto done;
14591475
}
14601476

1461-
slash_pos = strrchr(parent_pathname.buf, '/');
1462-
1463-
if (slash_pos == parent_pathname.buf) {
1477+
if (!slash_pos) {
14641478
/* include every file in root */
14651479
result = MATCHED;
14661480
goto done;
14671481
}
14681482

1469-
strbuf_setlen(&parent_pathname, slash_pos - parent_pathname.buf);
1483+
strbuf_setlen(&parent_pathname, slash_pos);
14701484

14711485
if (hashmap_contains_path(&pl->parent_hashmap, &parent_pathname)) {
14721486
result = MATCHED;

pathspec.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ void add_pathspec_matches_against_index(const struct pathspec *pathspec,
3737
num_unmatched++;
3838
if (!num_unmatched)
3939
return;
40-
/* TODO: audit for interaction with sparse-index. */
41-
ensure_full_index(istate);
4240
for (i = 0; i < istate->cache_nr; i++) {
4341
const struct cache_entry *ce = istate->cache[i];
4442
if (sw_action == PS_IGNORE_SKIP_WORKTREE && ce_skip_worktree(ce))

read-cache.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,8 +1598,7 @@ int refresh_index(struct index_state *istate, unsigned int flags,
15981598
*/
15991599
preload_index(istate, pathspec, 0);
16001600
trace2_region_enter("index", "refresh", NULL);
1601-
/* TODO: audit for interaction with sparse-index. */
1602-
ensure_full_index(istate);
1601+
16031602
for (i = 0; i < istate->cache_nr; i++) {
16041603
struct cache_entry *ce, *new_entry;
16051604
int cache_errno = 0;
@@ -1614,6 +1613,13 @@ int refresh_index(struct index_state *istate, unsigned int flags,
16141613
if (ignore_skip_worktree && ce_skip_worktree(ce))
16151614
continue;
16161615

1616+
/*
1617+
* If this entry is a sparse directory, then there isn't
1618+
* any stat() information to update. Ignore the entry.
1619+
*/
1620+
if (S_ISSPARSEDIR(ce->ce_mode))
1621+
continue;
1622+
16171623
if (pathspec && !ce_path_match(istate, ce, pathspec, seen))
16181624
filtered = 1;
16191625

repo-settings.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ void prepare_repo_settings(struct repository *r)
9797
r->settings.command_requires_full_index = 1;
9898

9999
/*
100-
* Initialize this as off.
100+
* Initialize this as on.
101101
*/
102-
r->settings.sparse_index = 0;
103-
if (!repo_config_get_bool(r, "index.sparse", &value) && value)
104-
r->settings.sparse_index = 1;
102+
r->settings.sparse_index = 1;
103+
if (!repo_config_get_bool(r, "index.sparse", &value) && !value)
104+
r->settings.sparse_index = 0;
105105
}

sparse-index.c

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -108,18 +108,30 @@ int set_sparse_index_config(struct repository *repo, int enable)
108108
char *config_path = repo_git_path(repo, "config.worktree");
109109
res = git_config_set_in_file_gently(config_path,
110110
"index.sparse",
111-
enable ? "true" : NULL);
111+
enable ? "true" : "false");
112112
free(config_path);
113113

114114
prepare_repo_settings(repo);
115115
repo->settings.sparse_index = enable;
116116
return res;
117117
}
118118

119+
static int index_has_unmerged_entries(struct index_state *istate)
120+
{
121+
int i;
122+
for (i = 0; i < istate->cache_nr; i++) {
123+
if (ce_stage(istate->cache[i]))
124+
return 1;
125+
}
126+
127+
return 0;
128+
}
129+
119130
int convert_to_sparse(struct index_state *istate)
120131
{
121132
int test_env;
122-
if (istate->split_index || istate->sparse_index ||
133+
134+
if (istate->split_index || istate->sparse_index || !istate->cache_nr ||
123135
!core_apply_sparse_checkout || !core_sparse_checkout_cone)
124136
return 0;
125137

@@ -147,15 +159,35 @@ int convert_to_sparse(struct index_state *istate)
147159
return 0;
148160
}
149161

150-
if (!istate->sparse_checkout_patterns->use_cone_patterns) {
151-
warning(_("attempting to use sparse-index without cone mode"));
152-
return -1;
153-
}
162+
/*
163+
* We need cone-mode patterns to use sparse-index. If a user edits
164+
* their sparse-checkout file manually, then we can detect during
165+
* parsing that they are not actually using cone-mode patterns and
166+
* hence we need to abort this conversion _without error_. Warnings
167+
* already exist in the pattern parsing to inform the user of their
168+
* bad patterns.
169+
*/
170+
if (!istate->sparse_checkout_patterns->use_cone_patterns)
171+
return 0;
154172

155-
if (cache_tree_update(istate, 0)) {
156-
warning(_("unable to update cache-tree, staying full"));
157-
return -1;
158-
}
173+
/*
174+
* NEEDSWORK: If we have unmerged entries, then stay full.
175+
* Unmerged entries prevent the cache-tree extension from working.
176+
*/
177+
if (index_has_unmerged_entries(istate))
178+
return 0;
179+
180+
/* Clear and recompute the cache-tree */
181+
cache_tree_free(&istate->cache_tree);
182+
/*
183+
* Silently return if there is a problem with the cache tree update,
184+
* which might just be due to a conflict state in some entry.
185+
*
186+
* This might create new tree objects, so be sure to use
187+
* WRITE_TREE_MISSING_OK.
188+
*/
189+
if (cache_tree_update(istate, WRITE_TREE_MISSING_OK))
190+
return 0;
159191

160192
remove_fsmonitor(istate);
161193

@@ -168,6 +200,10 @@ int convert_to_sparse(struct index_state *istate)
168200
cache_tree_free(&istate->cache_tree);
169201
cache_tree_update(istate, 0);
170202

203+
istate->fsmonitor_has_run_once = 0;
204+
FREE_AND_NULL(istate->fsmonitor_dirty);
205+
FREE_AND_NULL(istate->fsmonitor_last_update);
206+
171207
istate->sparse_index = 1;
172208
trace2_region_leave("index", "convert_to_sparse", istate->repo);
173209
return 0;
@@ -195,7 +231,7 @@ static int add_path_to_index(const struct object_id *oid,
195231
strbuf_addstr(base, path);
196232

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

201237
strbuf_setlen(base, len);
@@ -239,7 +275,7 @@ void ensure_full_index(struct index_state *istate)
239275
warning(_("index entry is a directory, but not sparse (%08x)"),
240276
ce->ce_flags);
241277

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

245281
memset(&ps, 0, sizeof(ps));
@@ -264,6 +300,9 @@ void ensure_full_index(struct index_state *istate)
264300
istate->cache = full->cache;
265301
istate->cache_nr = full->cache_nr;
266302
istate->cache_alloc = full->cache_alloc;
303+
istate->fsmonitor_has_run_once = 0;
304+
FREE_AND_NULL(istate->fsmonitor_dirty);
305+
FREE_AND_NULL(istate->fsmonitor_last_update);
267306

268307
strbuf_release(&base);
269308
free(full);

0 commit comments

Comments
 (0)