3 test_description='object name disambiguation
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.
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.
13 +-------------------------------------------+
15 | .-------b3wettvi---- ad2uee |
17 | a2onsxbvj---czy8f73t--ioiley5o |
19 +-------------------------------------------+
23 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
24 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
28 if ! test_have_prereq SHA1
30 skip_all='not using SHA-1 for objects'
34 test_expect_success 'blob and tree' '
37 for i in 0 1 2 3 4 5 6 7 8 9
45 # create one blob 0000000000b36
48 # create one tree 0000000000cdc
52 test_expect_success 'warn ambiguity when no candidate matches type hint' '
53 test_must_fail git rev-parse --verify 000000000^{commit} 2>actual &&
54 test_i18ngrep "short object ID 000000000 is ambiguous" actual
57 test_expect_success 'disambiguate tree-ish' '
58 # feed tree-ish in an unambiguous way
59 git rev-parse --verify 0000000000cdc:a0blgqsjc &&
61 # ambiguous at the object name level, but there is only one
62 # such tree-ish (the other is a blob)
63 git rev-parse --verify 000000000:a0blgqsjc
66 test_expect_success 'disambiguate blob' '
67 sed -e "s/|$//" >patch <<-EOF &&
68 diff --git a/frotz b/frotz
69 index 000000000..ffffff 100644
79 GIT_INDEX_FILE=frotz &&
80 export GIT_INDEX_FILE &&
81 git apply --build-fake-ancestor frotz patch &&
82 git cat-file blob :frotz >actual
84 test_cmp a0blgqsjc actual
87 test_expect_success 'disambiguate tree' '
88 commit=$(echo "d7xm" | git commit-tree 000000000) &&
89 # this commit is fffff2e and not ambiguous with the 00000* objects
90 test $(git rev-parse $commit^{tree}) = $(git rev-parse 0000000000cdc)
93 test_expect_success 'first commit' '
94 # create one commit 0000000000e4f
95 git commit -m a2onsxbvj
98 test_expect_success 'disambiguate commit-ish' '
99 # feed commit-ish in an unambiguous way
100 git rev-parse --verify 0000000000e4f^{commit} &&
102 # ambiguous at the object name level, but there is only one
103 # such commit (the others are tree and blob)
104 git rev-parse --verify 000000000^{commit} &&
107 git rev-parse --verify 000000000^0
110 test_expect_success 'disambiguate commit' '
111 commit=$(echo "hoaxj" | git commit-tree 0000000000cdc -p 000000000) &&
112 # this commit is ffffffd8 and not ambiguous with the 00000* objects
113 test $(git rev-parse $commit^) = $(git rev-parse 0000000000e4f)
116 test_expect_success 'log name1..name2 takes only commit-ishes on both ends' '
117 # These are underspecified from the prefix-length point of view
118 # to disambiguate the commit with other objects, but there is only
119 # one commit that has 00000* prefix at this point.
120 git log 000000000..000000000 &&
121 git log ..000000000 &&
122 git log 000000000.. &&
123 git log 000000000...000000000 &&
124 git log ...000000000 &&
128 test_expect_success 'rev-parse name1..name2 takes only commit-ishes on both ends' '
130 git rev-parse 000000000..000000000 &&
131 git rev-parse ..000000000 &&
132 git rev-parse 000000000..
135 test_expect_success 'git log takes only commit-ish' '
140 test_expect_success 'git reset takes only commit-ish' '
145 test_expect_success 'first tag' '
146 # create one tag 0000000000f8f
147 git tag -a -m j7cp83um v1.0.0
150 test_expect_failure 'two semi-ambiguous commit-ish' '
151 # At this point, we have a tag 0000000000f8f that points
152 # at a commit 0000000000e4f, and a tree and a blob that
153 # share 0000000000 prefix with these tag and commit.
155 # Once the parser becomes ultra-smart, it could notice that
156 # 0000000000 before ^{commit} name many different objects, but
157 # that only two (HEAD and v1.0.0 tag) can be peeled to commit,
158 # and that peeling them down to commit yield the same commit
160 git rev-parse --verify 0000000000^{commit} &&
163 git log 0000000000..0000000000 &&
164 git log ..0000000000 &&
165 git log 0000000000.. &&
166 git log 0000000000...0000000000 &&
167 git log ...0000000000 &&
168 git log 0000000000...
171 test_expect_failure 'three semi-ambiguous tree-ish' '
172 # Likewise for tree-ish. HEAD, v1.0.0 and HEAD^{tree} share
173 # the prefix but peeling them to tree yields the same thing
174 git rev-parse --verify 0000000000^{tree}
177 test_expect_success 'parse describe name' '
178 # feed an unambiguous describe name
179 git rev-parse --verify v1.0.0-0-g0000000000e4f &&
181 # ambiguous at the object name level, but there is only one
182 # such commit (others are blob, tree and tag)
183 git rev-parse --verify v1.0.0-0-g000000000
186 test_expect_success 'more history' '
187 # commit 0000000000043
188 git mv a0blgqsjc d12cr3h8t &&
189 echo h62xsjeu >>d12cr3h8t &&
193 git commit -m czy8f73t &&
195 # commit 00000000008ec
196 git mv d12cr3h8t j000jmpzn &&
197 echo j08bekfvt >>j000jmpzn &&
201 git commit -m ioiley5o &&
203 # commit 0000000005b0
204 git checkout v1.0.0^0 &&
205 git mv a0blgqsjc f5518nwu &&
207 for i in h62xsjeu j08bekfvt kg7xflhm
214 git commit -m b3wettvi &&
215 side=$(git rev-parse HEAD) &&
217 # commit 000000000066
220 # If you use recursive, merge will fail and you will need to
221 # clean up a0blgqsjc as well. If you use resolve, merge will
223 test_might_fail git merge --no-commit -s recursive $side &&
224 git rm -f f5518nwu j000jmpzn &&
226 test_might_fail git rm -f a0blgqsjc &&
228 git cat-file blob $side:f5518nwu &&
238 test_expect_failure 'parse describe name taking advantage of generation' '
239 # ambiguous at the object name level, but there is only one
240 # such commit at generation 0
241 git rev-parse --verify v1.0.0-0-g000000000 &&
243 # likewise for generation 2 and 4
244 git rev-parse --verify v1.0.0-2-g000000000 &&
245 git rev-parse --verify v1.0.0-4-g000000000
248 # Note: because rev-parse does not even try to disambiguate based on
249 # the generation number, this test currently succeeds for a wrong
250 # reason. When it learns to use the generation number, the previous
251 # test should succeed, and also this test should fail because the
252 # describe name used in the test with generation number can name two
253 # commits. Make sure that such a future enhancement does not randomly
255 test_expect_success 'parse describe name not ignoring ambiguity' '
256 # ambiguous at the object name level, and there are two such
257 # commits at generation 1
258 test_must_fail git rev-parse --verify v1.0.0-1-g000000000
261 test_expect_success 'ambiguous commit-ish' '
262 # Now there are many commits that begin with the
263 # common prefix, none of these should pick one at
264 # random. They all should result in ambiguity errors.
265 test_must_fail git rev-parse --verify 00000000^{commit} &&
268 test_must_fail git log 000000000..000000000 &&
269 test_must_fail git log ..000000000 &&
270 test_must_fail git log 000000000.. &&
271 test_must_fail git log 000000000...000000000 &&
272 test_must_fail git log ...000000000 &&
273 test_must_fail git log 000000000...
276 # There are three objects with this prefix: a blob, a tree, and a tag. We know
277 # the blob will not pass as a treeish, but the tree and tag should (and thus
279 test_expect_success 'ambiguous tags peel to treeish' '
280 test_must_fail git rev-parse 0000000000f^{tree}
283 test_expect_success 'rev-parse --disambiguate' '
284 # The test creates 16 objects that share the prefix and two
285 # commits created by commit-tree in earlier tests share a
287 git rev-parse --disambiguate=000000000 >actual &&
288 test_line_count = 16 actual &&
289 test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000
292 test_expect_success 'rev-parse --disambiguate drops duplicates' '
293 git rev-parse --disambiguate=000000000 >expect &&
294 git pack-objects .git/objects/pack/pack <expect &&
295 git rev-parse --disambiguate=000000000 >actual &&
296 test_cmp expect actual
299 test_expect_success 'ambiguous 40-hex ref' '
300 TREE=$(git mktree </dev/null) &&
301 REF=$(git rev-parse 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) = $REF &&
305 grep "refname.*${REF}.*ambiguous" err
308 test_expect_success 'ambiguous short sha1 ref' '
309 TREE=$(git mktree </dev/null) &&
310 REF=$(git rev-parse --short HEAD) &&
311 VAL=$(git commit-tree $TREE </dev/null) &&
312 git update-ref refs/heads/$REF $VAL &&
313 test $(git rev-parse $REF 2>err) = $VAL &&
314 grep "refname.*${REF}.*ambiguous" err
317 test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated (raw)' '
318 test_must_fail git rev-parse 00000 2>stderr &&
319 grep "is ambiguous" stderr >errors &&
320 test_line_count = 1 errors
323 test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated (treeish)' '
324 test_must_fail git rev-parse 00000:foo 2>stderr &&
325 grep "is ambiguous" stderr >errors &&
326 test_line_count = 1 errors
329 test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated (peel)' '
330 test_must_fail git rev-parse 00000^{commit} 2>stderr &&
331 grep "is ambiguous" stderr >errors &&
332 test_line_count = 1 errors
335 test_expect_success C_LOCALE_OUTPUT 'ambiguity hints' '
336 test_must_fail git rev-parse 000000000 2>stderr &&
337 grep ^hint: stderr >hints &&
338 # 16 candidates, plus one intro line
339 test_line_count = 17 hints
342 test_expect_success C_LOCALE_OUTPUT 'ambiguity hints respect type' '
343 test_must_fail git rev-parse 000000000^{commit} 2>stderr &&
344 grep ^hint: stderr >hints &&
345 # 5 commits, 1 tag (which is a committish), plus intro line
346 test_line_count = 7 hints
349 test_expect_success C_LOCALE_OUTPUT 'failed type-selector still shows hint' '
350 # these two blobs share the same prefix "ee3d", but neither
351 # will pass for a commit
352 echo 851 | git hash-object --stdin -w &&
353 echo 872 | git hash-object --stdin -w &&
354 test_must_fail git rev-parse ee3d^{commit} 2>stderr &&
355 grep ^hint: stderr >hints &&
356 test_line_count = 3 hints
359 test_expect_success 'core.disambiguate config can prefer types' '
360 # ambiguous between tree and tag
362 test_must_fail git rev-parse $sha1 &&
363 git rev-parse $sha1^{commit} &&
364 git -c core.disambiguate=committish rev-parse $sha1
367 test_expect_success 'core.disambiguate does not override context' '
368 # treeish ambiguous between tag and tree
370 git -c core.disambiguate=committish rev-parse $sha1^{tree}
373 test_expect_success C_LOCALE_OUTPUT 'ambiguous commits are printed by type first, then hash order' '
374 test_must_fail git rev-parse 0000 2>stderr &&
375 grep ^hint: stderr >hints &&
376 grep 0000 hints >objects &&
377 cat >expected <<-\EOF &&
383 awk "{print \$3}" <objects >objects.types &&
384 uniq <objects.types >objects.types.uniq &&
385 test_cmp expected objects.types.uniq &&
386 for type in tag commit tree blob
388 grep $type objects >$type.objects &&
389 sort $type.objects >$type.objects.sorted &&
390 test_cmp $type.objects.sorted $type.objects
394 test_expect_success 'cat-file --batch and --batch-check show ambiguous' '
395 echo "0000 ambiguous" >expect &&
396 echo 0000 | git cat-file --batch-check >actual 2>err &&
397 test_cmp expect actual &&
398 test_i18ngrep hint: err &&
399 echo 0000 | git cat-file --batch >actual 2>err &&
400 test_cmp expect actual &&
401 test_i18ngrep hint: err