int is_repository_shallow(void) { FILE *fp; char buf[1024]; const char *path = alternate_shallow_file; if (is_shallow >= 0) return is_shallow; if (!path) path = git_path("shallow"); /* * fetch-pack sets '--shallow-file ""' as an indicator that no * shallow file should be used. We could just open it and it * will likely fail. But let's do an explicit check instead. */ if (!*path || stat(path, &shallow_stat) || (fp = fopen(path, "r")) == NULL) { is_shallow = 0; return is_shallow; } is_shallow = 1; while (fgets(buf, sizeof(buf), fp)) { unsigned char sha1[20]; if (get_sha1_hex(buf, sha1)) die("bad shallow line: %s", buf); register_shallow(sha1); } fclose(fp); return is_shallow; }
static void send_unshallow(const struct object_array *shallows) { int i; for (i = 0; i < shallows->nr; i++) { struct object *object = shallows->objects[i].item; if (object->flags & NOT_SHALLOW) { struct commit_list *parents; packet_write_fmt(1, "unshallow %s", oid_to_hex(&object->oid)); object->flags &= ~CLIENT_SHALLOW; /* * We want to _register_ "object" as shallow, but we * also need to traverse object's parents to deepen a * shallow clone. Unregister it for now so we can * parse and add the parents to the want list, then * re-register it. */ unregister_shallow(&object->oid); object->parsed = 0; parse_commit_or_die((struct commit *)object); parents = ((struct commit *)object)->parents; while (parents) { add_object_array(&parents->item->object, NULL, &want_obj); parents = parents->next; } add_object_array(object, NULL, &extra_edge_obj); } /* make sure commit traversal conforms to client */ register_shallow(the_repository, &object->oid); } }
static void send_shallow(struct commit_list *result) { while (result) { struct object *object = &result->item->object; if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) { packet_write_fmt(1, "shallow %s", oid_to_hex(&object->oid)); register_shallow(the_repository, &object->oid); shallow_nr++; } result = result->next; } }
/* Returns 1 if a shallow list is sent or 0 otherwise */ static int send_shallow_list(int depth, int deepen_rev_list, timestamp_t deepen_since, struct string_list *deepen_not, struct object_array *shallows) { int ret = 0; if (depth > 0 && deepen_rev_list) die("git upload-pack: deepen and deepen-since (or deepen-not) cannot be used together"); if (depth > 0) { deepen(depth, deepen_relative, shallows); ret = 1; } else if (deepen_rev_list) { struct argv_array av = ARGV_ARRAY_INIT; int i; argv_array_push(&av, "rev-list"); if (deepen_since) argv_array_pushf(&av, "--max-age=%"PRItime, deepen_since); if (deepen_not->nr) { argv_array_push(&av, "--not"); for (i = 0; i < deepen_not->nr; i++) { struct string_list_item *s = deepen_not->items + i; argv_array_push(&av, s->string); } argv_array_push(&av, "--not"); } for (i = 0; i < want_obj.nr; i++) { struct object *o = want_obj.objects[i].item; argv_array_push(&av, oid_to_hex(&o->oid)); } deepen_by_rev_list(av.argc, av.argv, shallows); argv_array_clear(&av); ret = 1; } else { if (shallows->nr > 0) { int i; for (i = 0; i < shallows->nr; i++) register_shallow(the_repository, &shallows->objects[i].item->oid); } } shallow_nr += shallows->nr; return ret; }
static void receive_shallow_info(struct fetch_pack_args *args, struct packet_reader *reader) { int line_received = 0; process_section_header(reader, "shallow-info", 0); while (packet_reader_read(reader) == PACKET_READ_NORMAL) { const char *arg; struct object_id oid; 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); line_received = 1; 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)) 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); line_received = 1; continue; } die(_("expected shallow/unshallow, got %s"), reader->line); } if (reader->status != PACKET_READ_FLUSH && reader->status != PACKET_READ_DELIM) die(_("error processing shallow info: %d"), reader->status); if (line_received) { setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, NULL); args->deepen = 1; } }
static int update_shallow_ref(struct command *cmd, struct shallow_info *si) { static struct lock_file shallow_lock; struct sha1_array extra = SHA1_ARRAY_INIT; const char *alt_file; uint32_t mask = 1 << (cmd->index % 32); int i; trace_printf_key(&trace_shallow, "shallow: update_shallow_ref %s\n", cmd->ref_name); for (i = 0; i < si->shallow->nr; i++) if (si->used_shallow[i] && (si->used_shallow[i][cmd->index / 32] & mask) && !delayed_reachability_test(si, i)) sha1_array_append(&extra, si->shallow->sha1[i]); setup_alternate_shallow(&shallow_lock, &alt_file, &extra); if (check_shallow_connected(command_singleton_iterator, 0, cmd, alt_file)) { rollback_lock_file(&shallow_lock); sha1_array_clear(&extra); return -1; } commit_lock_file(&shallow_lock); /* * Make sure setup_alternate_shallow() for the next ref does * not lose these new roots.. */ for (i = 0; i < extra.nr; i++) register_shallow(extra.sha1[i]); si->shallow_ref[cmd->index] = 0; sha1_array_clear(&extra); return 0; }
static int find_common(struct fetch_pack_args *args, int fd[2], unsigned char *result_sha1, struct ref *refs) { int fetching; int count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval; const unsigned char *sha1; unsigned in_vain = 0; int got_continue = 0; int got_ready = 0; struct strbuf req_buf = STRBUF_INIT; size_t state_len = 0; 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, NULL); for_each_alternate_ref(insert_one_alternate_ref, NULL); fetching = 0; for ( ; refs ; refs = refs->next) { unsigned char *remote = refs->old_sha1; const char *remote_hex; struct object *o; /* * If that object is complete (i.e. it is an ancestor of a * local ref), we tell them we have it but do not have to * tell them about its ancestors, which they already know * about. * * We use lookup_object here because we are only * interested in the case we *know* the object is * reachable and we have already scanned it. */ if (((o = lookup_object(remote)) != NULL) && (o->flags & COMPLETE)) { continue; } remote_hex = sha1_to_hex(remote); if (!fetching) { struct strbuf c = STRBUF_INIT; if (multi_ack == 2) strbuf_addstr(&c, " multi_ack_detailed"); if (multi_ack == 1) strbuf_addstr(&c, " multi_ack"); if (no_done) strbuf_addstr(&c, " no-done"); if (use_sideband == 2) strbuf_addstr(&c, " side-band-64k"); if (use_sideband == 1) strbuf_addstr(&c, " side-band"); if (args->use_thin_pack) strbuf_addstr(&c, " thin-pack"); if (args->no_progress) strbuf_addstr(&c, " no-progress"); if (args->include_tag) strbuf_addstr(&c, " include-tag"); if (prefer_ofs_delta) strbuf_addstr(&c, " ofs-delta"); if (agent_supported) strbuf_addf(&c, " agent=%s", git_user_agent_sanitized()); packet_buf_write(&req_buf, "want %s%s\n", remote_hex, c.buf); strbuf_release(&c); } else packet_buf_write(&req_buf, "want %s\n", remote_hex); fetching++; } if (!fetching) { strbuf_release(&req_buf); packet_flush(fd[1]); return 1; } if (is_repository_shallow()) write_shallow_commits(&req_buf, 1, NULL); if (args->depth > 0) packet_buf_write(&req_buf, "deepen %d", args->depth); packet_buf_flush(&req_buf); state_len = req_buf.len; if (args->depth > 0) { char *line; const char *arg; unsigned char sha1[20]; send_request(args, fd[1], &req_buf); while ((line = packet_read_line(fd[0], NULL))) { if (skip_prefix(line, "shallow ", &arg)) { if (get_sha1_hex(arg, sha1)) die("invalid shallow line: %s", line); register_shallow(sha1); continue; } if (skip_prefix(line, "unshallow ", &arg)) { if (get_sha1_hex(arg, sha1)) die("invalid unshallow line: %s", line); if (!lookup_object(sha1)) die("object not found: %s", line); /* make sure that it is parsed as shallow */ if (!parse_object(sha1)) die("error in object: %s", line); if (unregister_shallow(sha1)) die("no shallow found: %s", line); continue; } die("expected shallow/unshallow, got %s", line); } } else if (!args->stateless_rpc) send_request(args, fd[1], &req_buf); if (!args->stateless_rpc) { /* If we aren't using the stateless-rpc interface * we don't need to retain the headers. */ strbuf_setlen(&req_buf, 0); state_len = 0; } flushes = 0; retval = -1; while ((sha1 = get_rev())) { packet_buf_write(&req_buf, "have %s\n", sha1_to_hex(sha1)); if (args->verbose) fprintf(stderr, "have %s\n", sha1_to_hex(sha1)); in_vain++; if (flush_at <= ++count) { int ack; packet_buf_flush(&req_buf); send_request(args, fd[1], &req_buf); strbuf_setlen(&req_buf, state_len); flushes++; flush_at = next_flush(args, count); /* * We keep one window "ahead" of the other side, and * will wait for an ACK only on the next one */ if (!args->stateless_rpc && count == INITIAL_FLUSH) continue; consume_shallow_list(args, fd[0]); do { ack = get_ack(fd[0], result_sha1); if (args->verbose && ack) fprintf(stderr, "got ack %d %s\n", ack, sha1_to_hex(result_sha1)); switch (ack) { case ACK: flushes = 0; multi_ack = 0; retval = 0; goto done; case ACK_common: case ACK_ready: case ACK_continue: { struct commit *commit = lookup_commit(result_sha1); if (!commit) die("invalid commit %s", sha1_to_hex(result_sha1)); if (args->stateless_rpc && ack == ACK_common && !(commit->object.flags & 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. */ const char *hex = sha1_to_hex(result_sha1); packet_buf_write(&req_buf, "have %s\n", hex); state_len = req_buf.len; } mark_common(commit, 0, 1); retval = 0; in_vain = 0; got_continue = 1; if (ack == ACK_ready) { clear_prio_queue(&rev_list); got_ready = 1; } break; } } } while (ack); flushes--; if (got_continue && MAX_IN_VAIN < in_vain) { if (args->verbose) fprintf(stderr, "giving up\n"); break; /* give up */ } } } done: if (!got_ready || !no_done) { packet_buf_write(&req_buf, "done\n"); send_request(args, fd[1], &req_buf); } if (args->verbose) fprintf(stderr, "done\n"); if (retval != 0) { multi_ack = 0; flushes++; } strbuf_release(&req_buf); if (!got_ready || !no_done) consume_shallow_list(args, fd[0]); while (flushes || multi_ack) { int ack = get_ack(fd[0], result_sha1); if (ack) { if (args->verbose) fprintf(stderr, "got ack (%d) %s\n", ack, sha1_to_hex(result_sha1)); if (ack == ACK) return 0; multi_ack = 1; continue; } flushes--; } /* it is no error to fetch into a completely empty repo */ return count ? retval : 0; }
static void receive_needs(void) { struct object_array shallows = OBJECT_ARRAY_INIT; int depth = 0; int has_non_tip = 0; shallow_nr = 0; for (;;) { struct object *o; const char *features; unsigned char sha1_buf[20]; char *line = packet_read_line(0, NULL); reset_timeout(); if (!line) break; if (starts_with(line, "shallow ")) { unsigned char sha1[20]; struct object *object; if (get_sha1_hex(line + 8, sha1)) die("invalid shallow line: %s", line); object = parse_object(sha1); if (!object) continue; if (object->type != OBJ_COMMIT) die("invalid shallow object %s", sha1_to_hex(sha1)); if (!(object->flags & CLIENT_SHALLOW)) { object->flags |= CLIENT_SHALLOW; add_object_array(object, NULL, &shallows); } continue; } if (starts_with(line, "deepen ")) { char *end; depth = strtol(line + 7, &end, 0); if (end == line + 7 || depth <= 0) die("Invalid deepen: %s", line); continue; } if (!starts_with(line, "want ") || get_sha1_hex(line+5, sha1_buf)) die("git upload-pack: protocol error, " "expected to get sha, not '%s'", line); features = line + 45; if (parse_feature_request(features, "multi_ack_detailed")) multi_ack = 2; else if (parse_feature_request(features, "multi_ack")) multi_ack = 1; if (parse_feature_request(features, "no-done")) no_done = 1; if (parse_feature_request(features, "thin-pack")) use_thin_pack = 1; if (parse_feature_request(features, "ofs-delta")) use_ofs_delta = 1; if (parse_feature_request(features, "side-band-64k")) use_sideband = LARGE_PACKET_MAX; else if (parse_feature_request(features, "side-band")) use_sideband = DEFAULT_PACKET_MAX; if (parse_feature_request(features, "no-progress")) no_progress = 1; if (parse_feature_request(features, "include-tag")) use_include_tag = 1; o = parse_object(sha1_buf); if (!o) die("git upload-pack: not our ref %s", sha1_to_hex(sha1_buf)); if (!(o->flags & WANTED)) { o->flags |= WANTED; if (!is_our_ref(o)) has_non_tip = 1; add_object_array(o, NULL, &want_obj); } } /* * We have sent all our refs already, and the other end * should have chosen out of them. When we are operating * in the stateless RPC mode, however, their choice may * have been based on the set of older refs advertised * by another process that handled the initial request. */ if (has_non_tip) check_non_tip(); if (!use_sideband && daemon_mode) no_progress = 1; if (depth == 0 && shallows.nr == 0) return; if (depth > 0) { struct commit_list *result = NULL, *backup = NULL; int i; if (depth == INFINITE_DEPTH && !is_repository_shallow()) for (i = 0; i < shallows.nr; i++) { struct object *object = shallows.objects[i].item; object->flags |= NOT_SHALLOW; } else backup = result = get_shallow_commits(&want_obj, depth, SHALLOW, NOT_SHALLOW); while (result) { struct object *object = &result->item->object; if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) { packet_write(1, "shallow %s", sha1_to_hex(object->sha1)); register_shallow(object->sha1); shallow_nr++; } result = result->next; } free_commit_list(backup); for (i = 0; i < shallows.nr; i++) { struct object *object = shallows.objects[i].item; if (object->flags & NOT_SHALLOW) { struct commit_list *parents; packet_write(1, "unshallow %s", sha1_to_hex(object->sha1)); object->flags &= ~CLIENT_SHALLOW; /* make sure the real parents are parsed */ unregister_shallow(object->sha1); object->parsed = 0; parse_commit_or_die((struct commit *)object); parents = ((struct commit *)object)->parents; while (parents) { add_object_array(&parents->item->object, NULL, &want_obj); parents = parents->next; } add_object_array(object, NULL, &extra_edge_obj); } /* make sure commit traversal conforms to client */ register_shallow(object->sha1); } packet_flush(1); } else if (shallows.nr > 0) { int i; for (i = 0; i < shallows.nr; i++) register_shallow(shallows.objects[i].item->sha1); } shallow_nr += shallows.nr; free(shallows.objects); }
static int find_common(struct fetch_negotiator *negotiator, struct fetch_pack_args *args, int fd[2], struct object_id *result_oid, struct ref *refs) { int fetching; int count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval; const struct object_id *oid; unsigned in_vain = 0; int got_continue = 0; int got_ready = 0; struct strbuf req_buf = STRBUF_INIT; size_t state_len = 0; if (args->stateless_rpc && multi_ack == 1) die(_("--stateless-rpc requires multi_ack_detailed")); if (!args->no_dependents) { mark_tips(negotiator, args->negotiation_tips); for_each_cached_alternate(negotiator, insert_one_alternate_object); } fetching = 0; for ( ; refs ; refs = refs->next) { struct object_id *remote = &refs->old_oid; const char *remote_hex; struct object *o; /* * If that object is complete (i.e. it is an ancestor of a * local ref), we tell them we have it but do not have to * tell them about its ancestors, which they already know * about. * * We use lookup_object here because we are only * interested in the case we *know* the object is * reachable and we have already scanned it. * * Do this only if args->no_dependents is false (if it is true, * we cannot trust the object flags). */ if (!args->no_dependents && ((o = lookup_object(the_repository, remote->hash)) != NULL) && (o->flags & COMPLETE)) { continue; } remote_hex = oid_to_hex(remote); if (!fetching) { struct strbuf c = STRBUF_INIT; if (multi_ack == 2) strbuf_addstr(&c, " multi_ack_detailed"); if (multi_ack == 1) strbuf_addstr(&c, " multi_ack"); if (no_done) strbuf_addstr(&c, " no-done"); if (use_sideband == 2) strbuf_addstr(&c, " side-band-64k"); if (use_sideband == 1) strbuf_addstr(&c, " side-band"); if (args->deepen_relative) strbuf_addstr(&c, " deepen-relative"); if (args->use_thin_pack) strbuf_addstr(&c, " thin-pack"); if (args->no_progress) strbuf_addstr(&c, " no-progress"); if (args->include_tag) strbuf_addstr(&c, " include-tag"); if (prefer_ofs_delta) strbuf_addstr(&c, " ofs-delta"); if (deepen_since_ok) strbuf_addstr(&c, " deepen-since"); if (deepen_not_ok) strbuf_addstr(&c, " deepen-not"); if (agent_supported) strbuf_addf(&c, " agent=%s", git_user_agent_sanitized()); if (args->filter_options.choice) strbuf_addstr(&c, " filter"); packet_buf_write(&req_buf, "want %s%s\n", remote_hex, c.buf); strbuf_release(&c); } else packet_buf_write(&req_buf, "want %s\n", remote_hex); fetching++; } if (!fetching) { strbuf_release(&req_buf); packet_flush(fd[1]); return 1; } 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 (args->deepen_since) { timestamp_t max_age = approxidate(args->deepen_since); packet_buf_write(&req_buf, "deepen-since %"PRItime, max_age); } if (args->deepen_not) { int i; for (i = 0; i < args->deepen_not->nr; i++) { struct string_list_item *s = args->deepen_not->items + i; 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); 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)) { if (get_oid_hex(arg, &oid)) die(_("invalid shallow line: %s"), line); 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(the_repository, oid.hash)) die(_("object not found: %s"), line); /* make sure that it is parsed as shallow */ if (!parse_object(the_repository, &oid)) die(_("error in object: %s"), line); if (unregister_shallow(&oid)) die(_("no shallow found: %s"), line); continue; } die(_("expected shallow/unshallow, got %s"), line); } } else if (!args->stateless_rpc) send_request(args, fd[1], &req_buf); if (!args->stateless_rpc) { /* If we aren't using the stateless-rpc interface * we don't need to retain the headers. */ strbuf_setlen(&req_buf, 0); state_len = 0; } flushes = 0; retval = -1; if (args->no_dependents) goto done; 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++; if (flush_at <= ++count) { int ack; packet_buf_flush(&req_buf); send_request(args, fd[1], &req_buf); strbuf_setlen(&req_buf, state_len); flushes++; flush_at = next_flush(args->stateless_rpc, count); /* * We keep one window "ahead" of the other side, and * will wait for an ACK only on the next one */ if (!args->stateless_rpc && count == INITIAL_FLUSH) continue; consume_shallow_list(args, fd[0]); do { ack = get_ack(fd[0], result_oid); if (ack) print_verbose(args, _("got %s %d %s"), "ack", ack, oid_to_hex(result_oid)); switch (ack) { case ACK: flushes = 0; multi_ack = 0; retval = 0; goto done; case ACK_common: case ACK_ready: case ACK_continue: { struct commit *commit = 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 && !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. */ const char *hex = oid_to_hex(result_oid); packet_buf_write(&req_buf, "have %s\n", hex); state_len = req_buf.len; /* * Reset in_vain because an ack * for this commit has not been * seen. */ in_vain = 0; } else if (!args->stateless_rpc || ack != ACK_common) in_vain = 0; retval = 0; got_continue = 1; if (ack == ACK_ready) got_ready = 1; break; } } } while (ack); flushes--; if (got_continue && MAX_IN_VAIN < in_vain) { print_verbose(args, _("giving up")); break; /* give up */ } if (got_ready) break; } } done: if (!got_ready || !no_done) { packet_buf_write(&req_buf, "done\n"); send_request(args, fd[1], &req_buf); } print_verbose(args, _("done")); if (retval != 0) { multi_ack = 0; flushes++; } strbuf_release(&req_buf); if (!got_ready || !no_done) consume_shallow_list(args, fd[0]); while (flushes || multi_ack) { int ack = get_ack(fd[0], result_oid); if (ack) { print_verbose(args, _("got %s (%d) %s"), "ack", ack, oid_to_hex(result_oid)); if (ack == ACK) return 0; multi_ack = 1; continue; } flushes--; } /* it is no error to fetch into a completely empty repo */ return count ? retval : 0; }
static int find_common(int fd[2], unsigned char *result_sha1, struct ref *refs) { int fetching; int count = 0, flushes = 0, retval; const unsigned char *sha1; unsigned in_vain = 0; int got_continue = 0; if (marked) for_each_ref(clear_marks, NULL); marked = 1; for_each_ref(rev_list_insert_ref, NULL); fetching = 0; for ( ; refs ; refs = refs->next) { unsigned char *remote = refs->old_sha1; struct object *o; /* * If that object is complete (i.e. it is an ancestor of a * local ref), we tell them we have it but do not have to * tell them about its ancestors, which they already know * about. * * We use lookup_object here because we are only * interested in the case we *know* the object is * reachable and we have already scanned it. */ if (((o = lookup_object(remote)) != NULL) && (o->flags & COMPLETE)) { continue; } if (!fetching) packet_write(fd[1], "want %s%s%s%s%s%s%s%s\n", sha1_to_hex(remote), (multi_ack ? " multi_ack" : ""), (use_sideband == 2 ? " side-band-64k" : ""), (use_sideband == 1 ? " side-band" : ""), (args.use_thin_pack ? " thin-pack" : ""), (args.no_progress ? " no-progress" : ""), (args.include_tag ? " include-tag" : ""), " ofs-delta"); else packet_write(fd[1], "want %s\n", sha1_to_hex(remote)); fetching++; } if (is_repository_shallow()) write_shallow_commits(fd[1], 1); if (args.depth > 0) packet_write(fd[1], "deepen %d", args.depth); packet_flush(fd[1]); if (!fetching) return 1; if (args.depth > 0) { char line[1024]; unsigned char sha1[20]; while (packet_read_line(fd[0], line, sizeof(line))) { if (!prefixcmp(line, "shallow ")) { if (get_sha1_hex(line + 8, sha1)) die("invalid shallow line: %s", line); register_shallow(sha1); continue; } if (!prefixcmp(line, "unshallow ")) { if (get_sha1_hex(line + 10, sha1)) die("invalid unshallow line: %s", line); if (!lookup_object(sha1)) die("object not found: %s", line); /* make sure that it is parsed as shallow */ if (!parse_object(sha1)) die("error in object: %s", line); if (unregister_shallow(sha1)) die("no shallow found: %s", line); continue; } die("expected shallow/unshallow, got %s", line); } } flushes = 0; retval = -1; while ((sha1 = get_rev())) { packet_write(fd[1], "have %s\n", sha1_to_hex(sha1)); if (args.verbose) fprintf(stderr, "have %s\n", sha1_to_hex(sha1)); in_vain++; if (!(31 & ++count)) { int ack; packet_flush(fd[1]); flushes++; /* * We keep one window "ahead" of the other side, and * will wait for an ACK only on the next one */ if (count == 32) continue; do { ack = get_ack(fd[0], result_sha1); if (args.verbose && ack) fprintf(stderr, "got ack %d %s\n", ack, sha1_to_hex(result_sha1)); if (ack == 1) { flushes = 0; multi_ack = 0; retval = 0; goto done; } else if (ack == 2) { struct commit *commit = lookup_commit(result_sha1); mark_common(commit, 0, 1); retval = 0; in_vain = 0; got_continue = 1; } } while (ack); flushes--; if (got_continue && MAX_IN_VAIN < in_vain) { if (args.verbose) fprintf(stderr, "giving up\n"); break; /* give up */ } } } done: packet_write(fd[1], "done\n"); if (args.verbose) fprintf(stderr, "done\n"); if (retval != 0) { multi_ack = 0; flushes++; } while (flushes || multi_ack) { int ack = get_ack(fd[0], result_sha1); if (ack) { if (args.verbose) fprintf(stderr, "got ack (%d) %s\n", ack, sha1_to_hex(result_sha1)); if (ack == 1) return 0; multi_ack = 1; continue; } flushes--; } /* it is no error to fetch into a completely empty repo */ return count ? retval : 0; }
static void receive_needs(void) { struct object_array shallows = OBJECT_ARRAY_INIT; struct string_list deepen_not = STRING_LIST_INIT_DUP; int depth = 0; int has_non_tip = 0; timestamp_t deepen_since = 0; int deepen_rev_list = 0; shallow_nr = 0; for (;;) { struct object *o; const char *features; struct object_id oid_buf; char *line = packet_read_line(0, NULL); const char *arg; reset_timeout(); if (!line) break; if (skip_prefix(line, "shallow ", &arg)) { struct object_id oid; struct object *object; if (get_oid_hex(arg, &oid)) die("invalid shallow line: %s", line); object = parse_object(&oid); if (!object) continue; if (object->type != OBJ_COMMIT) die("invalid shallow object %s", oid_to_hex(&oid)); if (!(object->flags & CLIENT_SHALLOW)) { object->flags |= CLIENT_SHALLOW; add_object_array(object, NULL, &shallows); } continue; } if (skip_prefix(line, "deepen ", &arg)) { char *end = NULL; depth = strtol(arg, &end, 0); if (!end || *end || depth <= 0) die("Invalid deepen: %s", line); continue; } if (skip_prefix(line, "deepen-since ", &arg)) { char *end = NULL; deepen_since = parse_timestamp(arg, &end, 0); if (!end || *end || !deepen_since || /* revisions.c's max_age -1 is special */ deepen_since == -1) die("Invalid deepen-since: %s", line); deepen_rev_list = 1; continue; } if (skip_prefix(line, "deepen-not ", &arg)) { char *ref = NULL; struct object_id oid; if (expand_ref(arg, strlen(arg), &oid, &ref) != 1) die("git upload-pack: ambiguous deepen-not: %s", line); string_list_append(&deepen_not, ref); free(ref); deepen_rev_list = 1; continue; } if (skip_prefix(line, "filter ", &arg)) { if (!filter_capability_requested) die("git upload-pack: filtering capability not negotiated"); parse_list_objects_filter(&filter_options, arg); continue; } if (!skip_prefix(line, "want ", &arg) || get_oid_hex(arg, &oid_buf)) die("git upload-pack: protocol error, " "expected to get sha, not '%s'", line); features = arg + 40; if (parse_feature_request(features, "deepen-relative")) deepen_relative = 1; if (parse_feature_request(features, "multi_ack_detailed")) multi_ack = 2; else if (parse_feature_request(features, "multi_ack")) multi_ack = 1; if (parse_feature_request(features, "no-done")) no_done = 1; if (parse_feature_request(features, "thin-pack")) use_thin_pack = 1; if (parse_feature_request(features, "ofs-delta")) use_ofs_delta = 1; if (parse_feature_request(features, "side-band-64k")) use_sideband = LARGE_PACKET_MAX; else if (parse_feature_request(features, "side-band")) use_sideband = DEFAULT_PACKET_MAX; if (parse_feature_request(features, "no-progress")) no_progress = 1; if (parse_feature_request(features, "include-tag")) use_include_tag = 1; if (allow_filter && parse_feature_request(features, "filter")) filter_capability_requested = 1; o = parse_object(&oid_buf); if (!o) { packet_write_fmt(1, "ERR upload-pack: not our ref %s", oid_to_hex(&oid_buf)); die("git upload-pack: not our ref %s", oid_to_hex(&oid_buf)); } if (!(o->flags & WANTED)) { o->flags |= WANTED; if (!((allow_unadvertised_object_request & ALLOW_ANY_SHA1) == ALLOW_ANY_SHA1 || is_our_ref(o))) has_non_tip = 1; add_object_array(o, NULL, &want_obj); } } /* * We have sent all our refs already, and the other end * should have chosen out of them. When we are operating * in the stateless RPC mode, however, their choice may * have been based on the set of older refs advertised * by another process that handled the initial request. */ if (has_non_tip) check_non_tip(); if (!use_sideband && daemon_mode) no_progress = 1; if (depth == 0 && !deepen_rev_list && shallows.nr == 0) return; if (depth > 0 && deepen_rev_list) die("git upload-pack: deepen and deepen-since (or deepen-not) cannot be used together"); if (depth > 0) deepen(depth, deepen_relative, &shallows); else if (deepen_rev_list) { struct argv_array av = ARGV_ARRAY_INIT; int i; argv_array_push(&av, "rev-list"); if (deepen_since) argv_array_pushf(&av, "--max-age=%"PRItime, deepen_since); if (deepen_not.nr) { argv_array_push(&av, "--not"); for (i = 0; i < deepen_not.nr; i++) { struct string_list_item *s = deepen_not.items + i; argv_array_push(&av, s->string); } argv_array_push(&av, "--not"); } for (i = 0; i < want_obj.nr; i++) { struct object *o = want_obj.objects[i].item; argv_array_push(&av, oid_to_hex(&o->oid)); } deepen_by_rev_list(av.argc, av.argv, &shallows); argv_array_clear(&av); } else if (shallows.nr > 0) { int i; for (i = 0; i < shallows.nr; i++) register_shallow(&shallows.objects[i].item->oid); } shallow_nr += shallows.nr; object_array_clear(&shallows); }
static void receive_needs(void) { struct object_array shallows = {0, 0, NULL}; static char line[1000]; int len, depth = 0; if (debug_fd) write_in_full(debug_fd, "#S\n", 3); for (;;) { struct object *o; unsigned char sha1_buf[20]; len = packet_read_line(0, line, sizeof(line)); reset_timeout(); if (!len) break; if (debug_fd) write_in_full(debug_fd, line, len); if (!prefixcmp(line, "shallow ")) { unsigned char sha1[20]; struct object *object; use_thin_pack = 0; if (get_sha1(line + 8, sha1)) die("invalid shallow line: %s", line); object = parse_object(sha1); if (!object) die("did not find object for %s", line); object->flags |= CLIENT_SHALLOW; add_object_array(object, NULL, &shallows); continue; } if (!prefixcmp(line, "deepen ")) { char *end; use_thin_pack = 0; depth = strtol(line + 7, &end, 0); if (end == line + 7 || depth <= 0) die("Invalid deepen: %s", line); continue; } if (prefixcmp(line, "want ") || get_sha1_hex(line+5, sha1_buf)) die("git upload-pack: protocol error, " "expected to get sha, not '%s'", line); if (strstr(line+45, "multi_ack")) multi_ack = 1; if (strstr(line+45, "thin-pack")) use_thin_pack = 1; if (strstr(line+45, "ofs-delta")) use_ofs_delta = 1; if (strstr(line+45, "side-band-64k")) use_sideband = LARGE_PACKET_MAX; else if (strstr(line+45, "side-band")) use_sideband = DEFAULT_PACKET_MAX; if (strstr(line+45, "no-progress")) no_progress = 1; if (strstr(line+45, "include-tag")) use_include_tag = 1; /* We have sent all our refs already, and the other end * should have chosen out of them; otherwise they are * asking for nonsense. * * Hmph. We may later want to allow "want" line that * asks for something like "master~10" (symbolic)... * would it make sense? I don't know. */ o = lookup_object(sha1_buf); if (!o || !(o->flags & OUR_REF)) die("git upload-pack: not our ref %s", line+5); if (!(o->flags & WANTED)) { o->flags |= WANTED; add_object_array(o, NULL, &want_obj); } } if (debug_fd) write_in_full(debug_fd, "#E\n", 3); if (!use_sideband && daemon_mode) no_progress = 1; if (depth == 0 && shallows.nr == 0) return; if (depth > 0) { struct commit_list *result, *backup; int i; backup = result = get_shallow_commits(&want_obj, depth, SHALLOW, NOT_SHALLOW); while (result) { struct object *object = &result->item->object; if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) { packet_write(1, "shallow %s", sha1_to_hex(object->sha1)); register_shallow(object->sha1); } result = result->next; } free_commit_list(backup); for (i = 0; i < shallows.nr; i++) { struct object *object = shallows.objects[i].item; if (object->flags & NOT_SHALLOW) { struct commit_list *parents; packet_write(1, "unshallow %s", sha1_to_hex(object->sha1)); object->flags &= ~CLIENT_SHALLOW; /* make sure the real parents are parsed */ unregister_shallow(object->sha1); object->parsed = 0; if (parse_commit((struct commit *)object)) die("invalid commit"); parents = ((struct commit *)object)->parents; while (parents) { add_object_array(&parents->item->object, NULL, &want_obj); parents = parents->next; } } /* make sure commit traversal conforms to client */ register_shallow(object->sha1); } packet_flush(1); } else if (shallows.nr > 0) { int i; for (i = 0; i < shallows.nr; i++) register_shallow(shallows.objects[i].item->sha1); } free(shallows.objects); }