Skip to content

Commit 294a029

Browse files
desprestonmislav
authored andcommitted
add --branch flag to pr checkout
Allows renaming the checked out branch.
1 parent 95a515e commit 294a029

File tree

2 files changed

+81
-7
lines changed

2 files changed

+81
-7
lines changed

pkg/cmd/pr/checkout/checkout.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type CheckoutOptions struct {
3333
RecurseSubmodules bool
3434
Force bool
3535
Detach bool
36+
BranchName string
3637
}
3738

3839
func NewCmdCheckout(f *cmdutil.Factory, runF func(*CheckoutOptions) error) *cobra.Command {
@@ -65,6 +66,7 @@ func NewCmdCheckout(f *cmdutil.Factory, runF func(*CheckoutOptions) error) *cobr
6566
cmd.Flags().BoolVarP(&opts.RecurseSubmodules, "recurse-submodules", "", false, "Update all submodules after checkout")
6667
cmd.Flags().BoolVarP(&opts.Force, "force", "f", false, "Reset the existing local branch to the latest state of the pull request")
6768
cmd.Flags().BoolVarP(&opts.Detach, "detach", "", false, "Checkout PR with a detached HEAD")
69+
cmd.Flags().StringVarP(&opts.BranchName, "branch", "b", "", "Local branch name to use (default: the name of the head branch)")
6870

6971
return cmd
7072
}
@@ -139,7 +141,6 @@ func checkoutRun(opts *CheckoutOptions) error {
139141

140142
func cmdsForExistingRemote(remote *context.Remote, pr *api.PullRequest, opts *CheckoutOptions) [][]string {
141143
var cmds [][]string
142-
143144
remoteBranch := fmt.Sprintf("%s/%s", remote.Name, pr.HeadRefName)
144145

145146
refSpec := fmt.Sprintf("+refs/heads/%s", pr.HeadRefName)
@@ -149,21 +150,29 @@ func cmdsForExistingRemote(remote *context.Remote, pr *api.PullRequest, opts *Ch
149150

150151
cmds = append(cmds, []string{"git", "fetch", remote.Name, refSpec})
151152

153+
localBranch := pr.HeadRefName
154+
if opts.BranchName != "" {
155+
localBranch = opts.BranchName
156+
}
157+
152158
switch {
153159
case opts.Detach:
154160
cmds = append(cmds, []string{"git", "checkout", "--detach", "FETCH_HEAD"})
155-
case localBranchExists(pr.HeadRefName):
156-
cmds = append(cmds, []string{"git", "checkout", pr.HeadRefName})
161+
case localBranchExists(localBranch):
162+
cmds = append(cmds, []string{"git", "checkout", localBranch})
157163
if opts.Force {
158164
cmds = append(cmds, []string{"git", "reset", "--hard", fmt.Sprintf("refs/remotes/%s", remoteBranch)})
159165
} else {
160166
// TODO: check if non-fast-forward and suggest to use `--force`
161167
cmds = append(cmds, []string{"git", "merge", "--ff-only", fmt.Sprintf("refs/remotes/%s", remoteBranch)})
162168
}
163169
default:
164-
cmds = append(cmds, []string{"git", "checkout", "-b", pr.HeadRefName, "--no-track", remoteBranch})
165-
cmds = append(cmds, []string{"git", "config", fmt.Sprintf("branch.%s.remote", pr.HeadRefName), remote.Name})
166-
cmds = append(cmds, []string{"git", "config", fmt.Sprintf("branch.%s.merge", pr.HeadRefName), "refs/heads/" + pr.HeadRefName})
170+
cmds = append(
171+
cmds,
172+
[]string{"git", "checkout", "-b", localBranch, "--no-track", remoteBranch},
173+
[]string{"git", "config", fmt.Sprintf("branch.%s.remote", localBranch), remote.Name},
174+
[]string{"git", "config", fmt.Sprintf("branch.%s.merge", pr.HeadRefName), "refs/heads/" + pr.HeadRefName},
175+
)
167176
}
168177

169178
return cmds
@@ -204,7 +213,12 @@ func cmdsForMissingRemote(pr *api.PullRequest, baseURLOrName, repoHost, defaultB
204213
// TODO: check if non-fast-forward and suggest to use `--force`
205214
cmds = append(cmds, []string{"git", "fetch", baseURLOrName, fmt.Sprintf("%s:%s", ref, newBranchName)})
206215
}
207-
cmds = append(cmds, []string{"git", "checkout", newBranchName})
216+
217+
if opts.BranchName != "" {
218+
cmds = append(cmds, []string{"git", "checkout", "-b", opts.BranchName, "--track", newBranchName})
219+
} else {
220+
cmds = append(cmds, []string{"git", "checkout", newBranchName})
221+
}
208222
}
209223

210224
remote := baseURLOrName

pkg/cmd/pr/checkout/checkout_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,66 @@ func Test_checkoutRun(t *testing.T) {
100100
cs.Register(`git config branch\.feature\.merge refs/pull/123/head`, 0, "")
101101
},
102102
},
103+
{
104+
name: "with local branch rename",
105+
opts: &CheckoutOptions{
106+
SelectorArg: "123",
107+
BranchName: "foobar",
108+
Finder: func() shared.PRFinder {
109+
baseRepo, pr := stubPR("OWNER/REPO:master", "hubot/REPO:feature")
110+
pr.MaintainerCanModify = true
111+
pr.HeadRepository = nil
112+
finder := shared.NewMockFinder("123", pr, baseRepo)
113+
return finder
114+
}(),
115+
Config: func() (config.Config, error) {
116+
return config.NewBlankConfig(), nil
117+
},
118+
Branch: func() (string, error) {
119+
return "main", nil
120+
},
121+
},
122+
remotes: map[string]string{
123+
"origin": "OWNER/REPO",
124+
},
125+
runStubs: func(cs *run.CommandStubber) {
126+
cs.Register(`git fetch origin refs/pull/123/head:feature`, 0, "")
127+
cs.Register(`git config branch\.feature\.merge`, 1, "")
128+
cs.Register(`git checkout -b foobar --track feature`, 0, "")
129+
cs.Register(`git config branch\.feature\.remote origin`, 0, "")
130+
cs.Register(`git config branch\.feature\.merge refs/pull/123/head`, 0, "")
131+
},
132+
},
133+
{
134+
name: "with local branch name, no existing git remote",
135+
opts: &CheckoutOptions{
136+
SelectorArg: "123",
137+
BranchName: "foobar",
138+
Finder: func() shared.PRFinder {
139+
baseRepo, pr := stubPR("OWNER/REPO:master", "hubot/REPO:feature")
140+
pr.MaintainerCanModify = true
141+
pr.HeadRepository = nil
142+
finder := shared.NewMockFinder("123", pr, baseRepo)
143+
return finder
144+
}(),
145+
Config: func() (config.Config, error) {
146+
return config.NewBlankConfig(), nil
147+
},
148+
Branch: func() (string, error) {
149+
return "main", nil
150+
},
151+
},
152+
remotes: map[string]string{
153+
"origin": "OWNER/REPO",
154+
},
155+
runStubs: func(cs *run.CommandStubber) {
156+
cs.Register(`git fetch origin refs/pull/123/head:feature`, 0, "")
157+
cs.Register(`git config branch\.feature\.merge`, 1, "")
158+
cs.Register(`git checkout -b foobar --track feature`, 0, "")
159+
cs.Register(`git config branch\.feature\.remote origin`, 0, "")
160+
cs.Register(`git config branch\.feature\.merge refs/pull/123/head`, 0, "")
161+
},
162+
},
103163
}
104164
for _, tt := range tests {
105165
t.Run(tt.name, func(t *testing.T) {

0 commit comments

Comments
 (0)