t / t1512-rev-parse-disambiguation.shon commit patch-ids: convert to struct object_id (34f3c0e)
   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
  25test_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
  43test_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
  48test_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
  57test_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
  78test_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
  84test_expect_success 'first commit' '
  85        # create one commit 0000000000e4f
  86        git commit -m a2onsxbvj
  87'
  88
  89test_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
 101test_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
 107test_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
 119test_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
 126test_expect_success 'git log takes only commit-ish' '
 127        # Likewise.
 128        git log 000000000
 129'
 130
 131test_expect_success 'git reset takes only commit-ish' '
 132        # Likewise.
 133        git reset 000000000
 134'
 135
 136test_expect_success 'first tag' '
 137        # create one tag 0000000000f8f
 138        git tag -a -m j7cp83um v1.0.0
 139'
 140
 141test_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
 162test_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
 168test_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
 177test_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
 229test_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.
 246test_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
 252test_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).
 270test_expect_success 'ambiguous tags peel to treeish' '
 271        test_must_fail git rev-parse 0000000000f^{tree}
 272'
 273
 274test_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
 283test_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
 290test_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
 299test_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
 308test_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
 314test_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
 320test_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
 326test_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
 333test_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
 340test_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
 350test_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
 358test_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
 364test_done