Skip to content

Commit 8662fb2

Browse files
dschovdye
authored andcommitted
Merge branch 'sparse-index-stuff'
This is random stuff that probably all got upstream in the meantime.
2 parents 8997bd1 + 88a2c49 commit 8662fb2

15 files changed

+233
-17
lines changed

Documentation/config/index.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
index.deleteSparseDirectories::
2+
When enabled, the cone mode sparse-checkout feature will delete
3+
directories that are outside of the sparse-checkout cone, unless
4+
such a directory contains an untracked, non-ignored file. Defaults
5+
to true.
6+
17
index.recordEndOfIndexEntries::
28
Specifies whether the index file should include an "End Of Index
39
Entry" section. This reduces index load time on multiprocessor

builtin/add.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
#define USE_THE_INDEX_VARIABLE
77
#include "cache.h"
8+
#include "environment.h"
89
#include "advice.h"
910
#include "config.h"
1011
#include "builtin.h"
@@ -50,6 +51,7 @@ static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
5051
int err;
5152

5253
if (!include_sparse &&
54+
!core_virtualfilesystem &&
5355
(ce_skip_worktree(ce) ||
5456
!path_in_sparse_checkout(ce->name, &the_index)))
5557
continue;
@@ -100,7 +102,8 @@ static void update_callback(struct diff_queue_struct *q,
100102
struct diff_filepair *p = q->queue[i];
101103
const char *path = p->one->path;
102104

103-
if (!include_sparse && !path_in_sparse_checkout(path, &the_index))
105+
if (!include_sparse && !core_virtualfilesystem &&
106+
!path_in_sparse_checkout(path, &the_index))
104107
continue;
105108

106109
switch (fix_unmerged_status(p, data)) {
@@ -219,8 +222,9 @@ static int refresh(int verbose, const struct pathspec *pathspec)
219222
if (!seen[i]) {
220223
const char *path = pathspec->items[i].original;
221224

222-
if (matches_skip_worktree(pathspec, i, &skip_worktree_seen) ||
223-
!path_in_sparse_checkout(path, &the_index)) {
225+
if (!core_virtualfilesystem &&
226+
(matches_skip_worktree(pathspec, i, &skip_worktree_seen) ||
227+
!path_in_sparse_checkout(path, &the_index))) {
224228
string_list_append(&only_match_skip_worktree,
225229
pathspec->items[i].original);
226230
} else {
@@ -230,7 +234,11 @@ static int refresh(int verbose, const struct pathspec *pathspec)
230234
}
231235
}
232236

233-
if (only_match_skip_worktree.nr) {
237+
/*
238+
* When using a virtual filesystem, we might re-add a path
239+
* that is currently virtual and we want that to succeed.
240+
*/
241+
if (!core_virtualfilesystem && only_match_skip_worktree.nr) {
234242
advise_on_updating_sparse_paths(&only_match_skip_worktree);
235243
ret = 1;
236244
}
@@ -604,7 +612,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)
604612
if (seen[i])
605613
continue;
606614

607-
if (!include_sparse &&
615+
/*
616+
* When using a virtual filesystem, we might re-add a path
617+
* that is currently virtual and we want that to succeed.
618+
*/
619+
if (!include_sparse && !core_virtualfilesystem &&
608620
matches_skip_worktree(&pathspec, i, &skip_worktree_seen)) {
609621
string_list_append(&only_match_skip_worktree,
610622
pathspec.items[i].original);
@@ -628,7 +640,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
628640
}
629641
}
630642

631-
632643
if (only_match_skip_worktree.nr) {
633644
advise_on_updating_sparse_paths(&only_match_skip_worktree);
634645
exit_status = 1;

builtin/gc.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,8 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
13091309
char *lock_path = xstrfmt("%s/maintenance", r->objects->odb->path);
13101310

13111311
if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
1312+
struct stat st;
1313+
struct strbuf lock_dot_lock = STRBUF_INIT;
13121314
/*
13131315
* Another maintenance command is running.
13141316
*
@@ -1319,6 +1321,25 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
13191321
if (!opts->auto_flag && !opts->quiet)
13201322
warning(_("lock file '%s' exists, skipping maintenance"),
13211323
lock_path);
1324+
1325+
/*
1326+
* Check timestamp on .lock file to see if we should
1327+
* delete it to recover from a fail state.
1328+
*/
1329+
strbuf_addstr(&lock_dot_lock, lock_path);
1330+
strbuf_addstr(&lock_dot_lock, ".lock");
1331+
if (lstat(lock_dot_lock.buf, &st))
1332+
warning_errno(_("unable to stat '%s'"), lock_dot_lock.buf);
1333+
else {
1334+
if (st.st_mtime < time(NULL) - (6 * 60 * 60)) {
1335+
if (unlink(lock_dot_lock.buf))
1336+
warning_errno(_("unable to delete stale lock file"));
1337+
else
1338+
warning(_("deleted stale lock file"));
1339+
}
1340+
}
1341+
1342+
strbuf_release(&lock_dot_lock);
13221343
free(lock_path);
13231344
return 0;
13241345
}

builtin/reset.c

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
#include "add-interactive.h"
3838
#include "strbuf.h"
3939
#include "quote.h"
40+
#include "dir.h"
41+
#include "entry.h"
4042

4143
#define REFRESH_INDEX_DELAY_WARNING_IN_MS (2 * 1000)
4244

@@ -153,9 +155,47 @@ static void update_index_from_diff(struct diff_queue_struct *q,
153155

154156
for (i = 0; i < q->nr; i++) {
155157
int pos;
158+
int respect_skip_worktree = 1;
156159
struct diff_filespec *one = q->queue[i]->one;
160+
struct diff_filespec *two = q->queue[i]->two;
157161
int is_in_reset_tree = one->mode && !is_null_oid(&one->oid);
162+
int is_missing = !(one->mode && !is_null_oid(&one->oid));
163+
int was_missing = !two->mode && is_null_oid(&two->oid);
158164
struct cache_entry *ce;
165+
struct cache_entry *ceBefore;
166+
struct checkout state = CHECKOUT_INIT;
167+
168+
/*
169+
* When using the virtual filesystem feature, the cache entries that are
170+
* added here will not have the skip-worktree bit set.
171+
*
172+
* Without this code there is data that is lost because the files that
173+
* would normally be in the working directory are not there and show as
174+
* deleted for the next status or in the case of added files just disappear.
175+
* We need to create the previous version of the files in the working
176+
* directory so that they will have the right content and the next
177+
* status call will show modified or untracked files correctly.
178+
*/
179+
if (core_virtualfilesystem && !file_exists(two->path))
180+
{
181+
pos = index_name_pos(&the_index, two->path, strlen(two->path));
182+
if ((pos >= 0 && ce_skip_worktree(the_index.cache[pos])) &&
183+
(is_missing || !was_missing))
184+
{
185+
state.force = 1;
186+
state.refresh_cache = 1;
187+
state.istate = &the_index;
188+
ceBefore = make_cache_entry(&the_index, two->mode,
189+
&two->oid, two->path,
190+
0, 0);
191+
if (!ceBefore)
192+
die(_("make_cache_entry failed for path '%s'"),
193+
two->path);
194+
195+
checkout_entry(ceBefore, &state, NULL, NULL);
196+
respect_skip_worktree = 0;
197+
}
198+
}
159199

160200
if (!is_in_reset_tree && !intent_to_add) {
161201
remove_file_from_index(&the_index, one->path);
@@ -174,8 +214,14 @@ static void update_index_from_diff(struct diff_queue_struct *q,
174214
* to properly construct the reset sparse directory.
175215
*/
176216
pos = index_name_pos(&the_index, one->path, strlen(one->path));
177-
if ((pos >= 0 && ce_skip_worktree(the_index.cache[pos])) ||
178-
(pos < 0 && !path_in_sparse_checkout(one->path, &the_index)))
217+
218+
/*
219+
* Do not add the SKIP_WORKTREE bit back if we populated the
220+
* file on purpose in a virtual filesystem scenario.
221+
*/
222+
if (respect_skip_worktree &&
223+
((pos >= 0 && ce_skip_worktree(the_index.cache[pos])) ||
224+
(pos < 0 && !path_in_sparse_checkout(one->path, &the_index))))
179225
ce->ce_flags |= CE_SKIP_WORKTREE;
180226

181227
if (!ce)

builtin/rm.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
#define USE_THE_INDEX_VARIABLE
77
#include "builtin.h"
8+
#include "environment.h"
89
#include "alloc.h"
910
#include "advice.h"
1011
#include "config.h"
@@ -311,7 +312,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
311312
for (i = 0; i < the_index.cache_nr; i++) {
312313
const struct cache_entry *ce = the_index.cache[i];
313314

314-
if (!include_sparse &&
315+
if (!include_sparse && !core_virtualfilesystem &&
315316
(ce_skip_worktree(ce) ||
316317
!path_in_sparse_checkout(ce->name, &the_index)))
317318
continue;
@@ -348,7 +349,11 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
348349
*original ? original : ".");
349350
}
350351

351-
if (only_match_skip_worktree.nr) {
352+
/*
353+
* When using a virtual filesystem, we might re-add a path
354+
* that is currently virtual and we want that to succeed.
355+
*/
356+
if (!core_virtualfilesystem && only_match_skip_worktree.nr) {
352357
advise_on_updating_sparse_paths(&only_match_skip_worktree);
353358
ret = 1;
354359
}

builtin/sparse-checkout.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix)
112112

113113
static void clean_tracked_sparse_directories(struct repository *r)
114114
{
115-
int i, was_full = 0;
115+
int i, value, was_full = 0;
116116
struct strbuf path = STRBUF_INIT;
117117
size_t pathlen;
118118
struct string_list_item *item;
@@ -128,6 +128,13 @@ static void clean_tracked_sparse_directories(struct repository *r)
128128
!r->index->sparse_checkout_patterns->use_cone_patterns)
129129
return;
130130

131+
/*
132+
* Users can disable this behavior.
133+
*/
134+
if (!repo_config_get_bool(r, "index.deletesparsedirectories", &value) &&
135+
!value)
136+
return;
137+
131138
/*
132139
* Use the sparse index as a data structure to assist finding
133140
* directories that are safe to delete. This conversion to a

diff.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3992,6 +3992,13 @@ static int reuse_worktree_file(struct index_state *istate,
39923992
if (!FAST_WORKING_DIRECTORY && !want_file && has_object_pack(oid))
39933993
return 0;
39943994

3995+
/*
3996+
* If this path does not match our sparse-checkout definition,
3997+
* then the file will not be in the working directory.
3998+
*/
3999+
if (!path_in_sparse_checkout(name, istate))
4000+
return 0;
4001+
39954002
/*
39964003
* Similarly, if we'd have to convert the file contents anyway, that
39974004
* makes the optimization not worthwhile.

dir.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,6 +1531,13 @@ static int path_in_sparse_checkout_1(const char *path,
15311531
enum pattern_match_result match = UNDECIDED;
15321532
const char *end, *slash;
15331533

1534+
/*
1535+
* When using a virtual filesystem, there aren't really patterns
1536+
* to follow, but be extra careful to skip this check.
1537+
*/
1538+
if (core_virtualfilesystem)
1539+
return 1;
1540+
15341541
/*
15351542
* We default to accepting a path if the path is empty, there are no
15361543
* patterns, or the patterns are of the wrong type.

repo-settings.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ void prepare_repo_settings(struct repository *r)
8686
/* Boolean config or default, does not cascade (simple) */
8787
repo_cfg_bool(r, "pack.usesparse", &r->settings.pack_use_sparse, 1);
8888
repo_cfg_bool(r, "core.multipackindex", &r->settings.core_multi_pack_index, 1);
89-
repo_cfg_bool(r, "index.sparse", &r->settings.sparse_index, 0);
89+
repo_cfg_bool(r, "index.sparse", &r->settings.sparse_index, 1);
9090
repo_cfg_bool(r, "index.skiphash", &r->settings.index_skip_hash, r->settings.index_skip_hash);
9191
repo_cfg_bool(r, "pack.readreverseindex", &r->settings.pack_read_reverse_index, 1);
9292

sequencer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ static int do_recursive_merge(struct repository *r,
696696
o.branch2 = next ? next_label : "(empty tree)";
697697
if (is_rebase_i(opts))
698698
o.buffer_output = 2;
699-
o.show_rename_progress = 1;
699+
o.show_rename_progress = isatty(2);
700700

701701
head_tree = parse_tree_indirect(head);
702702
next_tree = next ? repo_get_commit_tree(r, next) : empty_tree(r);

t/perf/p2000-sparse-operations.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ test_expect_success 'setup repo and indexes' '
5656
git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . full-v3 &&
5757
(
5858
cd full-v3 &&
59-
git sparse-checkout init --cone &&
59+
git sparse-checkout init --cone --no-sparse-index &&
6060
git sparse-checkout set $SPARSE_CONE &&
6161
git config index.version 3 &&
6262
git update-index --index-version=3 &&
@@ -65,7 +65,7 @@ test_expect_success 'setup repo and indexes' '
6565
git -c core.sparseCheckoutCone=true clone --branch=wide --sparse . full-v4 &&
6666
(
6767
cd full-v4 &&
68-
git sparse-checkout init --cone &&
68+
git sparse-checkout init --cone --no-sparse-index &&
6969
git sparse-checkout set $SPARSE_CONE &&
7070
git config index.version 4 &&
7171
git update-index --index-version=4 &&

t/t1091-sparse-checkout-builtin.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,10 @@ test_expect_success 'cone mode clears ignored subdirectories' '
782782
git -C repo status --porcelain=v2 >out &&
783783
test_must_be_empty out &&
784784
785+
git -C repo -c index.deleteSparseDirectories=false sparse-checkout reapply &&
786+
test_path_is_dir repo/folder1 &&
787+
test_path_is_dir repo/deep/deeper2 &&
788+
785789
git -C repo sparse-checkout reapply &&
786790
test_path_is_missing repo/folder1 &&
787791
test_path_is_missing repo/deep/deeper2 &&

0 commit comments

Comments
 (0)