all repos — legit @ d1a2847a266f344911bb791d083b72529cf90c63

web frontend for git

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	IsBinary      bool
 24}
 25
 26// A nicer git diff representation.
 27type NiceDiff struct {
 28	Commit struct {
 29		Message string
 30		Author  object.Signature
 31		This    string
 32		Parent  string
 33	}
 34	Stat struct {
 35		FilesChanged int
 36		Insertions   int
 37		Deletions    int
 38	}
 39	Diff []Diff
 40}
 41
 42func (g *GitRepo) Diff() (*NiceDiff, error) {
 43	c, err := g.r.CommitObject(g.h)
 44	if err != nil {
 45		return nil, fmt.Errorf("commit object: %w", err)
 46	}
 47
 48	patch := &object.Patch{}
 49	commitTree, err := c.Tree()
 50	parent := &object.Commit{}
 51	if err == nil {
 52		parentTree := &object.Tree{}
 53		if c.NumParents() != 0 {
 54			parent, err = c.Parents().Next()
 55			if err == nil {
 56				parentTree, err = parent.Tree()
 57				if err == nil {
 58					patch, err = parentTree.Patch(commitTree)
 59					if err != nil {
 60						return nil, fmt.Errorf("patch: %w", err)
 61					}
 62				}
 63			}
 64		} else {
 65			patch, err = parentTree.Patch(commitTree)
 66			if err != nil {
 67				return nil, fmt.Errorf("patch: %w", err)
 68			}
 69		}
 70	}
 71
 72	diffs, _, err := gitdiff.Parse(strings.NewReader(patch.String()))
 73	if err != nil {
 74		log.Println(err)
 75	}
 76
 77	nd := NiceDiff{}
 78	nd.Commit.This = c.Hash.String()
 79
 80	if parent.Hash.IsZero() {
 81		nd.Commit.Parent = ""
 82	} else {
 83		nd.Commit.Parent = parent.Hash.String()
 84	}
 85	nd.Commit.Author = c.Author
 86	nd.Commit.Message = c.Message
 87
 88	for _, d := range diffs {
 89		ndiff := Diff{}
 90		ndiff.Name.New = d.NewName
 91		ndiff.Name.Old = d.OldName
 92		ndiff.IsBinary = d.IsBinary
 93
 94		for _, tf := range d.TextFragments {
 95			ndiff.TextFragments = append(ndiff.TextFragments, TextFragment{
 96				Header: tf.Header(),
 97				Lines:  tf.Lines,
 98			})
 99			for _, l := range tf.Lines {
100				switch l.Op {
101				case gitdiff.OpAdd:
102					nd.Stat.Insertions += 1
103				case gitdiff.OpDelete:
104					nd.Stat.Deletions += 1
105				}
106			}
107		}
108
109		nd.Diff = append(nd.Diff, ndiff)
110	}
111
112	nd.Stat.FilesChanged = len(diffs)
113
114	return &nd, nil
115}