Skip to content

Commit

Permalink
Merge branch 'sparse-index-stuff'
Browse files Browse the repository at this point in the history
This is random stuff that probably all got upstream in the meantime.
  • Loading branch information
dscho committed Sep 19, 2022
2 parents 5c1449f + 58726e8 commit 47b56ab
Show file tree
Hide file tree
Showing 18 changed files with 288 additions and 53 deletions.
6 changes: 6 additions & 0 deletions Documentation/config/index.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
index.deleteSparseDirectories::
When enabled, the cone mode sparse-checkout feature will delete
directories that are outside of the sparse-checkout cone, unless
such a directory contains an untracked, non-ignored file. Defaults
to true.

index.recordEndOfIndexEntries::
Specifies whether the index file should include an "End Of Index
Entry" section. This reduces index load time on multiprocessor
Expand Down
22 changes: 16 additions & 6 deletions builtin/add.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
int err;

if (!include_sparse &&
!core_virtualfilesystem &&
(ce_skip_worktree(ce) ||
!path_in_sparse_checkout(ce->name, &the_index)))
continue;
Expand Down Expand Up @@ -97,7 +98,8 @@ static void update_callback(struct diff_queue_struct *q,
struct diff_filepair *p = q->queue[i];
const char *path = p->one->path;

if (!include_sparse && !path_in_sparse_checkout(path, &the_index))
if (!include_sparse && !core_virtualfilesystem &&
!path_in_sparse_checkout(path, &the_index))
continue;

switch (fix_unmerged_status(p, data)) {
Expand Down Expand Up @@ -215,8 +217,9 @@ static int refresh(int verbose, const struct pathspec *pathspec)
if (!seen[i]) {
const char *path = pathspec->items[i].original;

if (matches_skip_worktree(pathspec, i, &skip_worktree_seen) ||
!path_in_sparse_checkout(path, &the_index)) {
if (!core_virtualfilesystem &&
(matches_skip_worktree(pathspec, i, &skip_worktree_seen) ||
!path_in_sparse_checkout(path, &the_index))) {
string_list_append(&only_match_skip_worktree,
pathspec->items[i].original);
} else {
Expand All @@ -226,7 +229,11 @@ static int refresh(int verbose, const struct pathspec *pathspec)
}
}

if (only_match_skip_worktree.nr) {
/*
* When using a virtual filesystem, we might re-add a path
* that is currently virtual and we want that to succeed.
*/
if (!core_virtualfilesystem && only_match_skip_worktree.nr) {
advise_on_updating_sparse_paths(&only_match_skip_worktree);
ret = 1;
}
Expand Down Expand Up @@ -644,7 +651,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (seen[i])
continue;

if (!include_sparse &&
/*
* When using a virtual filesystem, we might re-add a path
* that is currently virtual and we want that to succeed.
*/
if (!include_sparse && !core_virtualfilesystem &&
matches_skip_worktree(&pathspec, i, &skip_worktree_seen)) {
string_list_append(&only_match_skip_worktree,
pathspec.items[i].original);
Expand All @@ -668,7 +679,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
}
}


if (only_match_skip_worktree.nr) {
advise_on_updating_sparse_paths(&only_match_skip_worktree);
exit_status = 1;
Expand Down
21 changes: 21 additions & 0 deletions builtin/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1285,6 +1285,8 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
char *lock_path = xstrfmt("%s/maintenance", r->objects->odb->path);

if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
struct stat st;
struct strbuf lock_dot_lock = STRBUF_INIT;
/*
* Another maintenance command is running.
*
Expand All @@ -1295,6 +1297,25 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
if (!opts->auto_flag && !opts->quiet)
warning(_("lock file '%s' exists, skipping maintenance"),
lock_path);

/*
* Check timestamp on .lock file to see if we should
* delete it to recover from a fail state.
*/
strbuf_addstr(&lock_dot_lock, lock_path);
strbuf_addstr(&lock_dot_lock, ".lock");
if (lstat(lock_dot_lock.buf, &st))
warning_errno(_("unable to stat '%s'"), lock_dot_lock.buf);
else {
if (st.st_mtime < time(NULL) - (6 * 60 * 60)) {
if (unlink(lock_dot_lock.buf))
warning_errno(_("unable to delete stale lock file"));
else
warning(_("deleted stale lock file"));
}
}

strbuf_release(&lock_dot_lock);
free(lock_path);
return 0;
}
Expand Down
50 changes: 48 additions & 2 deletions builtin/reset.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#include "dir.h"
#include "strbuf.h"
#include "quote.h"
#include "dir.h"
#include "entry.h"

#define REFRESH_INDEX_DELAY_WARNING_IN_MS (2 * 1000)

Expand Down Expand Up @@ -141,9 +143,47 @@ static void update_index_from_diff(struct diff_queue_struct *q,

for (i = 0; i < q->nr; i++) {
int pos;
int respect_skip_worktree = 1;
struct diff_filespec *one = q->queue[i]->one;
struct diff_filespec *two = q->queue[i]->two;
int is_in_reset_tree = one->mode && !is_null_oid(&one->oid);
int is_missing = !(one->mode && !is_null_oid(&one->oid));
int was_missing = !two->mode && is_null_oid(&two->oid);
struct cache_entry *ce;
struct cache_entry *ceBefore;
struct checkout state = CHECKOUT_INIT;

/*
* When using the virtual filesystem feature, the cache entries that are
* added here will not have the skip-worktree bit set.
*
* Without this code there is data that is lost because the files that
* would normally be in the working directory are not there and show as
* deleted for the next status or in the case of added files just disappear.
* We need to create the previous version of the files in the working
* directory so that they will have the right content and the next
* status call will show modified or untracked files correctly.
*/
if (core_virtualfilesystem && !file_exists(two->path))
{
pos = cache_name_pos(two->path, strlen(two->path));
if ((pos >= 0 && ce_skip_worktree(active_cache[pos])) &&
(is_missing || !was_missing))
{
state.force = 1;
state.refresh_cache = 1;
state.istate = &the_index;
ceBefore = make_cache_entry(&the_index, two->mode,
&two->oid, two->path,
0, 0);
if (!ceBefore)
die(_("make_cache_entry failed for path '%s'"),
two->path);

checkout_entry(ceBefore, &state, NULL, NULL);
respect_skip_worktree = 0;
}
}

if (!is_in_reset_tree && !intent_to_add) {
remove_file_from_cache(one->path);
Expand All @@ -162,8 +202,14 @@ static void update_index_from_diff(struct diff_queue_struct *q,
* to properly construct the reset sparse directory.
*/
pos = cache_name_pos(one->path, strlen(one->path));
if ((pos >= 0 && ce_skip_worktree(active_cache[pos])) ||
(pos < 0 && !path_in_sparse_checkout(one->path, &the_index)))

/*
* Do not add the SKIP_WORKTREE bit back if we populated the
* file on purpose in a virtual filesystem scenario.
*/
if (respect_skip_worktree &&
((pos >= 0 && ce_skip_worktree(active_cache[pos])) ||
(pos < 0 && !path_in_sparse_checkout(one->path, &the_index))))
ce->ce_flags |= CE_SKIP_WORKTREE;

if (!ce)
Expand Down
8 changes: 6 additions & 2 deletions builtin/rm.c
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
for (i = 0; i < active_nr; i++) {
const struct cache_entry *ce = active_cache[i];

if (!include_sparse &&
if (!include_sparse && !core_virtualfilesystem &&
(ce_skip_worktree(ce) ||
!path_in_sparse_checkout(ce->name, &the_index)))
continue;
Expand Down Expand Up @@ -341,7 +341,11 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
*original ? original : ".");
}

if (only_match_skip_worktree.nr) {
/*
* When using a virtual filesystem, we might re-add a path
* that is currently virtual and we want that to succeed.
*/
if (!core_virtualfilesystem && only_match_skip_worktree.nr) {
advise_on_updating_sparse_paths(&only_match_skip_worktree);
ret = 1;
}
Expand Down
9 changes: 8 additions & 1 deletion builtin/sparse-checkout.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix)

static void clean_tracked_sparse_directories(struct repository *r)
{
int i, was_full = 0;
int i, value, was_full = 0;
struct strbuf path = STRBUF_INIT;
size_t pathlen;
struct string_list_item *item;
Expand All @@ -122,6 +122,13 @@ static void clean_tracked_sparse_directories(struct repository *r)
!r->index->sparse_checkout_patterns->use_cone_patterns)
return;

/*
* Users can disable this behavior.
*/
if (!repo_config_get_bool(r, "index.deletesparsedirectories", &value) &&
!value)
return;

/*
* Use the sparse index as a data structure to assist finding
* directories that are safe to delete. This conversion to a
Expand Down
7 changes: 7 additions & 0 deletions diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -3922,6 +3922,13 @@ static int reuse_worktree_file(struct index_state *istate,
if (!FAST_WORKING_DIRECTORY && !want_file && has_object_pack(oid))
return 0;

/*
* If this path does not match our sparse-checkout definition,
* then the file will not be in the working directory.
*/
if (!path_in_sparse_checkout(name, istate))
return 0;

/*
* Similarly, if we'd have to convert the file contents anyway, that
* makes the optimization not worthwhile.
Expand Down
85 changes: 51 additions & 34 deletions dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1398,46 +1398,16 @@ static struct path_pattern *last_matching_pattern_from_list(const char *pathname
return res;
}

/*
* Scan the list of patterns to determine if the ordered list
* of patterns matches on 'pathname'.
*
* Return 1 for a match, 0 for not matched and -1 for undecided.
*/
enum pattern_match_result path_matches_pattern_list(
enum pattern_match_result path_matches_cone_mode_pattern_list(
const char *pathname, int pathlen,
const char *basename, int *dtype,
struct pattern_list *pl,
struct index_state *istate)
struct pattern_list *pl)
{
struct path_pattern *pattern;
struct strbuf parent_pathname = STRBUF_INIT;
int result = NOT_MATCHED;
size_t slash_pos;

/*
* The virtual file system data is used to prevent git from traversing
* any part of the tree that is not in the virtual file system. Return
* 1 to exclude the entry if it is not found in the virtual file system,
* else fall through to the regular excludes logic as it may further exclude.
*/
if (*dtype == DT_UNKNOWN)
*dtype = resolve_dtype(DT_UNKNOWN, istate, pathname, pathlen);
if (is_excluded_from_virtualfilesystem(pathname, pathlen, *dtype) > 0)
return 1;

if (!pl->use_cone_patterns) {
pattern = last_matching_pattern_from_list(pathname, pathlen, basename,
dtype, pl, istate);
if (pattern) {
if (pattern->flags & PATTERN_FLAG_NEGATIVE)
return NOT_MATCHED;
else
return MATCHED;
}

return UNDECIDED;
}
if (!pl->use_cone_patterns)
BUG("path_matches_cone_mode_pattern_list requires cone mode patterns");

if (pl->full_cone)
return MATCHED;
Expand Down Expand Up @@ -1490,6 +1460,46 @@ enum pattern_match_result path_matches_pattern_list(
return result;
}

/*
* Scan the list of patterns to determine if the ordered list
* of patterns matches on 'pathname'.
*
* Return 1 for a match, 0 for not matched and -1 for undecided.
*/
enum pattern_match_result path_matches_pattern_list(
const char *pathname, int pathlen,
const char *basename, int *dtype,
struct pattern_list *pl,
struct index_state *istate)
{
/*
* The virtual file system data is used to prevent git from traversing
* any part of the tree that is not in the virtual file system. Return
* 1 to exclude the entry if it is not found in the virtual file system,
* else fall through to the regular excludes logic as it may further exclude.
*/
if (*dtype == DT_UNKNOWN)
*dtype = resolve_dtype(DT_UNKNOWN, istate, pathname, pathlen);
if (is_excluded_from_virtualfilesystem(pathname, pathlen, *dtype) > 0)
return 1;

if (!pl->use_cone_patterns) {
struct path_pattern *pattern = last_matching_pattern_from_list(
pathname, pathlen, basename,
dtype, pl, istate);
if (pattern) {
if (pattern->flags & PATTERN_FLAG_NEGATIVE)
return NOT_MATCHED;
else
return MATCHED;
}

return UNDECIDED;
}

return path_matches_cone_mode_pattern_list(pathname, pathlen, pl);
}

int init_sparse_checkout_patterns(struct index_state *istate)
{
if (!core_apply_sparse_checkout)
Expand All @@ -1515,6 +1525,13 @@ static int path_in_sparse_checkout_1(const char *path,
enum pattern_match_result match = UNDECIDED;
const char *end, *slash;

/*
* When using a virtual filesystem, there aren't really patterns
* to follow, but be extra careful to skip this check.
*/
if (core_virtualfilesystem)
return 1;

/*
* We default to accepting a path if the path is empty, there are no
* patterns, or the patterns are of the wrong type.
Expand Down
9 changes: 9 additions & 0 deletions dir.h
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,15 @@ enum pattern_match_result {
MATCHED_RECURSIVE = 2,
};

/*
* Test if a given path is contained in the given pattern list.
*
* The given pattern list _must_ use cone mode patterns.
*/
enum pattern_match_result path_matches_cone_mode_pattern_list(
const char *pathname, int pathlen,
struct pattern_list *pl);

/*
* Scan the list of patterns to determine if the ordered list
* of patterns matches on 'pathname'.
Expand Down
2 changes: 1 addition & 1 deletion repo-settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ void prepare_repo_settings(struct repository *r)
/* Boolean config or default, does not cascade (simple) */
repo_cfg_bool(r, "pack.usesparse", &r->settings.pack_use_sparse, 1);
repo_cfg_bool(r, "core.multipackindex", &r->settings.core_multi_pack_index, 1);
repo_cfg_bool(r, "index.sparse", &r->settings.sparse_index, 0);
repo_cfg_bool(r, "index.sparse", &r->settings.sparse_index, 1);

/*
* The GIT_TEST_MULTI_PACK_INDEX variable is special in that
Expand Down
2 changes: 1 addition & 1 deletion sequencer.c
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ static int do_recursive_merge(struct repository *r,
o.branch2 = next ? next_label : "(empty tree)";
if (is_rebase_i(opts))
o.buffer_output = 2;
o.show_rename_progress = 1;
o.show_rename_progress = isatty(2);

head_tree = parse_tree_indirect(head);
next_tree = next ? get_commit_tree(next) : empty_tree(r);
Expand Down
Loading

0 comments on commit 47b56ab

Please sign in to comment.