Check if all objects reachable from the fetched refs exist after fetching instead of before: this allows us to distinguish between a repository which is not up to date and a corrupted repository, and to ensure that the repository is up to date and complete after the fetch. In select_missing_refs() we must check which objects we have, instead of checking which refs are up to date: otherwise, we might fetch objects into the repository which exist in an alternate. Signed-off-by: Andreas Gruenbacher <agruen@xxxxxxx> --- builtin/fetch.c | 82 ++++++++++++++++++++++++++----------------------------- 1 files changed, 39 insertions(+), 43 deletions(-) diff --git a/builtin/fetch.c b/builtin/fetch.c index 6dc75d4..0f292b8 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -440,20 +440,15 @@ static int store_updated_refs(const char *raw_url, const char *remote_name, } /* - * We would want to bypass the object transfer altogether if - * everything we are going to fetch already exists and is connected - * locally. - * - * The refs we are going to fetch are in ref_map. If running + * If running * * $ git rev-list --objects --stdin --not --all * * (feeding all the refs in ref_map on its standard input) * does not error out, that means everything reachable from the - * refs we are going to fetch exists and is connected to some of - * our existing refs. + * refs we have fetched exists. */ -static int quickfetch(struct ref *ref_map) +static int check_connectivity(struct ref *ref_map) { struct child_process revlist; struct ref *ref; @@ -461,16 +456,6 @@ static int quickfetch(struct ref *ref_map) const char *argv[] = {"rev-list", "--quiet", "--objects", "--stdin", "--not", "--all", NULL}; - /* - * If we are deepening a shallow clone we already have these - * objects reachable. Running rev-list here will return with - * a good (0) exit status and we'll bypass the fetch that we - * really need to perform. Claiming failure now will ensure - * we perform the network exchange to deepen our history. - */ - if (depth) - return -1; - if (!ref_map) return 0; @@ -513,46 +498,57 @@ static int quickfetch(struct ref *ref_map) return finish_command(&revlist) || err; } -static void check_existing_refs(struct ref *ref_map) { +static void select_missing_refs(struct ref *ref_map) { struct ref *ref; - int done = 1; - if (!depth) { - for (ref = ref_map; ref; ref = ref->next) { - if (ref->peer_ref && - !is_null_sha1(ref->old_sha1) && - !hashcmp(ref->peer_ref->old_sha1, ref->old_sha1)) - ref->dont_fetch = 1; - else - done = 0; - } + for (ref = ref_map; ref; ref = ref->next) { + if (has_sha1_file(ref->old_sha1)) + ref->dont_fetch = 1; } - if (done) { - /* - * When deepening of a shallow repository is requested, local - * and remote refs are likely to still be equal. In addition, - * we get here if all refs are up to date but quickfetch() did - * not succeed. In both cases, fetch all refs. - */ - for (ref = ref_map; ref; ref = ref->next) +} + +static int select_all_refs(struct ref *ref_map) { + struct ref *ref; + int done = 1; + + for (ref = ref_map; ref; ref = ref->next) { + if (ref->dont_fetch) { ref->dont_fetch = 0; + done = 0; + } } + + return done; } static int fetch_refs(struct transport *transport, struct ref *ref_map) { int ret; - ret = quickfetch(ref_map); + if (depth) { + /* When deepening a shallow clone, re-fetch all the refs: + * it doesn't help to have the topmost commits of each ref. + */ + select_all_refs(ref_map); + } else + select_missing_refs(ref_map); + ret = transport_fetch_refs(transport, ref_map); + if (ret) + return ret; + ret = check_connectivity(ref_map); if (ret) { - check_existing_refs(ref_map); + if (select_all_refs(ref_map)) + return ret; + transport_unlock_pack(transport); ret = transport_fetch_refs(transport, ref_map); + if (ret) + return ret; } - if (!ret) - ret |= store_updated_refs(transport->url, - transport->remote->name, - ref_map); + ret = store_updated_refs(transport->url, + transport->remote->name, + ref_map); transport_unlock_pack(transport); + return ret; } -- 1.7.0.2.273.gc2413 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html