hub/commands/checkout.go

155 строки
4.0 KiB
Go
Исходник Обычный вид История

2013-06-21 22:40:42 +04:00
package commands
2013-06-22 00:17:52 +04:00
import (
2013-06-22 04:01:00 +04:00
"fmt"
2014-04-01 00:01:05 +04:00
"regexp"
"github.com/github/hub/git"
2014-02-10 20:22:36 +04:00
"github.com/github/hub/github"
"github.com/github/hub/utils"
2013-06-22 00:17:52 +04:00
)
2013-06-21 22:40:42 +04:00
var cmdCheckout = &Command{
Run: checkout,
GitExtension: true,
Usage: "checkout <PULLREQ-URL> [<BRANCH>]",
Long: `Check out the head of a pull request as a local branch.
## Examples:
$ hub checkout https://github.com/jingweno/gh/pull/73
> git fetch origin pull/73/head:jingweno-feature
> git checkout jingweno-feature
2016-01-24 18:50:01 +03:00
## See also:
hub-merge(1), hub-am(1), hub(1), git-checkout(1)
`,
2013-06-21 22:40:42 +04:00
}
func init() {
CmdRunner.Use(cmdCheckout)
}
2013-06-26 19:48:34 +04:00
func checkout(command *Command, args *Args) {
2013-12-11 10:05:26 +04:00
words := args.Words()
2014-04-01 00:01:05 +04:00
2013-12-11 10:05:26 +04:00
if len(words) == 0 {
return
2013-12-11 10:05:26 +04:00
}
2013-06-22 04:01:00 +04:00
2013-12-11 10:05:26 +04:00
checkoutURL := words[0]
var newBranchName string
if len(words) > 1 {
newBranchName = words[1]
}
2014-04-01 00:01:05 +04:00
url, err := github.ParseURL(checkoutURL)
if err != nil {
// not a valid GitHub URL
return
2014-04-01 00:01:05 +04:00
}
2013-06-22 05:02:29 +04:00
2013-12-11 10:05:26 +04:00
pullURLRegex := regexp.MustCompile("^pull/(\\d+)")
projectPath := url.ProjectPath()
if !pullURLRegex.MatchString(projectPath) {
2014-04-01 00:01:05 +04:00
// not a valid PR URL
return
2013-12-11 10:05:26 +04:00
}
2013-07-02 22:28:50 +04:00
err = sanitizeCheckoutFlags(args)
utils.Check(err)
2013-12-11 10:05:26 +04:00
id := pullURLRegex.FindStringSubmatch(projectPath)[1]
2013-12-17 19:45:48 +04:00
gh := github.NewClient(url.Project.Host)
pullRequest, err := gh.PullRequest(url.Project, id)
utils.Check(err)
newArgs, err := transformCheckoutArgs(args, pullRequest, newBranchName)
utils.Check(err)
2013-06-22 04:01:00 +04:00
2013-12-11 10:05:26 +04:00
if idx := args.IndexOfParam(newBranchName); idx >= 0 {
args.RemoveParam(idx)
}
replaceCheckoutParam(args, checkoutURL, newArgs...)
}
2013-06-22 04:01:00 +04:00
func transformCheckoutArgs(args *Args, pullRequest *github.PullRequest, newBranchName string) (newArgs []string, err error) {
repo, err := github.LocalRepo()
if err != nil {
return
}
baseRemote, err := repo.RemoteForRepo(pullRequest.Base.Repo)
if err != nil {
return
2013-06-22 04:01:00 +04:00
}
var headRemote *github.Remote
if pullRequest.IsSameRepo() {
headRemote = baseRemote
} else if pullRequest.Head.Repo != nil {
headRemote, _ = repo.RemoteForRepo(pullRequest.Head.Repo)
}
if headRemote != nil {
if newBranchName == "" {
newBranchName = pullRequest.Head.Ref
}
remoteBranch := fmt.Sprintf("%s/%s", headRemote.Name, pullRequest.Head.Ref)
refSpec := fmt.Sprintf("+refs/heads/%s:refs/remotes/%s", pullRequest.Head.Ref, remoteBranch)
if git.HasFile("refs", "heads", newBranchName) {
newArgs = append(newArgs, newBranchName)
args.After("git", "merge", "--ff-only", fmt.Sprintf("refs/remotes/%s", remoteBranch))
} else {
newArgs = append(newArgs, "-b", newBranchName, "--track", remoteBranch)
}
args.Before("git", "fetch", headRemote.Name, refSpec)
} else {
if newBranchName == "" {
if pullRequest.Head.Repo == nil {
newBranchName = fmt.Sprintf("pr-%d", pullRequest.Number)
} else {
newBranchName = fmt.Sprintf("%s-%s", pullRequest.Head.Repo.Owner.Login, pullRequest.Head.Ref)
}
}
newArgs = append(newArgs, newBranchName)
ref := fmt.Sprintf("refs/pull/%d/head", pullRequest.Number)
args.Before("git", "fetch", baseRemote.Name, fmt.Sprintf("%s:%s", ref, newBranchName))
remote := baseRemote.Name
mergeRef := ref
if pullRequest.MaintainerCanModify && pullRequest.Head.Repo != nil {
var project *github.Project
project, err = github.NewProjectFromRepo(pullRequest.Head.Repo)
2017-02-04 02:54:44 +03:00
if err != nil {
return
2017-02-04 02:54:44 +03:00
}
remote = project.GitURL("", "", true)
mergeRef = fmt.Sprintf("refs/heads/%s", pullRequest.Head.Ref)
}
args.Before("git", "config", fmt.Sprintf("branch.%s.remote", newBranchName), remote)
args.Before("git", "config", fmt.Sprintf("branch.%s.merge", newBranchName), mergeRef)
}
return
2013-07-02 22:28:50 +04:00
}
func sanitizeCheckoutFlags(args *Args) error {
if i := args.IndexOfParam("-b"); i != -1 {
return fmt.Errorf("Unsupported flag -b when checking out pull request")
}
if i := args.IndexOfParam("--orphan"); i != -1 {
return fmt.Errorf("Unsupported flag --orphan when checking out pull request")
}
return nil
}
func replaceCheckoutParam(args *Args, checkoutURL string, replacement ...string) {
idx := args.IndexOfParam(checkoutURL)
args.RemoveParam(idx)
args.InsertParam(idx, replacement...)
}