Skip to content

Commit dc6315e

Browse files
committed
Merge branch 'gg/worktree-from-the-above'
In a non-bare repository, the behavior of Git when the core.worktree configuration variable points at a directory that has a repository as its subdirectory, regressed in Git 2.27 days. * gg/worktree-from-the-above: dir: minor refactoring / clean-up dir: traverse into repository
2 parents 4e2a4d1 + d6c9a71 commit dc6315e

File tree

2 files changed

+293
-7
lines changed

2 files changed

+293
-7
lines changed

dir.c

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,7 +1861,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
18611861
*/
18621862
enum path_treatment state;
18631863
int matches_how = 0;
1864-
int nested_repo = 0, check_only, stop_early;
1864+
int check_only, stop_early;
18651865
int old_ignored_nr, old_untracked_nr;
18661866
/* The "len-1" is to strip the final '/' */
18671867
enum exist_status status = directory_exists_in_index(istate, dirname, len-1);
@@ -1893,16 +1893,37 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
18931893

18941894
if ((dir->flags & DIR_SKIP_NESTED_GIT) ||
18951895
!(dir->flags & DIR_NO_GITLINKS)) {
1896+
/*
1897+
* Determine if `dirname` is a nested repo by confirming that:
1898+
* 1) we are in a nonbare repository, and
1899+
* 2) `dirname` is not an immediate parent of `the_repository->gitdir`,
1900+
* which could occur if the git_dir or worktree location was
1901+
* manually configured by the user; see t2205 testcases 1-3 for
1902+
* examples where this matters
1903+
*/
1904+
int nested_repo;
18961905
struct strbuf sb = STRBUF_INIT;
18971906
strbuf_addstr(&sb, dirname);
18981907
nested_repo = is_nonbare_repository_dir(&sb);
1908+
1909+
if (nested_repo) {
1910+
char *real_dirname, *real_gitdir;
1911+
strbuf_addstr(&sb, ".git");
1912+
real_dirname = real_pathdup(sb.buf, 1);
1913+
real_gitdir = real_pathdup(the_repository->gitdir, 1);
1914+
1915+
nested_repo = !!strcmp(real_dirname, real_gitdir);
1916+
free(real_gitdir);
1917+
free(real_dirname);
1918+
}
18991919
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;
1920+
1921+
if (nested_repo) {
1922+
if ((dir->flags & DIR_SKIP_NESTED_GIT) ||
1923+
(matches_how == MATCHED_RECURSIVELY_LEADING_PATHSPEC))
1924+
return path_none;
1925+
return excluded ? path_excluded : path_untracked;
1926+
}
19061927
}
19071928

19081929
if (!(dir->flags & DIR_SHOW_OTHER_DIRECTORIES)) {

t/t2205-add-worktree-config.sh

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
#!/bin/sh
2+
3+
test_description='directory traversal respects user config
4+
5+
This test verifies the traversal of the directory tree when the traversal begins
6+
outside the repository. Two instances for which this can occur are tested:
7+
8+
1) The user manually sets the worktree. For this instance, the test sets
9+
the worktree two levels above the `.git` directory and checks whether we
10+
are able to add to the index those files that are in either (1) the
11+
manually configured worktree directory or (2) the standard worktree
12+
location with respect to the `.git` directory (i.e. ensuring that the
13+
encountered `.git` directory is not treated as belonging to a foreign
14+
nested repository).
15+
2) The user manually sets the `git_dir` while the working directory is
16+
outside the repository. The test checks that files inside the
17+
repository can be added to the index.
18+
'
19+
20+
. ./test-lib.sh
21+
22+
test_expect_success '1a: setup--config worktree' '
23+
mkdir test1 &&
24+
(
25+
cd test1 &&
26+
test_create_repo repo &&
27+
git --git-dir="repo/.git" config core.worktree "$(pwd)" &&
28+
29+
mkdir -p outside-tracked outside-untracked &&
30+
mkdir -p repo/inside-tracked repo/inside-untracked &&
31+
>file-tracked &&
32+
>file-untracked &&
33+
>outside-tracked/file &&
34+
>outside-untracked/file &&
35+
>repo/file-tracked &&
36+
>repo/file-untracked &&
37+
>repo/inside-tracked/file &&
38+
>repo/inside-untracked/file &&
39+
40+
cat >expect-tracked-unsorted <<-EOF &&
41+
../file-tracked
42+
../outside-tracked/file
43+
file-tracked
44+
inside-tracked/file
45+
EOF
46+
47+
cat >expect-untracked-unsorted <<-EOF &&
48+
../file-untracked
49+
../outside-untracked/file
50+
file-untracked
51+
inside-untracked/file
52+
EOF
53+
54+
cat >expect-all-dir-unsorted <<-EOF &&
55+
../file-untracked
56+
../file-tracked
57+
../outside-untracked/
58+
../outside-tracked/
59+
./
60+
EOF
61+
62+
cat expect-tracked-unsorted expect-untracked-unsorted >expect-all-unsorted &&
63+
64+
cat >.gitignore <<-EOF
65+
.gitignore
66+
actual-*
67+
expect-*
68+
EOF
69+
)
70+
'
71+
72+
test_expect_success '1b: pre-add all' '
73+
(
74+
cd test1 &&
75+
local parent_dir="$(pwd)" &&
76+
git -C repo ls-files -o --exclude-standard "$parent_dir" >actual-all-unsorted &&
77+
sort actual-all-unsorted >actual-all &&
78+
sort expect-all-unsorted >expect-all &&
79+
test_cmp expect-all actual-all
80+
)
81+
'
82+
83+
test_expect_success '1c: pre-add dir all' '
84+
(
85+
cd test1 &&
86+
local parent_dir="$(pwd)" &&
87+
git -C repo ls-files -o --directory --exclude-standard "$parent_dir" >actual-all-dir-unsorted &&
88+
sort actual-all-dir-unsorted >actual-all &&
89+
sort expect-all-dir-unsorted >expect-all &&
90+
test_cmp expect-all actual-all
91+
)
92+
'
93+
94+
test_expect_success '1d: post-add tracked' '
95+
(
96+
cd test1 &&
97+
local parent_dir="$(pwd)" &&
98+
(
99+
cd repo &&
100+
git add file-tracked &&
101+
git add inside-tracked &&
102+
git add ../outside-tracked &&
103+
git add "$parent_dir/file-tracked" &&
104+
git ls-files "$parent_dir" >../actual-tracked-unsorted
105+
) &&
106+
sort actual-tracked-unsorted >actual-tracked &&
107+
sort expect-tracked-unsorted >expect-tracked &&
108+
test_cmp expect-tracked actual-tracked
109+
)
110+
'
111+
112+
test_expect_success '1e: post-add untracked' '
113+
(
114+
cd test1 &&
115+
local parent_dir="$(pwd)" &&
116+
git -C repo ls-files -o --exclude-standard "$parent_dir" >actual-untracked-unsorted &&
117+
sort actual-untracked-unsorted >actual-untracked &&
118+
sort expect-untracked-unsorted >expect-untracked &&
119+
test_cmp expect-untracked actual-untracked
120+
)
121+
'
122+
123+
test_expect_success '2a: setup--set git-dir' '
124+
mkdir test2 &&
125+
(
126+
cd test2 &&
127+
test_create_repo repo &&
128+
# create two foreign repositories that should remain untracked
129+
test_create_repo repo-outside &&
130+
test_create_repo repo/repo-inside &&
131+
132+
mkdir -p repo/inside-tracked repo/inside-untracked &&
133+
>repo/file-tracked &&
134+
>repo/file-untracked &&
135+
>repo/inside-tracked/file &&
136+
>repo/inside-untracked/file &&
137+
>repo-outside/file &&
138+
>repo/repo-inside/file &&
139+
140+
cat >expect-tracked-unsorted <<-EOF &&
141+
repo/file-tracked
142+
repo/inside-tracked/file
143+
EOF
144+
145+
cat >expect-untracked-unsorted <<-EOF &&
146+
repo/file-untracked
147+
repo/inside-untracked/file
148+
repo/repo-inside/
149+
repo-outside/
150+
EOF
151+
152+
cat >expect-all-dir-unsorted <<-EOF &&
153+
repo/
154+
repo-outside/
155+
EOF
156+
157+
cat expect-tracked-unsorted expect-untracked-unsorted >expect-all-unsorted &&
158+
159+
cat >.gitignore <<-EOF
160+
.gitignore
161+
actual-*
162+
expect-*
163+
EOF
164+
)
165+
'
166+
167+
test_expect_success '2b: pre-add all' '
168+
(
169+
cd test2 &&
170+
git --git-dir=repo/.git ls-files -o --exclude-standard >actual-all-unsorted &&
171+
sort actual-all-unsorted >actual-all &&
172+
sort expect-all-unsorted >expect-all &&
173+
test_cmp expect-all actual-all
174+
)
175+
'
176+
177+
test_expect_success '2c: pre-add dir all' '
178+
(
179+
cd test2 &&
180+
git --git-dir=repo/.git ls-files -o --directory --exclude-standard >actual-all-dir-unsorted &&
181+
sort actual-all-dir-unsorted >actual-all &&
182+
sort expect-all-dir-unsorted >expect-all &&
183+
test_cmp expect-all actual-all
184+
)
185+
'
186+
187+
test_expect_success '2d: post-add tracked' '
188+
(
189+
cd test2 &&
190+
git --git-dir=repo/.git add repo/file-tracked &&
191+
git --git-dir=repo/.git add repo/inside-tracked &&
192+
git --git-dir=repo/.git ls-files >actual-tracked-unsorted &&
193+
sort actual-tracked-unsorted >actual-tracked &&
194+
sort expect-tracked-unsorted >expect-tracked &&
195+
test_cmp expect-tracked actual-tracked
196+
)
197+
'
198+
199+
test_expect_success '2e: post-add untracked' '
200+
(
201+
cd test2 &&
202+
git --git-dir=repo/.git ls-files -o --exclude-standard >actual-untracked-unsorted &&
203+
sort actual-untracked-unsorted >actual-untracked &&
204+
sort expect-untracked-unsorted >expect-untracked &&
205+
test_cmp expect-untracked actual-untracked
206+
)
207+
'
208+
209+
test_expect_success '3a: setup--add repo dir' '
210+
mkdir test3 &&
211+
(
212+
cd test3 &&
213+
test_create_repo repo &&
214+
215+
mkdir -p repo/inside-tracked repo/inside-ignored &&
216+
>repo/file-tracked &&
217+
>repo/file-ignored &&
218+
>repo/inside-tracked/file &&
219+
>repo/inside-ignored/file &&
220+
221+
cat >.gitignore <<-EOF &&
222+
.gitignore
223+
actual-*
224+
expect-*
225+
*ignored
226+
EOF
227+
228+
cat >expect-tracked-unsorted <<-EOF &&
229+
repo/file-tracked
230+
repo/inside-tracked/file
231+
EOF
232+
233+
cat >expect-ignored-unsorted <<-EOF
234+
repo/file-ignored
235+
repo/inside-ignored/
236+
.gitignore
237+
actual-ignored-unsorted
238+
expect-ignored-unsorted
239+
expect-tracked-unsorted
240+
EOF
241+
)
242+
'
243+
244+
test_expect_success '3b: ignored' '
245+
(
246+
cd test3 &&
247+
git --git-dir=repo/.git ls-files -io --directory --exclude-standard >actual-ignored-unsorted &&
248+
sort actual-ignored-unsorted >actual-ignored &&
249+
sort expect-ignored-unsorted >expect-ignored &&
250+
test_cmp expect-ignored actual-ignored
251+
)
252+
'
253+
254+
test_expect_success '3c: add repo' '
255+
(
256+
cd test3 &&
257+
git --git-dir=repo/.git add repo &&
258+
git --git-dir=repo/.git ls-files >actual-tracked-unsorted &&
259+
sort actual-tracked-unsorted >actual-tracked &&
260+
sort expect-tracked-unsorted >expect-tracked &&
261+
test_cmp expect-tracked actual-tracked
262+
)
263+
'
264+
265+
test_done

0 commit comments

Comments
 (0)