mirror of
https://github.com/ckaczor/vscode-gitlens.git
synced 2026-02-16 10:58:34 -05:00
Adds compare with branch command
Adds branches quick pick
This commit is contained in:
@@ -359,6 +359,11 @@
|
|||||||
"title": "Directory Compare",
|
"title": "Directory Compare",
|
||||||
"category": "GitLens"
|
"category": "GitLens"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.diffWithBranch",
|
||||||
|
"title": "Compare with...",
|
||||||
|
"category": "GitLens"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.diffWithNext",
|
"command": "gitlens.diffWithNext",
|
||||||
"title": "Compare with Next Commit",
|
"title": "Compare with Next Commit",
|
||||||
@@ -465,6 +470,10 @@
|
|||||||
"command": "gitlens.diffDirectory",
|
"command": "gitlens.diffDirectory",
|
||||||
"when": "gitlens:enabled"
|
"when": "gitlens:enabled"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "gitlens.diffWithBranch",
|
||||||
|
"when": "gitlens:enabled"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "gitlens.diffWithNext",
|
"command": "gitlens.diffWithNext",
|
||||||
"when": "gitlens:enabled"
|
"when": "gitlens:enabled"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export { CopyShaToClipboardCommand } from './commands/copyShaToClipboard';
|
|||||||
export { DiffDirectoryCommand } from './commands/diffDirectory';
|
export { DiffDirectoryCommand } from './commands/diffDirectory';
|
||||||
export { DiffLineWithPreviousCommand } from './commands/diffLineWithPrevious';
|
export { DiffLineWithPreviousCommand } from './commands/diffLineWithPrevious';
|
||||||
export { DiffLineWithWorkingCommand } from './commands/diffLineWithWorking';
|
export { DiffLineWithWorkingCommand } from './commands/diffLineWithWorking';
|
||||||
|
export { DiffWithBranchCommand } from './commands/diffWithBranch';
|
||||||
export { DiffWithNextCommand } from './commands/diffWithNext';
|
export { DiffWithNextCommand } from './commands/diffWithNext';
|
||||||
export { DiffWithPreviousCommand } from './commands/diffWithPrevious';
|
export { DiffWithPreviousCommand } from './commands/diffWithPrevious';
|
||||||
export { DiffWithWorkingCommand } from './commands/diffWithWorking';
|
export { DiffWithWorkingCommand } from './commands/diffWithWorking';
|
||||||
|
|||||||
@@ -2,12 +2,13 @@
|
|||||||
import { commands, Disposable, TextEditor, TextEditorEdit, Uri, window, workspace } from 'vscode';
|
import { commands, Disposable, TextEditor, TextEditorEdit, Uri, window, workspace } from 'vscode';
|
||||||
import { BuiltInCommands } from '../constants';
|
import { BuiltInCommands } from '../constants';
|
||||||
|
|
||||||
export type Commands = 'gitlens.closeUnchangedFiles' | 'gitlens.copyMessageToClipboard' | 'gitlens.copyShaToClipboard' | 'gitlens.diffDirectory' | 'gitlens.diffWithNext' | 'gitlens.diffWithPrevious' | 'gitlens.diffLineWithPrevious' | 'gitlens.diffWithWorking' | 'gitlens.diffLineWithWorking' | 'gitlens.openChangedFiles' | 'gitlens.showBlame' | 'gitlens.showBlameHistory' | 'gitlens.showFileHistory' | 'gitlens.showQuickCommitDetails' | 'gitlens.showQuickCommitFileDetails' | 'gitlens.showQuickFileHistory' | 'gitlens.showQuickRepoHistory' | 'gitlens.showQuickRepoStatus' | 'gitlens.toggleBlame' | 'gitlens.toggleCodeLens';
|
export type Commands = 'gitlens.closeUnchangedFiles' | 'gitlens.copyMessageToClipboard' | 'gitlens.copyShaToClipboard' | 'gitlens.diffDirectory' | 'gitlens.diffWithBranch' | 'gitlens.diffWithNext' | 'gitlens.diffWithPrevious' | 'gitlens.diffLineWithPrevious' | 'gitlens.diffWithWorking' | 'gitlens.diffLineWithWorking' | 'gitlens.openChangedFiles' | 'gitlens.showBlame' | 'gitlens.showBlameHistory' | 'gitlens.showFileHistory' | 'gitlens.showQuickCommitDetails' | 'gitlens.showQuickCommitFileDetails' | 'gitlens.showQuickFileHistory' | 'gitlens.showQuickRepoHistory' | 'gitlens.showQuickRepoStatus' | 'gitlens.toggleBlame' | 'gitlens.toggleCodeLens';
|
||||||
export const Commands = {
|
export const Commands = {
|
||||||
CloseUnchangedFiles: 'gitlens.closeUnchangedFiles' as Commands,
|
CloseUnchangedFiles: 'gitlens.closeUnchangedFiles' as Commands,
|
||||||
CopyMessageToClipboard: 'gitlens.copyMessageToClipboard' as Commands,
|
CopyMessageToClipboard: 'gitlens.copyMessageToClipboard' as Commands,
|
||||||
CopyShaToClipboard: 'gitlens.copyShaToClipboard' as Commands,
|
CopyShaToClipboard: 'gitlens.copyShaToClipboard' as Commands,
|
||||||
DiffDirectory: 'gitlens.diffDirectory' as Commands,
|
DiffDirectory: 'gitlens.diffDirectory' as Commands,
|
||||||
|
DiffWithBranch: 'gitlens.diffWithBranch' as Commands,
|
||||||
DiffWithNext: 'gitlens.diffWithNext' as Commands,
|
DiffWithNext: 'gitlens.diffWithNext' as Commands,
|
||||||
DiffWithPrevious: 'gitlens.diffWithPrevious' as Commands,
|
DiffWithPrevious: 'gitlens.diffWithPrevious' as Commands,
|
||||||
DiffLineWithPrevious: 'gitlens.diffLineWithPrevious' as Commands,
|
DiffLineWithPrevious: 'gitlens.diffLineWithPrevious' as Commands,
|
||||||
|
|||||||
47
src/commands/diffWithBranch.ts
Normal file
47
src/commands/diffWithBranch.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
'use strict';
|
||||||
|
import { commands, TextEditor, Uri, window } from 'vscode';
|
||||||
|
import { ActiveEditorCommand, Commands } from './commands';
|
||||||
|
import { BuiltInCommands } from '../constants';
|
||||||
|
import { GitService, GitUri } from '../gitService';
|
||||||
|
import { Logger } from '../logger';
|
||||||
|
import { CommandQuickPickItem, BranchesQuickPick } from '../quickPicks';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
export class DiffWithBranchCommand extends ActiveEditorCommand {
|
||||||
|
|
||||||
|
constructor(private git: GitService) {
|
||||||
|
super(Commands.DiffWithBranch);
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(editor: TextEditor, uri?: Uri, goBackCommand?: CommandQuickPickItem): Promise<any> {
|
||||||
|
if (!(uri instanceof Uri)) {
|
||||||
|
if (!editor || !editor.document) return undefined;
|
||||||
|
uri = editor.document.uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
const line = (editor && editor.selection.active.line) || 0;
|
||||||
|
|
||||||
|
const gitUri = await GitUri.fromUri(uri, this.git);
|
||||||
|
|
||||||
|
const branches = await this.git.getBranches(gitUri.repoPath);
|
||||||
|
const pick = await BranchesQuickPick.show(branches, gitUri, goBackCommand);
|
||||||
|
if (!pick) return undefined;
|
||||||
|
|
||||||
|
if (pick instanceof CommandQuickPickItem) {
|
||||||
|
return pick.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
const branch = pick.branch.name;
|
||||||
|
if (!branch) return undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const compare = await this.git.getVersionedFile(gitUri.repoPath, gitUri.fsPath, branch);
|
||||||
|
await commands.executeCommand(BuiltInCommands.Diff, Uri.file(compare), gitUri.fileUri(), `${path.basename(gitUri.fsPath)} (${branch}) ↔ ${path.basename(gitUri.fsPath)}`);
|
||||||
|
return await commands.executeCommand(BuiltInCommands.RevealLine, { lineNumber: line, at: 'center' });
|
||||||
|
}
|
||||||
|
catch (ex) {
|
||||||
|
Logger.error('[GitLens.DiffWithBranchCommand]', 'getVersionedFile', ex);
|
||||||
|
return window.showErrorMessage(`Unable to open diff. See output channel for more details`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ import { configureCssCharacters } from './blameAnnotationFormatter';
|
|||||||
import { CommandContext, setCommandContext } from './commands';
|
import { CommandContext, setCommandContext } from './commands';
|
||||||
import { CloseUnchangedFilesCommand, OpenChangedFilesCommand } from './commands';
|
import { CloseUnchangedFilesCommand, OpenChangedFilesCommand } from './commands';
|
||||||
import { CopyMessageToClipboardCommand, CopyShaToClipboardCommand } from './commands';
|
import { CopyMessageToClipboardCommand, CopyShaToClipboardCommand } from './commands';
|
||||||
import { DiffDirectoryCommand, DiffLineWithPreviousCommand, DiffLineWithWorkingCommand, DiffWithNextCommand, DiffWithPreviousCommand, DiffWithWorkingCommand} from './commands';
|
import { DiffDirectoryCommand, DiffLineWithPreviousCommand, DiffLineWithWorkingCommand, DiffWithBranchCommand, DiffWithNextCommand, DiffWithPreviousCommand, DiffWithWorkingCommand} from './commands';
|
||||||
import { ShowBlameCommand, ToggleBlameCommand } from './commands';
|
import { ShowBlameCommand, ToggleBlameCommand } from './commands';
|
||||||
import { ShowBlameHistoryCommand, ShowFileHistoryCommand } from './commands';
|
import { ShowBlameHistoryCommand, ShowFileHistoryCommand } from './commands';
|
||||||
import { ShowQuickCommitDetailsCommand, ShowQuickCommitFileDetailsCommand, ShowQuickFileHistoryCommand, ShowQuickRepoHistoryCommand, ShowQuickRepoStatusCommand} from './commands';
|
import { ShowQuickCommitDetailsCommand, ShowQuickCommitFileDetailsCommand, ShowQuickFileHistoryCommand, ShowQuickRepoHistoryCommand, ShowQuickRepoStatusCommand} from './commands';
|
||||||
@@ -95,6 +95,7 @@ export async function activate(context: ExtensionContext) {
|
|||||||
context.subscriptions.push(new DiffDirectoryCommand(git, repoPath));
|
context.subscriptions.push(new DiffDirectoryCommand(git, repoPath));
|
||||||
context.subscriptions.push(new DiffLineWithPreviousCommand(git));
|
context.subscriptions.push(new DiffLineWithPreviousCommand(git));
|
||||||
context.subscriptions.push(new DiffLineWithWorkingCommand(git));
|
context.subscriptions.push(new DiffLineWithWorkingCommand(git));
|
||||||
|
context.subscriptions.push(new DiffWithBranchCommand(git));
|
||||||
context.subscriptions.push(new DiffWithNextCommand(git));
|
context.subscriptions.push(new DiffWithNextCommand(git));
|
||||||
context.subscriptions.push(new DiffWithPreviousCommand(git));
|
context.subscriptions.push(new DiffWithPreviousCommand(git));
|
||||||
context.subscriptions.push(new DiffWithWorkingCommand(git));
|
context.subscriptions.push(new DiffWithWorkingCommand(git));
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export class Git {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getVersionedFile(fileName: string, repoPath: string, branchOrSha: string) {
|
static async getVersionedFile(repoPath: string, fileName: string, branchOrSha: string) {
|
||||||
const data = await Git.show(repoPath, fileName, branchOrSha);
|
const data = await Git.show(repoPath, fileName, branchOrSha);
|
||||||
|
|
||||||
const suffix = Git.isSha(branchOrSha) ? branchOrSha.substring(0, 8) : branchOrSha;
|
const suffix = Git.isSha(branchOrSha) ? branchOrSha.substring(0, 8) : branchOrSha;
|
||||||
@@ -70,7 +70,7 @@ export class Git {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.log(`getVersionedFile(${fileName}, ${repoPath}, ${branchOrSha}); destination=${destination}`);
|
Logger.log(`getVersionedFile('${repoPath}', '${fileName}', ${branchOrSha}); destination=${destination}`);
|
||||||
fs.appendFile(destination, data, err => {
|
fs.appendFile(destination, data, err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
@@ -127,6 +127,12 @@ export class Git {
|
|||||||
return gitCommand(root, ...params, `--`, file);
|
return gitCommand(root, ...params, `--`, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static branch(repoPath: string) {
|
||||||
|
const params = [`branch`, `-a`];
|
||||||
|
|
||||||
|
return gitCommand(repoPath, ...params);
|
||||||
|
}
|
||||||
|
|
||||||
static diff_nameStatus(repoPath: string, sha1?: string, sha2?: string) {
|
static diff_nameStatus(repoPath: string, sha1?: string, sha2?: string) {
|
||||||
const params = [`diff`, `--name-status`, `-M`];
|
const params = [`diff`, `--name-status`, `-M`];
|
||||||
if (sha1) {
|
if (sha1) {
|
||||||
|
|||||||
@@ -210,3 +210,31 @@ const statusOcticonsMap = {
|
|||||||
export function getGitStatusIcon(status: GitFileStatus, missing: string = '\u00a0\u00a0\u00a0\u00a0'): string {
|
export function getGitStatusIcon(status: GitFileStatus, missing: string = '\u00a0\u00a0\u00a0\u00a0'): string {
|
||||||
return statusOcticonsMap[status] || missing;
|
return statusOcticonsMap[status] || missing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class GitBranch {
|
||||||
|
|
||||||
|
current: boolean;
|
||||||
|
name: string;
|
||||||
|
remote: boolean;
|
||||||
|
|
||||||
|
constructor(branch: string) {
|
||||||
|
branch = branch.trim();
|
||||||
|
|
||||||
|
if (branch.startsWith('* ')) {
|
||||||
|
branch = branch.substring(2);
|
||||||
|
this.current = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (branch.startsWith('remotes/')) {
|
||||||
|
branch = branch.substring(8);
|
||||||
|
this.remote = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = branch.indexOf(' ');
|
||||||
|
if (index !== -1) {
|
||||||
|
branch = branch.substring(0, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.name = branch;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ import { Disposable, Event, EventEmitter, ExtensionContext, FileSystemWatcher, l
|
|||||||
import { CommandContext, setCommandContext } from './commands';
|
import { CommandContext, setCommandContext } from './commands';
|
||||||
import { CodeLensVisibility, IConfig } from './configuration';
|
import { CodeLensVisibility, IConfig } from './configuration';
|
||||||
import { DocumentSchemes, WorkspaceState } from './constants';
|
import { DocumentSchemes, WorkspaceState } from './constants';
|
||||||
import { Git, GitBlameParserEnricher, GitBlameFormat, GitCommit, GitFileStatusItem, GitLogParserEnricher, IGitAuthor, IGitBlame, IGitBlameLine, IGitBlameLines, IGitLog } from './git/git';
|
import { Git, GitBlameParserEnricher, GitBlameFormat, GitBranch, GitCommit, GitFileStatusItem, GitLogParserEnricher, IGitAuthor, IGitBlame, IGitBlameLine, IGitBlameLines, IGitLog } from './git/git';
|
||||||
import { IGitUriData, GitUri } from './git/gitUri';
|
import { IGitUriData, GitUri } from './git/gitUri';
|
||||||
import GitCodeLensProvider from './gitCodeLensProvider';
|
import GitCodeLensProvider from './gitCodeLensProvider';
|
||||||
import { Logger } from './logger';
|
import { Logger } from './logger';
|
||||||
@@ -491,6 +491,14 @@ export class GitService extends Disposable {
|
|||||||
return locations;
|
return locations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getBranches(repoPath: string): Promise<GitBranch[]> {
|
||||||
|
Logger.log(`getBranches('${repoPath}')`);
|
||||||
|
|
||||||
|
const data = await Git.branch(repoPath);
|
||||||
|
const branches = data.split('\n').filter(_ => !!_).map(_ => new GitBranch(_));
|
||||||
|
return branches;
|
||||||
|
}
|
||||||
|
|
||||||
async getLogForRepo(repoPath: string, sha?: string, maxCount?: number, reverse: boolean = false): Promise<IGitLog | undefined> {
|
async getLogForRepo(repoPath: string, sha?: string, maxCount?: number, reverse: boolean = false): Promise<IGitLog | undefined> {
|
||||||
Logger.log(`getLogForRepo('${repoPath}', ${maxCount})`);
|
Logger.log(`getLogForRepo('${repoPath}', ${maxCount})`);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
export { BranchQuickPickItem, BranchesQuickPick } from './quickPicks/branches';
|
||||||
export { CommandQuickPickItem, OpenFileCommandQuickPickItem, OpenFilesCommandQuickPickItem, showQuickPickProgress } from './quickPicks/quickPicks';
|
export { CommandQuickPickItem, OpenFileCommandQuickPickItem, OpenFilesCommandQuickPickItem, showQuickPickProgress } from './quickPicks/quickPicks';
|
||||||
export { CommitQuickPickItem, CommitWithFileStatusQuickPickItem } from './quickPicks/gitQuickPicks';
|
export { CommitQuickPickItem, CommitWithFileStatusQuickPickItem } from './quickPicks/gitQuickPicks';
|
||||||
export { OpenCommitFilesCommandQuickPickItem, OpenCommitWorkingTreeFilesCommandQuickPickItem, CommitDetailsQuickPick } from './quickPicks/commitDetails';
|
export { OpenCommitFilesCommandQuickPickItem, OpenCommitWorkingTreeFilesCommandQuickPickItem, CommitDetailsQuickPick } from './quickPicks/commitDetails';
|
||||||
|
|||||||
42
src/quickPicks/branches.ts
Normal file
42
src/quickPicks/branches.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
'use strict';
|
||||||
|
import { QuickPickItem, QuickPickOptions, window } from 'vscode';
|
||||||
|
import { GitBranch, GitUri } from '../gitService';
|
||||||
|
import { CommandQuickPickItem, getQuickPickIgnoreFocusOut } from './quickPicks';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
export class BranchQuickPickItem implements QuickPickItem {
|
||||||
|
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
detail: string;
|
||||||
|
|
||||||
|
constructor(public branch: GitBranch) {
|
||||||
|
this.label = `${branch.current ? '$(check)\u00a0' : '\u00a0\u00a0\u00a0\u00a0'} ${branch.name}`;
|
||||||
|
this.description = branch.remote ? '\u00a0\u00a0 remote branch' : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BranchesQuickPick {
|
||||||
|
|
||||||
|
static async show(branches: GitBranch[], uri: GitUri, goBackCommand?: CommandQuickPickItem): Promise<BranchQuickPickItem | CommandQuickPickItem | undefined> {
|
||||||
|
|
||||||
|
const items = branches.map(_ => new BranchQuickPickItem(_)) as (BranchQuickPickItem | CommandQuickPickItem)[];
|
||||||
|
|
||||||
|
if (goBackCommand) {
|
||||||
|
items.splice(0, 0, goBackCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
// const scope = await Keyboard.instance.beginScope({ left: goBackCommand });
|
||||||
|
|
||||||
|
const pick = await window.showQuickPick(items,
|
||||||
|
{
|
||||||
|
placeHolder: `Compare ${path.basename(uri.fsPath)} to \u2026`,
|
||||||
|
ignoreFocusOut: getQuickPickIgnoreFocusOut()
|
||||||
|
} as QuickPickOptions);
|
||||||
|
if (!pick) return undefined;
|
||||||
|
|
||||||
|
// await scope.dispose();
|
||||||
|
|
||||||
|
return pick;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user