@@ -186,98 +186,104 @@ func (w *commitPostIterator) Close() {}
186
186
187
187
// commitAllIterator stands for commit iterator for all refs.
188
188
type commitAllIterator struct {
189
- // el points to the current commit.
190
- el * list.Element
189
+ // currCommit points to the current commit.
190
+ currCommit * list.Element
191
191
}
192
192
193
193
// NewCommitAllIter returns a new commit iterator for all refs.
194
- // s is a repo Storer used to get commits and references.
195
- // fn is a commit iterator function, used to iterate through ref commits in chosen order
196
- func NewCommitAllIter (s storage.Storer , fn func (* Commit ) CommitIter ) (CommitIter , error ) {
197
- l := list .New ()
198
- m := make (map [plumbing.Hash ]* list.Element )
199
-
200
- // ...along with the HEAD
201
- head , err := storer .ResolveReference (s , plumbing .HEAD )
194
+ // repoStorer is a repo Storer used to get commits and references.
195
+ // commitIterFunc is a commit iterator function, used to iterate through ref commits in chosen order
196
+ func NewCommitAllIter (repoStorer storage.Storer , commitIterFunc func (* Commit ) CommitIter ) (CommitIter , error ) {
197
+ commitsPath := list .New ()
198
+ commitsLookup := make (map [plumbing.Hash ]* list.Element )
199
+ head , err := storer .ResolveReference (repoStorer , plumbing .HEAD )
202
200
if err != nil {
203
201
return nil , err
204
202
}
205
- headCommit , err := GetCommit (s , head .Hash ())
206
- if err != nil {
203
+
204
+ // add all references along with the HEAD
205
+ if err = addReference (repoStorer , commitIterFunc , head , commitsPath , commitsLookup ); err != nil {
207
206
return nil , err
208
207
}
209
- err = fn (headCommit ).ForEach (func (c * Commit ) error {
210
- el := l .PushBack (c )
211
- m [c .Hash ] = el
212
- return nil
213
- })
208
+ refIter , err := repoStorer .IterReferences ()
214
209
if err != nil {
215
210
return nil , err
216
211
}
217
-
218
- refIter , err := s .IterReferences ()
212
+ defer refIter .Close ()
213
+ err = refIter .ForEach (
214
+ func (ref * plumbing.Reference ) error {
215
+ return addReference (repoStorer , commitIterFunc , ref , commitsPath , commitsLookup )
216
+ },
217
+ )
219
218
if err != nil {
220
219
return nil , err
221
220
}
222
- defer refIter .Close ()
223
- err = refIter .ForEach (func (r * plumbing.Reference ) error {
224
- if r .Hash () == head .Hash () {
225
- // we already have the HEAD
226
- return nil
227
- }
228
221
229
- el , ok := m [r .Hash ()]
230
- if ok {
231
- return nil
232
- }
222
+ return & commitAllIterator {commitsPath .Front ()}, nil
223
+ }
224
+
225
+ func addReference (
226
+ repoStorer storage.Storer ,
227
+ commitIterFunc func (* Commit ) CommitIter ,
228
+ ref * plumbing.Reference ,
229
+ commitsPath * list.List ,
230
+ commitsLookup map [plumbing.Hash ]* list.Element ) error {
231
+
232
+ _ , exists := commitsLookup [ref .Hash ()]
233
+ if exists {
234
+ // we already have it - skip the reference.
235
+ return nil
236
+ }
233
237
234
- var refCommits [] * Commit
235
- c , _ := GetCommit ( s , r . Hash ())
238
+ refCommit , _ := GetCommit ( repoStorer , ref . Hash ())
239
+ if refCommit == nil {
236
240
// if it's not a commit - skip it.
237
- if c == nil {
238
- return nil
241
+ return nil
242
+ }
243
+
244
+ var (
245
+ refCommits []* Commit
246
+ parent * list.Element
247
+ )
248
+ // collect all ref commits to add
249
+ commitIter := commitIterFunc (refCommit )
250
+ for c , e := commitIter .Next (); e == nil ; {
251
+ parent , exists = commitsLookup [c .Hash ]
252
+ if exists {
253
+ break
239
254
}
240
- cit := fn (c )
241
- for c , e := cit .Next (); e == nil ; {
242
- el , ok = m [c .Hash ]
243
- if ok {
244
- break
245
- }
246
- refCommits = append (refCommits , c )
247
- c , e = cit .Next ()
255
+ refCommits = append (refCommits , c )
256
+ c , e = commitIter .Next ()
257
+ }
258
+ commitIter .Close ()
259
+
260
+ if parent == nil {
261
+ // common parent - not found
262
+ // add all commits to the path from this ref (maybe it's a HEAD and we don't have anything, yet)
263
+ for _ , c := range refCommits {
264
+ parent = commitsPath .PushBack (c )
265
+ commitsLookup [c .Hash ] = parent
248
266
}
249
- cit .Close ()
250
-
251
- if el == nil {
252
- // push back all commits from this ref.
253
- for _ , c := range refCommits {
254
- el = l .PushBack (c )
255
- m [c .Hash ] = el
256
- }
257
- } else {
258
- // insert ref's commits into the list
259
- for i := len (refCommits ) - 1 ; i >= 0 ; i -- {
260
- c := refCommits [i ]
261
- el = l .InsertBefore (c , el )
262
- m [c .Hash ] = el
263
- }
267
+ } else {
268
+ // add ref's commits to the path in reverse order (from the latest)
269
+ for i := len (refCommits ) - 1 ; i >= 0 ; i -- {
270
+ c := refCommits [i ]
271
+ // insert before found common parent
272
+ parent = commitsPath .InsertBefore (c , parent )
273
+ commitsLookup [c .Hash ] = parent
264
274
}
265
- return nil
266
- })
267
- if err != nil {
268
- return nil , err
269
275
}
270
276
271
- return & commitAllIterator { l . Front ()}, nil
277
+ return nil
272
278
}
273
279
274
280
func (it * commitAllIterator ) Next () (* Commit , error ) {
275
- if it .el == nil {
281
+ if it .currCommit == nil {
276
282
return nil , io .EOF
277
283
}
278
284
279
- c := it .el .Value .(* Commit )
280
- it .el = it .el .Next ()
285
+ c := it .currCommit .Value .(* Commit )
286
+ it .currCommit = it .currCommit .Next ()
281
287
282
288
return c , nil
283
289
}
@@ -305,5 +311,5 @@ func (it *commitAllIterator) ForEach(cb func(*Commit) error) error {
305
311
}
306
312
307
313
func (it * commitAllIterator ) Close () {
308
- it .el = nil
314
+ it .currCommit = nil
309
315
}
0 commit comments