diff --git a/extensions/git/src/api/git.d.ts b/extensions/git/src/api/git.d.ts index ae8eb5315bc..14eeff9942c 100644 --- a/extensions/git/src/api/git.d.ts +++ b/extensions/git/src/api/git.d.ts @@ -26,6 +26,11 @@ export interface Ref { readonly remote?: string; } +export interface TrackingShip { + readonly local: string; + readonly upstream: string; +} + export interface UpstreamRef { readonly remote: string; readonly name: string; @@ -235,4 +240,4 @@ export const enum GitErrorCodes { CantRebaseMultipleBranches = 'CantRebaseMultipleBranches', PatchDoesNotApply = 'PatchDoesNotApply', NoPathFound = 'NoPathFound' -} \ No newline at end of file +} diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index f6e00e9abdd..a87b7dddfe2 100755 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -52,11 +52,20 @@ class CheckoutRemoteHeadItem extends CheckoutItem { } async run(repository: Repository): Promise { - if (!this.ref.name) { + const ref = this.ref.name; + if (!ref) { return; } - await repository.checkoutTracking(this.ref.name); + // Check whether there's a local branch which already has the target branch as an upstream + const trackings = await repository.getTracking(ref); + if (trackings.length > 0) { + //Just checkout the local branch + await repository.checkout(trackings[0].local); + } else { + // Default: checkout a new local branch tracking the upstream + await repository.checkoutTracking(ref); + } } } diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 896942d2d3f..ef1d0e8c70f 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -14,7 +14,7 @@ import * as filetype from 'file-type'; import { assign, groupBy, denodeify, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent } from './util'; import { CancellationToken, Uri, workspace } from 'vscode'; import { detectEncoding } from './encoding'; -import { Ref, RefType, Branch, Remote, GitErrorCodes, LogOptions, Change, Status } from './api/git'; +import { Ref, RefType, Branch, Remote, GitErrorCodes, LogOptions, Change, Status, TrackingShip } from './api/git'; const readfile = denodeify(fs.readFile); @@ -1578,6 +1578,21 @@ export class Repository { } } + async GetTracking(upstreamBranch: string): Promise { + const result = await this.run(['for-each-ref', '--format', '%(if)%(upstream:short)%(then)%(refname:short)->%(upstream:short) %(else)* %(end)', 'refs/heads']); + return result.stdout.trim().split('\n') + .map(line => line.trim()) + .filter(line => line !== '*') + .map(line => { + const splited = line.split('->'); + return { + local: splited[0], + upstream: splited[1] + } as TrackingShip; + }) + .filter(trackingShip => trackingShip.upstream === upstreamBranch); + } + async getRefs(): Promise { const result = await this.run(['for-each-ref', '--format', '%(refname) %(objectname)', '--sort', '-committerdate']); diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 803c4881fa5..a085336e653 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -13,7 +13,7 @@ import * as path from 'path'; import * as nls from 'vscode-nls'; import * as fs from 'fs'; import { StatusBarCommands } from './statusbar'; -import { Branch, Ref, Remote, RefType, GitErrorCodes, Status, LogOptions, Change } from './api/git'; +import { Branch, Ref, Remote, RefType, GitErrorCodes, Status, LogOptions, Change, TrackingShip } from './api/git'; const timeout = (millis: number) => new Promise(c => setTimeout(c, millis)); @@ -299,6 +299,7 @@ export const enum Operation { GetObjectDetails = 'GetObjectDetails', SubmoduleUpdate = 'SubmoduleUpdate', RebaseContinue = 'RebaseContinue', + GetTracking = 'GetTracking', Apply = 'Apply', Blame = 'Blame', Log = 'Log', @@ -909,6 +910,10 @@ export class Repository implements Disposable { await this.run(Operation.CheckoutTracking, () => this.repository.checkout(treeish, [], { track: true })); } + async getTracking(treeish: string): Promise { + return await this.run(Operation.GetTracking, () => this.repository.GetTracking(treeish)); + } + async getCommit(ref: string): Promise { return await this.repository.getCommit(ref); }