Merge branch 'sl/sparse-check-attr' into next
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:
57
attr.c
57
attr.c
@ -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,
|
static struct attr_stack *read_attr_from_index(struct index_state *istate,
|
||||||
const char *path, unsigned flags)
|
const char *path, unsigned flags)
|
||||||
{
|
{
|
||||||
|
struct attr_stack *stack = NULL;
|
||||||
char *buf;
|
char *buf;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
|
int sparse_dir_pos = -1;
|
||||||
|
|
||||||
if (!istate)
|
if (!istate)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The .gitattributes file only applies to files within its
|
* When handling sparse-checkouts, .gitattributes files
|
||||||
* parent directory. In the case of cone-mode sparse-checkout,
|
* may reside within a sparse directory. We distinguish
|
||||||
* the .gitattributes file is sparse if and only if all paths
|
* whether a path exists directly in the index or not by
|
||||||
* within that directory are also sparse. Thus, don't load the
|
* evaluating if 'pos' is negative.
|
||||||
* .gitattributes file since it will not matter.
|
* If 'pos' is negative, the path is not directly present
|
||||||
*
|
* in the index and is likely within a sparse directory.
|
||||||
* In the case of a sparse index, it is critical that we don't go
|
* For paths not in the index, The absolute value of 'pos'
|
||||||
* looking for a .gitattributes file, as doing so would cause the
|
* minus 1 gives us the position where the path would be
|
||||||
* index to expand.
|
* 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))
|
if (!path_in_cone_mode_sparse_checkout(path, istate)) {
|
||||||
return NULL;
|
int pos = index_name_pos_sparse(istate, path, strlen(path));
|
||||||
|
|
||||||
buf = read_blob_data_from_index(istate, path, &size);
|
if (pos < 0)
|
||||||
if (!buf)
|
sparse_dir_pos = -pos - 2;
|
||||||
return NULL;
|
|
||||||
if (size >= ATTR_MAX_FILE_SIZE) {
|
|
||||||
warning(_("ignoring overly large gitattributes blob '%s'"), path);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
static struct attr_stack *read_attr(struct index_state *istate,
|
||||||
|
@ -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,
|
argc = parse_options(argc, argv, prefix, check_attr_options,
|
||||||
check_attr_usage, PARSE_OPT_KEEP_DASHDASH);
|
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) {
|
if (repo_read_index(the_repository) < 0) {
|
||||||
die("invalid cache");
|
die("invalid cache");
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
test_perf_on_all git diff-tree HEAD -- $SPARSE_CONE/a
|
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 worktree add ../temp && git worktree remove ../temp"
|
||||||
|
test_perf_on_all git check-attr -a -- $SPARSE_CONE/a
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
@ -2259,4 +2259,76 @@ test_expect_success 'worktree is not expanded' '
|
|||||||
ensure_not_expanded worktree remove .worktrees/hotfix
|
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
|
test_done
|
||||||
|
Reference in New Issue
Block a user