-
Notifications
You must be signed in to change notification settings - Fork 27
/
git.go
110 lines (95 loc) · 2.78 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
109
110
package notes
import (
"github.com/pkg/errors"
"os"
"os/exec"
"path/filepath"
"strings"
)
// Git represents Git command for specific repository
type Git struct {
bin string
root string
}
func (git *Git) canonRoot() string {
return canonPath(git.root)
}
// Command returns exec.Command instance which runs given Git subcommand with given arguments
func (git *Git) Command(subcmd string, args ...string) *exec.Cmd {
// e.g. 'git diff --cached' -> 'git -C /path/to/repo diff --cached'
a := append([]string{"-C", git.root, subcmd}, args...)
cmd := exec.Command(git.bin, a...)
return cmd
}
// Exec runs runs given Git subcommand with given arguments
func (git *Git) Exec(subcmd string, args ...string) (string, error) {
b, err := git.Command(subcmd, args...).CombinedOutput()
// Chop last newline
l := len(b)
if l > 0 && b[l-1] == '\n' {
b = b[:l-1]
}
// Make output in oneline in error cases
if err != nil {
for i := range b {
if b[i] == '\n' {
b[i] = ' '
}
}
}
return string(b), err
}
// Init runs `git init` with no argument
func (git *Git) Init() error {
if s, err := os.Stat(filepath.Join(git.root, ".git")); err == nil && s.IsDir() {
// Repository was already created
return nil
}
out, err := git.Exec("init")
if err != nil {
return errors.Wrapf(err, "Cannot init Git repository at '%s': %s", git.canonRoot(), out)
}
return nil
}
// AddAll runs `git add -A`
func (git *Git) AddAll() error {
out, err := git.Exec("add", "-A")
if err != nil {
return errors.Wrapf(err, "Cannot add changes to index tree at '%s': %s", git.canonRoot(), out)
}
return nil
}
// Commit runs `git commit` with given message
func (git *Git) Commit(msg string) error {
out, err := git.Exec("commit", "-m", msg)
if err != nil {
return errors.Wrapf(err, "Cannot commit changes to repository at '%s': %s", git.canonRoot(), out)
}
return nil
}
// TrackingRemote returns remote name branch name. It fails when current branch does not track any branch
func (git *Git) TrackingRemote() (string, string, error) {
s, err := git.Exec("rev-parse", "--abbrev-ref", "--symbolic", "@{u}")
if err != nil {
return "", "", errors.Wrapf(err, "Cannot retrieve remote name: %s", s)
}
// e.g. origin/master
ss := strings.Split(s, "/")
return ss[0], ss[1], nil
}
// Push pushes given branch of repository to the given remote
func (git *Git) Push(remote, branch string) error {
out, err := git.Exec("push", "-u", remote, branch)
if err != nil {
return errors.Wrapf(err, "Cannot push changes to %s/%s at '%s': %s", remote, branch, git.canonRoot(), out)
}
return nil
}
// NewGit creates Git instance from Config value. Home directory is assumed to be a root of Git repository
func NewGit(c *Config) *Git {
if c.GitPath == "" {
// Git is optional
return nil
}
return &Git{c.GitPath, c.HomePath}
}