From 9a3321404e1afaccd34c63ce5c482d07b2f65ab1 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 8 Feb 2017 12:59:07 +0100 Subject: [PATCH] git: undo command --- extensions/git/package.json | 2 +- extensions/git/src/commands.ts | 14 ++++++++++--- extensions/git/src/git.ts | 30 +++++++++++++------------- extensions/git/src/model.ts | 37 +++++++++++++++++++++------------ extensions/git/src/statusbar.ts | 4 ++-- 5 files changed, 53 insertions(+), 34 deletions(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index c3be0f5dc2c..5564a3d409b 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -247,7 +247,7 @@ { "command": "git.undoCommit", "group": "3_commit", - "when": "scmProvider == none" + "when": "scmProvider == git" }, { "command": "git.unstageAll", diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 6eb6fedbd77..5f2faed952a 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -6,7 +6,7 @@ 'use strict'; import { Uri, commands, scm, Disposable, SCMResourceGroup, SCMResource, window, workspace, QuickPickItem, OutputChannel } from 'vscode'; -import { IRef, RefType } from './git'; +import { Ref, RefType } from './git'; import { Model, Resource, Status, CommitOptions } from './model'; import * as path from 'path'; import * as nls from 'vscode-nls'; @@ -38,7 +38,7 @@ class CheckoutItem implements QuickPickItem { get label(): string { return this.ref.name || this.shortCommit; } get description(): string { return this.shortCommit; } - constructor(protected ref: IRef) { } + constructor(protected ref: Ref) { } async run(model: Model): Promise { const ref = this.treeish; @@ -415,7 +415,15 @@ export class CommandCenter { @CommandCenter.Command('git.undoCommit') @CommandCenter.CatchErrors async undoCommit(): Promise { - await Promise.reject('not implemented'); + const HEAD = this.model.HEAD; + + if (!HEAD || !HEAD.commit) { + return; + } + + const commit = await this.model.getCommit('HEAD'); + await this.model.reset('HEAD~'); + scm.inputBox.value = commit.message; } @CommandCenter.Command('git.checkout') diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index b7f1bd33b1e..1adc670f6ae 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -22,7 +22,7 @@ export interface IGit { version: string; } -export interface IPushOptions { +export interface PushOptions { setUpstream?: boolean; } @@ -33,7 +33,7 @@ export interface IFileStatus { rename?: string; } -export interface IRemote { +export interface Remote { name: string; url: string; } @@ -44,14 +44,14 @@ export enum RefType { Tag } -export interface IRef { +export interface Ref { type: RefType; name?: string; commit?: string; remote?: string; } -export interface IBranch extends IRef { +export interface Branch extends Ref { upstream?: string; ahead?: number; behind?: number; @@ -371,7 +371,7 @@ export class Git { } } -export interface ICommit { +export interface Commit { hash: string; message: string; } @@ -676,7 +676,7 @@ export class Repository { } } - async push(remote?: string, name?: string, options?: IPushOptions): Promise { + async push(remote?: string, name?: string, options?: PushOptions): Promise { const args = ['push']; if (options && options.setUpstream) { @@ -754,7 +754,7 @@ export class Repository { return result; } - async getHEAD(): Promise { + async getHEAD(): Promise { try { const result = await this.run(['symbolic-ref', '--short', 'HEAD']); @@ -774,10 +774,10 @@ export class Repository { } } - async getRefs(): Promise { + async getRefs(): Promise { const result = await this.run(['for-each-ref', '--format', '%(refname) %(objectname)']); - const fn = (line): IRef | null => { + const fn = (line): Ref | null => { let match: RegExpExecArray | null; if (match = /^refs\/heads\/([^ ]+) ([0-9a-f]{40})$/.exec(line)) { @@ -794,10 +794,10 @@ export class Repository { return result.stdout.trim().split('\n') .filter(line => !!line) .map(fn) - .filter(ref => !!ref) as IRef[]; + .filter(ref => !!ref) as Ref[]; } - async getRemotes(): Promise { + async getRemotes(): Promise { const result = await this.run(['remote', '--verbose']); const regex = /^([^\s]+)\s+([^\s]+)\s/; const rawRemotes = result.stdout.trim().split('\n') @@ -809,7 +809,7 @@ export class Repository { return uniqBy(rawRemotes, remote => remote.name); } - async getBranch(name: string): Promise { + async getBranch(name: string): Promise { if (name === 'HEAD') { return this.getHEAD(); } @@ -817,7 +817,7 @@ export class Repository { const result = await this.run(['rev-parse', name]); if (!result.stdout) { - return Promise.reject(new Error('No such branch')); + return Promise.reject(new Error('No such branch')); } const commit = result.stdout.trim(); @@ -872,12 +872,12 @@ export class Repository { } } - async getCommit(ref: string): Promise { + async getCommit(ref: string): Promise { const result = await this.run(['show', '-s', '--format=%H\n%B', ref]); const match = /^([0-9a-f]{40})\n([^]*)$/m.exec(result.stdout.trim()); if (!match) { - return Promise.reject('bad commit format'); + return Promise.reject('bad commit format'); } return { hash: match[1], message: match[2] }; diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index 9cf8268ad08..f894ad1998f 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -6,7 +6,7 @@ 'use strict'; import { Uri, EventEmitter, Event, SCMResource, SCMResourceDecorations, SCMResourceGroup, Disposable, window, workspace } from 'vscode'; -import { Repository, IRef, IBranch, IRemote, IPushOptions } from './git'; +import { Repository, Ref, Branch, Remote, PushOptions, Commit } from './git'; import { anyEvent, eventToPromise, filterEvent, mapEvent } from './util'; import { memoize, throttle, debounce } from './decorators'; import { watch } from './watch'; @@ -161,10 +161,11 @@ export enum Operation { Clean = 1 << 4, Branch = 1 << 5, Checkout = 1 << 6, - Fetch = 1 << 7, - Pull = 1 << 8, - Push = 1 << 9, - Sync = 1 << 10 + Reset = 1 << 7, + Fetch = 1 << 8, + Pull = 1 << 9, + Push = 1 << 10, + Sync = 1 << 11, } export interface Operations { @@ -274,18 +275,18 @@ export class Model { return this._repositoryRoot; } - private _HEAD: IBranch | undefined; - get HEAD(): IBranch | undefined { + private _HEAD: Branch | undefined; + get HEAD(): Branch | undefined { return this._HEAD; } - private _refs: IRef[] = []; - get refs(): IRef[] { + private _refs: Ref[] = []; + get refs(): Ref[] { return this._refs; } - private _remotes: IRemote[] = []; - get remotes(): IRemote[] { + private _remotes: Remote[] = []; + get remotes(): Remote[] { return this._remotes; } @@ -358,6 +359,16 @@ export class Model { await this.run(Operation.Checkout, () => this.repository.checkout(treeish, [])); } + @throttle + async getCommit(ref: string): Promise { + return await this.repository.getCommit(ref); + } + + @throttle + async reset(treeish: string, hard?: boolean): Promise { + await this.run(Operation.Reset, () => this.repository.reset(treeish, hard)); + } + @throttle async fetch(): Promise { await this.run(Operation.Fetch, () => this.repository.fetch()); @@ -369,7 +380,7 @@ export class Model { } @throttle - async push(remote?: string, name?: string, options?: IPushOptions): Promise { + async push(remote?: string, name?: string, options?: PushOptions): Promise { await this.run(Operation.Push, () => this.repository.push(remote, name, options)); } @@ -396,7 +407,7 @@ export class Model { @throttle private async update(): Promise { const status = await this.repository.getStatus(); - let HEAD: IBranch | undefined; + let HEAD: Branch | undefined; try { HEAD = await this.repository.getHEAD(); diff --git a/extensions/git/src/statusbar.ts b/extensions/git/src/statusbar.ts index 436ee05bc72..f3171809317 100644 --- a/extensions/git/src/statusbar.ts +++ b/extensions/git/src/statusbar.ts @@ -6,7 +6,7 @@ 'use strict'; import { window, Disposable, StatusBarItem, StatusBarAlignment } from 'vscode'; -import { RefType, IBranch } from './git'; +import { RefType, Branch } from './git'; import { Model, Operation } from './model'; import * as nls from 'vscode-nls'; @@ -58,7 +58,7 @@ export class CheckoutStatusBar { interface SyncStatusBarState { isSyncRunning: boolean; hasRemotes: boolean; - HEAD: IBranch | undefined; + HEAD: Branch | undefined; } export class SyncStatusBar { -- GitLab