git/diff.go (view raw)
1package git
2
3import (
4 "fmt"
5 "log"
6 "strings"
7
8 "github.com/bluekeyes/go-gitdiff/gitdiff"
9 "github.com/go-git/go-git/v5/plumbing/object"
10)
11
12type TextFragment struct {
13 Header string
14 Lines []gitdiff.Line
15}
16
17type Diff struct {
18 Name struct {
19 Old string
20 New string
21 }
22 TextFragments []TextFragment
23}
24
25// A nicer git diff representation.
26type NiceDiff struct {
27 Commit struct {
28 Message string
29 Author object.Signature
30 This string
31 Parent string
32 }
33 Stat struct {
34 FilesChanged int
35 Insertions int
36 Deletions int
37 }
38 Diff []Diff
39}
40
41func (g *GitRepo) Diff() (*NiceDiff, error) {
42 c, err := g.r.CommitObject(g.h)
43 if err != nil {
44 return nil, fmt.Errorf("commit object: %w", err)
45 }
46
47 var parent *object.Commit
48 if len(c.ParentHashes) > 0 {
49 parent, err = c.Parent(0)
50 if err != nil {
51 return nil, fmt.Errorf("getting parent: %w", err)
52 }
53 } else {
54 parent = c
55 }
56
57 patch, err := parent.Patch(c)
58 if err != nil {
59 return nil, fmt.Errorf("patch: %w", err)
60 }
61
62 diffs, _, err := gitdiff.Parse(strings.NewReader(patch.String()))
63 if err != nil {
64 log.Println(err)
65 }
66
67 nd := NiceDiff{}
68 nd.Commit.This = c.Hash.String()
69 nd.Commit.Parent = parent.Hash.String()
70 nd.Commit.Author = c.Author
71 nd.Commit.Message = c.Message
72 ndiff := Diff{}
73
74 for _, d := range diffs {
75 ndiff.Name.New = d.NewName
76 ndiff.Name.Old = d.OldName
77
78 for _, tf := range d.TextFragments {
79 ndiff.TextFragments = append(ndiff.TextFragments, TextFragment{
80 Header: tf.Header(),
81 Lines: tf.Lines,
82 })
83 for _, l := range tf.Lines {
84 switch l.Op {
85 case gitdiff.OpAdd:
86 nd.Stat.Insertions += 1
87 case gitdiff.OpDelete:
88 nd.Stat.Deletions += 1
89 }
90 }
91 }
92
93 nd.Diff = append(nd.Diff, ndiff)
94 }
95
96 nd.Stat.FilesChanged = len(diffs)
97
98 return &nd, nil
99}