Merge branch 'jk/make-protocol-v2-the-default'
[git] / t / t1512-rev-parse-disambiguation.sh
1 #!/bin/sh
2
3 test_description='object name disambiguation
4
5 Create blobs, trees, commits and a tag that all share the same
6 prefix, and make sure "git rev-parse" can take advantage of
7 type information to disambiguate short object names that are
8 not necessarily unique.
9
10 The final history used in the test has five commits, with the bottom
11 one tagged as v1.0.0.  They all have one regular file each.
12
13   +-------------------------------------------+
14   |                                           |
15   |           .-------b3wettvi---- ad2uee     |
16   |          /                   /            |
17   |  a2onsxbvj---czy8f73t--ioiley5o           |
18   |                                           |
19   +-------------------------------------------+
20
21 '
22
23 . ./test-lib.sh
24
25 if ! test_have_prereq SHA1
26 then
27         skip_all='not using SHA-1 for objects'
28         test_done
29 fi
30
31 test_expect_success 'blob and tree' '
32         test_tick &&
33         (
34                 for i in 0 1 2 3 4 5 6 7 8 9
35                 do
36                         echo $i
37                 done &&
38                 echo &&
39                 echo b1rwzyc3
40         ) >a0blgqsjc &&
41
42         # create one blob 0000000000b36
43         git add a0blgqsjc &&
44
45         # create one tree 0000000000cdc
46         git write-tree
47 '
48
49 test_expect_success 'warn ambiguity when no candidate matches type hint' '
50         test_must_fail git rev-parse --verify 000000000^{commit} 2>actual &&
51         test_i18ngrep "short SHA1 000000000 is ambiguous" actual
52 '
53
54 test_expect_success 'disambiguate tree-ish' '
55         # feed tree-ish in an unambiguous way
56         git rev-parse --verify 0000000000cdc:a0blgqsjc &&
57
58         # ambiguous at the object name level, but there is only one
59         # such tree-ish (the other is a blob)
60         git rev-parse --verify 000000000:a0blgqsjc
61 '
62
63 test_expect_success 'disambiguate blob' '
64         sed -e "s/|$//" >patch <<-EOF &&
65         diff --git a/frotz b/frotz
66         index 000000000..ffffff 100644
67         --- a/frotz
68         +++ b/frotz
69         @@ -10,3 +10,4 @@
70          9
71          |
72          b1rwzyc3
73         +irwry
74         EOF
75         (
76                 GIT_INDEX_FILE=frotz &&
77                 export GIT_INDEX_FILE &&
78                 git apply --build-fake-ancestor frotz patch &&
79                 git cat-file blob :frotz >actual
80         ) &&
81         test_cmp a0blgqsjc actual
82 '
83
84 test_expect_success 'disambiguate tree' '
85         commit=$(echo "d7xm" | git commit-tree 000000000) &&
86         # this commit is fffff2e and not ambiguous with the 00000* objects
87         test $(git rev-parse $commit^{tree}) = $(git rev-parse 0000000000cdc)
88 '
89
90 test_expect_success 'first commit' '
91         # create one commit 0000000000e4f
92         git commit -m a2onsxbvj
93 '
94
95 test_expect_success 'disambiguate commit-ish' '
96         # feed commit-ish in an unambiguous way
97         git rev-parse --verify 0000000000e4f^{commit} &&
98
99         # ambiguous at the object name level, but there is only one
100         # such commit (the others are tree and blob)
101         git rev-parse --verify 000000000^{commit} &&
102
103         # likewise
104         git rev-parse --verify 000000000^0
105 '
106
107 test_expect_success 'disambiguate commit' '
108         commit=$(echo "hoaxj" | git commit-tree 0000000000cdc -p 000000000) &&
109         # this commit is ffffffd8 and not ambiguous with the 00000* objects
110         test $(git rev-parse $commit^) = $(git rev-parse 0000000000e4f)
111 '
112
113 test_expect_success 'log name1..name2 takes only commit-ishes on both ends' '
114         # These are underspecified from the prefix-length point of view
115         # to disambiguate the commit with other objects, but there is only
116         # one commit that has 00000* prefix at this point.
117         git log 000000000..000000000 &&
118         git log ..000000000 &&
119         git log 000000000.. &&
120         git log 000000000...000000000 &&
121         git log ...000000000 &&
122         git log 000000000...
123 '
124
125 test_expect_success 'rev-parse name1..name2 takes only commit-ishes on both ends' '
126         # Likewise.
127         git rev-parse 000000000..000000000 &&
128         git rev-parse ..000000000 &&
129         git rev-parse 000000000..
130 '
131
132 test_expect_success 'git log takes only commit-ish' '
133         # Likewise.
134         git log 000000000
135 '
136
137 test_expect_success 'git reset takes only commit-ish' '
138         # Likewise.
139         git reset 000000000
140 '
141
142 test_expect_success 'first tag' '
143         # create one tag 0000000000f8f
144         git tag -a -m j7cp83um v1.0.0
145 '
146
147 test_expect_failure 'two semi-ambiguous commit-ish' '
148         # At this point, we have a tag 0000000000f8f that points
149         # at a commit 0000000000e4f, and a tree and a blob that
150         # share 0000000000 prefix with these tag and commit.
151         #
152         # Once the parser becomes ultra-smart, it could notice that
153         # 0000000000 before ^{commit} name many different objects, but
154         # that only two (HEAD and v1.0.0 tag) can be peeled to commit,
155         # and that peeling them down to commit yield the same commit
156         # without ambiguity.
157         git rev-parse --verify 0000000000^{commit} &&
158
159         # likewise
160         git log 0000000000..0000000000 &&
161         git log ..0000000000 &&
162         git log 0000000000.. &&
163         git log 0000000000...0000000000 &&
164         git log ...0000000000 &&
165         git log 0000000000...
166 '
167
168 test_expect_failure 'three semi-ambiguous tree-ish' '
169         # Likewise for tree-ish.  HEAD, v1.0.0 and HEAD^{tree} share
170         # the prefix but peeling them to tree yields the same thing
171         git rev-parse --verify 0000000000^{tree}
172 '
173
174 test_expect_success 'parse describe name' '
175         # feed an unambiguous describe name
176         git rev-parse --verify v1.0.0-0-g0000000000e4f &&
177
178         # ambiguous at the object name level, but there is only one
179         # such commit (others are blob, tree and tag)
180         git rev-parse --verify v1.0.0-0-g000000000
181 '
182
183 test_expect_success 'more history' '
184         # commit 0000000000043
185         git mv a0blgqsjc d12cr3h8t &&
186         echo h62xsjeu >>d12cr3h8t &&
187         git add d12cr3h8t &&
188
189         test_tick &&
190         git commit -m czy8f73t &&
191
192         # commit 00000000008ec
193         git mv d12cr3h8t j000jmpzn &&
194         echo j08bekfvt >>j000jmpzn &&
195         git add j000jmpzn &&
196
197         test_tick &&
198         git commit -m ioiley5o &&
199
200         # commit 0000000005b0
201         git checkout v1.0.0^0 &&
202         git mv a0blgqsjc f5518nwu &&
203
204         for i in h62xsjeu j08bekfvt kg7xflhm
205         do
206                 echo $i
207         done >>f5518nwu &&
208         git add f5518nwu &&
209
210         test_tick &&
211         git commit -m b3wettvi &&
212         side=$(git rev-parse HEAD) &&
213
214         # commit 000000000066
215         git checkout master &&
216
217         # If you use recursive, merge will fail and you will need to
218         # clean up a0blgqsjc as well.  If you use resolve, merge will
219         # succeed.
220         test_might_fail git merge --no-commit -s recursive $side &&
221         git rm -f f5518nwu j000jmpzn &&
222
223         test_might_fail git rm -f a0blgqsjc &&
224         (
225                 git cat-file blob $side:f5518nwu &&
226                 echo j3l0i9s6
227         ) >ab2gs879 &&
228         git add ab2gs879 &&
229
230         test_tick &&
231         git commit -m ad2uee
232
233 '
234
235 test_expect_failure 'parse describe name taking advantage of generation' '
236         # ambiguous at the object name level, but there is only one
237         # such commit at generation 0
238         git rev-parse --verify v1.0.0-0-g000000000 &&
239
240         # likewise for generation 2 and 4
241         git rev-parse --verify v1.0.0-2-g000000000 &&
242         git rev-parse --verify v1.0.0-4-g000000000
243 '
244
245 # Note: because rev-parse does not even try to disambiguate based on
246 # the generation number, this test currently succeeds for a wrong
247 # reason.  When it learns to use the generation number, the previous
248 # test should succeed, and also this test should fail because the
249 # describe name used in the test with generation number can name two
250 # commits.  Make sure that such a future enhancement does not randomly
251 # pick one.
252 test_expect_success 'parse describe name not ignoring ambiguity' '
253         # ambiguous at the object name level, and there are two such
254         # commits at generation 1
255         test_must_fail git rev-parse --verify v1.0.0-1-g000000000
256 '
257
258 test_expect_success 'ambiguous commit-ish' '
259         # Now there are many commits that begin with the
260         # common prefix, none of these should pick one at
261         # random.  They all should result in ambiguity errors.
262         test_must_fail git rev-parse --verify 00000000^{commit} &&
263
264         # likewise
265         test_must_fail git log 000000000..000000000 &&
266         test_must_fail git log ..000000000 &&
267         test_must_fail git log 000000000.. &&
268         test_must_fail git log 000000000...000000000 &&
269         test_must_fail git log ...000000000 &&
270         test_must_fail git log 000000000...
271 '
272
273 # There are three objects with this prefix: a blob, a tree, and a tag. We know
274 # the blob will not pass as a treeish, but the tree and tag should (and thus
275 # cause an error).
276 test_expect_success 'ambiguous tags peel to treeish' '
277         test_must_fail git rev-parse 0000000000f^{tree}
278 '
279
280 test_expect_success 'rev-parse --disambiguate' '
281         # The test creates 16 objects that share the prefix and two
282         # commits created by commit-tree in earlier tests share a
283         # different prefix.
284         git rev-parse --disambiguate=000000000 >actual &&
285         test_line_count = 16 actual &&
286         test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000
287 '
288
289 test_expect_success 'rev-parse --disambiguate drops duplicates' '
290         git rev-parse --disambiguate=000000000 >expect &&
291         git pack-objects .git/objects/pack/pack <expect &&
292         git rev-parse --disambiguate=000000000 >actual &&
293         test_cmp expect actual
294 '
295
296 test_expect_success 'ambiguous 40-hex ref' '
297         TREE=$(git mktree </dev/null) &&
298         REF=$(git rev-parse HEAD) &&
299         VAL=$(git commit-tree $TREE </dev/null) &&
300         git update-ref refs/heads/$REF $VAL &&
301         test $(git rev-parse $REF 2>err) = $REF &&
302         grep "refname.*${REF}.*ambiguous" err
303 '
304
305 test_expect_success 'ambiguous short sha1 ref' '
306         TREE=$(git mktree </dev/null) &&
307         REF=$(git rev-parse --short HEAD) &&
308         VAL=$(git commit-tree $TREE </dev/null) &&
309         git update-ref refs/heads/$REF $VAL &&
310         test $(git rev-parse $REF 2>err) = $VAL &&
311         grep "refname.*${REF}.*ambiguous" err
312 '
313
314 test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated (raw)' '
315         test_must_fail git rev-parse 00000 2>stderr &&
316         grep "is ambiguous" stderr >errors &&
317         test_line_count = 1 errors
318 '
319
320 test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated (treeish)' '
321         test_must_fail git rev-parse 00000:foo 2>stderr &&
322         grep "is ambiguous" stderr >errors &&
323         test_line_count = 1 errors
324 '
325
326 test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated (peel)' '
327         test_must_fail git rev-parse 00000^{commit} 2>stderr &&
328         grep "is ambiguous" stderr >errors &&
329         test_line_count = 1 errors
330 '
331
332 test_expect_success C_LOCALE_OUTPUT 'ambiguity hints' '
333         test_must_fail git rev-parse 000000000 2>stderr &&
334         grep ^hint: stderr >hints &&
335         # 16 candidates, plus one intro line
336         test_line_count = 17 hints
337 '
338
339 test_expect_success C_LOCALE_OUTPUT 'ambiguity hints respect type' '
340         test_must_fail git rev-parse 000000000^{commit} 2>stderr &&
341         grep ^hint: stderr >hints &&
342         # 5 commits, 1 tag (which is a committish), plus intro line
343         test_line_count = 7 hints
344 '
345
346 test_expect_success C_LOCALE_OUTPUT 'failed type-selector still shows hint' '
347         # these two blobs share the same prefix "ee3d", but neither
348         # will pass for a commit
349         echo 851 | git hash-object --stdin -w &&
350         echo 872 | git hash-object --stdin -w &&
351         test_must_fail git rev-parse ee3d^{commit} 2>stderr &&
352         grep ^hint: stderr >hints &&
353         test_line_count = 3 hints
354 '
355
356 test_expect_success 'core.disambiguate config can prefer types' '
357         # ambiguous between tree and tag
358         sha1=0000000000f &&
359         test_must_fail git rev-parse $sha1 &&
360         git rev-parse $sha1^{commit} &&
361         git -c core.disambiguate=committish rev-parse $sha1
362 '
363
364 test_expect_success 'core.disambiguate does not override context' '
365         # treeish ambiguous between tag and tree
366         test_must_fail \
367                 git -c core.disambiguate=committish rev-parse $sha1^{tree}
368 '
369
370 test_expect_success C_LOCALE_OUTPUT 'ambiguous commits are printed by type first, then hash order' '
371         test_must_fail git rev-parse 0000 2>stderr &&
372         grep ^hint: stderr >hints &&
373         grep 0000 hints >objects &&
374         cat >expected <<-\EOF &&
375         tag
376         commit
377         tree
378         blob
379         EOF
380         awk "{print \$3}" <objects >objects.types &&
381         uniq <objects.types >objects.types.uniq &&
382         test_cmp expected objects.types.uniq &&
383         for type in tag commit tree blob
384         do
385                 grep $type objects >$type.objects &&
386                 sort $type.objects >$type.objects.sorted &&
387                 test_cmp $type.objects.sorted $type.objects
388         done
389 '
390
391 test_expect_success 'cat-file --batch and --batch-check show ambiguous' '
392         echo "0000 ambiguous" >expect &&
393         echo 0000 | git cat-file --batch-check >actual 2>err &&
394         test_cmp expect actual &&
395         test_i18ngrep hint: err &&
396         echo 0000 | git cat-file --batch >actual 2>err &&
397         test_cmp expect actual &&
398         test_i18ngrep hint: err
399 '
400
401 test_done