forked from tangled.org/core
this repo has no description
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" 10 "github.com/go-git/go-git/v5/plumbing/object" 11 "tangled.sh/tangled.sh/core/types" 12) 13 14func (g *GitRepo) Diff() (*types.NiceDiff, error) { 15 c, err := g.r.CommitObject(g.h) 16 if err != nil { 17 return nil, fmt.Errorf("commit object: %w", err) 18 } 19 20 patch := &object.Patch{} 21 commitTree, err := c.Tree() 22 parent := &object.Commit{} 23 if err == nil { 24 parentTree := &object.Tree{} 25 if c.NumParents() != 0 { 26 parent, err = c.Parents().Next() 27 if err == nil { 28 parentTree, err = parent.Tree() 29 if err == nil { 30 patch, err = parentTree.Patch(commitTree) 31 if err != nil { 32 return nil, fmt.Errorf("patch: %w", err) 33 } 34 } 35 } 36 } else { 37 patch, err = parentTree.Patch(commitTree) 38 if err != nil { 39 return nil, fmt.Errorf("patch: %w", err) 40 } 41 } 42 } 43 44 diffs, _, err := gitdiff.Parse(strings.NewReader(patch.String())) 45 if err != nil { 46 log.Println(err) 47 } 48 49 nd := types.NiceDiff{} 50 for _, d := range diffs { 51 ndiff := types.Diff{} 52 ndiff.Name.New = d.NewName 53 ndiff.Name.Old = d.OldName 54 ndiff.IsBinary = d.IsBinary 55 ndiff.IsNew = d.IsNew 56 ndiff.IsDelete = d.IsDelete 57 ndiff.IsCopy = d.IsCopy 58 ndiff.IsRename = d.IsRename 59 60 for _, tf := range d.TextFragments { 61 ndiff.TextFragments = append(ndiff.TextFragments, *tf) 62 for _, l := range tf.Lines { 63 switch l.Op { 64 case gitdiff.OpAdd: 65 nd.Stat.Insertions += 1 66 case gitdiff.OpDelete: 67 nd.Stat.Deletions += 1 68 } 69 } 70 } 71 72 nd.Diff = append(nd.Diff, ndiff) 73 } 74 75 nd.Stat.FilesChanged = len(diffs) 76 nd.Commit.This = c.Hash.String() 77 78 if parent.Hash.IsZero() { 79 nd.Commit.Parent = "" 80 } else { 81 nd.Commit.Parent = parent.Hash.String() 82 } 83 nd.Commit.Author = c.Author 84 nd.Commit.Message = c.Message 85 86 return &nd, nil 87} 88 89func (g *GitRepo) DiffTree(commit1, commit2 *object.Commit) (*types.DiffTree, error) { 90 tree1, err := commit1.Tree() 91 if err != nil { 92 return nil, err 93 } 94 95 tree2, err := commit2.Tree() 96 if err != nil { 97 return nil, err 98 } 99 100 diff, err := object.DiffTree(tree1, tree2) 101 if err != nil { 102 return nil, err 103 } 104 105 patch, err := diff.Patch() 106 if err != nil { 107 return nil, err 108 } 109 110 diffs, _, err := gitdiff.Parse(strings.NewReader(patch.String())) 111 if err != nil { 112 return nil, err 113 } 114 115 return &types.DiffTree{ 116 Rev1: commit1.Hash.String(), 117 Rev2: commit2.Hash.String(), 118 Patch: patch.String(), 119 Diff: diffs, 120 }, nil 121} 122 123func (g *GitRepo) MergeBase(commit1, commit2 *object.Commit) (*object.Commit, error) { 124 isAncestor, err := commit1.IsAncestor(commit2) 125 if err != nil { 126 return nil, err 127 } 128 129 if isAncestor { 130 return commit1, nil 131 } 132 133 mergeBase, err := commit1.MergeBase(commit2) 134 if err != nil { 135 return nil, err 136 } 137 138 if len(mergeBase) == 0 { 139 return nil, fmt.Errorf("failed to find a merge-base") 140 } 141 142 return mergeBase[0], nil 143} 144 145func (g *GitRepo) ResolveRevision(revStr string) (*object.Commit, error) { 146 rev, err := g.r.ResolveRevision(plumbing.Revision(revStr)) 147 if err != nil { 148 return nil, fmt.Errorf("resolving revision %s: %w", revStr, err) 149 } 150 151 commit, err := g.r.CommitObject(*rev) 152 if err != nil { 153 154 return nil, fmt.Errorf("getting commit for %s: %w", revStr, err) 155 } 156 157 return commit, nil 158}