SCM - add more commands to the repositories view (#274352)

* SCM - artifact tree improvements

* Add support for compression

* Add more commands
This commit is contained in:
Ladislau Szomoru
2025-10-31 14:44:15 +00:00
committed by GitHub
parent 4b1a7b8b8c
commit e82ab3b366
5 changed files with 251 additions and 87 deletions

View File

@@ -1028,6 +1028,18 @@
"icon": "$(target)",
"category": "Git",
"enablement": "!operationInProgress"
},
{
"command": "git.repositories.checkoutDetached",
"title": "%command.graphCheckoutDetached%",
"category": "Git",
"enablement": "!operationInProgress"
},
{
"command": "git.repositories.compareRef",
"title": "%command.graphCompareRef%",
"category": "Git",
"enablement": "!operationInProgress"
}
],
"continueEditSession": [
@@ -1655,6 +1667,14 @@
{
"command": "git.repositories.checkout",
"when": "false"
},
{
"command": "git.repositories.checkoutDetached",
"when": "false"
},
{
"command": "git.repositories.compareRef",
"when": "false"
}
],
"scm/title": [
@@ -1862,6 +1882,21 @@
"command": "git.repositories.checkout",
"group": "inline@1",
"when": "scmProvider == git"
},
{
"command": "git.repositories.checkout",
"group": "1_checkout@1",
"when": "scmProvider == git"
},
{
"command": "git.repositories.checkoutDetached",
"group": "1_checkout@2",
"when": "scmProvider == git"
},
{
"command": "git.repositories.compareRef",
"group": "2_compare@1",
"when": "scmProvider == git"
}
],
"scm/resourceGroup/context": [

View File

@@ -14,7 +14,7 @@ import { Model } from './model';
import { GitResourceGroup, Repository, Resource, ResourceGroupType } from './repository';
import { DiffEditorSelectionHunkToolbarContext, LineChange, applyLineChanges, getIndexDiffInformation, getModifiedRange, getWorkingTreeDiffInformation, intersectDiffWithRange, invertLineChange, toLineChanges, toLineRanges, compareLineChanges } from './staging';
import { fromGitUri, toGitUri, isGitUri, toMergeUris, toMultiFileDiffEditorUris } from './uri';
import { DiagnosticSeverityConfig, dispose, fromNow, grep, isDefined, isDescendant, isLinuxSnap, isRemote, isWindows, pathEquals, relativePath, subject, toDiagnosticSeverity, truncate } from './util';
import { DiagnosticSeverityConfig, dispose, fromNow, getHistoryItemDisplayName, grep, isDefined, isDescendant, isLinuxSnap, isRemote, isWindows, pathEquals, relativePath, subject, toDiagnosticSeverity, truncate } from './util';
import { GitTimelineItem } from './timelineProvider';
import { ApiRepository } from './api/api1';
import { getRemoteSourceActions, pickRemoteSource } from './remoteSource';
@@ -124,6 +124,7 @@ class RefItem implements QuickPickItem {
get refName(): string | undefined { return this.ref.name; }
get refRemote(): string | undefined { return this.ref.remote; }
get shortCommit(): string { return (this.ref.commit || '').substring(0, this.shortCommitLength); }
get commitMessage(): string | undefined { return this.ref.commitDetails?.message; }
private _buttons?: QuickInputButton[];
get buttons(): QuickInputButton[] | undefined { return this._buttons; }
@@ -3115,10 +3116,13 @@ export class CommandCenter {
return;
}
const title = `${repository.historyProvider.currentHistoryItemRemoteRef.name}${getHistoryItemDisplayName(historyItem)}`;
await this._openChangesBetweenRefs(
repository,
repository.historyProvider.currentHistoryItemRemoteRef.name,
historyItem);
repository.historyProvider.currentHistoryItemRemoteRef.revision,
historyItem.id,
title);
}
@command('git.graph.compareWithMergeBase', { repository: true })
@@ -3127,14 +3131,17 @@ export class CommandCenter {
return;
}
const title = `${repository.historyProvider.currentHistoryItemBaseRef.name}${getHistoryItemDisplayName(historyItem)}`;
await this._openChangesBetweenRefs(
repository,
repository.historyProvider.currentHistoryItemBaseRef.name,
historyItem);
historyItem.id,
title);
}
@command('git.graph.compareRef', { repository: true })
async compareBranch(repository: Repository, historyItem?: SourceControlHistoryItem): Promise<void> {
async compareRef(repository: Repository, historyItem?: SourceControlHistoryItem): Promise<void> {
if (!repository || !historyItem) {
return;
}
@@ -3161,39 +3168,30 @@ export class CommandCenter {
return;
}
const title = `${sourceRef.ref.name}${getHistoryItemDisplayName(historyItem)}`;
await this._openChangesBetweenRefs(
repository,
sourceRef.ref.name,
historyItem);
sourceRef.ref.commit,
historyItem.id,
title);
}
private async _openChangesBetweenRefs(repository: Repository, ref: string | undefined, historyItem: SourceControlHistoryItem | undefined): Promise<void> {
if (!repository || !ref || !historyItem) {
private async _openChangesBetweenRefs(repository: Repository, ref1: string | undefined, ref2: string | undefined, title: string): Promise<void> {
if (!repository || !ref1 || !ref2) {
return;
}
const ref2 = historyItem.references?.length
? historyItem.references[0].name
: historyItem.id;
try {
const changes = await repository.diffBetween2(ref, historyItem.id);
const changes = await repository.diffBetween2(ref1, ref2);
if (changes.length === 0) {
window.showInformationMessage(l10n.t('There are no changes between "{0}" and "{1}".', ref, ref2));
window.showInformationMessage(l10n.t('There are no changes between "{0}" and "{1}".', ref1, ref2));
return;
}
const refDisplayName = historyItem.references?.length
? historyItem.references[0].name
: `${historyItem.displayId || historyItem.id} - ${historyItem.subject}`;
const resources = changes.map(change => toMultiFileDiffEditorUris(change, ref, ref2));
const title = `${ref}${refDisplayName}`;
const multiDiffSourceUri = Uri.from({
scheme: 'git-ref-compare',
path: `${repository.root}/${ref}..${ref2}`
});
const multiDiffSourceUri = Uri.from({ scheme: 'git-ref-compare', path: `${repository.root}/${ref1}..${ref2}` });
const resources = changes.map(change => toMultiFileDiffEditorUris(change, ref1, ref2));
await commands.executeCommand('_workbench.openMultiDiffEditor', {
multiDiffSourceUri,
@@ -3201,7 +3199,7 @@ export class CommandCenter {
resources
});
} catch (err) {
window.showErrorMessage(l10n.t('Failed to open changes between "{0}" and "{1}": {2}', ref, ref2, err.message));
window.showErrorMessage(l10n.t('Failed to open changes between "{0}" and "{1}": {2}', ref1, ref2, err.message));
}
}
@@ -5191,6 +5189,50 @@ export class CommandCenter {
await this._checkout(repository, { treeish: artifact.name });
}
@command('git.repositories.checkoutDetached', { repository: true })
async artifactCheckoutDetached(repository: Repository, artifact: SourceControlArtifact): Promise<void> {
if (!repository || !artifact) {
return;
}
await this._checkout(repository, { treeish: artifact.name, detached: true });
}
@command('git.repositories.compareRef', { repository: true })
async artifactCompareWith(repository: Repository, artifact: SourceControlArtifact): Promise<void> {
if (!repository || !artifact) {
return;
}
const config = workspace.getConfiguration('git');
const showRefDetails = config.get<boolean>('showReferenceDetails') === true;
const getRefPicks = async () => {
const refs = await repository.getRefs({ includeCommitDetails: showRefDetails });
const processors = [
new RefProcessor(RefType.Head, BranchItem),
new RefProcessor(RefType.RemoteHead, BranchItem),
new RefProcessor(RefType.Tag, BranchItem)
];
const itemsProcessor = new RefItemsProcessor(repository, processors);
return itemsProcessor.processRefs(refs);
};
const placeHolder = l10n.t('Select a reference to compare with');
const sourceRef = await this.pickRef(getRefPicks(), placeHolder);
if (!(sourceRef instanceof BranchItem) || !sourceRef.ref.commit) {
return;
}
await this._openChangesBetweenRefs(
repository,
sourceRef.ref.commit,
artifact.id,
`${sourceRef.ref.name}${artifact.name}`);
}
private createCommand(id: string, key: string, method: Function, options: ScmCommandOptions): (...args: any[]) => any {
const result = (...args: any[]) => {
let result: Promise<any>;

View File

@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Event, Disposable, EventEmitter, SourceControlHistoryItemRef, l10n, workspace, Uri, DiagnosticSeverity, env } from 'vscode';
import { Event, Disposable, EventEmitter, SourceControlHistoryItemRef, l10n, workspace, Uri, DiagnosticSeverity, env, SourceControlHistoryItem } from 'vscode';
import { dirname, normalize, sep, relative } from 'path';
import { Readable } from 'stream';
import { promises as fs, createReadStream } from 'fs';
@@ -797,6 +797,12 @@ export function getCommitShortHash(scope: Uri, hash: string): string {
return hash.substring(0, shortHashLength);
}
export function getHistoryItemDisplayName(historyItem: SourceControlHistoryItem): string {
return historyItem.references?.length
? historyItem.references[0].name
: historyItem.displayId ?? historyItem.id;
}
export type DiagnosticSeverityConfig = 'error' | 'warning' | 'information' | 'hint' | 'none';
export function toDiagnosticSeverity(value: DiagnosticSeverityConfig): DiagnosticSeverity {