]>
Commit | Line | Data |
---|---|---|
6269b6b6 JH |
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 | ||
06d53148 | 23 | GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main |
334afbc7 JS |
24 | export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME |
25 | ||
6269b6b6 JH |
26 | . ./test-lib.sh |
27 | ||
8d56136d ÆAB |
28 | test_cmp_failed_rev_parse () { |
29 | dir=$1 | |
30 | rev=$2 | |
31 | ||
32 | cat >expect && | |
33 | test_must_fail git -C "$dir" rev-parse "$rev" 2>actual.raw && | |
34 | sed "s/\($rev\)[0-9a-f]*/\1.../" <actual.raw >actual && | |
35 | test_cmp expect actual | |
36 | } | |
37 | ||
38 | test_expect_success 'ambiguous blob output' ' | |
39 | git init --bare blob.prefix && | |
40 | ( | |
41 | cd blob.prefix && | |
42 | ||
43 | # Both start with "dead..", under both SHA-1 and SHA-256 | |
44 | echo brocdnra | git hash-object -w --stdin && | |
45 | echo brigddsv | git hash-object -w --stdin && | |
46 | ||
47 | # Both start with "beef.." | |
48 | echo 1agllotbh | git hash-object -w --stdin && | |
49 | echo 1bbfctrkc | git hash-object -w --stdin | |
50 | ) && | |
51 | ||
52 | test_must_fail git -C blob.prefix rev-parse dead && | |
53 | test_cmp_failed_rev_parse blob.prefix beef <<-\EOF | |
54 | error: short object ID beef... is ambiguous | |
55 | hint: The candidates are: | |
56 | hint: beef... blob | |
57 | hint: beef... blob | |
58 | fatal: ambiguous argument '\''beef...'\'': unknown revision or path not in the working tree. | |
59 | Use '\''--'\'' to separate paths from revisions, like this: | |
60 | '\''git <command> [<revision>...] -- [<file>...]'\'' | |
61 | EOF | |
62 | ' | |
63 | ||
64 | test_expect_success 'ambiguous loose bad object parsed as OBJ_BAD' ' | |
65 | git init --bare blob.bad && | |
66 | ( | |
67 | cd blob.bad && | |
68 | ||
69 | # Both have the prefix "bad0" | |
70 | echo xyzfaowcoh | git hash-object -t bad -w --stdin --literally && | |
71 | echo xyzhjpyvwl | git hash-object -t bad -w --stdin --literally | |
72 | ) && | |
73 | ||
74 | test_cmp_failed_rev_parse blob.bad bad0 <<-\EOF | |
75 | error: short object ID bad0... is ambiguous | |
8d56136d ÆAB |
76 | fatal: invalid object type |
77 | EOF | |
78 | ' | |
79 | ||
80 | test_expect_success POSIXPERM 'ambigous zlib corrupt loose blob' ' | |
81 | git init --bare blob.corrupt && | |
82 | ( | |
83 | cd blob.corrupt && | |
84 | ||
85 | # Both have the prefix "cafe" | |
86 | echo bnkxmdwz | git hash-object -w --stdin && | |
87 | oid=$(echo bmwsjxzi | git hash-object -w --stdin) && | |
88 | ||
89 | oidf=objects/$(test_oid_to_path "$oid") && | |
90 | chmod 755 $oidf && | |
91 | echo broken >$oidf | |
92 | ) && | |
93 | ||
94 | test_cmp_failed_rev_parse blob.corrupt cafe <<-\EOF | |
95 | error: short object ID cafe... is ambiguous | |
8d56136d ÆAB |
96 | error: inflate: data stream error (incorrect header check) |
97 | error: unable to unpack cafe... header | |
98 | error: inflate: data stream error (incorrect header check) | |
99 | error: unable to unpack cafe... header | |
d2ef3cb7 | 100 | hint: The candidates are: |
6780e680 | 101 | hint: cafe... [bad object] |
8d56136d ÆAB |
102 | hint: cafe... blob |
103 | fatal: ambiguous argument '\''cafe...'\'': unknown revision or path not in the working tree. | |
104 | Use '\''--'\'' to separate paths from revisions, like this: | |
105 | '\''git <command> [<revision>...] -- [<file>...]'\'' | |
106 | EOF | |
107 | ' | |
108 | ||
d7a2fc82 | 109 | if ! test_have_prereq SHA1 |
110 | then | |
111 | skip_all='not using SHA-1 for objects' | |
112 | test_done | |
113 | fi | |
114 | ||
6269b6b6 JH |
115 | test_expect_success 'blob and tree' ' |
116 | test_tick && | |
117 | ( | |
08495412 | 118 | test_write_lines 0 1 2 3 4 5 6 7 8 9 && |
f2deabfc | 119 | echo && |
6269b6b6 JH |
120 | echo b1rwzyc3 |
121 | ) >a0blgqsjc && | |
122 | ||
123 | # create one blob 0000000000b36 | |
124 | git add a0blgqsjc && | |
125 | ||
126 | # create one tree 0000000000cdc | |
127 | git write-tree | |
128 | ' | |
129 | ||
130 | test_expect_success 'warn ambiguity when no candidate matches type hint' ' | |
131 | test_must_fail git rev-parse --verify 000000000^{commit} 2>actual && | |
6789275d | 132 | test_grep "short object ID 000000000 is ambiguous" actual |
6269b6b6 JH |
133 | ' |
134 | ||
daba53ae | 135 | test_expect_success 'disambiguate tree-ish' ' |
6269b6b6 JH |
136 | # feed tree-ish in an unambiguous way |
137 | git rev-parse --verify 0000000000cdc:a0blgqsjc && | |
138 | ||
139 | # ambiguous at the object name level, but there is only one | |
140 | # such tree-ish (the other is a blob) | |
141 | git rev-parse --verify 000000000:a0blgqsjc | |
142 | ' | |
143 | ||
da3ac0c1 | 144 | test_expect_success 'disambiguate blob' ' |
6269b6b6 JH |
145 | sed -e "s/|$//" >patch <<-EOF && |
146 | diff --git a/frotz b/frotz | |
147 | index 000000000..ffffff 100644 | |
148 | --- a/frotz | |
149 | +++ b/frotz | |
150 | @@ -10,3 +10,4 @@ | |
151 | 9 | |
152 | | | |
153 | b1rwzyc3 | |
154 | +irwry | |
155 | EOF | |
156 | ( | |
157 | GIT_INDEX_FILE=frotz && | |
158 | export GIT_INDEX_FILE && | |
159 | git apply --build-fake-ancestor frotz patch && | |
160 | git cat-file blob :frotz >actual | |
161 | ) && | |
162 | test_cmp a0blgqsjc actual | |
163 | ' | |
164 | ||
75f5ac04 | 165 | test_expect_success 'disambiguate tree' ' |
6269b6b6 | 166 | commit=$(echo "d7xm" | git commit-tree 000000000) && |
2c57f7c9 | 167 | # this commit is fffff2e and not ambiguous with the 00000* objects |
6269b6b6 JH |
168 | test $(git rev-parse $commit^{tree}) = $(git rev-parse 0000000000cdc) |
169 | ' | |
170 | ||
171 | test_expect_success 'first commit' ' | |
172 | # create one commit 0000000000e4f | |
173 | git commit -m a2onsxbvj | |
174 | ' | |
175 | ||
e2643617 | 176 | test_expect_success 'disambiguate commit-ish' ' |
6269b6b6 JH |
177 | # feed commit-ish in an unambiguous way |
178 | git rev-parse --verify 0000000000e4f^{commit} && | |
179 | ||
180 | # ambiguous at the object name level, but there is only one | |
181 | # such commit (the others are tree and blob) | |
182 | git rev-parse --verify 000000000^{commit} && | |
183 | ||
184 | # likewise | |
185 | git rev-parse --verify 000000000^0 | |
186 | ' | |
187 | ||
75f5ac04 | 188 | test_expect_success 'disambiguate commit' ' |
31ffd0c0 | 189 | commit=$(echo "hoaxj" | git commit-tree 0000000000cdc -p 000000000) && |
2c57f7c9 | 190 | # this commit is ffffffd8 and not ambiguous with the 00000* objects |
6269b6b6 JH |
191 | test $(git rev-parse $commit^) = $(git rev-parse 0000000000e4f) |
192 | ' | |
193 | ||
cd74e473 | 194 | test_expect_success 'log name1..name2 takes only commit-ishes on both ends' ' |
2c57f7c9 JH |
195 | # These are underspecified from the prefix-length point of view |
196 | # to disambiguate the commit with other objects, but there is only | |
197 | # one commit that has 00000* prefix at this point. | |
6269b6b6 JH |
198 | git log 000000000..000000000 && |
199 | git log ..000000000 && | |
200 | git log 000000000.. && | |
201 | git log 000000000...000000000 && | |
202 | git log ...000000000 && | |
203 | git log 000000000... | |
204 | ' | |
205 | ||
c036c4c5 | 206 | test_expect_success 'rev-parse name1..name2 takes only commit-ishes on both ends' ' |
2c57f7c9 | 207 | # Likewise. |
6269b6b6 JH |
208 | git rev-parse 000000000..000000000 && |
209 | git rev-parse ..000000000 && | |
210 | git rev-parse 000000000.. | |
211 | ' | |
212 | ||
d5f6b1d7 | 213 | test_expect_success 'git log takes only commit-ish' ' |
2c57f7c9 | 214 | # Likewise. |
6269b6b6 JH |
215 | git log 000000000 |
216 | ' | |
217 | ||
13243c2c | 218 | test_expect_success 'git reset takes only commit-ish' ' |
2c57f7c9 | 219 | # Likewise. |
6269b6b6 JH |
220 | git reset 000000000 |
221 | ' | |
222 | ||
223 | test_expect_success 'first tag' ' | |
224 | # create one tag 0000000000f8f | |
225 | git tag -a -m j7cp83um v1.0.0 | |
226 | ' | |
227 | ||
228 | test_expect_failure 'two semi-ambiguous commit-ish' ' | |
2c57f7c9 JH |
229 | # At this point, we have a tag 0000000000f8f that points |
230 | # at a commit 0000000000e4f, and a tree and a blob that | |
231 | # share 0000000000 prefix with these tag and commit. | |
232 | # | |
6269b6b6 | 233 | # Once the parser becomes ultra-smart, it could notice that |
2c57f7c9 | 234 | # 0000000000 before ^{commit} name many different objects, but |
6269b6b6 JH |
235 | # that only two (HEAD and v1.0.0 tag) can be peeled to commit, |
236 | # and that peeling them down to commit yield the same commit | |
237 | # without ambiguity. | |
2c57f7c9 | 238 | git rev-parse --verify 0000000000^{commit} && |
6269b6b6 JH |
239 | |
240 | # likewise | |
2c57f7c9 JH |
241 | git log 0000000000..0000000000 && |
242 | git log ..0000000000 && | |
243 | git log 0000000000.. && | |
244 | git log 0000000000...0000000000 && | |
245 | git log ...0000000000 && | |
246 | git log 0000000000... | |
6269b6b6 JH |
247 | ' |
248 | ||
249 | test_expect_failure 'three semi-ambiguous tree-ish' ' | |
250 | # Likewise for tree-ish. HEAD, v1.0.0 and HEAD^{tree} share | |
251 | # the prefix but peeling them to tree yields the same thing | |
2c57f7c9 | 252 | git rev-parse --verify 0000000000^{tree} |
6269b6b6 JH |
253 | ' |
254 | ||
255 | test_expect_success 'parse describe name' ' | |
256 | # feed an unambiguous describe name | |
257 | git rev-parse --verify v1.0.0-0-g0000000000e4f && | |
258 | ||
259 | # ambiguous at the object name level, but there is only one | |
260 | # such commit (others are blob, tree and tag) | |
261 | git rev-parse --verify v1.0.0-0-g000000000 | |
262 | ' | |
263 | ||
264 | test_expect_success 'more history' ' | |
265 | # commit 0000000000043 | |
266 | git mv a0blgqsjc d12cr3h8t && | |
267 | echo h62xsjeu >>d12cr3h8t && | |
268 | git add d12cr3h8t && | |
269 | ||
270 | test_tick && | |
271 | git commit -m czy8f73t && | |
272 | ||
273 | # commit 00000000008ec | |
274 | git mv d12cr3h8t j000jmpzn && | |
275 | echo j08bekfvt >>j000jmpzn && | |
276 | git add j000jmpzn && | |
277 | ||
278 | test_tick && | |
279 | git commit -m ioiley5o && | |
280 | ||
281 | # commit 0000000005b0 | |
282 | git checkout v1.0.0^0 && | |
283 | git mv a0blgqsjc f5518nwu && | |
284 | ||
08495412 | 285 | test_write_lines h62xsjeu j08bekfvt kg7xflhm >>f5518nwu && |
6269b6b6 JH |
286 | git add f5518nwu && |
287 | ||
288 | test_tick && | |
289 | git commit -m b3wettvi && | |
290 | side=$(git rev-parse HEAD) && | |
291 | ||
292 | # commit 000000000066 | |
06d53148 | 293 | git checkout main && |
6269b6b6 JH |
294 | |
295 | # If you use recursive, merge will fail and you will need to | |
296 | # clean up a0blgqsjc as well. If you use resolve, merge will | |
297 | # succeed. | |
298 | test_might_fail git merge --no-commit -s recursive $side && | |
299 | git rm -f f5518nwu j000jmpzn && | |
300 | ||
301 | test_might_fail git rm -f a0blgqsjc && | |
302 | ( | |
f2deabfc | 303 | git cat-file blob $side:f5518nwu && |
6269b6b6 JH |
304 | echo j3l0i9s6 |
305 | ) >ab2gs879 && | |
306 | git add ab2gs879 && | |
307 | ||
308 | test_tick && | |
309 | git commit -m ad2uee | |
310 | ||
311 | ' | |
312 | ||
313 | test_expect_failure 'parse describe name taking advantage of generation' ' | |
314 | # ambiguous at the object name level, but there is only one | |
315 | # such commit at generation 0 | |
316 | git rev-parse --verify v1.0.0-0-g000000000 && | |
317 | ||
318 | # likewise for generation 2 and 4 | |
319 | git rev-parse --verify v1.0.0-2-g000000000 && | |
320 | git rev-parse --verify v1.0.0-4-g000000000 | |
321 | ' | |
322 | ||
323 | # Note: because rev-parse does not even try to disambiguate based on | |
324 | # the generation number, this test currently succeeds for a wrong | |
325 | # reason. When it learns to use the generation number, the previous | |
326 | # test should succeed, and also this test should fail because the | |
327 | # describe name used in the test with generation number can name two | |
328 | # commits. Make sure that such a future enhancement does not randomly | |
329 | # pick one. | |
330 | test_expect_success 'parse describe name not ignoring ambiguity' ' | |
331 | # ambiguous at the object name level, and there are two such | |
332 | # commits at generation 1 | |
333 | test_must_fail git rev-parse --verify v1.0.0-1-g000000000 | |
334 | ' | |
335 | ||
336 | test_expect_success 'ambiguous commit-ish' ' | |
337 | # Now there are many commits that begin with the | |
338 | # common prefix, none of these should pick one at | |
339 | # random. They all should result in ambiguity errors. | |
2c57f7c9 | 340 | test_must_fail git rev-parse --verify 00000000^{commit} && |
6269b6b6 JH |
341 | |
342 | # likewise | |
343 | test_must_fail git log 000000000..000000000 && | |
344 | test_must_fail git log ..000000000 && | |
345 | test_must_fail git log 000000000.. && | |
346 | test_must_fail git log 000000000...000000000 && | |
347 | test_must_fail git log ...000000000 && | |
348 | test_must_fail git log 000000000... | |
349 | ' | |
350 | ||
5d5def2a JK |
351 | # There are three objects with this prefix: a blob, a tree, and a tag. We know |
352 | # the blob will not pass as a treeish, but the tree and tag should (and thus | |
353 | # cause an error). | |
354 | test_expect_success 'ambiguous tags peel to treeish' ' | |
355 | test_must_fail git rev-parse 0000000000f^{tree} | |
356 | ' | |
357 | ||
957d7406 JH |
358 | test_expect_success 'rev-parse --disambiguate' ' |
359 | # The test creates 16 objects that share the prefix and two | |
31ffd0c0 JH |
360 | # commits created by commit-tree in earlier tests share a |
361 | # different prefix. | |
957d7406 | 362 | git rev-parse --disambiguate=000000000 >actual && |
a5d04a3e | 363 | test_line_count = 16 actual && |
957d7406 JH |
364 | test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000 |
365 | ' | |
366 | ||
fad6b9e5 JK |
367 | test_expect_success 'rev-parse --disambiguate drops duplicates' ' |
368 | git rev-parse --disambiguate=000000000 >expect && | |
369 | git pack-objects .git/objects/pack/pack <expect && | |
370 | git rev-parse --disambiguate=000000000 >actual && | |
371 | test_cmp expect actual | |
372 | ' | |
373 | ||
798c35fc NTND |
374 | test_expect_success 'ambiguous 40-hex ref' ' |
375 | TREE=$(git mktree </dev/null) && | |
dcfbb2aa | 376 | REF=$(git rev-parse HEAD) && |
798c35fc NTND |
377 | VAL=$(git commit-tree $TREE </dev/null) && |
378 | git update-ref refs/heads/$REF $VAL && | |
dcfbb2aa | 379 | test $(git rev-parse $REF 2>err) = $REF && |
798c35fc NTND |
380 | grep "refname.*${REF}.*ambiguous" err |
381 | ' | |
382 | ||
383 | test_expect_success 'ambiguous short sha1 ref' ' | |
384 | TREE=$(git mktree </dev/null) && | |
dcfbb2aa | 385 | REF=$(git rev-parse --short HEAD) && |
798c35fc NTND |
386 | VAL=$(git commit-tree $TREE </dev/null) && |
387 | git update-ref refs/heads/$REF $VAL && | |
dcfbb2aa | 388 | test $(git rev-parse $REF 2>err) = $VAL && |
798c35fc NTND |
389 | grep "refname.*${REF}.*ambiguous" err |
390 | ' | |
391 | ||
a926c4b9 | 392 | test_expect_success 'ambiguity errors are not repeated (raw)' ' |
7243ffdd JK |
393 | test_must_fail git rev-parse 00000 2>stderr && |
394 | grep "is ambiguous" stderr >errors && | |
395 | test_line_count = 1 errors | |
396 | ' | |
397 | ||
a926c4b9 | 398 | test_expect_success 'ambiguity errors are not repeated (treeish)' ' |
8a10fea4 JK |
399 | test_must_fail git rev-parse 00000:foo 2>stderr && |
400 | grep "is ambiguous" stderr >errors && | |
401 | test_line_count = 1 errors | |
402 | ' | |
403 | ||
a926c4b9 | 404 | test_expect_success 'ambiguity errors are not repeated (peel)' ' |
8a10fea4 JK |
405 | test_must_fail git rev-parse 00000^{commit} 2>stderr && |
406 | grep "is ambiguous" stderr >errors && | |
407 | test_line_count = 1 errors | |
408 | ' | |
409 | ||
a926c4b9 | 410 | test_expect_success 'ambiguity hints' ' |
1ffa26c4 JK |
411 | test_must_fail git rev-parse 000000000 2>stderr && |
412 | grep ^hint: stderr >hints && | |
413 | # 16 candidates, plus one intro line | |
414 | test_line_count = 17 hints | |
415 | ' | |
416 | ||
a926c4b9 | 417 | test_expect_success 'ambiguity hints respect type' ' |
1ffa26c4 JK |
418 | test_must_fail git rev-parse 000000000^{commit} 2>stderr && |
419 | grep ^hint: stderr >hints && | |
7a40cf15 | 420 | # 5 commits, 1 tag (which is a committish), plus intro line |
1ffa26c4 JK |
421 | test_line_count = 7 hints |
422 | ' | |
423 | ||
a926c4b9 | 424 | test_expect_success 'failed type-selector still shows hint' ' |
1ffa26c4 JK |
425 | # these two blobs share the same prefix "ee3d", but neither |
426 | # will pass for a commit | |
427 | echo 851 | git hash-object --stdin -w && | |
428 | echo 872 | git hash-object --stdin -w && | |
429 | test_must_fail git rev-parse ee3d^{commit} 2>stderr && | |
430 | grep ^hint: stderr >hints && | |
431 | test_line_count = 3 hints | |
432 | ' | |
433 | ||
5b33cb1f JK |
434 | test_expect_success 'core.disambiguate config can prefer types' ' |
435 | # ambiguous between tree and tag | |
436 | sha1=0000000000f && | |
437 | test_must_fail git rev-parse $sha1 && | |
438 | git rev-parse $sha1^{commit} && | |
439 | git -c core.disambiguate=committish rev-parse $sha1 | |
440 | ' | |
441 | ||
442 | test_expect_success 'core.disambiguate does not override context' ' | |
443 | # treeish ambiguous between tag and tree | |
444 | test_must_fail \ | |
445 | git -c core.disambiguate=committish rev-parse $sha1^{tree} | |
446 | ' | |
447 | ||
a926c4b9 | 448 | test_expect_success 'ambiguous commits are printed by type first, then hash order' ' |
5cc044e0 ÆAB |
449 | test_must_fail git rev-parse 0000 2>stderr && |
450 | grep ^hint: stderr >hints && | |
451 | grep 0000 hints >objects && | |
452 | cat >expected <<-\EOF && | |
453 | tag | |
454 | commit | |
455 | tree | |
456 | blob | |
457 | EOF | |
458 | awk "{print \$3}" <objects >objects.types && | |
459 | uniq <objects.types >objects.types.uniq && | |
460 | test_cmp expected objects.types.uniq && | |
461 | for type in tag commit tree blob | |
462 | do | |
463 | grep $type objects >$type.objects && | |
464 | sort $type.objects >$type.objects.sorted && | |
db5875aa | 465 | test_cmp $type.objects.sorted $type.objects || return 1 |
5cc044e0 ÆAB |
466 | done |
467 | ' | |
468 | ||
df799f5d EW |
469 | test_expect_success 'cat-file --batch and --batch-check show ambiguous' ' |
470 | echo "0000 ambiguous" >expect && | |
471 | echo 0000 | git cat-file --batch-check >actual 2>err && | |
472 | test_cmp expect actual && | |
6789275d | 473 | test_grep hint: err && |
df799f5d EW |
474 | echo 0000 | git cat-file --batch >actual 2>err && |
475 | test_cmp expect actual && | |
6789275d | 476 | test_grep hint: err |
df799f5d EW |
477 | ' |
478 | ||
6269b6b6 | 479 | test_done |