Skip to content

Commit 49ac629

Browse files
committed
feat(cli): implement delta-push object reachability pruning
1 parent 1a1f10a commit 49ac629

1 file changed

Lines changed: 24 additions & 9 deletions

File tree

internal/cli/push.go

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,23 @@ func Push(repoPath, daemonURL, repoID string, refNames ...string) error {
8585
return nil
8686
}
8787

88-
// Collect all reachable objects
89-
gitObjects, err := collectObjects(repo, commitHashes)
88+
// Build map of commits and trees already present on the remote to prune the walk (delta push)
89+
remoteCommits := make(map[string]bool)
90+
remoteTrees := make(map[string]bool)
91+
for _, remoteHashStr := range remoteRefs {
92+
remoteHash := plumbing.NewHash(remoteHashStr)
93+
if commit, err := repo.CommitObject(remoteHash); err == nil {
94+
commitIter := object.NewCommitPreorderIter(commit, nil, nil)
95+
_ = commitIter.ForEach(func(c *object.Commit) error {
96+
remoteCommits[c.Hash.String()] = true
97+
remoteTrees[c.TreeHash.String()] = true
98+
return nil
99+
})
100+
}
101+
}
102+
103+
// Collect all reachable objects (excluding remote ones)
104+
gitObjects, err := collectObjects(repo, commitHashes, remoteCommits, remoteTrees)
90105
if err != nil {
91106
return fmt.Errorf("collecting objects: %w", err)
92107
}
@@ -155,8 +170,8 @@ func createPackfile(objects []GitObject) ([]byte, error) {
155170
return writer.WritePackfile(gitObjects)
156171
}
157172

158-
// collectObjects walks the git graph from the given commits and collects all reachable objects
159-
func collectObjects(repo *git.Repository, hashes []plumbing.Hash) ([]GitObject, error) {
173+
// collectObjects walks the git graph from the given commits and collects all reachable objects (excluding remote ones)
174+
func collectObjects(repo *git.Repository, hashes []plumbing.Hash, remoteCommits map[string]bool, remoteTrees map[string]bool) ([]GitObject, error) {
160175
seen := make(map[string]bool)
161176
var objects []GitObject
162177

@@ -168,7 +183,7 @@ func collectObjects(repo *git.Repository, hashes []plumbing.Hash) ([]GitObject,
168183
// Walk commits
169184
commitIter := object.NewCommitPreorderIter(commit, nil, nil)
170185
commitIter.ForEach(func(c *object.Commit) error {
171-
if seen[c.Hash.String()] {
186+
if remoteCommits[c.Hash.String()] || seen[c.Hash.String()] {
172187
return nil
173188
}
174189
seen[c.Hash.String()] = true
@@ -182,7 +197,7 @@ func collectObjects(repo *git.Repository, hashes []plumbing.Hash) ([]GitObject,
182197
// Add tree and blobs
183198
tree, err := repo.TreeObject(c.TreeHash)
184199
if err == nil {
185-
treeObjs, err := collectTreeObjects(repo, tree, seen)
200+
treeObjs, err := collectTreeObjects(repo, tree, seen, remoteTrees)
186201
if err == nil {
187202
objects = append(objects, treeObjs...)
188203
}
@@ -195,10 +210,10 @@ func collectObjects(repo *git.Repository, hashes []plumbing.Hash) ([]GitObject,
195210
}
196211

197212
// collectTreeObjects recursively collects tree and blob objects
198-
func collectTreeObjects(repo *git.Repository, tree *object.Tree, seen map[string]bool) ([]GitObject, error) {
213+
func collectTreeObjects(repo *git.Repository, tree *object.Tree, seen map[string]bool, remoteTrees map[string]bool) ([]GitObject, error) {
199214
var objects []GitObject
200215

201-
if seen[tree.Hash.String()] {
216+
if remoteTrees[tree.Hash.String()] || seen[tree.Hash.String()] {
202217
return objects, nil
203218
}
204219
seen[tree.Hash.String()] = true
@@ -223,7 +238,7 @@ func collectTreeObjects(repo *git.Repository, tree *object.Tree, seen map[string
223238
case filemode.Dir:
224239
subtree, err := repo.TreeObject(entry.Hash)
225240
if err == nil {
226-
subObjs, err := collectTreeObjects(repo, subtree, seen)
241+
subObjs, err := collectTreeObjects(repo, subtree, seen, remoteTrees)
227242
if err == nil {
228243
objects = append(objects, subObjs...)
229244
}

0 commit comments

Comments
 (0)