t / t5510-fetch.shon commit index-pack: work around thread-unsafe pread() (3953949)
   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 --tags prunes branches but not tags' '
 117        cd "$D" &&
 118        git clone . prune-tags &&
 119        cd prune-tags &&
 120        git tag sometag master &&
 121        # Create what looks like a remote-tracking branch from an earlier
 122        # fetch that has since been deleted from the remote:
 123        git update-ref refs/remotes/origin/fake-remote master &&
 124
 125        git fetch --prune --tags origin &&
 126        git rev-parse origin/master &&
 127        test_must_fail git rev-parse origin/fake-remote &&
 128        git rev-parse sometag
 129'
 130
 131test_expect_success 'fetch --prune --tags with branch does not prune other things' '
 132        cd "$D" &&
 133        git clone . prune-tags-branch &&
 134        cd prune-tags-branch &&
 135        git tag sometag master &&
 136        git update-ref refs/remotes/origin/extrabranch master &&
 137
 138        git fetch --prune --tags origin master &&
 139        git rev-parse origin/extrabranch &&
 140        git rev-parse sometag
 141'
 142
 143test_expect_success 'fetch --prune --tags with refspec prunes based on refspec' '
 144        cd "$D" &&
 145        git clone . prune-tags-refspec &&
 146        cd prune-tags-refspec &&
 147        git tag sometag master &&
 148        git update-ref refs/remotes/origin/foo/otherbranch master &&
 149        git update-ref refs/remotes/origin/extrabranch master &&
 150
 151        git fetch --prune --tags origin refs/heads/foo/*:refs/remotes/origin/foo/* &&
 152        test_must_fail git rev-parse refs/remotes/origin/foo/otherbranch &&
 153        git rev-parse origin/extrabranch &&
 154        git rev-parse sometag
 155'
 156
 157test_expect_success 'fetch tags when there is no tags' '
 158
 159    cd "$D" &&
 160
 161    mkdir notags &&
 162    cd notags &&
 163    git init &&
 164
 165    git fetch -t ..
 166
 167'
 168
 169test_expect_success 'fetch following tags' '
 170
 171        cd "$D" &&
 172        git tag -a -m 'annotated' anno HEAD &&
 173        git tag light HEAD &&
 174
 175        mkdir four &&
 176        cd four &&
 177        git init &&
 178
 179        git fetch .. :track &&
 180        git show-ref --verify refs/tags/anno &&
 181        git show-ref --verify refs/tags/light
 182
 183'
 184
 185test_expect_success 'fetch uses remote ref names to describe new refs' '
 186        cd "$D" &&
 187        git init descriptive &&
 188        (
 189                cd descriptive &&
 190                git config remote.o.url .. &&
 191                git config remote.o.fetch "refs/heads/*:refs/crazyheads/*" &&
 192                git config --add remote.o.fetch "refs/others/*:refs/heads/*" &&
 193                git fetch o
 194        ) &&
 195        git tag -a -m "Descriptive tag" descriptive-tag &&
 196        git branch descriptive-branch &&
 197        git checkout descriptive-branch &&
 198        echo "Nuts" >crazy &&
 199        git add crazy &&
 200        git commit -a -m "descriptive commit" &&
 201        git update-ref refs/others/crazy HEAD &&
 202        (
 203                cd descriptive &&
 204                git fetch o 2>actual &&
 205                grep " -> refs/crazyheads/descriptive-branch$" actual |
 206                test_i18ngrep "new branch" &&
 207                grep " -> descriptive-tag$" actual |
 208                test_i18ngrep "new tag" &&
 209                grep " -> crazy$" actual |
 210                test_i18ngrep "new ref"
 211        ) &&
 212        git checkout master
 213'
 214
 215test_expect_success 'fetch must not resolve short tag name' '
 216
 217        cd "$D" &&
 218
 219        mkdir five &&
 220        cd five &&
 221        git init &&
 222
 223        test_must_fail git fetch .. anno:five
 224
 225'
 226
 227test_expect_success 'fetch can now resolve short remote name' '
 228
 229        cd "$D" &&
 230        git update-ref refs/remotes/six/HEAD HEAD &&
 231
 232        mkdir six &&
 233        cd six &&
 234        git init &&
 235
 236        git fetch .. six:six
 237'
 238
 239test_expect_success 'create bundle 1' '
 240        cd "$D" &&
 241        echo >file updated again by origin &&
 242        git commit -a -m "tip" &&
 243        git bundle create bundle1 master^..master
 244'
 245
 246test_expect_success 'header of bundle looks right' '
 247        head -n 1 "$D"/bundle1 | grep "^#" &&
 248        head -n 2 "$D"/bundle1 | grep "^-[0-9a-f]\{40\} " &&
 249        head -n 3 "$D"/bundle1 | grep "^[0-9a-f]\{40\} " &&
 250        head -n 4 "$D"/bundle1 | grep "^$"
 251'
 252
 253test_expect_success 'create bundle 2' '
 254        cd "$D" &&
 255        git bundle create bundle2 master~2..master
 256'
 257
 258test_expect_success 'unbundle 1' '
 259        cd "$D/bundle" &&
 260        git checkout -b some-branch &&
 261        test_must_fail git fetch "$D/bundle1" master:master
 262'
 263
 264
 265test_expect_success 'bundle 1 has only 3 files ' '
 266        cd "$D" &&
 267        convert_bundle_to_pack <bundle1 >bundle.pack &&
 268        git index-pack bundle.pack &&
 269        test_bundle_object_count bundle.pack 3
 270'
 271
 272test_expect_success 'unbundle 2' '
 273        cd "$D/bundle" &&
 274        git fetch ../bundle2 master:master &&
 275        test "tip" = "$(git log -1 --pretty=oneline master | cut -b42-)"
 276'
 277
 278test_expect_success 'bundle does not prerequisite objects' '
 279        cd "$D" &&
 280        touch file2 &&
 281        git add file2 &&
 282        git commit -m add.file2 file2 &&
 283        git bundle create bundle3 -1 HEAD &&
 284        convert_bundle_to_pack <bundle3 >bundle.pack &&
 285        git index-pack bundle.pack &&
 286        test_bundle_object_count bundle.pack 3
 287'
 288
 289test_expect_success 'bundle should be able to create a full history' '
 290
 291        cd "$D" &&
 292        git tag -a -m '1.0' v1.0 master &&
 293        git bundle create bundle4 v1.0
 294
 295'
 296
 297! rsync --help > /dev/null 2> /dev/null &&
 298say 'Skipping rsync tests because rsync was not found' || {
 299test_expect_success 'fetch via rsync' '
 300        git pack-refs &&
 301        mkdir rsynced &&
 302        (cd rsynced &&
 303         git init --bare &&
 304         git fetch "rsync:$(pwd)/../.git" master:refs/heads/master &&
 305         git gc --prune &&
 306         test $(git rev-parse master) = $(cd .. && git rev-parse master) &&
 307         git fsck --full)
 308'
 309
 310test_expect_success 'push via rsync' '
 311        mkdir rsynced2 &&
 312        (cd rsynced2 &&
 313         git init) &&
 314        (cd rsynced &&
 315         git push "rsync:$(pwd)/../rsynced2/.git" master) &&
 316        (cd rsynced2 &&
 317         git gc --prune &&
 318         test $(git rev-parse master) = $(cd .. && git rev-parse master) &&
 319         git fsck --full)
 320'
 321
 322test_expect_success 'push via rsync' '
 323        mkdir rsynced3 &&
 324        (cd rsynced3 &&
 325         git init) &&
 326        git push --all "rsync:$(pwd)/rsynced3/.git" &&
 327        (cd rsynced3 &&
 328         test $(git rev-parse master) = $(cd .. && git rev-parse master) &&
 329         git fsck --full)
 330'
 331}
 332
 333test_expect_success 'fetch with a non-applying branch.<name>.merge' '
 334        git config branch.master.remote yeti &&
 335        git config branch.master.merge refs/heads/bigfoot &&
 336        git config remote.blub.url one &&
 337        git config remote.blub.fetch "refs/heads/*:refs/remotes/one/*" &&
 338        git fetch blub
 339'
 340
 341# URL supplied to fetch does not match the url of the configured branch's remote
 342test_expect_success 'fetch from GIT URL with a non-applying branch.<name>.merge [1]' '
 343        one_head=$(cd one && git rev-parse HEAD) &&
 344        this_head=$(git rev-parse HEAD) &&
 345        git update-ref -d FETCH_HEAD &&
 346        git fetch one &&
 347        test $one_head = "$(git rev-parse --verify FETCH_HEAD)" &&
 348        test $this_head = "$(git rev-parse --verify HEAD)"
 349'
 350
 351# URL supplied to fetch matches the url of the configured branch's remote and
 352# the merge spec matches the branch the remote HEAD points to
 353test_expect_success 'fetch from GIT URL with a non-applying branch.<name>.merge [2]' '
 354        one_ref=$(cd one && git symbolic-ref HEAD) &&
 355        git config branch.master.remote blub &&
 356        git config branch.master.merge "$one_ref" &&
 357        git update-ref -d FETCH_HEAD &&
 358        git fetch one &&
 359        test $one_head = "$(git rev-parse --verify FETCH_HEAD)" &&
 360        test $this_head = "$(git rev-parse --verify HEAD)"
 361'
 362
 363# URL supplied to fetch matches the url of the configured branch's remote, but
 364# the merge spec does not match the branch the remote HEAD points to
 365test_expect_success 'fetch from GIT URL with a non-applying branch.<name>.merge [3]' '
 366        git config branch.master.merge "${one_ref}_not" &&
 367        git update-ref -d FETCH_HEAD &&
 368        git fetch one &&
 369        test $one_head = "$(git rev-parse --verify FETCH_HEAD)" &&
 370        test $this_head = "$(git rev-parse --verify HEAD)"
 371'
 372
 373# the strange name is: a\!'b
 374test_expect_success 'quoting of a strangely named repo' '
 375        test_must_fail git fetch "a\\!'\''b" > result 2>&1 &&
 376        cat result &&
 377        grep "fatal: '\''a\\\\!'\''b'\''" result
 378'
 379
 380test_expect_success 'bundle should record HEAD correctly' '
 381
 382        cd "$D" &&
 383        git bundle create bundle5 HEAD master &&
 384        git bundle list-heads bundle5 >actual &&
 385        for h in HEAD refs/heads/master
 386        do
 387                echo "$(git rev-parse --verify $h) $h"
 388        done >expect &&
 389        test_cmp expect actual
 390
 391'
 392
 393test_expect_success 'mark initial state of origin/master' '
 394        (
 395                cd three &&
 396                git tag base-origin-master refs/remotes/origin/master
 397        )
 398'
 399
 400test_expect_success 'explicit fetch should update tracking' '
 401
 402        cd "$D" &&
 403        git branch -f side &&
 404        (
 405                cd three &&
 406                git update-ref refs/remotes/origin/master base-origin-master &&
 407                o=$(git rev-parse --verify refs/remotes/origin/master) &&
 408                git fetch origin master &&
 409                n=$(git rev-parse --verify refs/remotes/origin/master) &&
 410                test "$o" != "$n" &&
 411                test_must_fail git rev-parse --verify refs/remotes/origin/side
 412        )
 413'
 414
 415test_expect_success 'explicit pull should update tracking' '
 416
 417        cd "$D" &&
 418        git branch -f side &&
 419        (
 420                cd three &&
 421                git update-ref refs/remotes/origin/master base-origin-master &&
 422                o=$(git rev-parse --verify refs/remotes/origin/master) &&
 423                git pull origin master &&
 424                n=$(git rev-parse --verify refs/remotes/origin/master) &&
 425                test "$o" != "$n" &&
 426                test_must_fail git rev-parse --verify refs/remotes/origin/side
 427        )
 428'
 429
 430test_expect_success 'configured fetch updates tracking' '
 431
 432        cd "$D" &&
 433        git branch -f side &&
 434        (
 435                cd three &&
 436                git update-ref refs/remotes/origin/master base-origin-master &&
 437                o=$(git rev-parse --verify refs/remotes/origin/master) &&
 438                git fetch origin &&
 439                n=$(git rev-parse --verify refs/remotes/origin/master) &&
 440                test "$o" != "$n" &&
 441                git rev-parse --verify refs/remotes/origin/side
 442        )
 443'
 444
 445test_expect_success 'non-matching refspecs do not confuse tracking update' '
 446        cd "$D" &&
 447        git update-ref refs/odd/location HEAD &&
 448        (
 449                cd three &&
 450                git update-ref refs/remotes/origin/master base-origin-master &&
 451                git config --add remote.origin.fetch \
 452                        refs/odd/location:refs/remotes/origin/odd &&
 453                o=$(git rev-parse --verify refs/remotes/origin/master) &&
 454                git fetch origin master &&
 455                n=$(git rev-parse --verify refs/remotes/origin/master) &&
 456                test "$o" != "$n" &&
 457                test_must_fail git rev-parse --verify refs/remotes/origin/odd
 458        )
 459'
 460
 461test_expect_success 'pushing nonexistent branch by mistake should not segv' '
 462
 463        cd "$D" &&
 464        test_must_fail git push seven no:no
 465
 466'
 467
 468test_expect_success 'auto tag following fetches minimum' '
 469
 470        cd "$D" &&
 471        git clone .git follow &&
 472        git checkout HEAD^0 &&
 473        (
 474                for i in 1 2 3 4 5 6 7
 475                do
 476                        echo $i >>file &&
 477                        git commit -m $i -a &&
 478                        git tag -a -m $i excess-$i || exit 1
 479                done
 480        ) &&
 481        git checkout master &&
 482        (
 483                cd follow &&
 484                git fetch
 485        )
 486'
 487
 488test_expect_success 'refuse to fetch into the current branch' '
 489
 490        test_must_fail git fetch . side:master
 491
 492'
 493
 494test_expect_success 'fetch into the current branch with --update-head-ok' '
 495
 496        git fetch --update-head-ok . side:master
 497
 498'
 499
 500test_expect_success 'fetch --dry-run' '
 501
 502        rm -f .git/FETCH_HEAD &&
 503        git fetch --dry-run . &&
 504        ! test -f .git/FETCH_HEAD
 505'
 506
 507test_expect_success "should be able to fetch with duplicate refspecs" '
 508        mkdir dups &&
 509        (
 510                cd dups &&
 511                git init &&
 512                git config branch.master.remote three &&
 513                git config remote.three.url ../three/.git &&
 514                git config remote.three.fetch +refs/heads/*:refs/remotes/origin/* &&
 515                git config --add remote.three.fetch +refs/heads/*:refs/remotes/origin/* &&
 516                git fetch three
 517        )
 518'
 519
 520# configured prune tests
 521
 522set_config_tristate () {
 523        # var=$1 val=$2
 524        case "$2" in
 525        unset)  test_unconfig "$1" ;;
 526        *)      git config "$1" "$2" ;;
 527        esac
 528}
 529
 530test_configured_prune () {
 531        fetch_prune=$1 remote_origin_prune=$2 cmdline=$3 expected=$4
 532
 533        test_expect_success "prune fetch.prune=$1 remote.origin.prune=$2${3:+ $3}; $4" '
 534                # make sure a newbranch is there in . and also in one
 535                git branch -f newbranch &&
 536                (
 537                        cd one &&
 538                        test_unconfig fetch.prune &&
 539                        test_unconfig remote.origin.prune &&
 540                        git fetch &&
 541                        git rev-parse --verify refs/remotes/origin/newbranch
 542                )
 543
 544                # now remove it
 545                git branch -d newbranch &&
 546
 547                # then test
 548                (
 549                        cd one &&
 550                        set_config_tristate fetch.prune $fetch_prune &&
 551                        set_config_tristate remote.origin.prune $remote_origin_prune &&
 552
 553                        git fetch $cmdline &&
 554                        case "$expected" in
 555                        pruned)
 556                                test_must_fail git rev-parse --verify refs/remotes/origin/newbranch
 557                                ;;
 558                        kept)
 559                                git rev-parse --verify refs/remotes/origin/newbranch
 560                                ;;
 561                        esac
 562                )
 563        '
 564}
 565
 566test_configured_prune unset unset ""            kept
 567test_configured_prune unset unset "--no-prune"  kept
 568test_configured_prune unset unset "--prune"     pruned
 569
 570test_configured_prune false unset ""            kept
 571test_configured_prune false unset "--no-prune"  kept
 572test_configured_prune false unset "--prune"     pruned
 573
 574test_configured_prune true  unset ""            pruned
 575test_configured_prune true  unset "--prune"     pruned
 576test_configured_prune true  unset "--no-prune"  kept
 577
 578test_configured_prune unset false ""            kept
 579test_configured_prune unset false "--no-prune"  kept
 580test_configured_prune unset false "--prune"     pruned
 581
 582test_configured_prune false false ""            kept
 583test_configured_prune false false "--no-prune"  kept
 584test_configured_prune false false "--prune"     pruned
 585
 586test_configured_prune true  false ""            kept
 587test_configured_prune true  false "--prune"     pruned
 588test_configured_prune true  false "--no-prune"  kept
 589
 590test_configured_prune unset true  ""            pruned
 591test_configured_prune unset true  "--no-prune"  kept
 592test_configured_prune unset true  "--prune"     pruned
 593
 594test_configured_prune false true  ""            pruned
 595test_configured_prune false true  "--no-prune"  kept
 596test_configured_prune false true  "--prune"     pruned
 597
 598test_configured_prune true  true  ""            pruned
 599test_configured_prune true  true  "--prune"     pruned
 600test_configured_prune true  true  "--no-prune"  kept
 601
 602test_expect_success 'all boundary commits are excluded' '
 603        test_commit base &&
 604        test_commit oneside &&
 605        git checkout HEAD^ &&
 606        test_commit otherside &&
 607        git checkout master &&
 608        test_tick &&
 609        git merge otherside &&
 610        ad=$(git log --no-walk --format=%ad HEAD) &&
 611        git bundle create twoside-boundary.bdl master --since="$ad" &&
 612        convert_bundle_to_pack <twoside-boundary.bdl >twoside-boundary.pack &&
 613        pack=$(git index-pack --fix-thin --stdin <twoside-boundary.pack) &&
 614        test_bundle_object_count .git/objects/pack/pack-${pack##pack    }.pack 3
 615'
 616
 617test_expect_success 'fetch --prune prints the remotes url' '
 618        git branch goodbye &&
 619        git clone . only-prunes &&
 620        git branch -D goodbye &&
 621        (
 622                cd only-prunes &&
 623                git fetch --prune origin 2>&1 | head -n1 >../actual
 624        ) &&
 625        echo "From ${D}/." >expect &&
 626        test_cmp expect actual
 627'
 628
 629test_expect_success 'branchname D/F conflict resolved by --prune' '
 630        git branch dir/file &&
 631        git clone . prune-df-conflict &&
 632        git branch -D dir/file &&
 633        git branch dir &&
 634        (
 635                cd prune-df-conflict &&
 636                git fetch --prune &&
 637                git rev-parse origin/dir >../actual
 638        ) &&
 639        git rev-parse dir >expect &&
 640        test_cmp expect actual
 641'
 642
 643test_expect_success 'fetching a one-level ref works' '
 644        test_commit extra &&
 645        git reset --hard HEAD^ &&
 646        git update-ref refs/foo extra &&
 647        git init one-level &&
 648        (
 649                cd one-level &&
 650                git fetch .. HEAD refs/foo
 651        )
 652'
 653
 654test_done