瀏覽代碼

Changes PR worktree create to open if possible

Aligns worktree open prompting using quick picks
main
Eric Amodio 1 年之前
父節點
當前提交
13585b23b3
共有 10 個檔案被更改,包括 249 行新增215 行删除
  1. +2
    -1
      CHANGELOG.md
  2. +4
    -4
      package.json
  3. +1
    -1
      src/commands.ts
  4. +11
    -3
      src/commands/ghpr/openOrCreateWorktree.ts
  5. +57
    -63
      src/commands/git/worktree.ts
  6. +3
    -3
      src/commands/quickCommand.steps.ts
  7. +1
    -2
      src/constants.ts
  8. +35
    -3
      src/git/actions/worktree.ts
  9. +2
    -2
      src/views/viewCommands.ts

+ 2
- 1
CHANGELOG.md 查看文件

@ -29,7 +29,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- Adds a `worktrees.openAfterCreate` setting to specify how and when to open a worktree after it is created
- Ensures new worktrees are created from the "main" repo, if already in a worktree
- Adds a new _remote_ command to the _Git Command Palette_ to add, prune, and remove remotes
- Adds a _Create Worktree for Pull Request via GitLens..._ context menu command on pull requests in the _GitHub Pull Requests and Issues_ extension's views
- Adds a _Open Worktree for Pull Request via GitLens..._ context menu command on pull requests in the _GitHub Pull Requests and Issues_ extension's views
- Opens an associated worktree, if one exists, otherwise it creates a new worktree for the pull request
- Adds settings to control the format of commits in the GitLens views
### Changed

+ 4
- 4
package.json 查看文件

@ -5571,8 +5571,8 @@
"enablement": "!operationInProgress"
},
{
"command": "gitlens.ghpr.views.createWorktree",
"title": "Create Worktree for Pull Request via GitLens...",
"command": "gitlens.ghpr.views.openOrCreateWorktree",
"title": "Open Worktree for Pull Request via GitLens...",
"category": "GitLens",
"enablement": "!operationInProgress"
},
@ -8064,7 +8064,7 @@
"when": "false"
},
{
"command": "gitlens.ghpr.views.createWorktree",
"command": "gitlens.ghpr.views.openOrCreateWorktree",
"when": "false"
},
{
@ -11483,7 +11483,7 @@
"group": "1_gitlens@0"
},
{
"command": "gitlens.ghpr.views.createWorktree",
"command": "gitlens.ghpr.views.openOrCreateWorktree",
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && view == pr:github && viewItem =~ /pullrequest(:local)?:nonactive|description/",
"group": "pullrequest@2"
}

+ 1
- 1
src/commands.ts 查看文件

@ -17,7 +17,7 @@ export * from './commands/diffWithRevision';
export * from './commands/diffWithRevisionFrom';
export * from './commands/diffWithWorking';
export * from './commands/externalDiff';
export * from './commands/ghpr/createWorktree';
export * from './commands/ghpr/openOrCreateWorktree';
export * from './commands/gitCommands';
export * from './commands/inviteToLiveShare';
export * from './commands/logging';

src/commands/ghpr/createWorktree.ts → src/commands/ghpr/openOrCreateWorktree.ts 查看文件

@ -3,7 +3,7 @@ import { window } from 'vscode';
import { Commands } from '../../constants';
import type { Container } from '../../container';
import { add as addRemote } from '../../git/actions/remote';
import { create as createWorktree } from '../../git/actions/worktree';
import { create as createWorktree, open as openWorktree } from '../../git/actions/worktree';
import { GitReference } from '../../git/models/reference';
import type { GitRemote } from '../../git/models/remote';
import { parseGitRemoteUrl } from '../../git/parsers/remoteParser';
@ -41,9 +41,9 @@ interface PullRequest {
}
@command()
export class CreateWorktreeCommand extends Command {
export class OpenOrCreateWorktreeCommand extends Command {
constructor(private readonly container: Container) {
super(Commands.CreateWorktreeForGHPR);
super(Commands.OpenOrCreateWorktreeForGHPR);
}
async execute(...args: [PullRequestNode | PullRequest, ...unknown[]]) {
@ -79,6 +79,14 @@ export class CreateWorktreeCommand extends Command {
return;
}
const worktrees = await repo.getWorktrees();
const worktree = worktrees.find(w => w.branch === ref);
if (worktree != null) {
void openWorktree(worktree);
return;
}
const remoteUrl = remoteUri.toString();
const [, remoteDomain, remotePath] = parseGitRemoteUrl(remoteUrl);

+ 57
- 63
src/commands/git/worktree.ts 查看文件

@ -1,10 +1,10 @@
import type { MessageItem } from 'vscode';
import { QuickInputButtons, Uri, window } from 'vscode';
import { QuickInputButtons, Uri, window, workspace } from 'vscode';
import type { Config } from '../../configuration';
import { configuration } from '../../configuration';
import type { Container } from '../../container';
import { PlusFeatures } from '../../features';
import { open, reveal, revealInFileExplorer } from '../../git/actions/worktree';
import { convertOpenFlagsToLocation, reveal, revealInFileExplorer } from '../../git/actions/worktree';
import {
WorktreeCreateError,
WorktreeCreateErrorReason,
@ -22,7 +22,7 @@ import type { FlagsQuickPickItem } from '../../quickpicks/items/flags';
import { createFlagsQuickPickItem } from '../../quickpicks/items/flags';
import { basename, isDescendent } from '../../system/path';
import { pluralize, truncateLeft } from '../../system/string';
import { OpenWorkspaceLocation } from '../../system/utils';
import { openWorkspace, OpenWorkspaceLocation } from '../../system/utils';
import type { ViewsWithRepositoryFolders } from '../../views/viewBase';
import type {
AsyncStepResultGenerator,
@ -85,7 +85,7 @@ interface DeleteState {
flags: DeleteFlags[];
}
type OpenFlags = '--new-window' | '--reveal-explorer';
type OpenFlags = '--add-to-workspace' | '--new-window' | '--reveal-explorer';
interface OpenState {
subcommand: 'open';
@ -385,8 +385,9 @@ export class WorktreeGitCommand extends QuickCommand {
...(state.createBranch ?? state.reference.name).replace(/\\/g, '/').split('/'),
);
let worktree: GitWorktree | undefined;
try {
const worktree = await state.repo.createWorktree(uri, {
worktree = await state.repo.createWorktree(uri, {
commitish: state.reference?.name,
createBranch: state.flags.includes('-b') ? state.createBranch : undefined,
detach: state.flags.includes('--detach'),
@ -399,55 +400,6 @@ export class WorktreeGitCommand extends QuickCommand {
focus: true,
});
}
if (worktree == null) return;
type OpenAction = Config['worktrees']['openAfterCreate'] | 'addToWorkspace';
let action: OpenAction = configuration.get('worktrees.openAfterCreate');
if (action === 'never') return;
queueMicrotask(async () => {
if (action === 'prompt') {
type ActionMessageItem = MessageItem & { action: OpenAction };
const open: ActionMessageItem = { title: 'Open', action: 'always' };
const openNewWindow: ActionMessageItem = {
title: 'Open in New Window',
action: 'alwaysNewWindow',
};
const addToWorkspace: ActionMessageItem = {
title: 'Add to Workspace',
action: 'addToWorkspace',
};
const cancel: ActionMessageItem = { title: 'Cancel', isCloseAffordance: true, action: 'never' };
const result = await window.showInformationMessage(
`Would you like to open the new worktree, or add it to the current workspace?`,
{ modal: true },
open,
openNewWindow,
addToWorkspace,
cancel,
);
action = result?.action ?? 'never';
}
switch (action) {
case 'always':
open(worktree, {
location: OpenWorkspaceLocation.CurrentWindow,
});
break;
case 'alwaysNewWindow':
open(worktree, { location: OpenWorkspaceLocation.NewWindow });
break;
case 'addToWorkspace':
open(worktree, {
location: OpenWorkspaceLocation.AddToWorkspace,
});
break;
}
});
} catch (ex) {
if (
WorktreeCreateError.is(ex, WorktreeCreateErrorReason.AlreadyCheckedOut) &&
@ -495,6 +447,44 @@ export class WorktreeGitCommand extends QuickCommand {
}
endSteps(state);
if (worktree == null) break;
type OpenAction = Config['worktrees']['openAfterCreate'];
const action: OpenAction = configuration.get('worktrees.openAfterCreate');
if (action === 'never') break;
if (action === 'prompt') {
yield* this.openCommandSteps(
{
subcommand: 'open',
repo: state.repo,
uri: worktree.uri,
counter: 3,
confirm: true,
} as OpenStepState,
context,
);
break;
}
queueMicrotask(() => {
switch (action) {
case 'always':
openWorkspace(worktree!.uri, { location: OpenWorkspaceLocation.CurrentWindow });
break;
case 'alwaysNewWindow':
openWorkspace(worktree!.uri, { location: OpenWorkspaceLocation.NewWindow });
break;
case 'onlyWhenEmpty':
openWorkspace(worktree!.uri, {
location: workspace.workspaceFolders?.length
? OpenWorkspaceLocation.CurrentWindow
: OpenWorkspaceLocation.NewWindow,
});
break;
}
});
}
}
@ -804,15 +794,13 @@ export class WorktreeGitCommand extends QuickCommand {
endSteps(state);
const worktree = context.worktrees.find(wt => wt.uri.toString() === state.uri.toString())!;
const worktree = context.worktrees.find(wt => wt.uri.toString() === state.uri.toString());
if (worktree == null) break;
if (state.flags.includes('--reveal-explorer')) {
void revealInFileExplorer(worktree);
} else {
open(worktree, {
location: state.flags.includes('--new-window')
? OpenWorkspaceLocation.NewWindow
: OpenWorkspaceLocation.CurrentWindow,
});
openWorkspace(worktree.uri, { location: convertOpenFlagsToLocation(state.flags) });
}
}
}
@ -823,19 +811,25 @@ export class WorktreeGitCommand extends QuickCommand {
[
createFlagsQuickPickItem<OpenFlags>(state.flags, [], {
label: context.title,
detail: `Will open, in the current window, the worktree in $(folder) ${GitWorktree.getFriendlyPath(
detail: `Will open in the current window, the worktree in $(folder) ${GitWorktree.getFriendlyPath(
state.uri,
)}`,
}),
createFlagsQuickPickItem<OpenFlags>(state.flags, ['--new-window'], {
label: `${context.title} in a New Window`,
detail: `Will open, in a new window, the worktree in $(folder) ${GitWorktree.getFriendlyPath(
detail: `Will open in a new window, the worktree in $(folder) ${GitWorktree.getFriendlyPath(
state.uri,
)}`,
}),
createFlagsQuickPickItem<OpenFlags>(state.flags, ['--add-to-workspace'], {
label: `Add Worktree to Workspace`,
detail: `Will add into the current workspace, the worktree in $(folder) ${GitWorktree.getFriendlyPath(
state.uri,
)}`,
}),
createFlagsQuickPickItem<OpenFlags>(state.flags, ['--reveal-explorer'], {
label: `Reveal in File Explorer`,
detail: `Will open, in the File Explorer, the worktree in $(folder) ${GitWorktree.getFriendlyPath(
detail: `Will open in the File Explorer, the worktree in $(folder) ${GitWorktree.getFriendlyPath(
state.uri,
)}`,
}),

+ 3
- 3
src/commands/quickCommand.steps.ts 查看文件

@ -89,7 +89,7 @@ import { formatPath } from '../system/formatPath';
import { map } from '../system/iterable';
import { getSettledValue } from '../system/promise';
import { pad, pluralize, truncate } from '../system/string';
import { OpenWorkspaceLocation } from '../system/utils';
import { openWorkspace, OpenWorkspaceLocation } from '../system/utils';
import type { ViewsWithRepositoryFolders } from '../views/viewBase';
import type {
AsyncStepResultGenerator,
@ -1635,7 +1635,7 @@ export async function* pickWorktreeStep<
onDidClickItemButton: (quickpick, button, { item }) => {
switch (button) {
case QuickCommandButtons.OpenInNewWindow:
WorktreeActions.open(item, { location: OpenWorkspaceLocation.NewWindow });
openWorkspace(item.uri, { location: OpenWorkspaceLocation.NewWindow });
break;
case QuickCommandButtons.RevealInSideBar:
void WorktreeActions.reveal(item, { select: true, focus: false, expand: true });
@ -1696,7 +1696,7 @@ export async function* pickWorktreesStep<
onDidClickItemButton: (quickpick, button, { item }) => {
switch (button) {
case QuickCommandButtons.OpenInNewWindow:
WorktreeActions.open(item, { location: OpenWorkspaceLocation.NewWindow });
openWorkspace(item.uri, { location: OpenWorkspaceLocation.NewWindow });
break;
case QuickCommandButtons.RevealInSideBar:
void WorktreeActions.reveal(item, { select: true, focus: false, expand: true });

+ 1
- 2
src/constants.ts 查看文件

@ -170,6 +170,7 @@ export const enum Commands {
GitCommandsSwitch = 'gitlens.gitCommands.switch',
GitCommandsTag = 'gitlens.gitCommands.tag',
GitCommandsWorktree = 'gitlens.gitCommands.worktree',
OpenOrCreateWorktreeForGHPR = 'gitlens.ghpr.views.openOrCreateWorktree',
PlusHide = 'gitlens.plus.hide',
PlusLearn = 'gitlens.plus.learn',
PlusLoginOrSignUp = 'gitlens.plus.loginOrSignUp',
@ -259,8 +260,6 @@ export const enum Commands {
ViewsOpenDirectoryDiff = 'gitlens.views.openDirectoryDiff',
ViewsOpenDirectoryDiffWithWorking = 'gitlens.views.openDirectoryDiffWithWorking',
CreateWorktreeForGHPR = 'gitlens.ghpr.views.createWorktree',
Deprecated_DiffHeadWith = 'gitlens.diffHeadWith',
Deprecated_DiffWorkingWith = 'gitlens.diffWorkingWith',
Deprecated_OpenBranchesInRemote = 'gitlens.openBranchesInRemote',

+ 35
- 3
src/git/actions/worktree.ts 查看文件

@ -1,10 +1,10 @@
import type { Uri } from 'vscode';
import type { WorktreeGitCommandArgs } from '../../commands/git/worktree';
import { CoreCommands } from '../../constants';
import { Container } from '../../container';
import { ensure } from '../../system/array';
import { executeCoreCommand } from '../../system/command';
import type { OpenWorkspaceLocation } from '../../system/utils';
import { openWorkspace } from '../../system/utils';
import { OpenWorkspaceLocation } from '../../system/utils';
import { executeGitCommand } from '../actions';
import type { GitReference } from '../models/reference';
import type { Repository } from '../models/repository';
@ -18,7 +18,15 @@ export function create(repo?: string | Repository, uri?: Uri, ref?: GitReference
}
export function open(worktree: GitWorktree, options?: { location?: OpenWorkspaceLocation }) {
return openWorkspace(worktree.uri, options);
return executeGitCommand({
command: 'worktree',
state: {
subcommand: 'open',
repo: worktree.repoPath,
uri: worktree.uri,
flags: convertLocationToOpenFlags(options?.location),
},
});
}
export function remove(repo?: string | Repository, uri?: Uri) {
@ -48,3 +56,27 @@ export async function reveal(
export async function revealInFileExplorer(worktree: GitWorktree) {
void (await executeCoreCommand(CoreCommands.RevealInFileExplorer, worktree.uri));
}
type OpenFlagsArray = Extract<NonNullable<Required<WorktreeGitCommandArgs['state']>>, { subcommand: 'open' }>['flags'];
export function convertLocationToOpenFlags(location: OpenWorkspaceLocation | undefined): OpenFlagsArray | undefined {
if (location == null) return undefined;
switch (location) {
case OpenWorkspaceLocation.NewWindow:
return ['--new-window'];
case OpenWorkspaceLocation.AddToWorkspace:
return ['--add-to-workspace'];
case OpenWorkspaceLocation.CurrentWindow:
default:
return [];
}
}
export function convertOpenFlagsToLocation(flags: OpenFlagsArray | undefined): OpenWorkspaceLocation | undefined {
if (flags == null) return undefined;
if (flags.includes('--new-window')) return OpenWorkspaceLocation.NewWindow;
if (flags.includes('--add-to-workspace')) return OpenWorkspaceLocation.AddToWorkspace;
return OpenWorkspaceLocation.CurrentWindow;
}

+ 2
- 2
src/views/viewCommands.ts 查看文件

@ -33,7 +33,7 @@ import {
} from '../system/command';
import { debug } from '../system/decorators/log';
import { sequentialize } from '../system/function';
import { OpenWorkspaceLocation } from '../system/utils';
import { openWorkspace, OpenWorkspaceLocation } from '../system/utils';
import type { BranchesNode } from './nodes/branchesNode';
import { BranchNode } from './nodes/branchNode';
import { BranchTrackingStatusNode } from './nodes/branchTrackingStatusNode';
@ -572,7 +572,7 @@ export class ViewCommands {
private openWorktree(node: WorktreeNode, options?: { location?: OpenWorkspaceLocation }) {
if (!(node instanceof WorktreeNode)) return undefined;
return WorktreeActionsspan>class="p">.open(node.worktree, options);
return openWorkspace(node.worktree.uri, options);
}
@debug()

Loading…
取消
儲存