#include "fetch-pack.h"
#include "refs.h"
#include "refspec.h"
+#include "object-store.h"
#include "tree.h"
#include "tree-walk.h"
#include "unpack-trees.h"
install_branch_config(0, head, option_origin, our->name);
}
} else if (our) {
- struct commit *c = lookup_commit_reference(&our->old_oid);
+ struct commit *c = lookup_commit_reference(the_repository,
+ &our->old_oid);
/* --branch specifies a non-branch (i.e. tags), detach HEAD */
update_ref(msg, "HEAD", &c->object.oid, NULL, REF_NO_DEREF,
UPDATE_REFS_DIE_ON_ERR);
int err = 0, complete_refs_before_fetch = 1;
int submodule_progress;
- struct refspec_item refspec;
+ struct refspec rs = REFSPEC_INIT_FETCH;
+ struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
fetch_if_missing = 0;
if (option_required_reference.nr || option_optional_reference.nr)
setup_reference();
- refspec_item_init(&refspec, value.buf, REFSPEC_FETCH);
+ refspec_append(&rs, value.buf);
strbuf_reset(&value);
if (transport->smart_options && !deepen && !filter_options.choice)
transport->smart_options->check_self_contained_and_connected = 1;
- refs = transport_get_remote_refs(transport, NULL);
+
+ argv_array_push(&ref_prefixes, "HEAD");
+ refspec_ref_prefixes(&rs, &ref_prefixes);
+ if (option_branch)
+ expand_ref_prefix(&ref_prefixes, option_branch);
+ if (!option_no_tags)
+ argv_array_push(&ref_prefixes, "refs/tags/");
+
+ refs = transport_get_remote_refs(transport, &ref_prefixes);
if (refs) {
- mapped_refs = wanted_peer_refs(refs, &refspec);
+ mapped_refs = wanted_peer_refs(refs, &rs.items[0]);
/*
* transport_get_remote_refs() may return refs with null sha-1
* in mapped_refs (see struct transport->get_refs_list
}
if (!is_local && !complete_refs_before_fetch)
- transport_fetch_refs(transport, mapped_refs, NULL);
+ transport_fetch_refs(transport, mapped_refs);
remote_head = find_ref_by_name(refs, "HEAD");
remote_head_points_at =
if (is_local)
clone_local(path, git_dir);
else if (refs && complete_refs_before_fetch)
- transport_fetch_refs(transport, mapped_refs, NULL);
+ transport_fetch_refs(transport, mapped_refs);
update_remote_refs(refs, mapped_refs, remote_head_points_at,
branch_top.buf, reflog_msg.buf, transport,
- !is_local && !filter_options.choice);
+ !is_local);
update_head(our_head_points_at, remote_head, reflog_msg.buf);
strbuf_release(&value);
junk_mode = JUNK_LEAVE_ALL;
- refspec_item_clear(&refspec);
+ refspec_clear(&rs);
+ argv_array_clear(&ref_prefixes);
return err;
}
#include "repository.h"
#include "refs.h"
#include "refspec.h"
+#include "object-store.h"
#include "commit.h"
#include "builtin.h"
#include "string-list.h"
static struct refspec refmap = REFSPEC_INIT_FETCH;
static struct list_objects_filter_options filter_options;
static struct string_list server_options = STRING_LIST_INIT_DUP;
+static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
static int git_fetch_config(const char *k, const char *v, void *cb)
{
return git_default_config(k, v, cb);
}
-static int gitmodules_fetch_config(const char *var, const char *value, void *cb)
-{
- if (!strcmp(var, "submodule.fetchjobs")) {
- max_children = parse_submodule_fetchjobs(var, value);
- return 0;
- } else if (!strcmp(var, "fetch.recursesubmodules")) {
- recurse_submodules = parse_fetch_recurse_submodules_arg(var, value);
- return 0;
- }
-
- return 0;
-}
-
static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
{
/*
TRANSPORT_FAMILY_IPV4),
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
TRANSPORT_FAMILY_IPV6),
+ OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"),
+ N_("report that we have only objects reachable from this object")),
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
OPT_END()
};
return r;
}
- current = lookup_commit_reference_gently(&ref->old_oid, 1);
- updated = lookup_commit_reference_gently(&ref->new_oid, 1);
+ current = lookup_commit_reference_gently(the_repository,
+ &ref->old_oid, 1);
+ updated = lookup_commit_reference_gently(the_repository,
+ &ref->new_oid, 1);
if (!current || !updated) {
const char *msg;
const char *what;
const char *what, *kind;
struct ref *rm;
char *url;
- const char *filename = dry_run ? "/dev/null" : git_path_fetch_head();
+ const char *filename = dry_run ? "/dev/null" : git_path_fetch_head(the_repository);
int want_status;
int summary_width = transport_summary_width(ref_map);
continue;
}
- commit = lookup_commit_reference_gently(&rm->old_oid,
+ commit = lookup_commit_reference_gently(the_repository,
+ &rm->old_oid,
1);
if (!commit)
rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
return check_connected(iterate_ref_map, &rm, &opt);
}
- static int fetch_refs(struct transport *transport, struct ref *ref_map,
- struct ref **updated_remote_refs)
+ static int fetch_refs(struct transport *transport, struct ref *ref_map)
{
int ret = quickfetch(ref_map);
if (ret)
- ret = transport_fetch_refs(transport, ref_map,
- updated_remote_refs);
+ ret = transport_fetch_refs(transport, ref_map);
if (!ret)
/*
* Keep the new pack's ".keep" file around to allow the caller
static int truncate_fetch_head(void)
{
- const char *filename = git_path_fetch_head();
+ const char *filename = git_path_fetch_head(the_repository);
FILE *fp = fopen_for_writing(filename);
if (!fp)
name, transport->url);
}
+
+static int add_oid(const char *refname, const struct object_id *oid, int flags,
+ void *cb_data)
+{
+ struct oid_array *oids = cb_data;
+
+ oid_array_append(oids, oid);
+ return 0;
+}
+
+static void add_negotiation_tips(struct git_transport_options *smart_options)
+{
+ struct oid_array *oids = xcalloc(1, sizeof(*oids));
+ int i;
+
+ for (i = 0; i < negotiation_tip.nr; i++) {
+ const char *s = negotiation_tip.items[i].string;
+ int old_nr;
+ if (!has_glob_specials(s)) {
+ struct object_id oid;
+ if (get_oid(s, &oid))
+ die("%s is not a valid object", s);
+ oid_array_append(oids, &oid);
+ continue;
+ }
+ old_nr = oids->nr;
+ for_each_glob_ref(add_oid, s, oids);
+ if (old_nr == oids->nr)
+ warning("Ignoring --negotiation-tip=%s because it does not match any refs",
+ s);
+ }
+ smart_options->negotiation_tips = oids;
+}
+
static struct transport *prepare_transport(struct remote *remote, int deepen)
{
struct transport *transport;
filter_options.filter_spec);
set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
}
+ if (negotiation_tip.nr) {
+ if (transport->smart_options)
+ add_negotiation_tips(transport->smart_options);
+ else
+ warning("Ignoring --negotiation-tip because the protocol does not support it.");
+ }
return transport;
}
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
transport_set_option(transport, TRANS_OPT_DEPTH, "0");
transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);
- if (!fetch_refs(transport, ref_map, NULL))
+ if (!fetch_refs(transport, ref_map))
consume_refs(transport, ref_map);
if (gsecondary) {
int autotags = (transport->remote->fetch_tags == 1);
int retcode = 0;
const struct ref *remote_refs;
- struct ref *updated_remote_refs = NULL;
struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
if (tags == TAGS_DEFAULT) {
refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes);
if (ref_prefixes.argc &&
- (tags == TAGS_SET || (tags == TAGS_DEFAULT && !rs->nr))) {
+ (tags == TAGS_SET || (tags == TAGS_DEFAULT))) {
argv_array_push(&ref_prefixes, "refs/tags/");
}
transport->url);
}
}
-
- if (fetch_refs(transport, ref_map, &updated_remote_refs)) {
- free_refs(ref_map);
- retcode = 1;
- goto cleanup;
- }
- if (updated_remote_refs) {
- /*
- * Regenerate ref_map using the updated remote refs. This is
- * to account for additional information which may be provided
- * by the transport (e.g. shallow info).
- */
- free_refs(ref_map);
- ref_map = get_ref_map(transport->remote, updated_remote_refs, rs,
- tags, &autotags);
- free_refs(updated_remote_refs);
- }
- if (consume_refs(transport, ref_map)) {
+ if (fetch_refs(transport, ref_map) || consume_refs(transport, ref_map)) {
free_refs(ref_map);
retcode = 1;
goto cleanup;
for (i = 1; i < argc; i++)
strbuf_addf(&default_rla, " %s", argv[i]);
- config_from_gitmodules(gitmodules_fetch_config, NULL);
+ fetch_config_from_gitmodules(&max_children, &recurse_submodules);
git_config(git_fetch_config, NULL);
argc = parse_options(argc, argv, prefix,
if (unshallow) {
if (depth)
die(_("--depth and --unshallow cannot be used together"));
- else if (!is_repository_shallow())
+ else if (!is_repository_shallow(the_repository))
die(_("--unshallow on a complete repository does not make sense"));
else
depth = xstrfmt("%d", INFINITE_DEPTH);
#include "connect.h"
#include "transport.h"
#include "version.h"
-#include "prio-queue.h"
#include "sha1-array.h"
#include "oidset.h"
#include "packfile.h"
+#include "object-store.h"
#include "connected.h"
+#include "fetch-negotiator.h"
static int transfer_unpack_limit = -1;
static int fetch_unpack_limit = -1;
static int server_supports_filtering;
static struct lock_file shallow_lock;
static const char *alternate_shallow_file;
+static char *negotiation_algorithm;
/* Remember to update object flag allocation in object.h */
#define COMPLETE (1U << 0)
-#define COMMON (1U << 1)
-#define COMMON_REF (1U << 2)
-#define SEEN (1U << 3)
-#define POPPED (1U << 4)
-#define ALTERNATE (1U << 5)
-
-static int marked;
+#define ALTERNATE (1U << 1)
/*
* After sending this many "have"s if we do not get any new ACK , we
*/
#define MAX_IN_VAIN 256
-static struct prio_queue rev_list = { compare_commits_by_commit_date };
-static int non_common_revs, multi_ack, use_sideband;
+static int multi_ack, use_sideband;
/* Allow specifying sha1 if it is a ref tip. */
#define ALLOW_TIP_SHA1 01
/* Allow request of a sha1 if it is reachable from a ref (possibly hidden ref). */
void *vcache)
{
struct alternate_object_cache *cache = vcache;
- struct object *obj = parse_object(oid);
+ struct object *obj = parse_object(the_repository, oid);
if (!obj || (obj->flags & ALTERNATE))
return;
cache->items[cache->nr++] = obj;
}
-static void for_each_cached_alternate(void (*cb)(struct object *))
+static void for_each_cached_alternate(struct fetch_negotiator *negotiator,
+ void (*cb)(struct fetch_negotiator *,
+ struct object *))
{
static int initialized;
static struct alternate_object_cache cache;
}
for (i = 0; i < cache.nr; i++)
- cb(cache.items[i]);
+ cb(negotiator, cache.items[i]);
}
-static void rev_list_push(struct commit *commit, int mark)
+static int rev_list_insert_ref(struct fetch_negotiator *negotiator,
+ const char *refname,
+ const struct object_id *oid)
{
- if (!(commit->object.flags & mark)) {
- commit->object.flags |= mark;
-
- if (parse_commit(commit))
- return;
-
- prio_queue_put(&rev_list, commit);
-
- if (!(commit->object.flags & COMMON))
- non_common_revs++;
- }
-}
-
-static int rev_list_insert_ref(const char *refname, const struct object_id *oid)
-{
- struct object *o = deref_tag(parse_object(oid), refname, 0);
+ struct object *o = deref_tag(the_repository,
+ parse_object(the_repository, oid),
+ refname, 0);
if (o && o->type == OBJ_COMMIT)
- rev_list_push((struct commit *)o, SEEN);
+ negotiator->add_tip(negotiator, (struct commit *)o);
return 0;
}
static int rev_list_insert_ref_oid(const char *refname, const struct object_id *oid,
int flag, void *cb_data)
{
- return rev_list_insert_ref(refname, oid);
-}
-
-static int clear_marks(const char *refname, const struct object_id *oid,
- int flag, void *cb_data)
-{
- struct object *o = deref_tag(parse_object(oid), refname, 0);
-
- if (o && o->type == OBJ_COMMIT)
- clear_commit_marks((struct commit *)o,
- COMMON | COMMON_REF | SEEN | POPPED);
- return 0;
-}
-
-/*
- This function marks a rev and its ancestors as common.
- In some cases, it is desirable to mark only the ancestors (for example
- when only the server does not yet know that they are common).
-*/
-
-static void mark_common(struct commit *commit,
- int ancestors_only, int dont_parse)
-{
- if (commit != NULL && !(commit->object.flags & COMMON)) {
- struct object *o = (struct object *)commit;
-
- if (!ancestors_only)
- o->flags |= COMMON;
-
- if (!(o->flags & SEEN))
- rev_list_push(commit, SEEN);
- else {
- struct commit_list *parents;
-
- if (!ancestors_only && !(o->flags & POPPED))
- non_common_revs--;
- if (!o->parsed && !dont_parse)
- if (parse_commit(commit))
- return;
-
- for (parents = commit->parents;
- parents;
- parents = parents->next)
- mark_common(parents->item, 0, dont_parse);
- }
- }
-}
-
-/*
- Get the next rev to send, ignoring the common.
-*/
-
-static const struct object_id *get_rev(void)
-{
- struct commit *commit = NULL;
-
- while (commit == NULL) {
- unsigned int mark;
- struct commit_list *parents;
-
- if (rev_list.nr == 0 || non_common_revs == 0)
- return NULL;
-
- commit = prio_queue_get(&rev_list);
- parse_commit(commit);
- parents = commit->parents;
-
- commit->object.flags |= POPPED;
- if (!(commit->object.flags & COMMON))
- non_common_revs--;
-
- if (commit->object.flags & COMMON) {
- /* do not send "have", and ignore ancestors */
- commit = NULL;
- mark = COMMON | SEEN;
- } else if (commit->object.flags & COMMON_REF)
- /* send "have", and ignore ancestors */
- mark = COMMON | SEEN;
- else
- /* send "have", also for its ancestors */
- mark = SEEN;
-
- while (parents) {
- if (!(parents->item->object.flags & SEEN))
- rev_list_push(parents->item, mark);
- if (mark & COMMON)
- mark_common(parents->item, 1, 0);
- parents = parents->next;
- }
- }
-
- return &commit->object.oid;
+ return rev_list_insert_ref(cb_data, refname, oid);
}
enum ack_type {
write_or_die(fd, buf->buf, buf->len);
}
-static void insert_one_alternate_object(struct object *obj)
+static void insert_one_alternate_object(struct fetch_negotiator *negotiator,
+ struct object *obj)
{
- rev_list_insert_ref(NULL, &obj->oid);
+ rev_list_insert_ref(negotiator, NULL, &obj->oid);
}
#define INITIAL_FLUSH 16
return count;
}
-static int find_common(struct fetch_pack_args *args,
+static void mark_tips(struct fetch_negotiator *negotiator,
+ const struct oid_array *negotiation_tips)
+{
+ int i;
+
+ if (!negotiation_tips) {
+ for_each_ref(rev_list_insert_ref_oid, negotiator);
+ return;
+ }
+
+ for (i = 0; i < negotiation_tips->nr; i++)
+ rev_list_insert_ref(negotiator, NULL,
+ &negotiation_tips->oid[i]);
+ return;
+}
+
+static int find_common(struct fetch_negotiator *negotiator,
+ struct fetch_pack_args *args,
int fd[2], struct object_id *result_oid,
struct ref *refs)
{
if (args->stateless_rpc && multi_ack == 1)
die(_("--stateless-rpc requires multi_ack_detailed"));
- if (marked)
- for_each_ref(clear_marks, NULL);
- marked = 1;
- for_each_ref(rev_list_insert_ref_oid, NULL);
- for_each_cached_alternate(insert_one_alternate_object);
+ mark_tips(negotiator, args->negotiation_tips);
+ for_each_cached_alternate(negotiator, insert_one_alternate_object);
fetching = 0;
for ( ; refs ; refs = refs->next) {
* interested in the case we *know* the object is
* reachable and we have already scanned it.
*/
- if (((o = lookup_object(remote->hash)) != NULL) &&
+ if (((o = lookup_object(the_repository, remote->hash)) != NULL) &&
(o->flags & COMPLETE)) {
continue;
}
return 1;
}
- if (is_repository_shallow())
+ if (is_repository_shallow(the_repository))
write_shallow_commits(&req_buf, 1, NULL);
if (args->depth > 0)
packet_buf_write(&req_buf, "deepen %d", args->depth);
if (skip_prefix(line, "shallow ", &arg)) {
if (get_oid_hex(arg, &oid))
die(_("invalid shallow line: %s"), line);
- register_shallow(&oid);
+ register_shallow(the_repository, &oid);
continue;
}
if (skip_prefix(line, "unshallow ", &arg)) {
if (get_oid_hex(arg, &oid))
die(_("invalid unshallow line: %s"), line);
- if (!lookup_object(oid.hash))
+ if (!lookup_object(the_repository, oid.hash))
die(_("object not found: %s"), line);
/* make sure that it is parsed as shallow */
- if (!parse_object(&oid))
+ if (!parse_object(the_repository, &oid))
die(_("error in object: %s"), line);
if (unregister_shallow(&oid))
die(_("no shallow found: %s"), line);
retval = -1;
if (args->no_dependents)
goto done;
- while ((oid = get_rev())) {
+ while ((oid = negotiator->next(negotiator))) {
packet_buf_write(&req_buf, "have %s\n", oid_to_hex(oid));
print_verbose(args, "have %s", oid_to_hex(oid));
in_vain++;
case ACK_ready:
case ACK_continue: {
struct commit *commit =
- lookup_commit(result_oid);
+ lookup_commit(the_repository,
+ result_oid);
+ int was_common;
+
if (!commit)
die(_("invalid commit %s"), oid_to_hex(result_oid));
+ was_common = negotiator->ack(negotiator, commit);
if (args->stateless_rpc
&& ack == ACK_common
- && !(commit->object.flags & COMMON)) {
+ && !was_common) {
/* We need to replay the have for this object
* on the next RPC request so the peer knows
* it is in common with us.
} else if (!args->stateless_rpc
|| ack != ACK_common)
in_vain = 0;
- mark_common(commit, 0, 1);
retval = 0;
got_continue = 1;
- if (ack == ACK_ready) {
- clear_prio_queue(&rev_list);
+ if (ack == ACK_ready)
got_ready = 1;
- }
break;
}
}
print_verbose(args, _("giving up"));
break; /* give up */
}
+ if (got_ready)
+ break;
}
}
done:
static int mark_complete(const struct object_id *oid)
{
- struct object *o = parse_object(oid);
+ struct object *o = parse_object(the_repository, oid);
while (o && o->type == OBJ_TAG) {
struct tag *t = (struct tag *) o;
if (!t->tagged)
break; /* broken repository */
o->flags |= COMPLETE;
- o = parse_object(&t->tagged->oid);
+ o = parse_object(the_repository, &t->tagged->oid);
}
if (o && o->type == OBJ_COMMIT) {
struct commit *commit = (struct commit *)o;
}
i++;
}
- }
- if (!keep && args->fetch_all &&
- (!args->deepen || !starts_with(ref->name, "refs/tags/")))
- keep = 1;
+ if (!keep && args->fetch_all &&
+ (!args->deepen || !starts_with(ref->name, "refs/tags/")))
+ keep = 1;
+ }
if (keep) {
*newtail = ref;
*refs = newlist;
}
-static void mark_alternate_complete(struct object *obj)
+static void mark_alternate_complete(struct fetch_negotiator *unused,
+ struct object *obj)
{
mark_complete(&obj->oid);
}
return 0;
}
-static int everything_local(struct fetch_pack_args *args,
- struct ref **refs,
- struct ref **sought, int nr_sought)
+/*
+ * Mark recent commits available locally and reachable from a local ref as
+ * COMPLETE. If args->no_dependents is false, also mark COMPLETE remote refs as
+ * COMMON_REF (otherwise, we are not planning to participate in negotiation, and
+ * thus do not need COMMON_REF marks).
+ *
+ * The cutoff time for recency is determined by this heuristic: it is the
+ * earliest commit time of the objects in refs that are commits and that we know
+ * the commit time of.
+ */
+static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
+ struct fetch_pack_args *args,
+ struct ref **refs)
{
struct ref *ref;
- int retval;
int old_save_commit_buffer = save_commit_buffer;
timestamp_t cutoff = 0;
struct oidset loose_oid_set = OIDSET_INIT;
if (!has_object_file_with_flags(&ref->old_oid, flags))
continue;
- o = parse_object(&ref->old_oid);
+ o = parse_object(the_repository, &ref->old_oid);
if (!o)
continue;
if (!args->no_dependents) {
if (!args->deepen) {
for_each_ref(mark_complete_oid, NULL);
- for_each_cached_alternate(mark_alternate_complete);
+ for_each_cached_alternate(NULL, mark_alternate_complete);
commit_list_sort_by_date(&complete);
if (cutoff)
mark_recent_complete_commits(args, cutoff);
* Don't mark them common yet; the server has to be told so first.
*/
for (ref = *refs; ref; ref = ref->next) {
- struct object *o = deref_tag(lookup_object(ref->old_oid.hash),
+ struct object *o = deref_tag(the_repository,
+ lookup_object(the_repository,
+ ref->old_oid.hash),
NULL, 0);
if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE))
continue;
- if (!(o->flags & SEEN)) {
- rev_list_push((struct commit *)o, COMMON_REF | SEEN);
-
- mark_common((struct commit *)o, 1, 1);
- }
+ negotiator->known_common(negotiator,
+ (struct commit *)o);
}
}
- filter_refs(args, refs, sought, nr_sought);
+ save_commit_buffer = old_save_commit_buffer;
+}
+
+/*
+ * Returns 1 if every object pointed to by the given remote refs is available
+ * locally and reachable from a local ref, and 0 otherwise.
+ */
+static int everything_local(struct fetch_pack_args *args,
+ struct ref **refs)
+{
+ struct ref *ref;
+ int retval;
for (retval = 1, ref = *refs; ref ; ref = ref->next) {
const struct object_id *remote = &ref->old_oid;
struct object *o;
- o = lookup_object(remote->hash);
+ o = lookup_object(the_repository, remote->hash);
if (!o || !(o->flags & COMPLETE)) {
retval = 0;
print_verbose(args, "want %s (%s)", oid_to_hex(remote),
ref->name);
}
- save_commit_buffer = old_save_commit_buffer;
-
return retval;
}
struct object_id oid;
const char *agent_feature;
int agent_len;
+ struct fetch_negotiator negotiator;
+ fetch_negotiator_init(&negotiator, negotiation_algorithm);
sort_ref_list(&ref, ref_compare_name);
QSORT(sought, nr_sought, cmp_ref_by_name);
- if ((args->depth > 0 || is_repository_shallow()) && !server_supports("shallow"))
+ if ((args->depth > 0 || is_repository_shallow(the_repository)) && !server_supports("shallow"))
die(_("Server does not support shallow clients"));
if (args->depth > 0 || args->deepen_since || args->deepen_not)
args->deepen = 1;
if (!server_supports("deepen-relative") && args->deepen_relative)
die(_("Server does not support --deepen"));
- if (everything_local(args, &ref, sought, nr_sought)) {
+ mark_complete_and_common_ref(&negotiator, args, &ref);
+ filter_refs(args, &ref, sought, nr_sought);
+ if (everything_local(args, &ref)) {
packet_flush(fd[1]);
goto all_done;
}
- if (find_common(args, fd, &oid, ref) < 0)
+ if (find_common(&negotiator, args, fd, &oid, ref) < 0)
if (!args->keep_pack)
/* When cloning, it is not unusual to have
* no common commit.
die(_("git fetch-pack: fetch failed."));
all_done:
+ negotiator.release(&negotiator);
return ref;
}
static void add_shallow_requests(struct strbuf *req_buf,
const struct fetch_pack_args *args)
{
- if (is_repository_shallow())
+ if (is_repository_shallow(the_repository))
write_shallow_commits(req_buf, 1, NULL);
if (args->depth > 0)
packet_buf_write(req_buf, "deepen %d", args->depth);
* interested in the case we *know* the object is
* reachable and we have already scanned it.
*/
- if (((o = lookup_object(remote->hash)) != NULL) &&
+ if (((o = lookup_object(the_repository, remote->hash)) != NULL) &&
(o->flags & COMPLETE)) {
continue;
}
}
}
-static int add_haves(struct strbuf *req_buf, int *haves_to_send, int *in_vain)
+static int add_haves(struct fetch_negotiator *negotiator,
+ struct strbuf *req_buf,
+ int *haves_to_send, int *in_vain)
{
int ret = 0;
int haves_added = 0;
const struct object_id *oid;
- while ((oid = get_rev())) {
+ while ((oid = negotiator->next(negotiator))) {
packet_buf_write(req_buf, "have %s\n", oid_to_hex(oid));
if (++haves_added >= *haves_to_send)
break;
return ret;
}
-static int send_fetch_request(int fd_out, const struct fetch_pack_args *args,
+static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
+ const struct fetch_pack_args *args,
const struct ref *wants, struct oidset *common,
int *haves_to_send, int *in_vain)
{
/* Add shallow-info and deepen request */
if (server_supports_feature("fetch", "shallow", 0))
add_shallow_requests(&req_buf, args);
- else if (is_repository_shallow() || args->deepen)
+ else if (is_repository_shallow(the_repository) || args->deepen)
die(_("Server does not support shallow requests"));
/* Add filter */
add_common(&req_buf, common);
/* Add initial haves */
- ret = add_haves(&req_buf, haves_to_send, in_vain);
+ ret = add_haves(negotiator, &req_buf, haves_to_send, in_vain);
}
/* Send request */
int ret;
if (packet_reader_peek(reader) != PACKET_READ_NORMAL)
- die("error reading section header '%s'", section);
+ die(_("error reading section header '%s'"), section);
ret = !strcmp(reader->line, section);
if (!peek) {
if (!ret)
- die("expected '%s', received '%s'",
+ die(_("expected '%s', received '%s'"),
section, reader->line);
packet_reader_read(reader);
}
return ret;
}
-static int process_acks(struct packet_reader *reader, struct oidset *common)
+static int process_acks(struct fetch_negotiator *negotiator,
+ struct packet_reader *reader,
+ struct oidset *common)
{
/* received */
int received_ready = 0;
if (!get_oid_hex(arg, &oid)) {
struct commit *commit;
oidset_insert(common, &oid);
- commit = lookup_commit(&oid);
- mark_common(commit, 0, 1);
+ commit = lookup_commit(the_repository, &oid);
+ negotiator->ack(negotiator, commit);
}
continue;
}
if (!strcmp(reader->line, "ready")) {
- clear_prio_queue(&rev_list);
received_ready = 1;
continue;
}
- die("unexpected acknowledgment line: '%s'", reader->line);
+ die(_("unexpected acknowledgment line: '%s'"), reader->line);
}
if (reader->status != PACKET_READ_FLUSH &&
reader->status != PACKET_READ_DELIM)
- die("error processing acks: %d", reader->status);
+ die(_("error processing acks: %d"), reader->status);
/* return 0 if no common, 1 if there are common, or 2 if ready */
return received_ready ? 2 : (received_ack ? 1 : 0);
if (skip_prefix(reader->line, "shallow ", &arg)) {
if (get_oid_hex(arg, &oid))
die(_("invalid shallow line: %s"), reader->line);
- register_shallow(&oid);
+ register_shallow(the_repository, &oid);
continue;
}
if (skip_prefix(reader->line, "unshallow ", &arg)) {
if (get_oid_hex(arg, &oid))
die(_("invalid unshallow line: %s"), reader->line);
- if (!lookup_object(oid.hash))
+ if (!lookup_object(the_repository, oid.hash))
die(_("object not found: %s"), reader->line);
/* make sure that it is parsed as shallow */
- if (!parse_object(&oid))
+ if (!parse_object(the_repository, &oid))
die(_("error in object: %s"), reader->line);
if (unregister_shallow(&oid))
die(_("no shallow found: %s"), reader->line);
if (reader->status != PACKET_READ_FLUSH &&
reader->status != PACKET_READ_DELIM)
- die("error processing shallow info: %d", reader->status);
+ die(_("error processing shallow info: %d"), reader->status);
setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, NULL);
args->deepen = 1;
}
- static void receive_wanted_refs(struct packet_reader *reader, struct ref *refs)
+ static void receive_wanted_refs(struct packet_reader *reader,
+ struct ref **sought, int nr_sought)
{
process_section_header(reader, "wanted-refs", 0);
while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
struct object_id oid;
const char *end;
- struct ref *r = NULL;
+ int i;
if (parse_oid_hex(reader->line, &oid, &end) || *end++ != ' ')
- die("expected wanted-ref, got '%s'", reader->line);
+ die(_("expected wanted-ref, got '%s'"), reader->line);
- for (r = refs; r; r = r->next) {
- if (!strcmp(end, r->name)) {
- oidcpy(&r->old_oid, &oid);
+ for (i = 0; i < nr_sought; i++) {
+ if (!strcmp(end, sought[i]->name)) {
+ oidcpy(&sought[i]->old_oid, &oid);
break;
}
}
- if (!r)
+ if (i == nr_sought)
- die("unexpected wanted-ref: '%s'", reader->line);
+ die(_("unexpected wanted-ref: '%s'"), reader->line);
}
if (reader->status != PACKET_READ_DELIM)
- die("error processing wanted refs: %d", reader->status);
+ die(_("error processing wanted refs: %d"), reader->status);
}
enum fetch_state {
struct packet_reader reader;
int in_vain = 0;
int haves_to_send = INITIAL_FLUSH;
+ struct fetch_negotiator negotiator;
+ fetch_negotiator_init(&negotiator, negotiation_algorithm);
packet_reader_init(&reader, fd[0], NULL, 0,
PACKET_READ_CHOMP_NEWLINE);
if (args->depth > 0 || args->deepen_since || args->deepen_not)
args->deepen = 1;
- if (marked)
- for_each_ref(clear_marks, NULL);
- marked = 1;
-
- for_each_ref(rev_list_insert_ref_oid, NULL);
- for_each_cached_alternate(insert_one_alternate_object);
-
/* Filter 'ref' by 'sought' and those that aren't local */
- if (everything_local(args, &ref, sought, nr_sought))
+ mark_complete_and_common_ref(&negotiator, args, &ref);
+ filter_refs(args, &ref, sought, nr_sought);
+ if (everything_local(args, &ref))
state = FETCH_DONE;
else
state = FETCH_SEND_REQUEST;
+
+ mark_tips(&negotiator, args->negotiation_tips);
+ for_each_cached_alternate(&negotiator,
+ insert_one_alternate_object);
break;
case FETCH_SEND_REQUEST:
- if (send_fetch_request(fd[1], args, ref, &common,
+ if (send_fetch_request(&negotiator, fd[1], args, ref,
+ &common,
&haves_to_send, &in_vain))
state = FETCH_GET_PACK;
else
break;
case FETCH_PROCESS_ACKS:
/* Process ACKs/NAKs */
- switch (process_acks(&reader, &common)) {
+ switch (process_acks(&negotiator, &reader, &common)) {
case 2:
state = FETCH_GET_PACK;
break;
receive_shallow_info(args, &reader);
if (process_section_header(&reader, "wanted-refs", 1))
- receive_wanted_refs(&reader, ref);
+ receive_wanted_refs(&reader, sought, nr_sought);
/* get the pack */
process_section_header(&reader, "packfile", 0);
}
}
+ negotiator.release(&negotiator);
oidset_clear(&common);
return ref;
}
git_config_get_bool("repack.usedeltabaseoffset", &prefer_ofs_delta);
git_config_get_bool("fetch.fsckobjects", &fetch_fsck_objects);
git_config_get_bool("transfer.fsckobjects", &transfer_fsck_objects);
+ git_config_get_string("fetch.negotiationalgorithm",
+ &negotiation_algorithm);
git_config(git_default_config, NULL);
}
}
static void update_shallow(struct fetch_pack_args *args,
- struct ref *refs,
+ struct ref **sought, int nr_sought,
struct shallow_info *si)
{
struct oid_array ref = OID_ARRAY_INIT;
int *status;
int i;
- struct ref *r;
if (args->deepen && alternate_shallow_file) {
if (*alternate_shallow_file == '\0') { /* --unshallow */
- unlink_or_warn(git_path_shallow());
+ unlink_or_warn(git_path_shallow(the_repository));
rollback_lock_file(&shallow_lock);
} else
commit_lock_file(&shallow_lock);
remove_nonexistent_theirs_shallow(si);
if (!si->nr_ours && !si->nr_theirs)
return;
- for (r = refs; r; r = r->next)
- oid_array_append(&ref, &r->old_oid);
+ for (i = 0; i < nr_sought; i++)
+ oid_array_append(&ref, &sought[i]->old_oid);
si->ref = &ref;
if (args->update_shallow) {
* remote is also shallow, check what ref is safe to update
* without updating .git/shallow
*/
- status = xcalloc(ref.nr, sizeof(*status));
+ status = xcalloc(nr_sought, sizeof(*status));
assign_shallow_commits_to_refs(si, NULL, status);
if (si->nr_ours || si->nr_theirs) {
- for (r = refs, i = 0; r; r = r->next, i++)
+ for (i = 0; i < nr_sought; i++)
if (status[i])
- r->status = REF_STATUS_REJECT_SHALLOW;
+ sought[i]->status = REF_STATUS_REJECT_SHALLOW;
}
free(status);
oid_array_clear(&ref);
args->connectivity_checked = 1;
}
- update_shallow(args, ref_cpy, &si);
+ update_shallow(args, sought, nr_sought, &si);
cleanup:
clear_shallow_info(&si);
return ref_cpy;
POST /smart/repo.git/git-upload-pack HTTP/1.1 200
EOF
test_expect_success 'used upload-pack service' '
- sed -e "
- s/^.* \"//
- s/\"//
- s/ [1-9][0-9]*\$//
- s/^GET /GET /
- " >act <"$HTTPD_ROOT_PATH"/access.log &&
- test_cmp exp act
+ check_access_log exp
'
test_expect_success 'follow redirects (301)' '
submodule update sub
'
+ test_expect_success 'using fetch command in remote-curl updates refs' '
+ SERVER="$HTTPD_DOCUMENT_ROOT_PATH/twobranch" &&
+ rm -rf "$SERVER" client &&
+
+ git init "$SERVER" &&
+ test_commit -C "$SERVER" foo &&
+ git -C "$SERVER" update-ref refs/heads/anotherbranch foo &&
+
+ git clone $HTTPD_URL/smart/twobranch client &&
+
+ test_commit -C "$SERVER" bar &&
+ git -C client -c protocol.version=0 fetch &&
+
+ git -C "$SERVER" rev-parse master >expect &&
+ git -C client rev-parse origin/master >actual &&
+ test_cmp expect actual
+ '
+
test_expect_success 'GIT_REDACT_COOKIES redacts cookies' '
rm -rf clone &&
echo "Set-Cookie: Foo=1" >cookies &&
if (debug)
fprintf(stderr, "Debug: Remote helper: -> %s", buffer->buf);
if (write_in_full(helper->helper->in, buffer->buf, buffer->len) < 0)
- die_errno("Full write to remote helper failed");
+ die_errno(_("full write to remote helper failed"));
}
static int recvline_fh(FILE *helper, struct strbuf *buffer)
if (debug)
fprintf(stderr, "Debug: Remote helper: -> %s", str);
if (write_in_full(fd, str, strlen(str)) < 0)
- die_errno("Full write to remote helper failed");
+ die_errno(_("full write to remote helper failed"));
}
static const char *remove_ext_force(const char *url)
code = start_command(helper);
if (code < 0 && errno == ENOENT)
- die("Unable to find remote helper for '%s'", data->name);
+ die(_("unable to find remote helper for '%s'"), data->name);
else if (code != 0)
exit(code);
*/
duped = dup(helper->out);
if (duped < 0)
- die_errno("Can't dup helper output fd");
+ die_errno(_("can't dup helper output fd"));
data->out = xfdopen(duped, "r");
write_constant(helper->in, "capabilities\n");
} else if (starts_with(capname, "no-private-update")) {
data->no_private_update = 1;
} else if (mandatory) {
- die("Unknown mandatory capability %s. This remote "
- "helper probably needs newer version of Git.",
+ die(_("unknown mandatory capability %s; this remote "
+ "helper probably needs newer version of Git"),
capname);
}
}
if (!data->rs.nr && (data->import || data->bidi_import || data->export)) {
- warning("This remote helper should implement refspec capability.");
+ warning(_("this remote helper should implement refspec capability"));
}
strbuf_release(&buf);
if (debug)
else if (!strcmp(buf->buf, "unsupported"))
ret = 1;
else {
- warning("%s unexpectedly said: '%s'", data->name, buf->buf);
+ warning(_("%s unexpectedly said: '%s'"), data->name, buf->buf);
ret = 1;
}
return ret;
if (starts_with(buf.buf, "lock ")) {
const char *name = buf.buf + 5;
if (transport->pack_lockfile)
- warning("%s also locked %s", data->name, name);
+ warning(_("%s also locked %s"), data->name, name);
else
transport->pack_lockfile = xstrdup(name);
}
else if (!buf.len)
break;
else
- warning("%s unexpectedly said: '%s'", data->name, buf.buf);
+ warning(_("%s unexpectedly said: '%s'"), data->name, buf.buf);
}
strbuf_release(&buf);
return 0;
get_helper(transport);
if (get_importer(transport, &fastimport))
- die("Couldn't run fast-import");
+ die(_("couldn't run fast-import"));
for (i = 0; i < nr_heads; i++) {
posn = to_fetch[i];
*/
if (finish_command(&fastimport))
- die("Error while running fast-import");
+ die(_("error while running fast-import"));
/*
* The fast-import stream of a remote helper that advertises
private = xstrdup(name);
if (private) {
if (read_ref(private, &posn->old_oid) < 0)
- die("Could not read ref %s", private);
+ die(_("could not read ref %s"), private);
free(private);
}
}
*/
duped = dup(helper->out);
if (duped < 0)
- die_errno("Can't dup helper output fd");
+ die_errno(_("can't dup helper output fd"));
input = xfdopen(duped, "r");
setvbuf(input, NULL, _IONBF, 0);
fprintf(stderr, "Debug: Falling back to dumb "
"transport.\n");
} else {
- die("Unknown response to connect: %s",
- cmdbuf->buf);
+ die(_(_("unknown response to connect: %s")),
+ cmdbuf->buf);
}
fclose(input);
if (strcmp(name, exec)) {
int r = set_helper_option(transport, "servpath", exec);
if (r > 0)
- warning("Setting remote service path not supported by protocol.");
+ warning(_("setting remote service path not supported by protocol"));
else if (r < 0)
- warning("Invalid remote service path.");
+ warning(_("invalid remote service path"));
}
if (data->connect) {
/* Get_helper so connect is inited. */
get_helper(transport);
if (!data->connect)
- die("Operation not supported by protocol.");
+ die(_("operation not supported by protocol"));
if (!process_connect_service(transport, name, exec))
- die("Can't connect to subservice %s.", name);
+ die(_("can't connect to subservice %s"), name);
fd[0] = data->helper->out;
fd[1] = data->helper->in;
}
static int fetch(struct transport *transport,
- int nr_heads, struct ref **to_fetch,
- struct ref **fetched_refs)
+ int nr_heads, struct ref **to_fetch)
{
struct helper_data *data = transport->data;
int i, count;
if (process_connect(transport, 0)) {
do_take_over(transport);
- return transport->vtable->fetch(transport, nr_heads, to_fetch,
- fetched_refs);
+ return transport->vtable->fetch(transport, nr_heads, to_fetch);
}
count = 0;
transport, "filter",
data->transport_options.filter_options.filter_spec);
+ if (data->transport_options.negotiation_tips)
+ warning("Ignoring --negotiation-tip because the protocol does not support it.");
+
if (data->fetch)
return fetch_with_fetch(transport, nr_heads, to_fetch);
status = REF_STATUS_REMOTE_REJECT;
refname = buf->buf + 6;
} else
- die("expected ok/error, helper said '%s'", buf->buf);
+ die(_("expected ok/error, helper said '%s'"), buf->buf);
msg = strchr(refname, ' ');
if (msg) {
if (!*ref)
*ref = find_ref_by_name(remote_refs, refname);
if (!*ref) {
- warning("helper reported unexpected status of %s", refname);
+ warning(_("helper reported unexpected status of %s"), refname);
return 1;
}
{
if (flags & TRANSPORT_PUSH_DRY_RUN) {
if (set_helper_option(transport, "dry-run", "true") != 0)
- die("helper %s does not support dry-run", name);
+ die(_("helper %s does not support dry-run"), name);
} else if (flags & TRANSPORT_PUSH_CERT_ALWAYS) {
if (set_helper_option(transport, TRANS_OPT_PUSH_CERT, "true") != 0)
- die("helper %s does not support --signed", name);
+ die(_("helper %s does not support --signed"), name);
} else if (flags & TRANSPORT_PUSH_CERT_IF_ASKED) {
if (set_helper_option(transport, TRANS_OPT_PUSH_CERT, "if-asked") != 0)
- die("helper %s does not support --signed=if-asked", name);
+ die(_("helper %s does not support --signed=if-asked"), name);
}
if (flags & TRANSPORT_PUSH_OPTIONS) {
struct string_list_item *item;
for_each_string_list_item(item, transport->push_options)
if (set_helper_option(transport, "push-option", item->string) != 0)
- die("helper %s does not support 'push-option'", name);
+ die(_("helper %s does not support 'push-option'"), name);
}
}
struct strbuf buf = STRBUF_INIT;
if (!data->rs.nr)
- die("remote-helper doesn't support push; refspec needed");
+ die(_("remote-helper doesn't support push; refspec needed"));
set_common_push_options(transport, data->name, flags);
if (flags & TRANSPORT_PUSH_FORCE) {
if (set_helper_option(transport, "force", "true") != 0)
- warning("helper %s does not support 'force'", data->name);
+ warning(_("helper %s does not support 'force'"), data->name);
}
helper = get_helper(transport);
}
if (get_exporter(transport, &exporter, &revlist_args))
- die("Couldn't run fast-export");
+ die(_("couldn't run fast-export"));
string_list_clear(&revlist_args, 1);
if (finish_command(&exporter))
- die("Error while running fast-export");
+ die(_("error while running fast-export"));
if (push_update_refs_status(data, remote_refs, flags))
return 1;
}
if (!remote_refs) {
- fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
- "Perhaps you should specify a branch such as 'master'.\n");
+ fprintf(stderr,
+ _("No refs in common and none specified; doing nothing.\n"
+ "Perhaps you should specify a branch such as 'master'.\n"));
return 0;
}
eov = strchr(buf.buf, ' ');
if (!eov)
- die("Malformed response in ref list: %s", buf.buf);
+ die(_("malformed response in ref list: %s"), buf.buf);
eon = strchr(eov + 1, ' ');
*eov = '\0';
if (eon)
if (has_attribute(eon + 1, "unchanged")) {
(*tail)->status |= REF_STATUS_UPTODATE;
if (read_ref((*tail)->name, &(*tail)->old_oid) < 0)
- die(_("Could not read ref %s"),
+ die(_("could not read ref %s"),
(*tail)->name);
}
}
bytes = read(t->src, t->buf + t->bufuse, BUFFERSIZE - t->bufuse);
if (bytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN &&
errno != EINTR) {
- error_errno("read(%s) failed", t->src_name);
+ error_errno(_("read(%s) failed"), t->src_name);
return -1;
} else if (bytes == 0) {
transfer_debug("%s EOF (with %i bytes in buffer)",
transfer_debug("%s is writable", t->dest_name);
bytes = xwrite(t->dest, t->buf, t->bufuse);
if (bytes < 0 && errno != EWOULDBLOCK) {
- error_errno("write(%s) failed", t->dest_name);
+ error_errno(_("write(%s) failed"), t->dest_name);
return -1;
} else if (bytes > 0) {
t->bufuse -= bytes;
void *tret;
err = pthread_join(thread, &tret);
if (!tret) {
- error("%s thread failed", name);
+ error(_("%s thread failed"), name);
return 1;
}
if (err) {
- error("%s thread failed to join: %s", name, strerror(err));
+ error(_("%s thread failed to join: %s"), name, strerror(err));
return 1;
}
return 0;
err = pthread_create(>p_thread, NULL, udt_copy_task_routine,
&s->gtp);
if (err)
- die("Can't start thread for copying data: %s", strerror(err));
+ die(_("can't start thread for copying data: %s"), strerror(err));
err = pthread_create(&ptg_thread, NULL, udt_copy_task_routine,
&s->ptg);
if (err)
- die("Can't start thread for copying data: %s", strerror(err));
+ die(_("can't start thread for copying data: %s"), strerror(err));
ret |= tloop_join(gtp_thread, "Git to program copy");
ret |= tloop_join(ptg_thread, "Program to git copy");
{
int tret;
if (waitpid(pid, &tret, 0) < 0) {
- error_errno("%s process failed to wait", name);
+ error_errno(_("%s process failed to wait"), name);
return 1;
}
if (!WIFEXITED(tret) || WEXITSTATUS(tret)) {
- error("%s process failed", name);
+ error(_("%s process failed"), name);
return 1;
}
return 0;
/* Fork thread #1: git to program. */
pid1 = fork();
if (pid1 < 0)
- die_errno("Can't start thread for copying data");
+ die_errno(_("can't start thread for copying data"));
else if (pid1 == 0) {
udt_kill_transfer(&s->ptg);
exit(udt_copy_task_routine(&s->gtp) ? 0 : 1);
/* Fork thread #2: program to git. */
pid2 = fork();
if (pid2 < 0)
- die_errno("Can't start thread for copying data");
+ die_errno(_("can't start thread for copying data"));
else if (pid2 == 0) {
udt_kill_transfer(&s->gtp);
exit(udt_copy_task_routine(&s->ptg) ? 0 : 1);
close(data->fd);
data->fd = read_bundle_header(transport->url, &data->header);
if (data->fd < 0)
- die ("Could not read bundle '%s'.", transport->url);
+ die(_("could not read bundle '%s'"), transport->url);
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);
}
static int fetch_refs_from_bundle(struct transport *transport,
- int nr_heads, struct ref **to_fetch,
- struct ref **fetched_refs)
+ int nr_heads, struct ref **to_fetch)
{
struct bundle_transport_data *data = transport->data;
return unbundle(&data->header, data->fd,
}
static int fetch_refs_via_pack(struct transport *transport,
- int nr_heads, struct ref **to_fetch,
- struct ref **fetched_refs)
+ int nr_heads, struct ref **to_fetch)
{
int ret = 0;
struct git_transport_data *data = transport->data;
args.filter_options = data->options.filter_options;
args.stateless_rpc = transport->stateless_rpc;
args.server_options = transport->server_options;
+ args.negotiation_tips = data->options.negotiation_tips;
if (!data->got_remote_heads)
refs_tmp = get_refs_via_connect(transport, 0, NULL);
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;
}
switch (data->version) {
case protocol_v2:
- die("support for protocol v2 not implemented yet");
+ die(_("support for protocol v2 not implemented yet"));
break;
case protocol_v1:
case protocol_v0:
else if (!strcasecmp(value, "user"))
return PROTOCOL_ALLOW_USER_ONLY;
- die("unknown value for config '%s': %s", key, value);
+ die(_("unknown value for config '%s': %s"), key, value);
}
static enum protocol_allow_config get_protocol_config(const char *type)
void transport_check_allowed(const char *type)
{
if (!is_transport_allowed(type, -1))
- die("transport '%s' not allowed", type);
+ die(_("transport '%s' not allowed"), type);
}
static struct transport_vtable bundle_vtable = {
ret->progress = isatty(2);
if (!remote)
- die("No remote provided to transport_get()");
+ BUG("No remote provided to transport_get()");
ret->got_remote_refs = 0;
ret->remote = remote;
if (helper) {
transport_helper_init(ret, helper);
} else if (starts_with(url, "rsync:")) {
- die("git-over-rsync is no longer supported");
+ 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));
transport_check_allowed("file");
transport->push_options,
pretend)) {
oid_array_clear(&commits);
- die("Failed to push all needed submodules!");
+ die(_("failed to push all needed submodules"));
}
oid_array_clear(&commits);
}
return transport->remote_refs;
}
- int transport_fetch_refs(struct transport *transport, struct ref *refs,
- struct ref **fetched_refs)
+ int transport_fetch_refs(struct transport *transport, struct ref *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)) {
- /*
- * 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;
- }
+ !oidcmp(&rm->peer_ref->old_oid, &rm->old_oid))
continue;
- }
ALLOC_GROW(heads, nr_heads + 1, nr_alloc);
heads[nr_heads++] = rm;
}
heads[nr_heads++] = rm;
}
- rc = transport->vtable->fetch(transport, nr_heads, heads, fetched_refs);
- if (fetched_refs && nop_head) {
- *nop_tail = *fetched_refs;
- *fetched_refs = nop_head;
- }
+ rc = transport->vtable->fetch(transport, nr_heads, heads);
free(heads);
return rc;
if (transport->vtable->connect)
return transport->vtable->connect(transport, name, exec, fd);
else
- die("Operation not supported by protocol");
+ die(_("operation not supported by protocol"));
}
int transport_disconnect(struct transport *transport)
if (get_oid_hex(line.buf, &oid) ||
line.buf[GIT_SHA1_HEXSZ] != ' ') {
- warning("invalid line while parsing alternate refs: %s",
+ warning(_("invalid line while parsing alternate refs: %s"),
line.buf);
break;
}
const char *receivepack;
struct push_cas_option *cas;
struct list_objects_filter_options filter_options;
+
+ /*
+ * This is only used during fetch. See the documentation of
+ * negotiation_tips in struct fetch_pack_args.
+ *
+ * This field is only supported by transports that support connect or
+ * stateless_connect. Set this field directly instead of using
+ * transport_set_option().
+ */
+ struct oid_array *negotiation_tips;
};
enum transport_family {
const struct ref *transport_get_remote_refs(struct transport *transport,
const struct argv_array *ref_prefixes);
- int transport_fetch_refs(struct transport *transport, struct ref *refs,
- struct ref **fetched_refs);
+ int transport_fetch_refs(struct transport *transport, struct ref *refs);
void transport_unlock_pack(struct transport *transport);
int transport_disconnect(struct transport *transport);
char *transport_anonymize_url(const char *url);