Code

GIT 1.6.1.3
[git.git] / builtin-send-pack.c
index ed94f9a460336d84ef5c1edcc0c4b5a26163c74d..d65d01969252332eeee12b0419e4ba3a806952b1 100644 (file)
@@ -15,10 +15,24 @@ static struct send_pack_args args = {
        /* .receivepack = */ "git-receive-pack",
 };
 
+static int feed_object(const unsigned char *sha1, int fd, int negative)
+{
+       char buf[42];
+
+       if (negative && !has_sha1_file(sha1))
+               return 1;
+
+       memcpy(buf + negative, sha1_to_hex(sha1), 40);
+       if (negative)
+               buf[0] = '^';
+       buf[40 + negative] = '\n';
+       return write_or_whine(fd, buf, 41 + negative, "send-pack: send refs");
+}
+
 /*
  * Make a pack stream and spit it out into file descriptor fd
  */
-static int pack_objects(int fd, struct ref *refs)
+static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra)
 {
        /*
         * The child becomes pack-objects --revs; we feed
@@ -34,6 +48,7 @@ static int pack_objects(int fd, struct ref *refs)
                NULL,
        };
        struct child_process po;
+       int i;
 
        if (args.use_thin_pack)
                argv[4] = "--thin";
@@ -49,25 +64,17 @@ static int pack_objects(int fd, struct ref *refs)
         * We feed the pack-objects we just spawned with revision
         * parameters by writing to the pipe.
         */
-       while (refs) {
-               char buf[42];
+       for (i = 0; i < extra->nr; i++)
+               if (!feed_object(extra->array[i], po.in, 1))
+                       break;
 
+       while (refs) {
                if (!is_null_sha1(refs->old_sha1) &&
-                   has_sha1_file(refs->old_sha1)) {
-                       memcpy(buf + 1, sha1_to_hex(refs->old_sha1), 40);
-                       buf[0] = '^';
-                       buf[41] = '\n';
-                       if (!write_or_whine(po.in, buf, 42,
-                                               "send-pack: send refs"))
-                               break;
-               }
-               if (!is_null_sha1(refs->new_sha1)) {
-                       memcpy(buf, sha1_to_hex(refs->new_sha1), 40);
-                       buf[40] = '\n';
-                       if (!write_or_whine(po.in, buf, 41,
-                                               "send-pack: send refs"))
-                               break;
-               }
+                   !feed_object(refs->old_sha1, po.in, 1))
+                       break;
+               if (!is_null_sha1(refs->new_sha1) &&
+                   !feed_object(refs->new_sha1, po.in, 0))
+                       break;
                refs = refs->next;
        }
 
@@ -222,7 +229,7 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref)
 {
        struct refspec rs;
 
-       if (ref->status != REF_STATUS_OK)
+       if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
                return;
 
        rs.src = ref->name;
@@ -387,14 +394,17 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
        int expect_status_report = 0;
        int flags = MATCH_REFS_NONE;
        int ret;
+       struct extra_have_objects extra_have;
 
+       memset(&extra_have, 0, sizeof(extra_have));
        if (args.send_all)
                flags |= MATCH_REFS_ALL;
        if (args.send_mirror)
                flags |= MATCH_REFS_MIRROR;
 
        /* No funny business with the matcher */
-       remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL);
+       remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL,
+                                      &extra_have);
        get_local_heads();
 
        /* Does the other end support the reporting? */
@@ -424,24 +434,19 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
         */
        new_refs = 0;
        for (ref = remote_refs; ref; ref = ref->next) {
-               const unsigned char *new_sha1;
-
-               if (!ref->peer_ref) {
-                       if (!args.send_mirror)
-                               continue;
-                       new_sha1 = null_sha1;
-               }
-               else
-                       new_sha1 = ref->peer_ref->new_sha1;
 
+               if (ref->peer_ref)
+                       hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
+               else if (!args.send_mirror)
+                       continue;
 
-               ref->deletion = is_null_sha1(new_sha1);
+               ref->deletion = is_null_sha1(ref->new_sha1);
                if (ref->deletion && !allow_deleting_refs) {
                        ref->status = REF_STATUS_REJECT_NODELETE;
                        continue;
                }
                if (!ref->deletion &&
-                   !hashcmp(ref->old_sha1, new_sha1)) {
+                   !hashcmp(ref->old_sha1, ref->new_sha1)) {
                        ref->status = REF_STATUS_UPTODATE;
                        continue;
                }
@@ -469,14 +474,13 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
                    !ref->deletion &&
                    !is_null_sha1(ref->old_sha1) &&
                    (!has_sha1_file(ref->old_sha1)
-                     || !ref_newer(new_sha1, ref->old_sha1));
+                     || !ref_newer(ref->new_sha1, ref->old_sha1));
 
                if (ref->nonfastforward && !ref->force && !args.force_update) {
                        ref->status = REF_STATUS_REJECT_NONFASTFORWARD;
                        continue;
                }
 
-               hashcpy(ref->new_sha1, new_sha1);
                if (!ref->deletion)
                        new_refs++;
 
@@ -502,7 +506,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
 
        packet_flush(out);
        if (new_refs && !args.dry_run) {
-               if (pack_objects(out, remote_refs) < 0)
+               if (pack_objects(out, remote_refs, &extra_have) < 0)
                        return -1;
        }
        else