fetch-pack: put shallow info in output parameter
[gitweb.git] / transport.c
index 6785fcceed245769d7d9515a73b7e29c99ee268b..39d8c2fa552d69f2759475062e38a0132894bdcf 100644 (file)
@@ -11,6 +11,7 @@
 #include "bundle.h"
 #include "dir.h"
 #include "refs.h"
+#include "refspec.h"
 #include "branch.h"
 #include "url.h"
 #include "submodule.h"
@@ -150,7 +151,8 @@ static struct ref *get_refs_from_bundle(struct transport *transport,
 }
 
 static int fetch_refs_from_bundle(struct transport *transport,
-                              int nr_heads, struct ref **to_fetch)
+                              int nr_heads, struct ref **to_fetch,
+                              struct ref **fetched_refs)
 {
        struct bundle_transport_data *data = transport->data;
        return unbundle(&data->header, data->fd,
@@ -286,7 +288,8 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
 }
 
 static int fetch_refs_via_pack(struct transport *transport,
-                              int nr_heads, struct ref **to_fetch)
+                              int nr_heads, struct ref **to_fetch,
+                              struct ref **fetched_refs)
 {
        int ret = 0;
        struct git_transport_data *data = transport->data;
@@ -353,8 +356,12 @@ static int fetch_refs_via_pack(struct transport *transport,
        if (report_unmatched_refs(to_fetch, nr_heads))
                ret = -1;
 
+       if (fetched_refs)
+               *fetched_refs = refs;
+       else
+               free_refs(refs);
+
        free_refs(refs_tmp);
-       free_refs(refs);
        free(dest);
        return ret;
 }
@@ -390,7 +397,7 @@ int transport_refs_pushed(struct ref *ref)
 
 void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose)
 {
-       struct refspec rs;
+       struct refspec_item rs;
 
        if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
                return;
@@ -619,29 +626,6 @@ void transport_print_push_status(const char *dest, struct ref *refs,
        free(head);
 }
 
-void transport_verify_remote_names(int nr_heads, const char **heads)
-{
-       int i;
-
-       for (i = 0; i < nr_heads; i++) {
-               const char *local = heads[i];
-               const char *remote = strrchr(heads[i], ':');
-
-               if (*local == '+')
-                       local++;
-
-               /* A matching refspec is okay.  */
-               if (remote == local && remote[1] == '\0')
-                       continue;
-
-               remote = remote ? (remote + 1) : local;
-               if (check_refname_format(remote,
-                               REFNAME_ALLOW_ONELEVEL|REFNAME_REFSPEC_PATTERN))
-                       die("remote part of refspec is not a valid name in %s",
-                               heads[i]);
-       }
-}
-
 static int git_transport_push(struct transport *transport, struct ref *remote_refs, int flags)
 {
        struct git_transport_data *data = transport->data;
@@ -1093,11 +1077,10 @@ static int run_pre_push_hook(struct transport *transport,
 }
 
 int transport_push(struct transport *transport,
-                  int refspec_nr, const char **refspec, int flags,
+                  struct refspec *rs, int flags,
                   unsigned int *reject_reasons)
 {
        *reject_reasons = 0;
-       transport_verify_remote_names(refspec_nr, refspec);
 
        if (transport_color_config() < 0)
                return -1;
@@ -1111,38 +1094,17 @@ int transport_push(struct transport *transport,
                int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
                int pretend = flags & TRANSPORT_PUSH_DRY_RUN;
                int push_ret, ret, err;
-               struct refspec *tmp_rs;
                struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
-               int i;
 
-               if (check_push_refs(local_refs, refspec_nr, refspec) < 0)
+               if (check_push_refs(local_refs, rs) < 0)
                        return -1;
 
-               tmp_rs = parse_push_refspec(refspec_nr, refspec);
-               for (i = 0; i < refspec_nr; i++) {
-                       const char *prefix = NULL;
-
-                       if (tmp_rs[i].dst)
-                               prefix = tmp_rs[i].dst;
-                       else if (tmp_rs[i].src && !tmp_rs[i].exact_sha1)
-                               prefix = tmp_rs[i].src;
-
-                       if (prefix) {
-                               const char *glob = strchr(prefix, '*');
-                               if (glob)
-                                       argv_array_pushf(&ref_prefixes, "%.*s",
-                                                        (int)(glob - prefix),
-                                                        prefix);
-                               else
-                                       expand_ref_prefix(&ref_prefixes, prefix);
-                       }
-               }
+               refspec_ref_prefixes(rs, &ref_prefixes);
 
                remote_refs = transport->vtable->get_refs_list(transport, 1,
                                                               &ref_prefixes);
 
                argv_array_clear(&ref_prefixes);
-               free_refspec(refspec_nr, tmp_rs);
 
                if (flags & TRANSPORT_PUSH_ALL)
                        match_flags |= MATCH_REFS_ALL;
@@ -1153,10 +1115,8 @@ int transport_push(struct transport *transport,
                if (flags & TRANSPORT_PUSH_FOLLOW_TAGS)
                        match_flags |= MATCH_REFS_FOLLOW_TAGS;
 
-               if (match_push_refs(local_refs, &remote_refs,
-                                   refspec_nr, refspec, match_flags)) {
+               if (match_push_refs(local_refs, &remote_refs, rs, match_flags))
                        return -1;
-               }
 
                if (transport->smart_options &&
                    transport->smart_options->cas &&
@@ -1185,7 +1145,7 @@ int transport_push(struct transport *transport,
 
                        if (!push_unpushed_submodules(&commits,
                                                      transport->remote,
-                                                     refspec, refspec_nr,
+                                                     rs,
                                                      transport->push_options,
                                                      pretend)) {
                                oid_array_clear(&commits);
@@ -1261,19 +1221,31 @@ const struct ref *transport_get_remote_refs(struct transport *transport,
        return transport->remote_refs;
 }
 
-int transport_fetch_refs(struct transport *transport, struct ref *refs)
+int transport_fetch_refs(struct transport *transport, struct ref *refs,
+                        struct ref **fetched_refs)
 {
        int rc;
        int nr_heads = 0, nr_alloc = 0, nr_refs = 0;
        struct ref **heads = NULL;
+       struct ref *nop_head = NULL, **nop_tail = &nop_head;
        struct ref *rm;
 
        for (rm = refs; rm; rm = rm->next) {
                nr_refs++;
                if (rm->peer_ref &&
                    !is_null_oid(&rm->old_oid) &&
-                   !oidcmp(&rm->peer_ref->old_oid, &rm->old_oid))
+                   !oidcmp(&rm->peer_ref->old_oid, &rm->old_oid)) {
+                       /*
+                        * These need to be reported as fetched, but we don't
+                        * actually need to fetch them.
+                        */
+                       if (fetched_refs) {
+                               struct ref *nop_ref = copy_ref(rm);
+                               *nop_tail = nop_ref;
+                               nop_tail = &nop_ref->next;
+                       }
                        continue;
+               }
                ALLOC_GROW(heads, nr_heads + 1, nr_alloc);
                heads[nr_heads++] = rm;
        }
@@ -1291,7 +1263,11 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)
                        heads[nr_heads++] = rm;
        }
 
-       rc = transport->vtable->fetch(transport, nr_heads, heads);
+       rc = transport->vtable->fetch(transport, nr_heads, heads, fetched_refs);
+       if (fetched_refs && nop_head) {
+               *nop_tail = *fetched_refs;
+               *fetched_refs = nop_head;
+       }
 
        free(heads);
        return rc;