1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
package object
import (
"fmt"
"time"
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph"
"gopkg.in/src-d/go-git.v4/plumbing/storer"
)
// graphCommitNode is a reduced representation of Commit as presented in the commit
// graph file (commitgraph.Node). It is merely useful as an optimization for walking
// the commit graphs.
//
// graphCommitNode implements the CommitNode interface.
type graphCommitNode struct {
// Hash for the Commit object
hash plumbing.Hash
// Index of the node in the commit graph file
index int
commitData *commitgraph.CommitData
gci *graphCommitNodeIndex
}
// graphCommitNodeIndex is an index that can load CommitNode objects from both the commit
// graph files and the object store.
//
// graphCommitNodeIndex implements the CommitNodeIndex interface
type graphCommitNodeIndex struct {
commitGraph commitgraph.Index
s storer.EncodedObjectStorer
}
// NewGraphCommitNodeIndex returns CommitNodeIndex implementation that uses commit-graph
// files as backing storage and falls back to object storage when necessary
func NewGraphCommitNodeIndex(commitGraph commitgraph.Index, s storer.EncodedObjectStorer) CommitNodeIndex {
return &graphCommitNodeIndex{commitGraph, s}
}
func (gci *graphCommitNodeIndex) Get(hash plumbing.Hash) (CommitNode, error) {
// Check the commit graph first
parentIndex, err := gci.commitGraph.GetIndexByHash(hash)
if err == nil {
parent, err := gci.commitGraph.GetCommitDataByIndex(parentIndex)
if err != nil {
return nil, err
}
return &graphCommitNode{
hash: hash,
index: parentIndex,
commitData: parent,
gci: gci,
}, nil
}
// Fallback to loading full commit object
commit, err := GetCommit(gci.s, hash)
if err != nil {
return nil, err
}
return &objectCommitNode{
nodeIndex: gci,
commit: commit,
}, nil
}
func (c *graphCommitNode) ID() plumbing.Hash {
return c.hash
}
func (c *graphCommitNode) Tree() (*Tree, error) {
return GetTree(c.gci.s, c.commitData.TreeHash)
}
func (c *graphCommitNode) CommitTime() time.Time {
return c.commitData.When
}
func (c *graphCommitNode) NumParents() int {
return len(c.commitData.ParentIndexes)
}
func (c *graphCommitNode) ParentNodes() CommitNodeIter {
return newParentgraphCommitNodeIter(c)
}
func (c *graphCommitNode) ParentNode(i int) (CommitNode, error) {
if i < 0 || i >= len(c.commitData.ParentIndexes) {
return nil, ErrParentNotFound
}
parent, err := c.gci.commitGraph.GetCommitDataByIndex(c.commitData.ParentIndexes[i])
if err != nil {
return nil, err
}
return &graphCommitNode{
hash: c.commitData.ParentHashes[i],
index: c.commitData.ParentIndexes[i],
commitData: parent,
gci: c.gci,
}, nil
}
func (c *graphCommitNode) ParentHashes() []plumbing.Hash {
return c.commitData.ParentHashes
}
func (c *graphCommitNode) Generation() uint64 {
// If the commit-graph file was generated with older Git version that
// set the generation to zero for every commit the generation assumption
// is still valid. It is just less useful.
return uint64(c.commitData.Generation)
}
func (c *graphCommitNode) Commit() (*Commit, error) {
return GetCommit(c.gci.s, c.hash)
}
func (c *graphCommitNode) String() string {
return fmt.Sprintf(
"%s %s\nDate: %s",
plumbing.CommitObject, c.ID(),
c.CommitTime().Format(DateFormat),
)
}
|