]> git.ipfire.org Git - thirdparty/git.git/blobdiff - transport.c
Merge branch 'master' of github.com:nafmo/git-l10n-sv
[thirdparty/git.git] / transport.c
index 26fefd13c17220f9f69d87cbbc0553db418e56a2..ffe21158455116972dd8b0cf77167948fb6e66e6 100644 (file)
@@ -127,7 +127,7 @@ struct bundle_transport_data {
 
 static struct ref *get_refs_from_bundle(struct transport *transport,
                                        int for_push,
-                                       const struct argv_array *ref_prefixes)
+                                       const struct strvec *ref_prefixes)
 {
        struct bundle_transport_data *data = transport->data;
        struct ref *result = NULL;
@@ -143,6 +143,9 @@ static struct ref *get_refs_from_bundle(struct transport *transport,
        data->fd = read_bundle_header(transport->url, &data->header);
        if (data->fd < 0)
                die(_("could not read bundle '%s'"), transport->url);
+
+       transport->hash_algo = data->header.hash_algo;
+
        for (i = 0; i < data->header.references.nr; i++) {
                struct ref_list_entry *e = data->header.references.list + i;
                struct ref *ref = alloc_ref(e->name);
@@ -157,11 +160,14 @@ static int fetch_refs_from_bundle(struct transport *transport,
                               int nr_heads, struct ref **to_fetch)
 {
        struct bundle_transport_data *data = transport->data;
+       int ret;
 
        if (!data->get_refs_from_bundle_called)
                get_refs_from_bundle(transport, 0, NULL);
-       return unbundle(the_repository, &data->header, data->fd,
-                       transport->progress ? BUNDLE_VERBOSE : 0);
+       ret = unbundle(the_repository, &data->header, data->fd,
+                          transport->progress ? BUNDLE_VERBOSE : 0);
+       transport->hash_algo = data->header.hash_algo;
+       return ret;
 }
 
 static int close_bundle(struct transport *transport)
@@ -226,9 +232,6 @@ static int set_git_option(struct git_transport_options *opts,
        } else if (!strcmp(name, TRANS_OPT_FROM_PROMISOR)) {
                opts->from_promisor = !!value;
                return 0;
-       } else if (!strcmp(name, TRANS_OPT_NO_DEPENDENTS)) {
-               opts->no_dependents = !!value;
-               return 0;
        } else if (!strcmp(name, TRANS_OPT_LIST_OBJECTS_FILTER)) {
                list_objects_filter_die_if_populated(&opts->filter_options);
                parse_list_objects_filter(&opts->filter_options, value);
@@ -277,7 +280,7 @@ static void die_if_server_options(struct transport *transport)
  * remote refs.
  */
 static struct ref *handshake(struct transport *transport, int for_push,
-                            const struct argv_array *ref_prefixes,
+                            const struct strvec *ref_prefixes,
                             int must_list_refs)
 {
        struct git_transport_data *data = transport->data;
@@ -297,7 +300,8 @@ static struct ref *handshake(struct transport *transport, int for_push,
                if (must_list_refs)
                        get_remote_refs(data->fd[1], &reader, &refs, for_push,
                                        ref_prefixes,
-                                       transport->server_options);
+                                       transport->server_options,
+                                       transport->stateless_rpc);
                break;
        case protocol_v1:
        case protocol_v0:
@@ -311,6 +315,7 @@ static struct ref *handshake(struct transport *transport, int for_push,
                BUG("unknown protocol version");
        }
        data->got_remote_heads = 1;
+       transport->hash_algo = reader.hash_algo;
 
        if (reader.line_peeked)
                BUG("buffer must be empty at the end of handshake()");
@@ -319,7 +324,7 @@ static struct ref *handshake(struct transport *transport, int for_push,
 }
 
 static struct ref *get_refs_via_connect(struct transport *transport, int for_push,
-                                       const struct argv_array *ref_prefixes)
+                                       const struct strvec *ref_prefixes)
 {
        return handshake(transport, for_push, ref_prefixes, 1);
 }
@@ -351,7 +356,6 @@ static int fetch_refs_via_pack(struct transport *transport,
        args.cloning = transport->cloning;
        args.update_shallow = data->options.update_shallow;
        args.from_promisor = data->options.from_promisor;
-       args.no_dependents = data->options.no_dependents;
        args.filter_options = data->options.filter_options;
        args.stateless_rpc = transport->stateless_rpc;
        args.server_options = transport->server_options;
@@ -369,24 +373,15 @@ static int fetch_refs_via_pack(struct transport *transport,
                refs_tmp = handshake(transport, 0, NULL, must_list_refs);
        }
 
-       switch (data->version) {
-       case protocol_v2:
-               refs = fetch_pack(&args, data->fd,
-                                 refs_tmp ? refs_tmp : transport->remote_refs,
-                                 to_fetch, nr_heads, &data->shallow,
-                                 &transport->pack_lockfile, data->version);
-               break;
-       case protocol_v1:
-       case protocol_v0:
-               die_if_server_options(transport);
-               refs = fetch_pack(&args, data->fd,
-                                 refs_tmp ? refs_tmp : transport->remote_refs,
-                                 to_fetch, nr_heads, &data->shallow,
-                                 &transport->pack_lockfile, data->version);
-               break;
-       case protocol_unknown_version:
+       if (data->version == protocol_unknown_version)
                BUG("unknown protocol version");
-       }
+       else if (data->version <= protocol_v1)
+               die_if_server_options(transport);
+
+       refs = fetch_pack(&args, data->fd,
+                         refs_tmp ? refs_tmp : transport->remote_refs,
+                         to_fetch, nr_heads, &data->shallow,
+                         &transport->pack_lockfiles, data->version);
 
        close(data->fd[0]);
        close(data->fd[1]);
@@ -437,37 +432,67 @@ int transport_refs_pushed(struct ref *ref)
        return 0;
 }
 
-void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose)
+static void update_one_tracking_ref(struct remote *remote, char *refname,
+                                   struct object_id *new_oid, int deletion,
+                                   int verbose)
 {
        struct refspec_item rs;
 
-       if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
-               return;
-
-       rs.src = ref->name;
+       memset(&rs, 0, sizeof(rs));
+       rs.src = refname;
        rs.dst = NULL;
 
        if (!remote_find_tracking(remote, &rs)) {
                if (verbose)
                        fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
-               if (ref->deletion) {
+               if (deletion)
                        delete_ref(NULL, rs.dst, NULL, 0);
-               else
-                       update_ref("update by push", rs.dst, &ref->new_oid,
+               else
+                       update_ref("update by push", rs.dst, new_oid,
                                   NULL, 0, 0);
                free(rs.dst);
        }
 }
 
+void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose)
+{
+       char *refname;
+       struct object_id *new_oid;
+       struct ref_push_report *report;
+
+       if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
+               return;
+
+       report = ref->report;
+       if (!report)
+               update_one_tracking_ref(remote, ref->name, &ref->new_oid,
+                                       ref->deletion, verbose);
+       else
+               for (; report; report = report->next) {
+                       refname = report->ref_name ? (char *)report->ref_name : ref->name;
+                       new_oid = report->new_oid ? report->new_oid : &ref->new_oid;
+                       update_one_tracking_ref(remote, refname, new_oid,
+                                               is_null_oid(new_oid), verbose);
+               }
+}
+
 static void print_ref_status(char flag, const char *summary,
                             struct ref *to, struct ref *from, const char *msg,
+                            struct ref_push_report *report,
                             int porcelain, int summary_width)
 {
+       const char *to_name;
+
+       if (report && report->ref_name)
+               to_name = report->ref_name;
+       else
+               to_name = to->name;
+
        if (porcelain) {
                if (from)
-                       fprintf(stdout, "%c\t%s:%s\t", flag, from->name, to->name);
+                       fprintf(stdout, "%c\t%s:%s\t", flag, from->name, to_name);
                else
-                       fprintf(stdout, "%c\t:%s\t", flag, to->name);
+                       fprintf(stdout, "%c\t:%s\t", flag, to_name);
                if (msg)
                        fprintf(stdout, "%s (%s)\n", summary, msg);
                else
@@ -481,9 +506,11 @@ static void print_ref_status(char flag, const char *summary,
                fprintf(stderr, " %s%c %-*s%s ", red, flag, summary_width,
                        summary, reset);
                if (from)
-                       fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
+                       fprintf(stderr, "%s -> %s",
+                               prettify_refname(from->name),
+                               prettify_refname(to_name));
                else
-                       fputs(prettify_refname(to->name), stderr);
+                       fputs(prettify_refname(to_name), stderr);
                if (msg) {
                        fputs(" (", stderr);
                        fputs(msg, stderr);
@@ -493,27 +520,52 @@ static void print_ref_status(char flag, const char *summary,
        }
 }
 
-static void print_ok_ref_status(struct ref *ref, int porcelain, int summary_width)
+static void print_ok_ref_status(struct ref *ref,
+                               struct ref_push_report *report,
+                               int porcelain, int summary_width)
 {
+       struct object_id *old_oid;
+       struct object_id *new_oid;
+       const char *ref_name;
+       int forced_update;
+
+       if (report && report->old_oid)
+               old_oid = report->old_oid;
+       else
+               old_oid = &ref->old_oid;
+       if (report && report->new_oid)
+               new_oid = report->new_oid;
+       else
+               new_oid = &ref->new_oid;
+       if (report && report->forced_update)
+               forced_update = report->forced_update;
+       else
+               forced_update = ref->forced_update;
+       if (report && report->ref_name)
+               ref_name = report->ref_name;
+       else
+               ref_name = ref->name;
+
        if (ref->deletion)
                print_ref_status('-', "[deleted]", ref, NULL, NULL,
-                                porcelain, summary_width);
-       else if (is_null_oid(&ref->old_oid))
+                                report, porcelain, summary_width);
+       else if (is_null_oid(old_oid))
                print_ref_status('*',
-                                (starts_with(ref->name, "refs/tags/")
+                                (starts_with(ref_name, "refs/tags/")
                                  ? "[new tag]"
-                                 : (starts_with(ref->name, "refs/heads/")
+                                 : (starts_with(ref_name, "refs/heads/")
                                     ? "[new branch]"
                                     : "[new reference]")),
-                                ref, ref->peer_ref, NULL, porcelain, summary_width);
+                                ref, ref->peer_ref, NULL,
+                                report, porcelain, summary_width);
        else {
                struct strbuf quickref = STRBUF_INIT;
                char type;
                const char *msg;
 
-               strbuf_add_unique_abbrev(&quickref, &ref->old_oid,
+               strbuf_add_unique_abbrev(&quickref, old_oid,
                                         DEFAULT_ABBREV);
-               if (ref->forced_update) {
+               if (forced_update) {
                        strbuf_addstr(&quickref, "...");
                        type = '+';
                        msg = "forced update";
@@ -522,16 +574,17 @@ static void print_ok_ref_status(struct ref *ref, int porcelain, int summary_widt
                        type = ' ';
                        msg = NULL;
                }
-               strbuf_add_unique_abbrev(&quickref, &ref->new_oid,
+               strbuf_add_unique_abbrev(&quickref, new_oid,
                                         DEFAULT_ABBREV);
 
                print_ref_status(type, quickref.buf, ref, ref->peer_ref, msg,
-                                porcelain, summary_width);
+                                report, porcelain, summary_width);
                strbuf_release(&quickref);
        }
 }
 
-static int print_one_push_status(struct ref *ref, const char *dest, int count,
+static int print_one_push_report(struct ref *ref, const char *dest, int count,
+                                struct ref_push_report *report,
                                 int porcelain, int summary_width)
 {
        if (!count) {
@@ -543,65 +596,89 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count,
        switch(ref->status) {
        case REF_STATUS_NONE:
                print_ref_status('X', "[no match]", ref, NULL, NULL,
-                                porcelain, summary_width);
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_NODELETE:
                print_ref_status('!', "[rejected]", ref, NULL,
                                 "remote does not support deleting refs",
-                                porcelain, summary_width);
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_UPTODATE:
                print_ref_status('=', "[up to date]", ref,
-                                ref->peer_ref, NULL, porcelain, summary_width);
+                                ref->peer_ref, NULL,
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_NONFASTFORWARD:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                "non-fast-forward", porcelain, summary_width);
+                                "non-fast-forward",
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_ALREADY_EXISTS:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                "already exists", porcelain, summary_width);
+                                "already exists",
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_FETCH_FIRST:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                "fetch first", porcelain, summary_width);
+                                "fetch first",
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_NEEDS_FORCE:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                "needs force", porcelain, summary_width);
+                                "needs force",
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_STALE:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                "stale info", porcelain, summary_width);
+                                "stale info",
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_REJECT_SHALLOW:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
                                 "new shallow roots not allowed",
-                                porcelain, summary_width);
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_REMOTE_REJECT:
                print_ref_status('!', "[remote rejected]", ref,
                                 ref->deletion ? NULL : ref->peer_ref,
-                                ref->remote_status, porcelain, summary_width);
+                                ref->remote_status,
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_EXPECTING_REPORT:
                print_ref_status('!', "[remote failure]", ref,
                                 ref->deletion ? NULL : ref->peer_ref,
                                 "remote failed to report status",
-                                porcelain, summary_width);
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_ATOMIC_PUSH_FAILED:
                print_ref_status('!', "[rejected]", ref, ref->peer_ref,
-                                "atomic push failed", porcelain, summary_width);
+                                "atomic push failed",
+                                report, porcelain, summary_width);
                break;
        case REF_STATUS_OK:
-               print_ok_ref_status(ref, porcelain, summary_width);
+               print_ok_ref_status(ref, report, porcelain, summary_width);
                break;
        }
 
        return 1;
 }
 
+static int print_one_push_status(struct ref *ref, const char *dest, int count,
+                                int porcelain, int summary_width)
+{
+       struct ref_push_report *report;
+       int n = 0;
+
+       if (!ref->report)
+               return print_one_push_report(ref, dest, count,
+                                            NULL, porcelain, summary_width);
+
+       for (report = ref->report; report; report = report->next)
+               print_one_push_report(ref, dest, count + n++,
+                                     report, porcelain, summary_width);
+       return n;
+}
+
 static int measure_abbrev(const struct object_id *oid, int sofar)
 {
        char hex[GIT_MAX_HEXSZ + 1];
@@ -932,6 +1009,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
        struct transport *ret = xcalloc(1, sizeof(*ret));
 
        ret->progress = isatty(2);
+       string_list_init(&ret->pack_lockfiles, 1);
 
        if (!remote)
                BUG("No remote provided to transport_get()");
@@ -999,9 +1077,16 @@ struct transport *transport_get(struct remote *remote, const char *url)
                        ret->smart_options->receivepack = remote->receivepack;
        }
 
+       ret->hash_algo = &hash_algos[GIT_HASH_SHA1];
+
        return ret;
 }
 
+const struct git_hash_algo *transport_get_hash_algo(struct transport *transport)
+{
+       return transport->hash_algo;
+}
+
 int transport_set_option(struct transport *transport,
                         const char *name, const char *value)
 {
@@ -1149,7 +1234,7 @@ int transport_push(struct repository *r,
                int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
                int pretend = flags & TRANSPORT_PUSH_DRY_RUN;
                int push_ret, ret, err;
-               struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
+               struct strvec ref_prefixes = STRVEC_INIT;
 
                if (check_push_refs(local_refs, rs) < 0)
                        return -1;
@@ -1161,7 +1246,7 @@ int transport_push(struct repository *r,
                                                               &ref_prefixes);
                trace2_region_leave("transport_push", "get_refs_list", r);
 
-               argv_array_clear(&ref_prefixes);
+               strvec_clear(&ref_prefixes);
 
                if (flags & TRANSPORT_PUSH_ALL)
                        match_flags |= MATCH_REFS_ALL;
@@ -1277,7 +1362,7 @@ int transport_push(struct repository *r,
 }
 
 const struct ref *transport_get_remote_refs(struct transport *transport,
-                                           const struct argv_array *ref_prefixes)
+                                           const struct strvec *ref_prefixes)
 {
        if (!transport->got_remote_refs) {
                transport->remote_refs =
@@ -1327,10 +1412,11 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)
 
 void transport_unlock_pack(struct transport *transport)
 {
-       if (transport->pack_lockfile) {
-               unlink_or_warn(transport->pack_lockfile);
-               FREE_AND_NULL(transport->pack_lockfile);
-       }
+       int i;
+
+       for (i = 0; i < transport->pack_lockfiles.nr; i++)
+               unlink_or_warn(transport->pack_lockfiles.items[i].string);
+       string_list_clear(&transport->pack_lockfiles, 0);
 }
 
 int transport_connect(struct transport *transport, const char *name,