Skip to content

Commit 4723ae1

Browse files
Cheskaqiqigitster
authored andcommitted
attr.c: read attributes in a sparse directory
Before this patch, git check-attr was unable to read the attributes from a .gitattributes file within a sparse directory. The original comment was operating under the assumption that users are only interested in files or directories inside the cones. Therefore, in the original code, in the case of a cone-mode sparse-checkout, we didn't load the .gitattributes file. However, this behavior can lead to missing attributes for files inside sparse directories, causing inconsistencies in file handling. To resolve this, revise 'git check-attr' to allow attribute reading for files in sparse directories from the corresponding .gitattributes files: 1.Utilize path_in_cone_mode_sparse_checkout() and index_name_pos_sparse to check if a path falls within a sparse directory. 2.If path is inside a sparse directory, employ the value of index_name_pos_sparse() to find the sparse directory containing path and path relative to sparse directory. Proceed to read attributes from the tree OID of the sparse directory using read_attr_from_blob(). 3.If path is not inside a sparse directory,ensure that attributes are fetched from the index blob with read_blob_data_from_index(). Change the test 'check-attr with pathspec outside sparse definition' to 'test_expect_success' to reflect that the attributes inside a sparse directory can now be read. Ensure that the sparse index case works correctly for git check-attr to illustrate the successful handling of attributes within sparse directories. Helped-by: Victoria Dye <[email protected]> Signed-off-by: Shuqi Liang <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent fd4faf7 commit 4723ae1

File tree

2 files changed

+48
-19
lines changed

2 files changed

+48
-19
lines changed

attr.c

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -808,35 +808,56 @@ static struct attr_stack *read_attr_from_blob(struct index_state *istate,
808808
static struct attr_stack *read_attr_from_index(struct index_state *istate,
809809
const char *path, unsigned flags)
810810
{
811+
struct attr_stack *stack = NULL;
811812
char *buf;
812813
unsigned long size;
814+
int sparse_dir_pos = -1;
813815

814816
if (!istate)
815817
return NULL;
816818

817819
/*
818-
* The .gitattributes file only applies to files within its
819-
* parent directory. In the case of cone-mode sparse-checkout,
820-
* the .gitattributes file is sparse if and only if all paths
821-
* within that directory are also sparse. Thus, don't load the
822-
* .gitattributes file since it will not matter.
823-
*
824-
* In the case of a sparse index, it is critical that we don't go
825-
* looking for a .gitattributes file, as doing so would cause the
826-
* index to expand.
820+
* When handling sparse-checkouts, .gitattributes files
821+
* may reside within a sparse directory. We distinguish
822+
* whether a path exists directly in the index or not by
823+
* evaluating if 'pos' is negative.
824+
* If 'pos' is negative, the path is not directly present
825+
* in the index and is likely within a sparse directory.
826+
* For paths not in the index, The absolute value of 'pos'
827+
* minus 1 gives us the position where the path would be
828+
* inserted in lexicographic order within the index.
829+
* We then subtract another 1 from this value
830+
* (sparse_dir_pos = -pos - 2) to find the position of the
831+
* last index entry which is lexicographically smaller than
832+
* the path. This would be the sparse directory containing
833+
* the path. By identifying the sparse directory containing
834+
* the path, we can correctly read the attributes specified
835+
* in the .gitattributes file from the tree object of the
836+
* sparse directory.
827837
*/
828-
if (!path_in_cone_mode_sparse_checkout(path, istate))
829-
return NULL;
838+
if (!path_in_cone_mode_sparse_checkout(path, istate)) {
839+
int pos = index_name_pos_sparse(istate, path, strlen(path));
830840

831-
buf = read_blob_data_from_index(istate, path, &size);
832-
if (!buf)
833-
return NULL;
834-
if (size >= ATTR_MAX_FILE_SIZE) {
835-
warning(_("ignoring overly large gitattributes blob '%s'"), path);
836-
return NULL;
841+
if (pos < 0)
842+
sparse_dir_pos = -pos - 2;
837843
}
838844

839-
return read_attr_from_buf(buf, path, flags);
845+
if (sparse_dir_pos >= 0 &&
846+
S_ISSPARSEDIR(istate->cache[sparse_dir_pos]->ce_mode) &&
847+
!strncmp(istate->cache[sparse_dir_pos]->name, path, ce_namelen(istate->cache[sparse_dir_pos]))) {
848+
const char *relative_path = path + ce_namelen(istate->cache[sparse_dir_pos]);
849+
stack = read_attr_from_blob(istate, &istate->cache[sparse_dir_pos]->oid, relative_path, flags);
850+
} else {
851+
buf = read_blob_data_from_index(istate, path, &size);
852+
if (!buf)
853+
return NULL;
854+
if (size >= ATTR_MAX_FILE_SIZE) {
855+
warning(_("ignoring overly large gitattributes blob '%s'"), path);
856+
return NULL;
857+
}
858+
stack = read_attr_from_buf(buf, path, flags);
859+
}
860+
return stack;
840861
}
841862

842863
static struct attr_stack *read_attr(struct index_state *istate,

t/t1092-sparse-checkout-compatibility.sh

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2271,7 +2271,7 @@ test_expect_success 'check-attr with pathspec inside sparse definition' '
22712271
test_all_match git check-attr -a --cached -- deep/a
22722272
'
22732273

2274-
test_expect_failure 'check-attr with pathspec outside sparse definition' '
2274+
test_expect_success 'check-attr with pathspec outside sparse definition' '
22752275
init_repos &&
22762276
22772277
echo "a -crlf myAttr" >>.gitattributes &&
@@ -2288,6 +2288,14 @@ test_expect_failure 'check-attr with pathspec outside sparse definition' '
22882288
test_all_match git check-attr -a --cached -- folder1/a
22892289
'
22902290

2291+
# NEEDSWORK: The 'diff --check' test is left as 'test_expect_failure' due
2292+
# to an underlying issue in oneway_diff() within diff-lib.c.
2293+
# 'do_oneway_diff()' is not called as expected for paths that could match
2294+
# inside of a sparse directory. Specifically, the 'ce_path_match()' function
2295+
# fails to recognize files inside a sparse directory (e.g., when 'folder1/'
2296+
# is a sparse directory, 'folder1/a' cannot be recognized). The goal is to
2297+
# proceed with 'do_oneway_diff()' if the pathspec could match inside of a
2298+
# sparse directory.
22912299
test_expect_failure 'diff --check with pathspec outside sparse definition' '
22922300
init_repos &&
22932301

0 commit comments

Comments
 (0)