mugit/internal/git/diff.go(view raw)
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 131 |
package git
import (
"fmt"
"strings"
"github.com/bluekeyes/go-gitdiff/gitdiff"
"github.com/go-git/go-git/v5/plumbing/object"
)
type TextFragment struct {
Header string
Lines []gitdiff.Line
}
type Diff struct {
Name struct {
Old string
New string
}
TextFragments []TextFragment
IsBinary bool
IsNew bool
IsDelete bool
}
type NiceDiff struct {
Diff []Diff
Commit struct {
Commit
This string
Parent string
}
Stat struct {
FilesChanged int
Insertions int
Deletions int
}
}
func (g *Repo) Diff() (*NiceDiff, error) {
c, err := g.r.CommitObject(g.h)
if err != nil {
return nil, fmt.Errorf("commit object: %w", err)
}
patch, parent, err := g.getPatch(c)
if err != nil {
return nil, err
}
diffs, _, err := gitdiff.Parse(strings.NewReader(patch.String()))
if err != nil {
return nil, fmt.Errorf("parsing diff: %w", err)
}
nd := NiceDiff{}
nd.Commit.Message = c.Message
nd.Commit.Hash = c.Hash.String()
nd.Commit.HashShort = c.Hash.String()[:8]
nd.Commit.AuthorEmail = c.Author.Email
nd.Commit.AuthorName = c.Author.Name
nd.Commit.This = c.Hash.String()
nd.Commit.Parent = getParentHash(parent)
nd.Stat.FilesChanged = len(diffs)
nd.Diff = make([]Diff, len(diffs))
for i, d := range diffs {
diff := &nd.Diff[i]
diff.Name.New = d.NewName
if d.OldName != d.NewName {
diff.Name.Old = d.OldName
}
diff.IsBinary = d.IsBinary
diff.IsNew = d.IsNew
diff.IsDelete = d.IsDelete
for _, tf := range d.TextFragments {
diff.TextFragments = append(diff.TextFragments, TextFragment{
Header: tf.Header(),
Lines: tf.Lines,
})
for _, l := range tf.Lines {
switch l.Op {
case gitdiff.OpAdd:
nd.Stat.Insertions += 1
case gitdiff.OpDelete:
nd.Stat.Deletions += 1
}
}
}
}
return &nd, nil
}
func (g *Repo) getPatch(c *object.Commit) (*object.Patch, *object.Commit, error) {
commitTree, err := c.Tree()
if err != nil {
return nil, nil, err
}
var parentTree *object.Tree
var parent *object.Commit
if c.NumParents() != 0 {
parent, err = c.Parents().Next()
if err != nil {
return nil, nil, err
}
parentTree, err = parent.Tree()
if err != nil {
return nil, nil, err
}
} else {
parentTree = &object.Tree{}
}
patch, err := parentTree.Patch(commitTree)
if err != nil {
return nil, nil, fmt.Errorf("patch: %w", err)
}
return patch, parent, nil
}
func getParentHash(parent *object.Commit) string {
if parent == nil || parent.Hash.IsZero() {
return ""
}
return parent.Hash.String()
}
|