From 27128996b88f3dd0624324f8eb9648c0754cfa20 Mon Sep 17 00:00:00 2001 From: Goss Geppert Date: Thu, 16 Jun 2022 23:19:55 +0000 Subject: dir: traverse into repository Since 8d92fb2927 (dir: replace exponential algorithm with a linear one, 2020-04-01) traversing into a repository's directory tree when the traversal began outside the repository's standard location has failed because the encountered repository was identified as a nested foreign repository. Prior to this commit, the failure to traverse into a repository's default worktree location was observable from a user's perspective under either of the following conditions (there may be others): 1) Set the `core.worktree` location to a parent directory of the default worktree; or 2) Use the `--git_dir` option while the working directory is outside the repository's default worktree location Under either of these conditions, symptoms of the failure to traverse into the repository's default worktree location include the inability to add files to the index or get a list of untracked files via ls-files. This commit adds a check to determine whether a nested repository that is encountered in recursing a path is actually `the_repository`. If so, we simply treat the directory as if it doesn't contain a nested repository. The commit includes test-cases to reduce the likelihood of future regressions. Signed-off-by: Goss Geppert Reviewed-by: Elijah Newren Signed-off-by: Junio C Hamano --- dir.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'dir.c') diff --git a/dir.c b/dir.c index f2b0f24210..0fd5912b39 100644 --- a/dir.c +++ b/dir.c @@ -1893,9 +1893,28 @@ static enum path_treatment treat_directory(struct dir_struct *dir, if ((dir->flags & DIR_SKIP_NESTED_GIT) || !(dir->flags & DIR_NO_GITLINKS)) { + /* + * Determine if `dirname` is a nested repo by confirming that: + * 1) we are in a nonbare repository, and + * 2) `dirname` is not an immediate parent of `the_repository->gitdir`, + * which could occur if the git_dir or worktree location was + * manually configured by the user; see t2205 testcases 1-3 for + * examples where this matters + */ struct strbuf sb = STRBUF_INIT; strbuf_addstr(&sb, dirname); nested_repo = is_nonbare_repository_dir(&sb); + + if (nested_repo) { + char *real_dirname, *real_gitdir; + strbuf_addstr(&sb, ".git"); + real_dirname = real_pathdup(sb.buf, 1); + real_gitdir = real_pathdup(the_repository->gitdir, 1); + + nested_repo = !!strcmp(real_dirname, real_gitdir); + free(real_gitdir); + free(real_dirname); + } strbuf_release(&sb); } if (nested_repo) { -- cgit v1.3-6-g1900 From d6c9a717558a5ec36516026e68dcad3cbc4df1ff Mon Sep 17 00:00:00 2001 From: Goss Geppert Date: Thu, 16 Jun 2022 23:44:33 +0000 Subject: dir: minor refactoring / clean-up Narrow the scope of the `nested_repo` variable and conditional return statement to the block where the variable is set. Signed-off-by: Goss Geppert Reviewed-by: Elijah Newren Signed-off-by: Junio C Hamano --- dir.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'dir.c') diff --git a/dir.c b/dir.c index 0fd5912b39..4166d1b16a 100644 --- a/dir.c +++ b/dir.c @@ -1861,7 +1861,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir, */ enum path_treatment state; int matches_how = 0; - int nested_repo = 0, check_only, stop_early; + int check_only, stop_early; int old_ignored_nr, old_untracked_nr; /* The "len-1" is to strip the final '/' */ enum exist_status status = directory_exists_in_index(istate, dirname, len-1); @@ -1901,6 +1901,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir, * manually configured by the user; see t2205 testcases 1-3 for * examples where this matters */ + int nested_repo; struct strbuf sb = STRBUF_INIT; strbuf_addstr(&sb, dirname); nested_repo = is_nonbare_repository_dir(&sb); @@ -1916,12 +1917,13 @@ static enum path_treatment treat_directory(struct dir_struct *dir, free(real_dirname); } strbuf_release(&sb); - } - if (nested_repo) { - if ((dir->flags & DIR_SKIP_NESTED_GIT) || - (matches_how == MATCHED_RECURSIVELY_LEADING_PATHSPEC)) - return path_none; - return excluded ? path_excluded : path_untracked; + + if (nested_repo) { + if ((dir->flags & DIR_SKIP_NESTED_GIT) || + (matches_how == MATCHED_RECURSIVELY_LEADING_PATHSPEC)) + return path_none; + return excluded ? path_excluded : path_untracked; + } } if (!(dir->flags & DIR_SHOW_OTHER_DIRECTORIES)) { -- cgit v1.3-6-g1900