-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgit.go
More file actions
120 lines (100 loc) · 2.55 KB
/
Copy pathgit.go
File metadata and controls
120 lines (100 loc) · 2.55 KB
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
111
112
113
114
115
116
117
118
119
120
package main
import (
"os"
"os/exec"
"regexp"
"strings"
)
var conventionalScopeRe = regexp.MustCompile(`^\w+\(([^)]+)\):`)
// GetScopesFromLog runs git log for the current user and extracts scopes
// from conventional commit messages, sorted by frequency descending.
func GetScopesFromLog() []string {
email, err := gitConfig("user.email")
if err != nil || email == "" {
return nil
}
out, err := exec.Command("git", "log", "--author="+email, "--format=%s").Output()
if err != nil {
return nil
}
freq := map[string]int{}
for _, line := range strings.Split(string(out), "\n") {
line = strings.TrimSpace(line)
if m := conventionalScopeRe.FindStringSubmatch(line); m != nil {
freq[m[1]]++
}
}
// Sort by frequency descending.
type pair struct {
scope string
count int
}
pairs := make([]pair, 0, len(freq))
for s, c := range freq {
pairs = append(pairs, pair{s, c})
}
// Simple insertion sort — scope lists are small.
for i := 1; i < len(pairs); i++ {
for j := i; j > 0 && pairs[j].count > pairs[j-1].count; j-- {
pairs[j], pairs[j-1] = pairs[j-1], pairs[j]
}
}
scopes := make([]string, len(pairs))
for i, p := range pairs {
scopes[i] = p.scope
}
return scopes
}
func gitConfig(key string) (string, error) {
out, err := exec.Command("git", "config", key).Output()
if err != nil {
return "", err
}
return strings.TrimSpace(string(out)), nil
}
// StagedFile holds a staged file's status and path.
type StagedFile struct {
Status string
Path string
}
// GetStagedFiles returns the list of staged files with their status (A/M/D).
func GetStagedFiles() []StagedFile {
out, err := exec.Command("git", "diff", "--cached", "--name-status").Output()
if err != nil {
return nil
}
var files []StagedFile
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
if line == "" {
continue
}
parts := strings.SplitN(line, "\t", 2)
if len(parts) == 2 {
files = append(files, StagedFile{Status: parts[0], Path: parts[1]})
}
}
return files
}
// StreamGitCommit runs `git commit` with output streamed directly to the terminal.
func StreamGitCommit(msg string, noVerify, amend, noEdit, allowEmpty bool) error {
args := []string{"commit"}
if msg != "" {
args = append(args, "-m", msg)
}
if noVerify {
args = append(args, "--no-verify")
}
if amend {
args = append(args, "--amend")
}
if noEdit {
args = append(args, "--no-edit")
}
if allowEmpty {
args = append(args, "--allow-empty")
}
cmd := exec.Command("git", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}