in pkg/git/mainline.go [68:136]
func MergePoints(r *gogit.Repository, mainLine []*object.Commit) (map[plumbing.Hash]*object.Commit, error) {
// create lookup table for the position in mainLine
mainLinePos := map[plumbing.Hash]int{}
for i, c := range mainLine {
mainLinePos[c.Hash] = i
}
earliestMergePoints := map[plumbing.Hash]int{} // the earlist mainline commit index a given commit was merged into the mainline
seen := map[plumbing.Hash]*object.Commit{}
// pos is the position of the current mainline commit, h
var visit func(pos int, h plumbing.Hash) error
visit = func(pos int, h plumbing.Hash) error {
// stop if we reached the mainline
if _, isOnMainLine := mainLinePos[h]; isOnMainLine {
return nil
}
// was h seen before as descendent of a mainline commit? It must have had
// a better position as we saw it earlier.
if _, seenBefore := earliestMergePoints[h]; seenBefore {
return nil
}
earliestMergePoints[h] = pos
// resolve hash
c := seen[h]
if c == nil {
var err error
c, err = cache.CommitObject(r, h)
if err != nil {
return fmt.Errorf("failed to get %s: %v", h.String(), err)
}
seen[h] = c
}
// recurse into parents
for _, ph := range c.ParentHashes {
err := visit(pos, ph)
if err != nil {
return err
}
}
return nil
}
// recursively enumerate all reachable commits
for pos := len(mainLine) - 1; pos >= 0; pos-- {
c := mainLine[pos]
earliestMergePoints[c.Hash] = pos
seen[c.Hash] = c
for _, ph := range c.ParentHashes {
err := visit(pos, ph)
if err != nil {
return nil, err
}
}
}
// map commit hash to best merge point on mainline
result := map[plumbing.Hash]*object.Commit{}
for _, c := range seen {
result[c.Hash] = mainLine[earliestMergePoints[c.Hash]]
}
return result, nil
}