-
Notifications
You must be signed in to change notification settings - Fork 739
Add checkout pull request in worktree option #8513
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+282
−13
Merged
Changes from 17 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
b44c1ed
Initial plan
Copilot cf08027
initial plan for checkout PR in worktree feature
Copilot 40d6d90
feat: add checkout pull request in worktree option
Copilot ecc650d
fix: use VS Code Tasks API for reliable cross-platform worktree creation
Copilot fab1204
fix: address code review feedback - improve error handling and branch…
Copilot 80e46a2
argument clean up and keep branch name
alexr00 103da71
Update git API
alexr00 04c416a
refactor: use git extension API for worktree creation instead of shel…
Copilot ad74445
fix: run fetch and worktree selection in parallel, move info message …
Copilot 3e1c44e
Fix createWorktree call
alexr00 766d8a0
fix: start progress before fetch operation, include fetch in progress…
Copilot fa08fb7
feat: add 'Checkout in Worktree' option to PR Description checkout bu…
Copilot 8ea92b4
Merge branch 'main' into copilot/add-worktree-checkout-option
alexr00 db793c6
fix: handle existing local branch when creating worktree
Copilot 5f65fda
feat: use modal dialog with new window and current window options for…
Copilot af07a44
feat: add pr.pickInWorktreeFromDescription command for PR overview ch…
Copilot ed22158
refactor: extract worktree checkout logic into standalone utility fun…
Copilot b79ac67
Fix strings
alexr00 4fc3bc1
fix strings
alexr00 897e23d
fix: stop if fetch fails and use commands.openFolder helper
Copilot 290ab97
CCR cleanup
alexr00 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,133 @@ | ||
| /*--------------------------------------------------------------------------------------------- | ||
| * Copyright (c) Microsoft Corporation. All rights reserved. | ||
| * Licensed under the MIT License. See License.txt in the project root for license information. | ||
| *--------------------------------------------------------------------------------------------*/ | ||
|
|
||
| import * as path from 'path'; | ||
| import * as vscode from 'vscode'; | ||
| import { FolderRepositoryManager } from './folderRepositoryManager'; | ||
| import { PullRequestModel } from './pullRequestModel'; | ||
| import { Repository } from '../api/api'; | ||
| import Logger from '../common/logger'; | ||
| import { ITelemetry } from '../common/telemetry'; | ||
|
|
||
| const logId = 'Worktree'; | ||
|
|
||
| /** | ||
| * Checks out a pull request in a new git worktree. | ||
| * @param telemetry Telemetry instance for tracking usage | ||
| * @param folderManager The folder repository manager | ||
| * @param pullRequestModel The pull request to checkout | ||
| * @param repository Optional repository to use (if not provided, uses folderManager.repository) | ||
| */ | ||
| export async function checkoutPRInWorktree( | ||
| telemetry: ITelemetry, | ||
| folderManager: FolderRepositoryManager, | ||
| pullRequestModel: PullRequestModel, | ||
| repository: Repository | undefined | ||
| ): Promise<void> { | ||
| // Validate that the PR has a valid head branch | ||
| if (!pullRequestModel.head) { | ||
| vscode.window.showErrorMessage(vscode.l10n.t('Unable to checkout pull request: missing head branch information.')); | ||
| return; | ||
|
alexr00 marked this conversation as resolved.
|
||
| } | ||
|
|
||
| const prHead = pullRequestModel.head; | ||
| const repositoryToUse = repository || folderManager.repository; | ||
|
|
||
| /* __GDPR__ | ||
| "pr.checkoutInWorktree" : {} | ||
| */ | ||
| telemetry.sendTelemetryEvent('pr.checkoutInWorktree'); | ||
|
|
||
| // Prepare for operations | ||
| const repoRootPath = repositoryToUse.rootUri.fsPath; | ||
| const parentDir = path.dirname(repoRootPath); | ||
| const defaultWorktreePath = path.join(parentDir, `pr-${pullRequestModel.number}`); | ||
| const branchName = prHead.ref; | ||
| const remoteName = pullRequestModel.remote.remoteName; | ||
|
|
||
| // Ask user for worktree location first (not in progress) | ||
| const worktreeUri = await vscode.window.showSaveDialog({ | ||
| defaultUri: vscode.Uri.file(defaultWorktreePath), | ||
| title: vscode.l10n.t('Select Worktree Location'), | ||
| saveLabel: vscode.l10n.t('Create Worktree'), | ||
| }); | ||
|
|
||
| if (!worktreeUri) { | ||
| return; // User cancelled | ||
| } | ||
|
|
||
| const worktreePath = worktreeUri.fsPath; | ||
| const trackedBranchName = `${remoteName}/${branchName}`; | ||
|
|
||
| try { | ||
| // Check if the createWorktree API is available | ||
| if (!repositoryToUse.createWorktree) { | ||
| throw new Error(vscode.l10n.t('Git worktree API is not available. Please update VS Code to the latest version.')); | ||
| } | ||
|
|
||
| // Start progress for fetch and worktree creation | ||
| await vscode.window.withProgress( | ||
| { | ||
| location: vscode.ProgressLocation.Notification, | ||
| title: vscode.l10n.t('Creating worktree for Pull Request #{0}...', pullRequestModel.number), | ||
| }, | ||
| async () => { | ||
| // Fetch the PR branch first | ||
| try { | ||
| await repositoryToUse.fetch({ remote: remoteName, ref: branchName }); | ||
| } catch (e) { | ||
| const errorMessage = e instanceof Error ? e.message : String(e); | ||
| Logger.appendLine(`Failed to fetch branch ${branchName}: ${errorMessage}`, logId); | ||
| // Continue even if fetch fails - the branch might already be available locally | ||
|
alexr00 marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| // Check if the branch already exists locally | ||
| let branchExists = false; | ||
| try { | ||
| await repositoryToUse.getBranch(branchName); | ||
| branchExists = true; | ||
| } catch { | ||
| // Branch doesn't exist locally, we'll create it | ||
| branchExists = false; | ||
| } | ||
|
|
||
| // Use the git extension's createWorktree API | ||
| // If branch already exists, don't specify the branch parameter to avoid "branch already exists" error | ||
| if (branchExists) { | ||
| await repositoryToUse.createWorktree!({ | ||
| path: worktreePath, | ||
| commitish: branchName | ||
| }); | ||
| } else { | ||
| await repositoryToUse.createWorktree!({ | ||
| path: worktreePath, | ||
| commitish: trackedBranchName, | ||
| branch: branchName | ||
|
alexr00 marked this conversation as resolved.
|
||
| }); | ||
| } | ||
| } | ||
| ); | ||
|
|
||
| // Ask user how they want to open the worktree (modal dialog) | ||
| const openInNewWindow = vscode.l10n.t('New Window'); | ||
| const openInCurrentWindow = vscode.l10n.t('Current Window'); | ||
| const result = await vscode.window.showInformationMessage( | ||
| vscode.l10n.t('Worktree created for Pull Request #{0}. How would you like to open it?', pullRequestModel.number), | ||
| { modal: true }, | ||
| openInNewWindow, | ||
| openInCurrentWindow | ||
| ); | ||
|
|
||
| if (result === openInNewWindow) { | ||
| await vscode.commands.executeCommand('vscode.openFolder', worktreeUri, { forceNewWindow: true }); | ||
| } else if (result === openInCurrentWindow) { | ||
|
alexr00 marked this conversation as resolved.
Outdated
|
||
| await vscode.commands.executeCommand('vscode.openFolder', worktreeUri, { forceNewWindow: false }); | ||
| } | ||
| } catch (e) { | ||
| const errorMessage = e instanceof Error ? e.message : String(e); | ||
| Logger.error(`Failed to create worktree: ${errorMessage}`, logId); | ||
| vscode.window.showErrorMessage(vscode.l10n.t('Failed to create worktree: {0}', errorMessage)); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.