diff --git a/src/config.ts b/src/config.ts
index 8d777ca8..2cacdafe 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -82,7 +82,7 @@ class Config {
const userConfig = this.config.get('contextMenuActionsVisibility', {});
const config: ContextMenuActionsVisibility = {
branch: { checkout: true, rename: true, delete: true, merge: true, rebase: true, push: true, viewIssue: true, createPullRequest: true, createArchive: true, selectInBranchesDropdown: true, unselectInBranchesDropdown: true, copyName: true },
- commit: { addTag: true, createBranch: true, checkout: true, cherrypick: true, revert: true, drop: true, merge: true, rebase: true, reset: true, copyHash: true, copySubject: true },
+ commit: { addTag: true, createBranch: true, checkout: true, cherrypick: true, commitFixup: true, revert: true, drop: true, merge: true, rebase: true, reset: true, copyHash: true, copySubject: true },
commitDetailsViewFile: { viewDiff: true, viewFileAtThisRevision: true, viewDiffWithWorkingFile: true, openFile: true, markAsReviewed: true, markAsNotReviewed: true, resetFileToThisRevision: true, copyAbsoluteFilePath: true, copyRelativeFilePath: true },
remoteBranch: { checkout: true, delete: true, fetch: true, merge: true, pull: true, viewIssue: true, createPullRequest: true, createArchive: true, selectInBranchesDropdown: true, unselectInBranchesDropdown: true, copyName: true },
stash: { apply: true, createBranch: true, pop: true, drop: true, copyName: true, copyHash: true },
@@ -218,7 +218,8 @@ class Config {
},
rebase: {
ignoreDate: !!this.config.get('dialog.rebase.ignoreDate', true),
- interactive: !!this.config.get('dialog.rebase.launchInteractiveRebase', false)
+ interactive: !!this.config.get('dialog.rebase.launchInteractiveRebase', false),
+ autosquash: !!this.config.get('dialog.rebase.autosquash', false)
},
resetCommit: {
mode: resetCommitMode === 'Soft' ? GitResetMode.Soft : (resetCommitMode === 'Hard' ? GitResetMode.Hard : GitResetMode.Mixed)
diff --git a/src/dataSource.ts b/src/dataSource.ts
index 10a3429f..c364e9df 100644
--- a/src/dataSource.ts
+++ b/src/dataSource.ts
@@ -1001,13 +1001,17 @@ export class DataSource extends Disposable {
* @param actionOn Is the rebase on a branch or commit.
* @param ignoreDate Is `--ignore-date` enabled.
* @param interactive Should the rebase be performed interactively.
+ * @param autosquash Is `--autosquash` enabled.
* @returns The ErrorInfo from the executed command.
*/
- public rebase(repo: string, obj: string, actionOn: RebaseActionOn, ignoreDate: boolean, interactive: boolean) {
+ public rebase(repo: string, obj: string, actionOn: RebaseActionOn, ignoreDate: boolean, interactive: boolean, autosquash: boolean) {
if (interactive) {
return this.openGitTerminal(
repo,
- 'rebase --interactive ' + (getConfig().signCommits ? '-S ' : '') + (actionOn === RebaseActionOn.Branch ? obj.replace(/'/g, '"\'"') : obj),
+ 'rebase --interactive ' +
+ (autosquash ? '--autosquash ' : '') +
+ (getConfig().signCommits ? '-S ' : '') +
+ (actionOn === RebaseActionOn.Branch ? obj.replace(/'/g, '"\'"') : obj),
'Rebase on "' + (actionOn === RebaseActionOn.Branch ? obj : abbrevCommit(obj)) + '"'
);
} else {
@@ -1092,6 +1096,17 @@ export class DataSource extends Disposable {
return this.runGitCommand(args, repo);
}
+ /**
+ * Commit the stashed files to fixup a commit.
+ * @param repo The path of the repository.
+ * @param commitHash The hash of the commit to drop.
+ * @returns The ErrorInfo from the executed command.
+ */
+ public commitFixup(repo: string, commitHash: string) {
+ const args = ['commit', '--fixup=' + commitHash];
+ return this.runGitCommand(args, repo);
+ }
+
/**
* Reset the current branch to a specified commit.
* @param repo The path of the repository.
diff --git a/src/gitGraphView.ts b/src/gitGraphView.ts
index 1acba6ff..ed68b07c 100644
--- a/src/gitGraphView.ts
+++ b/src/gitGraphView.ts
@@ -251,6 +251,13 @@ export class GitGraphView extends Disposable {
refresh: msg.refresh
});
break;
+ case 'commitFixup':
+ this.sendMessage({
+ command: 'commitFixup',
+ commitHash: msg.commitHash,
+ error: await this.dataSource.commitFixup(msg.repo, msg.commitHash)
+ });
+ break;
case 'compareCommits':
this.sendMessage({
command: 'compareCommits',
@@ -528,7 +535,7 @@ export class GitGraphView extends Disposable {
command: 'rebase',
actionOn: msg.actionOn,
interactive: msg.interactive,
- error: await this.dataSource.rebase(msg.repo, msg.obj, msg.actionOn, msg.ignoreDate, msg.interactive)
+ error: await this.dataSource.rebase(msg.repo, msg.obj, msg.actionOn, msg.ignoreDate, msg.interactive, msg.autosquash)
});
break;
case 'renameBranch':
diff --git a/src/types.ts b/src/types.ts
index c543fa9f..7712c9b7 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -361,6 +361,7 @@ export interface ContextMenuActionsVisibility {
readonly createBranch: boolean;
readonly checkout: boolean;
readonly cherrypick: boolean;
+ readonly commitFixup: boolean;
readonly revert: boolean;
readonly drop: boolean;
readonly merge: boolean;
@@ -496,6 +497,7 @@ export interface DialogDefaults {
readonly rebase: {
readonly ignoreDate: boolean,
readonly interactive: boolean
+ readonly autosquash: boolean
};
readonly resetCommit: {
readonly mode: GitResetMode
@@ -686,6 +688,17 @@ export interface RequestCommitDetails extends RepoRequest {
readonly avatarEmail: string | null; // string => fetch avatar with the given email, null => don't fetch avatar
readonly refresh: boolean;
}
+
+export interface ResponseCommitFixup extends ResponseWithErrorInfo {
+ readonly command: 'commitFixup';
+ readonly commitHash: string;
+}
+
+export interface RequestCommitFixup extends RepoRequest {
+ readonly command: 'commitFixup';
+ readonly commitHash: string;
+}
+
export interface ResponseCommitDetails extends ResponseWithErrorInfo {
readonly command: 'commitDetails';
readonly commitDetails: GitCommitDetails | null;
@@ -1095,6 +1108,7 @@ export interface RequestRebase extends RepoRequest {
readonly actionOn: RebaseActionOn;
readonly ignoreDate: boolean;
readonly interactive: boolean;
+ readonly autosquash: boolean;
}
export interface ResponseRebase extends ResponseWithErrorInfo {
readonly command: 'rebase';
@@ -1257,6 +1271,7 @@ export type RequestMessage =
| RequestCherrypickCommit
| RequestCleanUntrackedFiles
| RequestCommitDetails
+ | RequestCommitFixup
| RequestCompareCommits
| RequestCopyFilePath
| RequestCopyToClipboard
@@ -1322,6 +1337,7 @@ export type ResponseMessage =
| ResponseCleanUntrackedFiles
| ResponseCompareCommits
| ResponseCommitDetails
+ | ResponseCommitFixup
| ResponseCopyFilePath
| ResponseCopyToClipboard
| ResponseCreateArchive
diff --git a/web/main.ts b/web/main.ts
index 29c23c82..17afe5b6 100644
--- a/web/main.ts
+++ b/web/main.ts
@@ -1108,6 +1108,10 @@ class GitGraphView {
title: 'Create Branch' + ELLIPSIS,
visible: visibility.createBranch,
onClick: () => this.createBranchAction(hash, '', this.config.dialogDefaults.createBranch.checkout, target)
+ }, {
+ title: 'Fixup this Commit',
+ visible: visibility.commitFixup,
+ onClick: () => this.commitFixupAction(hash)
}
], [
{
@@ -1688,13 +1692,19 @@ class GitGraphView {
private rebaseAction(obj: string, name: string, actionOn: GG.RebaseActionOn, target: DialogTarget & (CommitTarget | RefTarget)) {
dialog.showForm('Are you sure you want to rebase ' + (this.gitBranchHead !== null ? '' + escapeHtml(this.gitBranchHead) + ' (the current branch)' : 'the current branch') + ' on ' + actionOn.toLowerCase() + ' ' + escapeHtml(name) + '?', [
{ type: DialogInputType.Checkbox, name: 'Launch Interactive Rebase in new Terminal', value: this.config.dialogDefaults.rebase.interactive },
+ { type: DialogInputType.Checkbox, name: 'Auto-squash', value: this.config.dialogDefaults.rebase.autosquash, info: 'Only applicable to an interactive rebase.' },
{ type: DialogInputType.Checkbox, name: 'Ignore Date', value: this.config.dialogDefaults.rebase.ignoreDate, info: 'Only applicable to a non-interactive rebase.' }
], 'Yes, rebase', (values) => {
let interactive = values[0];
- runAction({ command: 'rebase', repo: this.currentRepo, obj: obj, actionOn: actionOn, ignoreDate: values[1], interactive: interactive }, interactive ? 'Launching Interactive Rebase' : 'Rebasing on ' + actionOn);
+ let autosquash = interactive && values[1];
+ let ignoreDate = !interactive && values[2];
+ runAction({ command: 'rebase', repo: this.currentRepo, obj: obj, actionOn: actionOn, ignoreDate: ignoreDate, interactive: interactive, autosquash: autosquash }, interactive ? 'Launching Interactive Rebase' : 'Rebasing on ' + actionOn);
}, target);
}
+ private commitFixupAction(hash: string) {
+ runAction({ command: 'commitFixup', repo: this.currentRepo, commitHash: hash }, 'Commiting Fixup');
+ }
/* Table Utils */
@@ -3229,6 +3239,9 @@ window.addEventListener('load', () => {
dialog.showError('Unable to load Commit Details', msg.error, null, null);
}
break;
+ case 'commitFixup':
+ refreshOrDisplayError(msg.error, 'Unable to Commit');
+ break;
case 'compareCommits':
if (msg.error === null) {
gitGraph.showCommitComparison(msg.commitHash, msg.compareWithHash, msg.fileChanges, gitGraph.createFileTree(msg.fileChanges, msg.codeReview), msg.codeReview, msg.codeReview !== null ? msg.codeReview.lastViewedFile : null, msg.refresh);