1#!/bin/sh 2 3test_description='object name disambiguation 4 5Create blobs, trees, commits and a tag that all share the same 6prefix, and make sure "git rev-parse" can take advantage of 7type information to disambiguate short object names that are 8not necessarily unique. 9 10The final history used in the test has five commits, with the bottom 11one 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 25if! test_have_prereq SHA1 26then 27 skip_all='not using SHA-1 for objects' 28 test_done 29fi 30 31test_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 49test_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 54test_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 63test_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 84test_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 90test_expect_success 'first commit'' 91 # create one commit 0000000000e4f 92 git commit -m a2onsxbvj 93' 94 95test_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 107test_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 113test_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 125test_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 132test_expect_success 'git log takes only commit-ish'' 133 # Likewise. 134 git log 000000000 135' 136 137test_expect_success 'git reset takes only commit-ish'' 138 # Likewise. 139 git reset 000000000 140' 141 142test_expect_success 'first tag'' 143 # create one tag 0000000000f8f 144 git tag -a -m j7cp83um v1.0.0 145' 146 147test_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 168test_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 174test_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 183test_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 235test_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. 252test_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 258test_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). 276test_expect_success 'ambiguous tags peel to treeish'' 277 test_must_fail git rev-parse 0000000000f^{tree} 278' 279 280test_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$(wc -l <actual)= 16 && 286 test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000 287' 288 289test_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 296test_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 305test_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 314test_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 320test_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 326test_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 332test_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 339test_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 commitish), plus intro line 343 test_line_count = 7 hints 344' 345 346test_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 356test_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 364test_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 370test_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$typeobjects >$type.objects && 386 sort$type.objects >$type.objects.sorted && 387 test_cmp$type.objects.sorted$type.objects 388 done 389' 390 391test_done