t / t1512-rev-parse-disambiguation.shon commit ref_transaction_commit(): fix atomicity and avoid fd exhaustion (cf018ee)
   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        grep "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
 267test_expect_success 'rev-parse --disambiguate' '
 268        # The test creates 16 objects that share the prefix and two
 269        # commits created by commit-tree in earlier tests share a
 270        # different prefix.
 271        git rev-parse --disambiguate=000000000 >actual &&
 272        test $(wc -l <actual) = 16 &&
 273        test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000
 274'
 275
 276test_expect_success 'ambiguous 40-hex ref' '
 277        TREE=$(git mktree </dev/null) &&
 278        REF=`git rev-parse HEAD` &&
 279        VAL=$(git commit-tree $TREE </dev/null) &&
 280        git update-ref refs/heads/$REF $VAL &&
 281        test `git rev-parse $REF 2>err` = $REF &&
 282        grep "refname.*${REF}.*ambiguous" err
 283'
 284
 285test_expect_success 'ambiguous short sha1 ref' '
 286        TREE=$(git mktree </dev/null) &&
 287        REF=`git rev-parse --short HEAD` &&
 288        VAL=$(git commit-tree $TREE </dev/null) &&
 289        git update-ref refs/heads/$REF $VAL &&
 290        test `git rev-parse $REF 2>err` = $VAL &&
 291        grep "refname.*${REF}.*ambiguous" err
 292'
 293
 294test_done