From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: "Junio C Hamano" <gitster@pobox.com>,
"Shawn O. Pearce" <spearce@spearce.org>,
"Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH v3] Limit refs to fetch to minimum in shallow clones
Date: Fri, 6 Jan 2012 14:11:09 +0700 [thread overview]
Message-ID: <1325833869-20078-1-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <1325743516-14940-1-git-send-email-pclouds@gmail.com>
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 depend on how many refs to follow. So:
- Only fetch HEAD or the ref specified by --branch
- Only fetch tags that reference to downloaded objects
More tags/branches can be fetched later using git-fetch as usual.
The old behaviour can still be called with --no-single-branch
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
- add --no-single-branch so t5500 works without big changes.
- die() if we cannot find suitable branch to fetch (and suggest --no-single-branch)
- and a bit more tests to exercise new code
--branch=<tag> (or something similar) has to wait until my other
patch gets in a good shape (or gets dropped)
There may be something slightly wrong with shallow code. I expect it
to fetch only 3 objects (1 commit, 1 tree, 1 blob) with --depth=1
in my new test but it fetches 6 (one more commit).
Documentation/git-clone.txt | 12 ++++++++-
builtin/clone.c | 54 ++++++++++++++++++++++++++++++++++++++----
t/t5500-fetch-pack.sh | 34 ++++++++++++++++++++++++++-
3 files changed, 92 insertions(+), 8 deletions(-)
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 4b8b26b..58f21d6 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -13,7 +13,8 @@ SYNOPSIS
[-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
[-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>]
[--separate-git-dir <git dir>]
- [--depth <depth>] [--recursive|--recurse-submodules] [--] <repository>
+ [--depth <depth> [--[no-]single-branch]]
+ [--recursive|--recurse-submodules] [--] <repository>
[<directory>]
DESCRIPTION
@@ -179,6 +180,15 @@ objects from the source repository into a pack in the cloned repository.
with a long history, and would want to send in fixes
as patches.
+--single-branch::
+--no-single-branch::
+ These options are only valid when --depth is given.
+ `--single-branch` only fetches one branch (either HEAD or
+ specified by --branch) and tags that point to the downloaded
+ history. `--no-single-branch` fetches all branches and tags
+ like in normal clones. `--single-branch` is implied by
+ default.
+
--recursive::
--recurse-submodules::
After the clone is created, initialize all submodules within,
diff --git a/builtin/clone.c b/builtin/clone.c
index efe8b6c..3424e1c 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -37,7 +37,7 @@ static const char * const builtin_clone_usage[] = {
NULL
};
-static int option_no_checkout, option_bare, option_mirror;
+static int option_no_checkout, option_bare, option_mirror, option_single_branch = 1;
static int option_local, option_no_hardlinks, option_shared, option_recursive;
static char *option_template, *option_depth;
static char *option_origin = NULL;
@@ -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 const char *src_ref_prefix = "refs/heads/";
static int opt_parse_reference(const struct option *opt, const char *arg, int unset)
{
@@ -92,6 +93,8 @@ static struct option builtin_clone_options[] = {
"path to git-upload-pack on the remote"),
OPT_STRING(0, "depth", &option_depth, "depth",
"create a shallow clone of that depth"),
+ OPT_BOOL(0, "single-branch", &option_single_branch,
+ "do not limit fetched refs in shallow clones"),
OPT_STRING(0, "separate-git-dir", &real_git_dir, "gitdir",
"separate git dir from working tree"),
OPT_STRING_LIST('c', "config", &option_config, "key=value",
@@ -427,9 +430,29 @@ 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 && option_single_branch)) {
+ get_fetch_map(refs, refspec, &tail, 0);
+ if (!option_mirror)
+ get_fetch_map(refs, tag_refspec, &tail, 0);
+ } else {
+ 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)
+ die(_("Remote branch \"%s\" not found. Nothing to clone.\n"
+ "Try --no-single-branch to fetch all refs."),
+ option_branch ? option_branch : "HEAD");
+ get_fetch_map(remote_head, refspec, &tail, 0);
+ }
return local_refs;
}
@@ -448,6 +471,21 @@ static void write_remote_refs(const struct ref *local_refs)
clear_extra_refs();
}
+static void write_followtags(const struct ref *refs, const char *msg)
+{
+ 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;
+ update_ref(msg, ref->name, ref->old_sha1,
+ NULL, 0, DIE_ON_ERR);
+ }
+}
+
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 +516,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 +679,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,
+ option_single_branch ? "1" : NULL);
+ }
transport_set_verbosity(transport, option_verbosity, option_progress);
@@ -663,6 +703,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
clear_extra_refs();
write_remote_refs(mapped_refs);
+ if (option_depth && option_single_branch)
+ write_followtags(refs, reflog_msg.buf);
remote_head = find_ref_by_name(refs, "HEAD");
remote_head_points_at =
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index bafcca7..c76a53b 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -115,7 +115,7 @@ pull_to_client 2nd "B" $((64*3))
pull_to_client 3rd "A" $((1*3))
test_expect_success 'clone shallow' '
- git clone --depth 2 "file://$(pwd)/." shallow
+ git clone --no-single-branch --depth 2 "file://$(pwd)/." shallow
'
test_expect_success 'clone shallow object count' '
@@ -248,4 +248,36 @@ test_expect_success 'clone shallow object count' '
grep "^count: 52" count.shallow
'
+test_expect_success 'clone shallow without --no-single-branch' '
+ git clone --depth 1 "file://$(pwd)/." shallow2
+'
+
+test_expect_success 'clone shallow object count' '
+ (
+ cd shallow2 &&
+ git count-objects -v
+ ) > count.shallow2 &&
+ grep "^in-pack: 6" count.shallow2
+'
+
+test_expect_success 'shallow clone pulling tags' '
+ git tag -a -m A TAGA1 A &&
+ git tag -a -m B TAGB1 B &&
+ git tag TAGA2 A &&
+ git tag TAGB2 B &&
+ git clone --depth 1 "file://$(pwd)/." shallow3 &&
+
+ cat >taglist.expected <<\EOF &&
+TAGB1
+TAGB2
+EOF
+ GIT_DIR=shallow3/.git git tag -l >taglist.actual &&
+ test_cmp taglist.expected taglist.actual &&
+
+ echo "in-pack: 7" > count3.expected &&
+ GIT_DIR=shallow3/.git git count-objects -v |
+ grep "^in-pack" > count3.actual &&
+ test_cmp count3.expected count3.actual
+'
+
test_done
--
1.7.3.1.256.g2539c.dirty
next prev parent reply other threads:[~2012-01-06 7:11 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-01-04 11:35 [PATCH] Do not fetch tags on new shallow clones Nguyễn Thái Ngọc Duy
2012-01-04 15:16 ` Shawn Pearce
2012-01-04 23:59 ` Junio C Hamano
2012-01-05 3:05 ` Shawn Pearce
2012-01-05 5:57 ` Junio C Hamano
2012-01-05 15:16 ` Shawn Pearce
2012-01-05 6:05 ` [PATCH v2] Limit refs to fetch to minimum in " Nguyễn Thái Ngọc Duy
2012-01-05 21:25 ` Junio C Hamano
2012-01-06 7:11 ` Nguyễn Thái Ngọc Duy [this message]
2012-01-06 18:40 ` [PATCH v3] " Junio C Hamano
2012-01-07 14:16 ` Nguyen Thai Ngoc Duy
2012-01-07 14:45 ` [PATCH v4] clone: add --single-branch to fetch only one branch Nguyễn Thái Ngọc Duy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1325833869-20078-1-git-send-email-pclouds@gmail.com \
--to=pclouds@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=spearce@spearce.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).