Skip to content

Commit e4a0c67

Browse files
LaksVisterhansu
authored andcommitted
feat: add checkbox 'Allow unrelated histories' when merge action
1 parent acd0884 commit e4a0c67

File tree

9 files changed

+51
-20
lines changed

9 files changed

+51
-20
lines changed

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,11 @@
639639
"default": true,
640640
"description": "Default state of the \"Create a new commit even if fast-forward is possible\" checkbox."
641641
},
642+
"git-graph.dialog.merge.allowUnrelatedHistories": {
643+
"type": "boolean",
644+
"default": false,
645+
"description": "Default state of the \"Allow unrelated histories\" checkbox."
646+
},
642647
"git-graph.dialog.merge.squashCommits": {
643648
"type": "boolean",
644649
"default": false,

src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ class Config {
220220
merge: {
221221
noCommit: !!this.config.get('dialog.merge.noCommit', false),
222222
noFastForward: !!this.config.get('dialog.merge.noFastForward', true),
223+
allowUnrelatedHistories: !!this.config.get('dialog.merge.allowUnrelatedHistories', false),
223224
squash: !!this.config.get('dialog.merge.squashCommits', false)
224225
},
225226
popStash: {

src/dataSource.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1021,7 +1021,7 @@ export class DataSource extends Disposable {
10211021
* @param noCommit Is `--no-commit` enabled.
10221022
* @returns The ErrorInfo from the executed command.
10231023
*/
1024-
public merge(repo: string, obj: string, actionOn: MergeActionOn, createNewCommit: boolean, squash: boolean, noCommit: boolean) {
1024+
public merge(repo: string, obj: string, actionOn: MergeActionOn, createNewCommit: boolean, allowUnrelatedHistories: boolean, squash: boolean, noCommit: boolean) {
10251025
const args = ['merge', obj], config = getConfig();
10261026
if (squash) {
10271027
args.push('--squash');
@@ -1034,6 +1034,9 @@ export class DataSource extends Disposable {
10341034
if (config.signCommits) {
10351035
args.push('-S');
10361036
}
1037+
if (allowUnrelatedHistories) {
1038+
args.push('--allow-unrelated-histories');
1039+
}
10371040
return this.runGitCommand(args, repo).then((mergeStatus) => {
10381041
return mergeStatus === null && squash && !noCommit
10391042
? this.commitSquashIfStagedChangesExist(repo, obj, actionOn, config.squashMergeMessageFormat, config.signCommits)

src/gitGraphView.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ export class GitGraphView extends Disposable {
449449
this.sendMessage({
450450
command: 'merge',
451451
actionOn: msg.actionOn,
452-
error: await this.dataSource.merge(msg.repo, msg.obj, msg.actionOn, msg.createNewCommit, msg.squash, msg.noCommit)
452+
error: await this.dataSource.merge(msg.repo, msg.obj, msg.actionOn, msg.createNewCommit, msg.allowUnrelatedHistories, msg.squash, msg.noCommit)
453453
});
454454
break;
455455
case 'openExtensionSettings':

src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,7 @@ export interface DialogDefaults {
497497
readonly merge: {
498498
readonly noCommit: boolean,
499499
readonly noFastForward: boolean,
500+
readonly allowUnrelatedHistories: boolean,
500501
readonly squash: boolean
501502
};
502503
readonly popStash: {
@@ -986,6 +987,7 @@ export interface RequestMerge extends RepoRequest {
986987
readonly obj: string;
987988
readonly actionOn: MergeActionOn;
988989
readonly createNewCommit: boolean;
990+
readonly allowUnrelatedHistories: boolean;
989991
readonly squash: boolean;
990992
readonly noCommit: boolean;
991993
}

tests/config.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,7 @@ describe('Config', () => {
857857
'dialog.fetchRemote.pruneTags',
858858
'dialog.merge.noCommit',
859859
'dialog.merge.noFastForward',
860+
'dialog.merge.allowUnrelatedHistories',
860861
'dialog.merge.squashCommits',
861862
'dialog.popStash.reinstateIndex',
862863
'dialog.pullBranch.noFastForward',
@@ -883,6 +884,7 @@ describe('Config', () => {
883884
expect(workspaceConfiguration.get).toBeCalledWith('dialog.general.referenceInputSpaceSubstitution', 'None');
884885
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.noCommit', false);
885886
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.noFastForward', true);
887+
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.allowUnrelatedHistories', false);
886888
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.squashCommits', false);
887889
expect(workspaceConfiguration.get).toBeCalledWith('dialog.popStash.reinstateIndex', false);
888890
expect(workspaceConfiguration.get).toBeCalledWith('dialog.pullBranch.noFastForward', false);
@@ -923,6 +925,7 @@ describe('Config', () => {
923925
merge: {
924926
noCommit: true,
925927
noFastForward: true,
928+
allowUnrelatedHistories: true,
926929
squash: true
927930
},
928931
popStash: {
@@ -962,6 +965,7 @@ describe('Config', () => {
962965
'dialog.fetchRemote.pruneTags',
963966
'dialog.merge.noCommit',
964967
'dialog.merge.noFastForward',
968+
'dialog.merge.allowUnrelatedHistories',
965969
'dialog.merge.squashCommits',
966970
'dialog.popStash.reinstateIndex',
967971
'dialog.pullBranch.noFastForward',
@@ -988,6 +992,7 @@ describe('Config', () => {
988992
expect(workspaceConfiguration.get).toBeCalledWith('dialog.general.referenceInputSpaceSubstitution', 'None');
989993
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.noCommit', false);
990994
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.noFastForward', true);
995+
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.allowUnrelatedHistories', false);
991996
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.squashCommits', false);
992997
expect(workspaceConfiguration.get).toBeCalledWith('dialog.popStash.reinstateIndex', false);
993998
expect(workspaceConfiguration.get).toBeCalledWith('dialog.pullBranch.noFastForward', false);
@@ -1028,6 +1033,7 @@ describe('Config', () => {
10281033
merge: {
10291034
noCommit: false,
10301035
noFastForward: false,
1036+
allowUnrelatedHistories: false,
10311037
squash: false
10321038
},
10331039
popStash: {
@@ -1067,6 +1073,7 @@ describe('Config', () => {
10671073
'dialog.fetchRemote.pruneTags',
10681074
'dialog.merge.noCommit',
10691075
'dialog.merge.noFastForward',
1076+
'dialog.merge.allowUnrelatedHistories',
10701077
'dialog.merge.squashCommits',
10711078
'dialog.popStash.reinstateIndex',
10721079
'dialog.pullBranch.noFastForward',
@@ -1093,6 +1100,7 @@ describe('Config', () => {
10931100
expect(workspaceConfiguration.get).toBeCalledWith('dialog.general.referenceInputSpaceSubstitution', 'None');
10941101
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.noCommit', false);
10951102
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.noFastForward', true);
1103+
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.allowUnrelatedHistories', false);
10961104
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.squashCommits', false);
10971105
expect(workspaceConfiguration.get).toBeCalledWith('dialog.popStash.reinstateIndex', false);
10981106
expect(workspaceConfiguration.get).toBeCalledWith('dialog.pullBranch.noFastForward', false);
@@ -1133,6 +1141,7 @@ describe('Config', () => {
11331141
merge: {
11341142
noCommit: true,
11351143
noFastForward: true,
1144+
allowUnrelatedHistories: true,
11361145
squash: true
11371146
},
11381147
popStash: {
@@ -1172,6 +1181,7 @@ describe('Config', () => {
11721181
'dialog.fetchRemote.pruneTags',
11731182
'dialog.merge.noCommit',
11741183
'dialog.merge.noFastForward',
1184+
'dialog.merge.allowUnrelatedHistories',
11751185
'dialog.merge.squashCommits',
11761186
'dialog.popStash.reinstateIndex',
11771187
'dialog.pullBranch.noFastForward',
@@ -1198,6 +1208,7 @@ describe('Config', () => {
11981208
expect(workspaceConfiguration.get).toBeCalledWith('dialog.general.referenceInputSpaceSubstitution', 'None');
11991209
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.noCommit', false);
12001210
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.noFastForward', true);
1211+
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.allowUnrelatedHistories', false);
12011212
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.squashCommits', false);
12021213
expect(workspaceConfiguration.get).toBeCalledWith('dialog.popStash.reinstateIndex', false);
12031214
expect(workspaceConfiguration.get).toBeCalledWith('dialog.pullBranch.noFastForward', false);
@@ -1238,6 +1249,7 @@ describe('Config', () => {
12381249
merge: {
12391250
noCommit: false,
12401251
noFastForward: false,
1252+
allowUnrelatedHistories: false,
12411253
squash: false
12421254
},
12431255
popStash: {
@@ -1288,6 +1300,7 @@ describe('Config', () => {
12881300
expect(workspaceConfiguration.get).toBeCalledWith('dialog.general.referenceInputSpaceSubstitution', 'None');
12891301
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.noCommit', false);
12901302
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.noFastForward', true);
1303+
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.allowUnrelatedHistories', false);
12911304
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.squashCommits', false);
12921305
expect(workspaceConfiguration.get).toBeCalledWith('dialog.popStash.reinstateIndex', false);
12931306
expect(workspaceConfiguration.get).toBeCalledWith('dialog.pullBranch.noFastForward', false);
@@ -1328,6 +1341,7 @@ describe('Config', () => {
13281341
merge: {
13291342
noCommit: false,
13301343
noFastForward: true,
1344+
allowUnrelatedHistories: false,
13311345
squash: false
13321346
},
13331347
popStash: {
@@ -1371,6 +1385,7 @@ describe('Config', () => {
13711385
expect(workspaceConfiguration.get).toBeCalledWith('dialog.general.referenceInputSpaceSubstitution', 'None');
13721386
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.noCommit', false);
13731387
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.noFastForward', true);
1388+
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.allowUnrelatedHistories', false);
13741389
expect(workspaceConfiguration.get).toBeCalledWith('dialog.merge.squashCommits', false);
13751390
expect(workspaceConfiguration.get).toBeCalledWith('dialog.popStash.reinstateIndex', false);
13761391
expect(workspaceConfiguration.get).toBeCalledWith('dialog.pullBranch.noFastForward', false);
@@ -1411,6 +1426,7 @@ describe('Config', () => {
14111426
merge: {
14121427
noCommit: false,
14131428
noFastForward: true,
1429+
allowUnrelatedHistories: false,
14141430
squash: false
14151431
},
14161432
popStash: {

tests/dataSource.test.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5627,7 +5627,7 @@ describe('DataSource', () => {
56275627
vscode.mockExtensionSettingReturnValue('repository.sign.commits', false);
56285628

56295629
// Run
5630-
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, false, false);
5630+
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, false, false, false);
56315631

56325632
// Assert
56335633
expect(result).toBe(null);
@@ -5641,7 +5641,7 @@ describe('DataSource', () => {
56415641
vscode.mockExtensionSettingReturnValue('repository.sign.commits', false);
56425642

56435643
// Run
5644-
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, true, false, false);
5644+
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, true, false, false, false);
56455645

56465646
// Assert
56475647
expect(result).toBe(null);
@@ -5655,7 +5655,7 @@ describe('DataSource', () => {
56555655
vscode.mockExtensionSettingReturnValue('repository.sign.commits', true);
56565656

56575657
// Run
5658-
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, true, false, false);
5658+
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, true, false, false, false);
56595659

56605660
// Assert
56615661
expect(result).toBe(null);
@@ -5672,7 +5672,7 @@ describe('DataSource', () => {
56725672
vscode.mockExtensionSettingReturnValue('dialog.merge.squashMessageFormat', 'Default');
56735673

56745674
// Run
5675-
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, true, false);
5675+
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, false, true, false);
56765676

56775677
// Assert
56785678
expect(result).toBe(null);
@@ -5693,7 +5693,7 @@ describe('DataSource', () => {
56935693
vscode.mockExtensionSettingReturnValue('dialog.merge.squashMessageFormat', 'Default');
56945694

56955695
// Run
5696-
const result = await dataSource.merge('/path/to/repo', 'origin/develop', MergeActionOn.RemoteTrackingBranch, false, true, false);
5696+
const result = await dataSource.merge('/path/to/repo', 'origin/develop', MergeActionOn.RemoteTrackingBranch, false, false, true, false);
56975697

56985698
// Assert
56995699
expect(result).toBe(null);
@@ -5712,7 +5712,7 @@ describe('DataSource', () => {
57125712
vscode.mockExtensionSettingReturnValue('dialog.merge.squashMessageFormat', 'Default');
57135713

57145714
// Run
5715-
const result = await dataSource.merge('/path/to/repo', '1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b', MergeActionOn.Commit, false, true, false);
5715+
const result = await dataSource.merge('/path/to/repo', '1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b', MergeActionOn.Commit, false, false, true, false);
57165716

57175717
// Assert
57185718
expect(result).toBe(null);
@@ -5731,7 +5731,7 @@ describe('DataSource', () => {
57315731
vscode.mockExtensionSettingReturnValue('dialog.merge.squashMessageFormat', 'Default');
57325732

57335733
// Run
5734-
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, true, false);
5734+
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, false, true, false);
57355735

57365736
// Assert
57375737
expect(result).toBe(null);
@@ -5752,7 +5752,7 @@ describe('DataSource', () => {
57525752
vscode.mockExtensionSettingReturnValue('dialog.merge.squashMessageFormat', 'Git SQUASH_MSG');
57535753

57545754
// Run
5755-
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, true, false);
5755+
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, false, true, false);
57565756

57575757
// Assert
57585758
expect(result).toBe(null);
@@ -5769,7 +5769,7 @@ describe('DataSource', () => {
57695769
vscode.mockExtensionSettingReturnValue('repository.sign.commits', false);
57705770

57715771
// Run
5772-
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, true, false);
5772+
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, false, true, false);
57735773

57745774
// Assert
57755775
expect(result).toBe(null);
@@ -5784,7 +5784,7 @@ describe('DataSource', () => {
57845784
vscode.mockExtensionSettingReturnValue('repository.sign.commits', false);
57855785

57865786
// Run
5787-
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, false, true);
5787+
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, false, false, true);
57885788

57895789
// Assert
57905790
expect(result).toBe(null);
@@ -5798,7 +5798,7 @@ describe('DataSource', () => {
57985798
vscode.mockExtensionSettingReturnValue('repository.sign.commits', false);
57995799

58005800
// Run
5801-
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, true, true);
5801+
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, false, true, true);
58025802

58035803
// Assert
58045804
expect(result).toBe(null);
@@ -5812,7 +5812,7 @@ describe('DataSource', () => {
58125812
vscode.mockExtensionSettingReturnValue('repository.sign.commits', false);
58135813

58145814
// Run
5815-
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, true, true, true);
5815+
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, true, false, true, true);
58165816

58175817
// Assert
58185818
expect(result).toBe(null);
@@ -5826,7 +5826,7 @@ describe('DataSource', () => {
58265826
vscode.mockExtensionSettingReturnValue('repository.sign.commits', false);
58275827

58285828
// Run
5829-
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, true, false);
5829+
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, false, true, false);
58305830

58315831
// Assert
58325832
expect(result).toBe('error message');
@@ -5841,7 +5841,7 @@ describe('DataSource', () => {
58415841
vscode.mockExtensionSettingReturnValue('repository.sign.commits', false);
58425842

58435843
// Run
5844-
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, true, false);
5844+
const result = await dataSource.merge('/path/to/repo', 'develop', MergeActionOn.Branch, false, false, true, false);
58455845

58465846
// Assert
58475847
expect(result).toBe('error message');

tests/gitGraphView.test.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2624,13 +2624,14 @@ describe('GitGraphView', () => {
26242624
obj: 'master',
26252625
actionOn: MergeActionOn.Branch,
26262626
createNewCommit: true,
2627+
allowUnrelatedHistories: false,
26272628
squash: false,
26282629
noCommit: false
26292630
});
26302631

26312632
// Assert
26322633
await waitForExpect(() => {
2633-
expect(spyOnMerge).toHaveBeenCalledWith('/path/to/repo', 'master', MergeActionOn.Branch, true, false, false);
2634+
expect(spyOnMerge).toHaveBeenCalledWith('/path/to/repo', 'master', MergeActionOn.Branch, true, false, false, false);
26342635
expect(messages).toStrictEqual([
26352636
{
26362637
command: 'merge',
@@ -2654,13 +2655,14 @@ describe('GitGraphView', () => {
26542655
obj: 'master',
26552656
actionOn: MergeActionOn.Branch,
26562657
createNewCommit: false,
2658+
allowUnrelatedHistories: false,
26572659
squash: true,
26582660
noCommit: false
26592661
});
26602662

26612663
// Assert
26622664
await waitForExpect(() => {
2663-
expect(spyOnMerge).toHaveBeenCalledWith('/path/to/repo', 'master', MergeActionOn.Branch, false, true, false);
2665+
expect(spyOnMerge).toHaveBeenCalledWith('/path/to/repo', 'master', MergeActionOn.Branch, false, false, true, false);
26642666
expect(messages).toStrictEqual([
26652667
{
26662668
command: 'merge',
@@ -2684,13 +2686,14 @@ describe('GitGraphView', () => {
26842686
obj: 'master',
26852687
actionOn: MergeActionOn.Branch,
26862688
createNewCommit: false,
2689+
allowUnrelatedHistories: false,
26872690
squash: false,
26882691
noCommit: true
26892692
});
26902693

26912694
// Assert
26922695
await waitForExpect(() => {
2693-
expect(spyOnMerge).toHaveBeenCalledWith('/path/to/repo', 'master', MergeActionOn.Branch, false, false, true);
2696+
expect(spyOnMerge).toHaveBeenCalledWith('/path/to/repo', 'master', MergeActionOn.Branch, false, false, false, true);
26942697
expect(messages).toStrictEqual([
26952698
{
26962699
command: 'merge',

web/main.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1739,10 +1739,11 @@ class GitGraphView {
17391739
private mergeAction(obj: string, name: string, actionOn: GG.MergeActionOn, target: DialogTarget & (CommitTarget | RefTarget)) {
17401740
dialog.showForm('Are you sure you want to merge ' + actionOn.toLowerCase() + ' <b><i>' + escapeHtml(name) + '</i></b> into ' + (this.gitBranchHead !== null ? '<b><i>' + escapeHtml(this.gitBranchHead) + '</i></b> (the current branch)' : 'the current branch') + '?', [
17411741
{ type: DialogInputType.Checkbox, name: 'Create a new commit even if fast-forward is possible', value: this.config.dialogDefaults.merge.noFastForward },
1742+
{ type: DialogInputType.Checkbox, name: 'Allow unrelated histories', value: this.config.dialogDefaults.merge.allowUnrelatedHistories, info: 'Allow merging branches from two completely different repositories or branches.' },
17421743
{ type: DialogInputType.Checkbox, name: 'Squash Commits', value: this.config.dialogDefaults.merge.squash, info: 'Create a single commit on the current branch whose effect is the same as merging this ' + actionOn.toLowerCase() + '.' },
17431744
{ type: DialogInputType.Checkbox, name: 'No Commit', value: this.config.dialogDefaults.merge.noCommit, info: 'The changes of the merge will be staged but not committed, so that you can review and/or modify the merge result before committing.' }
17441745
], 'Yes, merge', (values) => {
1745-
runAction({ command: 'merge', repo: this.currentRepo, obj: obj, actionOn: actionOn, createNewCommit: <boolean>values[0], squash: <boolean>values[1], noCommit: <boolean>values[2] }, 'Merging ' + actionOn);
1746+
runAction({ command: 'merge', repo: this.currentRepo, obj: obj, actionOn: actionOn, createNewCommit: <boolean>values[0], allowUnrelatedHistories: <boolean>values[1], squash: <boolean>values[2], noCommit: <boolean>values[3] }, 'Merging ' + actionOn);
17461747
}, target);
17471748
}
17481749

0 commit comments

Comments
 (0)