-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgit_up.go
152 lines (135 loc) · 5.95 KB
/
git_up.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package gitgo
import (
"fmt"
"regexp"
"strings"
"github.com/pkg/errors"
"github.com/yyle88/erero"
)
// HasStagingChanges 查看是否有变动,使用场景是:没有变动就不要执行 commit 否则会报错或者产生空提交
func (G *Gcm) HasStagingChanges() (bool, error) {
if output, err := G.execConfig.Exec("git", "diff-index", "--cached", "--quiet", "HEAD"); err != nil {
if len(output) != 0 {
return false, errors.New(string(output))
}
return true, nil
}
return false, nil
}
// CheckStagedChanges 查看是否有变动,使用场景是:没有变动就不要执行 commit 否则会报错或者产生空提交
func (G *Gcm) CheckStagedChanges() *Gcm {
if output, err := G.execConfig.Exec("git", "diff", "--cached", "--quiet"); err == nil {
if len(output) != 0 {
return newWaGcm(G.execConfig, output, err, G.debugMode)
}
return newWaGcm(G.execConfig, []byte{}, errors.New("no-staged-changes"), G.debugMode)
}
return G
}
// LatestGitTag 获得项目的最新标签的名称
func (G *Gcm) LatestGitTag() (string, error) {
const commandBash = `
res=$(git describe --tags --abbrev=0 2>/dev/null)
if [ -z "$res" ]; then
echo ""
else
echo "$res"
fi
`
output, err := G.execConfig.ShallowClone().WithBash().Exec(strings.TrimSpace(commandBash))
if err != nil {
return "", erero.Wro(err)
}
return strings.TrimSpace(string(output)), nil
}
// LatestGitTagHasPrefix 获得指定前缀的子项目或主项目的最新标签名称
func (G *Gcm) LatestGitTagHasPrefix(prefix string) (string, error) {
if prefix == "" {
return "", erero.New("param prefix is none")
}
// Bash 命令:获取匹配前缀的最新标签。这里去掉 if [ -z "$res" ] 分支,因为 echo "$res" 在 res 为空时会自动输出空字符串
const commandBashTemplate = `
res=$(git for-each-ref --sort=creatordate --format '%%(refname:short)' refs/tags | grep "^%s" | tail -n 1)
echo "$res"
`
// Bash 命令:使用转义后的 prefix 格式化命令,获得完整的命令字符串
commandBash := fmt.Sprintf(commandBashTemplate, regexp.QuoteMeta(prefix))
// 存在问题,就是标签是打在commit提交上面的,因此在相同的提交上打多个标签时,他们的时间是相同的,这时候取到的,有可能不是最新的那个标签
output, err := G.execConfig.ShallowClone().WithBash().Exec(strings.TrimSpace(commandBash))
if err != nil {
return "", erero.Wro(err)
}
return strings.TrimSpace(string(output)), nil
}
// LatestGitTagMatchRegexp 获得匹配正则(shell的glob模式正则)的子项目或主项目的最新标签名称
func (G *Gcm) LatestGitTagMatchRegexp(regexpPattern string) (string, error) {
if regexpPattern == "" {
return "", erero.New("param regexp_pattern is none")
}
// Bash 命令:获取匹配前缀的最新标签。这里去掉 if [ -z "$res" ] 分支,因为 echo "$res" 在 res 为空时会自动输出空字符串
const commandBashTemplate = `
res=$(git for-each-ref --sort=creatordate --format '%%(refname:short)' refs/tags/%s | tail -n 1)
echo "$res"
`
// Bash 命令:使用转义后的 prefix 格式化命令,获得完整的命令字符串
commandBash := fmt.Sprintf(commandBashTemplate, regexp.QuoteMeta(regexpPattern))
// 存在问题,就是标签是打在commit提交上面的,因此在相同的提交上打多个标签时,他们的时间是相同的,这时候取到的,有可能不是最新的那个标签
output, err := G.execConfig.ShallowClone().WithBash().Exec(strings.TrimSpace(commandBash))
if err != nil {
return "", erero.Wro(err)
}
return strings.TrimSpace(string(output)), nil
}
// GitCommitHash 获得某个分支或标签的哈希
func (G *Gcm) GitCommitHash(refName string) (string, error) {
output, err := G.execConfig.Exec("git", "rev-parse", refName)
if err != nil {
return "", erero.Wro(err)
}
return strings.TrimSpace(string(output)), nil
}
// SortedGitTags 获取项目的标签列表,按时间从前到后排列。使用场景是仅仅观察标签,让用户自己想出下一个标签的序号,因此这里只返回个字符串就行
func (G *Gcm) SortedGitTags() (string, error) {
const commandBash = "git for-each-ref --sort=creatordate --format '%(refname) %(creatordate)' refs/tags"
output, err := G.execConfig.ShallowClone().WithBash().Exec(strings.TrimSpace(commandBash))
if err != nil {
return "", erero.Wro(err)
}
return strings.TrimSpace(string(output)), nil
}
// GetTopPath 获取 git 项目的根目录
func (G *Gcm) GetTopPath() (string, error) {
const commandBash = "git rev-parse --show-toplevel"
output, err := G.execConfig.ShallowClone().WithBash().Exec(strings.TrimSpace(commandBash))
if err != nil {
return "", erero.Wro(err)
}
return strings.TrimSpace(string(output)), nil
}
// GetGitDirAbsPath 获取 git 项目的 .git 目录的绝对路径(如 "/home/user/project/.git")
func (G *Gcm) GetGitDirAbsPath() (string, error) {
const commandBash = "git rev-parse --absolute-git-dir" // 这里不要使用 git rev-parse --git-dir 稍微有点不好用
output, err := G.execConfig.ShallowClone().WithBash().Exec(strings.TrimSpace(commandBash))
if err != nil {
return "", erero.Wro(err)
}
return strings.TrimSpace(string(output)), nil
}
// GetSubPathToRoot 获取从当前目录到 git 项目根目录的相对路径(如 "../",如果在根目录则为空字符串)
func (G *Gcm) GetSubPathToRoot() (string, error) {
const commandBash = "git rev-parse --show-cdup"
output, err := G.execConfig.ShallowClone().WithBash().Exec(strings.TrimSpace(commandBash))
if err != nil {
return "", erero.Wro(err)
}
return strings.TrimSpace(string(output)), nil
}
// GetSubPath 获取从 git 项目根目录到当前目录的相对路径(如 "subdir",如果在根目录则为空字符串)
func (G *Gcm) GetSubPath() (string, error) {
const commandBash = "git rev-parse --show-prefix"
output, err := G.execConfig.ShallowClone().WithBash().Exec(strings.TrimSpace(commandBash))
if err != nil {
return "", erero.Wro(err)
}
return strings.TrimSpace(string(output)), nil
}