mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 04:49:35 +00:00
[#25575] Add Git Tag feature.
This commit is contained in:
parent
56b341c2e0
commit
211e7a3030
|
@ -172,6 +172,21 @@
|
|||
"title": "%command.branch%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.createTag",
|
||||
"title": "%command.createTag%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.showTags",
|
||||
"title": "%command.showTags%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.pushWithTags",
|
||||
"title": "%command.pushWithTags%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.pull",
|
||||
"title": "%command.pull%",
|
||||
|
@ -306,10 +321,22 @@
|
|||
"command": "git.pullRebase",
|
||||
"when": "config.git.enabled && scmProvider == git && gitState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.showTags",
|
||||
"when": "config.git.enabled && scmProvider == git && gitState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.createTag",
|
||||
"when": "config.git.enabled && scmProvider == git && gitState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.push",
|
||||
"when": "config.git.enabled && scmProvider == git && gitState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.pushWithTags",
|
||||
"when": "config.git.enabled && scmProvider == git && gitState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.pushTo",
|
||||
"when": "config.git.enabled && scmProvider == git && gitState == idle"
|
||||
|
|
|
@ -21,8 +21,11 @@
|
|||
"command.undoCommit": "Undo Last Commit",
|
||||
"command.checkout": "Checkout to...",
|
||||
"command.branch": "Create Branch...",
|
||||
"command.createTag": "Create Tag",
|
||||
"command.showTags": "Show Tags",
|
||||
"command.pull": "Pull",
|
||||
"command.pullRebase": "Pull (Rebase)",
|
||||
"command.pushWithTags": "Push With Tags",
|
||||
"command.push": "Push",
|
||||
"command.pushTo": "Push to...",
|
||||
"command.sync": "Sync",
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
'use strict';
|
||||
|
||||
import { Uri, commands, scm, Disposable, window, workspace, QuickPickItem, OutputChannel, Range, WorkspaceEdit, Position, LineChange, SourceControlResourceState } from 'vscode';
|
||||
import { Ref, RefType, Git, GitErrorCodes } from './git';
|
||||
import { Ref, RefType, Git, GitErrorCodes, PushOptions } from './git';
|
||||
import { Model, Resource, Status, CommitOptions, WorkingTreeGroup, IndexGroup, MergeGroup } from './model';
|
||||
import { toGitUri, fromGitUri } from './uri';
|
||||
import { applyLineChanges, intersectDiffWithRange, toLineRanges, invertLineChange } from './staging';
|
||||
|
@ -17,6 +17,10 @@ import * as nls from 'vscode-nls';
|
|||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
class PushOptionsImpl implements PushOptions {
|
||||
withTags: boolean;
|
||||
}
|
||||
|
||||
class CheckoutItem implements QuickPickItem {
|
||||
|
||||
protected get shortCommit(): string { return (this.ref.commit || '').substr(0, 8); }
|
||||
|
@ -37,6 +41,26 @@ class CheckoutItem implements QuickPickItem {
|
|||
}
|
||||
}
|
||||
|
||||
class ShowTag implements QuickPickItem {
|
||||
|
||||
protected get shortCommit(): string { return (this.ref.commit || '').substr(0, 8); }
|
||||
get label(): string { return this.ref.name || this.shortCommit; }
|
||||
get description(): string { return this.shortCommit; }
|
||||
|
||||
constructor(protected ref: Ref) { }
|
||||
|
||||
async run(model: Model): Promise<void> {
|
||||
const result = await model.showObject(this.ref.name || '');
|
||||
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
workspace.openTextDocument({ language: 'en', content: result.trim() })
|
||||
.then(window.showTextDocument);
|
||||
}
|
||||
}
|
||||
|
||||
class CheckoutTagItem extends CheckoutItem {
|
||||
|
||||
get description(): string {
|
||||
|
@ -699,6 +723,48 @@ export class CommandCenter {
|
|||
await this.model.branch(name);
|
||||
}
|
||||
|
||||
@command('git.showTags')
|
||||
async showTags(): Promise<void> {
|
||||
const tags = this.model.refs
|
||||
.filter(x => x.type === RefType.Tag)
|
||||
.map(tag => new ShowTag(tag));
|
||||
|
||||
const placeHolder = 'Select a tag';
|
||||
|
||||
var choice = await window.showQuickPick<ShowTag>(tags, { placeHolder });
|
||||
|
||||
if (!choice) {
|
||||
return;
|
||||
}
|
||||
|
||||
await choice.run(this.model);
|
||||
}
|
||||
|
||||
@command('git.createTag')
|
||||
async createTag(): Promise<void> {
|
||||
const inputTagName = await window.showInputBox({
|
||||
placeHolder: localize('tag name', "Tag name"),
|
||||
prompt: localize('provide tag name', "Please provide a tag name"),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (!inputTagName) {
|
||||
return;
|
||||
}
|
||||
|
||||
const inputMessage = await window.showInputBox({
|
||||
placeHolder: localize('tag message', "Message"),
|
||||
prompt: localize('provide tag message', "Please provide a message"),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
const name = inputTagName.replace(/^\.|\/\.|\.\.|~|\^|:|\/$|\.lock$|\.lock\/|\\|\*|\s|^\s*$|\.$/g, '-');
|
||||
const message = inputMessage || name;
|
||||
await this.model.tag(name, message);
|
||||
|
||||
window.showInformationMessage(localize('tag creation success', "Successfully created tag."));
|
||||
}
|
||||
|
||||
@command('git.pull')
|
||||
async pull(): Promise<void> {
|
||||
const remotes = this.model.remotes;
|
||||
|
@ -735,6 +801,23 @@ export class CommandCenter {
|
|||
await this.model.push();
|
||||
}
|
||||
|
||||
@command('git.pushWithTags')
|
||||
async pushWithTags(): Promise<void> {
|
||||
const remotes = this.model.remotes;
|
||||
|
||||
if (remotes.length === 0) {
|
||||
window.showWarningMessage(localize('no remotes to push', "Your repository has no remotes configured to push to."));
|
||||
return;
|
||||
}
|
||||
|
||||
let pushOptions = new PushOptionsImpl();
|
||||
pushOptions.withTags = true;
|
||||
|
||||
await this.model.push(undefined, undefined, pushOptions);
|
||||
|
||||
window.showInformationMessage(localize('push with tags success', "Successfully pushed with tags."));
|
||||
}
|
||||
|
||||
@command('git.pushTo')
|
||||
async pushTo(): Promise<void> {
|
||||
const remotes = this.model.remotes;
|
||||
|
|
|
@ -23,6 +23,7 @@ export interface IGit {
|
|||
|
||||
export interface PushOptions {
|
||||
setUpstream?: boolean;
|
||||
withTags?: boolean;
|
||||
}
|
||||
|
||||
export interface IFileStatus {
|
||||
|
@ -650,6 +651,29 @@ export class Repository {
|
|||
await this.run(args);
|
||||
}
|
||||
|
||||
async show(ref: string): Promise<string> {
|
||||
let args = ['show', '-s', '--format=%H\n%B', ref];
|
||||
const result = await this.run(args);
|
||||
|
||||
if (!result) {
|
||||
return Promise.reject<string>('Invalid reference provided.');
|
||||
}
|
||||
|
||||
return result.stdout;
|
||||
}
|
||||
|
||||
async tag(name: string, message: string, lightweight: boolean): Promise<void> {
|
||||
let args = ['tag'];
|
||||
|
||||
if (lightweight) {
|
||||
args.push(name);
|
||||
} else {
|
||||
args = args.concat(['-a', name, '-m', message]);
|
||||
}
|
||||
|
||||
await this.run(args);
|
||||
}
|
||||
|
||||
async clean(paths: string[]): Promise<void> {
|
||||
const pathsByGroup = groupBy(paths, p => path.dirname(p));
|
||||
const groups = Object.keys(pathsByGroup).map(k => pathsByGroup[k]);
|
||||
|
@ -757,8 +781,14 @@ export class Repository {
|
|||
async push(remote?: string, name?: string, options?: PushOptions): Promise<void> {
|
||||
const args = ['push'];
|
||||
|
||||
if (options && options.setUpstream) {
|
||||
args.push('-u');
|
||||
if (options) {
|
||||
if (options.setUpstream) {
|
||||
args.push('-u');
|
||||
}
|
||||
|
||||
if (options.withTags) {
|
||||
args.push('--tags');
|
||||
}
|
||||
}
|
||||
|
||||
if (remote) {
|
||||
|
@ -945,8 +975,8 @@ export class Repository {
|
|||
}
|
||||
|
||||
async getCommit(ref: string): Promise<Commit> {
|
||||
const result = await this.run(['show', '-s', '--format=%H\n%B', ref]);
|
||||
const match = /^([0-9a-f]{40})\n([^]*)$/m.exec(result.stdout.trim());
|
||||
const result = await this.show(ref);
|
||||
const match = /^([0-9a-f]{40})\n([^]*)$/m.exec(result.trim());
|
||||
|
||||
if (!match) {
|
||||
return Promise.reject<Commit>('bad commit format');
|
||||
|
|
|
@ -211,7 +211,8 @@ export enum Operation {
|
|||
Init = 1 << 12,
|
||||
Show = 1 << 13,
|
||||
Stage = 1 << 14,
|
||||
GetCommitTemplate = 1 << 15
|
||||
GetCommitTemplate = 1 << 15,
|
||||
Tag = 1 << 16
|
||||
}
|
||||
|
||||
// function getOperationName(operation: Operation): string {
|
||||
|
@ -454,6 +455,10 @@ export class Model implements Disposable {
|
|||
await this.run(Operation.Branch, () => this.repository.branch(name, true));
|
||||
}
|
||||
|
||||
async tag(name: string, message: string): Promise<void> {
|
||||
await this.run(Operation.Tag, () => this.repository.tag(name, message, false));
|
||||
}
|
||||
|
||||
async checkout(treeish: string): Promise<void> {
|
||||
await this.run(Operation.Checkout, () => this.repository.checkout(treeish, []));
|
||||
}
|
||||
|
@ -506,6 +511,10 @@ export class Model implements Disposable {
|
|||
});
|
||||
}
|
||||
|
||||
async showObject(ref: string): Promise<string> {
|
||||
return await this.run(Operation.Show, () => this.repository.show(ref));
|
||||
}
|
||||
|
||||
async getCommitTemplate(): Promise<string> {
|
||||
return await this.run(Operation.GetCommitTemplate, async () => this.repository.getCommitTemplate());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue