Merge branch 'jk/fetch-pack'
authorJunio C Hamano <gitster@pobox.com>
Wed, 25 Mar 2015 19:54:25 +0000 (12:54 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 25 Mar 2015 19:54:25 +0000 (12:54 -0700)
"git fetch" that fetches a commit using the allow-tip-sha1-in-want
extension could have failed to fetch all the requested refs.

* jk/fetch-pack:
fetch-pack: remove dead assignment to ref->new_sha1
fetch_refs_via_pack: free extra copy of refs
filter_ref: make a copy of extra "sought" entries
filter_ref: avoid overwriting ref->old_sha1 with garbage

1  2 
t/t5516-fetch-push.sh
transport.c
diff --combined t/t5516-fetch-push.sh
index 630885d6df2fed0b8ba35005f150ccd3838dfcca,f7947315ba0fda1060930932afe5e6a0c065d0da..5e04d641092267e5bf6ae7fa0a1e36959d8c6b80
@@@ -238,7 -238,7 +238,7 @@@ test_expect_success 'push with pushInst
  test_expect_success 'push with pushInsteadOf and explicit pushurl (pushInsteadOf should not rewrite)' '
        mk_empty testrepo &&
        test_config "url.trash2/.pushInsteadOf" testrepo/ &&
 -      test_config "url.trash3/.pusnInsteadOf" trash/wrong &&
 +      test_config "url.trash3/.pushInsteadOf" trash/wrong &&
        test_config remote.r.url trash/wrong &&
        test_config remote.r.pushurl "testrepo/" &&
        git push r refs/heads/master:refs/remotes/origin/master &&
@@@ -1107,9 -1107,16 +1107,16 @@@ test_expect_success 'fetch exact SHA1' 
                        git config uploadpack.allowtipsha1inwant true
                ) &&
  
-               git fetch -v ../testrepo $the_commit:refs/heads/copy &&
-               result=$(git rev-parse --verify refs/heads/copy) &&
-               test "$the_commit" = "$result"
+               git fetch -v ../testrepo $the_commit:refs/heads/copy master:refs/heads/extra &&
+               cat >expect <<-EOF &&
+               $the_commit
+               $the_first_commit
+               EOF
+               {
+                       git rev-parse --verify refs/heads/copy &&
+                       git rev-parse --verify refs/heads/extra
+               } >actual &&
+               test_cmp expect actual
        )
  '
  
@@@ -1330,171 -1337,4 +1337,171 @@@ test_expect_success 'fetch into bare re
        )
  '
  
 +test_expect_success 'receive.denyCurrentBranch = updateInstead' '
 +      git push testrepo master &&
 +      (
 +              cd testrepo &&
 +              git reset --hard &&
 +              git config receive.denyCurrentBranch updateInstead
 +      ) &&
 +      test_commit third path2 &&
 +
 +      # Try pushing into a repository with pristine working tree
 +      git push testrepo master &&
 +      (
 +              cd testrepo &&
 +              git update-index -q --refresh &&
 +              git diff-files --quiet -- &&
 +              git diff-index --quiet --cached HEAD -- &&
 +              test third = "$(cat path2)" &&
 +              test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
 +      ) &&
 +
 +      # Try pushing into a repository with working tree needing a refresh
 +      (
 +              cd testrepo &&
 +              git reset --hard HEAD^ &&
 +              test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) &&
 +              test-chmtime +100 path1
 +      ) &&
 +      git push testrepo master &&
 +      (
 +              cd testrepo &&
 +              git update-index -q --refresh &&
 +              git diff-files --quiet -- &&
 +              git diff-index --quiet --cached HEAD -- &&
 +              test_cmp ../path1 path1 &&
 +              test third = "$(cat path2)" &&
 +              test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
 +      ) &&
 +
 +      # Update what is to be pushed
 +      test_commit fourth path2 &&
 +
 +      # Try pushing into a repository with a dirty working tree
 +      # (1) the working tree updated
 +      (
 +              cd testrepo &&
 +              echo changed >path1
 +      ) &&
 +      test_must_fail git push testrepo master &&
 +      (
 +              cd testrepo &&
 +              test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) &&
 +              git diff --quiet --cached &&
 +              test changed = "$(cat path1)"
 +      ) &&
 +
 +      # (2) the index updated
 +      (
 +              cd testrepo &&
 +              echo changed >path1 &&
 +              git add path1
 +      ) &&
 +      test_must_fail git push testrepo master &&
 +      (
 +              cd testrepo &&
 +              test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) &&
 +              git diff --quiet &&
 +              test changed = "$(cat path1)"
 +      ) &&
 +
 +      # Introduce a new file in the update
 +      test_commit fifth path3 &&
 +
 +      # (3) the working tree has an untracked file that would interfere
 +      (
 +              cd testrepo &&
 +              git reset --hard &&
 +              echo changed >path3
 +      ) &&
 +      test_must_fail git push testrepo master &&
 +      (
 +              cd testrepo &&
 +              test $(git -C .. rev-parse HEAD^^) = $(git rev-parse HEAD) &&
 +              git diff --quiet &&
 +              git diff --quiet --cached &&
 +              test changed = "$(cat path3)"
 +      ) &&
 +
 +      # (4) the target changes to what gets pushed but it still is a change
 +      (
 +              cd testrepo &&
 +              git reset --hard &&
 +              echo fifth >path3 &&
 +              git add path3
 +      ) &&
 +      test_must_fail git push testrepo master &&
 +      (
 +              cd testrepo &&
 +              test $(git -C .. rev-parse HEAD^^) = $(git rev-parse HEAD) &&
 +              git diff --quiet &&
 +              test fifth = "$(cat path3)"
 +      )
 +
 +'
 +
 +test_expect_success 'updateInstead with push-to-checkout hook' '
 +      rm -fr testrepo &&
 +      git init testrepo &&
 +      (
 +              cd testrepo &&
 +              git pull .. master &&
 +              git reset --hard HEAD^^ &&
 +              git tag initial &&
 +              git config receive.denyCurrentBranch updateInstead &&
 +              write_script .git/hooks/push-to-checkout <<-\EOF
 +              echo >&2 updating from $(git rev-parse HEAD)
 +              echo >&2 updating to "$1"
 +
 +              git update-index -q --refresh &&
 +              git read-tree -u -m HEAD "$1" || {
 +                      status=$?
 +                      echo >&2 read-tree failed
 +                      exit $status
 +              }
 +              EOF
 +      ) &&
 +
 +      # Try pushing into a pristine
 +      git push testrepo master &&
 +      (
 +              cd testrepo &&
 +              git diff --quiet &&
 +              git diff HEAD --quiet &&
 +              test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
 +      ) &&
 +
 +      # Try pushing into a repository with conflicting change
 +      (
 +              cd testrepo &&
 +              git reset --hard initial &&
 +              echo conflicting >path2
 +      ) &&
 +      test_must_fail git push testrepo master &&
 +      (
 +              cd testrepo &&
 +              test $(git rev-parse initial) = $(git rev-parse HEAD) &&
 +              test conflicting = "$(cat path2)" &&
 +              git diff-index --quiet --cached HEAD
 +      ) &&
 +
 +      # Try pushing into a repository with unrelated change
 +      (
 +              cd testrepo &&
 +              git reset --hard initial &&
 +              echo unrelated >path1 &&
 +              echo irrelevant >path5 &&
 +              git add path5
 +      ) &&
 +      git push testrepo master &&
 +      (
 +              cd testrepo &&
 +              test "$(cat path1)" = unrelated &&
 +              test "$(cat path5)" = irrelevant &&
 +              test "$(git diff --name-only --cached HEAD)" = path5 &&
 +              test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
 +      )
 +'
 +
  test_done
diff --combined transport.c
index 00f39d9f5ba8c024ec2b9c6c2a054a0045eadbbb,2e11f8ea82ee980aec86c0394aeed30aa7f52053..eca9b8c817bd723532d7f92da8cfa9f8ee82bb43
@@@ -117,7 -117,7 +117,7 @@@ static void insert_packed_refs(const ch
                        return;
                }
  
 -              if (hexval(buffer[0]) > 0xf)
 +              if (!isxdigit(buffer[0]))
                        continue;
                len = strlen(buffer);
                if (len && buffer[len - 1] == '\n')
@@@ -519,7 -519,7 +519,7 @@@ static int fetch_refs_via_pack(struct t
                               int nr_heads, struct ref **to_fetch)
  {
        struct git_transport_data *data = transport->data;
-       const struct ref *refs;
+       struct ref *refs;
        char *dest = xstrdup(transport->url);
        struct fetch_pack_args args;
        struct ref *refs_tmp = NULL;
                          &transport->pack_lockfile);
        close(data->fd[0]);
        close(data->fd[1]);
-       if (finish_connect(data->conn))
+       if (finish_connect(data->conn)) {
+               free_refs(refs);
                refs = NULL;
+       }
        data->conn = NULL;
        data->got_remote_heads = 0;
        data->options.self_contained_and_connected =
                args.self_contained_and_connected;
  
        free_refs(refs_tmp);
+       free_refs(refs);
        free(dest);
        return (refs ? 0 : -1);
  }
@@@ -728,10 -730,6 +730,10 @@@ static int print_one_push_status(struc
                                                 ref->deletion ? NULL : ref->peer_ref,
                                                 "remote failed to report status", porcelain);
                break;
 +      case REF_STATUS_ATOMIC_PUSH_FAILED:
 +              print_ref_status('!', "[rejected]", ref, ref->peer_ref,
 +                                               "atomic push failed", porcelain);
 +              break;
        case REF_STATUS_OK:
                print_ok_ref_status(ref, porcelain);
                break;
@@@ -830,7 -828,6 +832,7 @@@ static int git_transport_push(struct tr
        args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
        args.porcelain = !!(flags & TRANSPORT_PUSH_PORCELAIN);
        args.push_cert = !!(flags & TRANSPORT_PUSH_CERT);
 +      args.atomic = !!(flags & TRANSPORT_PUSH_ATOMIC);
        args.url = transport->url;
  
        ret = send_pack(&args, data->fd, data->conn, remote_refs,
@@@ -976,7 -973,9 +978,7 @@@ struct transport *transport_get(struct 
        } else {
                /* Unknown protocol in URL. Pass to external handler. */
                int len = external_specification_len(url);
 -              char *handler = xmalloc(len + 1);
 -              handler[len] = 0;
 -              strncpy(handler, url, len);
 +              char *handler = xmemdupz(url, len);
                transport_helper_init(ret, handler);
        }