diff --git a/CHANGELOG.md b/CHANGELOG.md index bfe5f7b..c8758bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Adds a new _revert_ Git command to revert specific commits - Adds a new _stash_ Git command with sub-commands for _apply_, _drop_, _pop_, and _push_ - Adds a new _Fetch All & Prune_ option to the _fetch_ Git command + - Adds the last fetched on date to the confirmation step of the _fetch_ Git command (when a single repo is selected) + - Adds the last fetched on date to the confirmation step of the _pull_ Git command (when a single repo is selected) + - Adds a fetch button to the confirmation step of the _pull_ Git command (when a single repo is selected) + - Adds the number of commits to pull to the confirmation step of the _pull_ Git command (when a single repo is selected) + - Adds the number of commits to push to the confirmation step of the _push_ Git command (when a single repo is selected) - Adds a new _Squash Merge_ option to the _merge_ Git command - Adds a new _Force Push_ option to the _push_ Git command - Adds ability to create a local branch from a remote branch when using the _switch_ Git command diff --git a/src/commands/git/fetch.ts b/src/commands/git/fetch.ts index 8979e1b..57fcf63 100644 --- a/src/commands/git/fetch.ts +++ b/src/commands/git/fetch.ts @@ -3,7 +3,7 @@ import { Container } from '../../container'; import { Repository } from '../../git/gitService'; import { QuickCommandBase, StepAsyncGenerator, StepSelection, StepState } from '../quickCommand'; import { GitFlagsQuickPickItem, RepositoryQuickPickItem } from '../../quickpicks'; -import { Strings } from '../../system'; +import { Dates, Strings } from '../../system'; import { GlyphChars } from '../../constants'; import { Logger } from '../../logger'; @@ -87,10 +87,20 @@ export class FetchGitCommand extends QuickCommandBase { } if (this.confirm(state.confirm)) { + let fetchedOn = ''; + if (state.repos.length === 1) { + const lastFetched = await state.repos[0].getLastFetched(); + if (lastFetched !== 0) { + fetchedOn = `${Strings.pad(GlyphChars.Dot, 2, 2)}Last fetched ${Dates.getFormatter( + new Date(lastFetched) + ).fromNow()}`; + } + } + const step = this.createConfirmStep( `Confirm ${this.title}${Strings.pad(GlyphChars.Dot, 2, 2)}${ state.repos.length === 1 - ? state.repos[0].formattedName + ? `${state.repos[0].formattedName}${fetchedOn}` : `${state.repos.length} repositories` }`, [ diff --git a/src/commands/git/pull.ts b/src/commands/git/pull.ts index cc8a6d5..5eedeae 100644 --- a/src/commands/git/pull.ts +++ b/src/commands/git/pull.ts @@ -1,9 +1,10 @@ 'use strict'; +import { QuickInputButton } from 'vscode'; import { Container } from '../../container'; import { Repository } from '../../git/gitService'; import { QuickCommandBase, StepAsyncGenerator, StepSelection, StepState } from '../quickCommand'; import { GitFlagsQuickPickItem, RepositoryQuickPickItem } from '../../quickpicks'; -import { Strings } from '../../system'; +import { Dates, Strings } from '../../system'; import { GlyphChars } from '../../constants'; import { Logger } from '../../logger'; @@ -84,35 +85,31 @@ export class PullGitCommand extends QuickCommandBase { } if (this.confirm(state.confirm)) { - const step = this.createConfirmStep( - `Confirm ${this.title}${Strings.pad(GlyphChars.Dot, 2, 2)}${ - state.repos.length === 1 - ? state.repos[0].formattedName - : `${state.repos.length} repositories` - }`, - [ - { - label: this.title, - description: '', - detail: `Will pull ${ - state.repos.length === 1 - ? state.repos[0].formattedName - : `${state.repos.length} repositories` - }`, - item: [] - }, - { - label: `${this.title} with Rebase`, - description: '--rebase', - detail: `Will pull with rebase ${ - state.repos.length === 1 - ? state.repos[0].formattedName - : `${state.repos.length} repositories` - }`, - item: ['--rebase'] - } - ] - ); + let step; + if (state.repos.length > 1) { + step = this.createConfirmStep( + `Confirm ${this.title}${Strings.pad(GlyphChars.Dot, 2, 2)}${ + state.repos.length + } repositories`, + [ + { + label: this.title, + description: '', + detail: `Will pull ${state.repos.length} repositories`, + item: [] + }, + { + label: `${this.title} with Rebase`, + description: '--rebase', + detail: `Will pull with rebase ${state.repos.length} repositories`, + item: ['--rebase'] + } + ] + ); + } else { + step = await this.getSingleRepoConfirmStep(state); + } + const selection: StepSelection = yield step; if (!this.canPickStepMoveNext(step, state, selection)) { @@ -139,4 +136,66 @@ export class PullGitCommand extends QuickCommandBase { return undefined; } + + private async getSingleRepoConfirmStep(state: StepState) { + const repo = state.repos![0]; + const [status, lastFetched] = await Promise.all([repo.getStatus(), repo.getLastFetched()]); + + const title = `Confirm ${this.title}${Strings.pad(GlyphChars.Dot, 2, 2)}${repo.formattedName}`; + + let detail = repo.formattedName; + let fetchedOn = ''; + if (lastFetched !== 0 && status !== undefined) { + detail = Strings.pluralize('commit', status.state.behind); + + fetchedOn = `${Strings.pad(GlyphChars.Dot, 2, 2)}Last fetched ${Dates.getFormatter( + new Date(lastFetched) + ).fromNow()}`; + } + + const step = this.createConfirmStep(`${title}${fetchedOn}`, [ + { + label: this.title, + description: '', + detail: `Will pull ${detail}`, + item: [] + }, + { + label: `${this.title} with Rebase`, + description: '--rebase', + detail: `Will pull ${detail} with rebase`, + item: ['--rebase'] + } + ]); + + const fetchButton: QuickInputButton = { + iconPath: { + dark: Container.context.asAbsolutePath('images/dark/icon-sync.svg') as any, + light: Container.context.asAbsolutePath('images/light/icon-sync.svg') as any + }, + tooltip: 'Fetch' + }; + + step.additionalButtons = [fetchButton]; + step.onDidClickButton = async (quickpick, button) => { + if (button !== fetchButton) return; + + quickpick.title = `${title}${Strings.pad(GlyphChars.Dot, 2, 2)}Fetching${GlyphChars.Ellipsis}`; + quickpick.busy = true; + quickpick.enabled = false; + + try { + await repo.fetch({ progress: true }); + + const step = await this.getSingleRepoConfirmStep(state); + quickpick.title = step.title; + quickpick.items = step.items as any; + } finally { + quickpick.busy = false; + quickpick.enabled = true; + } + }; + + return step; + } } diff --git a/src/commands/git/push.ts b/src/commands/git/push.ts index 46211d5..0aabeef 100644 --- a/src/commands/git/push.ts +++ b/src/commands/git/push.ts @@ -2,7 +2,7 @@ import { Container } from '../../container'; import { Repository } from '../../git/gitService'; import { QuickCommandBase, StepAsyncGenerator, StepSelection, StepState } from '../quickCommand'; -import { RepositoryQuickPickItem } from '../../quickpicks'; +import { Directive, DirectiveQuickPickItem, RepositoryQuickPickItem } from '../../quickpicks'; import { Strings } from '../../system'; import { GlyphChars } from '../../constants'; import { Logger } from '../../logger'; @@ -84,35 +84,31 @@ export class PushGitCommand extends QuickCommandBase { } if (this.confirm(state.confirm)) { - const step = this.createConfirmStep( - `Confirm ${this.title}${Strings.pad(GlyphChars.Dot, 2, 2)}${ - state.repos.length === 1 - ? state.repos[0].formattedName - : `${state.repos.length} repositories` - }`, - [ - { - label: this.title, - description: '', - detail: `Will push ${ - state.repos.length === 1 - ? state.repos[0].formattedName - : `${state.repos.length} repositories` - }`, - item: [] - }, - { - label: `Force ${this.title}`, - description: '--force', - detail: `Will force push ${ - state.repos.length === 1 - ? state.repos[0].formattedName - : `${state.repos.length} repositories` - }`, - item: ['--force'] - } - ] - ); + let step; + if (state.repos.length > 1) { + step = this.createConfirmStep( + `Confirm ${this.title}${Strings.pad(GlyphChars.Dot, 2, 2)}${ + state.repos.length + } repositories`, + [ + { + label: this.title, + description: '', + detail: `Will push ${state.repos.length} repositories`, + item: [] + }, + { + label: `Force ${this.title}`, + description: '--force', + detail: `Will force push ${state.repos.length} repositories`, + item: ['--force'] + } + ] + ); + } else { + step = await this.getSingleRepoConfirmStep(state); + } + const selection: StepSelection = yield step; if (!this.canPickStepMoveNext(step, state, selection)) { @@ -139,4 +135,45 @@ export class PushGitCommand extends QuickCommandBase { return undefined; } + + private async getSingleRepoConfirmStep(state: StepState) { + const repo = state.repos![0]; + const status = await repo.getStatus(); + + let detail = repo.formattedName; + if (status !== undefined) { + if (status.state.ahead === 0) { + return this.createConfirmStep( + `Confirm ${this.title}${Strings.pad(GlyphChars.Dot, 2, 2)}${repo.formattedName}`, + [], + { + cancel: DirectiveQuickPickItem.create(Directive.Cancel, true, { + label: `Cancel ${this.title}`, + detail: 'No commits to push' + }) + } + ); + } + + detail = Strings.pluralize('commit', status.state.ahead); + } + + return this.createConfirmStep( + `Confirm ${this.title}${Strings.pad(GlyphChars.Dot, 2, 2)}${repo.formattedName}`, + [ + { + label: this.title, + description: '', + detail: `Will push ${detail}`, + item: [] + }, + { + label: `Force ${this.title}`, + description: '--force', + detail: `Will force push ${detail}`, + item: ['--force'] + } + ] + ); + } }