-
Notifications
You must be signed in to change notification settings - Fork 18
/
git.go
108 lines (89 loc) · 2.24 KB
/
git.go
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
package helpers
import (
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/format/gitignore"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/go-git/go-git/v5/utils/merkletrie"
"github.com/go-git/go-git/v5/utils/merkletrie/filesystem"
mindex "github.com/go-git/go-git/v5/utils/merkletrie/index"
"github.com/go-git/go-git/v5/utils/merkletrie/noder"
"os"
"strings"
)
// GitDiff is a simplified "git diff" and "git diff --cached" implementation using go-git.
//
// GitDiff closely resembles the implementation of go-git Worktree's Status() method.
func GitDiff(dir string, revision string, cached bool) ([]string, error) {
repo, err := git.PlainOpen(dir)
if err != nil {
return nil, err
}
hash, err := repo.ResolveRevision(plumbing.Revision(revision))
if err != nil {
return nil, err
}
commit, err := repo.CommitObject(*hash)
if err != nil {
return nil, err
}
tree, err := commit.Tree()
if err != nil {
return nil, err
}
from := object.NewTreeRootNode(tree)
var to noder.Noder
worktree, err := repo.Worktree()
if err != nil {
return nil, err
}
if cached {
idx, err := repo.Storer.Index()
if err != nil {
return nil, err
}
to = mindex.NewRootNode(idx)
} else {
submodules, err := getSubmodulesStatus(worktree)
if err != nil {
return nil, err
}
to = filesystem.NewRootNode(worktree.Filesystem, submodules)
}
// .gitignore support
changes, err := merkletrie.DiffTree(from, to, diffTreeIsEquals)
if err != nil {
return nil, err
}
patterns, err := gitignore.ReadPatterns(worktree.Filesystem, nil)
if err != nil {
return nil, err
}
matcher := gitignore.NewMatcher(patterns)
var result []string
for _, change := range changes {
action, err := change.Action()
if err != nil {
return nil, err
}
var path string
var isDir bool
switch action {
case merkletrie.Insert:
fallthrough
case merkletrie.Modify:
path = change.To.String()
isDir = change.To.IsDir()
case merkletrie.Delete:
path = change.From.String()
isDir = change.From.IsDir()
default:
continue
}
if matcher.Match(strings.Split(path, string(os.PathSeparator)), isDir) {
continue
}
result = append(result, path)
}
return result, nil
}