提交 eaf1759f 编写于 作者: J Joao Moreno

Merge commit 'refs/pull/53286/head' of github.com:Microsoft/vscode into pr/53286

......@@ -285,16 +285,31 @@
"title": "%command.push%",
"category": "Git"
},
{
"command": "git.pushForce",
"title": "%command.pushForce%",
"category": "Git"
},
{
"command": "git.pushTo",
"title": "%command.pushTo%",
"category": "Git"
},
{
"command": "git.pushToForce",
"title": "%command.pushToForce%",
"category": "Git"
},
{
"command": "git.pushWithTags",
"title": "%command.pushWithTags%",
"category": "Git"
},
{
"command": "git.pushWithTagsForce",
"title": "%command.pushWithTagsForce%",
"category": "Git"
},
{
"command": "git.sync",
"title": "%command.sync%",
......@@ -517,14 +532,26 @@
"command": "git.push",
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.pushForce",
"when": "config.git.enabled && config.git.allowForcePush && gitOpenRepositoryCount != 0"
},
{
"command": "git.pushTo",
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.pushToForce",
"when": "config.git.enabled && config.git.allowForcePush && gitOpenRepositoryCount != 0"
},
{
"command": "git.pushWithTags",
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.pushWithTagsForce",
"when": "config.git.enabled && config.git.allowForcePush && gitOpenRepositoryCount != 0"
},
{
"command": "git.sync",
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
......@@ -1127,6 +1154,21 @@
"scope": "resource",
"default": false,
"description": "%config.fetchOnPull%"
},
"git.allowForcePush": {
"type": "boolean",
"default": false,
"description": "%config.allowForcePush%"
},
"git.useForceWithLease": {
"type": "boolean",
"default": true,
"description": "%config.useForceWithLease%"
},
"git.dontAskForcePushConfirmation": {
"type": "boolean",
"default": false,
"description": "%config.dontAskForcePushConfirmation%"
}
}
},
......
......@@ -41,8 +41,11 @@
"command.pullRebase": "Pull (Rebase)",
"command.pullFrom": "Pull from...",
"command.push": "Push",
"command.pushForce": "Push (Force)",
"command.pushTo": "Push to...",
"command.pushToForce": "Push to... (Force)",
"command.pushWithTags": "Push With Tags",
"command.pushWithTagsForce": "Push With Tags (Force)",
"command.sync": "Sync",
"command.syncRebase": "Sync (Rebase)",
"command.publish": "Publish Branch",
......@@ -89,7 +92,6 @@
"config.showPushSuccessNotification": "Controls whether to show a notification when a push is successful.",
"config.inputValidation": "Controls when to show commit message input validation.",
"config.detectSubmodules": "Controls whether to automatically detect git submodules.",
"colors.added": "Color for added resources.",
"config.detectSubmodulesLimit": "Controls the limit of git submodules detected.",
"config.alwaysShowStagedChangesResourceGroup": "Always show the Staged Changes resource group.",
"config.alwaysSignOff": "Controls the signoff flag for all commits.",
......@@ -98,6 +100,10 @@
"config.rebaseWhenSync": "Use rebase instead of merge when running the sync command.",
"config.confirmEmptyCommits": "Always confirm the creation of empty commits.",
"config.fetchOnPull": "Fetch all branches when pulling or just the current one.",
"config.allowForcePush": "Controls whether force push (with or without lease) is enabled.",
"config.useForceWithLease": "Controls whether force pushing uses the safer force-with-lease variant.",
"config.dontAskForcePushConfirmation": "Controls whether to ask for confirmation before force-pushing.",
"colors.added": "Color for added resources.",
"colors.modified": "Color for modified resources.",
"colors.deleted": "Color for deleted resources.",
"colors.untracked": "Color for untracked resources.",
......
......@@ -19,6 +19,11 @@ export const enum RefType {
Tag
}
export enum ForcePushMode {
Force,
ForceWithLease,
}
export interface Ref {
readonly type: RefType;
readonly name?: string;
......
......@@ -17,7 +17,7 @@ import { lstat, Stats } from 'fs';
import * as os from 'os';
import TelemetryReporter from 'vscode-extension-telemetry';
import * as nls from 'vscode-nls';
import { Ref, RefType, Branch, GitErrorCodes } from './api/git';
import { Ref, RefType, Branch, GitErrorCodes, ForcePushMode } from './api/git';
const localize = nls.loadMessageBundle();
......@@ -152,6 +152,17 @@ async function categorizeResourceByResolution(resources: Resource[]): Promise<{
return { merge, resolved, unresolved };
}
enum PushType {
Push,
PushTo,
PushTags,
}
interface PushOptions {
pushType: PushType;
forcePush?: boolean;
}
export class CommandCenter {
private disposables: Disposable[];
......@@ -1486,76 +1497,100 @@ export class CommandCenter {
await repository.pullWithRebase(repository.HEAD);
}
@command('git.push', { repository: true })
async push(repository: Repository): Promise<void> {
private async pushWithOptions(repository: Repository, pushOptions: PushOptions) {
const remotes = repository.remotes;
const config = workspace.getConfiguration('git');
const forcePushMode = pushOptions.forcePush && config.get<boolean>('useForceWithLease') === true ? ForcePushMode.ForceWithLease : ForcePushMode.Force;
if (pushOptions.forcePush && config.get<boolean>('dontAskForcePushConfirmation') === false) {
const message = localize('confirm force push', "You are about to force push your changes, this can be destructive and could inadvertedly overwrite changes made by others.\n\nAre you sure to continue?");
const yes = localize('ok', "OK");
const dontAsk = localize('dontAsk', "OK, do not ask me again");
const pick = await window.showWarningMessage(message, { modal: true }, yes, dontAsk);
if (pick === dontAsk) {
config.update('dontAskForcePushConfirmation', true, true);
} else if (pick !== yes) {
return;
}
}
if (remotes.length === 0) {
window.showWarningMessage(localize('no remotes to push', "Your repository has no remotes configured to push to."));
return;
}
if (pushOptions.pushType === PushType.PushTags) {
await repository.pushTags(undefined, forcePushMode);
window.showInformationMessage(localize('push with tags success', "Successfully pushed with tags."));
return;
}
if (!repository.HEAD || !repository.HEAD.name) {
window.showWarningMessage(localize('nobranch', "Please check out a branch to push to a remote."));
return;
}
try {
await repository.push(repository.HEAD);
} catch (err) {
if (err.gitErrorCode !== GitErrorCodes.NoUpstreamBranch) {
throw err;
}
if (pushOptions.pushType === PushType.Push) {
try {
await repository.push(repository.HEAD, forcePushMode);
} catch (err) {
if (err.gitErrorCode !== GitErrorCodes.NoUpstreamBranch) {
throw err;
}
const branchName = repository.HEAD.name;
const message = localize('confirm publish branch', "The branch '{0}' has no upstream branch. Would you like to publish this branch?", branchName);
const yes = localize('ok', "OK");
const pick = await window.showWarningMessage(message, { modal: true }, yes);
if (pick === yes) {
await this.publish(repository);
}
}
} else {
const branchName = repository.HEAD.name;
const message = localize('confirm publish branch', "The branch '{0}' has no upstream branch. Would you like to publish this branch?", branchName);
const yes = localize('ok', "OK");
const pick = await window.showWarningMessage(message, { modal: true }, yes);
const picks = remotes.filter(r => r.pushUrl !== undefined).map(r => ({ label: r.name, description: r.pushUrl! }));
const placeHolder = localize('pick remote', "Pick a remote to publish the branch '{0}' to:", branchName);
const pick = await window.showQuickPick(picks, { placeHolder });
if (pick === yes) {
await this.publish(repository);
if (!pick) {
return;
}
await repository.pushTo(pick.label, branchName, undefined, forcePushMode);
}
}
@command('git.pushWithTags', { repository: true })
async pushWithTags(repository: Repository): Promise<void> {
const remotes = repository.remotes;
@command('git.push', { repository: true })
async push(repository: Repository): Promise<void> {
await this.pushWithOptions(repository, { pushType: PushType.Push });
}
if (remotes.length === 0) {
window.showWarningMessage(localize('no remotes to push', "Your repository has no remotes configured to push to."));
return;
}
@command('git.pushForce', { repository: true })
async pushForce(repository: Repository): Promise<void> {
await this.pushWithOptions(repository, { pushType: PushType.Push, forcePush: true });
}
await repository.pushTags();
@command('git.pushWithTags', { repository: true })
async pushWithTags(repository: Repository): Promise<void> {
await this.pushWithOptions(repository, { pushType: PushType.PushTags });
}
window.showInformationMessage(localize('push with tags success', "Successfully pushed with tags."));
@command('git.pushWithTagsForce', { repository: true })
async pushWithTagsForce(repository: Repository): Promise<void> {
await this.pushWithOptions(repository, { pushType: PushType.PushTags, forcePush: true });
}
@command('git.pushTo', { repository: true })
async pushTo(repository: Repository): Promise<void> {
const remotes = repository.remotes;
if (remotes.length === 0) {
window.showWarningMessage(localize('no remotes to push', "Your repository has no remotes configured to push to."));
return;
}
if (!repository.HEAD || !repository.HEAD.name) {
window.showWarningMessage(localize('nobranch', "Please check out a branch to push to a remote."));
return;
}
const branchName = repository.HEAD.name;
const picks = remotes.filter(r => r.pushUrl !== undefined).map(r => ({ label: r.name, description: r.pushUrl! }));
const placeHolder = localize('pick remote', "Pick a remote to publish the branch '{0}' to:", branchName);
const pick = await window.showQuickPick(picks, { placeHolder });
if (!pick) {
return;
}
await this.pushWithOptions(repository, { pushType: PushType.PushTo });
}
await repository.pushTo(pick.label, branchName);
@command('git.pushToForce', { repository: true })
async pushToForce(repository: Repository): Promise<void> {
await this.pushWithOptions(repository, { pushType: PushType.PushTo, forcePush: true });
}
private async _sync(repository: Repository, rebase: boolean): Promise<void> {
......
......@@ -1198,9 +1198,17 @@ export class Repository {
}
}
async push(remote?: string, name?: string, setUpstream: boolean = false, tags = false): Promise<void> {
async push(remote?: string, name?: string, setUpstream: boolean = false, tags = false, forcePushMode?: ForcePushMode): Promise<void> {
const args = ['push'];
if (forcePushMode) {
if (forcePushMode === ForcePushMode.ForceWithLease) {
args.push('--force-with-lease');
} else if (forcePushMode === ForcePushMode.Force) {
args.push('--force');
}
}
if (setUpstream) {
args.push('-u');
}
......
......@@ -15,7 +15,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 } from './api/git';
import { Branch, Ref, Remote, RefType, GitErrorCodes, ForcePushMode } from './api/git';
const timeout = (millis: number) => new Promise(c => setTimeout(c, millis));
......@@ -961,7 +961,7 @@ export class Repository implements Disposable {
}
@throttle
async push(head: Branch): Promise<void> {
async push(head: Branch, forcePushMode?: ForcePushMode): Promise<void> {
let remote: string | undefined;
let branch: string | undefined;
......@@ -970,15 +970,15 @@ export class Repository implements Disposable {
branch = `${head.name}:${head.upstream.name}`;
}
await this.run(Operation.Push, () => this.repository.push(remote, branch));
await this.run(Operation.Push, () => this.repository.push(remote, branch, undefined, undefined, forcePushMode));
}
async pushTo(remote?: string, name?: string, setUpstream: boolean = false): Promise<void> {
await this.run(Operation.Push, () => this.repository.push(remote, name, setUpstream));
async pushTo(remote?: string, name?: string, setUpstream: boolean = false, forcePushMode?: ForcePushMode): Promise<void> {
await this.run(Operation.Push, () => this.repository.push(remote, name, setUpstream, undefined, forcePushMode));
}
async pushTags(remote?: string): Promise<void> {
await this.run(Operation.Push, () => this.repository.push(remote, undefined, false, true));
async pushTags(remote?: string, forcePushMode?: ForcePushMode): Promise<void> {
await this.run(Operation.Push, () => this.repository.push(remote, undefined, false, true, forcePushMode));
}
@throttle
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册