Merge branch 'jc/calloc-fix'
[git] / t / t1092-sparse-checkout-compatibility.sh
1 #!/bin/sh
2
3 test_description='compare full workdir to sparse workdir'
4
5 . ./test-lib.sh
6
7 test_expect_success 'setup' '
8         git init initial-repo &&
9         (
10                 cd initial-repo &&
11                 echo a >a &&
12                 echo "after deep" >e &&
13                 echo "after folder1" >g &&
14                 echo "after x" >z &&
15                 mkdir folder1 folder2 deep x &&
16                 mkdir deep/deeper1 deep/deeper2 &&
17                 mkdir deep/deeper1/deepest &&
18                 echo "after deeper1" >deep/e &&
19                 echo "after deepest" >deep/deeper1/e &&
20                 cp a folder1 &&
21                 cp a folder2 &&
22                 cp a x &&
23                 cp a deep &&
24                 cp a deep/deeper1 &&
25                 cp a deep/deeper2 &&
26                 cp a deep/deeper1/deepest &&
27                 cp -r deep/deeper1/deepest deep/deeper2 &&
28                 git add . &&
29                 git commit -m "initial commit" &&
30                 git checkout -b base &&
31                 for dir in folder1 folder2 deep
32                 do
33                         git checkout -b update-$dir &&
34                         echo "updated $dir" >$dir/a &&
35                         git commit -a -m "update $dir" || return 1
36                 done &&
37
38                 git checkout -b rename-base base &&
39                 echo >folder1/larger-content <<-\EOF &&
40                 matching
41                 lines
42                 help
43                 inexact
44                 renames
45                 EOF
46                 cp folder1/larger-content folder2/ &&
47                 cp folder1/larger-content deep/deeper1/ &&
48                 git add . &&
49                 git commit -m "add interesting rename content" &&
50
51                 git checkout -b rename-out-to-out rename-base &&
52                 mv folder1/a folder2/b &&
53                 mv folder1/larger-content folder2/edited-content &&
54                 echo >>folder2/edited-content &&
55                 git add . &&
56                 git commit -m "rename folder1/... to folder2/..." &&
57
58                 git checkout -b rename-out-to-in rename-base &&
59                 mv folder1/a deep/deeper1/b &&
60                 mv folder1/larger-content deep/deeper1/edited-content &&
61                 echo >>deep/deeper1/edited-content &&
62                 git add . &&
63                 git commit -m "rename folder1/... to deep/deeper1/..." &&
64
65                 git checkout -b rename-in-to-out rename-base &&
66                 mv deep/deeper1/a folder1/b &&
67                 mv deep/deeper1/larger-content folder1/edited-content &&
68                 echo >>folder1/edited-content &&
69                 git add . &&
70                 git commit -m "rename deep/deeper1/... to folder1/..." &&
71
72                 git checkout -b deepest base &&
73                 echo "updated deepest" >deep/deeper1/deepest/a &&
74                 git commit -a -m "update deepest" &&
75
76                 git checkout -f base &&
77                 git reset --hard
78         )
79 '
80
81 init_repos () {
82         rm -rf full-checkout sparse-checkout sparse-index &&
83
84         # create repos in initial state
85         cp -r initial-repo full-checkout &&
86         git -C full-checkout reset --hard &&
87
88         cp -r initial-repo sparse-checkout &&
89         git -C sparse-checkout reset --hard &&
90         git -C sparse-checkout sparse-checkout init --cone &&
91
92         # initialize sparse-checkout definitions
93         git -C sparse-checkout sparse-checkout set deep
94 }
95
96 run_on_sparse () {
97         (
98                 cd sparse-checkout &&
99                 $* >../sparse-checkout-out 2>../sparse-checkout-err
100         )
101 }
102
103 run_on_all () {
104         (
105                 cd full-checkout &&
106                 $* >../full-checkout-out 2>../full-checkout-err
107         ) &&
108         run_on_sparse $*
109 }
110
111 test_all_match () {
112         run_on_all $* &&
113         test_cmp full-checkout-out sparse-checkout-out &&
114         test_cmp full-checkout-err sparse-checkout-err
115 }
116
117 test_expect_success 'status with options' '
118         init_repos &&
119         test_all_match git status --porcelain=v2 &&
120         test_all_match git status --porcelain=v2 -z -u &&
121         test_all_match git status --porcelain=v2 -uno &&
122         run_on_all "touch README.md" &&
123         test_all_match git status --porcelain=v2 &&
124         test_all_match git status --porcelain=v2 -z -u &&
125         test_all_match git status --porcelain=v2 -uno &&
126         test_all_match git add README.md &&
127         test_all_match git status --porcelain=v2 &&
128         test_all_match git status --porcelain=v2 -z -u &&
129         test_all_match git status --porcelain=v2 -uno
130 '
131
132 test_expect_success 'add, commit, checkout' '
133         init_repos &&
134
135         write_script edit-contents <<-\EOF &&
136         echo text >>$1
137         EOF
138         run_on_all "../edit-contents README.md" &&
139
140         test_all_match git add README.md &&
141         test_all_match git status --porcelain=v2 &&
142         test_all_match git commit -m "Add README.md" &&
143
144         test_all_match git checkout HEAD~1 &&
145         test_all_match git checkout - &&
146
147         run_on_all "../edit-contents README.md" &&
148
149         test_all_match git add -A &&
150         test_all_match git status --porcelain=v2 &&
151         test_all_match git commit -m "Extend README.md" &&
152
153         test_all_match git checkout HEAD~1 &&
154         test_all_match git checkout - &&
155
156         run_on_all "../edit-contents deep/newfile" &&
157
158         test_all_match git status --porcelain=v2 -uno &&
159         test_all_match git status --porcelain=v2 &&
160         test_all_match git add . &&
161         test_all_match git status --porcelain=v2 &&
162         test_all_match git commit -m "add deep/newfile" &&
163
164         test_all_match git checkout HEAD~1 &&
165         test_all_match git checkout -
166 '
167
168 test_expect_success 'checkout and reset --hard' '
169         init_repos &&
170
171         test_all_match git checkout update-folder1 &&
172         test_all_match git status --porcelain=v2 &&
173
174         test_all_match git checkout update-deep &&
175         test_all_match git status --porcelain=v2 &&
176
177         test_all_match git checkout -b reset-test &&
178         test_all_match git reset --hard deepest &&
179         test_all_match git reset --hard update-folder1 &&
180         test_all_match git reset --hard update-folder2
181 '
182
183 test_expect_success 'diff --staged' '
184         init_repos &&
185
186         write_script edit-contents <<-\EOF &&
187         echo text >>README.md
188         EOF
189         run_on_all "../edit-contents" &&
190
191         test_all_match git diff &&
192         test_all_match git diff --staged &&
193         test_all_match git add README.md &&
194         test_all_match git diff &&
195         test_all_match git diff --staged
196 '
197
198 test_expect_success 'diff with renames' '
199         init_repos &&
200
201         for branch in rename-out-to-out rename-out-to-in rename-in-to-out
202         do
203                 test_all_match git checkout rename-base &&
204                 test_all_match git checkout $branch -- .&&
205                 test_all_match git diff --staged --no-renames &&
206                 test_all_match git diff --staged --find-renames || return 1
207         done
208 '
209
210 test_expect_success 'log with pathspec outside sparse definition' '
211         init_repos &&
212
213         test_all_match git log -- a &&
214         test_all_match git log -- folder1/a &&
215         test_all_match git log -- folder2/a &&
216         test_all_match git log -- deep/a &&
217         test_all_match git log -- deep/deeper1/a &&
218         test_all_match git log -- deep/deeper1/deepest/a &&
219
220         test_all_match git checkout update-folder1 &&
221         test_all_match git log -- folder1/a
222 '
223
224 test_expect_success 'blame with pathspec inside sparse definition' '
225         init_repos &&
226
227         test_all_match git blame a &&
228         test_all_match git blame deep/a &&
229         test_all_match git blame deep/deeper1/a &&
230         test_all_match git blame deep/deeper1/deepest/a
231 '
232
233 # TODO: blame currently does not support blaming files outside of the
234 # sparse definition. It complains that the file doesn't exist locally.
235 test_expect_failure 'blame with pathspec outside sparse definition' '
236         init_repos &&
237
238         test_all_match git blame folder1/a &&
239         test_all_match git blame folder2/a &&
240         test_all_match git blame deep/deeper2/a &&
241         test_all_match git blame deep/deeper2/deepest/a
242 '
243
244 # TODO: reset currently does not behave as expected when in a
245 # sparse-checkout.
246 test_expect_failure 'checkout and reset (mixed)' '
247         init_repos &&
248
249         test_all_match git checkout -b reset-test update-deep &&
250         test_all_match git reset deepest &&
251         test_all_match git reset update-folder1 &&
252         test_all_match git reset update-folder2
253 '
254
255 test_expect_success 'merge' '
256         init_repos &&
257
258         test_all_match git checkout -b merge update-deep &&
259         test_all_match git merge -m "folder1" update-folder1 &&
260         test_all_match git rev-parse HEAD^{tree} &&
261         test_all_match git merge -m "folder2" update-folder2 &&
262         test_all_match git rev-parse HEAD^{tree}
263 '
264
265 test_expect_success 'merge with outside renames' '
266         init_repos &&
267
268         for type in out-to-out out-to-in in-to-out
269         do
270                 test_all_match git reset --hard &&
271                 test_all_match git checkout -f -b merge-$type update-deep &&
272                 test_all_match git merge -m "$type" rename-$type &&
273                 test_all_match git rev-parse HEAD^{tree} || return 1
274         done
275 '
276
277 test_expect_success 'clean' '
278         init_repos &&
279
280         echo bogus >>.gitignore &&
281         run_on_all cp ../.gitignore . &&
282         test_all_match git add .gitignore &&
283         test_all_match git commit -m ignore-bogus-files &&
284
285         run_on_sparse mkdir folder1 &&
286         run_on_all touch folder1/bogus &&
287
288         test_all_match git status --porcelain=v2 &&
289         test_all_match git clean -f &&
290         test_all_match git status --porcelain=v2 &&
291
292         test_all_match git clean -xf &&
293         test_all_match git status --porcelain=v2 &&
294
295         test_all_match git clean -xdf &&
296         test_all_match git status --porcelain=v2 &&
297
298         test_path_is_dir sparse-checkout/folder1
299 '
300
301 test_done