@@ -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