The main purpose of shallow clones is to reduce download by only fetching objects up to a certain depth from the given refs. The number of objects depends on how many refs to follow. So: - Only fetch HEAD or the ref specified by --branch - Only fetch tags that point to downloaded objects More tags/branches can be fetched later using git-fetch as usual. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- Only lightly tested, but seems to work. I'll check later if --branch works with a tag like Junio's example --single=v3.2 Documentation/git-clone.txt | 14 ++++++---- builtin/clone.c | 54 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index 4b8b26b..d69f440 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -172,12 +172,14 @@ objects from the source repository into a pack in the cloned repository. --depth <depth>:: Create a 'shallow' clone with a history truncated to the - specified number of revisions. A shallow repository has a - number of limitations (you cannot clone or fetch from - it, nor push from nor into it), but is adequate if you - are only interested in the recent history of a large project - with a long history, and would want to send in fixes - as patches. + specified number of revisions. Only one branch (either HEAD + or specified by --branch) is fetched. Tags that point + outside truncated history are not fetched. ++ +A shallow repository has a number of limitations (you cannot clone or +fetch from it, nor push from nor into it), but is adequate if you are +only interested in the recent history of a large project with a long +history, and would want to send in fixes as patches. --recursive:: --recurse-submodules:: diff --git a/builtin/clone.c b/builtin/clone.c index efe8b6c..8de9248 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -48,6 +48,7 @@ static int option_verbosity; static int option_progress; static struct string_list option_config; static struct string_list option_reference; +static char *src_ref_prefix = "refs/heads/"; static int opt_parse_reference(const struct option *opt, const char *arg, int unset) { @@ -427,9 +428,27 @@ static struct ref *wanted_peer_refs(const struct ref *refs, struct ref *local_refs = head; struct ref **tail = head ? &head->next : &local_refs; - get_fetch_map(refs, refspec, &tail, 0); - if (!option_mirror) - get_fetch_map(refs, tag_refspec, &tail, 0); + if (option_depth) { + struct ref *remote_head = NULL; + + if (!option_branch) + remote_head = guess_remote_head(head, refs, 0); + else { + struct strbuf sb = STRBUF_INIT; + strbuf_addstr(&sb, src_ref_prefix); + strbuf_addstr(&sb, option_branch); + remote_head = find_ref_by_name(refs, sb.buf); + strbuf_release(&sb); + } + + if (remote_head) + get_fetch_map(remote_head, refspec, &tail, 0); + } + else { + get_fetch_map(refs, refspec, &tail, 0); + if (!option_mirror) + get_fetch_map(refs, tag_refspec, &tail, 0); + } return local_refs; } @@ -448,6 +467,27 @@ static void write_remote_refs(const struct ref *local_refs) clear_extra_refs(); } +static void write_followtags(const struct ref *refs) +{ + struct ref_lock *lock; + const struct ref *ref; + + for (ref = refs; ref; ref = ref->next) { + if (prefixcmp(ref->name, "refs/tags")) + continue; + if (!suffixcmp(ref->name, "^{}")) + continue; + if (!has_sha1_file(ref->old_sha1)) + continue; + + lock = lock_any_ref_for_update(ref->name, NULL, 0); + if (!lock) + die_errno(_("unable to lock %s for writing"), ref->name); + if (write_ref_sha1(lock, ref->old_sha1, "storing tag") < 0) + die_errno(_("unable to write %s"), ref->name); + } +} + static int write_one_config(const char *key, const char *value, void *data) { return git_config_set_multivar(key, value ? value : "true", "^$", 0); @@ -478,7 +518,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix) struct strbuf key = STRBUF_INIT, value = STRBUF_INIT; struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT; struct transport *transport = NULL; - char *src_ref_prefix = "refs/heads/"; int err = 0; struct refspec *refspec; @@ -642,9 +681,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix) transport_set_option(transport, TRANS_OPT_KEEP, "yes"); - if (option_depth) + if (option_depth) { transport_set_option(transport, TRANS_OPT_DEPTH, option_depth); + transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, + "1"); + } transport_set_verbosity(transport, option_verbosity, option_progress); @@ -663,6 +705,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix) clear_extra_refs(); write_remote_refs(mapped_refs); + if (option_depth) + write_followtags(refs); remote_head = find_ref_by_name(refs, "HEAD"); remote_head_points_at = -- 1.7.3.1.256.g2539c.dirty -- 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