Ver código fonte

Adds setUpstream ability to push

main
Eric Amodio 4 anos atrás
pai
commit
a7e6e4112a
4 arquivos alterados com 148 adições e 22 exclusões
  1. +69
    -3
      src/@types/git.d.ts
  2. +49
    -10
      src/commands/git/push.ts
  3. +4
    -1
      src/git/gitService.ts
  4. +26
    -8
      src/git/models/repository.ts

+ 69
- 3
src/@types/git.d.ts Ver arquivo

@ -3,7 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Event, Uri } from 'vscode';
import { Disposable, Event, ProviderResult, Uri } from 'vscode';
export { ProviderResult } from 'vscode';
export interface Git {
readonly path: string;
@ -41,7 +43,10 @@ export interface Commit {
readonly hash: string;
readonly message: string;
readonly parents: string[];
readonly authorEmail?: string | undefined;
readonly authorDate?: Date;
readonly authorName?: string;
readonly authorEmail?: string;
readonly commitDate?: Date;
}
export interface Submodule {
@ -117,6 +122,22 @@ export interface RepositoryUIState {
export interface LogOptions {
/** Max number of log entries to retrieve. If not specified, the default is 32. */
readonly maxEntries?: number;
readonly path?: string;
}
export interface CommitOptions {
all?: boolean | 'tracked';
amend?: boolean;
signoff?: boolean;
signCommit?: boolean;
empty?: boolean;
}
export interface BranchQuery {
readonly remote?: boolean;
readonly pattern?: string;
readonly count?: number;
readonly contains?: string;
}
export interface Repository {
@ -158,6 +179,7 @@ export interface Repository {
createBranch(name: string, checkout: boolean, ref?: string): Promise<void>;
deleteBranch(name: string, force?: boolean): Promise<void>;
getBranch(name: string): Promise<Branch>;
getBranches(query: BranchQuery): Promise<Ref[]>;
setBranchUpstream(name: string, upstream: string): Promise<void>;
getMergeBase(ref1: string, ref2: string): Promise<string>;
@ -167,6 +189,7 @@ export interface Repository {
addRemote(name: string, url: string): Promise<void>;
removeRemote(name: string): Promise<void>;
renameRemote(name: string, newName: string): Promise<void>;
fetch(remote?: string, ref?: string, depth?: number): Promise<void>;
pull(unshallow?: boolean): Promise<void>;
@ -174,13 +197,54 @@ export interface Repository {
blame(path: string): Promise<string>;
log(options?: LogOptions): Promise<Commit[]>;
commit(message: string, opts?: CommitOptions): Promise<void>;
}
export interface RemoteSource {
readonly name: string;
readonly description?: string;
readonly url: string | string[];
}
export interface RemoteSourceProvider {
readonly name: string;
readonly icon?: string; // codicon name
readonly supportsQuery?: boolean;
getRemoteSources(query?: string): ProviderResult<RemoteSource[]>;
publishRepository?(repository: Repository): Promise<void>;
}
export interface Credentials {
readonly username: string;
readonly password: string;
}
export interface CredentialsProvider {
getCredentials(host: Uri): ProviderResult<Credentials>;
}
export interface PushErrorHandler {
handlePushError(repository: Repository, remote: Remote, refspec: string, error: Error & { gitErrorCode: GitErrorCodes }): Promise<boolean>;
}
export type APIState = 'uninitialized' | 'initialized';
export interface API {
readonly state: APIState;
readonly onDidChangeState: Event<APIState>;
readonly git: Git;
readonly repositories: Repository[];
readonly onDidOpenRepository: Event<Repository>;
readonly onDidCloseRepository: Event<Repository>;
toGitUri(uri: Uri, ref: string): Uri;
getRepository(uri: Uri): Repository | null;
init(root: Uri): Promise<Repository | null>;
registerRemoteSourceProvider(provider: RemoteSourceProvider): Disposable;
registerCredentialsProvider(provider: CredentialsProvider): Disposable;
registerPushErrorHandler(handler: PushErrorHandler): Disposable;
}
export interface GitExtension {
@ -218,6 +282,7 @@ export const enum GitErrorCodes {
CantOpenResource = 'CantOpenResource',
GitNotFound = 'GitNotFound',
CantCreatePipe = 'CantCreatePipe',
PermissionDenied = 'PermissionDenied',
CantAccessRemote = 'CantAccessRemote',
RepositoryNotFound = 'RepositoryNotFound',
RepositoryIsLocked = 'RepositoryIsLocked',
@ -234,5 +299,6 @@ export const enum GitErrorCodes {
CantLockRef = 'CantLockRef',
CantRebaseMultipleBranches = 'CantRebaseMultipleBranches',
PatchDoesNotApply = 'PatchDoesNotApply',
NoPathFound = 'NoPathFound'
NoPathFound = 'NoPathFound',
UnknownPath = 'UnknownPath',
}

+ 49
- 10
src/commands/git/push.ts Ver arquivo

@ -1,7 +1,7 @@
'use strict';
import { configuration } from '../../configuration';
import { Container } from '../../container';
import { GitReference, Repository } from '../../git/git';
import { GitBranchReference, GitReference, Repository } from '../../git/git';
import {
appendReposToTitle,
PartialStepState,
@ -25,7 +25,7 @@ interface Context {
title: string;
}
type Flags = '--force';
type Flags = '--force' | '--set-upstream' | string;
interface State<Repos = string | string[] | Repository | Repository[]> {
repos: Repos;
@ -60,8 +60,15 @@ export class PushGitCommand extends QuickCommand {
}
execute(state: State<Repository[]>) {
let setUpstream: { branch: string; remote: string } | undefined;
if (state.flags.includes('--set-upstream')) {
const index = state.flags.indexOf('--set-upstream');
setUpstream = { branch: state.flags[index + 1], remote: state.flags[index + 2] };
}
return Container.git.pushAll(state.repos, {
force: state.flags.includes('--force'),
setUpstream: setUpstream,
reference: state.reference,
});
}
@ -159,14 +166,46 @@ export class PushGitCommand extends QuickCommand {
const status = await repo.getStatus();
if (status?.state.ahead === 0) {
step = this.createConfirmStep(
appendReposToTitle(`Confirm ${context.title}`, state, context),
[],
DirectiveQuickPickItem.create(Directive.Cancel, true, {
label: `Cancel ${this.title}`,
detail: 'No commits found to push',
}),
);
const items: FlagsQuickPickItem<Flags>[] = [];
if (state.reference == null && status.upstream == null) {
const branchRef: GitBranchReference = {
refType: 'branch',
name: status.branch,
ref: status.branch,
remote: false,
repoPath: status.repoPath,
};
for (const remote of await repo.getRemotes()) {
items.push(
FlagsQuickPickItem.create<Flags>(
state.flags,
['--set-upstream', status.branch, remote.name],
{
label: `${this.title} to ${remote.name}`,
detail: `Will push ${GitReference.toString(branchRef)} to ${remote.name}`,
},
),
);
}
}
if (items.length) {
step = this.createConfirmStep(
appendReposToTitle(`Confirm ${context.title}`, state, context),
items,
);
} else {
step = this.createConfirmStep(
appendReposToTitle(`Confirm ${context.title}`, state, context),
[],
DirectiveQuickPickItem.create(Directive.Cancel, true, {
label: `Cancel ${this.title}`,
detail: 'No commits found to push',
}),
);
}
} else {
let lastFetchedOn = '';

+ 4
- 1
src/git/gitService.ts Ver arquivo

@ -622,7 +622,10 @@ export class GitService implements Disposable {
0: (repos?: Repository[]) => (repos == null ? false : repos.map(r => r.name).join(', ')),
},
})
async pushAll(repositories?: Repository[], options: { force?: boolean; reference?: GitReference } = {}) {
async pushAll(
repositories?: Repository[],
options: { force?: boolean; reference?: GitReference; setUpstream?: { branch: string; remote: string } } = {},
) {
if (repositories == null) {
repositories = await this.getOrderedRepositories();
}

+ 26
- 8
src/git/models/repository.ts Ver arquivo

@ -445,22 +445,40 @@ export class Repository implements Disposable {
@gate()
@log()
async push(options: { force?: boolean; progress?: boolean; reference?: GitReference } = {}) {
const { force, progress, reference } = { progress: true, ...options };
if (!progress) return this.pushCore(force, reference);
async push(
options: {
force?: boolean;
progress?: boolean;
reference?: GitReference;
setUpstream?: { branch: string; remote: string };
} = {},
) {
const { progress, ...opts } = { progress: true, ...options };
if (!progress) return this.pushCore(opts);
return void (await window.withProgress(
{
location: ProgressLocation.Notification,
title: `Pushing ${this.formattedName}...`,
},
() => this.pushCore(force, reference),
() => this.pushCore(opts),
));
}
private async pushCore(force: boolean = false, reference?: GitReference) {
private async pushCore(
options: {
force?: boolean;
reference?: GitReference;
setUpstream?: { branch: string; remote: string };
} = {},
) {
try {
if (reference != null) {
if (options.setUpstream != null) {
const repo = await GitService.getBuiltInGitRepository(this.path);
if (repo == null) return;
await repo?.push(options.setUpstream.remote, options.setUpstream.branch, true);
} else if (options.reference != null) {
const branch = await this.getBranch();
if (branch === undefined) return;
@ -469,11 +487,11 @@ export class Repository implements Disposable {
await repo?.push(
branch.getRemoteName(),
`${reference.ref}:${branch.getNameWithoutRemote()}`,
`${options.reference.ref}:${branch.getNameWithoutRemote()}`,
undefined,
);
} else {
void (await commands.executeCommand(force ? 'git.pushForce' : 'git.push', this.path));
void (await commands.executeCommand(options.force ? 'git.pushForce' : 'git.push', this.path));
}
this.fireChange(RepositoryChange.Repository);

Carregando…
Cancelar
Salvar