static int server_supports_filtering;
static struct lock_file shallow_lock;
static const char *alternate_shallow_file;
-static char *negotiation_algorithm;
static struct strbuf fsck_msg_types = STRBUF_INIT;
/* Remember to update object flag allocation in object.h */
ACK_ready
};
-static void consume_shallow_list(struct fetch_pack_args *args, int fd)
+static void consume_shallow_list(struct fetch_pack_args *args,
+ struct packet_reader *reader)
{
if (args->stateless_rpc && args->deepen) {
/* If we sent a depth we will get back "duplicate"
* shallow and unshallow commands every time there
* is a block of have lines exchanged.
*/
- char *line;
- while ((line = packet_read_line(fd, NULL))) {
- if (starts_with(line, "shallow "))
+ while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
+ if (starts_with(reader->line, "shallow "))
continue;
- if (starts_with(line, "unshallow "))
+ if (starts_with(reader->line, "unshallow "))
continue;
die(_("git fetch-pack: expected shallow list"));
}
+ if (reader->status != PACKET_READ_FLUSH)
+ die(_("git fetch-pack: expected a flush packet after shallow list"));
}
}
-static enum ack_type get_ack(int fd, struct object_id *result_oid)
+static enum ack_type get_ack(struct packet_reader *reader,
+ struct object_id *result_oid)
{
int len;
- char *line = packet_read_line(fd, &len);
const char *arg;
- if (!line)
+ if (packet_reader_read(reader) != PACKET_READ_NORMAL)
die(_("git fetch-pack: expected ACK/NAK, got a flush packet"));
- if (!strcmp(line, "NAK"))
+ len = reader->pktlen;
+
+ if (!strcmp(reader->line, "NAK"))
return NAK;
- if (skip_prefix(line, "ACK ", &arg)) {
+ if (skip_prefix(reader->line, "ACK ", &arg)) {
if (!get_oid_hex(arg, result_oid)) {
arg += 40;
- len -= arg - line;
+ len -= arg - reader->line;
if (len < 1)
return ACK;
if (strstr(arg, "continue"))
return ACK;
}
}
- if (skip_prefix(line, "ERR ", &arg))
- die(_("remote error: %s"), arg);
- die(_("git fetch-pack: expected ACK/NAK, got '%s'"), line);
+ die(_("git fetch-pack: expected ACK/NAK, got '%s'"), reader->line);
}
static void send_request(struct fetch_pack_args *args,
if (args->stateless_rpc) {
send_sideband(fd, -1, buf->buf, buf->len, LARGE_PACKET_MAX);
packet_flush(fd);
- } else
- write_or_die(fd, buf->buf, buf->len);
+ } else {
+ if (write_in_full(fd, buf->buf, buf->len) < 0)
+ die_errno(_("unable to write to remote"));
+ }
}
static void insert_one_alternate_object(struct fetch_negotiator *negotiator,
int got_ready = 0;
struct strbuf req_buf = STRBUF_INIT;
size_t state_len = 0;
+ struct packet_reader reader;
if (args->stateless_rpc && multi_ack == 1)
die(_("--stateless-rpc requires multi_ack_detailed"));
+ packet_reader_init(&reader, fd[0], NULL, 0,
+ PACKET_READ_CHOMP_NEWLINE |
+ PACKET_READ_DIE_ON_ERR_PACKET);
+
if (!args->no_dependents) {
mark_tips(negotiator, args->negotiation_tips);
for_each_cached_alternate(negotiator, insert_one_alternate_object);
* we cannot trust the object flags).
*/
if (!args->no_dependents &&
- ((o = lookup_object(the_repository, remote->hash)) != NULL) &&
+ ((o = lookup_object(the_repository, remote)) != NULL) &&
(o->flags & COMPLETE)) {
continue;
}
packet_buf_write(&req_buf, "deepen-not %s", s->string);
}
}
- if (server_supports_filtering && args->filter_options.choice)
- packet_buf_write(&req_buf, "filter %s",
- args->filter_options.filter_spec);
+ if (server_supports_filtering && args->filter_options.choice) {
+ const char *spec =
+ expand_list_objects_filter_spec(&args->filter_options);
+ packet_buf_write(&req_buf, "filter %s", spec);
+ }
packet_buf_flush(&req_buf);
state_len = req_buf.len;
if (args->deepen) {
- char *line;
const char *arg;
struct object_id oid;
send_request(args, fd[1], &req_buf);
- while ((line = packet_read_line(fd[0], NULL))) {
- if (skip_prefix(line, "shallow ", &arg)) {
+ while (packet_reader_read(&reader) == PACKET_READ_NORMAL) {
+ if (skip_prefix(reader.line, "shallow ", &arg)) {
if (get_oid_hex(arg, &oid))
- die(_("invalid shallow line: %s"), line);
+ die(_("invalid shallow line: %s"), reader.line);
register_shallow(the_repository, &oid);
continue;
}
- if (skip_prefix(line, "unshallow ", &arg)) {
+ if (skip_prefix(reader.line, "unshallow ", &arg)) {
if (get_oid_hex(arg, &oid))
- die(_("invalid unshallow line: %s"), line);
- if (!lookup_object(the_repository, oid.hash))
- die(_("object not found: %s"), line);
+ die(_("invalid unshallow line: %s"), reader.line);
+ if (!lookup_object(the_repository, &oid))
+ die(_("object not found: %s"), reader.line);
/* make sure that it is parsed as shallow */
if (!parse_object(the_repository, &oid))
- die(_("error in object: %s"), line);
+ die(_("error in object: %s"), reader.line);
if (unregister_shallow(&oid))
- die(_("no shallow found: %s"), line);
+ die(_("no shallow found: %s"), reader.line);
continue;
}
- die(_("expected shallow/unshallow, got %s"), line);
+ die(_("expected shallow/unshallow, got %s"), reader.line);
}
} else if (!args->stateless_rpc)
send_request(args, fd[1], &req_buf);
if (!args->stateless_rpc && count == INITIAL_FLUSH)
continue;
- consume_shallow_list(args, fd[0]);
+ consume_shallow_list(args, &reader);
do {
- ack = get_ack(fd[0], result_oid);
+ ack = get_ack(&reader, result_oid);
if (ack)
print_verbose(args, _("got %s %d %s"), "ack",
ack, oid_to_hex(result_oid));
strbuf_release(&req_buf);
if (!got_ready || !no_done)
- consume_shallow_list(args, fd[0]);
+ consume_shallow_list(args, &reader);
while (flushes || multi_ack) {
- int ack = get_ack(fd[0], result_oid);
+ int ack = get_ack(&reader, result_oid);
if (ack) {
print_verbose(args, _("got %s (%d) %s"), "ack",
ack, oid_to_hex(result_oid));
next = ref->next;
if (starts_with(ref->name, "refs/") &&
- check_refname_format(ref->name, 0))
- ; /* trash */
- else {
+ check_refname_format(ref->name, 0)) {
+ /*
+ * trash or a peeled value; do not even add it to
+ * unmatched list
+ */
+ free_one_ref(ref);
+ continue;
+ } else {
while (i < nr_sought) {
int cmp = strcmp(ref->name, sought[i]->name);
if (cmp < 0)
}
oidset_clear(&tip_oids);
- for (ref = unmatched; ref; ref = next) {
- next = ref->next;
- free(ref);
- }
+ free_refs(unmatched);
*refs = newlist;
}
for (ref = *refs; ref; ref = ref->next) {
struct object *o = deref_tag(the_repository,
lookup_object(the_repository,
- ref->old_oid.hash),
+ &ref->old_oid),
NULL, 0);
if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE))
const struct object_id *remote = &ref->old_oid;
struct object *o;
- o = lookup_object(the_repository, remote->hash);
+ o = lookup_object(the_repository, remote);
if (!o || !(o->flags & COMPLETE)) {
retval = 0;
print_verbose(args, "want %s (%s)", oid_to_hex(remote),
struct shallow_info *si,
char **pack_lockfile)
{
+ struct repository *r = the_repository;
struct ref *ref = copy_ref_list(orig_ref);
struct object_id oid;
const char *agent_feature;
int agent_len;
struct fetch_negotiator negotiator;
- fetch_negotiator_init(&negotiator, negotiation_algorithm);
+ fetch_negotiator_init(r, &negotiator);
sort_ref_list(&ref, ref_compare_name);
QSORT(sought, nr_sought, cmp_ref_by_name);
- if ((args->depth > 0 || is_repository_shallow(the_repository)) && !server_supports("shallow"))
+ if ((agent_feature = server_feature_value("agent", &agent_len))) {
+ agent_supported = 1;
+ if (agent_len)
+ print_verbose(args, _("Server version is %.*s"),
+ agent_len, agent_feature);
+ }
+
+ if (server_supports("shallow"))
+ print_verbose(args, _("Server supports %s"), "shallow");
+ else if (args->depth > 0 || is_repository_shallow(r))
die(_("Server does not support shallow clients"));
if (args->depth > 0 || args->deepen_since || args->deepen_not)
args->deepen = 1;
if (server_supports("multi_ack_detailed")) {
- print_verbose(args, _("Server supports multi_ack_detailed"));
+ print_verbose(args, _("Server supports %s"), "multi_ack_detailed");
multi_ack = 2;
if (server_supports("no-done")) {
- print_verbose(args, _("Server supports no-done"));
+ print_verbose(args, _("Server supports %s"), "no-done");
if (args->stateless_rpc)
no_done = 1;
}
}
else if (server_supports("multi_ack")) {
- print_verbose(args, _("Server supports multi_ack"));
+ print_verbose(args, _("Server supports %s"), "multi_ack");
multi_ack = 1;
}
if (server_supports("side-band-64k")) {
- print_verbose(args, _("Server supports side-band-64k"));
+ print_verbose(args, _("Server supports %s"), "side-band-64k");
use_sideband = 2;
}
else if (server_supports("side-band")) {
- print_verbose(args, _("Server supports side-band"));
+ print_verbose(args, _("Server supports %s"), "side-band");
use_sideband = 1;
}
if (server_supports("allow-tip-sha1-in-want")) {
- print_verbose(args, _("Server supports allow-tip-sha1-in-want"));
+ print_verbose(args, _("Server supports %s"), "allow-tip-sha1-in-want");
allow_unadvertised_object_request |= ALLOW_TIP_SHA1;
}
if (server_supports("allow-reachable-sha1-in-want")) {
- print_verbose(args, _("Server supports allow-reachable-sha1-in-want"));
+ print_verbose(args, _("Server supports %s"), "allow-reachable-sha1-in-want");
allow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1;
}
- if (!server_supports("thin-pack"))
+ if (server_supports("thin-pack"))
+ print_verbose(args, _("Server supports %s"), "thin-pack");
+ else
args->use_thin_pack = 0;
- if (!server_supports("no-progress"))
+ if (server_supports("no-progress"))
+ print_verbose(args, _("Server supports %s"), "no-progress");
+ else
args->no_progress = 0;
- if (!server_supports("include-tag"))
+ if (server_supports("include-tag"))
+ print_verbose(args, _("Server supports %s"), "include-tag");
+ else
args->include_tag = 0;
if (server_supports("ofs-delta"))
- print_verbose(args, _("Server supports ofs-delta"));
+ print_verbose(args, _("Server supports %s"), "ofs-delta");
else
prefer_ofs_delta = 0;
if (server_supports("filter")) {
server_supports_filtering = 1;
- print_verbose(args, _("Server supports filter"));
+ print_verbose(args, _("Server supports %s"), "filter");
} else if (args->filter_options.choice) {
warning("filtering not recognized by server, ignoring");
}
- if ((agent_feature = server_feature_value("agent", &agent_len))) {
- agent_supported = 1;
- if (agent_len)
- print_verbose(args, _("Server version is %.*s"),
- agent_len, agent_feature);
- }
- if (server_supports("deepen-since"))
+ if (server_supports("deepen-since")) {
+ print_verbose(args, _("Server supports %s"), "deepen-since");
deepen_since_ok = 1;
- else if (args->deepen_since)
+ } else if (args->deepen_since)
die(_("Server does not support --shallow-since"));
- if (server_supports("deepen-not"))
+ if (server_supports("deepen-not")) {
+ print_verbose(args, _("Server supports %s"), "deepen-not");
deepen_not_ok = 1;
- else if (args->deepen_not)
+ } else if (args->deepen_not)
die(_("Server does not support --shallow-exclude"));
- if (!server_supports("deepen-relative") && args->deepen_relative)
+ if (server_supports("deepen-relative"))
+ print_verbose(args, _("Server supports %s"), "deepen-relative");
+ else if (args->deepen_relative)
die(_("Server does not support --deepen"));
if (!args->no_dependents) {
packet_buf_write(req_buf, "deepen-not %s", s->string);
}
}
+ if (args->deepen_relative)
+ packet_buf_write(req_buf, "deepen-relative\n");
}
static void add_wants(int no_dependents, const struct ref *wants, struct strbuf *req_buf)
* we cannot trust the object flags).
*/
if (!no_dependents &&
- ((o = lookup_object(the_repository, remote->hash)) != NULL) &&
+ ((o = lookup_object(the_repository, remote)) != NULL) &&
(o->flags & COMPLETE)) {
continue;
}
}
static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
- const struct fetch_pack_args *args,
+ struct fetch_pack_args *args,
const struct ref *wants, struct oidset *common,
- int *haves_to_send, int *in_vain)
+ int *haves_to_send, int *in_vain,
+ int sideband_all)
{
int ret = 0;
struct strbuf req_buf = STRBUF_INIT;
server_supports_v2("server-option", 1)) {
int i;
for (i = 0; i < args->server_options->nr; i++)
- packet_write_fmt(fd_out, "server-option=%s",
+ packet_buf_write(&req_buf, "server-option=%s",
args->server_options->items[i].string);
}
packet_buf_write(&req_buf, "include-tag");
if (prefer_ofs_delta)
packet_buf_write(&req_buf, "ofs-delta");
+ if (sideband_all)
+ packet_buf_write(&req_buf, "sideband-all");
/* Add shallow-info and deepen request */
if (server_supports_feature("fetch", "shallow", 0))
/* Add filter */
if (server_supports_feature("fetch", "filter", 0) &&
args->filter_options.choice) {
+ const char *spec =
+ expand_list_objects_filter_spec(&args->filter_options);
print_verbose(args, _("Server supports filter"));
- packet_buf_write(&req_buf, "filter %s",
- args->filter_options.filter_spec);
+ packet_buf_write(&req_buf, "filter %s", spec);
} else if (args->filter_options.choice) {
warning("filtering not recognized by server, ignoring");
}
/* Send request */
packet_buf_flush(&req_buf);
- write_or_die(fd_out, req_buf.buf, req_buf.len);
+ if (write_in_full(fd_out, req_buf.buf, req_buf.len) < 0)
+ die_errno(_("unable to write request to remote"));
strbuf_release(&req_buf);
return ret;
}
static void receive_shallow_info(struct fetch_pack_args *args,
- struct packet_reader *reader)
+ struct packet_reader *reader,
+ struct oid_array *shallows,
+ struct shallow_info *si)
{
+ int unshallow_received = 0;
+
process_section_header(reader, "shallow-info", 0);
while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
const char *arg;
if (skip_prefix(reader->line, "shallow ", &arg)) {
if (get_oid_hex(arg, &oid))
die(_("invalid shallow line: %s"), reader->line);
- register_shallow(the_repository, &oid);
+ oid_array_append(shallows, &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(the_repository, oid.hash))
+ if (!lookup_object(the_repository, &oid))
die(_("object not found: %s"), reader->line);
/* make sure that it is parsed as shallow */
if (!parse_object(the_repository, &oid))
die(_("error in object: %s"), reader->line);
if (unregister_shallow(&oid))
die(_("no shallow found: %s"), reader->line);
+ unshallow_received = 1;
continue;
}
die(_("expected shallow/unshallow, got %s"), reader->line);
reader->status != PACKET_READ_DELIM)
die(_("error processing shallow info: %d"), reader->status);
- setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, NULL);
- args->deepen = 1;
+ if (args->deepen || unshallow_received) {
+ /*
+ * Treat these as shallow lines caused by our depth settings.
+ * In v0, these lines cannot cause refs to be rejected; do the
+ * same.
+ */
+ int i;
+
+ for (i = 0; i < shallows->nr; i++)
+ register_shallow(the_repository, &shallows->oid[i]);
+ setup_alternate_shallow(&shallow_lock, &alternate_shallow_file,
+ NULL);
+ args->deepen = 1;
+ } else if (shallows->nr) {
+ /*
+ * Treat these as shallow lines caused by the remote being
+ * shallow. In v0, remote refs that reach these objects are
+ * rejected (unless --update-shallow is set); do the same.
+ */
+ prepare_shallow_info(si, shallows);
+ if (si->nr_ours || si->nr_theirs)
+ alternate_shallow_file =
+ setup_temporary_shallow(si->shallow);
+ else
+ alternate_shallow_file = NULL;
+ } else {
+ alternate_shallow_file = NULL;
+ }
+}
+
+static int cmp_name_ref(const void *name, const void *ref)
+{
+ return strcmp(name, (*(struct ref **)ref)->name);
}
static void receive_wanted_refs(struct packet_reader *reader,
while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
struct object_id oid;
const char *end;
- int i;
+ struct ref **found;
if (parse_oid_hex(reader->line, &oid, &end) || *end++ != ' ')
die(_("expected wanted-ref, got '%s'"), reader->line);
- for (i = 0; i < nr_sought; i++) {
- if (!strcmp(end, sought[i]->name)) {
- oidcpy(&sought[i]->old_oid, &oid);
- break;
- }
- }
-
- if (i == nr_sought)
+ found = bsearch(end, sought, nr_sought, sizeof(*sought),
+ cmp_name_ref);
+ if (!found)
die(_("unexpected wanted-ref: '%s'"), reader->line);
+ oidcpy(&(*found)->old_oid, &oid);
}
if (reader->status != PACKET_READ_DELIM)
int fd[2],
const struct ref *orig_ref,
struct ref **sought, int nr_sought,
+ struct oid_array *shallows,
+ struct shallow_info *si,
char **pack_lockfile)
{
+ struct repository *r = the_repository;
struct ref *ref = copy_ref_list(orig_ref);
enum fetch_state state = FETCH_CHECK_LOCAL;
struct oidset common = OIDSET_INIT;
int in_vain = 0;
int haves_to_send = INITIAL_FLUSH;
struct fetch_negotiator negotiator;
- fetch_negotiator_init(&negotiator, negotiation_algorithm);
+ fetch_negotiator_init(r, &negotiator);
packet_reader_init(&reader, fd[0], NULL, 0,
- PACKET_READ_CHOMP_NEWLINE);
+ PACKET_READ_CHOMP_NEWLINE |
+ PACKET_READ_DIE_ON_ERR_PACKET);
+ if (git_env_bool("GIT_TEST_SIDEBAND_ALL", 1) &&
+ server_supports_feature("fetch", "sideband-all", 0)) {
+ reader.use_sideband = 1;
+ reader.me = "fetch-pack";
+ }
while (state != FETCH_DONE) {
switch (state) {
case FETCH_SEND_REQUEST:
if (send_fetch_request(&negotiator, fd[1], args, ref,
&common,
- &haves_to_send, &in_vain))
+ &haves_to_send, &in_vain,
+ reader.use_sideband))
state = FETCH_GET_PACK;
else
state = FETCH_PROCESS_ACKS;
case FETCH_GET_PACK:
/* Check for shallow-info section */
if (process_section_header(&reader, "shallow-info", 1))
- receive_shallow_info(args, &reader);
+ receive_shallow_info(args, &reader, shallows, si);
if (process_section_header(&reader, "wanted-refs", 1))
receive_wanted_refs(&reader, sought, nr_sought);
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(fetch_pack_config_cb, NULL);
}
rollback_lock_file(&shallow_lock);
} else
commit_lock_file(&shallow_lock);
+ alternate_shallow_file = NULL;
return;
}
&alternate_shallow_file,
&extra);
commit_lock_file(&shallow_lock);
+ alternate_shallow_file = NULL;
}
oid_array_clear(&extra);
return;
commit_lock_file(&shallow_lock);
oid_array_clear(&extra);
oid_array_clear(&ref);
+ alternate_shallow_file = NULL;
return;
}
}
struct ref *fetch_pack(struct fetch_pack_args *args,
- int fd[], struct child_process *conn,
+ int fd[],
const struct ref *ref,
- const char *dest,
struct ref **sought, int nr_sought,
struct oid_array *shallow,
char **pack_lockfile,
{
struct ref *ref_cpy;
struct shallow_info si;
+ struct oid_array shallows_scratch = OID_ARRAY_INIT;
fetch_pack_setup();
if (nr_sought)
packet_flush(fd[1]);
die(_("no matching remote head"));
}
- prepare_shallow_info(&si, shallow);
- if (version == protocol_v2)
+ if (version == protocol_v2) {
+ if (shallow->nr)
+ BUG("Protocol V2 does not provide shallows at this point in the fetch");
+ memset(&si, 0, sizeof(si));
ref_cpy = do_fetch_pack_v2(args, fd, ref, sought, nr_sought,
+ &shallows_scratch, &si,
pack_lockfile);
- else
+ } else {
+ prepare_shallow_info(&si, shallow);
ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought,
&si, pack_lockfile);
+ }
reprepare_packed_git(the_repository);
if (!args->cloning && args->deepen) {
update_shallow(args, sought, nr_sought, &si);
cleanup:
clear_shallow_info(&si);
+ oid_array_clear(&shallows_scratch);
return ref_cpy;
}