Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sparse Index: upstream updates to git reset #444

Merged
merged 7 commits into from
Oct 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 87 additions & 62 deletions builtin/reset.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
#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 @@ -132,71 +131,118 @@ static void update_index_from_diff(struct diff_queue_struct *q,
struct diff_options *opt, void *data)
{
int i;
int pos;
int intent_to_add = *(int *)data;

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

/*
* When using the sparse-checkout 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_apply_sparse_checkout && !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);
}
}

if (is_missing && !intent_to_add) {
if (!is_in_reset_tree && !intent_to_add) {
remove_file_from_cache(one->path);
continue;
}

ce = make_cache_entry(&the_index, one->mode, &one->oid, one->path,
0, 0);

/*
* If the file 1) corresponds to an existing index entry with
* skip-worktree set, or 2) does not exist in the index but is
* outside the sparse checkout definition, add a skip-worktree bit
* to the new index entry. Note that a sparse index will be expanded
* if this entry is outside the sparse cone - this is necessary
* 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)))
ce->ce_flags |= CE_SKIP_WORKTREE;

if (!ce)
die(_("make_cache_entry failed for path '%s'"),
one->path);
if (is_missing) {
if (!is_in_reset_tree) {
ce->ce_flags |= CE_INTENT_TO_ADD;
set_object_name_for_intent_to_add_entry(ce);
}
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
}
}

static int pathspec_needs_expanded_index(const struct pathspec *pathspec)
{
unsigned int i, pos;
int res = 0;
char *skip_worktree_seen = NULL;

/*
* When using a magic pathspec, assume for the sake of simplicity that
* the index needs to be expanded to match all matchable files.
*/
if (pathspec->magic)
return 1;

for (i = 0; i < pathspec->nr; i++) {
struct pathspec_item item = pathspec->items[i];

/*
* If the pathspec item has a wildcard, the index should be expanded
* if the pathspec has the possibility of matching a subset of entries inside
* of a sparse directory (but not the entire directory).
*
* If the pathspec item is a literal path, the index only needs to be expanded
* if a) the pathspec isn't in the sparse checkout cone (to make sure we don't
* expand for in-cone files) and b) it doesn't match any sparse directories
* (since we can reset whole sparse directories without expanding them).
*/
if (item.nowildcard_len < item.len) {
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];

if (!S_ISSPARSEDIR(ce->ce_mode))
continue;

/*
* If the pre-wildcard length is longer than the sparse
* directory name and the sparse directory is the first
* component of the pathspec, need to expand the index.
*/
if (item.nowildcard_len > ce_namelen(ce) &&
!strncmp(item.original, ce->name, ce_namelen(ce))) {
res = 1;
break;
}

/*
* If the pre-wildcard length is shorter than the sparse
* directory and the pathspec does not match the whole
* directory, need to expand the index.
*/
if (!strncmp(item.original, ce->name, item.nowildcard_len) &&
wildmatch(item.original, ce->name, 0)) {
res = 1;
break;
}
}
} else if (!path_in_cone_modesparse_checkout(item.original, &the_index) &&
!matches_skip_worktree(pathspec, i, &skip_worktree_seen))
res = 1;

if (res > 0)
break;
}

free(skip_worktree_seen);
return res;
}

static int read_from_tree(const struct pathspec *pathspec,
struct object_id *tree_oid,
int intent_to_add)
{
struct diff_options opt;
unsigned int i;
char *skip_worktree_seen = NULL;

memset(&opt, 0, sizeof(opt));
copy_pathspec(&opt.pathspec, pathspec);
Expand All @@ -209,29 +255,8 @@ static int read_from_tree(const struct pathspec *pathspec,
opt.change = diff_change;
opt.add_remove = diff_addremove;

/*
* When pathspec is given for resetting a cone-mode sparse checkout, it may
* identify entries that are nested in sparse directories, in which case the
* index should be expanded. For the sake of efficiency, this check is
* overly-cautious: anything with a wildcard or a magic prefix requires
* expansion, as well as literal paths that aren't in the sparse checkout
* definition AND don't match any directory in the index.
*/
if (pathspec->nr && the_index.sparse_index) {
if (pathspec->magic || pathspec->has_wildcard) {
ensure_full_index(&the_index);
} else {
for (i = 0; i < pathspec->nr; i++) {
if (!path_in_cone_modesparse_checkout(pathspec->items[i].original, &the_index) &&
!matches_skip_worktree(pathspec, i, &skip_worktree_seen)) {
ensure_full_index(&the_index);
break;
}
}
}
}

free(skip_worktree_seen);
if (pathspec->nr && the_index.sparse_index && pathspec_needs_expanded_index(pathspec))
ensure_full_index(&the_index);

if (do_diff_cache(tree_oid, &opt))
return 1;
Expand Down
47 changes: 25 additions & 22 deletions cache-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -800,26 +800,23 @@ int write_index_as_tree(struct object_id *oid, struct index_state *index_state,
return ret;
}

static void prime_cache_tree_sparse_dir(struct repository *r,
struct cache_tree *it,
struct tree *tree,
struct strbuf *tree_path)
static void prime_cache_tree_sparse_dir(struct cache_tree *it,
struct tree *tree)
{

oidcpy(&it->oid, &tree->object.oid);
it->entry_count = 1;
return;
}

static void prime_cache_tree_rec(struct repository *r,
struct cache_tree *it,
struct tree *tree,
struct strbuf *tree_path)
{
struct strbuf subtree_path = STRBUF_INIT;
struct tree_desc desc;
struct name_entry entry;
int cnt;
int base_path_len = tree_path->len;

oidcpy(&it->oid, &tree->object.oid);

Expand All @@ -836,30 +833,36 @@ static void prime_cache_tree_rec(struct repository *r,
parse_tree(subtree);
sub = cache_tree_sub(it, entry.path);
sub->cache_tree = cache_tree();
strbuf_reset(&subtree_path);
strbuf_grow(&subtree_path, tree_path->len + entry.pathlen + 1);
strbuf_addbuf(&subtree_path, tree_path);
strbuf_add(&subtree_path, entry.path, entry.pathlen);
strbuf_addch(&subtree_path, '/');

/*
* If a sparse index is in use, the directory being processed may be
* sparse. To confirm that, we can check whether an entry with that
* exact name exists in the index. If it does, the created subtree
* should be sparse. Otherwise, cache tree expansion should continue
* as normal.
*/
* Recursively-constructed subtree path is only needed when working
* in a sparse index (where it's used to determine whether the
* subtree is a sparse directory in the index).
*/
if (r->index->sparse_index) {
strbuf_setlen(tree_path, base_path_len);
strbuf_grow(tree_path, base_path_len + entry.pathlen + 1);
strbuf_add(tree_path, entry.path, entry.pathlen);
strbuf_addch(tree_path, '/');
}

/*
* If a sparse index is in use, the directory being processed may be
* sparse. To confirm that, we can check whether an entry with that
* exact name exists in the index. If it does, the created subtree
* should be sparse. Otherwise, cache tree expansion should continue
* as normal.
*/
if (r->index->sparse_index &&
index_entry_exists(r->index, subtree_path.buf, subtree_path.len))
prime_cache_tree_sparse_dir(r, sub->cache_tree, subtree, &subtree_path);
index_entry_exists(r->index, tree_path->buf, tree_path->len))
prime_cache_tree_sparse_dir(sub->cache_tree, subtree);
else
prime_cache_tree_rec(r, sub->cache_tree, subtree, &subtree_path);
prime_cache_tree_rec(r, sub->cache_tree, subtree, tree_path);
cnt += sub->cache_tree->entry_count;
}
}
it->entry_count = cnt;

strbuf_release(&subtree_path);
it->entry_count = cnt;
}

void prime_cache_tree(struct repository *r,
Expand Down
24 changes: 15 additions & 9 deletions read-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@
*/
#define CACHE_ENTRY_PATH_LENGTH 80

enum index_search_mode {
NO_EXPAND_SPARSE = 0,
EXPAND_SPARSE = 1
};

static inline struct cache_entry *mem_pool__ce_alloc(struct mem_pool *mem_pool, size_t len)
{
struct cache_entry *ce;
Expand Down Expand Up @@ -567,7 +572,7 @@ int cache_name_stage_compare(const char *name1, int len1, int stage1, const char
static int index_name_stage_pos(struct index_state *istate,
const char *name, int namelen,
int stage,
int search_sparse)
enum index_search_mode search_mode)
{
int first, last;

Expand All @@ -586,7 +591,7 @@ static int index_name_stage_pos(struct index_state *istate,
first = next+1;
}

if (search_sparse && istate->sparse_index &&
if (search_mode == EXPAND_SPARSE && istate->sparse_index &&
first > 0) {
/* Note: first <= istate->cache_nr */
struct cache_entry *ce = istate->cache[first - 1];
Expand All @@ -602,7 +607,7 @@ static int index_name_stage_pos(struct index_state *istate,
ce_namelen(ce) < namelen &&
!strncmp(name, ce->name, ce_namelen(ce))) {
ensure_full_index(istate);
return index_name_stage_pos(istate, name, namelen, stage, search_sparse);
return index_name_stage_pos(istate, name, namelen, stage, search_mode);
}
}

Expand All @@ -611,12 +616,12 @@ static int index_name_stage_pos(struct index_state *istate,

int index_name_pos(struct index_state *istate, const char *name, int namelen)
{
return index_name_stage_pos(istate, name, namelen, 0, 1);
return index_name_stage_pos(istate, name, namelen, 0, EXPAND_SPARSE);
}

int index_entry_exists(struct index_state *istate, const char *name, int namelen)
{
return index_name_stage_pos(istate, name, namelen, 0, 0) >= 0;
return index_name_stage_pos(istate, name, namelen, 0, NO_EXPAND_SPARSE) >= 0;
}

int remove_index_entry_at(struct index_state *istate, int pos)
Expand Down Expand Up @@ -1243,7 +1248,7 @@ static int has_dir_name(struct index_state *istate,
*/
}

pos = index_name_stage_pos(istate, name, len, stage, 1);
pos = index_name_stage_pos(istate, name, len, stage, EXPAND_SPARSE);
if (pos >= 0) {
/*
* Found one, but not so fast. This could
Expand Down Expand Up @@ -1340,7 +1345,7 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
strcmp(ce->name, istate->cache[istate->cache_nr - 1]->name) > 0)
pos = index_pos_to_insert_pos(istate->cache_nr);
else
pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce), 1);
pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce), EXPAND_SPARSE);

/*
* Cache tree path should be invalidated only after index_name_stage_pos,
Expand Down Expand Up @@ -1382,7 +1387,7 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
if (!ok_to_replace)
return error(_("'%s' appears as both a file and as a directory"),
ce->name);
pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce), 1);
pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce), EXPAND_SPARSE);
pos = -pos-1;
}
return pos + 1;
Expand Down Expand Up @@ -2376,7 +2381,8 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
if (!istate->repo)
istate->repo = the_repository;
prepare_repo_settings(istate->repo);
if (istate->repo->settings.command_requires_full_index)
if (!istate->repo->settings.sparse_index ||
istate->repo->settings.command_requires_full_index)
ensure_full_index(istate);

return istate->cache_nr;
Expand Down
Loading