diff options
author | Máximo Cuadros <mcuadros@gmail.com> | 2016-08-23 00:37:36 +0200 |
---|---|---|
committer | Máximo Cuadros <mcuadros@gmail.com> | 2016-08-23 00:37:36 +0200 |
commit | 9ae3c5808fcfa468d1f9394c9b16bc02f573ba79 (patch) | |
tree | 917c5dc717c02654baeebd06bef89436ad4c65ec | |
parent | 2ed3474ab8e52c98a87e390d5128d45d693a115d (diff) | |
download | go-git-9ae3c5808fcfa468d1f9394c9b16bc02f573ba79.tar.gz |
WalkCommitHistory adn Commit.History
-rw-r--r-- | commit.go | 18 | ||||
-rw-r--r-- | commit_test.go | 8 | ||||
-rw-r--r-- | commit_walker.go | 67 | ||||
-rw-r--r-- | commit_walker_test.go | 38 | ||||
-rw-r--r-- | examples/basic/main.go | 13 |
5 files changed, 144 insertions, 0 deletions
@@ -125,6 +125,18 @@ func (c *Commit) Decode(o core.Object) (err error) { } } +// History return a slice with the previous commits in the history of this commit +func (c *Commit) History() ([]*Commit, error) { + var commits []*Commit + err := WalkCommitHistory(c, func(commit *Commit) error { + commits = append(commits, commit) + return nil + }) + + ReverseSortCommits(commits) + return commits, err +} + func (c *Commit) String() string { return fmt.Sprintf( "%s %s\nAuthor: %s\nDate: %s\n", @@ -193,3 +205,9 @@ func SortCommits(l []*Commit) { s := &commitSorterer{l} sort.Sort(s) } + +// ReverseSortCommits sort a commit list by commit date, from newer to older. +func ReverseSortCommits(l []*Commit) { + s := &commitSorterer{l} + sort.Sort(sort.Reverse(s)) +} diff --git a/commit_test.go b/commit_test.go index 82133da..9a05cd8 100644 --- a/commit_test.go +++ b/commit_test.go @@ -72,6 +72,14 @@ func (s *SuiteCommit) TestNumParents(c *C) { c.Assert(s.Commit.NumParents(), Equals, 2) } +func (s *SuiteCommit) TestHistory(c *C) { + commits, err := s.Commit.History() + c.Assert(err, IsNil) + c.Assert(commits, HasLen, 5) + c.Assert(commits[0].Hash.String(), Equals, s.Commit.Hash.String()) + c.Assert(commits[len(commits)-1].Hash.String(), Equals, "b029517f6300c2da0f4b651b8642506cd6aaf45d") +} + func (s *SuiteCommit) TestString(c *C) { c.Assert(s.Commit.String(), Equals, ""+ "commit 1669dce138d9b841a518c64b10914d88f5e488ea\n"+ diff --git a/commit_walker.go b/commit_walker.go new file mode 100644 index 0000000..e595a84 --- /dev/null +++ b/commit_walker.go @@ -0,0 +1,67 @@ +package git + +import ( + "io" + + "gopkg.in/src-d/go-git.v4/core" +) + +type commitWalker struct { + seen map[core.Hash]bool + stack []*CommitIter + start *Commit + cb func(*Commit) error +} + +// WalkCommitHistory walks the commit history +func WalkCommitHistory(c *Commit, cb func(*Commit) error) error { + w := &commitWalker{ + seen: make(map[core.Hash]bool), + stack: make([]*CommitIter, 0), + start: c, + cb: cb, + } + + return w.walk() +} + +func (w *commitWalker) walk() error { + var commit *Commit + + if w.start != nil { + commit = w.start + w.start = nil + } else { + current := len(w.stack) - 1 + if current < 0 { + return nil + } + + var err error + commit, err = w.stack[current].Next() + if err == io.EOF { + w.stack = w.stack[:current] + return w.walk() + } + + if err != nil { + return err + } + } + + // check and update seen + if w.seen[commit.Hash] { + return w.walk() + } + + w.seen[commit.Hash] = true + if commit.NumParents() > 0 { + w.stack = append(w.stack, commit.Parents()) + } + + if err := w.cb(commit); err != nil { + return err + } + + return w.walk() +} diff --git a/commit_walker_test.go b/commit_walker_test.go new file mode 100644 index 0000000..cf239bc --- /dev/null +++ b/commit_walker_test.go @@ -0,0 +1,38 @@ +package git + +import . "gopkg.in/check.v1" + +type CommitWalkerSuite struct { + BaseSuite +} + +var _ = Suite(&CommitWalkerSuite{}) + +func (s *CommitWalkerSuite) TestWalkerNext(c *C) { + r, err := s.Repository.Head() + c.Assert(err, IsNil) + + commit, err := s.Repository.Commit(r.Hash()) + c.Assert(err, IsNil) + + var commits []*Commit + + WalkCommitHistory(commit, func(c *Commit) error { + commits = append(commits, c) + return nil + }) + + SortCommits(commits) + c.Assert(commits, HasLen, 8) + + expected := []string{ + "b029517f6300c2da0f4b651b8642506cd6aaf45d", "b8e471f58bcbca63b07bda20e428190409c2db47", + "35e85108805c84807bc66a02d91535e1e24b38b9", "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69", + "1669dce138d9b841a518c64b10914d88f5e488ea", "af2d6a6954d532f8ffb47615169c8fdf9d383a1a", + "918c48b83bd081e863dbe1b80f8998f058cd8294", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + } + + for i, commit := range commits { + c.Assert(commit.Hash.String(), Equals, expected[i]) + } +} diff --git a/examples/basic/main.go b/examples/basic/main.go index 85d6a57..4cdfa4b 100644 --- a/examples/basic/main.go +++ b/examples/basic/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "strings" "github.com/fatih/color" @@ -46,4 +47,16 @@ func main() { fmt.Printf("100644 blob %s %s\n", f.Hash, f.Name) return nil }) + + // List the history of the repository + // > git log --oneline + color.Blue("git log --oneline") + + commits, _ := commit.History() + for _, c := range commits { + hash := c.Hash.String() + line := strings.Split(c.Message, "\n") + fmt.Println(hash[:7], line[0]) + } + } |