forked from jbrukh/ggit
/
commits.go
96 lines (88 loc) · 2.91 KB
/
commits.go
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
//
// Unless otherwise noted, this project is licensed under the Creative
// Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. Please
// see the README file.
//
// Copyright (c) 2012 The ggit Authors
//
/*
trees.go implements ggit Commit objects, their parsing and formatting,
and useful operations that allow users to resolve and navigate commits.
*/
package api
import (
"errors"
"fmt"
"github.com/jbrukh/ggit/api/objects"
)
// ================================================================= //
// COMMIT OPERATIONS
// ================================================================= //
func CommitNthParent(repo Repository, c *objects.Commit, n int) (rc *objects.Commit, err error) {
if n == 0 {
return c, nil
}
l := len(c.Parents())
if 0 < n && n <= l {
oid := c.Parents()[n-1]
return CommitFromOid(repo, oid)
}
return nil, fmt.Errorf("cannot find parent n=%d", n)
}
// CommitNthAncestor will look up a chain of n objects by
// following the first parent. If n == 0, then the parameterized
// commit is returned. If along the way, a commit is found
// to not have a first parent, an error is returned.
func CommitNthAncestor(repo Repository, c *objects.Commit, n int) (rc *objects.Commit, err error) {
rc = c
for i := 0; i < n; i++ {
if len(rc.Parents()) > 0 {
rc, err = CommitFromOid(repo, rc.Parents()[0])
if err != nil {
return nil, err
}
} else {
return nil, errors.New("no first parent")
}
}
return rc, nil
}
// CommitFromObject returns the commit being referred to; that is, if
// the object is a commit object, it is converted and returned. If the
// object is a tag, then the target of the tag is returned. Other object
// types cause an error to be returned.
func CommitFromObject(repo Repository, o objects.Object) (*objects.Commit, error) {
switch t := o.(type) {
case *objects.Commit:
return t, nil
case *objects.Tag:
obj, err := repo.ObjectFromOid(t.Object())
if err != nil {
return nil, err
}
return obj.(*objects.Commit), nil
}
return nil, errors.New("not a commit or tag")
}
// CommitFromOid takes an oid and turns it into a commit object. If the
// oid points at a commit, the Commit object is returned. If the oid
// points at an annotated tag, then the target commit is returned. If
// the oid points to another type of object, an error is returned.
func CommitFromOid(repo Repository, oid *objects.ObjectId) (*objects.Commit, error) {
o, err := repo.ObjectFromOid(oid)
if err != nil {
return nil, err
}
return CommitFromObject(repo, o)
}
// CommitFromRef turns a full reference to be converted to the commit
// object. If the reference is a reference to a commit, the commit
// object is returned. If the reference is a tag, then the target commit
// of the tag is returned.
func CommitFromRef(repo Repository, spec string) (*objects.Commit, error) {
o, err := ObjectFromRef(repo, spec)
if err != nil {
return nil, err
}
return CommitFromObject(repo, o)
}