0

I have a repo with two branches dist and master. When I do

git clone --no-hardlinks -b dist --single-branch test test-dist

then the resulting clone has the same (large) size as the original repo. Once I run

git gc --prune=all

the single-branch clone "test-dist" becomes much smaller, i.e. the size that I expected in the first place. When doing

git pull

in the single-branch repo afterwards the size isn't blown up again, it stays at the size of the branch I clone.

Am I doing something wrong while cloning the single branch? How do I avoid first doing a copy of the whole history, only to then delete most of it with git gc?

4
  • According to this Stack Overflow question, @Nobody, an equivalent output produced by the git clone command can be obtain using the git init .;git remote add -t \* -f origin <repository-url>;git checkout master sequence of git commands. Maybe it is worthwhile to try them out. Oct 2, 2020 at 14:34
  • @MihaiDobrescu I don't know how to adapt that sequence to a --single-branch clone, as it is the remote add step copies the whole history into the new repository.
    – Nobody
    Oct 2, 2020 at 14:53
  • I have seen that that sequence refers to a git checkout master git command, @Nobody, and that it has to be adapted to your case. I am hoping that you are going to adapt it to your own situation or that somebody else will help you to succeed in doing so. However, there might be nothing wrong with your initial sequence of git commands. Oct 2, 2020 at 15:04
  • According to the git-gc documentation page, such cleaning processes should be done very seldom. To quote exactly: "Running git gc manually should only be needed when adding objects to a repository without regularly running such porcelain commands, to do a one-off repository optimization, or e.g. to clean up a suboptimal mass-import." So maybe it is designed to behave this way and you are simply pushing its optimizations just too far. Oct 2, 2020 at 15:06

1 Answer 1

1

The option you're looking for is --no-local. From the git-clone(1) documentation option for --local (emphasis mine):

When the repository to clone from is on a local machine, this flag bypasses the normal "Git aware" transport mechanism and clones the repository by making a copy of HEAD and everything under objects and refs directories. The files under .git/objects/ directory are hardlinked to save space when possible.

If the repository is specified as a local path (e.g., /path/to/repo), this is the default, and --local is essentially a no-op. If the repository is specified as a URL, then this flag is ignored (and we never use the local optimizations). Specifying --no-local will override the default when /path/to/repo is given, using the regular Git transport instead.

When you use the --local option, either implicitly or explicitly, Git copies everything because it is much, much faster than walking the history and copying only the objects you asked for. You would need to copy most of the pack files anyway, because in most cases, at least one of the objects you've requested will be in a pack file. And if you use hardlinks, the copy is extremely cheap and adds no increased disk space usage, so there's really no reason not to do so.

If you use --no-local, you'll then get the normal transport output, which tells you that Git is really producing an independent pack and running it over the normal protocols.

Do note that it is possible for Git to unpack objects after a clone or fetch even when it uses the normal transport mechanisms; it depends on the number of objects transferred and the configuration. Small fetches will often have their objects unpacked because having many small, independent packs that don't share many objects aren't an efficient use of space; it's better to have the normal git gc process pack them more efficiently in the future.

1
  • Thanks, you are absolutely right. Makes sense the clone would be much slower that way.
    – Nobody
    Oct 3, 2020 at 10:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .