Code

Merge branch 'jc/maint-fetch-alt'
authorJunio C Hamano <gitster@pobox.com>
Wed, 23 Mar 2011 04:37:53 +0000 (21:37 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 23 Mar 2011 04:37:53 +0000 (21:37 -0700)
* jc/maint-fetch-alt:
  fetch-pack: objects in our alternates are available to us
  refs_from_alternate: helper to use refs from alternates

Conflicts:
builtin/receive-pack.c

builtin/fetch-pack.c
builtin/receive-pack.c
t/t5501-fetch-push-alternates.sh [new file with mode: 0755]
transport.c
transport.h

index ef398620affcb55aa1ee0fdd3ca74dda58c37172..28d6900bb0e2a4deb036013236e489f1ffaa9e41 100644 (file)
@@ -9,6 +9,7 @@
 #include "fetch-pack.h"
 #include "remote.h"
 #include "run-command.h"
+#include "transport.h"
 
 static int transfer_unpack_limit = -1;
 static int fetch_unpack_limit = -1;
@@ -217,6 +218,16 @@ static void send_request(int fd, struct strbuf *buf)
                safe_write(fd, buf->buf, buf->len);
 }
 
+static void insert_one_alternate_ref(const struct ref *ref, void *unused)
+{
+       rev_list_insert_ref(NULL, ref->old_sha1, 0, NULL);
+}
+
+static void insert_alternate_refs(void)
+{
+       foreach_alt_odb(refs_from_alternate_cb, insert_one_alternate_ref);
+}
+
 static int find_common(int fd[2], unsigned char *result_sha1,
                       struct ref *refs)
 {
@@ -235,6 +246,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
        marked = 1;
 
        for_each_ref(rev_list_insert_ref, NULL);
+       insert_alternate_refs();
 
        fetching = 0;
        for ( ; refs ; refs = refs->next) {
index d8e2c5fca7902d6d9a9e8300e129d58ad7a98192..27050e7c1627ed2899963fb3fdb81a7ba95d06df 100644 (file)
@@ -731,43 +731,14 @@ static int delete_only(struct command *commands)
        return 1;
 }
 
-static int add_refs_from_alternate(struct alternate_object_database *e, void *unused)
+static void add_one_alternate_ref(const struct ref *ref, void *unused)
 {
-       char *other;
-       size_t len;
-       struct remote *remote;
-       struct transport *transport;
-       const struct ref *extra;
-
-       e->name[-1] = '\0';
-       other = xstrdup(real_path(e->base));
-       e->name[-1] = '/';
-       len = strlen(other);
-
-       while (other[len-1] == '/')
-               other[--len] = '\0';
-       if (len < 8 || memcmp(other + len - 8, "/objects", 8))
-               return 0;
-       /* Is this a git repository with refs? */
-       memcpy(other + len - 8, "/refs", 6);
-       if (!is_directory(other))
-               return 0;
-       other[len - 8] = '\0';
-       remote = remote_get(other);
-       transport = transport_get(remote, other);
-       for (extra = transport_get_remote_refs(transport);
-            extra;
-            extra = extra->next) {
-               add_extra_ref(".have", extra->old_sha1, 0);
-       }
-       transport_disconnect(transport);
-       free(other);
-       return 0;
+       add_extra_ref(".have", ref->old_sha1, 0);
 }
 
 static void add_alternate_refs(void)
 {
-       foreach_alt_odb(add_refs_from_alternate, NULL);
+       foreach_alt_odb(refs_from_alternate_cb, add_one_alternate_ref);
 }
 
 int cmd_receive_pack(int argc, const char **argv, const char *prefix)
diff --git a/t/t5501-fetch-push-alternates.sh b/t/t5501-fetch-push-alternates.sh
new file mode 100755 (executable)
index 0000000..b5ced84
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+test_description='fetch/push involving alternates'
+. ./test-lib.sh
+
+count_objects () {
+       loose=0 inpack=0
+       eval "$(
+               git count-objects -v |
+               sed -n -e 's/^count: \(.*\)/loose=\1/p' \
+                   -e 's/^in-pack: \(.*\)/inpack=\1/p'
+       )" &&
+       echo $(( $loose + $inpack ))
+}
+
+
+test_expect_success setup '
+       (
+               git init original &&
+               cd original &&
+               i=0 &&
+               while test $i -le 100
+               do
+                       echo "$i" >count &&
+                       git add count &&
+                       git commit -m "$i" || exit
+                       i=$(($i + 1))
+               done
+       ) &&
+       (
+               git clone --reference=original "file:///$(pwd)/original" one &&
+               cd one &&
+               echo Z >count &&
+               git add count &&
+               git commit -m Z &&
+               count_objects >../one.count
+       ) &&
+       A=$(pwd)/original/.git/objects &&
+       git init receiver &&
+       echo "$A" >receiver/.git/objects/info/alternates &&
+       git init fetcher &&
+       echo "$A" >fetcher/.git/objects/info/alternates
+'
+
+test_expect_success 'pushing into a repository with the same alternate' '
+       (
+               cd one &&
+               git push ../receiver master:refs/heads/it
+       ) &&
+       (
+               cd receiver &&
+               count_objects >../receiver.count
+       ) &&
+       test_cmp one.count receiver.count
+'
+
+test_expect_success 'fetching from a repository with the same alternate' '
+       (
+               cd fetcher &&
+               git fetch ../one master:refs/heads/it &&
+               count_objects >../fetcher.count
+       ) &&
+       test_cmp one.count fetcher.count
+'
+
+test_done
index f1c07816e01bb0b1ad93d7665b1374e8cd36e6cb..a02f79aae3d91ea4109d21a9ed9ca2d962125375 100644 (file)
@@ -1189,3 +1189,37 @@ char *transport_anonymize_url(const char *url)
 literal_copy:
        return xstrdup(url);
 }
+
+int refs_from_alternate_cb(struct alternate_object_database *e, void *cb)
+{
+       char *other;
+       size_t len;
+       struct remote *remote;
+       struct transport *transport;
+       const struct ref *extra;
+       alternate_ref_fn *ref_fn = cb;
+
+       e->name[-1] = '\0';
+       other = xstrdup(real_path(e->base));
+       e->name[-1] = '/';
+       len = strlen(other);
+
+       while (other[len-1] == '/')
+               other[--len] = '\0';
+       if (len < 8 || memcmp(other + len - 8, "/objects", 8))
+               return 0;
+       /* Is this a git repository with refs? */
+       memcpy(other + len - 8, "/refs", 6);
+       if (!is_directory(other))
+               return 0;
+       other[len - 8] = '\0';
+       remote = remote_get(other);
+       transport = transport_get(remote, other);
+       for (extra = transport_get_remote_refs(transport);
+            extra;
+            extra = extra->next)
+               ref_fn(extra, NULL);
+       transport_disconnect(transport);
+       free(other);
+       return 0;
+}
index e803c0e7baf3785fac35fca64072e05e4f668a26..efb19688692b5f1be4fc085cc36d737ace2df417 100644 (file)
@@ -166,4 +166,7 @@ int transport_refs_pushed(struct ref *ref);
 void transport_print_push_status(const char *dest, struct ref *refs,
                  int verbose, int porcelain, int *nonfastforward);
 
+typedef void alternate_ref_fn(const struct ref *, void *);
+extern int refs_from_alternate_cb(struct alternate_object_database *e, void *cb);
+
 #endif