diff options
Diffstat (limited to 'fetch-pack.c')
-rw-r--r-- | fetch-pack.c | 144 |
1 files changed, 120 insertions, 24 deletions
diff --git a/fetch-pack.c b/fetch-pack.c index fab5e80175..eeee2bb7e0 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -13,6 +13,7 @@ #include "transport.h" #include "version.h" #include "prio-queue.h" +#include "sha1-array.h" static int transfer_unpack_limit = -1; static int fetch_unpack_limit = -1; @@ -25,6 +26,7 @@ static int agent_supported; static struct lock_file shallow_lock; static const char *alternate_shallow_file; +/* Remember to update object flag allocation in object.h */ #define COMPLETE (1U << 0) #define COMMON (1U << 1) #define COMMON_REF (1U << 2) @@ -47,9 +49,8 @@ static void rev_list_push(struct commit *commit, int mark) if (!(commit->object.flags & mark)) { commit->object.flags |= mark; - if (!(commit->object.parsed)) - if (parse_commit(commit)) - return; + if (parse_commit(commit)) + return; prio_queue_put(&rev_list, commit); @@ -128,8 +129,7 @@ static const unsigned char *get_rev(void) return NULL; commit = prio_queue_get(&rev_list); - if (!commit->object.parsed) - parse_commit(commit); + parse_commit(commit); parents = commit->parents; commit->object.flags |= POPPED; @@ -176,9 +176,9 @@ static void consume_shallow_list(struct fetch_pack_args *args, int fd) */ char *line; while ((line = packet_read_line(fd, NULL))) { - if (!prefixcmp(line, "shallow ")) + if (starts_with(line, "shallow ")) continue; - if (!prefixcmp(line, "unshallow ")) + if (starts_with(line, "unshallow ")) continue; die("git fetch-pack: expected shallow list"); } @@ -194,7 +194,7 @@ static enum ack_type get_ack(int fd, unsigned char *result_sha1) die("git fetch-pack: expected ACK/NAK, got EOF"); if (!strcmp(line, "NAK")) return NAK; - if (!prefixcmp(line, "ACK ")) { + if (starts_with(line, "ACK ")) { if (!get_sha1_hex(line+4, result_sha1)) { if (len < 45) return ACK; @@ -311,7 +311,7 @@ static int find_common(struct fetch_pack_args *args, } if (is_repository_shallow()) - write_shallow_commits(&req_buf, 1); + 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); @@ -323,13 +323,13 @@ static int find_common(struct fetch_pack_args *args, send_request(args, fd[1], &req_buf); while ((line = packet_read_line(fd[0], NULL))) { - if (!prefixcmp(line, "shallow ")) { + if (starts_with(line, "shallow ")) { if (get_sha1_hex(line + 8, sha1)) die("invalid shallow line: %s", line); register_shallow(sha1); continue; } - if (!prefixcmp(line, "unshallow ")) { + if (starts_with(line, "unshallow ")) { if (get_sha1_hex(line + 10, sha1)) die("invalid unshallow line: %s", line); if (!lookup_object(sha1)) @@ -440,7 +440,8 @@ done: } strbuf_release(&req_buf); - consume_shallow_list(args, fd[0]); + 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) { @@ -523,7 +524,7 @@ static void filter_refs(struct fetch_pack_args *args, } if (!keep && args->fetch_all && - (!args->depth || prefixcmp(ref->name, "refs/tags/"))) + (!args->depth || !starts_with(ref->name, "refs/tags/"))) keep = 1; if (keep) { @@ -774,6 +775,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, int fd[2], const struct ref *orig_ref, struct ref **sought, int nr_sought, + struct shallow_info *si, char **pack_lockfile) { struct ref *ref = copy_ref_list(orig_ref); @@ -850,7 +852,10 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, if (args->stateless_rpc) packet_flush(fd[1]); if (args->depth > 0) - setup_alternate_shallow(&shallow_lock, &alternate_shallow_file); + setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, + NULL); + else if (si->nr_ours || si->nr_theirs) + alternate_shallow_file = setup_temporary_shallow(si->shallow); else alternate_shallow_file = NULL; if (get_pack(args, fd, pack_lockfile)) @@ -924,14 +929,110 @@ static int remove_duplicates_in_refs(struct ref **ref, int nr) return dst; } +static void update_shallow(struct fetch_pack_args *args, + struct ref **sought, int nr_sought, + struct shallow_info *si) +{ + struct sha1_array ref = SHA1_ARRAY_INIT; + int *status; + int i; + + if (args->depth > 0 && alternate_shallow_file) { + if (*alternate_shallow_file == '\0') { /* --unshallow */ + unlink_or_warn(git_path("shallow")); + rollback_lock_file(&shallow_lock); + } else + commit_lock_file(&shallow_lock); + return; + } + + if (!si->shallow || !si->shallow->nr) + return; + + if (args->cloning) { + /* + * remote is shallow, but this is a clone, there are + * no objects in repo to worry about. Accept any + * shallow points that exist in the pack (iow in repo + * after get_pack() and reprepare_packed_git()) + */ + struct sha1_array extra = SHA1_ARRAY_INIT; + unsigned char (*sha1)[20] = si->shallow->sha1; + for (i = 0; i < si->shallow->nr; i++) + if (has_sha1_file(sha1[i])) + sha1_array_append(&extra, sha1[i]); + if (extra.nr) { + setup_alternate_shallow(&shallow_lock, + &alternate_shallow_file, + &extra); + commit_lock_file(&shallow_lock); + } + sha1_array_clear(&extra); + return; + } + + if (!si->nr_ours && !si->nr_theirs) + return; + + remove_nonexistent_theirs_shallow(si); + if (!si->nr_ours && !si->nr_theirs) + return; + for (i = 0; i < nr_sought; i++) + sha1_array_append(&ref, sought[i]->old_sha1); + si->ref = &ref; + + if (args->update_shallow) { + /* + * remote is also shallow, .git/shallow may be updated + * so all refs can be accepted. Make sure we only add + * shallow roots that are actually reachable from new + * refs. + */ + struct sha1_array extra = SHA1_ARRAY_INIT; + unsigned char (*sha1)[20] = si->shallow->sha1; + assign_shallow_commits_to_refs(si, NULL, NULL); + if (!si->nr_ours && !si->nr_theirs) { + sha1_array_clear(&ref); + return; + } + for (i = 0; i < si->nr_ours; i++) + sha1_array_append(&extra, sha1[si->ours[i]]); + for (i = 0; i < si->nr_theirs; i++) + sha1_array_append(&extra, sha1[si->theirs[i]]); + setup_alternate_shallow(&shallow_lock, + &alternate_shallow_file, + &extra); + commit_lock_file(&shallow_lock); + sha1_array_clear(&extra); + sha1_array_clear(&ref); + return; + } + + /* + * remote is also shallow, check what ref is safe to update + * without updating .git/shallow + */ + status = xcalloc(nr_sought, sizeof(*status)); + assign_shallow_commits_to_refs(si, NULL, status); + if (si->nr_ours || si->nr_theirs) { + for (i = 0; i < nr_sought; i++) + if (status[i]) + sought[i]->status = REF_STATUS_REJECT_SHALLOW; + } + free(status); + sha1_array_clear(&ref); +} + struct ref *fetch_pack(struct fetch_pack_args *args, int fd[], struct child_process *conn, const struct ref *ref, const char *dest, struct ref **sought, int nr_sought, + struct sha1_array *shallow, char **pack_lockfile) { struct ref *ref_cpy; + struct shallow_info si; fetch_pack_setup(); if (nr_sought) @@ -941,16 +1042,11 @@ struct ref *fetch_pack(struct fetch_pack_args *args, packet_flush(fd[1]); die("no matching remote head"); } - ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought, pack_lockfile); - - if (args->depth > 0 && alternate_shallow_file) { - if (*alternate_shallow_file == '\0') { /* --unshallow */ - unlink_or_warn(git_path("shallow")); - rollback_lock_file(&shallow_lock); - } else - commit_lock_file(&shallow_lock); - } - + prepare_shallow_info(&si, shallow); + ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought, + &si, pack_lockfile); reprepare_packed_git(); + update_shallow(args, sought, nr_sought, &si); + clear_shallow_info(&si); return ref_cpy; } |