To walk history we need to read a commit back into its parts: the tree it points at, its parents, and its message. Today you parse a commit object, the inverse of building one.
Parse a commit object into its tree, parents, and message.
Parsing a commit mirrors parsing a tree, but it is line-oriented text. Split the
body at the first blank line: everything before it is headers, everything
after is the message. Each header line is a keyword and a value: tree with one
id, zero or more parent lines each with an id, and the author and committer
lines. Collect the parents into a list in the order they appear.
This gives us everything we need to traverse the commit graph. A commit knows its
tree (so we can inspect the snapshot) and its parents (so we can walk
backward through history). With reading in hand, log becomes a simple loop:
start at a commit, print it, follow the first parent, repeat. We build that once
we have refs to tell us where to start.
// header lines until the blank line: "tree X", "parent Y", "author ...";// everything after the blank line is the messagefunc (r *Repo) ReadCommit(id string) (*Commit, error) {_, _, body, _ := r.CatFile(id)// split on the first blank line; parse "key value" header lines}