diff options
Diffstat (limited to 'transport.c')
-rw-r--r-- | transport.c | 127 |
1 files changed, 79 insertions, 48 deletions
diff --git a/transport.c b/transport.c index 679a35e7c1..e4f1decae2 100644 --- a/transport.c +++ b/transport.c @@ -1,7 +1,7 @@ #include "cache.h" #include "config.h" #include "transport.h" -#include "run-command.h" +#include "hook.h" #include "pkt-line.h" #include "fetch-pack.h" #include "remote.h" @@ -108,11 +108,11 @@ static void set_upstreams(struct transport *transport, struct ref *refs, if (!remotename || !starts_with(remotename, "refs/heads/")) continue; - if (!pretend) - install_branch_config(BRANCH_CONFIG_VERBOSE, - localname + 11, transport->remote->name, - remotename); - else + if (!pretend) { + int flag = transport->verbose < 0 ? 0 : BRANCH_CONFIG_VERBOSE; + install_branch_config(flag, localname + 11, + transport->remote->name, remotename); + } else if (transport->verbose >= 0) printf(_("Would set upstream of '%s' to '%s' of '%s'\n"), localname + 11, remotename + 11, transport->remote->name); @@ -127,7 +127,7 @@ struct bundle_transport_data { static struct ref *get_refs_from_bundle(struct transport *transport, int for_push, - const struct strvec *ref_prefixes) + struct transport_ls_refs_options *transport_options) { struct bundle_transport_data *data = transport->data; struct ref *result = NULL; @@ -147,9 +147,11 @@ static struct ref *get_refs_from_bundle(struct transport *transport, 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); - oidcpy(&ref->old_oid, &e->oid); + struct string_list_item *e = data->header.references.items + i; + const char *name = e->string; + struct ref *ref = alloc_ref(name); + struct object_id *oid = e->util; + oidcpy(&ref->old_oid, oid); ref->next = result; result = ref; } @@ -160,12 +162,16 @@ static int fetch_refs_from_bundle(struct transport *transport, int nr_heads, struct ref **to_fetch) { struct bundle_transport_data *data = transport->data; + struct strvec extra_index_pack_args = STRVEC_INIT; int ret; + if (transport->progress) + strvec_push(&extra_index_pack_args, "-v"); + if (!data->get_refs_from_bundle_called) get_refs_from_bundle(transport, 0, NULL); ret = unbundle(the_repository, &data->header, data->fd, - transport->progress ? BUNDLE_VERBOSE : 0); + &extra_index_pack_args); transport->hash_algo = data->header.hash_algo; return ret; } @@ -175,6 +181,7 @@ static int close_bundle(struct transport *transport) struct bundle_transport_data *data = transport->data; if (data->fd > 0) close(data->fd); + bundle_header_release(&data->header); free(data); return 0; } @@ -236,6 +243,9 @@ static int set_git_option(struct git_transport_options *opts, list_objects_filter_die_if_populated(&opts->filter_options); parse_list_objects_filter(&opts->filter_options, value); return 0; + } else if (!strcmp(name, TRANS_OPT_REJECT_SHALLOW)) { + opts->reject_shallow = !!value; + return 0; } return 1; } @@ -280,7 +290,7 @@ static void die_if_server_options(struct transport *transport) * remote refs. */ static struct ref *handshake(struct transport *transport, int for_push, - const struct strvec *ref_prefixes, + struct transport_ls_refs_options *options, int must_list_refs) { struct git_transport_data *data = transport->data; @@ -303,7 +313,7 @@ static struct ref *handshake(struct transport *transport, int for_push, trace2_data_string("transfer", NULL, "server-sid", server_sid); if (must_list_refs) get_remote_refs(data->fd[1], &reader, &refs, for_push, - ref_prefixes, + options, transport->server_options, transport->stateless_rpc); break; @@ -334,9 +344,9 @@ 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 strvec *ref_prefixes) + struct transport_ls_refs_options *options) { - return handshake(transport, for_push, ref_prefixes, 1); + return handshake(transport, for_push, options, 1); } static int fetch_refs_via_pack(struct transport *transport, @@ -370,6 +380,7 @@ static int fetch_refs_via_pack(struct transport *transport, args.stateless_rpc = transport->stateless_rpc; args.server_options = transport->server_options; args.negotiation_tips = data->options.negotiation_tips; + args.reject_shallow_remote = transport->smart_options->reject_shallow; if (!data->got_remote_heads) { int i; @@ -388,16 +399,29 @@ static int fetch_refs_via_pack(struct transport *transport, else if (data->version <= protocol_v1) die_if_server_options(transport); + if (data->options.acked_commits) { + if (data->version < protocol_v2) { + warning(_("--negotiate-only requires protocol v2")); + ret = -1; + } else if (!server_supports_feature("fetch", "wait-for-done", 0)) { + warning(_("server does not support wait-for-done")); + ret = -1; + } else { + negotiate_using_fetch(data->options.negotiation_tips, + transport->server_options, + transport->stateless_rpc, + data->fd, + data->options.acked_commits); + ret = 0; + } + goto cleanup; + } + 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]); - if (finish_connect(data->conn)) - ret = -1; - data->conn = NULL; data->got_remote_heads = 0; data->options.self_contained_and_connected = args.self_contained_and_connected; @@ -408,6 +432,14 @@ static int fetch_refs_via_pack(struct transport *transport, if (report_unmatched_refs(to_fetch, nr_heads)) ret = -1; +cleanup: + close(data->fd[0]); + if (data->fd[1] >= 0) + close(data->fd[1]); + if (finish_connect(data->conn)) + ret = -1; + data->conn = NULL; + free_refs(refs_tmp); free_refs(refs); return ret; @@ -845,7 +877,8 @@ static int disconnect_git(struct transport *transport) if (data->got_remote_heads && !transport->stateless_rpc) packet_flush(data->fd[1]); close(data->fd[0]); - close(data->fd[1]); + if (data->fd[1] >= 0) + close(data->fd[1]); finish_connect(data->conn); } @@ -854,12 +887,10 @@ static int disconnect_git(struct transport *transport) } static struct transport_vtable taken_over_vtable = { - NULL, - get_refs_via_connect, - fetch_refs_via_pack, - git_transport_push, - NULL, - disconnect_git + .get_refs_list = get_refs_via_connect, + .fetch_refs = fetch_refs_via_pack, + .push_refs = git_transport_push, + .disconnect = disconnect_git }; void transport_take_over(struct transport *transport, @@ -871,7 +902,7 @@ void transport_take_over(struct transport *transport, BUG("taking over transport requires non-NULL " "smart_options field."); - data = xcalloc(1, sizeof(*data)); + CALLOC_ARRAY(data, 1); data->options = *transport->smart_options; data->conn = child; data->fd[0] = data->conn->out; @@ -1003,21 +1034,17 @@ void transport_check_allowed(const char *type) } static struct transport_vtable bundle_vtable = { - NULL, - get_refs_from_bundle, - fetch_refs_from_bundle, - NULL, - NULL, - close_bundle + .get_refs_list = get_refs_from_bundle, + .fetch_refs = fetch_refs_from_bundle, + .disconnect = close_bundle }; static struct transport_vtable builtin_smart_vtable = { - NULL, - get_refs_via_connect, - fetch_refs_via_pack, - git_transport_push, - connect_git, - disconnect_git + .get_refs_list = get_refs_via_connect, + .fetch_refs = fetch_refs_via_pack, + .push_refs = git_transport_push, + .connect = connect_git, + .disconnect = disconnect_git }; struct transport *transport_get(struct remote *remote, const char *url) @@ -1026,7 +1053,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); + string_list_init_dup(&ret->pack_lockfiles); if (!remote) BUG("No remote provided to transport_get()"); @@ -1055,6 +1082,7 @@ struct transport *transport_get(struct remote *remote, const char *url) die(_("git-over-rsync is no longer supported")); } else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) { struct bundle_transport_data *data = xcalloc(1, sizeof(*data)); + bundle_header_init(&data->header); transport_check_allowed("file"); ret->data = data; ret->vtable = &bundle_vtable; @@ -1252,19 +1280,20 @@ 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 strvec ref_prefixes = STRVEC_INIT; + struct transport_ls_refs_options transport_options = + TRANSPORT_LS_REFS_OPTIONS_INIT; if (check_push_refs(local_refs, rs) < 0) return -1; - refspec_ref_prefixes(rs, &ref_prefixes); + refspec_ref_prefixes(rs, &transport_options.ref_prefixes); trace2_region_enter("transport_push", "get_refs_list", r); remote_refs = transport->vtable->get_refs_list(transport, 1, - &ref_prefixes); + &transport_options); trace2_region_leave("transport_push", "get_refs_list", r); - strvec_clear(&ref_prefixes); + strvec_clear(&transport_options.ref_prefixes); if (flags & TRANSPORT_PUSH_ALL) match_flags |= MATCH_REFS_ALL; @@ -1380,12 +1409,12 @@ int transport_push(struct repository *r, } const struct ref *transport_get_remote_refs(struct transport *transport, - const struct strvec *ref_prefixes) + struct transport_ls_refs_options *transport_options) { if (!transport->got_remote_refs) { transport->remote_refs = transport->vtable->get_refs_list(transport, 0, - ref_prefixes); + transport_options); transport->got_remote_refs = 1; } @@ -1422,7 +1451,7 @@ 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_refs(transport, nr_heads, heads); free(heads); return rc; @@ -1451,6 +1480,8 @@ int transport_disconnect(struct transport *transport) int ret = 0; if (transport->vtable->disconnect) ret = transport->vtable->disconnect(transport); + if (transport->got_remote_refs) + free_refs((void *)transport->remote_refs); free(transport); return ret; } |