go-git
go-git copied to clipboard
Unshallow support
Currently, there's no way to directly unshallow a repo clone; the workaround is to fetch with Depth: <really-big-number>
. It'd be nice if there were a way to do the equivalent of git fetch --unshallow
Thanks!
@novas0x2a , did you test fetch with Depth: <really-big-number>
? This doesn't seem to work for me. I am currently iterating over logs in a shallow clone which results in plumbing.ErrObjectNotFound
(returned by the Next()
func on iterators) if I hit the end of the shallow log. So then i attempt to fetch:
if err == plumbing.ErrObjectNotFound {
depth := 50
err := repo.Fetch(&git.FetchOptions{Depth: depth})
if err != nil {
return "", fmt.Errorf("failed to fetch %d: %v", depth, err)
}
}
but this simply results in:
failed to fetch 50: already up-to-date
50 isn't a particularly big number in this case. Did you try, like, 999999?
Actually, I'm working on a very controlled test case. In the test, i commit 3 times, and do a git clone --depth 1
in order to mimic what our CI is doing. As such, the 50 should be plenty...
I walked through a lot of the fetch
code and came across this code:
req.Wants, err = getWants(r.s, refs)
if len(req.Wants) > 0 {
req.Haves, err = getHaves(localRefs, remoteRefs, r.s)
if err != nil {
return nil, err
}
if err = r.fetchPack(ctx, o, s, req); err != nil {
return nil, err
}
}
It appears the r.fetchPack
only occurs if getWants
returns more than one. But getWants
only seems to check the hash at the tip of each branch:
wants := map[plumbing.Hash]bool{}
for _, ref := range refs {
hash := ref.Hash()
exists, err := objectExists(localStorer, ref.Hash())
if err != nil {
return nil, err
}
if !exists {
wants[hash] = true
}
}
So since its a shallow clone it has the same tip as the remote and no wants are detected.
I was able to work around this by creating a new remote... Its kinda crazy to have to do that though:
if err == plumbing.ErrObjectNotFound {
depth := 50
remote, err := repo.Remote("origin")
if err != nil {
return "", fmt.Errorf("remote origin: %v", err)
}
if len(remote.Config().URLs) != 1 {
return "", fmt.Errorf("origin urls %v", remote.Config())
}
r.SetRemote("foo", remote.Config().URLs[0])
err = repo.Fetch(&git.FetchOptions{RemoteName: "foo", Depth: depth})
if err != nil {
return "", fmt.Errorf("failed to fetch %d, parent %v: %v", depth, parent, err)
}
} else if err != nil && err != versionChanged {
return "", err
}
UPDATE: Nevermind, this workaround doesn't help because it just compares the hash from the different remote with the local hashes... And its already there.
Submitted #1250