@@ -47,10 +47,22 @@ struct cached_dir {
47
47
struct untracked_cache_dir * ucd ;
48
48
};
49
49
50
+ /*
51
+ * Support data structure for the recursing into the directory tree.
52
+ */
53
+ struct traversal_cache {
54
+ /*
55
+ * The realpath for the `git_dir` may be required in the recursion and is
56
+ * cached for repeated use.
57
+ */
58
+ char * real_gitdir ;
59
+ };
60
+
50
61
static enum path_treatment read_directory_recursive (struct dir_struct * dir ,
51
62
struct index_state * istate , const char * path , int len ,
52
63
struct untracked_cache_dir * untracked ,
53
- int check_only , int stop_at_first_file , const struct pathspec * pathspec );
64
+ int check_only , int stop_at_first_file , const struct pathspec * pathspec ,
65
+ struct traversal_cache * cache );
54
66
static int resolve_dtype (int dtype , struct index_state * istate ,
55
67
const char * path , int len );
56
68
struct dirent * readdir_skip_dot_and_dotdot (DIR * dirp )
@@ -1852,7 +1864,8 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
1852
1864
struct index_state * istate ,
1853
1865
struct untracked_cache_dir * untracked ,
1854
1866
const char * dirname , int len , int baselen , int excluded ,
1855
- const struct pathspec * pathspec )
1867
+ const struct pathspec * pathspec ,
1868
+ struct traversal_cache * cache )
1856
1869
{
1857
1870
/*
1858
1871
* WARNING: From this function, you can return path_recurse or you
@@ -1861,7 +1874,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
1861
1874
*/
1862
1875
enum path_treatment state ;
1863
1876
int matches_how = 0 ;
1864
- int nested_repo = 0 , check_only , stop_early ;
1877
+ int check_only , stop_early ;
1865
1878
int old_ignored_nr , old_untracked_nr ;
1866
1879
/* The "len-1" is to strip the final '/' */
1867
1880
enum exist_status status = directory_exists_in_index (istate , dirname , len - 1 );
@@ -1893,16 +1906,37 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
1893
1906
1894
1907
if ((dir -> flags & DIR_SKIP_NESTED_GIT ) ||
1895
1908
!(dir -> flags & DIR_NO_GITLINKS )) {
1909
+ /*
1910
+ * Determine if `dirname` is a nested repo by confirming that:
1911
+ * 1) we are in a nonbare repository, and
1912
+ * 2) `dirname` is not an immediate parent of `the_repository->gitdir`,
1913
+ * which could occur if the git_dir or worktree location was
1914
+ * manually configured by the user; see t2205 testcases 1-3 for
1915
+ * examples where this matters
1916
+ */
1917
+ int nested_repo ;
1896
1918
struct strbuf sb = STRBUF_INIT ;
1897
1919
strbuf_addstr (& sb , dirname );
1898
1920
nested_repo = is_nonbare_repository_dir (& sb );
1921
+
1922
+ if (nested_repo ) {
1923
+ char * real_dirname ;
1924
+ strbuf_addstr (& sb , ".git" );
1925
+ real_dirname = real_pathdup (sb .buf , 1 );
1926
+ if (!cache -> real_gitdir )
1927
+ cache -> real_gitdir = real_pathdup (the_repository -> gitdir , 1 );
1928
+
1929
+ nested_repo = !!strcmp (real_dirname , cache -> real_gitdir );
1930
+ free (real_dirname );
1931
+ }
1899
1932
strbuf_release (& sb );
1900
- }
1901
- if (nested_repo ) {
1902
- if ((dir -> flags & DIR_SKIP_NESTED_GIT ) ||
1903
- (matches_how == MATCHED_RECURSIVELY_LEADING_PATHSPEC ))
1904
- return path_none ;
1905
- return excluded ? path_excluded : path_untracked ;
1933
+
1934
+ if (nested_repo ) {
1935
+ if ((dir -> flags & DIR_SKIP_NESTED_GIT ) ||
1936
+ (matches_how == MATCHED_RECURSIVELY_LEADING_PATHSPEC ))
1937
+ return path_none ;
1938
+ return excluded ? path_excluded : path_untracked ;
1939
+ }
1906
1940
}
1907
1941
1908
1942
if (!(dir -> flags & DIR_SHOW_OTHER_DIRECTORIES )) {
@@ -1925,7 +1959,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
1925
1959
return path_excluded ;
1926
1960
1927
1961
if (read_directory_recursive (dir , istate , dirname , len ,
1928
- untracked , 1 , 1 , pathspec ) == path_excluded )
1962
+ untracked , 1 , 1 , pathspec , cache ) == path_excluded )
1929
1963
return path_excluded ;
1930
1964
1931
1965
return path_none ;
@@ -2026,7 +2060,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
2026
2060
untracked = lookup_untracked (dir -> untracked , untracked ,
2027
2061
dirname + baselen , len - baselen );
2028
2062
state = read_directory_recursive (dir , istate , dirname , len , untracked ,
2029
- check_only , stop_early , pathspec );
2063
+ check_only , stop_early , pathspec , cache );
2030
2064
2031
2065
/* There are a variety of reasons we may need to fixup the state... */
2032
2066
if (state == path_excluded ) {
@@ -2223,7 +2257,8 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,
2223
2257
struct index_state * istate ,
2224
2258
struct strbuf * path ,
2225
2259
int baselen ,
2226
- const struct pathspec * pathspec )
2260
+ const struct pathspec * pathspec ,
2261
+ struct traversal_cache * cache )
2227
2262
{
2228
2263
/*
2229
2264
* WARNING: From this function, you can return path_recurse or you
@@ -2245,7 +2280,7 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,
2245
2280
* with check_only set.
2246
2281
*/
2247
2282
return read_directory_recursive (dir , istate , path -> buf , path -> len ,
2248
- cdir -> ucd , 1 , 0 , pathspec );
2283
+ cdir -> ucd , 1 , 0 , pathspec , cache );
2249
2284
/*
2250
2285
* We get path_recurse in the first run when
2251
2286
* directory_exists_in_index() returns index_nonexistent. We
@@ -2261,13 +2296,14 @@ static enum path_treatment treat_path(struct dir_struct *dir,
2261
2296
struct index_state * istate ,
2262
2297
struct strbuf * path ,
2263
2298
int baselen ,
2264
- const struct pathspec * pathspec )
2299
+ const struct pathspec * pathspec ,
2300
+ struct traversal_cache * cache )
2265
2301
{
2266
2302
int has_path_in_index , dtype , excluded ;
2267
2303
2268
2304
if (!cdir -> d_name )
2269
2305
return treat_path_fast (dir , cdir , istate , path ,
2270
- baselen , pathspec );
2306
+ baselen , pathspec , cache );
2271
2307
if (is_dot_or_dotdot (cdir -> d_name ) || !fspathcmp (cdir -> d_name , ".git" ))
2272
2308
return path_none ;
2273
2309
strbuf_setlen (path , baselen );
@@ -2329,7 +2365,7 @@ static enum path_treatment treat_path(struct dir_struct *dir,
2329
2365
strbuf_addch (path , '/' );
2330
2366
return treat_directory (dir , istate , untracked ,
2331
2367
path -> buf , path -> len ,
2332
- baselen , excluded , pathspec );
2368
+ baselen , excluded , pathspec , cache );
2333
2369
case DT_REG :
2334
2370
case DT_LNK :
2335
2371
if (pathspec &&
@@ -2530,7 +2566,8 @@ static void add_path_to_appropriate_result_list(struct dir_struct *dir,
2530
2566
static enum path_treatment read_directory_recursive (struct dir_struct * dir ,
2531
2567
struct index_state * istate , const char * base , int baselen ,
2532
2568
struct untracked_cache_dir * untracked , int check_only ,
2533
- int stop_at_first_file , const struct pathspec * pathspec )
2569
+ int stop_at_first_file , const struct pathspec * pathspec ,
2570
+ struct traversal_cache * cache )
2534
2571
{
2535
2572
/*
2536
2573
* WARNING: Do NOT recurse unless path_recurse is returned from
@@ -2553,7 +2590,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
2553
2590
while (!read_cached_dir (& cdir )) {
2554
2591
/* check how the file or directory should be treated */
2555
2592
state = treat_path (dir , untracked , & cdir , istate , & path ,
2556
- baselen , pathspec );
2593
+ baselen , pathspec , cache );
2557
2594
dir -> visited_paths ++ ;
2558
2595
2559
2596
if (state > dir_state )
@@ -2568,7 +2605,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
2568
2605
subdir_state =
2569
2606
read_directory_recursive (dir , istate , path .buf ,
2570
2607
path .len , ud ,
2571
- check_only , stop_at_first_file , pathspec );
2608
+ check_only , stop_at_first_file , pathspec , cache );
2572
2609
if (subdir_state > dir_state )
2573
2610
dir_state = subdir_state ;
2574
2611
@@ -2642,7 +2679,8 @@ int check_dir_entry_contains(const struct dir_entry *out, const struct dir_entry
2642
2679
static int treat_leading_path (struct dir_struct * dir ,
2643
2680
struct index_state * istate ,
2644
2681
const char * path , int len ,
2645
- const struct pathspec * pathspec )
2682
+ const struct pathspec * pathspec ,
2683
+ struct traversal_cache * cache )
2646
2684
{
2647
2685
struct strbuf sb = STRBUF_INIT ;
2648
2686
struct strbuf subdir = STRBUF_INIT ;
@@ -2694,7 +2732,8 @@ static int treat_leading_path(struct dir_struct *dir,
2694
2732
strbuf_reset (& subdir );
2695
2733
strbuf_add (& subdir , path + prevlen , baselen - prevlen );
2696
2734
cdir .d_name = subdir .buf ;
2697
- state = treat_path (dir , NULL , & cdir , istate , & sb , prevlen , pathspec );
2735
+
2736
+ state = treat_path (dir , NULL , & cdir , istate , & sb , prevlen , pathspec , cache );
2698
2737
2699
2738
if (state != path_recurse )
2700
2739
break ; /* do not recurse into it */
@@ -2967,6 +3006,9 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,
2967
3006
const char * path , int len , const struct pathspec * pathspec )
2968
3007
{
2969
3008
struct untracked_cache_dir * untracked ;
3009
+ struct traversal_cache cache = {
3010
+ .real_gitdir = NULL ,
3011
+ };
2970
3012
2971
3013
trace2_region_enter ("dir" , "read_directory" , istate -> repo );
2972
3014
dir -> visited_paths = 0 ;
@@ -2984,8 +3026,10 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,
2984
3026
* e.g. prep_exclude()
2985
3027
*/
2986
3028
dir -> untracked = NULL ;
2987
- if (!len || treat_leading_path (dir , istate , path , len , pathspec ))
2988
- read_directory_recursive (dir , istate , path , len , untracked , 0 , 0 , pathspec );
3029
+ if (!len || treat_leading_path (dir , istate , path , len , pathspec , & cache )) {
3030
+ read_directory_recursive (dir , istate , path , len , untracked , 0 , 0 , pathspec , & cache );
3031
+ }
3032
+ FREE_AND_NULL (cache .real_gitdir );
2989
3033
QSORT (dir -> entries , dir -> nr , cmp_dir_entry );
2990
3034
QSORT (dir -> ignored , dir -> ignored_nr , cmp_dir_entry );
2991
3035
0 commit comments