t / t1512-rev-parse-disambiguation.shon commit t1700-split-index: date back files to avoid racy situations (c6e5607)
   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 $type objects >$type.objects &&
 386                sort $type.objects >$type.objects.sorted &&
 387                test_cmp $type.objects.sorted $type.objects
 388        done
 389'
 390
 391test_done