plumbing: fix pack commands for the file client on Windows

The default git install on Windows doesn't come with commands for
receive-pack and upload-pack in the default $PATH.  Instead, use
--exec-path to find pack executables in that case.
diff --git a/plumbing/transport/file/client.go b/plumbing/transport/file/client.go
index 0b42abf..af4a88b 100644
--- a/plumbing/transport/file/client.go
+++ b/plumbing/transport/file/client.go
@@ -2,9 +2,13 @@
 package file
 
 import (
+	"bufio"
+	"errors"
 	"io"
 	"os"
 	"os/exec"
+	"path/filepath"
+	"strings"
 
 	"gopkg.in/src-d/go-git.v4/plumbing/transport"
 	"gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common"
@@ -30,6 +34,45 @@
 	})
 }
 
+func prefixExecPath(cmd string) (string, error) {
+	// Use `git --exec-path` to find the exec path.
+	execCmd := exec.Command("git", "--exec-path")
+
+	stdout, err := execCmd.StdoutPipe()
+	if err != nil {
+		return "", err
+	}
+	stdoutBuf := bufio.NewReader(stdout)
+
+	err = execCmd.Start()
+	if err != nil {
+		return "", err
+	}
+
+	execPathBytes, isPrefix, err := stdoutBuf.ReadLine()
+	if err != nil {
+		return "", err
+	}
+	if isPrefix {
+		return "", errors.New("Couldn't read exec-path line all at once")
+	}
+
+	err = execCmd.Wait()
+	if err != nil {
+		return "", err
+	}
+	execPath := string(execPathBytes)
+	execPath = strings.TrimSpace(execPath)
+	cmd = filepath.Join(execPath, cmd)
+
+	// Make sure it actually exists.
+	_, err = os.Stat(cmd)
+	if err != nil {
+		return "", err
+	}
+	return cmd, nil
+}
+
 func (r *runner) Command(cmd string, ep transport.Endpoint, auth transport.AuthMethod,
 ) (common.Command, error) {
 
@@ -40,8 +83,16 @@
 		cmd = r.ReceivePackBin
 	}
 
-	if _, err := exec.LookPath(cmd); err != nil {
-		return nil, err
+	_, err := exec.LookPath(cmd)
+	if err != nil {
+		if e, ok := err.(*exec.Error); ok && e.Err == exec.ErrNotFound {
+			cmd, err = prefixExecPath(cmd)
+			if err != nil {
+				return nil, err
+			}
+		} else {
+			return nil, err
+		}
 	}
 
 	return &command{cmd: exec.Command(cmd, ep.Path())}, nil
diff --git a/plumbing/transport/file/client_test.go b/plumbing/transport/file/client_test.go
index 030175e..3532a4c 100644
--- a/plumbing/transport/file/client_test.go
+++ b/plumbing/transport/file/client_test.go
@@ -14,6 +14,28 @@
 
 func Test(t *testing.T) { TestingT(t) }
 
+type ClientSuite struct {
+	CommonSuite
+}
+
+var _ = Suite(&ClientSuite{})
+
+func (s *ClientSuite) TestCommand(c *C) {
+	runner := &runner{
+		UploadPackBin:  transport.UploadPackServiceName,
+		ReceivePackBin: transport.ReceivePackServiceName,
+	}
+	ep, err := transport.NewEndpoint(filepath.Join("fake", "repo"))
+	c.Assert(err, IsNil)
+	var emptyAuth transport.AuthMethod
+	_, err = runner.Command("git-receive-pack", ep, emptyAuth)
+	c.Assert(err, IsNil)
+
+	// Make sure we get an error for one that doesn't exist.
+	_, err = runner.Command("git-fake-command", ep, emptyAuth)
+	c.Assert(os.IsNotExist(err), Equals, true)
+}
+
 const bareConfig = `[core]
 repositoryformatversion = 0
 filemode = true