github.com/echohead/hub@v2.2.1+incompatible/git/git.go (about) 1 package git 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "strings" 9 10 "github.com/github/hub/cmd" 11 ) 12 13 var GlobalFlags []string 14 15 func Version() (string, error) { 16 output, err := gitOutput("version") 17 if err != nil { 18 return "", fmt.Errorf("Can't load git version") 19 } 20 21 return output[0], nil 22 } 23 24 func Dir() (string, error) { 25 output, err := gitOutput("rev-parse", "-q", "--git-dir") 26 if err != nil { 27 return "", fmt.Errorf("Not a git repository (or any of the parent directories): .git") 28 } 29 30 gitDir := output[0] 31 gitDir, err = filepath.Abs(gitDir) 32 if err != nil { 33 return "", err 34 } 35 36 return gitDir, nil 37 } 38 39 func HasFile(segments ...string) bool { 40 dir, err := Dir() 41 if err != nil { 42 return false 43 } 44 45 s := []string{dir} 46 s = append(s, segments...) 47 path := filepath.Join(s...) 48 if _, err := os.Stat(path); err == nil { 49 return true 50 } 51 52 return false 53 } 54 55 func BranchAtRef(paths ...string) (name string, err error) { 56 dir, err := Dir() 57 if err != nil { 58 return 59 } 60 61 segments := []string{dir} 62 segments = append(segments, paths...) 63 path := filepath.Join(segments...) 64 b, err := ioutil.ReadFile(path) 65 if err != nil { 66 return 67 } 68 69 n := string(b) 70 refPrefix := "ref: " 71 if strings.HasPrefix(n, refPrefix) { 72 name = strings.TrimPrefix(n, refPrefix) 73 name = strings.TrimSpace(name) 74 } else { 75 err = fmt.Errorf("No branch info in %s: %s", path, n) 76 } 77 78 return 79 } 80 81 func Editor() (string, error) { 82 output, err := gitOutput("var", "GIT_EDITOR") 83 if err != nil { 84 return "", fmt.Errorf("Can't load git var: GIT_EDITOR") 85 } 86 87 return output[0], nil 88 } 89 90 func Head() (string, error) { 91 return BranchAtRef("HEAD") 92 } 93 94 func SymbolicFullName(name string) (string, error) { 95 output, err := gitOutput("rev-parse", "--symbolic-full-name", name) 96 if err != nil { 97 return "", fmt.Errorf("Unknown revision or path not in the working tree: %s", name) 98 } 99 100 return output[0], nil 101 } 102 103 func Ref(ref string) (string, error) { 104 output, err := gitOutput("rev-parse", "-q", ref) 105 if err != nil { 106 return "", fmt.Errorf("Unknown revision or path not in the working tree: %s", ref) 107 } 108 109 return output[0], nil 110 } 111 112 func RefList(a, b string) ([]string, error) { 113 ref := fmt.Sprintf("%s...%s", a, b) 114 output, err := gitOutput("rev-list", "--cherry-pick", "--right-only", "--no-merges", ref) 115 if err != nil { 116 return []string{}, fmt.Errorf("Can't load rev-list for %s", ref) 117 } 118 119 return output, nil 120 } 121 122 func CommentChar() string { 123 char, err := Config("core.commentchar") 124 if err != nil { 125 char = "#" 126 } 127 128 return char 129 } 130 131 func Show(sha string) (string, error) { 132 cmd := cmd.New("git") 133 cmd.WithArg("show").WithArg("-s").WithArg("--format=%s%n%+b").WithArg(sha) 134 135 output, err := cmd.CombinedOutput() 136 output = strings.TrimSpace(output) 137 138 return output, err 139 } 140 141 func Log(sha1, sha2 string) (string, error) { 142 execCmd := cmd.New("git") 143 execCmd.WithArg("log").WithArg("--no-color") 144 execCmd.WithArg("--format=%h (%aN, %ar)%n%w(78,3,3)%s%n%+b") 145 execCmd.WithArg("--cherry") 146 shaRange := fmt.Sprintf("%s...%s", sha1, sha2) 147 execCmd.WithArg(shaRange) 148 149 outputs, err := execCmd.CombinedOutput() 150 if err != nil { 151 return "", fmt.Errorf("Can't load git log %s..%s", sha1, sha2) 152 } 153 154 return outputs, nil 155 } 156 157 func Remotes() ([]string, error) { 158 return gitOutput("remote", "-v") 159 } 160 161 func Config(name string) (string, error) { 162 return gitGetConfig(name) 163 } 164 165 func GlobalConfig(name string) (string, error) { 166 return gitGetConfig("--global", name) 167 } 168 169 func SetGlobalConfig(name, value string) error { 170 _, err := gitConfig("--global", name, value) 171 return err 172 } 173 174 func gitGetConfig(args ...string) (string, error) { 175 output, err := gitOutput(gitConfigCommand(args)...) 176 if err != nil { 177 return "", fmt.Errorf("Unknown config %s", args[len(args)-1]) 178 } 179 180 if len(output) == 0 { 181 return "", nil 182 } 183 184 return output[0], nil 185 } 186 187 func gitConfig(args ...string) ([]string, error) { 188 return gitOutput(gitConfigCommand(args)...) 189 } 190 191 func gitConfigCommand(args []string) []string { 192 cmd := []string{"config"} 193 return append(cmd, args...) 194 } 195 196 func Alias(name string) (string, error) { 197 return Config(fmt.Sprintf("alias.%s", name)) 198 } 199 200 func Run(command string, args ...string) error { 201 cmd := cmd.New("git") 202 203 for _, v := range GlobalFlags { 204 cmd.WithArg(v) 205 } 206 207 cmd.WithArg(command) 208 209 for _, a := range args { 210 cmd.WithArg(a) 211 } 212 213 return cmd.Run() 214 } 215 216 func gitOutput(input ...string) (outputs []string, err error) { 217 cmd := cmd.New("git") 218 219 for _, v := range GlobalFlags { 220 cmd.WithArg(v) 221 } 222 223 for _, i := range input { 224 cmd.WithArg(i) 225 } 226 227 out, err := cmd.CombinedOutput() 228 for _, line := range strings.Split(out, "\n") { 229 line = strings.TrimSpace(line) 230 if line != "" { 231 outputs = append(outputs, string(line)) 232 } 233 } 234 235 return outputs, err 236 }