Merge branch 'np/maint-1.6.3-deepen'
authorJunio C Hamano <gitster@pobox.com>
Sat, 29 Aug 2009 02:38:56 +0000 (19:38 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 29 Aug 2009 02:38:56 +0000 (19:38 -0700)
* np/maint-1.6.3-deepen:
fix simple deepening of a repo

Conflicts:
t/t5500-fetch-pack.sh

1  2 
t/t5500-fetch-pack.sh
transport.c
diff --combined t/t5500-fetch-pack.sh
index a8c2ca2a78dd54f69230cb443eff1d6e82336f0a,ea5a4ed3b230e259bcf81bb6c6e5f2370fa14205..18376d66081759c6a4959a2d8bc47ca441364660
@@@ -3,8 -3,9 +3,8 @@@
  # Copyright (c) 2005 Johannes Schindelin
  #
  
 -test_description='Testing multi_ack pack fetching
 +test_description='Testing multi_ack pack fetching'
  
 -'
  . ./test-lib.sh
  
  # Test fetch-pack/upload-pack pair.
  # Some convenience functions
  
  add () {
 -      name=$1
 -      text="$@"
 -      branch=`echo $name | sed -e 's/^\(.\).*$/\1/'`
 -      parents=""
 +      name=$1 &&
 +      text="$@" &&
 +      branch=`echo $name | sed -e 's/^\(.\).*$/\1/'` &&
 +      parents="" &&
  
 -      shift
 +      shift &&
        while test $1; do
 -              parents="$parents -p $1"
 +              parents="$parents -p $1" &&
                shift
 -      done
 +      done &&
  
 -      echo "$text" > test.txt
 -      git update-index --add test.txt
 -      tree=$(git write-tree)
 +      echo "$text" > test.txt &&
 +      git update-index --add test.txt &&
 +      tree=$(git write-tree) &&
        # make sure timestamps are in correct order
 -      sec=$(($sec+1))
 -      commit=$(echo "$text" | GIT_AUTHOR_DATE=$sec \
 -              git commit-tree $tree $parents 2>>log2.txt)
 -      eval "$name=$commit; export $name"
 -      echo $commit > .git/refs/heads/$branch
 +      test_tick &&
 +      commit=$(echo "$text" | git commit-tree $tree $parents) &&
 +      eval "$name=$commit; export $name" &&
 +      echo $commit > .git/refs/heads/$branch &&
        eval ${branch}TIP=$commit
  }
  
 -count_objects () {
 -      ls .git/objects/??/* 2>>log2.txt | wc -l | tr -d " "
 -}
 -
 -test_expect_object_count () {
 -      message=$1
 -      count=$2
 -
 -      output="$(count_objects)"
 -      test_expect_success \
 -              "new object count $message" \
 -              "test $count = $output"
 -}
 -
  pull_to_client () {
 -      number=$1
 -      heads=$2
 -      count=$3
 -      no_strict_count_check=$4
 -
 -      cd client
 -      test_expect_success "$number pull" \
 -              "git fetch-pack -k -v .. $heads"
 -      case "$heads" in *A*) echo $ATIP > .git/refs/heads/A;; esac
 -      case "$heads" in *B*) echo $BTIP > .git/refs/heads/B;; esac
 -      git symbolic-ref HEAD refs/heads/`echo $heads | sed -e 's/^\(.\).*$/\1/'`
 -
 -      test_expect_success "fsck" 'git fsck --full > fsck.txt 2>&1'
 -
 -      test_expect_success 'check downloaded results' \
 -      'mv .git/objects/pack/pack-* . &&
 -       p=`ls -1 pack-*.pack` &&
 -       git unpack-objects <$p &&
 -       git fsck --full'
 -
 -      test_expect_success "new object count after $number pull" \
 -      'idx=`echo pack-*.idx` &&
 -       pack_count=`git show-index <$idx | wc -l` &&
 -       test $pack_count = $count'
 -      test -z "$pack_count" && pack_count=0
 -      if [ -z "$no_strict_count_check" ]; then
 -              test_expect_success "minimal count" "test $count = $pack_count"
 -      else
 -              test $count != $pack_count && \
 -                      echo "WARNING: $pack_count objects transmitted, only $count of which were needed"
 -      fi
 -      rm -f pack-*
 -      cd ..
 +      number=$1 &&
 +      heads=$2 &&
 +      count=$3 &&
 +      test_expect_success "$number pull" '
 +              (
 +                      cd client &&
 +                      git fetch-pack -k -v .. $heads &&
 +
 +                      case "$heads" in
 +                          *A*)
 +                                  echo $ATIP > .git/refs/heads/A;;
 +                      esac &&
 +                      case "$heads" in *B*)
 +                          echo $BTIP > .git/refs/heads/B;;
 +                      esac &&
 +                      git symbolic-ref HEAD refs/heads/`echo $heads \
 +                              | sed -e "s/^\(.\).*$/\1/"` &&
 +
 +                      git fsck --full &&
 +
 +                      mv .git/objects/pack/pack-* . &&
 +                      p=`ls -1 pack-*.pack` &&
 +                      git unpack-objects <$p &&
 +                      git fsck --full &&
 +
 +                      idx=`echo pack-*.idx` &&
 +                      pack_count=`git show-index <$idx | wc -l` &&
 +                      test $pack_count = $count &&
 +                      rm -f pack-*
 +              )
 +      '
  }
  
  # Here begins the actual testing
  
  # client pulls A20, B1. Then tracks only B. Then pulls A.
  
 -(
 +test_expect_success 'setup' '
        mkdir client &&
 -      cd client &&
 -      git init 2>> log2.txt &&
 -      git config transfer.unpacklimit 0
 -)
 -
 -add A1
 -
 -prev=1; cur=2; while [ $cur -le 10 ]; do
 -      add A$cur $(eval echo \$A$prev)
 -      prev=$cur
 -      cur=$(($cur+1))
 -done
 -
 -add B1 $A1
 -
 -echo $ATIP > .git/refs/heads/A
 -echo $BTIP > .git/refs/heads/B
 -git symbolic-ref HEAD refs/heads/B
 +      (
 +              cd client &&
 +              git init &&
 +              git config transfer.unpacklimit 0
 +      ) &&
 +      add A1 &&
 +      prev=1 &&
 +      cur=2 &&
 +      while [ $cur -le 10 ]; do
 +              add A$cur $(eval echo \$A$prev) &&
 +              prev=$cur &&
 +              cur=$(($cur+1))
 +      done &&
 +      add B1 $A1
 +      echo $ATIP > .git/refs/heads/A &&
 +      echo $BTIP > .git/refs/heads/B &&
 +      git symbolic-ref HEAD refs/heads/B
 +'
  
  pull_to_client 1st "B A" $((11*3))
  
 -add A11 $A10
 -
 -prev=1; cur=2; while [ $cur -le 65 ]; do
 -      add B$cur $(eval echo \$B$prev)
 -      prev=$cur
 -      cur=$(($cur+1))
 -done
 +test_expect_success 'post 1st pull setup' '
 +      add A11 $A10 &&
 +      prev=1 &&
 +      cur=2 &&
 +      while [ $cur -le 65 ]; do
 +              add B$cur $(eval echo \$B$prev) &&
 +              prev=$cur &&
 +              cur=$(($cur+1))
 +      done
 +'
  
  pull_to_client 2nd "B" $((64*3))
  
 -pull_to_client 3rd "A" $((1*3)) # old fails
 -
 -test_expect_success "clone shallow" 'git clone --depth 2 "file://$(pwd)/." shallow'
 +pull_to_client 3rd "A" $((1*3))
  
 -(cd shallow; git count-objects -v) > count.shallow
 -
 -test_expect_success "clone shallow object count" \
 -      "test \"in-pack: 18\" = \"$(grep in-pack count.shallow)\""
 +test_expect_success 'clone shallow' '
 +      git clone --depth 2 "file://$(pwd)/." shallow
 +'
  
 -count_output () {
 -      sed -e '/^in-pack:/d' -e '/^packs:/d' -e '/^size-pack:/d' -e '/: 0$/d' "$1"
 -}
 +test_expect_success 'clone shallow object count' '
 +      (
 +              cd shallow &&
 +              git count-objects -v
 +      ) > count.shallow &&
 +      grep "^in-pack: 18" count.shallow
 +'
  
 -test_expect_success "clone shallow object count (part 2)" '
 -      test -z "$(count_output count.shallow)"
 +test_expect_success 'clone shallow object count (part 2)' '
 +      sed -e "/^in-pack:/d" -e "/^packs:/d" -e "/^size-pack:/d" \
 +          -e "/: 0$/d" count.shallow > count_output &&
 +      ! test -s count_output
  '
  
 -test_expect_success "fsck in shallow repo" \
 -      "(cd shallow; git fsck --full)"
 +test_expect_success 'fsck in shallow repo' '
 +      (
 +              cd shallow &&
 +              git fsck --full
 +      )
 +'
  
 -add B66 $B65
 -add B67 $B66
+ test_expect_success 'simple fetch in shallow repo' '
+       (
+               cd shallow &&
+               git fetch
+       )
+ '
+ test_expect_success 'no changes expected' '
+       (
+               cd shallow &&
+               git count-objects -v
+       ) > count.shallow.2 &&
+       cmp count.shallow count.shallow.2
+ '
+ test_expect_success 'fetch same depth in shallow repo' '
+       (
+               cd shallow &&
+               git fetch --depth=2
+       )
+ '
+ test_expect_success 'no changes expected' '
+       (
+               cd shallow &&
+               git count-objects -v
+       ) > count.shallow.3 &&
+       cmp count.shallow count.shallow.3
+ '
 +test_expect_success 'add two more' '
 +      add B66 $B65 &&
 +      add B67 $B66
 +'
  
 -test_expect_success "pull in shallow repo" \
 -      "(cd shallow; git pull .. B)"
 +test_expect_success 'pull in shallow repo' '
 +      (
 +              cd shallow &&
 +              git pull .. B
 +      )
 +'
  
 -(cd shallow; git count-objects -v) > count.shallow
 -test_expect_success "clone shallow object count" \
 -      "test \"count: 6\" = \"$(grep count count.shallow)\""
 +test_expect_success 'clone shallow object count' '
 +      (
 +              cd shallow &&
 +              git count-objects -v
 +      ) > count.shallow &&
 +      grep "^count: 6" count.shallow
 +'
  
 -add B68 $B67
 -add B69 $B68
 +test_expect_success 'add two more (part 2)' '
 +      add B68 $B67 &&
 +      add B69 $B68
 +'
  
 -test_expect_success "deepening pull in shallow repo" \
 -      "(cd shallow; git pull --depth 4 .. B)"
 +test_expect_success 'deepening pull in shallow repo' '
 +      (
 +              cd shallow &&
 +              git pull --depth 4 .. B
 +      )
 +'
  
 -(cd shallow; git count-objects -v) > count.shallow
 -test_expect_success "clone shallow object count" \
 -      "test \"count: 12\" = \"$(grep count count.shallow)\""
 +test_expect_success 'clone shallow object count' '
 +      (
 +              cd shallow &&
 +              git count-objects -v
 +      ) > count.shallow &&
 +      grep "^count: 12" count.shallow
 +'
  
 -test_expect_success "deepening fetch in shallow repo" \
 -      "(cd shallow; git fetch --depth 4 .. A:A)"
 +test_expect_success 'deepening fetch in shallow repo' '
 +      (
 +              cd shallow &&
 +              git fetch --depth 4 .. A:A
 +      )
 +'
  
 -(cd shallow; git count-objects -v) > count.shallow
 -test_expect_success "clone shallow object count" \
 -      "test \"count: 18\" = \"$(grep count count.shallow)\""
 +test_expect_success 'clone shallow object count' '
 +      (
 +              cd shallow &&
 +              git count-objects -v
 +      ) > count.shallow &&
 +      grep "^count: 18" count.shallow
 +'
  
 -test_expect_success "pull in shallow repo with missing merge base" \
 -      "(cd shallow && test_must_fail git pull --depth 4 .. A)"
 +test_expect_success 'pull in shallow repo with missing merge base' '
 +      (
 +              cd shallow &&
 +              test_must_fail git pull --depth 4 .. A
 +      )
 +'
  
+ test_expect_success 'additional simple shallow deepenings' '
+       (
+               cd shallow &&
+               git fetch --depth=8 &&
+               git fetch --depth=10 &&
+               git fetch --depth=11
+       )
+ '
+ test_expect_success 'clone shallow object count' '
+       (
+               cd shallow &&
+               git count-objects -v
+       ) > count.shallow &&
+       grep "^count: 52" count.shallow
+ '
  test_done
diff --combined transport.c
index faee154c383c9726017f1995121b510f770b655e,5342f1e2ec001445f7fe1d1da23c5c1f4195d729..f7e1663d18087f708da926d0978a4a3377ae2b50
@@@ -158,7 -158,7 +158,7 @@@ static struct ref *get_refs_via_rsync(s
  
        strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX"));
        if (!mkdtemp(temp_dir.buf))
 -              die ("Could not make temporary directory");
 +              die_errno ("Could not make temporary directory");
        temp_dir_len = temp_dir.len;
  
        strbuf_addstr(&buf, rsync_url(transport->url));
@@@ -321,7 -321,7 +321,7 @@@ static int rsync_transport_push(struct 
  
        strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX"));
        if (!mkdtemp(temp_dir.buf))
 -              die ("Could not make temporary directory");
 +              die_errno ("Could not make temporary directory");
        strbuf_addch(&temp_dir, '/');
  
        if (flags & TRANSPORT_PUSH_ALL) {
@@@ -396,6 -396,7 +396,6 @@@ static int curl_transport_push(struct t
  {
        const char **argv;
        int argc;
 -      int err;
  
        if (flags & TRANSPORT_PUSH_MIRROR)
                return error("http transport does not support mirror mode");
        while (refspec_nr--)
                argv[argc++] = *refspec++;
        argv[argc] = NULL;
 -      err = run_command_v_opt(argv, RUN_GIT_CMD);
 -      switch (err) {
 -      case -ERR_RUN_COMMAND_FORK:
 -              error("unable to fork for %s", argv[0]);
 -      case -ERR_RUN_COMMAND_EXEC:
 -              error("unable to exec %s", argv[0]);
 -              break;
 -      case -ERR_RUN_COMMAND_WAITPID:
 -      case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
 -      case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
 -      case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
 -              error("%s died with strange error", argv[0]);
 -      }
 -      return !!err;
 +      return !!run_command_v_opt(argv, RUN_GIT_CMD);
  }
  
  static struct ref *get_refs_via_curl(struct transport *transport, int for_push)
        char *ref_name;
        char *refs_url;
        int i = 0;
 -
 -      struct active_request_slot *slot;
 -      struct slot_results results;
 +      int http_ret;
  
        struct ref *refs = NULL;
        struct ref *ref = NULL;
        refs_url = xmalloc(strlen(transport->url) + 11);
        sprintf(refs_url, "%s/info/refs", transport->url);
  
 -      slot = get_active_slot();
 -      slot->results = &results;
 -      curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
 -      curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
 -      curl_easy_setopt(slot->curl, CURLOPT_URL, refs_url);
 -      curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
 -
 -      if (start_active_slot(slot)) {
 -              run_active_slot(slot);
 -              if (results.curl_result != CURLE_OK) {
 -                      strbuf_release(&buffer);
 -                      if (missing_target(&results))
 -                              die("%s not found: did you run git update-server-info on the server?", refs_url);
 -                      else
 -                              die("%s download error - %s", refs_url, curl_errorstr);
 -              }
 -      } else {
 -              strbuf_release(&buffer);
 -              die("Unable to start HTTP request");
 +      http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
 +      switch (http_ret) {
 +      case HTTP_OK:
 +              break;
 +      case HTTP_MISSING_TARGET:
 +              die("%s not found: did you run git update-server-info on the"
 +                  " server?", refs_url);
 +      default:
 +              http_error(refs_url, http_ret);
 +              die("HTTP request failed");
        }
  
        data = buffer.buf;
                free(ref);
        }
  
 +      strbuf_release(&buffer);
 +      free(refs_url);
        return refs;
  }
  
@@@ -667,21 -690,6 +667,21 @@@ static int fetch_refs_via_pack(struct t
        return (refs ? 0 : -1);
  }
  
 +static int push_had_errors(struct ref *ref)
 +{
 +      for (; ref; ref = ref->next) {
 +              switch (ref->status) {
 +              case REF_STATUS_NONE:
 +              case REF_STATUS_UPTODATE:
 +              case REF_STATUS_OK:
 +                      break;
 +              default:
 +                      return 1;
 +              }
 +      }
 +      return 0;
 +}
 +
  static int refs_pushed(struct ref *ref)
  {
        for (; ref; ref = ref->next) {
@@@ -720,30 -728,19 +720,30 @@@ static void update_tracking_ref(struct 
  
  #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
  
 -static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)
 +static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, int porcelain)
  {
 -      fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
 -      if (from)
 -              fprintf(stderr, "%s -> %s", prettify_ref(from), prettify_ref(to));
 -      else
 -              fputs(prettify_ref(to), stderr);
 -      if (msg) {
 -              fputs(" (", stderr);
 -              fputs(msg, stderr);
 -              fputc(')', stderr);
 +      if (porcelain) {
 +              if (from)
 +                      fprintf(stdout, "%c\t%s:%s\t", flag, from->name, to->name);
 +              else
 +                      fprintf(stdout, "%c\t:%s\t", flag, to->name);
 +              if (msg)
 +                      fprintf(stdout, "%s (%s)\n", summary, msg);
 +              else
 +                      fprintf(stdout, "%s\n", summary);
 +      } else {
 +              fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
 +              if (from)
 +                      fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
 +              else
 +                      fputs(prettify_refname(to->name), stderr);
 +              if (msg) {
 +                      fputs(" (", stderr);
 +                      fputs(msg, stderr);
 +                      fputc(')', stderr);
 +              }
 +              fputc('\n', stderr);
        }
 -      fputc('\n', stderr);
  }
  
  static const char *status_abbrev(unsigned char sha1[20])
        return find_unique_abbrev(sha1, DEFAULT_ABBREV);
  }
  
 -static void print_ok_ref_status(struct ref *ref)
 +static void print_ok_ref_status(struct ref *ref, int porcelain)
  {
        if (ref->deletion)
 -              print_ref_status('-', "[deleted]", ref, NULL, NULL);
 +              print_ref_status('-', "[deleted]", ref, NULL, NULL, porcelain);
        else if (is_null_sha1(ref->old_sha1))
                print_ref_status('*',
                        (!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" :
 -                        "[new branch]"),
 -                      ref, ref->peer_ref, NULL);
 +                      "[new branch]"),
 +                      ref, ref->peer_ref, NULL, porcelain);
        else {
                char quickref[84];
                char type;
                }
                strcat(quickref, status_abbrev(ref->new_sha1));
  
 -              print_ref_status(type, quickref, ref, ref->peer_ref, msg);
 +              print_ref_status(type, quickref, ref, ref->peer_ref, msg, porcelain);
        }
  }
  
 -static int print_one_push_status(struct ref *ref, const char *dest, int count)
 +static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain)
  {
        if (!count)
                fprintf(stderr, "To %s\n", dest);
  
        switch(ref->status) {
        case REF_STATUS_NONE:
 -              print_ref_status('X', "[no match]", ref, NULL, NULL);
 +              print_ref_status('X', "[no match]", ref, NULL, NULL, porcelain);
                break;
        case REF_STATUS_REJECT_NODELETE:
                print_ref_status('!', "[rejected]", ref, NULL,
 -                              "remote does not support deleting refs");
 +                                               "remote does not support deleting refs", porcelain);
                break;
        case REF_STATUS_UPTODATE:
                print_ref_status('=', "[up to date]", ref,
 -                              ref->peer_ref, NULL);
 +                                               ref->peer_ref, NULL, porcelain);
                break;
        case REF_STATUS_REJECT_NONFASTFORWARD:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
 -                              "non-fast forward");
 +                                               "non-fast forward", porcelain);
                break;
        case REF_STATUS_REMOTE_REJECT:
                print_ref_status('!', "[remote rejected]", ref,
 -                              ref->deletion ? NULL : ref->peer_ref,
 -                              ref->remote_status);
 +                                               ref->deletion ? NULL : ref->peer_ref,
 +                                               ref->remote_status, porcelain);
                break;
        case REF_STATUS_EXPECTING_REPORT:
                print_ref_status('!', "[remote failure]", ref,
 -                              ref->deletion ? NULL : ref->peer_ref,
 -                              "remote failed to report status");
 +                                               ref->deletion ? NULL : ref->peer_ref,
 +                                               "remote failed to report status", porcelain);
                break;
        case REF_STATUS_OK:
 -              print_ok_ref_status(ref);
 +              print_ok_ref_status(ref, porcelain);
                break;
        }
  
        return 1;
  }
  
 -static void print_push_status(const char *dest, struct ref *refs, int verbose)
 +static void print_push_status(const char *dest, struct ref *refs,
 +                            int verbose, int porcelain, int * nonfastforward)
  {
        struct ref *ref;
        int n = 0;
        if (verbose) {
                for (ref = refs; ref; ref = ref->next)
                        if (ref->status == REF_STATUS_UPTODATE)
 -                              n += print_one_push_status(ref, dest, n);
 +                              n += print_one_push_status(ref, dest, n, porcelain);
        }
  
        for (ref = refs; ref; ref = ref->next)
                if (ref->status == REF_STATUS_OK)
 -                      n += print_one_push_status(ref, dest, n);
 +                      n += print_one_push_status(ref, dest, n, porcelain);
  
 +      *nonfastforward = 0;
        for (ref = refs; ref; ref = ref->next) {
                if (ref->status != REF_STATUS_NONE &&
                    ref->status != REF_STATUS_UPTODATE &&
                    ref->status != REF_STATUS_OK)
 -                      n += print_one_push_status(ref, dest, n);
 +                      n += print_one_push_status(ref, dest, n, porcelain);
 +              if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD)
 +                      *nonfastforward = 1;
        }
  }
  
@@@ -896,7 -889,6 +896,7 @@@ static int git_transport_push(struct tr
        args.force_update = !!(flags & TRANSPORT_PUSH_FORCE);
        args.use_thin_pack = data->thin;
        args.verbose = !!(flags & TRANSPORT_PUSH_VERBOSE);
 +      args.quiet = !!(flags & TRANSPORT_PUSH_QUIET);
        args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
  
        ret = send_pack(&args, data->fd, data->conn, remote_refs,
@@@ -1002,8 -994,7 +1002,8 @@@ int transport_set_option(struct transpo
  }
  
  int transport_push(struct transport *transport,
 -                 int refspec_nr, const char **refspec, int flags)
 +                 int refspec_nr, const char **refspec, int flags,
 +                 int * nonfastforward)
  {
        verify_remote_names(refspec_nr, refspec);
  
        if (transport->push_refs) {
                struct ref *remote_refs =
                        transport->get_refs_list(transport, 1);
 -              struct ref **remote_tail;
                struct ref *local_refs = get_local_heads();
                int match_flags = MATCH_REFS_NONE;
                int verbose = flags & TRANSPORT_PUSH_VERBOSE;
 +              int quiet = flags & TRANSPORT_PUSH_QUIET;
 +              int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
                int ret;
  
                if (flags & TRANSPORT_PUSH_ALL)
                if (flags & TRANSPORT_PUSH_MIRROR)
                        match_flags |= MATCH_REFS_MIRROR;
  
 -              remote_tail = &remote_refs;
 -              while (*remote_tail)
 -                      remote_tail = &((*remote_tail)->next);
 -              if (match_refs(local_refs, remote_refs, &remote_tail,
 +              if (match_refs(local_refs, &remote_refs,
                               refspec_nr, refspec, match_flags)) {
                        return -1;
                }
  
                ret = transport->push_refs(transport, remote_refs, flags);
  
 -              print_push_status(transport->url, remote_refs, verbose);
 +              if (!quiet || push_had_errors(remote_refs))
 +                      print_push_status(transport->url, remote_refs,
 +                                      verbose | porcelain, porcelain,
 +                                      nonfastforward);
  
                if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
                        struct ref *ref;
@@@ -1059,11 -1049,12 +1059,12 @@@ const struct ref *transport_get_remote_
  int transport_fetch_refs(struct transport *transport, const struct ref *refs)
  {
        int rc;
-       int nr_heads = 0, nr_alloc = 0;
+       int nr_heads = 0, nr_alloc = 0, nr_refs = 0;
        const struct ref **heads = NULL;
        const struct ref *rm;
  
        for (rm = refs; rm; rm = rm->next) {
+               nr_refs++;
                if (rm->peer_ref &&
                    !hashcmp(rm->peer_ref->old_sha1, rm->old_sha1))
                        continue;
                heads[nr_heads++] = rm;
        }
  
+       if (!nr_heads) {
+               /*
+                * When deepening of a shallow repository is requested,
+                * then local and remote refs are likely to still be equal.
+                * Just feed them all to the fetch method in that case.
+                * This condition shouldn't be met in a non-deepening fetch
+                * (see builtin-fetch.c:quickfetch()).
+                */
+               heads = xmalloc(nr_refs * sizeof(*heads));
+               for (rm = refs; rm; rm = rm->next)
+                       heads[nr_heads++] = rm;
+       }
        rc = transport->fetch(transport, nr_heads, heads);
        free(heads);
        return rc;
@@@ -1093,51 -1097,3 +1107,51 @@@ int transport_disconnect(struct transpo
        free(transport);
        return ret;
  }
 +
 +/*
 + * Strip username (and password) from an url and return
 + * it in a newly allocated string.
 + */
 +char *transport_anonymize_url(const char *url)
 +{
 +      char *anon_url, *scheme_prefix, *anon_part;
 +      size_t anon_len, prefix_len = 0;
 +
 +      anon_part = strchr(url, '@');
 +      if (is_local(url) || !anon_part)
 +              goto literal_copy;
 +
 +      anon_len = strlen(++anon_part);
 +      scheme_prefix = strstr(url, "://");
 +      if (!scheme_prefix) {
 +              if (!strchr(anon_part, ':'))
 +                      /* cannot be "me@there:/path/name" */
 +                      goto literal_copy;
 +      } else {
 +              const char *cp;
 +              /* make sure scheme is reasonable */
 +              for (cp = url; cp < scheme_prefix; cp++) {
 +                      switch (*cp) {
 +                              /* RFC 1738 2.1 */
 +                      case '+': case '.': case '-':
 +                              break; /* ok */
 +                      default:
 +                              if (isalnum(*cp))
 +                                      break;
 +                              /* it isn't */
 +                              goto literal_copy;
 +                      }
 +              }
 +              /* @ past the first slash does not count */
 +              cp = strchr(scheme_prefix + 3, '/');
 +              if (cp && cp < anon_part)
 +                      goto literal_copy;
 +              prefix_len = scheme_prefix - url + 3;
 +      }
 +      anon_url = xcalloc(1, 1 + prefix_len + anon_len);
 +      memcpy(anon_url, url, prefix_len);
 +      memcpy(anon_url + prefix_len, anon_part, anon_len);
 +      return anon_url;
 +literal_copy:
 +      return xstrdup(url);
 +}