t / t5510-fetch.shon commit general improvements (43abf13)
   1#!/bin/sh
   2# Copyright (c) 2006, Junio C Hamano.
   3
   4test_description='Per branch config variables affects "git fetch".
   5
   6'
   7
   8. ./test-lib.sh
   9
  10D=$(pwd)
  11
  12test_bundle_object_count () {
  13        git verify-pack -v "$1" >verify.out &&
  14        test "$2" = $(grep '^[0-9a-f]\{40\} ' verify.out | wc -l)
  15}
  16
  17convert_bundle_to_pack () {
  18        while read x && test -n "$x"
  19        do
  20                :;
  21        done
  22        cat
  23}
  24
  25test_expect_success setup '
  26        echo >file original &&
  27        git add file &&
  28        git commit -a -m original'
  29
  30test_expect_success "clone and setup child repos" '
  31        git clone . one &&
  32        (
  33                cd one &&
  34                echo >file updated by one &&
  35                git commit -a -m "updated by one"
  36        ) &&
  37        git clone . two &&
  38        (
  39                cd two &&
  40                git config branch.master.remote one &&
  41                git config remote.one.url ../one/.git/ &&
  42                git config remote.one.fetch refs/heads/master:refs/heads/one
  43        ) &&
  44        git clone . three &&
  45        (
  46                cd three &&
  47                git config branch.master.remote two &&
  48                git config branch.master.merge refs/heads/one &&
  49                mkdir -p .git/remotes &&
  50                {
  51                        echo "URL: ../two/.git/"
  52                        echo "Pull: refs/heads/master:refs/heads/two"
  53                        echo "Pull: refs/heads/one:refs/heads/one"
  54                } >.git/remotes/two
  55        ) &&
  56        git clone . bundle &&
  57        git clone . seven
  58'
  59
  60test_expect_success "fetch test" '
  61        cd "$D" &&
  62        echo >file updated by origin &&
  63        git commit -a -m "updated by origin" &&
  64        cd two &&
  65        git fetch &&
  66        git rev-parse --verify refs/heads/one &&
  67        mine=$(git rev-parse refs/heads/one) &&
  68        his=$(cd ../one && git rev-parse refs/heads/master) &&
  69        test "z$mine" = "z$his"
  70'
  71
  72test_expect_success "fetch test for-merge" '
  73        cd "$D" &&
  74        cd three &&
  75        git fetch &&
  76        git rev-parse --verify refs/heads/two &&
  77        git rev-parse --verify refs/heads/one &&
  78        master_in_two=$(cd ../two && git rev-parse master) &&
  79        one_in_two=$(cd ../two && git rev-parse one) &&
  80        {
  81                echo "$one_in_two       "
  82                echo "$master_in_two    not-for-merge"
  83        } >expected &&
  84        cut -f -2 .git/FETCH_HEAD >actual &&
  85        test_cmp expected actual'
  86
  87test_expect_success 'fetch --prune on its own works as expected' '
  88        cd "$D" &&
  89        git clone . prune &&
  90        cd prune &&
  91        git update-ref refs/remotes/origin/extrabranch master &&
  92
  93        git fetch --prune origin &&
  94        test_must_fail git rev-parse origin/extrabranch
  95'
  96
  97test_expect_success 'fetch --prune with a branch name keeps branches' '
  98        cd "$D" &&
  99        git clone . prune-branch &&
 100        cd prune-branch &&
 101        git update-ref refs/remotes/origin/extrabranch master &&
 102
 103        git fetch --prune origin master &&
 104        git rev-parse origin/extrabranch
 105'
 106
 107test_expect_success 'fetch --prune with a namespace keeps other namespaces' '
 108        cd "$D" &&
 109        git clone . prune-namespace &&
 110        cd prune-namespace &&
 111
 112        git fetch --prune origin refs/heads/a/*:refs/remotes/origin/a/* &&
 113        git rev-parse origin/master
 114'
 115
 116test_expect_success 'fetch --prune handles overlapping refspecs' '
 117        cd "$D" &&
 118        git update-ref refs/pull/42/head master &&
 119        git clone . prune-overlapping &&
 120        cd prune-overlapping &&
 121        git config --add remote.origin.fetch refs/pull/*/head:refs/remotes/origin/pr/* &&
 122
 123        git fetch --prune origin &&
 124        git rev-parse origin/master &&
 125        git rev-parse origin/pr/42 &&
 126
 127        git config --unset-all remote.origin.fetch &&
 128        git config remote.origin.fetch refs/pull/*/head:refs/remotes/origin/pr/* &&
 129        git config --add remote.origin.fetch refs/heads/*:refs/remotes/origin/* &&
 130
 131        git fetch --prune origin &&
 132        git rev-parse origin/master &&
 133        git rev-parse origin/pr/42
 134'
 135
 136test_expect_success 'fetch --prune --tags prunes branches but not tags' '
 137        cd "$D" &&
 138        git clone . prune-tags &&
 139        cd prune-tags &&
 140        git tag sometag master &&
 141        # Create what looks like a remote-tracking branch from an earlier
 142        # fetch that has since been deleted from the remote:
 143        git update-ref refs/remotes/origin/fake-remote master &&
 144
 145        git fetch --prune --tags origin &&
 146        git rev-parse origin/master &&
 147        test_must_fail git rev-parse origin/fake-remote &&
 148        git rev-parse sometag
 149'
 150
 151test_expect_success 'fetch --prune --tags with branch does not prune other things' '
 152        cd "$D" &&
 153        git clone . prune-tags-branch &&
 154        cd prune-tags-branch &&
 155        git tag sometag master &&
 156        git update-ref refs/remotes/origin/extrabranch master &&
 157
 158        git fetch --prune --tags origin master &&
 159        git rev-parse origin/extrabranch &&
 160        git rev-parse sometag
 161'
 162
 163test_expect_success 'fetch --prune --tags with refspec prunes based on refspec' '
 164        cd "$D" &&
 165        git clone . prune-tags-refspec &&
 166        cd prune-tags-refspec &&
 167        git tag sometag master &&
 168        git update-ref refs/remotes/origin/foo/otherbranch master &&
 169        git update-ref refs/remotes/origin/extrabranch master &&
 170
 171        git fetch --prune --tags origin refs/heads/foo/*:refs/remotes/origin/foo/* &&
 172        test_must_fail git rev-parse refs/remotes/origin/foo/otherbranch &&
 173        git rev-parse origin/extrabranch &&
 174        git rev-parse sometag
 175'
 176
 177test_expect_success 'fetch tags when there is no tags' '
 178
 179    cd "$D" &&
 180
 181    mkdir notags &&
 182    cd notags &&
 183    git init &&
 184
 185    git fetch -t ..
 186
 187'
 188
 189test_expect_success 'fetch following tags' '
 190
 191        cd "$D" &&
 192        git tag -a -m 'annotated' anno HEAD &&
 193        git tag light HEAD &&
 194
 195        mkdir four &&
 196        cd four &&
 197        git init &&
 198
 199        git fetch .. :track &&
 200        git show-ref --verify refs/tags/anno &&
 201        git show-ref --verify refs/tags/light
 202
 203'
 204
 205test_expect_success 'fetch uses remote ref names to describe new refs' '
 206        cd "$D" &&
 207        git init descriptive &&
 208        (
 209                cd descriptive &&
 210                git config remote.o.url .. &&
 211                git config remote.o.fetch "refs/heads/*:refs/crazyheads/*" &&
 212                git config --add remote.o.fetch "refs/others/*:refs/heads/*" &&
 213                git fetch o
 214        ) &&
 215        git tag -a -m "Descriptive tag" descriptive-tag &&
 216        git branch descriptive-branch &&
 217        git checkout descriptive-branch &&
 218        echo "Nuts" >crazy &&
 219        git add crazy &&
 220        git commit -a -m "descriptive commit" &&
 221        git update-ref refs/others/crazy HEAD &&
 222        (
 223                cd descriptive &&
 224                git fetch o 2>actual &&
 225                test_i18ngrep "new branch.* -> refs/crazyheads/descriptive-branch$" actual &&
 226                test_i18ngrep "new tag.* -> descriptive-tag$" actual &&
 227                test_i18ngrep "new ref.* -> crazy$" actual
 228        ) &&
 229        git checkout master
 230'
 231
 232test_expect_success 'fetch must not resolve short tag name' '
 233
 234        cd "$D" &&
 235
 236        mkdir five &&
 237        cd five &&
 238        git init &&
 239
 240        test_must_fail git fetch .. anno:five
 241
 242'
 243
 244test_expect_success 'fetch can now resolve short remote name' '
 245
 246        cd "$D" &&
 247        git update-ref refs/remotes/six/HEAD HEAD &&
 248
 249        mkdir six &&
 250        cd six &&
 251        git init &&
 252
 253        git fetch .. six:six
 254'
 255
 256test_expect_success 'create bundle 1' '
 257        cd "$D" &&
 258        echo >file updated again by origin &&
 259        git commit -a -m "tip" &&
 260        git bundle create bundle1 master^..master
 261'
 262
 263test_expect_success 'header of bundle looks right' '
 264        head -n 1 "$D"/bundle1 | grep "^#" &&
 265        head -n 2 "$D"/bundle1 | grep "^-[0-9a-f]\{40\} " &&
 266        head -n 3 "$D"/bundle1 | grep "^[0-9a-f]\{40\} " &&
 267        head -n 4 "$D"/bundle1 | grep "^$"
 268'
 269
 270test_expect_success 'create bundle 2' '
 271        cd "$D" &&
 272        git bundle create bundle2 master~2..master
 273'
 274
 275test_expect_success 'unbundle 1' '
 276        cd "$D/bundle" &&
 277        git checkout -b some-branch &&
 278        test_must_fail git fetch "$D/bundle1" master:master
 279'
 280
 281
 282test_expect_success 'bundle 1 has only 3 files ' '
 283        cd "$D" &&
 284        convert_bundle_to_pack <bundle1 >bundle.pack &&
 285        git index-pack bundle.pack &&
 286        test_bundle_object_count bundle.pack 3
 287'
 288
 289test_expect_success 'unbundle 2' '
 290        cd "$D/bundle" &&
 291        git fetch ../bundle2 master:master &&
 292        test "tip" = "$(git log -1 --pretty=oneline master | cut -b42-)"
 293'
 294
 295test_expect_success 'bundle does not prerequisite objects' '
 296        cd "$D" &&
 297        touch file2 &&
 298        git add file2 &&
 299        git commit -m add.file2 file2 &&
 300        git bundle create bundle3 -1 HEAD &&
 301        convert_bundle_to_pack <bundle3 >bundle.pack &&
 302        git index-pack bundle.pack &&
 303        test_bundle_object_count bundle.pack 3
 304'
 305
 306test_expect_success 'bundle should be able to create a full history' '
 307
 308        cd "$D" &&
 309        git tag -a -m '1.0' v1.0 master &&
 310        git bundle create bundle4 v1.0
 311
 312'
 313
 314test_expect_success 'fetch with a non-applying branch.<name>.merge' '
 315        git config branch.master.remote yeti &&
 316        git config branch.master.merge refs/heads/bigfoot &&
 317        git config remote.blub.url one &&
 318        git config remote.blub.fetch "refs/heads/*:refs/remotes/one/*" &&
 319        git fetch blub
 320'
 321
 322# URL supplied to fetch does not match the url of the configured branch's remote
 323test_expect_success 'fetch from GIT URL with a non-applying branch.<name>.merge [1]' '
 324        one_head=$(cd one && git rev-parse HEAD) &&
 325        this_head=$(git rev-parse HEAD) &&
 326        git update-ref -d FETCH_HEAD &&
 327        git fetch one &&
 328        test $one_head = "$(git rev-parse --verify FETCH_HEAD)" &&
 329        test $this_head = "$(git rev-parse --verify HEAD)"
 330'
 331
 332# URL supplied to fetch matches the url of the configured branch's remote and
 333# the merge spec matches the branch the remote HEAD points to
 334test_expect_success 'fetch from GIT URL with a non-applying branch.<name>.merge [2]' '
 335        one_ref=$(cd one && git symbolic-ref HEAD) &&
 336        git config branch.master.remote blub &&
 337        git config branch.master.merge "$one_ref" &&
 338        git update-ref -d FETCH_HEAD &&
 339        git fetch one &&
 340        test $one_head = "$(git rev-parse --verify FETCH_HEAD)" &&
 341        test $this_head = "$(git rev-parse --verify HEAD)"
 342'
 343
 344# URL supplied to fetch matches the url of the configured branch's remote, but
 345# the merge spec does not match the branch the remote HEAD points to
 346test_expect_success 'fetch from GIT URL with a non-applying branch.<name>.merge [3]' '
 347        git config branch.master.merge "${one_ref}_not" &&
 348        git update-ref -d FETCH_HEAD &&
 349        git fetch one &&
 350        test $one_head = "$(git rev-parse --verify FETCH_HEAD)" &&
 351        test $this_head = "$(git rev-parse --verify HEAD)"
 352'
 353
 354# the strange name is: a\!'b
 355test_expect_success 'quoting of a strangely named repo' '
 356        test_must_fail git fetch "a\\!'\''b" > result 2>&1 &&
 357        cat result &&
 358        grep "fatal: '\''a\\\\!'\''b'\''" result
 359'
 360
 361test_expect_success 'bundle should record HEAD correctly' '
 362
 363        cd "$D" &&
 364        git bundle create bundle5 HEAD master &&
 365        git bundle list-heads bundle5 >actual &&
 366        for h in HEAD refs/heads/master
 367        do
 368                echo "$(git rev-parse --verify $h) $h"
 369        done >expect &&
 370        test_cmp expect actual
 371
 372'
 373
 374test_expect_success 'mark initial state of origin/master' '
 375        (
 376                cd three &&
 377                git tag base-origin-master refs/remotes/origin/master
 378        )
 379'
 380
 381test_expect_success 'explicit fetch should update tracking' '
 382
 383        cd "$D" &&
 384        git branch -f side &&
 385        (
 386                cd three &&
 387                git update-ref refs/remotes/origin/master base-origin-master &&
 388                o=$(git rev-parse --verify refs/remotes/origin/master) &&
 389                git fetch origin master &&
 390                n=$(git rev-parse --verify refs/remotes/origin/master) &&
 391                test "$o" != "$n" &&
 392                test_must_fail git rev-parse --verify refs/remotes/origin/side
 393        )
 394'
 395
 396test_expect_success 'explicit pull should update tracking' '
 397
 398        cd "$D" &&
 399        git branch -f side &&
 400        (
 401                cd three &&
 402                git update-ref refs/remotes/origin/master base-origin-master &&
 403                o=$(git rev-parse --verify refs/remotes/origin/master) &&
 404                git pull origin master &&
 405                n=$(git rev-parse --verify refs/remotes/origin/master) &&
 406                test "$o" != "$n" &&
 407                test_must_fail git rev-parse --verify refs/remotes/origin/side
 408        )
 409'
 410
 411test_expect_success 'explicit --refmap is allowed only with command-line refspec' '
 412        cd "$D" &&
 413        (
 414                cd three &&
 415                test_must_fail git fetch --refmap="*:refs/remotes/none/*"
 416        )
 417'
 418
 419test_expect_success 'explicit --refmap option overrides remote.*.fetch' '
 420        cd "$D" &&
 421        git branch -f side &&
 422        (
 423                cd three &&
 424                git update-ref refs/remotes/origin/master base-origin-master &&
 425                o=$(git rev-parse --verify refs/remotes/origin/master) &&
 426                git fetch --refmap="refs/heads/*:refs/remotes/other/*" origin master &&
 427                n=$(git rev-parse --verify refs/remotes/origin/master) &&
 428                test "$o" = "$n" &&
 429                test_must_fail git rev-parse --verify refs/remotes/origin/side &&
 430                git rev-parse --verify refs/remotes/other/master
 431        )
 432'
 433
 434test_expect_success 'explicitly empty --refmap option disables remote.*.fetch' '
 435        cd "$D" &&
 436        git branch -f side &&
 437        (
 438                cd three &&
 439                git update-ref refs/remotes/origin/master base-origin-master &&
 440                o=$(git rev-parse --verify refs/remotes/origin/master) &&
 441                git fetch --refmap="" origin master &&
 442                n=$(git rev-parse --verify refs/remotes/origin/master) &&
 443                test "$o" = "$n" &&
 444                test_must_fail git rev-parse --verify refs/remotes/origin/side
 445        )
 446'
 447
 448test_expect_success 'configured fetch updates tracking' '
 449
 450        cd "$D" &&
 451        git branch -f side &&
 452        (
 453                cd three &&
 454                git update-ref refs/remotes/origin/master base-origin-master &&
 455                o=$(git rev-parse --verify refs/remotes/origin/master) &&
 456                git fetch origin &&
 457                n=$(git rev-parse --verify refs/remotes/origin/master) &&
 458                test "$o" != "$n" &&
 459                git rev-parse --verify refs/remotes/origin/side
 460        )
 461'
 462
 463test_expect_success 'non-matching refspecs do not confuse tracking update' '
 464        cd "$D" &&
 465        git update-ref refs/odd/location HEAD &&
 466        (
 467                cd three &&
 468                git update-ref refs/remotes/origin/master base-origin-master &&
 469                git config --add remote.origin.fetch \
 470                        refs/odd/location:refs/remotes/origin/odd &&
 471                o=$(git rev-parse --verify refs/remotes/origin/master) &&
 472                git fetch origin master &&
 473                n=$(git rev-parse --verify refs/remotes/origin/master) &&
 474                test "$o" != "$n" &&
 475                test_must_fail git rev-parse --verify refs/remotes/origin/odd
 476        )
 477'
 478
 479test_expect_success 'pushing nonexistent branch by mistake should not segv' '
 480
 481        cd "$D" &&
 482        test_must_fail git push seven no:no
 483
 484'
 485
 486test_expect_success 'auto tag following fetches minimum' '
 487
 488        cd "$D" &&
 489        git clone .git follow &&
 490        git checkout HEAD^0 &&
 491        (
 492                for i in 1 2 3 4 5 6 7
 493                do
 494                        echo $i >>file &&
 495                        git commit -m $i -a &&
 496                        git tag -a -m $i excess-$i || exit 1
 497                done
 498        ) &&
 499        git checkout master &&
 500        (
 501                cd follow &&
 502                git fetch
 503        )
 504'
 505
 506test_expect_success 'refuse to fetch into the current branch' '
 507
 508        test_must_fail git fetch . side:master
 509
 510'
 511
 512test_expect_success 'fetch into the current branch with --update-head-ok' '
 513
 514        git fetch --update-head-ok . side:master
 515
 516'
 517
 518test_expect_success 'fetch --dry-run' '
 519
 520        rm -f .git/FETCH_HEAD &&
 521        git fetch --dry-run . &&
 522        ! test -f .git/FETCH_HEAD
 523'
 524
 525test_expect_success "should be able to fetch with duplicate refspecs" '
 526        mkdir dups &&
 527        (
 528                cd dups &&
 529                git init &&
 530                git config branch.master.remote three &&
 531                git config remote.three.url ../three/.git &&
 532                git config remote.three.fetch +refs/heads/*:refs/remotes/origin/* &&
 533                git config --add remote.three.fetch +refs/heads/*:refs/remotes/origin/* &&
 534                git fetch three
 535        )
 536'
 537
 538test_expect_success 'LHS of refspec follows ref disambiguation rules' '
 539        mkdir lhs-ambiguous &&
 540        (
 541                cd lhs-ambiguous &&
 542                git init server &&
 543                test_commit -C server unwanted &&
 544                test_commit -C server wanted &&
 545
 546                git init client &&
 547
 548                # Check a name coming after "refs" alphabetically ...
 549                git -C server update-ref refs/heads/s wanted &&
 550                git -C server update-ref refs/heads/refs/heads/s unwanted &&
 551                git -C client fetch ../server +refs/heads/s:refs/heads/checkthis &&
 552                git -C server rev-parse wanted >expect &&
 553                git -C client rev-parse checkthis >actual &&
 554                test_cmp expect actual &&
 555
 556                # ... and one before.
 557                git -C server update-ref refs/heads/q wanted &&
 558                git -C server update-ref refs/heads/refs/heads/q unwanted &&
 559                git -C client fetch ../server +refs/heads/q:refs/heads/checkthis &&
 560                git -C server rev-parse wanted >expect &&
 561                git -C client rev-parse checkthis >actual &&
 562                test_cmp expect actual &&
 563
 564                # Tags are preferred over branches like refs/{heads,tags}/*
 565                git -C server update-ref refs/tags/t wanted &&
 566                git -C server update-ref refs/heads/t unwanted &&
 567                git -C client fetch ../server +t:refs/heads/checkthis &&
 568                git -C server rev-parse wanted >expect &&
 569                git -C client rev-parse checkthis >actual
 570        )
 571'
 572
 573test_expect_success 'fetch.writeCommitGraph' '
 574        git clone three write &&
 575        (
 576                cd three &&
 577                test_commit new
 578        ) &&
 579        (
 580                cd write &&
 581                git -c fetch.writeCommitGraph fetch origin &&
 582                test_path_is_file .git/objects/info/commit-graphs/commit-graph-chain
 583        )
 584'
 585
 586# configured prune tests
 587
 588set_config_tristate () {
 589        # var=$1 val=$2
 590        case "$2" in
 591        unset)
 592                test_unconfig "$1"
 593                ;;
 594        *)
 595                git config "$1" "$2"
 596                key=$(echo $1 | sed -e 's/^remote\.origin/fetch/')
 597                git_fetch_c="$git_fetch_c -c $key=$2"
 598                ;;
 599        esac
 600}
 601
 602test_configured_prune () {
 603        test_configured_prune_type "$@" "name"
 604        test_configured_prune_type "$@" "link"
 605}
 606
 607test_configured_prune_type () {
 608        fetch_prune=$1
 609        remote_origin_prune=$2
 610        fetch_prune_tags=$3
 611        remote_origin_prune_tags=$4
 612        expected_branch=$5
 613        expected_tag=$6
 614        cmdline=$7
 615        mode=$8
 616
 617        if test -z "$cmdline_setup"
 618        then
 619                test_expect_success 'setup cmdline_setup variable for subsequent test' '
 620                        remote_url="file://$(git -C one config remote.origin.url)" &&
 621                        remote_fetch="$(git -C one config remote.origin.fetch)" &&
 622                        cmdline_setup="\"$remote_url\" \"$remote_fetch\""
 623                '
 624        fi
 625
 626        if test "$mode" = 'link'
 627        then
 628                new_cmdline=""
 629
 630                if test "$cmdline" = ""
 631                then
 632                        new_cmdline=$cmdline_setup
 633                else
 634                        new_cmdline=$(printf "%s" "$cmdline" | perl -pe 's[origin(?!/)]["'"$remote_url"'"]g')
 635                fi
 636
 637                if test "$fetch_prune_tags" = 'true' ||
 638                   test "$remote_origin_prune_tags" = 'true'
 639                then
 640                        if ! printf '%s' "$cmdline\n" | grep -q refs/remotes/origin/
 641                        then
 642                                new_cmdline="$new_cmdline refs/tags/*:refs/tags/*"
 643                        fi
 644                fi
 645
 646                cmdline="$new_cmdline"
 647        fi
 648
 649        test_expect_success "$mode prune fetch.prune=$1 remote.origin.prune=$2 fetch.pruneTags=$3 remote.origin.pruneTags=$4${7:+ $7}; branch:$5 tag:$6" '
 650                # make sure a newbranch is there in . and also in one
 651                git branch -f newbranch &&
 652                git tag -f newtag &&
 653                (
 654                        cd one &&
 655                        test_unconfig fetch.prune &&
 656                        test_unconfig fetch.pruneTags &&
 657                        test_unconfig remote.origin.prune &&
 658                        test_unconfig remote.origin.pruneTags &&
 659                        git fetch '"$cmdline_setup"' &&
 660                        git rev-parse --verify refs/remotes/origin/newbranch &&
 661                        git rev-parse --verify refs/tags/newtag
 662                ) &&
 663
 664                # now remove them
 665                git branch -d newbranch &&
 666                git tag -d newtag &&
 667
 668                # then test
 669                (
 670                        cd one &&
 671                        git_fetch_c="" &&
 672                        set_config_tristate fetch.prune $fetch_prune &&
 673                        set_config_tristate fetch.pruneTags $fetch_prune_tags &&
 674                        set_config_tristate remote.origin.prune $remote_origin_prune &&
 675                        set_config_tristate remote.origin.pruneTags $remote_origin_prune_tags &&
 676
 677                        if test "$mode" != "link"
 678                        then
 679                                git_fetch_c=""
 680                        fi &&
 681                        git$git_fetch_c fetch '"$cmdline"' &&
 682                        case "$expected_branch" in
 683                        pruned)
 684                                test_must_fail git rev-parse --verify refs/remotes/origin/newbranch
 685                                ;;
 686                        kept)
 687                                git rev-parse --verify refs/remotes/origin/newbranch
 688                                ;;
 689                        esac &&
 690                        case "$expected_tag" in
 691                        pruned)
 692                                test_must_fail git rev-parse --verify refs/tags/newtag
 693                                ;;
 694                        kept)
 695                                git rev-parse --verify refs/tags/newtag
 696                                ;;
 697                        esac
 698                )
 699        '
 700}
 701
 702# $1 config: fetch.prune
 703# $2 config: remote.<name>.prune
 704# $3 config: fetch.pruneTags
 705# $4 config: remote.<name>.pruneTags
 706# $5 expect: branch to be pruned?
 707# $6 expect: tag to be pruned?
 708# $7 git-fetch $cmdline:
 709#
 710#                     $1    $2    $3    $4    $5     $6     $7
 711test_configured_prune unset unset unset unset kept   kept   ""
 712test_configured_prune unset unset unset unset kept   kept   "--no-prune"
 713test_configured_prune unset unset unset unset pruned kept   "--prune"
 714test_configured_prune unset unset unset unset kept   pruned \
 715        "--prune origin refs/tags/*:refs/tags/*"
 716test_configured_prune unset unset unset unset pruned pruned \
 717        "--prune origin refs/tags/*:refs/tags/* +refs/heads/*:refs/remotes/origin/*"
 718
 719test_configured_prune false unset unset unset kept   kept   ""
 720test_configured_prune false unset unset unset kept   kept   "--no-prune"
 721test_configured_prune false unset unset unset pruned kept   "--prune"
 722
 723test_configured_prune true  unset unset unset pruned kept   ""
 724test_configured_prune true  unset unset unset pruned kept   "--prune"
 725test_configured_prune true  unset unset unset kept   kept   "--no-prune"
 726
 727test_configured_prune unset false unset unset kept   kept   ""
 728test_configured_prune unset false unset unset kept   kept   "--no-prune"
 729test_configured_prune unset false unset unset pruned kept   "--prune"
 730
 731test_configured_prune false false unset unset kept   kept   ""
 732test_configured_prune false false unset unset kept   kept   "--no-prune"
 733test_configured_prune false false unset unset pruned kept   "--prune"
 734test_configured_prune false false unset unset kept   pruned \
 735        "--prune origin refs/tags/*:refs/tags/*"
 736test_configured_prune false false unset unset pruned pruned \
 737        "--prune origin refs/tags/*:refs/tags/* +refs/heads/*:refs/remotes/origin/*"
 738
 739test_configured_prune true  false unset unset kept   kept   ""
 740test_configured_prune true  false unset unset pruned kept   "--prune"
 741test_configured_prune true  false unset unset kept   kept   "--no-prune"
 742
 743test_configured_prune unset true  unset unset pruned kept   ""
 744test_configured_prune unset true  unset unset kept   kept   "--no-prune"
 745test_configured_prune unset true  unset unset pruned kept   "--prune"
 746
 747test_configured_prune false true  unset unset pruned kept   ""
 748test_configured_prune false true  unset unset kept   kept   "--no-prune"
 749test_configured_prune false true  unset unset pruned kept   "--prune"
 750
 751test_configured_prune true  true  unset unset pruned kept   ""
 752test_configured_prune true  true  unset unset pruned kept   "--prune"
 753test_configured_prune true  true  unset unset kept   kept   "--no-prune"
 754test_configured_prune true  true  unset unset kept   pruned \
 755        "--prune origin refs/tags/*:refs/tags/*"
 756test_configured_prune true  true  unset unset pruned pruned \
 757        "--prune origin refs/tags/*:refs/tags/* +refs/heads/*:refs/remotes/origin/*"
 758
 759# --prune-tags on its own does nothing, needs --prune as well, same
 760# for for fetch.pruneTags without fetch.prune
 761test_configured_prune unset unset unset unset kept kept     "--prune-tags"
 762test_configured_prune unset unset true unset  kept kept     ""
 763test_configured_prune unset unset unset true  kept kept     ""
 764
 765# These will prune the tags
 766test_configured_prune unset unset unset unset pruned pruned "--prune --prune-tags"
 767test_configured_prune true  unset true  unset pruned pruned ""
 768test_configured_prune unset true  unset true  pruned pruned ""
 769
 770# remote.<name>.pruneTags overrides fetch.pruneTags, just like
 771# remote.<name>.prune overrides fetch.prune if set.
 772test_configured_prune true  unset true unset pruned pruned  ""
 773test_configured_prune false true  false true  pruned pruned ""
 774test_configured_prune true  false true  false kept   kept   ""
 775
 776# When --prune-tags is supplied it's ignored if an explicit refspec is
 777# given, same for the configuration options.
 778test_configured_prune unset unset unset unset pruned kept \
 779        "--prune --prune-tags origin +refs/heads/*:refs/remotes/origin/*"
 780test_configured_prune unset unset true  unset pruned kept \
 781        "--prune origin +refs/heads/*:refs/remotes/origin/*"
 782test_configured_prune unset unset unset true pruned  kept \
 783        "--prune origin +refs/heads/*:refs/remotes/origin/*"
 784
 785# Pruning that also takes place if a file:// url replaces a named
 786# remote. However, because there's no implicit
 787# +refs/heads/*:refs/remotes/origin/* refspec and supplying it on the
 788# command-line negates --prune-tags, the branches will not be pruned.
 789test_configured_prune_type unset unset unset unset kept   kept   "origin --prune-tags" "name"
 790test_configured_prune_type unset unset unset unset kept   kept   "origin --prune-tags" "link"
 791test_configured_prune_type unset unset unset unset pruned pruned "origin --prune --prune-tags" "name"
 792test_configured_prune_type unset unset unset unset kept   pruned "origin --prune --prune-tags" "link"
 793test_configured_prune_type unset unset unset unset pruned pruned "--prune --prune-tags origin" "name"
 794test_configured_prune_type unset unset unset unset kept   pruned "--prune --prune-tags origin" "link"
 795test_configured_prune_type unset unset true  unset pruned pruned "--prune origin" "name"
 796test_configured_prune_type unset unset true  unset kept   pruned "--prune origin" "link"
 797test_configured_prune_type unset unset unset true  pruned pruned "--prune origin" "name"
 798test_configured_prune_type unset unset unset true  kept   pruned "--prune origin" "link"
 799test_configured_prune_type true  unset true  unset pruned pruned "origin" "name"
 800test_configured_prune_type true  unset true  unset kept   pruned "origin" "link"
 801test_configured_prune_type unset  true true  unset pruned pruned "origin" "name"
 802test_configured_prune_type unset  true true  unset kept   pruned "origin" "link"
 803test_configured_prune_type unset  true unset true  pruned pruned "origin" "name"
 804test_configured_prune_type unset  true unset true  kept   pruned "origin" "link"
 805
 806# When all remote.origin.fetch settings are deleted a --prune
 807# --prune-tags still implicitly supplies refs/tags/*:refs/tags/* so
 808# tags, but not tracking branches, will be deleted.
 809test_expect_success 'remove remote.origin.fetch "one"' '
 810        (
 811                cd one &&
 812                git config --unset-all remote.origin.fetch
 813        )
 814'
 815test_configured_prune_type unset unset unset unset kept pruned "origin --prune --prune-tags" "name"
 816test_configured_prune_type unset unset unset unset kept pruned "origin --prune --prune-tags" "link"
 817
 818test_expect_success 'all boundary commits are excluded' '
 819        test_commit base &&
 820        test_commit oneside &&
 821        git checkout HEAD^ &&
 822        test_commit otherside &&
 823        git checkout master &&
 824        test_tick &&
 825        git merge otherside &&
 826        ad=$(git log --no-walk --format=%ad HEAD) &&
 827        git bundle create twoside-boundary.bdl master --since="$ad" &&
 828        convert_bundle_to_pack <twoside-boundary.bdl >twoside-boundary.pack &&
 829        pack=$(git index-pack --fix-thin --stdin <twoside-boundary.pack) &&
 830        test_bundle_object_count .git/objects/pack/pack-${pack##pack    }.pack 3
 831'
 832
 833test_expect_success 'fetch --prune prints the remotes url' '
 834        git branch goodbye &&
 835        git clone . only-prunes &&
 836        git branch -D goodbye &&
 837        (
 838                cd only-prunes &&
 839                git fetch --prune origin 2>&1 | head -n1 >../actual
 840        ) &&
 841        echo "From ${D}/." >expect &&
 842        test_i18ncmp expect actual
 843'
 844
 845test_expect_success 'branchname D/F conflict resolved by --prune' '
 846        git branch dir/file &&
 847        git clone . prune-df-conflict &&
 848        git branch -D dir/file &&
 849        git branch dir &&
 850        (
 851                cd prune-df-conflict &&
 852                git fetch --prune &&
 853                git rev-parse origin/dir >../actual
 854        ) &&
 855        git rev-parse dir >expect &&
 856        test_cmp expect actual
 857'
 858
 859test_expect_success 'fetching a one-level ref works' '
 860        test_commit extra &&
 861        git reset --hard HEAD^ &&
 862        git update-ref refs/foo extra &&
 863        git init one-level &&
 864        (
 865                cd one-level &&
 866                git fetch .. HEAD refs/foo
 867        )
 868'
 869
 870test_expect_success 'fetching with auto-gc does not lock up' '
 871        write_script askyesno <<-\EOF &&
 872        echo "$*" &&
 873        false
 874        EOF
 875        git clone "file://$D" auto-gc &&
 876        test_commit test2 &&
 877        (
 878                cd auto-gc &&
 879                git config fetch.unpackLimit 1 &&
 880                git config gc.autoPackLimit 1 &&
 881                git config gc.autoDetach false &&
 882                GIT_ASK_YESNO="$D/askyesno" git fetch >fetch.out 2>&1 &&
 883                test_i18ngrep "Auto packing the repository" fetch.out &&
 884                ! grep "Should I try again" fetch.out
 885        )
 886'
 887
 888test_expect_success C_LOCALE_OUTPUT 'fetch aligned output' '
 889        git clone . full-output &&
 890        test_commit looooooooooooong-tag &&
 891        (
 892                cd full-output &&
 893                git -c fetch.output=full fetch origin >actual 2>&1 &&
 894                grep -e "->" actual | cut -c 22- >../actual
 895        ) &&
 896        cat >expect <<-\EOF &&
 897        master               -> origin/master
 898        looooooooooooong-tag -> looooooooooooong-tag
 899        EOF
 900        test_cmp expect actual
 901'
 902
 903test_expect_success C_LOCALE_OUTPUT 'fetch compact output' '
 904        git clone . compact &&
 905        test_commit extraaa &&
 906        (
 907                cd compact &&
 908                git -c fetch.output=compact fetch origin >actual 2>&1 &&
 909                grep -e "->" actual | cut -c 22- >../actual
 910        ) &&
 911        cat >expect <<-\EOF &&
 912        master     -> origin/*
 913        extraaa    -> *
 914        EOF
 915        test_cmp expect actual
 916'
 917
 918test_expect_success '--no-show-forced-updates' '
 919        mkdir forced-updates &&
 920        (
 921                cd forced-updates &&
 922                git init &&
 923                test_commit 1 &&
 924                test_commit 2
 925        ) &&
 926        git clone forced-updates forced-update-clone &&
 927        git clone forced-updates no-forced-update-clone &&
 928        git -C forced-updates reset --hard HEAD~1 &&
 929        (
 930                cd forced-update-clone &&
 931                git fetch --show-forced-updates origin 2>output &&
 932                test_i18ngrep "(forced update)" output
 933        ) &&
 934        (
 935                cd no-forced-update-clone &&
 936                git fetch --no-show-forced-updates origin 2>output &&
 937                test_i18ngrep ! "(forced update)" output
 938        )
 939'
 940
 941setup_negotiation_tip () {
 942        SERVER="$1"
 943        URL="$2"
 944        USE_PROTOCOL_V2="$3"
 945
 946        rm -rf "$SERVER" client trace &&
 947        git init "$SERVER" &&
 948        test_commit -C "$SERVER" alpha_1 &&
 949        test_commit -C "$SERVER" alpha_2 &&
 950        git -C "$SERVER" checkout --orphan beta &&
 951        test_commit -C "$SERVER" beta_1 &&
 952        test_commit -C "$SERVER" beta_2 &&
 953
 954        git clone "$URL" client &&
 955
 956        if test "$USE_PROTOCOL_V2" -eq 1
 957        then
 958                git -C "$SERVER" config protocol.version 2 &&
 959                git -C client config protocol.version 2
 960        fi &&
 961
 962        test_commit -C "$SERVER" beta_s &&
 963        git -C "$SERVER" checkout master &&
 964        test_commit -C "$SERVER" alpha_s &&
 965        git -C "$SERVER" tag -d alpha_1 alpha_2 beta_1 beta_2
 966}
 967
 968check_negotiation_tip () {
 969        # Ensure that {alpha,beta}_1 are sent as "have", but not {alpha_beta}_2
 970        ALPHA_1=$(git -C client rev-parse alpha_1) &&
 971        grep "fetch> have $ALPHA_1" trace &&
 972        BETA_1=$(git -C client rev-parse beta_1) &&
 973        grep "fetch> have $BETA_1" trace &&
 974        ALPHA_2=$(git -C client rev-parse alpha_2) &&
 975        ! grep "fetch> have $ALPHA_2" trace &&
 976        BETA_2=$(git -C client rev-parse beta_2) &&
 977        ! grep "fetch> have $BETA_2" trace
 978}
 979
 980test_expect_success '--negotiation-tip limits "have" lines sent' '
 981        setup_negotiation_tip server server 0 &&
 982        GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch \
 983                --negotiation-tip=alpha_1 --negotiation-tip=beta_1 \
 984                origin alpha_s beta_s &&
 985        check_negotiation_tip
 986'
 987
 988test_expect_success '--negotiation-tip understands globs' '
 989        setup_negotiation_tip server server 0 &&
 990        GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch \
 991                --negotiation-tip=*_1 \
 992                origin alpha_s beta_s &&
 993        check_negotiation_tip
 994'
 995
 996test_expect_success '--negotiation-tip understands abbreviated SHA-1' '
 997        setup_negotiation_tip server server 0 &&
 998        GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch \
 999                --negotiation-tip=$(git -C client rev-parse --short alpha_1) \
1000                --negotiation-tip=$(git -C client rev-parse --short beta_1) \
1001                origin alpha_s beta_s &&
1002        check_negotiation_tip
1003'
1004
1005. "$TEST_DIRECTORY"/lib-httpd.sh
1006start_httpd
1007
1008test_expect_success '--negotiation-tip limits "have" lines sent with HTTP protocol v2' '
1009        setup_negotiation_tip "$HTTPD_DOCUMENT_ROOT_PATH/server" \
1010                "$HTTPD_URL/smart/server" 1 &&
1011        GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch \
1012                --negotiation-tip=alpha_1 --negotiation-tip=beta_1 \
1013                origin alpha_s beta_s &&
1014        check_negotiation_tip
1015'
1016
1017# DO NOT add non-httpd-specific tests here, because the last part of this
1018# test script is only executed when httpd is available and enabled.
1019
1020test_done