From: "Ævar Arnfjörð Bjarmason" <avarab@gmail.com>
To: git@vger.kernel.org
Cc: "Junio C Hamano" <gitster@pobox.com>,
"Brandon Williams" <bmwill@google.com>,
"Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>,
"Jonathan Nieder" <jrnieder@gmail.com>,
"Stefan Beller" <sbeller@google.com>,
"Ævar Arnfjörð Bjarmason" <avarab@gmail.com>
Subject: [PATCH v3 2/5] clone: add a --no-tags option to clone without tags
Date: Wed, 26 Apr 2017 23:12:33 +0000 [thread overview]
Message-ID: <20170426231236.27219-3-avarab@gmail.com> (raw)
In-Reply-To: <20170426231236.27219-1-avarab@gmail.com>
Add a --no-tags option to clone without fetching any tags.
Without this change there's no easy way to clone a repository without
also fetching its tags.
When supplying --single-branch the primary remote branch will be
cloned, but in addition tags will be followed & retrieved. Now
--no-tags can be added --single-branch to clone a repository without
tags, and which only tracks a single upstream branch.
This option works without --single-branch as well, and will do a
normal clone but not fetch any tags.
Many git commands pay some fixed overhead as a function of the number
of references. E.g. creating ~40k tags in linux.git will cause a
command like `git log -1 >/dev/null` to run in over a second instead
of in a matter of milliseconds, in addition numerous other things will
slow down, e.g. "git log <TAB>" with the bash completion will slowly
show ~40k references instead of 1.
The user might want to avoid all of that overhead to simply use a
repository like that to browse the "master" branch, or something like
a CI tool might want to keep that one branch up-to-date without caring
about any other references.
Without this change the only way of accomplishing this was either by
manually tweaking the config in a fresh repository:
git init git &&
cat >git/.git/config <<EOF &&
[remote "origin"]
url = git@github.com:git/git.git
tagOpt = --no-tags
fetch = +refs/heads/master:refs/remotes/origin/master
[branch "master"]
remote = origin
merge = refs/heads/master
EOF
cd git &&
git pull
Which requires hardcoding the "master" name, which may not be the main
--single-branch would have retrieved, or alternatively by setting
tagOpt=--no-tags right after cloning & deleting any existing tags:
git clone --single-branch git@github.com:git/git.git &&
cd git &&
git config remote.origin.tagOpt --no-tags &&
git tag -l | xargs git tag -d
Which of course was also subtly buggy if --branch was pointed at a
tag, leaving the user in a detached head:
git clone --single-branch --branch v2.12.0 git@github.com:git/git.git &&
cd git &&
git config remote.origin.tagOpt --no-tags &&
git tag -l | xargs git tag -d
Now all this complexity becomes the much simpler:
git clone --single-branch --no-tags git@github.com:git/git.git
Or in the case of cloning a single tag "branch":
git clone --single-branch --branch v2.12.0 --no-tags git@github.com:git/git.git
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
Documentation/git-clone.txt | 14 ++++++-
builtin/clone.c | 13 +++++-
contrib/completion/git-completion.bash | 1 +
t/t5612-clone-refspec.sh | 76 +++++++++++++++++++++++++++++++++-
4 files changed, 99 insertions(+), 5 deletions(-)
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 30052cce49..83c8e9b394 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -13,7 +13,7 @@ SYNOPSIS
[-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
[-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>]
[--dissociate] [--separate-git-dir <git dir>]
- [--depth <depth>] [--[no-]single-branch]
+ [--depth <depth>] [--[no-]single-branch] [--no-tags]
[--recurse-submodules] [--[no-]shallow-submodules]
[--jobs <n>] [--] <repository> [<directory>]
@@ -215,6 +215,18 @@ objects from the source repository into a pack in the cloned repository.
branch when `--single-branch` clone was made, no remote-tracking
branch is created.
+--no-tags::
+ Don't clone any tags, and set
+ `remote.<remote>.tagOpt=--no-tags` in the config, ensuring
+ that future `git pull` and `git fetch` operations won't follow
+ any tags. Subsequent explicit tag fetches will still work,
+ (see linkgit:git-fetch[1]).
++
+Can be used in conjunction with `--single-branch` to clone and
+maintain a branch with no references other than a single cloned
+branch. This is useful e.g. to maintain minimal clones of the default
+branch of some repository for search indexing.
+
--recurse-submodules[=<pathspec]::
After the clone is created, initialize and clone submodules
within based on the provided pathspec. If no pathspec is
diff --git a/builtin/clone.c b/builtin/clone.c
index de85b85254..05f52d6f2b 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -40,6 +40,7 @@ static const char * const builtin_clone_usage[] = {
static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;
static int option_local = -1, option_no_hardlinks, option_shared;
+static int option_no_tags;
static int option_shallow_submodules;
static int deepen;
static char *option_template, *option_depth, *option_since;
@@ -120,6 +121,8 @@ static struct option builtin_clone_options[] = {
N_("deepen history of shallow clone, excluding rev")),
OPT_BOOL(0, "single-branch", &option_single_branch,
N_("clone only one branch, HEAD or --branch")),
+ OPT_BOOL(0, "no-tags", &option_no_tags,
+ N_("don't clone any tags, and make later fetches not to follow them")),
OPT_BOOL(0, "shallow-submodules", &option_shallow_submodules,
N_("any cloned submodules will be shallow")),
OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
@@ -563,7 +566,7 @@ static struct ref *wanted_peer_refs(const struct ref *refs,
} else
get_fetch_map(refs, refspec, &tail, 0);
- if (!option_mirror && !option_single_branch)
+ if (!option_mirror && !option_single_branch && !option_no_tags)
get_fetch_map(refs, tag_refspec, &tail, 0);
return local_refs;
@@ -652,7 +655,7 @@ static void update_remote_refs(const struct ref *refs,
if (refs) {
write_remote_refs(mapped_refs);
- if (option_single_branch)
+ if (option_single_branch && !option_no_tags)
write_followtags(refs, msg);
}
@@ -1035,6 +1038,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
git_config_set(key.buf, repo);
strbuf_reset(&key);
+ if (option_no_tags) {
+ strbuf_addf(&key, "remote.%s.tagOpt", option_origin);
+ git_config_set(key.buf, "--no-tags");
+ strbuf_reset(&key);
+ }
+
if (option_required_reference.nr || option_optional_reference.nr)
setup_reference();
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 1150164d5c..6da997cf42 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1309,6 +1309,7 @@ _git_clone ()
--template=
--depth
--single-branch
+ --no-tags
--branch
--recurse-submodules
--no-single-branch
diff --git a/t/t5612-clone-refspec.sh b/t/t5612-clone-refspec.sh
index 97c847fab6..fac5a73851 100755
--- a/t/t5612-clone-refspec.sh
+++ b/t/t5612-clone-refspec.sh
@@ -17,13 +17,20 @@ test_expect_success 'setup' '
echo four >file &&
git commit -a -m four &&
git checkout master &&
+ git tag five &&
# default clone
git clone . dir_all &&
+ # default clone --no-tags
+ git clone --no-tags . dir_all_no_tags &&
+
# default --single that follows HEAD=master
git clone --single-branch . dir_master &&
+ # default --single that follows HEAD=master with no tags
+ git clone --single-branch --no-tags . dir_master_no_tags &&
+
# default --single that follows HEAD=side
git checkout side &&
git clone --single-branch . dir_side &&
@@ -45,6 +52,9 @@ test_expect_success 'setup' '
# explicit --single with tag
git clone --single-branch --branch two . dir_tag &&
+ # explicit --single with tag and --no-tags
+ git clone --single-branch --no-tags --branch two . dir_tag_no_tags &&
+
# advance both "master" and "side" branches
git checkout side &&
echo five >file &&
@@ -77,7 +87,18 @@ test_expect_success 'by default no tags will be kept updated' '
git for-each-ref refs/tags >../actual
) &&
git for-each-ref refs/tags >expect &&
- test_must_fail test_cmp expect actual
+ test_must_fail test_cmp expect actual &&
+ test_line_count = 2 actual
+'
+
+test_expect_success 'clone with --no-tags' '
+ (
+ cd dir_all_no_tags &&
+ git fetch &&
+ git for-each-ref refs/tags >../actual
+ ) &&
+ >expect &&
+ test_cmp expect actual
'
test_expect_success '--single-branch while HEAD pointing at master' '
@@ -90,7 +111,47 @@ test_expect_success '--single-branch while HEAD pointing at master' '
) &&
# only follow master
git for-each-ref refs/heads/master >expect &&
- test_cmp expect actual
+ # get & check latest tags
+ test_cmp expect actual &&
+ (
+ cd dir_master &&
+ git fetch --tags &&
+ git for-each-ref refs/tags >../actual
+ ) &&
+ git for-each-ref refs/tags >expect &&
+ test_cmp expect actual &&
+ test_line_count = 2 actual
+'
+
+test_expect_success '--single-branch while HEAD pointing at master and --no-tags' '
+ (
+ cd dir_master_no_tags &&
+ git fetch &&
+ git for-each-ref refs/remotes/origin |
+ sed -e "/HEAD$/d" \
+ -e "s|/remotes/origin/|/heads/|" >../actual
+ ) &&
+ # only follow master
+ git for-each-ref refs/heads/master >expect &&
+ test_cmp expect actual &&
+ # get tags (noop)
+ (
+ cd dir_master_no_tags &&
+ git fetch &&
+ git for-each-ref refs/tags >../actual
+ ) &&
+ >expect &&
+ test_cmp expect actual &&
+ test_line_count = 0 actual &&
+ # get tags with --tags overrides tagOpt
+ (
+ cd dir_master_no_tags &&
+ git fetch --tags &&
+ git for-each-ref refs/tags >../actual
+ ) &&
+ git for-each-ref refs/tags >expect &&
+ test_cmp expect actual &&
+ test_line_count = 2 actual
'
test_expect_success '--single-branch while HEAD pointing at side' '
@@ -129,6 +190,17 @@ test_expect_success '--single-branch with explicit --branch with tag fetches upd
test_cmp expect actual
'
+test_expect_success '--single-branch with explicit --branch with tag fetches updated tag despite --no-tags' '
+ (
+ cd dir_tag_no_tags &&
+ git fetch &&
+ git for-each-ref refs/tags >../actual
+ ) &&
+ git for-each-ref refs/tags/two >expect &&
+ test_cmp expect actual &&
+ test_line_count = 1 actual
+'
+
test_expect_success '--single-branch with --mirror' '
(
cd dir_mirror &&
--
2.11.0
next prev parent reply other threads:[~2017-04-26 23:13 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-04-26 23:12 [PATCH v3 0/5] clone: --no-tags option Ævar Arnfjörð Bjarmason
2017-04-26 23:12 ` [PATCH v3 1/5] tests: change "cd ... && git fetch" to "cd &&\n\tgit fetch" Ævar Arnfjörð Bjarmason
2017-04-26 23:12 ` Ævar Arnfjörð Bjarmason [this message]
2017-04-27 17:54 ` [PATCH v3 2/5] clone: add a --no-tags option to clone without tags Stefan Beller
2017-04-27 22:12 ` Brandon Williams
2017-04-28 14:44 ` Ævar Arnfjörð Bjarmason
2017-04-26 23:12 ` [PATCH v3 3/5] tests: rename a test having to do with shallow submodules Ævar Arnfjörð Bjarmason
2017-04-27 17:58 ` Stefan Beller
2017-04-27 22:13 ` Brandon Williams
2017-04-28 8:59 ` Ævar Arnfjörð Bjarmason
2017-04-28 17:50 ` Stefan Beller
2017-04-26 23:12 ` [PATCH v3 4/5] clone: add a --no-tags-submodules to pass --no-tags to submodules Ævar Arnfjörð Bjarmason
2017-04-27 2:34 ` Junio C Hamano
2017-04-27 16:33 ` Brandon Williams
2017-04-27 18:27 ` Stefan Beller
2017-04-27 22:19 ` Brandon Williams
2017-04-26 23:12 ` [RFC/PATCH v3 5/5] WIP clone: add a --[no-]recommend-tags & submodule.NAME.tags config Ævar Arnfjörð Bjarmason
2017-04-27 19:36 ` Stefan Beller
2017-04-27 22:27 ` [PATCH v3 0/5] clone: --no-tags option Brandon Williams
2017-04-28 8:57 ` Ævar Arnfjörð Bjarmason
2017-04-28 19:11 ` Ævar Arnfjörð Bjarmason
2017-04-28 19:16 ` Stefan Beller
2017-05-01 1:31 ` Junio C Hamano
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=20170426231236.27219-3-avarab@gmail.com \
--to=avarab@gmail.com \
--cc=bmwill@google.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=jrnieder@gmail.com \
--cc=pclouds@gmail.com \
--cc=sbeller@google.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.