Skip to content

Commit

Permalink
#63 Commits can be squashed when merging if the "Squash commits" chec…
Browse files Browse the repository at this point in the history
…kbox is checked on the commit and branch merge dialogs.
  • Loading branch information
mhutchie committed May 14, 2019
1 parent 5f43bc4 commit e72f144
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 14 deletions.
3 changes: 3 additions & 0 deletions media/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,9 @@ svg.openFolderIcon, svg.closedFolderIcon, svg.fileIcon{
#dialog > table.dialogForm.multi input[type=checkbox]{
margin-left:0;
}
#dialog > table.dialogForm.single input[type=checkbox], #dialog > table.dialogForm.multiCheckbox input[type=checkbox]{
margin-right:5px;
}
#dialog > table.dialogForm input[type=text], #dialog > table.dialogForm select{
padding:4px;
box-sizing:border-box;
Expand Down
26 changes: 22 additions & 4 deletions src/dataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,24 @@ export class DataSource {
return this.runGitCommand('branch -m ' + escapeRefName(oldName) + ' ' + escapeRefName(newName), repo);
}

public mergeBranch(repo: string, branchName: string, createNewCommit: boolean) {
return this.runGitCommand('merge ' + escapeRefName(branchName) + (createNewCommit ? ' --no-ff' : ''), repo);
public async mergeBranch(repo: string, branchName: string, createNewCommit: boolean, squash: boolean) {
let mergeStatus = await this.runGitCommand('merge ' + escapeRefName(branchName) + (createNewCommit && !squash ? ' --no-ff' : '') + (squash ? ' --squash' : ''), repo);
if (mergeStatus === null && squash) {
if (await this.areStagedChanges(repo)) {
return this.runGitCommand('commit -m "Merge branch \'' + escapeRefName(branchName) + '\'"', repo);
}
}
return mergeStatus;
}

public mergeCommit(repo: string, commitHash: string, createNewCommit: boolean) {
return this.runGitCommand('merge ' + commitHash + (createNewCommit ? ' --no-ff' : ''), repo);
public async mergeCommit(repo: string, commitHash: string, createNewCommit: boolean, squash: boolean) {
let mergeStatus = await this.runGitCommand('merge ' + commitHash + (createNewCommit && !squash ? ' --no-ff' : '') + (squash ? ' --squash' : ''), repo);
if (mergeStatus === null && squash) {
if (await this.areStagedChanges(repo)) {
return this.runGitCommand('commit -m "Merge commit \'' + commitHash + '\'"', repo);
}
}
return mergeStatus;
}

public cherrypickCommit(repo: string, commitHash: string, parentIndex: number) {
Expand Down Expand Up @@ -299,6 +311,12 @@ export class DataSource {
});
}

private areStagedChanges(repo: string) {
return new Promise<boolean>(resolve => {
this.execGit('diff-index HEAD', repo, (err, stdout) => resolve(!err && stdout !== ''));
});
}

private runGitCommand(command: string, repo: string) {
return new Promise<GitCommandStatus>((resolve) => {
this.execGit(command, repo, (err, stdout, stderr) => {
Expand Down
4 changes: 2 additions & 2 deletions src/gitGraphView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,13 +187,13 @@ export class GitGraphView {
case 'mergeBranch':
this.sendMessage({
command: 'mergeBranch',
status: await this.dataSource.mergeBranch(msg.repo, msg.branchName, msg.createNewCommit)
status: await this.dataSource.mergeBranch(msg.repo, msg.branchName, msg.createNewCommit, msg.squash)
});
break;
case 'mergeCommit':
this.sendMessage({
command: 'mergeCommit',
status: await this.dataSource.mergeCommit(msg.repo, msg.commitHash, msg.createNewCommit)
status: await this.dataSource.mergeCommit(msg.repo, msg.commitHash, msg.createNewCommit, msg.squash)
});
break;
case 'pushTag':
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ export interface RequestMergeBranch {
repo: string;
branchName: string;
createNewCommit: boolean;
squash: boolean;
}
export interface ResponseMergeBranch {
command: 'mergeBranch';
Expand All @@ -267,6 +268,7 @@ export interface RequestMergeCommit {
repo: string;
commitHash: string;
createNewCommit: boolean;
squash: boolean;
}
export interface ResponseMergeCommit {
command: 'mergeCommit';
Expand Down
36 changes: 28 additions & 8 deletions web/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,8 +399,12 @@ class GitGraphView {
{
title: 'Merge into current branch' + ELLIPSIS,
onClick: () => {
showCheckboxDialog('Are you sure you want to merge commit <b><i>' + abbrevCommit(hash) + '</i></b> into the current branch?', 'Create a new commit even if fast-forward is possible', true, 'Yes, merge', (createNewCommit) => {
sendMessage({ command: 'mergeCommit', repo: this.currentRepo, commitHash: hash, createNewCommit: createNewCommit });
showFormDialog('Are you sure you want to merge commit <b><i>' + abbrevCommit(hash) + '</i></b> into the current branch?', [
{ type: 'checkbox', name: 'Create a new commit even if fast-forward is possible', value: true },
{ type: 'checkbox', name: 'Squash commits', value: false }
], 'Yes, merge', values => {
showActionRunningDialog('Merging Commit');
sendMessage({ command: 'mergeCommit', repo: this.currentRepo, commitHash: hash, createNewCommit: values[0] === 'checked', squash: values[1] === 'checked' });
}, null);
}
},
Expand Down Expand Up @@ -484,8 +488,12 @@ class GitGraphView {
}, {
title: 'Merge into current branch' + ELLIPSIS,
onClick: () => {
showCheckboxDialog('Are you sure you want to merge branch <b><i>' + escapeHtml(refName) + '</i></b> into the current branch?', 'Create a new commit even if fast-forward is possible', true, 'Yes, merge', (createNewCommit) => {
sendMessage({ command: 'mergeBranch', repo: this.currentRepo, branchName: refName, createNewCommit: createNewCommit });
showFormDialog('Are you sure you want to merge branch <b><i>' + escapeHtml(refName) + '</i></b> into the current branch?', [
{ type: 'checkbox', name: 'Create a new commit even if fast-forward is possible', value: true },
{ type: 'checkbox', name: 'Squash commits', value: false }
], 'Yes, merge', values => {
showActionRunningDialog('Merging Branch');
sendMessage({ command: 'mergeBranch', repo: this.currentRepo, branchName: refName, createNewCommit: values[0] === 'checked', squash: values[1] === 'checked' });
}, null);
}
}
Expand Down Expand Up @@ -1030,26 +1038,38 @@ function showSelectDialog(message: string, defaultValue: string, options: { name
showFormDialog(message, [{ type: 'select', name: '', options: options, default: defaultValue }], actionName, values => actioned(values[0]), sourceElem);
}
function showFormDialog(message: string, inputs: DialogInput[], actionName: string, actioned: (values: string[]) => void, sourceElem: HTMLElement | null) {
let textRefInput = -1, multiElementForm = inputs.length > 1;
let html = message + '<br><table class="dialogForm ' + (multiElementForm ? 'multi' : 'single') + '">';
let textRefInput = -1, multiElement = inputs.length > 1;
let multiCheckbox = multiElement;

if (multiElement) { // If has multiple elements, then check if they are all checkboxes. If so, then the form is a checkbox multi
for (let i = 0; i < inputs.length; i++) {
if (inputs[i].type !== 'checkbox') {
multiCheckbox = false;
break;
}
}
}

let html = message + '<br><table class="dialogForm ' + (multiElement ? multiCheckbox ? 'multiCheckbox' : 'multi' : 'single') + '">';
for (let i = 0; i < inputs.length; i++) {
let input = inputs[i];
html += '<tr>' + (multiElementForm ? '<td>' + input.name + '</td>' : '') + '<td>';
html += '<tr>' + (multiElement && !multiCheckbox ? '<td>' + input.name + '</td>' : '') + '<td>';
if (input.type === 'select') {
html += '<select id="dialogInput' + i + '">';
for (let j = 0; j < input.options.length; j++) {
html += '<option value="' + input.options[j].value + '"' + (input.options[j].value === input.default ? ' selected' : '') + '>' + input.options[j].name + '</option>';
}
html += '</select>';
} else if (input.type === 'checkbox') {
html += '<span class="dialogFormCheckbox"><label><input id="dialogInput' + i + '" type="checkbox"' + (input.value ? ' checked' : '') + '/>' + (multiElementForm ? '' : input.name) + '</label></span>';
html += '<span class="dialogFormCheckbox"><label><input id="dialogInput' + i + '" type="checkbox"' + (input.value ? ' checked' : '') + '/>' + (multiElement && !multiCheckbox ? '' : input.name) + '</label></span>';
} else {
html += '<input id="dialogInput' + i + '" type="text" value="' + input.default + '"' + (input.type === 'text' && input.placeholder !== null ? ' placeholder="' + input.placeholder + '"' : '') + '/>';
if (input.type === 'text-ref') textRefInput = i;
}
html += '</td></tr>';
}
html += '</table>';

showDialog(html, actionName, 'Cancel', () => {
if (dialog.className === 'active noInput' || dialog.className === 'active inputInvalid') return;
let values = [];
Expand Down

0 comments on commit e72f144

Please sign in to comment.