Skip to content

Commit e6187c9

Browse files
committed
Merge branch 'gg/worktree-from-the-above' into seen
With a non-bare repository, with core.worktree pointing at a directory that has the repository as its subdirectory, regressed in Git 2.27 days. * gg/worktree-from-the-above: dir: minor refactoring / clean-up dir: cache git_dir's realpath dir: traverse into repository
2 parents f0c9a9a + cc82ad7 commit e6187c9

File tree

2 files changed

+341
-23
lines changed

2 files changed

+341
-23
lines changed

dir.c

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,22 @@ struct cached_dir {
4747
struct untracked_cache_dir *ucd;
4848
};
4949

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+
5061
static enum path_treatment read_directory_recursive(struct dir_struct *dir,
5162
struct index_state *istate, const char *path, int len,
5263
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);
5466
static int resolve_dtype(int dtype, struct index_state *istate,
5567
const char *path, int len);
5668
struct dirent *readdir_skip_dot_and_dotdot(DIR *dirp)
@@ -1852,7 +1864,8 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
18521864
struct index_state *istate,
18531865
struct untracked_cache_dir *untracked,
18541866
const char *dirname, int len, int baselen, int excluded,
1855-
const struct pathspec *pathspec)
1867+
const struct pathspec *pathspec,
1868+
struct traversal_cache *cache)
18561869
{
18571870
/*
18581871
* 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,
18611874
*/
18621875
enum path_treatment state;
18631876
int matches_how = 0;
1864-
int nested_repo = 0, check_only, stop_early;
1877+
int check_only, stop_early;
18651878
int old_ignored_nr, old_untracked_nr;
18661879
/* The "len-1" is to strip the final '/' */
18671880
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,
18931906

18941907
if ((dir->flags & DIR_SKIP_NESTED_GIT) ||
18951908
!(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;
18961918
struct strbuf sb = STRBUF_INIT;
18971919
strbuf_addstr(&sb, dirname);
18981920
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+
}
18991932
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+
}
19061940
}
19071941

19081942
if (!(dir->flags & DIR_SHOW_OTHER_DIRECTORIES)) {
@@ -1925,7 +1959,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
19251959
return path_excluded;
19261960

19271961
if (read_directory_recursive(dir, istate, dirname, len,
1928-
untracked, 1, 1, pathspec) == path_excluded)
1962+
untracked, 1, 1, pathspec, cache) == path_excluded)
19291963
return path_excluded;
19301964

19311965
return path_none;
@@ -2026,7 +2060,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
20262060
untracked = lookup_untracked(dir->untracked, untracked,
20272061
dirname + baselen, len - baselen);
20282062
state = read_directory_recursive(dir, istate, dirname, len, untracked,
2029-
check_only, stop_early, pathspec);
2063+
check_only, stop_early, pathspec, cache);
20302064

20312065
/* There are a variety of reasons we may need to fixup the state... */
20322066
if (state == path_excluded) {
@@ -2223,7 +2257,8 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,
22232257
struct index_state *istate,
22242258
struct strbuf *path,
22252259
int baselen,
2226-
const struct pathspec *pathspec)
2260+
const struct pathspec *pathspec,
2261+
struct traversal_cache *cache)
22272262
{
22282263
/*
22292264
* 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,
22452280
* with check_only set.
22462281
*/
22472282
return read_directory_recursive(dir, istate, path->buf, path->len,
2248-
cdir->ucd, 1, 0, pathspec);
2283+
cdir->ucd, 1, 0, pathspec, cache);
22492284
/*
22502285
* We get path_recurse in the first run when
22512286
* directory_exists_in_index() returns index_nonexistent. We
@@ -2261,13 +2296,14 @@ static enum path_treatment treat_path(struct dir_struct *dir,
22612296
struct index_state *istate,
22622297
struct strbuf *path,
22632298
int baselen,
2264-
const struct pathspec *pathspec)
2299+
const struct pathspec *pathspec,
2300+
struct traversal_cache *cache)
22652301
{
22662302
int has_path_in_index, dtype, excluded;
22672303

22682304
if (!cdir->d_name)
22692305
return treat_path_fast(dir, cdir, istate, path,
2270-
baselen, pathspec);
2306+
baselen, pathspec, cache);
22712307
if (is_dot_or_dotdot(cdir->d_name) || !fspathcmp(cdir->d_name, ".git"))
22722308
return path_none;
22732309
strbuf_setlen(path, baselen);
@@ -2329,7 +2365,7 @@ static enum path_treatment treat_path(struct dir_struct *dir,
23292365
strbuf_addch(path, '/');
23302366
return treat_directory(dir, istate, untracked,
23312367
path->buf, path->len,
2332-
baselen, excluded, pathspec);
2368+
baselen, excluded, pathspec, cache);
23332369
case DT_REG:
23342370
case DT_LNK:
23352371
if (pathspec &&
@@ -2530,7 +2566,8 @@ static void add_path_to_appropriate_result_list(struct dir_struct *dir,
25302566
static enum path_treatment read_directory_recursive(struct dir_struct *dir,
25312567
struct index_state *istate, const char *base, int baselen,
25322568
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)
25342571
{
25352572
/*
25362573
* 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,
25532590
while (!read_cached_dir(&cdir)) {
25542591
/* check how the file or directory should be treated */
25552592
state = treat_path(dir, untracked, &cdir, istate, &path,
2556-
baselen, pathspec);
2593+
baselen, pathspec, cache);
25572594
dir->visited_paths++;
25582595

25592596
if (state > dir_state)
@@ -2568,7 +2605,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
25682605
subdir_state =
25692606
read_directory_recursive(dir, istate, path.buf,
25702607
path.len, ud,
2571-
check_only, stop_at_first_file, pathspec);
2608+
check_only, stop_at_first_file, pathspec, cache);
25722609
if (subdir_state > dir_state)
25732610
dir_state = subdir_state;
25742611

@@ -2642,7 +2679,8 @@ int check_dir_entry_contains(const struct dir_entry *out, const struct dir_entry
26422679
static int treat_leading_path(struct dir_struct *dir,
26432680
struct index_state *istate,
26442681
const char *path, int len,
2645-
const struct pathspec *pathspec)
2682+
const struct pathspec *pathspec,
2683+
struct traversal_cache *cache)
26462684
{
26472685
struct strbuf sb = STRBUF_INIT;
26482686
struct strbuf subdir = STRBUF_INIT;
@@ -2694,7 +2732,8 @@ static int treat_leading_path(struct dir_struct *dir,
26942732
strbuf_reset(&subdir);
26952733
strbuf_add(&subdir, path+prevlen, baselen-prevlen);
26962734
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);
26982737

26992738
if (state != path_recurse)
27002739
break; /* do not recurse into it */
@@ -2967,6 +3006,9 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,
29673006
const char *path, int len, const struct pathspec *pathspec)
29683007
{
29693008
struct untracked_cache_dir *untracked;
3009+
struct traversal_cache cache = {
3010+
.real_gitdir = NULL,
3011+
};
29703012

29713013
trace2_region_enter("dir", "read_directory", istate->repo);
29723014
dir->visited_paths = 0;
@@ -2984,8 +3026,10 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,
29843026
* e.g. prep_exclude()
29853027
*/
29863028
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);
29893033
QSORT(dir->entries, dir->nr, cmp_dir_entry);
29903034
QSORT(dir->ignored, dir->ignored_nr, cmp_dir_entry);
29913035

0 commit comments

Comments
 (0)