prow/git/git.go
func (c *Client) Clone(repo string) (*Repo, error) {
	c.lockRepo(repo)
	defer c.unlockRepo(repo)

	base := c.base
	user, pass := c.getCredentials()
	if user != "" && pass != "" {
		base = fmt.Sprintf("https://%s:%s@%s", user, pass, github)
	}
	cache := filepath.Join(c.dir, repo) + ".git"
	if _, err := os.Stat(cache); os.IsNotExist(err) {
		// Cache miss, clone it now.
		c.logger.Infof("Cloning %s for the first time.", repo)
		if err := os.MkdirAll(filepath.Dir(cache), os.ModePerm); err != nil && !os.IsExist(err) {
			return nil, err
		}
		remote := fmt.Sprintf("%s/%s", base, repo)
		if b, err := retryCmd(c.logger, "", c.git, "clone", "--mirror", remote, cache); err != nil {
			return nil, fmt.Errorf("git cache clone error: %v. output: %s", err, string(b))
		}
	} else if err != nil {
		return nil, err
	} else {
		// Cache hit. Do a git fetch to keep updated.
		c.logger.Infof("Fetching %s.", repo)
		if b, err := retryCmd(c.logger, cache, c.git, "fetch"); err != nil {
			return nil, fmt.Errorf("git fetch error: %v. output: %s", err, string(b))
		}
	}
	t, err := ioutil.TempDir("", "git")
	if err != nil {
		return nil, err
	}
	if b, err := exec.Command(c.git, "clone", cache, t).CombinedOutput(); err != nil {
		return nil, fmt.Errorf("git repo clone error: %v. output: %s", err, string(b))
	}
	return &Repo{
		Dir:    t,
		logger: c.logger,
		git:    c.git,
		base:   base,
		repo:   repo,
		user:   user,
		pass:   pass,
	}, nil
}
func (c *Client) Clone(repo string) (*Repo, error) {
	c.lockRepo(repo)
	defer c.unlockRepo(repo)

	base := c.base
	user, pass := c.getCredentials()
	if user != "" && pass != "" {
		base = fmt.Sprintf("https://%s:%s@%s", user, pass, github)
	}
	cache := filepath.Join(c.dir, repo) + ".git"
	if _, err := os.Stat(cache); os.IsNotExist(err) {
		// Cache miss, clone it now.
		c.logger.Infof("Cloning %s for the first time.", repo)
		if err := os.MkdirAll(filepath.Dir(cache), os.ModePerm); err != nil && !os.IsExist(err) {
			return nil, err
		}
		remote := fmt.Sprintf("%s/%s", base, repo)
		if b, err := retryCmd(c.logger, "", c.git, "clone", "--mirror", remote, cache); err != nil {
			return nil, fmt.Errorf("git cache clone error: %v. output: %s", err, string(b))
		}
	} else if err != nil {
		return nil, err
	} else {
		// Cache hit. Do a git fetch to keep updated.
		c.logger.Infof("Fetching %s.", repo)
		if b, err := retryCmd(c.logger, cache, c.git, "fetch"); err != nil {
			return nil, fmt.Errorf("git fetch error: %v. output: %s", err, string(b))
		}
	}
	t, err := ioutil.TempDir("", "git")
	if err != nil {
		return nil, err
	}
	if b, err := exec.Command(c.git, "clone", cache, t).CombinedOutput(); err != nil {
		return nil, fmt.Errorf("git repo clone error: %v. output: %s", err, string(b))
	}
	return &Repo{
		Dir:    t,
		logger: c.logger,
		git:    c.git,
		base:   base,
		repo:   repo,
		user:   user,
		pass:   pass,
	}, nil
}
// Clone clones a repository. Pass the full repository name, such as
// "kubernetes/test-infra" as the repo.
// This function may take a long time if it is the first time cloning the repo.
// In that case, it must do a full git mirror clone. For large repos, this can
// take a while. Once that is done, it will do a git fetch instead of a clone,
// which will usually take at most a few seconds.