Robert
Robert

Reputation: 7053

Converting git repository to shallow?

How can I convert an already cloned git repository to a shallow repository?

The git repository is downloaded through a script outside of my control so I cannot do a shallow clone.

The reason for doing this is to save disk space. (Yes, I'm really short on disk space so even though a shallow repository doesn't save much, it is needed.)

I already tried

git repack -a -d -f -depth=1

But that actually made the repository larger.

Upvotes: 101

Views: 25466

Answers (8)

M Imam Pratama
M Imam Pratama

Reputation: 1309

git fetch --depth 1:

Limit fetching to the specified number of commits from the tip of each remote branch history. If fetching to a shallow repository created by git clone with --depth=<depth> option (see git-clone[1]), deepen or shorten the history to the specified number of commits. Tags for the deepened commits are not fetched.

git fetch --depth 1 or git pull --depth 1 will turn all branches into shallow/grafted branches since git fetch fetches all branches by default (unless it's a shallow clone where git clone --depth implies --single-branch).

To convert only one branch into a shallow/grafted branch, use git fetch --depth 1 <remote> <branch>.

Upvotes: 0

Jasen
Jasen

Reputation: 12412

This may seem like cheating, but check out a shallow copy of the repo and then replace the .git subdirectroy of your existing copy of the repo with the .git from with the new one.

You will lose any local custom git state like stash or local branches, but I'm guessing you want to purge that stuff too.

Upvotes: 0

fuzzyTew
fuzzyTew

Reputation: 3768

First, you may need to remove tags (as they prevent GC of tagged commits), like:

git tag -d $(git tag -l)

Then, this worked for me:

git pull --depth 1
git gc --prune=all

Which still leaves the reflog laying around, which like the tags references additional commits that can use up space. Note that I would not erase the reflog unless severely needed: it contains local change history used for recovery from mistakes.

There are additional commands on how to erase the reflog in the comments below, and a link to a similar question with a longer answer.

If you still have a lot of space used, ensure you removed the tags, which you should try first before removing the reflog.

Upvotes: 93

VasiliNovikov
VasiliNovikov

Reputation: 10256

Create shallow clone of a local repo:

git clone --depth 1 file:///full/path/to/original/dir destination

Note that the first "address" should be a file://, that's important. Also, git will assume your original local file:// address to be the "remote" ("origin"), so you'll need to update the new repository specifying the correct git remote.

Upvotes: 12

Samuel Marks
Samuel Marks

Reputation: 1898

Combining the answer from @fuzzyTew with what the comments on that answer:

git pull --depth 1
git tag -d $(git tag -l)
git reflog expire --expire=all --all
git gc --prune=all

Want to save space by running this across your entire disk? - Then run this fd command:

fd -HIFt d '.git' -x bash -c 'pushd "$0" && ( git pull --depth 1; git tag -d $(git tag -l); git reflog expire --expire=all --all; git gc --prune=all ) && popd' {//}

Or with just regular find:

find -type d -name '.git' -exec bash -c 'pushd "${0%/*}" && ( git pull --depth 1; git tag -d $(git tag -l); git reflog expire --expire=all --all; git gc --prune=all ) && popd' {} \;

Upvotes: 10

Pop Catalin
Pop Catalin

Reputation: 62960

Convert to shallow since a specific date:

git pull --shallow-since=YYYY-mm-dd
git gc --prune=all

Also works:

git fetch --shallow-since=YYYY-mm-dd
git gc --prune=all

Upvotes: 18

VonC
VonC

Reputation: 1325137

Note that a shallow repo (like one with git clone --depth 1 as a way to convert an existing repo to a shallow one) can fail on git repack.

See commit 5dcfbf5, commit 2588f6e, commit 328a435 (24 Oct 2018) by Johannes Schindelin (dscho).
(Merged by Junio C Hamano -- gitster -- in commit ea100b6, 06 Nov 2018)

repack -ad: prune the list of shallow commits

git repack can drop unreachable commits without further warning, making the corresponding entries in .git/shallow invalid, which causes serious problems when deepening the branches.

One scenario where unreachable commits are dropped by git repack is when a git fetch --prune (or even a git fetch when a ref was force-pushed in the meantime) can make a commit unreachable that was reachable before.

Therefore it is not safe to assume that a git repack -adlf will keep unreachable commits alone (under the assumption that they had not been packed in the first place, which is an assumption at least some of Git's code seems to make).

This is particularly important to keep in mind when looking at the .git/shallow file: if any commits listed in that file become unreachable, it is not a problem, but if they go missing, it is a problem.
One symptom of this problem is that a deepening fetch may now fail with:

fatal: error in object: unshallow <commit-hash>

To avoid this problem, let's prune the shallow list in git repack when the -d option is passed, unless -A is passed, too (which would force the now-unreachable objects to be turned into loose objects instead of being deleted).
Additionally, we also need to take --keep-reachable and --unpack-unreachable=<date> into account.

Note: an alternative solution discussed during the review of this patch was to teach git fetch to simply ignore entries in .git/shallow if the corresponding commits do not exist locally.
A quick test, however, revealed that the .git/shallow file is written during a shallow clone, in which case the commits do not exist, either, but the "shallow" line does need to be sent.
Therefore, this approach would be a lot more finicky than the approach presented by the this patch.

Upvotes: 3

user212328
user212328

Reputation: 620

You can convert git repo to a shallow one in place along this lines:

git show-ref -s HEAD > .git/shallow
git reflog expire --expire=0
git prune
git prune-packed

Make sure to make backup since this is destructive operation, also keep in mind that cloning nor fetching from shallow repo is not supported! To really remove all the history you also need to remove all references to previous commits before pruning.

Upvotes: 18

Related Questions