@@ -86,10 +86,42 @@ func getDefaultBase() string {
8686 return strings .TrimPrefix (ref , "refs/remotes/origin/" )
8787}
8888
89+ type RemoteType int
90+
91+ const (
92+ RemoteGitHub RemoteType = iota
93+ RemoteGitLab
94+ RemoteUnknown
95+ )
96+
97+ func getRemoteType () RemoteType {
98+ cmd := exec .Command ("git" , "remote" , "get-url" , "origin" )
99+ output , err := cmd .Output ()
100+ if err != nil {
101+ return RemoteUnknown
102+ }
103+
104+ url := strings .TrimSpace (string (output ))
105+ if strings .Contains (url , "github.com" ) {
106+ return RemoteGitHub
107+ }
108+ if strings .Contains (url , "gitlab.com" ) || strings .Contains (url , "gitlab" ) {
109+ return RemoteGitLab
110+ }
111+
112+ return RemoteUnknown
113+ }
114+
89115func getPRNumber (input string ) (string , error ) {
90116 // Check if it's a GitHub PR URL
91- urlRegex := regexp .MustCompile (`^https://github\.com/.*/pull/([0-9]+)` )
92- if matches := urlRegex .FindStringSubmatch (input ); matches != nil {
117+ githubRegex := regexp .MustCompile (`^https://github\.com/.*/pull/([0-9]+)` )
118+ if matches := githubRegex .FindStringSubmatch (input ); matches != nil {
119+ return matches [1 ], nil
120+ }
121+
122+ // Check if it's a GitLab MR URL
123+ gitlabRegex := regexp .MustCompile (`^https://gitlab\.com/.*/-/merge_requests/([0-9]+)` )
124+ if matches := gitlabRegex .FindStringSubmatch (input ); matches != nil {
93125 return matches [1 ], nil
94126 }
95127
@@ -99,7 +131,7 @@ func getPRNumber(input string) (string, error) {
99131 return input , nil
100132 }
101133
102- return "" , fmt .Errorf ("invalid PR number or URL: %s" , input )
134+ return "" , fmt .Errorf ("invalid PR/MR number or URL: %s" , input )
103135}
104136
105137func worktreeExists (branch string ) (string , bool ) {
@@ -221,27 +253,54 @@ var createCmd = &cobra.Command{
221253}
222254
223255var prCmd = & cobra.Command {
224- Use : "pr <number|url>" ,
225- Short : "Checkout GitHub PR in worktree (uses gh)" ,
226- Args : cobra .ExactArgs (1 ),
256+ Use : "pr <number|url>" ,
257+ Aliases : []string {"mr" },
258+ Short : "Checkout PR/MR in worktree (uses gh for GitHub, glab for GitLab)" ,
259+ Long : `Checkout a Pull Request (GitHub) or Merge Request (GitLab) in a worktree.
260+
261+ Automatically detects whether you're using GitHub or GitLab based on
262+ the git remote URL and uses the appropriate CLI tool (gh or glab).
263+
264+ Examples:
265+ wt pr 123 # PR/MR number
266+ wt pr https://github.com/org/repo/pull/123 # GitHub PR URL
267+ wt pr https://gitlab.com/org/repo/-/merge_requests/123 # GitLab MR URL
268+ wt mr 123 # Same as 'wt pr 123'` ,
269+ Args : cobra .ExactArgs (1 ),
227270 RunE : func (cmd * cobra.Command , args []string ) error {
228271 input := args [0 ]
229272 prNumber , err := getPRNumber (input )
230273 if err != nil {
231274 return err
232275 }
233276
234- // Check if gh is installed
235- if _ , err := exec .LookPath ("gh" ); err != nil {
236- return fmt .Errorf ("'gh' CLI not found. Install it from https://cli.github.com" )
277+ // Detect remote type
278+ remoteType := getRemoteType ()
279+ var refSpec , prefix string
280+
281+ switch remoteType {
282+ case RemoteGitHub :
283+ refSpec = fmt .Sprintf ("pull/%s/head" , prNumber )
284+ prefix = "pr"
285+ if _ , err := exec .LookPath ("gh" ); err != nil {
286+ return fmt .Errorf ("'gh' CLI not found. Install it from https://cli.github.com" )
287+ }
288+ case RemoteGitLab :
289+ refSpec = fmt .Sprintf ("merge-requests/%s/head" , prNumber )
290+ prefix = "mr"
291+ if _ , err := exec .LookPath ("glab" ); err != nil {
292+ return fmt .Errorf ("'glab' CLI not found. Install it from https://gitlab.com/gitlab-org/cli" )
293+ }
294+ default :
295+ return fmt .Errorf ("unable to detect remote type (GitHub or GitLab)" )
237296 }
238297
239298 repo , err := getRepoName ()
240299 if err != nil {
241300 return err
242301 }
243302
244- branch := fmt .Sprintf ("pr -%s" , prNumber )
303+ branch := fmt .Sprintf ("%s -%s" , prefix , prNumber )
245304 path := filepath .Join (worktreeRoot , repo , branch )
246305
247306 // Check if worktree already exists
@@ -251,8 +310,8 @@ var prCmd = &cobra.Command{
251310 return nil
252311 }
253312
254- // Fetch the PR
255- fetchCmd := exec .Command ("git" , "fetch" , "origin" , fmt .Sprintf ("pull/%s/head :%s" , prNumber , branch ))
313+ // Fetch the PR/MR
314+ fetchCmd := exec .Command ("git" , "fetch" , "origin" , fmt .Sprintf ("%s :%s" , refSpec , branch ))
256315 fetchCmd .Stderr = os .Stderr
257316 _ = fetchCmd .Run () // Ignore errors, branch might already exist
258317
@@ -264,7 +323,7 @@ var prCmd = &cobra.Command{
264323 return fmt .Errorf ("failed to create worktree: %w" , err )
265324 }
266325
267- fmt .Printf ("✓ PR #%s checked out at: %s\n " , prNumber , path )
326+ fmt .Printf ("✓ %s #%s checked out at: %s\n " , strings . ToUpper ( prefix ) , prNumber , path )
268327 printCDMarker (path )
269328 return nil
270329 },
@@ -351,7 +410,7 @@ if [ -n "$BASH_VERSION" ]; then
351410 COMPREPLY=()
352411 cur="${COMP_WORDS[COMP_CWORD]}"
353412 prev="${COMP_WORDS[COMP_CWORD-1]}"
354- commands="checkout co create pr list ls remove rm prune help shellenv"
413+ commands="checkout co create pr mr list ls remove rm prune help shellenv"
355414
356415 # Complete commands if first argument
357416 if [ $COMP_CWORD -eq 1 ]; then
@@ -380,7 +439,8 @@ if [ -n "$ZSH_VERSION" ]; then
380439 'checkout:Checkout existing branch in new worktree'
381440 'co:Checkout existing branch in new worktree'
382441 'create:Create new branch in worktree'
383- 'pr:Checkout GitHub PR in worktree'
442+ 'pr:Checkout PR/MR in worktree'
443+ 'mr:Checkout PR/MR in worktree'
384444 'list:List all worktrees'
385445 'ls:List all worktrees'
386446 'remove:Remove a worktree'
0 commit comments