@@ -13,6 +13,7 @@ import (
1313 "strings"
1414
1515 "github.com/cli/cli/internal/run"
16+ "github.com/cli/safeexec"
1617)
1718
1819// ErrNotOnAnyBranch indicates that the user is in detached HEAD state
@@ -37,7 +38,10 @@ func (r TrackingRef) String() string {
3738// ShowRefs resolves fully-qualified refs to commit hashes
3839func ShowRefs (ref ... string ) ([]Ref , error ) {
3940 args := append ([]string {"show-ref" , "--verify" , "--" }, ref ... )
40- showRef := exec .Command ("git" , args ... )
41+ showRef , err := GitCommand (args ... )
42+ if err != nil {
43+ return nil , err
44+ }
4145 output , err := run .PrepareCmd (showRef ).Output ()
4246
4347 var refs []Ref
@@ -57,7 +61,10 @@ func ShowRefs(ref ...string) ([]Ref, error) {
5761
5862// CurrentBranch reads the checked-out branch for the git repository
5963func CurrentBranch () (string , error ) {
60- refCmd := GitCommand ("symbolic-ref" , "--quiet" , "HEAD" )
64+ refCmd , err := GitCommand ("symbolic-ref" , "--quiet" , "HEAD" )
65+ if err != nil {
66+ return "" , err
67+ }
6168
6269 output , err := run .PrepareCmd (refCmd ).Output ()
6370 if err == nil {
@@ -78,13 +85,19 @@ func CurrentBranch() (string, error) {
7885}
7986
8087func listRemotes () ([]string , error ) {
81- remoteCmd := exec .Command ("git" , "remote" , "-v" )
88+ remoteCmd , err := GitCommand ("remote" , "-v" )
89+ if err != nil {
90+ return nil , err
91+ }
8292 output , err := run .PrepareCmd (remoteCmd ).Output ()
8393 return outputLines (output ), err
8494}
8595
8696func Config (name string ) (string , error ) {
87- configCmd := exec .Command ("git" , "config" , name )
97+ configCmd , err := GitCommand ("config" , name )
98+ if err != nil {
99+ return "" , err
100+ }
88101 output , err := run .PrepareCmd (configCmd ).Output ()
89102 if err != nil {
90103 return "" , fmt .Errorf ("unknown config key: %s" , name )
@@ -94,12 +107,19 @@ func Config(name string) (string, error) {
94107
95108}
96109
97- var GitCommand = func (args ... string ) * exec.Cmd {
98- return exec .Command ("git" , args ... )
110+ var GitCommand = func (args ... string ) (* exec.Cmd , error ) {
111+ gitExe , err := safeexec .LookPath ("git" )
112+ if err != nil {
113+ return nil , err
114+ }
115+ return exec .Command (gitExe , args ... ), nil
99116}
100117
101118func UncommittedChangeCount () (int , error ) {
102- statusCmd := GitCommand ("status" , "--porcelain" )
119+ statusCmd , err := GitCommand ("status" , "--porcelain" )
120+ if err != nil {
121+ return 0 , err
122+ }
103123 output , err := run .PrepareCmd (statusCmd ).Output ()
104124 if err != nil {
105125 return 0 , err
@@ -123,10 +143,13 @@ type Commit struct {
123143}
124144
125145func Commits (baseRef , headRef string ) ([]* Commit , error ) {
126- logCmd := GitCommand (
146+ logCmd , err := GitCommand (
127147 "-c" , "log.ShowSignature=false" ,
128148 "log" , "--pretty=format:%H,%s" ,
129149 "--cherry" , fmt .Sprintf ("%s...%s" , baseRef , headRef ))
150+ if err != nil {
151+ return nil , err
152+ }
130153 output , err := run .PrepareCmd (logCmd ).Output ()
131154 if err != nil {
132155 return []* Commit {}, err
@@ -154,7 +177,10 @@ func Commits(baseRef, headRef string) ([]*Commit, error) {
154177}
155178
156179func CommitBody (sha string ) (string , error ) {
157- showCmd := GitCommand ("-c" , "log.ShowSignature=false" , "show" , "-s" , "--pretty=format:%b" , sha )
180+ showCmd , err := GitCommand ("-c" , "log.ShowSignature=false" , "show" , "-s" , "--pretty=format:%b" , sha )
181+ if err != nil {
182+ return "" , err
183+ }
158184 output , err := run .PrepareCmd (showCmd ).Output ()
159185 if err != nil {
160186 return "" , err
@@ -164,7 +190,10 @@ func CommitBody(sha string) (string, error) {
164190
165191// Push publishes a git ref to a remote and sets up upstream configuration
166192func Push (remote string , ref string , cmdOut , cmdErr io.Writer ) error {
167- pushCmd := GitCommand ("push" , "--set-upstream" , remote , ref )
193+ pushCmd , err := GitCommand ("push" , "--set-upstream" , remote , ref )
194+ if err != nil {
195+ return err
196+ }
168197 pushCmd .Stdout = cmdOut
169198 pushCmd .Stderr = cmdErr
170199 return run .PrepareCmd (pushCmd ).Run ()
@@ -179,7 +208,10 @@ type BranchConfig struct {
179208// ReadBranchConfig parses the `branch.BRANCH.(remote|merge)` part of git config
180209func ReadBranchConfig (branch string ) (cfg BranchConfig ) {
181210 prefix := regexp .QuoteMeta (fmt .Sprintf ("branch.%s." , branch ))
182- configCmd := GitCommand ("config" , "--get-regexp" , fmt .Sprintf ("^%s(remote|merge)$" , prefix ))
211+ configCmd , err := GitCommand ("config" , "--get-regexp" , fmt .Sprintf ("^%s(remote|merge)$" , prefix ))
212+ if err != nil {
213+ return
214+ }
183215 output , err := run .PrepareCmd (configCmd ).Output ()
184216 if err != nil {
185217 return
@@ -209,21 +241,28 @@ func ReadBranchConfig(branch string) (cfg BranchConfig) {
209241}
210242
211243func DeleteLocalBranch (branch string ) error {
212- branchCmd := GitCommand ("branch" , "-D" , branch )
213- err := run .PrepareCmd (branchCmd ).Run ()
214- return err
244+ branchCmd , err := GitCommand ("branch" , "-D" , branch )
245+ if err != nil {
246+ return err
247+ }
248+ return run .PrepareCmd (branchCmd ).Run ()
215249}
216250
217251func HasLocalBranch (branch string ) bool {
218- configCmd := GitCommand ("rev-parse" , "--verify" , "refs/heads/" + branch )
219- _ , err := run .PrepareCmd (configCmd ).Output ()
252+ configCmd , err := GitCommand ("rev-parse" , "--verify" , "refs/heads/" + branch )
253+ if err != nil {
254+ return false
255+ }
256+ _ , err = run .PrepareCmd (configCmd ).Output ()
220257 return err == nil
221258}
222259
223260func CheckoutBranch (branch string ) error {
224- configCmd := GitCommand ("checkout" , branch )
225- err := run .PrepareCmd (configCmd ).Run ()
226- return err
261+ configCmd , err := GitCommand ("checkout" , branch )
262+ if err != nil {
263+ return err
264+ }
265+ return run .PrepareCmd (configCmd ).Run ()
227266}
228267
229268func parseCloneArgs (extraArgs []string ) (args []string , target string ) {
@@ -252,7 +291,10 @@ func RunClone(cloneURL string, args []string) (target string, err error) {
252291
253292 cloneArgs = append ([]string {"clone" }, cloneArgs ... )
254293
255- cloneCmd := GitCommand (cloneArgs ... )
294+ cloneCmd , err := GitCommand (cloneArgs ... )
295+ if err != nil {
296+ return "" , err
297+ }
256298 cloneCmd .Stdin = os .Stdin
257299 cloneCmd .Stdout = os .Stdout
258300 cloneCmd .Stderr = os .Stderr
@@ -262,7 +304,10 @@ func RunClone(cloneURL string, args []string) (target string, err error) {
262304}
263305
264306func AddUpstreamRemote (upstreamURL , cloneDir string ) error {
265- cloneCmd := GitCommand ("-C" , cloneDir , "remote" , "add" , "-f" , "upstream" , upstreamURL )
307+ cloneCmd , err := GitCommand ("-C" , cloneDir , "remote" , "add" , "-f" , "upstream" , upstreamURL )
308+ if err != nil {
309+ return err
310+ }
266311 cloneCmd .Stdout = os .Stdout
267312 cloneCmd .Stderr = os .Stderr
268313 return run .PrepareCmd (cloneCmd ).Run ()
@@ -274,7 +319,10 @@ func isFilesystemPath(p string) bool {
274319
275320// ToplevelDir returns the top-level directory path of the current repository
276321func ToplevelDir () (string , error ) {
277- showCmd := exec .Command ("git" , "rev-parse" , "--show-toplevel" )
322+ showCmd , err := GitCommand ("rev-parse" , "--show-toplevel" )
323+ if err != nil {
324+ return "" , err
325+ }
278326 output , err := run .PrepareCmd (showCmd ).Output ()
279327 return firstLine (output ), err
280328
0 commit comments