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