t / t6030-bisect-porcelain.shon commit Merge branch 'maint-1.6.0' into maint-1.6.1 (bf0fe35)
   1#!/bin/sh
   2#
   3# Copyright (c) 2007 Christian Couder
   4#
   5test_description='Tests git bisect functionality'
   6
   7exec </dev/null
   8
   9. ./test-lib.sh
  10
  11add_line_into_file()
  12{
  13    _line=$1
  14    _file=$2
  15
  16    if [ -f "$_file" ]; then
  17        echo "$_line" >> $_file || return $?
  18        MSG="Add <$_line> into <$_file>."
  19    else
  20        echo "$_line" > $_file || return $?
  21        git add $_file || return $?
  22        MSG="Create file <$_file> with <$_line> inside."
  23    fi
  24
  25    test_tick
  26    git commit --quiet -m "$MSG" $_file
  27}
  28
  29HASH1=
  30HASH2=
  31HASH3=
  32HASH4=
  33
  34test_expect_success 'set up basic repo with 1 file (hello) and 4 commits' '
  35     add_line_into_file "1: Hello World" hello &&
  36     HASH1=$(git rev-parse --verify HEAD) &&
  37     add_line_into_file "2: A new day for git" hello &&
  38     HASH2=$(git rev-parse --verify HEAD) &&
  39     add_line_into_file "3: Another new day for git" hello &&
  40     HASH3=$(git rev-parse --verify HEAD) &&
  41     add_line_into_file "4: Ciao for now" hello &&
  42     HASH4=$(git rev-parse --verify HEAD)
  43'
  44
  45test_expect_success 'bisect starts with only one bad' '
  46        git bisect reset &&
  47        git bisect start &&
  48        git bisect bad $HASH4 &&
  49        git bisect next
  50'
  51
  52test_expect_success 'bisect does not start with only one good' '
  53        git bisect reset &&
  54        git bisect start &&
  55        git bisect good $HASH1 || return 1
  56
  57        if git bisect next
  58        then
  59                echo Oops, should have failed.
  60                false
  61        else
  62                :
  63        fi
  64'
  65
  66test_expect_success 'bisect start with one bad and good' '
  67        git bisect reset &&
  68        git bisect start &&
  69        git bisect good $HASH1 &&
  70        git bisect bad $HASH4 &&
  71        git bisect next
  72'
  73
  74test_expect_success 'bisect fails if given any junk instead of revs' '
  75        git bisect reset &&
  76        test_must_fail git bisect start foo $HASH1 -- &&
  77        test_must_fail git bisect start $HASH4 $HASH1 bar -- &&
  78        test -z "$(git for-each-ref "refs/bisect/*")" &&
  79        test -z "$(ls .git/BISECT_* 2>/dev/null)" &&
  80        git bisect start &&
  81        test_must_fail git bisect good foo $HASH1 &&
  82        test_must_fail git bisect good $HASH1 bar &&
  83        test_must_fail git bisect bad frotz &&
  84        test_must_fail git bisect bad $HASH3 $HASH4 &&
  85        test_must_fail git bisect skip bar $HASH3 &&
  86        test_must_fail git bisect skip $HASH1 foo &&
  87        test -z "$(git for-each-ref "refs/bisect/*")" &&
  88        git bisect good $HASH1 &&
  89        git bisect bad $HASH4
  90'
  91
  92test_expect_success 'bisect reset: back in the master branch' '
  93        git bisect reset &&
  94        echo "* master" > branch.expect &&
  95        git branch > branch.output &&
  96        cmp branch.expect branch.output
  97'
  98
  99test_expect_success 'bisect reset: back in another branch' '
 100        git checkout -b other &&
 101        git bisect start &&
 102        git bisect good $HASH1 &&
 103        git bisect bad $HASH3 &&
 104        git bisect reset &&
 105        echo "  master" > branch.expect &&
 106        echo "* other" >> branch.expect &&
 107        git branch > branch.output &&
 108        cmp branch.expect branch.output
 109'
 110
 111test_expect_success 'bisect reset when not bisecting' '
 112        git bisect reset &&
 113        git branch > branch.output &&
 114        cmp branch.expect branch.output
 115'
 116
 117test_expect_success 'bisect reset removes packed refs' '
 118        git bisect reset &&
 119        git bisect start &&
 120        git bisect good $HASH1 &&
 121        git bisect bad $HASH3 &&
 122        git pack-refs --all --prune &&
 123        git bisect next &&
 124        git bisect reset &&
 125        test -z "$(git for-each-ref "refs/bisect/*")" &&
 126        test -z "$(git for-each-ref "refs/heads/bisect")"
 127'
 128
 129test_expect_success 'bisect start: back in good branch' '
 130        git branch > branch.output &&
 131        grep "* other" branch.output > /dev/null &&
 132        git bisect start $HASH4 $HASH1 -- &&
 133        git bisect good &&
 134        git bisect start $HASH4 $HASH1 -- &&
 135        git bisect bad &&
 136        git bisect reset &&
 137        git branch > branch.output &&
 138        grep "* other" branch.output > /dev/null
 139'
 140
 141test_expect_success 'bisect start: no ".git/BISECT_START" if junk rev' '
 142        git bisect start $HASH4 $HASH1 -- &&
 143        git bisect good &&
 144        test_must_fail git bisect start $HASH4 foo -- &&
 145        git branch > branch.output &&
 146        grep "* other" branch.output > /dev/null &&
 147        test_must_fail test -e .git/BISECT_START
 148'
 149
 150test_expect_success 'bisect start: no ".git/BISECT_START" if mistaken rev' '
 151        git bisect start $HASH4 $HASH1 -- &&
 152        git bisect good &&
 153        test_must_fail git bisect start $HASH1 $HASH4 -- &&
 154        git branch > branch.output &&
 155        grep "* other" branch.output > /dev/null &&
 156        test_must_fail test -e .git/BISECT_START
 157'
 158
 159test_expect_success 'bisect start: no ".git/BISECT_START" if checkout error' '
 160        echo "temp stuff" > hello &&
 161        test_must_fail git bisect start $HASH4 $HASH1 -- &&
 162        git branch &&
 163        git branch > branch.output &&
 164        grep "* other" branch.output > /dev/null &&
 165        test_must_fail test -e .git/BISECT_START &&
 166        test -z "$(git for-each-ref "refs/bisect/*")" &&
 167        git checkout HEAD hello
 168'
 169
 170# $HASH1 is good, $HASH4 is bad, we skip $HASH3
 171# but $HASH2 is bad,
 172# so we should find $HASH2 as the first bad commit
 173test_expect_success 'bisect skip: successfull result' '
 174        git bisect reset &&
 175        git bisect start $HASH4 $HASH1 &&
 176        git bisect skip &&
 177        git bisect bad > my_bisect_log.txt &&
 178        grep "$HASH2 is first bad commit" my_bisect_log.txt &&
 179        git bisect reset
 180'
 181
 182# $HASH1 is good, $HASH4 is bad, we skip $HASH3 and $HASH2
 183# so we should not be able to tell the first bad commit
 184# among $HASH2, $HASH3 and $HASH4
 185test_expect_success 'bisect skip: cannot tell between 3 commits' '
 186        git bisect start $HASH4 $HASH1 &&
 187        git bisect skip || return 1
 188
 189        if git bisect skip > my_bisect_log.txt
 190        then
 191                echo Oops, should have failed.
 192                false
 193        else
 194                test $? -eq 2 &&
 195                grep "first bad commit could be any of" my_bisect_log.txt &&
 196                ! grep $HASH1 my_bisect_log.txt &&
 197                grep $HASH2 my_bisect_log.txt &&
 198                grep $HASH3 my_bisect_log.txt &&
 199                grep $HASH4 my_bisect_log.txt &&
 200                git bisect reset
 201        fi
 202'
 203
 204# $HASH1 is good, $HASH4 is bad, we skip $HASH3
 205# but $HASH2 is good,
 206# so we should not be able to tell the first bad commit
 207# among $HASH3 and $HASH4
 208test_expect_success 'bisect skip: cannot tell between 2 commits' '
 209        git bisect start $HASH4 $HASH1 &&
 210        git bisect skip || return 1
 211
 212        if git bisect good > my_bisect_log.txt
 213        then
 214                echo Oops, should have failed.
 215                false
 216        else
 217                test $? -eq 2 &&
 218                grep "first bad commit could be any of" my_bisect_log.txt &&
 219                ! grep $HASH1 my_bisect_log.txt &&
 220                ! grep $HASH2 my_bisect_log.txt &&
 221                grep $HASH3 my_bisect_log.txt &&
 222                grep $HASH4 my_bisect_log.txt &&
 223                git bisect reset
 224        fi
 225'
 226
 227# $HASH1 is good, $HASH4 is both skipped and bad, we skip $HASH3
 228# and $HASH2 is good,
 229# so we should not be able to tell the first bad commit
 230# among $HASH3 and $HASH4
 231test_expect_success 'bisect skip: with commit both bad and skipped' '
 232        git bisect start &&
 233        git bisect skip &&
 234        git bisect bad &&
 235        git bisect good $HASH1 &&
 236        git bisect skip &&
 237        if git bisect good > my_bisect_log.txt
 238        then
 239                echo Oops, should have failed.
 240                false
 241        else
 242                test $? -eq 2 &&
 243                grep "first bad commit could be any of" my_bisect_log.txt &&
 244                ! grep $HASH1 my_bisect_log.txt &&
 245                ! grep $HASH2 my_bisect_log.txt &&
 246                grep $HASH3 my_bisect_log.txt &&
 247                grep $HASH4 my_bisect_log.txt &&
 248                git bisect reset
 249        fi
 250'
 251
 252# We want to automatically find the commit that
 253# introduced "Another" into hello.
 254test_expect_success \
 255    '"git bisect run" simple case' \
 256    'echo "#"\!"/bin/sh" > test_script.sh &&
 257     echo "grep Another hello > /dev/null" >> test_script.sh &&
 258     echo "test \$? -ne 0" >> test_script.sh &&
 259     chmod +x test_script.sh &&
 260     git bisect start &&
 261     git bisect good $HASH1 &&
 262     git bisect bad $HASH4 &&
 263     git bisect run ./test_script.sh > my_bisect_log.txt &&
 264     grep "$HASH3 is first bad commit" my_bisect_log.txt &&
 265     git bisect reset'
 266
 267# We want to automatically find the commit that
 268# introduced "Ciao" into hello.
 269test_expect_success \
 270    '"git bisect run" with more complex "git bisect start"' \
 271    'echo "#"\!"/bin/sh" > test_script.sh &&
 272     echo "grep Ciao hello > /dev/null" >> test_script.sh &&
 273     echo "test \$? -ne 0" >> test_script.sh &&
 274     chmod +x test_script.sh &&
 275     git bisect start $HASH4 $HASH1 &&
 276     git bisect run ./test_script.sh > my_bisect_log.txt &&
 277     grep "$HASH4 is first bad commit" my_bisect_log.txt &&
 278     git bisect reset'
 279
 280# $HASH1 is good, $HASH5 is bad, we skip $HASH3
 281# but $HASH4 is good,
 282# so we should find $HASH5 as the first bad commit
 283HASH5=
 284test_expect_success 'bisect skip: add line and then a new test' '
 285        add_line_into_file "5: Another new line." hello &&
 286        HASH5=$(git rev-parse --verify HEAD) &&
 287        git bisect start $HASH5 $HASH1 &&
 288        git bisect skip &&
 289        git bisect good > my_bisect_log.txt &&
 290        grep "$HASH5 is first bad commit" my_bisect_log.txt &&
 291        git bisect log > log_to_replay.txt &&
 292        git bisect reset
 293'
 294
 295test_expect_success 'bisect skip and bisect replay' '
 296        git bisect replay log_to_replay.txt > my_bisect_log.txt &&
 297        grep "$HASH5 is first bad commit" my_bisect_log.txt &&
 298        git bisect reset
 299'
 300
 301HASH6=
 302test_expect_success 'bisect run & skip: cannot tell between 2' '
 303        add_line_into_file "6: Yet a line." hello &&
 304        HASH6=$(git rev-parse --verify HEAD) &&
 305        echo "#"\!"/bin/sh" > test_script.sh &&
 306        echo "sed -ne \\\$p hello | grep Ciao > /dev/null && exit 125" >> test_script.sh &&
 307        echo "grep line hello > /dev/null" >> test_script.sh &&
 308        echo "test \$? -ne 0" >> test_script.sh &&
 309        chmod +x test_script.sh &&
 310        git bisect start $HASH6 $HASH1 &&
 311        if git bisect run ./test_script.sh > my_bisect_log.txt
 312        then
 313                echo Oops, should have failed.
 314                false
 315        else
 316                test $? -eq 2 &&
 317                grep "first bad commit could be any of" my_bisect_log.txt &&
 318                ! grep $HASH3 my_bisect_log.txt &&
 319                ! grep $HASH6 my_bisect_log.txt &&
 320                grep $HASH4 my_bisect_log.txt &&
 321                grep $HASH5 my_bisect_log.txt
 322        fi
 323'
 324
 325HASH7=
 326test_expect_success 'bisect run & skip: find first bad' '
 327        git bisect reset &&
 328        add_line_into_file "7: Should be the last line." hello &&
 329        HASH7=$(git rev-parse --verify HEAD) &&
 330        echo "#"\!"/bin/sh" > test_script.sh &&
 331        echo "sed -ne \\\$p hello | grep Ciao > /dev/null && exit 125" >> test_script.sh &&
 332        echo "sed -ne \\\$p hello | grep day > /dev/null && exit 125" >> test_script.sh &&
 333        echo "grep Yet hello > /dev/null" >> test_script.sh &&
 334        echo "test \$? -ne 0" >> test_script.sh &&
 335        chmod +x test_script.sh &&
 336        git bisect start $HASH7 $HASH1 &&
 337        git bisect run ./test_script.sh > my_bisect_log.txt &&
 338        grep "$HASH6 is first bad commit" my_bisect_log.txt
 339'
 340
 341test_expect_success 'bisect skip only one range' '
 342        git bisect reset &&
 343        git bisect start $HASH7 $HASH1 &&
 344        git bisect skip $HASH1..$HASH5 &&
 345        test "$HASH6" = "$(git rev-parse --verify HEAD)" &&
 346        test_must_fail git bisect bad > my_bisect_log.txt &&
 347        grep "first bad commit could be any of" my_bisect_log.txt
 348'
 349
 350test_expect_success 'bisect skip many ranges' '
 351        git bisect start $HASH7 $HASH1 &&
 352        test "$HASH4" = "$(git rev-parse --verify HEAD)" &&
 353        git bisect skip $HASH2 $HASH2.. ..$HASH5 &&
 354        test "$HASH6" = "$(git rev-parse --verify HEAD)" &&
 355        test_must_fail git bisect bad > my_bisect_log.txt &&
 356        grep "first bad commit could be any of" my_bisect_log.txt
 357'
 358
 359test_expect_success 'bisect starting with a detached HEAD' '
 360        git bisect reset &&
 361        git checkout master^ &&
 362        HEAD=$(git rev-parse --verify HEAD) &&
 363        git bisect start &&
 364        test $HEAD = $(cat .git/BISECT_START) &&
 365        git bisect reset &&
 366        test $HEAD = $(git rev-parse --verify HEAD)
 367'
 368
 369test_expect_success 'bisect errors out if bad and good are mistaken' '
 370        git bisect reset &&
 371        test_must_fail git bisect start $HASH2 $HASH4 2> rev_list_error &&
 372        grep "mistake good and bad" rev_list_error &&
 373        git bisect reset
 374'
 375
 376test_expect_success 'bisect does not create a "bisect" branch' '
 377        git bisect reset &&
 378        git bisect start $HASH7 $HASH1 &&
 379        git branch bisect &&
 380        rev_hash4=$(git rev-parse --verify HEAD) &&
 381        test "$rev_hash4" = "$HASH4" &&
 382        git branch -D bisect &&
 383        git bisect good &&
 384        git branch bisect &&
 385        rev_hash6=$(git rev-parse --verify HEAD) &&
 386        test "$rev_hash6" = "$HASH6" &&
 387        git bisect good > my_bisect_log.txt &&
 388        grep "$HASH7 is first bad commit" my_bisect_log.txt &&
 389        git bisect reset &&
 390        rev_hash6=$(git rev-parse --verify bisect) &&
 391        test "$rev_hash6" = "$HASH6" &&
 392        git branch -D bisect
 393'
 394
 395# This creates a "side" branch to test "siblings" cases.
 396#
 397# H1-H2-H3-H4-H5-H6-H7  <--other
 398#            \
 399#             S5-S6-S7  <--side
 400#
 401test_expect_success 'side branch creation' '
 402        git bisect reset &&
 403        git checkout -b side $HASH4 &&
 404        add_line_into_file "5(side): first line on a side branch" hello2 &&
 405        SIDE_HASH5=$(git rev-parse --verify HEAD) &&
 406        add_line_into_file "6(side): second line on a side branch" hello2 &&
 407        SIDE_HASH6=$(git rev-parse --verify HEAD) &&
 408        add_line_into_file "7(side): third line on a side branch" hello2 &&
 409        SIDE_HASH7=$(git rev-parse --verify HEAD)
 410'
 411
 412test_expect_success 'good merge base when good and bad are siblings' '
 413        git bisect start "$HASH7" "$SIDE_HASH7" > my_bisect_log.txt &&
 414        grep "merge base must be tested" my_bisect_log.txt &&
 415        grep $HASH4 my_bisect_log.txt &&
 416        git bisect good > my_bisect_log.txt &&
 417        test_must_fail grep "merge base must be tested" my_bisect_log.txt &&
 418        grep $HASH6 my_bisect_log.txt &&
 419        git bisect reset
 420'
 421test_expect_success 'skipped merge base when good and bad are siblings' '
 422        git bisect start "$SIDE_HASH7" "$HASH7" > my_bisect_log.txt &&
 423        grep "merge base must be tested" my_bisect_log.txt &&
 424        grep $HASH4 my_bisect_log.txt &&
 425        git bisect skip > my_bisect_log.txt 2>&1 &&
 426        grep "Warning" my_bisect_log.txt &&
 427        grep $SIDE_HASH6 my_bisect_log.txt &&
 428        git bisect reset
 429'
 430
 431test_expect_success 'bad merge base when good and bad are siblings' '
 432        git bisect start "$HASH7" HEAD > my_bisect_log.txt &&
 433        grep "merge base must be tested" my_bisect_log.txt &&
 434        grep $HASH4 my_bisect_log.txt &&
 435        test_must_fail git bisect bad > my_bisect_log.txt 2>&1 &&
 436        grep "merge base $HASH4 is bad" my_bisect_log.txt &&
 437        grep "fixed between $HASH4 and \[$SIDE_HASH7\]" my_bisect_log.txt &&
 438        git bisect reset
 439'
 440
 441# This creates a few more commits (A and B) to test "siblings" cases
 442# when a good and a bad rev have many merge bases.
 443#
 444# We should have the following:
 445#
 446# H1-H2-H3-H4-H5-H6-H7
 447#            \  \     \
 448#             S5-A     \
 449#              \        \
 450#               S6-S7----B
 451#
 452# And there A and B have 2 merge bases (S5 and H5) that should be
 453# reported by "git merge-base --all A B".
 454#
 455test_expect_success 'many merge bases creation' '
 456        git checkout "$SIDE_HASH5" &&
 457        git merge -m "merge HASH5 and SIDE_HASH5" "$HASH5" &&
 458        A_HASH=$(git rev-parse --verify HEAD) &&
 459        git checkout side &&
 460        git merge -m "merge HASH7 and SIDE_HASH7" "$HASH7" &&
 461        B_HASH=$(git rev-parse --verify HEAD) &&
 462        git merge-base --all "$A_HASH" "$B_HASH" > merge_bases.txt &&
 463        test $(wc -l < merge_bases.txt) = "2" &&
 464        grep "$HASH5" merge_bases.txt &&
 465        grep "$SIDE_HASH5" merge_bases.txt
 466'
 467
 468test_expect_success 'good merge bases when good and bad are siblings' '
 469        git bisect start "$B_HASH" "$A_HASH" > my_bisect_log.txt &&
 470        grep "merge base must be tested" my_bisect_log.txt &&
 471        git bisect good > my_bisect_log2.txt &&
 472        grep "merge base must be tested" my_bisect_log2.txt &&
 473        {
 474                {
 475                        grep "$SIDE_HASH5" my_bisect_log.txt &&
 476                        grep "$HASH5" my_bisect_log2.txt
 477                } || {
 478                        grep "$SIDE_HASH5" my_bisect_log2.txt &&
 479                        grep "$HASH5" my_bisect_log.txt
 480                }
 481        } &&
 482        git bisect reset
 483'
 484
 485check_trace() {
 486        grep "$1" "$GIT_TRACE" | grep "\^$2" | grep "$3" >/dev/null
 487}
 488
 489test_expect_success 'optimized merge base checks' '
 490        GIT_TRACE="$(pwd)/trace.log" &&
 491        export GIT_TRACE &&
 492        git bisect start "$HASH7" "$SIDE_HASH7" > my_bisect_log.txt &&
 493        grep "merge base must be tested" my_bisect_log.txt &&
 494        grep "$HASH4" my_bisect_log.txt &&
 495        check_trace "rev-list" "$HASH7" "$SIDE_HASH7" &&
 496        git bisect good > my_bisect_log2.txt &&
 497        test -f ".git/BISECT_ANCESTORS_OK" &&
 498        test "$HASH6" = $(git rev-parse --verify HEAD) &&
 499        : > "$GIT_TRACE" &&
 500        git bisect bad > my_bisect_log3.txt &&
 501        test_must_fail check_trace "rev-list" "$HASH6" "$SIDE_HASH7" &&
 502        git bisect good "$A_HASH" > my_bisect_log4.txt &&
 503        grep "merge base must be tested" my_bisect_log4.txt &&
 504        test_must_fail test -f ".git/BISECT_ANCESTORS_OK" &&
 505        check_trace "rev-list" "$HASH6" "$A_HASH" &&
 506        unset GIT_TRACE
 507'
 508
 509#
 510#
 511test_done