Merge branch 'js/ci-ghwf-dedup-tests'
[git] / t / t1501-work-tree.sh
1 #!/bin/sh
2
3 test_description='test separate work tree'
4 . ./test-lib.sh
5
6 test_expect_success 'setup' '
7         EMPTY_TREE=$(git write-tree) &&
8         EMPTY_BLOB=$(git hash-object -t blob --stdin </dev/null) &&
9         CHANGED_BLOB=$(echo changed | git hash-object -t blob --stdin) &&
10         EMPTY_BLOB7=$(echo $EMPTY_BLOB | sed "s/\(.......\).*/\1/") &&
11         CHANGED_BLOB7=$(echo $CHANGED_BLOB | sed "s/\(.......\).*/\1/") &&
12
13         mkdir -p work/sub/dir &&
14         mkdir -p work2 &&
15         mv .git repo.git
16 '
17
18 test_expect_success 'setup: helper for testing rev-parse' '
19         test_rev_parse() {
20                 echo $1 >expected.bare &&
21                 echo $2 >expected.inside-git &&
22                 echo $3 >expected.inside-worktree &&
23                 if test $# -ge 4
24                 then
25                         echo $4 >expected.prefix
26                 fi &&
27
28                 git rev-parse --is-bare-repository >actual.bare &&
29                 git rev-parse --is-inside-git-dir >actual.inside-git &&
30                 git rev-parse --is-inside-work-tree >actual.inside-worktree &&
31                 if test $# -ge 4
32                 then
33                         git rev-parse --show-prefix >actual.prefix
34                 fi &&
35
36                 test_cmp expected.bare actual.bare &&
37                 test_cmp expected.inside-git actual.inside-git &&
38                 test_cmp expected.inside-worktree actual.inside-worktree &&
39                 if test $# -ge 4
40                 then
41                         # rev-parse --show-prefix should output
42                         # a single newline when at the top of the work tree,
43                         # but we test for that separately.
44                         test -z "$4" && test_must_be_empty actual.prefix ||
45                         test_cmp expected.prefix actual.prefix
46                 fi
47         }
48 '
49
50 test_expect_success 'setup: core.worktree = relative path' '
51         sane_unset GIT_WORK_TREE &&
52         GIT_DIR=repo.git &&
53         GIT_CONFIG="$(pwd)"/$GIT_DIR/config &&
54         export GIT_DIR GIT_CONFIG &&
55         git config core.worktree ../work
56 '
57
58 test_expect_success 'outside' '
59         test_rev_parse false false false
60 '
61
62 test_expect_success 'inside work tree' '
63         (
64                 cd work &&
65                 GIT_DIR=../repo.git &&
66                 GIT_CONFIG="$(pwd)"/$GIT_DIR/config &&
67                 test_rev_parse false false true ""
68         )
69 '
70
71 test_expect_success 'empty prefix is actually written out' '
72         echo >expected &&
73         (
74                 cd work &&
75                 GIT_DIR=../repo.git &&
76                 GIT_CONFIG="$(pwd)"/$GIT_DIR/config &&
77                 git rev-parse --show-prefix >../actual
78         ) &&
79         test_cmp expected actual
80 '
81
82 test_expect_success 'subdir of work tree' '
83         (
84                 cd work/sub/dir &&
85                 GIT_DIR=../../../repo.git &&
86                 GIT_CONFIG="$(pwd)"/$GIT_DIR/config &&
87                 test_rev_parse false false true sub/dir/
88         )
89 '
90
91 test_expect_success 'setup: core.worktree = absolute path' '
92         sane_unset GIT_WORK_TREE &&
93         GIT_DIR=$(pwd)/repo.git &&
94         GIT_CONFIG=$GIT_DIR/config &&
95         export GIT_DIR GIT_CONFIG &&
96         git config core.worktree "$(pwd)/work"
97 '
98
99 test_expect_success 'outside' '
100         test_rev_parse false false false &&
101         (
102                 cd work2 &&
103                 test_rev_parse false false false
104         )
105 '
106
107 test_expect_success 'inside work tree' '
108         (
109                 cd work &&
110                 test_rev_parse false false true ""
111         )
112 '
113
114 test_expect_success 'subdir of work tree' '
115         (
116                 cd work/sub/dir &&
117                 test_rev_parse false false true sub/dir/
118         )
119 '
120
121 test_expect_success 'setup: GIT_WORK_TREE=relative (override core.worktree)' '
122         GIT_DIR=$(pwd)/repo.git &&
123         GIT_CONFIG=$GIT_DIR/config &&
124         git config core.worktree non-existent &&
125         GIT_WORK_TREE=work &&
126         export GIT_DIR GIT_CONFIG GIT_WORK_TREE
127 '
128
129 test_expect_success 'outside' '
130         test_rev_parse false false false &&
131         (
132                 cd work2 &&
133                 test_rev_parse false false false
134         )
135 '
136
137 test_expect_success 'inside work tree' '
138         (
139                 cd work &&
140                 GIT_WORK_TREE=. &&
141                 test_rev_parse false false true ""
142         )
143 '
144
145 test_expect_success 'subdir of work tree' '
146         (
147                 cd work/sub/dir &&
148                 GIT_WORK_TREE=../.. &&
149                 test_rev_parse false false true sub/dir/
150         )
151 '
152
153 test_expect_success 'setup: GIT_WORK_TREE=absolute, below git dir' '
154         mv work repo.git/work &&
155         mv work2 repo.git/work2 &&
156         GIT_DIR=$(pwd)/repo.git &&
157         GIT_CONFIG=$GIT_DIR/config &&
158         GIT_WORK_TREE=$(pwd)/repo.git/work &&
159         export GIT_DIR GIT_CONFIG GIT_WORK_TREE
160 '
161
162 test_expect_success 'outside' '
163         echo outside &&
164         test_rev_parse false false false
165 '
166
167 test_expect_success 'in repo.git' '
168         (
169                 cd repo.git &&
170                 test_rev_parse false true false
171         ) &&
172         (
173                 cd repo.git/objects &&
174                 test_rev_parse false true false
175         ) &&
176         (
177                 cd repo.git/work2 &&
178                 test_rev_parse false true false
179         )
180 '
181
182 test_expect_success 'inside work tree' '
183         (
184                 cd repo.git/work &&
185                 test_rev_parse false true true ""
186         )
187 '
188
189 test_expect_success 'subdir of work tree' '
190         (
191                 cd repo.git/work/sub/dir &&
192                 test_rev_parse false true true sub/dir/
193         )
194 '
195
196 test_expect_success 'find work tree from repo' '
197         echo sub/dir/untracked >expected &&
198         cat <<-\EOF >repo.git/work/.gitignore &&
199         expected.*
200         actual.*
201         .gitignore
202         EOF
203         >repo.git/work/sub/dir/untracked &&
204         (
205                 cd repo.git &&
206                 git ls-files --others --exclude-standard >../actual
207         ) &&
208         test_cmp expected actual
209 '
210
211 test_expect_success 'find work tree from work tree' '
212         echo sub/dir/tracked >expected &&
213         >repo.git/work/sub/dir/tracked &&
214         (
215                 cd repo.git/work/sub/dir &&
216                 git --git-dir=../../.. add tracked
217         ) &&
218         (
219                 cd repo.git &&
220                 git ls-files >../actual
221         ) &&
222         test_cmp expected actual
223 '
224
225 test_expect_success '_gently() groks relative GIT_DIR & GIT_WORK_TREE' '
226         (
227                 cd repo.git/work/sub/dir &&
228                 GIT_DIR=../../.. &&
229                 GIT_WORK_TREE=../.. &&
230                 GIT_PAGER= &&
231                 export GIT_DIR GIT_WORK_TREE GIT_PAGER &&
232
233                 git diff --exit-code tracked &&
234                 echo changed >tracked &&
235                 test_must_fail git diff --exit-code tracked
236         )
237 '
238
239 test_expect_success 'diff-index respects work tree under .git dir' '
240         cat >diff-index-cached.expected <<-EOF &&
241         :000000 100644 $ZERO_OID $EMPTY_BLOB A  sub/dir/tracked
242         EOF
243         cat >diff-index.expected <<-EOF &&
244         :000000 100644 $ZERO_OID $ZERO_OID A    sub/dir/tracked
245         EOF
246
247         (
248                 GIT_DIR=repo.git &&
249                 GIT_WORK_TREE=repo.git/work &&
250                 export GIT_DIR GIT_WORK_TREE &&
251                 git diff-index $EMPTY_TREE >diff-index.actual &&
252                 git diff-index --cached $EMPTY_TREE >diff-index-cached.actual
253         ) &&
254         test_cmp diff-index.expected diff-index.actual &&
255         test_cmp diff-index-cached.expected diff-index-cached.actual
256 '
257
258 test_expect_success 'diff-files respects work tree under .git dir' '
259         cat >diff-files.expected <<-EOF &&
260         :100644 100644 $EMPTY_BLOB $ZERO_OID M  sub/dir/tracked
261         EOF
262
263         (
264                 GIT_DIR=repo.git &&
265                 GIT_WORK_TREE=repo.git/work &&
266                 export GIT_DIR GIT_WORK_TREE &&
267                 git diff-files >diff-files.actual
268         ) &&
269         test_cmp diff-files.expected diff-files.actual
270 '
271
272 test_expect_success 'git diff respects work tree under .git dir' '
273         cat >diff-TREE.expected <<-EOF &&
274         diff --git a/sub/dir/tracked b/sub/dir/tracked
275         new file mode 100644
276         index 0000000..$CHANGED_BLOB7
277         --- /dev/null
278         +++ b/sub/dir/tracked
279         @@ -0,0 +1 @@
280         +changed
281         EOF
282         cat >diff-TREE-cached.expected <<-EOF &&
283         diff --git a/sub/dir/tracked b/sub/dir/tracked
284         new file mode 100644
285         index 0000000..$EMPTY_BLOB7
286         EOF
287         cat >diff-FILES.expected <<-EOF &&
288         diff --git a/sub/dir/tracked b/sub/dir/tracked
289         index $EMPTY_BLOB7..$CHANGED_BLOB7 100644
290         --- a/sub/dir/tracked
291         +++ b/sub/dir/tracked
292         @@ -0,0 +1 @@
293         +changed
294         EOF
295
296         (
297                 GIT_DIR=repo.git &&
298                 GIT_WORK_TREE=repo.git/work &&
299                 export GIT_DIR GIT_WORK_TREE &&
300                 git diff $EMPTY_TREE >diff-TREE.actual &&
301                 git diff --cached $EMPTY_TREE >diff-TREE-cached.actual &&
302                 git diff >diff-FILES.actual
303         ) &&
304         test_cmp diff-TREE.expected diff-TREE.actual &&
305         test_cmp diff-TREE-cached.expected diff-TREE-cached.actual &&
306         test_cmp diff-FILES.expected diff-FILES.actual
307 '
308
309 test_expect_success 'git grep' '
310         echo dir/tracked >expected.grep &&
311         (
312                 cd repo.git/work/sub &&
313                 GIT_DIR=../.. &&
314                 GIT_WORK_TREE=.. &&
315                 export GIT_DIR GIT_WORK_TREE &&
316                 git grep -l changed >../../../actual.grep
317         ) &&
318         test_cmp expected.grep actual.grep
319 '
320
321 test_expect_success 'git commit' '
322         (
323                 cd repo.git &&
324                 GIT_DIR=. GIT_WORK_TREE=work git commit -a -m done
325         )
326 '
327
328 test_expect_success 'absolute pathspec should fail gracefully' '
329         (
330                 cd repo.git &&
331                 test_might_fail git config --unset core.worktree &&
332                 test_must_fail git log HEAD -- /home
333         )
334 '
335
336 test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
337         >dummy_file &&
338         echo git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file &&
339         git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
340 '
341
342 test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
343         GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
344         test-tool subprocess --setup-work-tree rev-parse --show-toplevel >actual &&
345         echo "$(pwd)/repo.git/work" >expected &&
346         test_cmp expected actual
347 '
348
349 test_expect_success 'Multi-worktree setup' '
350         mkdir work &&
351         mkdir -p repo.git/repos/foo &&
352         cp repo.git/HEAD repo.git/index repo.git/repos/foo &&
353         { cp repo.git/sharedindex.* repo.git/repos/foo || :; } &&
354         sane_unset GIT_DIR GIT_CONFIG GIT_WORK_TREE
355 '
356
357 test_expect_success 'GIT_DIR set (1)' '
358         echo "gitdir: repo.git/repos/foo" >gitfile &&
359         echo ../.. >repo.git/repos/foo/commondir &&
360         (
361                 cd work &&
362                 GIT_DIR=../gitfile git rev-parse --git-common-dir >actual &&
363                 test-tool path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
364                 test_cmp expect actual
365         )
366 '
367
368 test_expect_success 'GIT_DIR set (2)' '
369         echo "gitdir: repo.git/repos/foo" >gitfile &&
370         echo "$(pwd)/repo.git" >repo.git/repos/foo/commondir &&
371         (
372                 cd work &&
373                 GIT_DIR=../gitfile git rev-parse --git-common-dir >actual &&
374                 test-tool path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
375                 test_cmp expect actual
376         )
377 '
378
379 test_expect_success 'Auto discovery' '
380         echo "gitdir: repo.git/repos/foo" >.git &&
381         echo ../.. >repo.git/repos/foo/commondir &&
382         (
383                 cd work &&
384                 git rev-parse --git-common-dir >actual &&
385                 test-tool path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
386                 test_cmp expect actual &&
387                 echo haha >data1 &&
388                 git add data1 &&
389                 git ls-files --full-name :/ | grep data1 >actual &&
390                 echo work/data1 >expect &&
391                 test_cmp expect actual
392         )
393 '
394
395 test_expect_success '$GIT_DIR/common overrides core.worktree' '
396         mkdir elsewhere &&
397         git --git-dir=repo.git config core.worktree "$TRASH_DIRECTORY/elsewhere" &&
398         echo "gitdir: repo.git/repos/foo" >.git &&
399         echo ../.. >repo.git/repos/foo/commondir &&
400         (
401                 cd work &&
402                 git rev-parse --git-common-dir >actual &&
403                 test-tool path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
404                 test_cmp expect actual &&
405                 echo haha >data2 &&
406                 git add data2 &&
407                 git ls-files --full-name :/ | grep data2 >actual &&
408                 echo work/data2 >expect &&
409                 test_cmp expect actual
410         )
411 '
412
413 test_expect_success '$GIT_WORK_TREE overrides $GIT_DIR/common' '
414         echo "gitdir: repo.git/repos/foo" >.git &&
415         echo ../.. >repo.git/repos/foo/commondir &&
416         (
417                 cd work &&
418                 echo haha >data3 &&
419                 git --git-dir=../.git --work-tree=. add data3 &&
420                 git ls-files --full-name -- :/ | grep data3 >actual &&
421                 echo data3 >expect &&
422                 test_cmp expect actual
423         )
424 '
425
426 test_expect_success 'error out gracefully on invalid $GIT_WORK_TREE' '
427         (
428                 GIT_WORK_TREE=/.invalid/work/tree &&
429                 export GIT_WORK_TREE &&
430                 test_expect_code 128 git rev-parse
431         )
432 '
433
434 test_expect_success 'refs work with relative gitdir and work tree' '
435         git init relative &&
436         git -C relative commit --allow-empty -m one &&
437         git -C relative commit --allow-empty -m two &&
438
439         GIT_DIR=relative/.git GIT_WORK_TREE=relative git reset HEAD^ &&
440
441         git -C relative log -1 --format=%s >actual &&
442         echo one >expect &&
443         test_cmp expect actual
444 '
445
446 test_done