On Thu, Apr 27, 2017 at 7:54 PM, Stefan Beller <sbeller@xxxxxxxxxx> wrote: > On Wed, Apr 26, 2017 at 4:12 PM, Ævar Arnfjörð Bjarmason > <avarab@xxxxxxxxx> wrote: >> 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@xxxxxxxxxx: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@xxxxxxxxxx: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@xxxxxxxxxx: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@xxxxxxxxxx:git/git.git >> >> Or in the case of cloning a single tag "branch": >> >> git clone --single-branch --branch v2.12.0 --no-tags git@xxxxxxxxxx:git/git.git >> >> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@xxxxxxxxx> > > I like the option, though I dislike the implementation, specifically as you > brought up e.g. "[PATCH] various: disallow --no-no-OPT for --no-opt options". > > Can we have an option "--tags" instead, which is on by default > and then you can negate it to --no-tags, without having to worry > about the no-no case. > > The problem with tags is that they are in a shared name-space > and not part of the remote refspec. If they were, the documentation > would be way easier, too going this way. I don't mind doing it this way, but this really should be part of an unrelated topic to eliminate --no-OPT in favor of just --OPT which is supplied by default, if we want to go that route. Right now it makes more sense to have a --no-tags, because this along with e.g. --no-hardlinks and numerous other options[1] is for an obscure use-case most users won't care about, and then we have & document --no-BEHAVIOR. Perhaps we shouldn't have that at all, go through all these --no-OPT and replace them with --OPT in both the docs & code & get rid of the --no-no-OPT & some confusion that way. 1. git grep -- '\[--no-' Documentation/git-*txt >> +--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. > > In the future we may want to have '--depth' also imply --no-tags, > just as it implies --single-branch. Are there some cases where we'd like to also somehow import & rewrite tags covering the given --depth? >> @@ -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) > > I am debating if this needs to be an || instead of &&, as you would not > want to write the tags with "--no-single-branch --no-tags" ? This hunk is confusing out of context, but I believe it's doing the right thing now. This write_followtags() codepath is only taken (and is only meaningful) with --single-branch, there's an earlier change just before that: - if (!option_mirror && !option_single_branch) + if (!option_mirror && !option_single_branch && !option_no_tags) get_fetch_map(refs, tag_refspec, &tail, 0); Which ensures that with --no-single-branch --no-tags that tags aren't written, and there's tests for that.