1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-05 18:46:10 +02:00

Merge branch 'sl/sparse-check-attr'

Teach "git check-attr" work better with sparse-index.

* sl/sparse-check-attr:
  check-attr: integrate with sparse-index
  attr.c: read attributes in a sparse directory
  t1092: add tests for 'git check-attr'
This commit is contained in:
Junio C Hamano 2023-08-29 13:51:43 -07:00
commit 354356feff
4 changed files with 115 additions and 18 deletions

57
attr.c
View File

@ -807,35 +807,56 @@ static struct attr_stack *read_attr_from_blob(struct index_state *istate,
static struct attr_stack *read_attr_from_index(struct index_state *istate,
const char *path, unsigned flags)
{
struct attr_stack *stack = NULL;
char *buf;
unsigned long size;
int sparse_dir_pos = -1;
if (!istate)
return NULL;
/*
* The .gitattributes file only applies to files within its
* parent directory. In the case of cone-mode sparse-checkout,
* the .gitattributes file is sparse if and only if all paths
* within that directory are also sparse. Thus, don't load the
* .gitattributes file since it will not matter.
*
* In the case of a sparse index, it is critical that we don't go
* looking for a .gitattributes file, as doing so would cause the
* index to expand.
* When handling sparse-checkouts, .gitattributes files
* may reside within a sparse directory. We distinguish
* whether a path exists directly in the index or not by
* evaluating if 'pos' is negative.
* If 'pos' is negative, the path is not directly present
* in the index and is likely within a sparse directory.
* For paths not in the index, The absolute value of 'pos'
* minus 1 gives us the position where the path would be
* inserted in lexicographic order within the index.
* We then subtract another 1 from this value
* (sparse_dir_pos = -pos - 2) to find the position of the
* last index entry which is lexicographically smaller than
* the path. This would be the sparse directory containing
* the path. By identifying the sparse directory containing
* the path, we can correctly read the attributes specified
* in the .gitattributes file from the tree object of the
* sparse directory.
*/
if (!path_in_cone_mode_sparse_checkout(path, istate))
return NULL;
if (!path_in_cone_mode_sparse_checkout(path, istate)) {
int pos = index_name_pos_sparse(istate, path, strlen(path));
buf = read_blob_data_from_index(istate, path, &size);
if (!buf)
return NULL;
if (size >= ATTR_MAX_FILE_SIZE) {
warning(_("ignoring overly large gitattributes blob '%s'"), path);
return NULL;
if (pos < 0)
sparse_dir_pos = -pos - 2;
}
return read_attr_from_buf(buf, path, flags);
if (sparse_dir_pos >= 0 &&
S_ISSPARSEDIR(istate->cache[sparse_dir_pos]->ce_mode) &&
!strncmp(istate->cache[sparse_dir_pos]->name, path, ce_namelen(istate->cache[sparse_dir_pos]))) {
const char *relative_path = path + ce_namelen(istate->cache[sparse_dir_pos]);
stack = read_attr_from_blob(istate, &istate->cache[sparse_dir_pos]->oid, relative_path, flags);
} else {
buf = read_blob_data_from_index(istate, path, &size);
if (!buf)
return NULL;
if (size >= ATTR_MAX_FILE_SIZE) {
warning(_("ignoring overly large gitattributes blob '%s'"), path);
return NULL;
}
stack = read_attr_from_buf(buf, path, flags);
}
return stack;
}
static struct attr_stack *read_attr(struct index_state *istate,

View File

@ -122,6 +122,9 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, check_attr_options,
check_attr_usage, PARSE_OPT_KEEP_DASHDASH);
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
if (repo_read_index(the_repository) < 0) {
die("invalid cache");
}

View File

@ -134,5 +134,6 @@ test_perf_on_all git diff-files -- $SPARSE_CONE/a
test_perf_on_all git diff-tree HEAD
test_perf_on_all git diff-tree HEAD -- $SPARSE_CONE/a
test_perf_on_all "git worktree add ../temp && git worktree remove ../temp"
test_perf_on_all git check-attr -a -- $SPARSE_CONE/a
test_done

View File

@ -2259,4 +2259,76 @@ test_expect_success 'worktree is not expanded' '
ensure_not_expanded worktree remove .worktrees/hotfix
'
test_expect_success 'check-attr with pathspec inside sparse definition' '
init_repos &&
echo "a -crlf myAttr" >>.gitattributes &&
run_on_all cp ../.gitattributes ./deep &&
test_all_match git check-attr -a -- deep/a &&
test_all_match git add deep/.gitattributes &&
test_all_match git check-attr -a --cached -- deep/a
'
test_expect_success 'check-attr with pathspec outside sparse definition' '
init_repos &&
echo "a -crlf myAttr" >>.gitattributes &&
run_on_sparse mkdir folder1 &&
run_on_all cp ../.gitattributes ./folder1 &&
run_on_all cp a folder1/a &&
test_all_match git check-attr -a -- folder1/a &&
git -C full-checkout add folder1/.gitattributes &&
test_sparse_match git add --sparse folder1/.gitattributes &&
test_all_match git commit -m "add .gitattributes" &&
test_sparse_match git sparse-checkout reapply &&
test_all_match git check-attr -a --cached -- folder1/a
'
# NEEDSWORK: The 'diff --check' test is left as 'test_expect_failure' due
# to an underlying issue in oneway_diff() within diff-lib.c.
# 'do_oneway_diff()' is not called as expected for paths that could match
# inside of a sparse directory. Specifically, the 'ce_path_match()' function
# fails to recognize files inside a sparse directory (e.g., when 'folder1/'
# is a sparse directory, 'folder1/a' cannot be recognized). The goal is to
# proceed with 'do_oneway_diff()' if the pathspec could match inside of a
# sparse directory.
test_expect_failure 'diff --check with pathspec outside sparse definition' '
init_repos &&
write_script edit-contents <<-\EOF &&
echo "a " >"$1"
EOF
test_all_match git config core.whitespace -trailing-space,-space-before-tab &&
echo "a whitespace=trailing-space,space-before-tab" >>.gitattributes &&
run_on_all mkdir -p folder1 &&
run_on_all cp ../.gitattributes ./folder1 &&
test_all_match git add --sparse folder1/.gitattributes &&
run_on_all ../edit-contents folder1/a &&
test_all_match git add --sparse folder1/a &&
test_sparse_match git sparse-checkout reapply &&
test_all_match test_must_fail git diff --check --cached -- folder1/a
'
test_expect_success 'sparse-index is not expanded: check-attr' '
init_repos &&
echo "a -crlf myAttr" >>.gitattributes &&
mkdir ./sparse-index/folder1 &&
cp ./sparse-index/a ./sparse-index/folder1/a &&
cp .gitattributes ./sparse-index/deep &&
cp .gitattributes ./sparse-index/folder1 &&
git -C sparse-index add deep/.gitattributes &&
git -C sparse-index add --sparse folder1/.gitattributes &&
ensure_not_expanded check-attr -a --cached -- deep/a &&
ensure_not_expanded check-attr -a --cached -- folder1/a
'
test_done