package commands import ( "io" "io/ioutil" "regexp" "github.com/github/hub/github" "github.com/github/hub/utils" ) var cmdApply = &Command{ Run: apply, GitExtension: true, Usage: "apply GITHUB-URL", Short: "Apply a patch to files and/or to the index", Long: `Downloads the patch file for the pull request or commit at the URL and applies that patch from disk with git am or git apply. Similar to cherry-pick, but doesn't add new remotes. git am creates commits while preserving authorship info while apply only applies the patch to the working copy. `, } var cmdAm = &Command{ Run: apply, GitExtension: true, Usage: "am GITHUB-URL", Short: "Apply a patch to files and/or to the index", Long: `Downloads the patch file for the pull request or commit at the URL and applies that patch from disk with git am or git apply. Similar to cherry-pick, but doesn't add new remotes. git am creates commits while preserving authorship info while apply only applies the patch to the working copy. `, } func init() { CmdRunner.Use(cmdApply) CmdRunner.Use(cmdAm) } /* $ gh apply https://github.com/jingweno/gh/pull/55 > curl https://github.com/jingweno/gh/pull/55.patch -o /tmp/55.patch > git apply /tmp/55.patch $ git apply --ignore-whitespace https://github.com/jingweno/gh/commit/fdb9921 > curl https://github.com/jingweno/gh/commit/fdb9921.patch -o /tmp/fdb9921.patch > git apply --ignore-whitespace /tmp/fdb9921.patch $ git apply https://gist.github.com/8da7fb575debd88c54cf > curl https://gist.github.com/8da7fb575debd88c54cf.txt -o /tmp/gist-8da7fb575debd88c54cf.txt > git apply /tmp/gist-8da7fb575debd88c54cf.txt */ func apply(command *Command, args *Args) { if !args.IsParamsEmpty() { transformApplyArgs(args) } } func transformApplyArgs(args *Args) { gistRegexp := regexp.MustCompile("^https?://gist\\.github\\.com/([\\w.-]+/)?([a-f0-9]+)") pullRegexp := regexp.MustCompile("^(pull|commit)/([0-9a-f]+)") for _, arg := range args.Params { var ( patch io.ReadCloser apiError error ) projectURL, err := github.ParseURL(arg) if err == nil { gh := github.NewClient(projectURL.Project.Host) match := pullRegexp.FindStringSubmatch(projectURL.ProjectPath()) if match != nil { if match[1] == "pull" { patch, apiError = gh.PullRequestPatch(projectURL.Project, match[2]) } else { patch, apiError = gh.CommitPatch(projectURL.Project, match[2]) } } } else { match := gistRegexp.FindStringSubmatch(arg) if match != nil { // TODO: support Enterprise gist gh := github.NewClient(github.GitHubHost) patch, apiError = gh.GistPatch(match[2]) } } utils.Check(apiError) if patch == nil { continue } idx := args.IndexOfParam(arg) patchFile, err := ioutil.TempFile("", "hub") utils.Check(err) _, err = io.Copy(patchFile, patch) utils.Check(err) patchFile.Close() patch.Close() args.Params[idx] = patchFile.Name() } }