t / t5510-fetch.shon commit fetch: add a --prune-tags option and fetch.pruneTags config (97716d2)
   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        test -f .git/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        test -f .git/refs/heads/two &&
  77        test -f .git/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                grep " -> refs/crazyheads/descriptive-branch$" actual |
 226                test_i18ngrep "new branch" &&
 227                grep " -> descriptive-tag$" actual |
 228                test_i18ngrep "new tag" &&
 229                grep " -> crazy$" actual |
 230                test_i18ngrep "new ref"
 231        ) &&
 232        git checkout master
 233'
 234
 235test_expect_success 'fetch must not resolve short tag name' '
 236
 237        cd "$D" &&
 238
 239        mkdir five &&
 240        cd five &&
 241        git init &&
 242
 243        test_must_fail git fetch .. anno:five
 244
 245'
 246
 247test_expect_success 'fetch can now resolve short remote name' '
 248
 249        cd "$D" &&
 250        git update-ref refs/remotes/six/HEAD HEAD &&
 251
 252        mkdir six &&
 253        cd six &&
 254        git init &&
 255
 256        git fetch .. six:six
 257'
 258
 259test_expect_success 'create bundle 1' '
 260        cd "$D" &&
 261        echo >file updated again by origin &&
 262        git commit -a -m "tip" &&
 263        git bundle create bundle1 master^..master
 264'
 265
 266test_expect_success 'header of bundle looks right' '
 267        head -n 1 "$D"/bundle1 | grep "^#" &&
 268        head -n 2 "$D"/bundle1 | grep "^-[0-9a-f]\{40\} " &&
 269        head -n 3 "$D"/bundle1 | grep "^[0-9a-f]\{40\} " &&
 270        head -n 4 "$D"/bundle1 | grep "^$"
 271'
 272
 273test_expect_success 'create bundle 2' '
 274        cd "$D" &&
 275        git bundle create bundle2 master~2..master
 276'
 277
 278test_expect_success 'unbundle 1' '
 279        cd "$D/bundle" &&
 280        git checkout -b some-branch &&
 281        test_must_fail git fetch "$D/bundle1" master:master
 282'
 283
 284
 285test_expect_success 'bundle 1 has only 3 files ' '
 286        cd "$D" &&
 287        convert_bundle_to_pack <bundle1 >bundle.pack &&
 288        git index-pack bundle.pack &&
 289        test_bundle_object_count bundle.pack 3
 290'
 291
 292test_expect_success 'unbundle 2' '
 293        cd "$D/bundle" &&
 294        git fetch ../bundle2 master:master &&
 295        test "tip" = "$(git log -1 --pretty=oneline master | cut -b42-)"
 296'
 297
 298test_expect_success 'bundle does not prerequisite objects' '
 299        cd "$D" &&
 300        touch file2 &&
 301        git add file2 &&
 302        git commit -m add.file2 file2 &&
 303        git bundle create bundle3 -1 HEAD &&
 304        convert_bundle_to_pack <bundle3 >bundle.pack &&
 305        git index-pack bundle.pack &&
 306        test_bundle_object_count bundle.pack 3
 307'
 308
 309test_expect_success 'bundle should be able to create a full history' '
 310
 311        cd "$D" &&
 312        git tag -a -m '1.0' v1.0 master &&
 313        git bundle create bundle4 v1.0
 314
 315'
 316
 317test_expect_success 'fetch with a non-applying branch.<name>.merge' '
 318        git config branch.master.remote yeti &&
 319        git config branch.master.merge refs/heads/bigfoot &&
 320        git config remote.blub.url one &&
 321        git config remote.blub.fetch "refs/heads/*:refs/remotes/one/*" &&
 322        git fetch blub
 323'
 324
 325# URL supplied to fetch does not match the url of the configured branch's remote
 326test_expect_success 'fetch from GIT URL with a non-applying branch.<name>.merge [1]' '
 327        one_head=$(cd one && git rev-parse HEAD) &&
 328        this_head=$(git rev-parse HEAD) &&
 329        git update-ref -d FETCH_HEAD &&
 330        git fetch one &&
 331        test $one_head = "$(git rev-parse --verify FETCH_HEAD)" &&
 332        test $this_head = "$(git rev-parse --verify HEAD)"
 333'
 334
 335# URL supplied to fetch matches the url of the configured branch's remote and
 336# the merge spec matches the branch the remote HEAD points to
 337test_expect_success 'fetch from GIT URL with a non-applying branch.<name>.merge [2]' '
 338        one_ref=$(cd one && git symbolic-ref HEAD) &&
 339        git config branch.master.remote blub &&
 340        git config branch.master.merge "$one_ref" &&
 341        git update-ref -d FETCH_HEAD &&
 342        git fetch one &&
 343        test $one_head = "$(git rev-parse --verify FETCH_HEAD)" &&
 344        test $this_head = "$(git rev-parse --verify HEAD)"
 345'
 346
 347# URL supplied to fetch matches the url of the configured branch's remote, but
 348# the merge spec does not match the branch the remote HEAD points to
 349test_expect_success 'fetch from GIT URL with a non-applying branch.<name>.merge [3]' '
 350        git config branch.master.merge "${one_ref}_not" &&
 351        git update-ref -d FETCH_HEAD &&
 352        git fetch one &&
 353        test $one_head = "$(git rev-parse --verify FETCH_HEAD)" &&
 354        test $this_head = "$(git rev-parse --verify HEAD)"
 355'
 356
 357# the strange name is: a\!'b
 358test_expect_success 'quoting of a strangely named repo' '
 359        test_must_fail git fetch "a\\!'\''b" > result 2>&1 &&
 360        cat result &&
 361        grep "fatal: '\''a\\\\!'\''b'\''" result
 362'
 363
 364test_expect_success 'bundle should record HEAD correctly' '
 365
 366        cd "$D" &&
 367        git bundle create bundle5 HEAD master &&
 368        git bundle list-heads bundle5 >actual &&
 369        for h in HEAD refs/heads/master
 370        do
 371                echo "$(git rev-parse --verify $h) $h"
 372        done >expect &&
 373        test_cmp expect actual
 374
 375'
 376
 377test_expect_success 'mark initial state of origin/master' '
 378        (
 379                cd three &&
 380                git tag base-origin-master refs/remotes/origin/master
 381        )
 382'
 383
 384test_expect_success 'explicit fetch should update tracking' '
 385
 386        cd "$D" &&
 387        git branch -f side &&
 388        (
 389                cd three &&
 390                git update-ref refs/remotes/origin/master base-origin-master &&
 391                o=$(git rev-parse --verify refs/remotes/origin/master) &&
 392                git fetch origin master &&
 393                n=$(git rev-parse --verify refs/remotes/origin/master) &&
 394                test "$o" != "$n" &&
 395                test_must_fail git rev-parse --verify refs/remotes/origin/side
 396        )
 397'
 398
 399test_expect_success 'explicit pull should update tracking' '
 400
 401        cd "$D" &&
 402        git branch -f side &&
 403        (
 404                cd three &&
 405                git update-ref refs/remotes/origin/master base-origin-master &&
 406                o=$(git rev-parse --verify refs/remotes/origin/master) &&
 407                git pull origin master &&
 408                n=$(git rev-parse --verify refs/remotes/origin/master) &&
 409                test "$o" != "$n" &&
 410                test_must_fail git rev-parse --verify refs/remotes/origin/side
 411        )
 412'
 413
 414test_expect_success 'explicit --refmap is allowed only with command-line refspec' '
 415        cd "$D" &&
 416        (
 417                cd three &&
 418                test_must_fail git fetch --refmap="*:refs/remotes/none/*"
 419        )
 420'
 421
 422test_expect_success 'explicit --refmap option overrides remote.*.fetch' '
 423        cd "$D" &&
 424        git branch -f side &&
 425        (
 426                cd three &&
 427                git update-ref refs/remotes/origin/master base-origin-master &&
 428                o=$(git rev-parse --verify refs/remotes/origin/master) &&
 429                git fetch --refmap="refs/heads/*:refs/remotes/other/*" origin master &&
 430                n=$(git rev-parse --verify refs/remotes/origin/master) &&
 431                test "$o" = "$n" &&
 432                test_must_fail git rev-parse --verify refs/remotes/origin/side &&
 433                git rev-parse --verify refs/remotes/other/master
 434        )
 435'
 436
 437test_expect_success 'explicitly empty --refmap option disables remote.*.fetch' '
 438        cd "$D" &&
 439        git branch -f side &&
 440        (
 441                cd three &&
 442                git update-ref refs/remotes/origin/master base-origin-master &&
 443                o=$(git rev-parse --verify refs/remotes/origin/master) &&
 444                git fetch --refmap="" origin master &&
 445                n=$(git rev-parse --verify refs/remotes/origin/master) &&
 446                test "$o" = "$n" &&
 447                test_must_fail git rev-parse --verify refs/remotes/origin/side
 448        )
 449'
 450
 451test_expect_success 'configured fetch updates tracking' '
 452
 453        cd "$D" &&
 454        git branch -f side &&
 455        (
 456                cd three &&
 457                git update-ref refs/remotes/origin/master base-origin-master &&
 458                o=$(git rev-parse --verify refs/remotes/origin/master) &&
 459                git fetch origin &&
 460                n=$(git rev-parse --verify refs/remotes/origin/master) &&
 461                test "$o" != "$n" &&
 462                git rev-parse --verify refs/remotes/origin/side
 463        )
 464'
 465
 466test_expect_success 'non-matching refspecs do not confuse tracking update' '
 467        cd "$D" &&
 468        git update-ref refs/odd/location HEAD &&
 469        (
 470                cd three &&
 471                git update-ref refs/remotes/origin/master base-origin-master &&
 472                git config --add remote.origin.fetch \
 473                        refs/odd/location:refs/remotes/origin/odd &&
 474                o=$(git rev-parse --verify refs/remotes/origin/master) &&
 475                git fetch origin master &&
 476                n=$(git rev-parse --verify refs/remotes/origin/master) &&
 477                test "$o" != "$n" &&
 478                test_must_fail git rev-parse --verify refs/remotes/origin/odd
 479        )
 480'
 481
 482test_expect_success 'pushing nonexistent branch by mistake should not segv' '
 483
 484        cd "$D" &&
 485        test_must_fail git push seven no:no
 486
 487'
 488
 489test_expect_success 'auto tag following fetches minimum' '
 490
 491        cd "$D" &&
 492        git clone .git follow &&
 493        git checkout HEAD^0 &&
 494        (
 495                for i in 1 2 3 4 5 6 7
 496                do
 497                        echo $i >>file &&
 498                        git commit -m $i -a &&
 499                        git tag -a -m $i excess-$i || exit 1
 500                done
 501        ) &&
 502        git checkout master &&
 503        (
 504                cd follow &&
 505                git fetch
 506        )
 507'
 508
 509test_expect_success 'refuse to fetch into the current branch' '
 510
 511        test_must_fail git fetch . side:master
 512
 513'
 514
 515test_expect_success 'fetch into the current branch with --update-head-ok' '
 516
 517        git fetch --update-head-ok . side:master
 518
 519'
 520
 521test_expect_success 'fetch --dry-run' '
 522
 523        rm -f .git/FETCH_HEAD &&
 524        git fetch --dry-run . &&
 525        ! test -f .git/FETCH_HEAD
 526'
 527
 528test_expect_success "should be able to fetch with duplicate refspecs" '
 529        mkdir dups &&
 530        (
 531                cd dups &&
 532                git init &&
 533                git config branch.master.remote three &&
 534                git config remote.three.url ../three/.git &&
 535                git config remote.three.fetch +refs/heads/*:refs/remotes/origin/* &&
 536                git config --add remote.three.fetch +refs/heads/*:refs/remotes/origin/* &&
 537                git fetch three
 538        )
 539'
 540
 541# configured prune tests
 542
 543set_config_tristate () {
 544        # var=$1 val=$2
 545        case "$2" in
 546        unset)
 547                test_unconfig "$1"
 548                ;;
 549        *)
 550                git config "$1" "$2"
 551                key=$(echo $1 | sed -e 's/^remote\.origin/fetch/')
 552                git_fetch_c="$git_fetch_c -c $key=$2"
 553                ;;
 554        esac
 555}
 556
 557test_configured_prune () {
 558        test_configured_prune_type "$@" "name"
 559        test_configured_prune_type "$@" "link"
 560}
 561
 562test_configured_prune_type () {
 563        fetch_prune=$1
 564        remote_origin_prune=$2
 565        fetch_prune_tags=$3
 566        remote_origin_prune_tags=$4
 567        expected_branch=$5
 568        expected_tag=$6
 569        cmdline=$7
 570        mode=$8
 571
 572        if test -z "$cmdline_setup"
 573        then
 574                test_expect_success 'setup cmdline_setup variable for subsequent test' '
 575                        remote_url="file://$(git -C one config remote.origin.url)" &&
 576                        remote_fetch="$(git -C one config remote.origin.fetch)" &&
 577                        cmdline_setup="\"$remote_url\" \"$remote_fetch\""
 578                '
 579        fi
 580
 581        if test "$mode" = 'link'
 582        then
 583                new_cmdline=""
 584
 585                if test "$cmdline" = ""
 586                then
 587                        new_cmdline=$cmdline_setup
 588                else
 589                        new_cmdline=$(printf "%s" "$cmdline" | perl -pe 's[origin(?!/)]["'"$remote_url"'"]g')
 590                fi
 591
 592                if test "$fetch_prune_tags" = 'true' ||
 593                   test "$remote_origin_prune_tags" = 'true'
 594                then
 595                        if ! printf '%s' "$cmdline\n" | grep -q refs/remotes/origin/
 596                        then
 597                                new_cmdline="$new_cmdline refs/tags/*:refs/tags/*"
 598                        fi
 599                fi
 600
 601                cmdline="$new_cmdline"
 602        fi
 603
 604        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" '
 605                # make sure a newbranch is there in . and also in one
 606                git branch -f newbranch &&
 607                git tag -f newtag &&
 608                (
 609                        cd one &&
 610                        test_unconfig fetch.prune &&
 611                        test_unconfig fetch.pruneTags &&
 612                        test_unconfig remote.origin.prune &&
 613                        test_unconfig remote.origin.pruneTags &&
 614                        git fetch '"$cmdline_setup"' &&
 615                        git rev-parse --verify refs/remotes/origin/newbranch &&
 616                        git rev-parse --verify refs/tags/newtag
 617                ) &&
 618
 619                # now remove it
 620                git branch -d newbranch &&
 621                git tag -d newtag &&
 622
 623                # then test
 624                (
 625                        cd one &&
 626                        git_fetch_c="" &&
 627                        set_config_tristate fetch.prune $fetch_prune &&
 628                        set_config_tristate fetch.pruneTags $fetch_prune_tags &&
 629                        set_config_tristate remote.origin.prune $remote_origin_prune &&
 630                        set_config_tristate remote.origin.pruneTags $remote_origin_prune_tags &&
 631
 632                        if test "$mode" != "link"
 633                        then
 634                                git_fetch_c=""
 635                        fi &&
 636                        git$git_fetch_c fetch '"$cmdline"' &&
 637                        case "$expected_branch" in
 638                        pruned)
 639                                test_must_fail git rev-parse --verify refs/remotes/origin/newbranch
 640                                ;;
 641                        kept)
 642                                git rev-parse --verify refs/remotes/origin/newbranch
 643                                ;;
 644                        esac &&
 645                        case "$expected_tag" in
 646                        pruned)
 647                                test_must_fail git rev-parse --verify refs/tags/newtag
 648                                ;;
 649                        kept)
 650                                git rev-parse --verify refs/tags/newtag
 651                                ;;
 652                        esac
 653                )
 654        '
 655}
 656
 657# $1 config: fetch.prune
 658# $2 config: remote.<name>.prune
 659# $3 config: fetch.pruneTags
 660# $4 config: remote.<name>.pruneTags
 661# $5 expect: branch to be pruned?
 662# $6 expect: tag to be pruned?
 663# $7 git-fetch $cmdline:
 664#
 665#                     $1    $2    $3    $4    $5     $6     $7
 666test_configured_prune unset unset unset unset kept   kept   ""
 667test_configured_prune unset unset unset unset kept   kept   "--no-prune"
 668test_configured_prune unset unset unset unset pruned kept   "--prune"
 669test_configured_prune unset unset unset unset kept   pruned \
 670        "--prune origin refs/tags/*:refs/tags/*"
 671test_configured_prune unset unset unset unset pruned pruned \
 672        "--prune origin refs/tags/*:refs/tags/* +refs/heads/*:refs/remotes/origin/*"
 673
 674test_configured_prune false unset unset unset kept   kept   ""
 675test_configured_prune false unset unset unset kept   kept   "--no-prune"
 676test_configured_prune false unset unset unset pruned kept   "--prune"
 677
 678test_configured_prune true  unset unset unset pruned kept   ""
 679test_configured_prune true  unset unset unset pruned kept   "--prune"
 680test_configured_prune true  unset unset unset kept   kept   "--no-prune"
 681
 682test_configured_prune unset false unset unset kept   kept   ""
 683test_configured_prune unset false unset unset kept   kept   "--no-prune"
 684test_configured_prune unset false unset unset pruned kept   "--prune"
 685
 686test_configured_prune false false unset unset kept   kept   ""
 687test_configured_prune false false unset unset kept   kept   "--no-prune"
 688test_configured_prune false false unset unset pruned kept   "--prune"
 689test_configured_prune false false unset unset kept   pruned \
 690        "--prune origin refs/tags/*:refs/tags/*"
 691test_configured_prune false false unset unset pruned pruned \
 692        "--prune origin refs/tags/*:refs/tags/* +refs/heads/*:refs/remotes/origin/*"
 693
 694test_configured_prune true  false unset unset kept   kept   ""
 695test_configured_prune true  false unset unset pruned kept   "--prune"
 696test_configured_prune true  false unset unset kept   kept   "--no-prune"
 697
 698test_configured_prune unset true  unset unset pruned kept   ""
 699test_configured_prune unset true  unset unset kept   kept   "--no-prune"
 700test_configured_prune unset true  unset unset pruned kept   "--prune"
 701
 702test_configured_prune false true  unset unset pruned kept   ""
 703test_configured_prune false true  unset unset kept   kept   "--no-prune"
 704test_configured_prune false true  unset unset pruned kept   "--prune"
 705
 706test_configured_prune true  true  unset unset pruned kept   ""
 707test_configured_prune true  true  unset unset pruned kept   "--prune"
 708test_configured_prune true  true  unset unset kept   kept   "--no-prune"
 709test_configured_prune true  true  unset unset kept   pruned \
 710        "--prune origin refs/tags/*:refs/tags/*"
 711test_configured_prune true  true  unset unset pruned pruned \
 712        "--prune origin refs/tags/*:refs/tags/* +refs/heads/*:refs/remotes/origin/*"
 713
 714# --prune-tags on its own does nothing, needs --prune as well, same
 715# for for fetch.pruneTags without fetch.prune
 716test_configured_prune unset unset unset unset kept kept     "--prune-tags"
 717test_configured_prune unset unset true unset  kept kept     ""
 718test_configured_prune unset unset unset true  kept kept     ""
 719
 720# These will prune the tags
 721test_configured_prune unset unset unset unset pruned pruned "--prune --prune-tags"
 722test_configured_prune true  unset true  unset pruned pruned ""
 723test_configured_prune unset true  unset true  pruned pruned ""
 724
 725# remote.<name>.pruneTags overrides fetch.pruneTags, just like
 726# remote.<name>.prune overrides fetch.prune if set.
 727test_configured_prune true  unset true unset pruned pruned  ""
 728test_configured_prune false true  false true  pruned pruned ""
 729test_configured_prune true  false true  false kept   kept   ""
 730
 731# When --prune-tags is supplied it's ignored if an explicit refspec is
 732# given, same for the configuration options.
 733test_configured_prune unset unset unset unset pruned kept \
 734        "--prune --prune-tags origin +refs/heads/*:refs/remotes/origin/*"
 735test_configured_prune unset unset true  unset pruned kept \
 736        "--prune origin +refs/heads/*:refs/remotes/origin/*"
 737test_configured_prune unset unset unset true pruned  kept \
 738        "--prune origin +refs/heads/*:refs/remotes/origin/*"
 739
 740# Pruning that also takes place if a file:// url replaces a named
 741# remote, with the exception of --prune-tags on the command-line
 742# (arbitrary limitation).
 743#
 744# However, because there's no implicit
 745# +refs/heads/*:refs/remotes/origin/* refspec and supplying it on the
 746# command-line negates --prune-tags, the branches will not be pruned.
 747test_configured_prune_type unset unset unset unset kept   kept   "origin --prune-tags" "name"
 748test_configured_prune_type unset unset unset unset kept   kept   "origin --prune-tags" "link"
 749test_configured_prune_type unset unset unset unset pruned pruned "origin --prune --prune-tags" "name"
 750test_configured_prune_type unset unset unset unset kept   kept   "origin --prune --prune-tags" "link"
 751test_configured_prune_type unset unset unset unset pruned pruned "--prune --prune-tags origin" "name"
 752test_configured_prune_type unset unset unset unset kept   kept   "--prune --prune-tags origin" "link"
 753test_configured_prune_type unset unset true  unset pruned pruned "--prune origin" "name"
 754test_configured_prune_type unset unset true  unset kept   pruned "--prune origin" "link"
 755test_configured_prune_type unset unset unset true  pruned pruned "--prune origin" "name"
 756test_configured_prune_type unset unset unset true  kept   pruned "--prune origin" "link"
 757test_configured_prune_type true  unset true  unset pruned pruned "origin" "name"
 758test_configured_prune_type true  unset true  unset kept   pruned "origin" "link"
 759test_configured_prune_type unset  true true  unset pruned pruned "origin" "name"
 760test_configured_prune_type unset  true true  unset kept   pruned "origin" "link"
 761test_configured_prune_type unset  true unset true  pruned pruned "origin" "name"
 762test_configured_prune_type unset  true unset true  kept   pruned "origin" "link"
 763
 764# Interaction between --prune-tags and no "fetch" config in the remote
 765# at all.
 766test_expect_success 'remove remote.origin.fetch "one"' '
 767        (
 768                cd one &&
 769                git config --unset-all remote.origin.fetch
 770        )
 771'
 772test_configured_prune_type unset unset unset unset kept pruned "origin --prune --prune-tags" "name"
 773test_configured_prune_type unset unset unset unset kept kept   "origin --prune --prune-tags" "link"
 774
 775test_expect_success 'all boundary commits are excluded' '
 776        test_commit base &&
 777        test_commit oneside &&
 778        git checkout HEAD^ &&
 779        test_commit otherside &&
 780        git checkout master &&
 781        test_tick &&
 782        git merge otherside &&
 783        ad=$(git log --no-walk --format=%ad HEAD) &&
 784        git bundle create twoside-boundary.bdl master --since="$ad" &&
 785        convert_bundle_to_pack <twoside-boundary.bdl >twoside-boundary.pack &&
 786        pack=$(git index-pack --fix-thin --stdin <twoside-boundary.pack) &&
 787        test_bundle_object_count .git/objects/pack/pack-${pack##pack    }.pack 3
 788'
 789
 790test_expect_success 'fetch --prune prints the remotes url' '
 791        git branch goodbye &&
 792        git clone . only-prunes &&
 793        git branch -D goodbye &&
 794        (
 795                cd only-prunes &&
 796                git fetch --prune origin 2>&1 | head -n1 >../actual
 797        ) &&
 798        echo "From ${D}/." >expect &&
 799        test_i18ncmp expect actual
 800'
 801
 802test_expect_success 'branchname D/F conflict resolved by --prune' '
 803        git branch dir/file &&
 804        git clone . prune-df-conflict &&
 805        git branch -D dir/file &&
 806        git branch dir &&
 807        (
 808                cd prune-df-conflict &&
 809                git fetch --prune &&
 810                git rev-parse origin/dir >../actual
 811        ) &&
 812        git rev-parse dir >expect &&
 813        test_cmp expect actual
 814'
 815
 816test_expect_success 'fetching a one-level ref works' '
 817        test_commit extra &&
 818        git reset --hard HEAD^ &&
 819        git update-ref refs/foo extra &&
 820        git init one-level &&
 821        (
 822                cd one-level &&
 823                git fetch .. HEAD refs/foo
 824        )
 825'
 826
 827test_expect_success 'fetching with auto-gc does not lock up' '
 828        write_script askyesno <<-\EOF &&
 829        echo "$*" &&
 830        false
 831        EOF
 832        git clone "file://$D" auto-gc &&
 833        test_commit test2 &&
 834        (
 835                cd auto-gc &&
 836                git config gc.autoPackLimit 1 &&
 837                git config gc.autoDetach false &&
 838                GIT_ASK_YESNO="$D/askyesno" git fetch >fetch.out 2>&1 &&
 839                ! grep "Should I try again" fetch.out
 840        )
 841'
 842
 843test_expect_success C_LOCALE_OUTPUT 'fetch aligned output' '
 844        git clone . full-output &&
 845        test_commit looooooooooooong-tag &&
 846        (
 847                cd full-output &&
 848                git -c fetch.output=full fetch origin 2>&1 | \
 849                        grep -e "->" | cut -c 22- >../actual
 850        ) &&
 851        cat >expect <<-\EOF &&
 852        master               -> origin/master
 853        looooooooooooong-tag -> looooooooooooong-tag
 854        EOF
 855        test_cmp expect actual
 856'
 857
 858test_expect_success C_LOCALE_OUTPUT 'fetch compact output' '
 859        git clone . compact &&
 860        test_commit extraaa &&
 861        (
 862                cd compact &&
 863                git -c fetch.output=compact fetch origin 2>&1 | \
 864                        grep -e "->" | cut -c 22- >../actual
 865        ) &&
 866        cat >expect <<-\EOF &&
 867        master     -> origin/*
 868        extraaa    -> *
 869        EOF
 870        test_cmp expect actual
 871'
 872
 873test_done