Skip to content

Commit bab40d4

Browse files
authored
Closes #3313 adds first parent toggle to Graph (#3345)
1 parent 9adf318 commit bab40d4

File tree

7 files changed

+76
-65
lines changed

7 files changed

+76
-65
lines changed

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2824,6 +2824,12 @@
28242824
"scope": "window",
28252825
"order": 30
28262826
},
2827+
"gitlens.graph.onlyFollowFirstParent": {
2828+
"type": "boolean",
2829+
"default": false,
2830+
"markdownDescription": "Specifies whether to only follow the first parent when showing commits on the _Commit Graph_",
2831+
"order": 31
2832+
},
28272833
"gitlens.graph.dateStyle": {
28282834
"type": [
28292835
"string",

src/config.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -377,27 +377,28 @@ export interface GraphConfig {
377377
readonly dateStyle: DateStyle | null;
378378
readonly defaultItemLimit: number;
379379
readonly dimMergeCommits: boolean;
380+
readonly highlightRowsOnRefHover: boolean;
381+
readonly layout: 'editor' | 'panel';
380382
readonly minimap: {
381383
readonly enabled: boolean;
382384
readonly dataType: 'commits' | 'lines';
383385
readonly additionalTypes: GraphMinimapMarkersAdditionalTypes[];
384386
};
385-
readonly highlightRowsOnRefHover: boolean;
386-
readonly layout: 'editor' | 'panel';
387-
readonly scrollRowPadding: number;
388-
readonly showDetailsView: 'open' | 'selection' | false;
389-
readonly showGhostRefsOnRowHover: boolean;
390-
readonly scrollMarkers: {
387+
readonly onlyFollowFirstParent: boolean;
388+
readonly pageItemLimit: number;
389+
readonly pullRequests: {
391390
readonly enabled: boolean;
392-
readonly additionalTypes: GraphScrollMarkersAdditionalTypes[];
393391
};
394-
readonly pullRequests: {
392+
readonly scrollMarkers: {
395393
readonly enabled: boolean;
394+
readonly additionalTypes: GraphScrollMarkersAdditionalTypes[];
396395
};
396+
readonly scrollRowPadding: number;
397+
readonly searchItemLimit: number;
398+
readonly showDetailsView: 'open' | 'selection' | false;
399+
readonly showGhostRefsOnRowHover: boolean;
397400
readonly showRemoteNames: boolean;
398401
readonly showUpstreamStatus: boolean;
399-
readonly pageItemLimit: number;
400-
readonly searchItemLimit: number;
401402
readonly statusBar: {
402403
readonly enabled: boolean;
403404
};

src/env/node/git/localGitProvider.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2306,6 +2306,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
23062306
const defaultLimit = options?.limit ?? configuration.get('graph.defaultItemLimit') ?? 5000;
23072307
const defaultPageLimit = configuration.get('graph.pageItemLimit') ?? 1000;
23082308
const ordering = configuration.get('graph.commitOrdering', undefined, 'date');
2309+
const onlyFollowFirstParent = configuration.get('graph.onlyFollowFirstParent', undefined, false);
23092310

23102311
const deferStats = options?.include?.stats; // && defaultLimit > 1000;
23112312

@@ -2370,6 +2371,9 @@ export class LocalGitProvider implements GitProvider, Disposable {
23702371

23712372
do {
23722373
const args = [...parser.arguments, `--${ordering}-order`, '--all'];
2374+
if (onlyFollowFirstParent) {
2375+
args.push('--first-parent');
2376+
}
23732377
if (cursor?.skip) {
23742378
args.push(`--skip=${cursor.skip}`);
23752379
}
@@ -2724,7 +2728,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
27242728

27252729
rows.push({
27262730
sha: commit.sha,
2727-
parents: parents,
2731+
parents: onlyFollowFirstParent ? [parents[0]] : parents,
27282732
author: isCurrentUser ? 'You' : commit.author,
27292733
email: commit.authorEmail,
27302734
date: Number(ordering === 'author-date' ? commit.authorDate : commit.committerDate) * 1000,

src/plus/webviews/graph/graphWebview.ts

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ import type {
131131
SearchParams,
132132
State,
133133
UpdateColumnsParams,
134-
UpdateDimMergeCommitsParams,
135134
UpdateExcludeTypeParams,
136135
UpdateGraphConfigurationParams,
137136
UpdateRefsVisibilityParams,
@@ -163,7 +162,6 @@ import {
163162
SearchRequest,
164163
supportedRefMetadataTypes,
165164
UpdateColumnsCommand,
166-
UpdateDimMergeCommitsCommand,
167165
UpdateExcludeTypeCommand,
168166
UpdateGraphConfigurationCommand,
169167
UpdateIncludeOnlyRefsCommand,
@@ -616,9 +614,6 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
616614
case ChooseRepositoryCommand.is(e):
617615
void this.onChooseRepository();
618616
break;
619-
case UpdateDimMergeCommitsCommand.is(e):
620-
this.dimMergeCommits(e.params);
621-
break;
622617
case DoubleClickedCommandType.is(e):
623618
void this.onDoubleClick(e.params);
624619
break;
@@ -694,6 +689,12 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
694689
void configuration.updateEffective('graph.minimap.additionalTypes', additionalTypes);
695690
break;
696691
}
692+
case 'dimMergeCommits':
693+
void configuration.updateEffective('graph.dimMergeCommits', params.changes[key]);
694+
break;
695+
case 'onlyFollowFirstParent':
696+
void configuration.updateEffective('graph.onlyFollowFirstParent', params.changes[key]);
697+
break;
697698
default:
698699
// TODO:@eamodio add more config options as needed
699700
debugger;
@@ -748,30 +749,17 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
748749
configuration.changed(e, 'defaultDateFormat') ||
749750
configuration.changed(e, 'defaultDateStyle') ||
750751
configuration.changed(e, 'advanced.abbreviatedShaLength') ||
751-
configuration.changed(e, 'graph.avatars') ||
752-
configuration.changed(e, 'graph.dateFormat') ||
753-
configuration.changed(e, 'graph.dateStyle') ||
754-
configuration.changed(e, 'graph.dimMergeCommits') ||
755-
configuration.changed(e, 'graph.highlightRowsOnRefHover') ||
756-
configuration.changed(e, 'graph.scrollRowPadding') ||
757-
configuration.changed(e, 'graph.scrollMarkers.enabled') ||
758-
configuration.changed(e, 'graph.scrollMarkers.additionalTypes') ||
759-
configuration.changed(e, 'graph.showGhostRefsOnRowHover') ||
760-
configuration.changed(e, 'graph.pullRequests.enabled') ||
761-
configuration.changed(e, 'graph.showRemoteNames') ||
762-
configuration.changed(e, 'graph.showUpstreamStatus') ||
763-
configuration.changed(e, 'graph.minimap.enabled') ||
764-
configuration.changed(e, 'graph.minimap.dataType') ||
765-
configuration.changed(e, 'graph.minimap.additionalTypes')
752+
configuration.changed(e, 'graph')
766753
) {
767754
void this.notifyDidChangeConfiguration();
768755

769756
if (
770-
(configuration.changed(e, 'graph.minimap.enabled') ||
757+
configuration.changed(e, 'graph.onlyFollowFirstParent') ||
758+
((configuration.changed(e, 'graph.minimap.enabled') ||
771759
configuration.changed(e, 'graph.minimap.dataType')) &&
772-
configuration.get('graph.minimap.enabled') &&
773-
configuration.get('graph.minimap.dataType') === 'lines' &&
774-
!this._graph?.includes?.stats
760+
configuration.get('graph.minimap.enabled') &&
761+
configuration.get('graph.minimap.dataType') === 'lines' &&
762+
!this._graph?.includes?.stats)
775763
) {
776764
this.updateState();
777765
}
@@ -833,10 +821,6 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
833821
this.updateState();
834822
}
835823

836-
private dimMergeCommits(e: UpdateDimMergeCommitsParams) {
837-
void configuration.updateEffective('graph.dimMergeCommits', e.dim);
838-
}
839-
840824
private onColumnsChanged(e: UpdateColumnsParams) {
841825
this.updateColumns(e.config);
842826
}
@@ -1846,6 +1830,7 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
18461830
minimap: configuration.get('graph.minimap.enabled'),
18471831
minimapDataType: configuration.get('graph.minimap.dataType'),
18481832
minimapMarkerTypes: this.getMinimapMarkerTypes(),
1833+
onlyFollowFirstParent: configuration.get('graph.onlyFollowFirstParent'),
18491834
scrollRowPadding: configuration.get('graph.scrollRowPadding'),
18501835
scrollMarkerTypes: this.getScrollMarkerTypes(),
18511836
showGhostRefsOnRowHover: configuration.get('graph.showGhostRefsOnRowHover'),

src/plus/webviews/graph/protocol.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ export interface GraphComponentConfig {
179179
minimap?: boolean;
180180
minimapDataType?: Config['graph']['minimap']['dataType'];
181181
minimapMarkerTypes?: GraphMinimapMarkerTypes[];
182+
onlyFollowFirstParent?: boolean;
182183
scrollMarkerTypes?: GraphScrollMarkerTypes[];
183184
scrollRowPadding?: number;
184185
showGhostRefsOnRowHover?: boolean;
@@ -262,11 +263,6 @@ export interface UpdateColumnsParams {
262263
}
263264
export const UpdateColumnsCommand = new IpcCommand<UpdateColumnsParams>(scope, 'columns/update');
264265

265-
export interface UpdateDimMergeCommitsParams {
266-
dim: boolean;
267-
}
268-
export const UpdateDimMergeCommitsCommand = new IpcCommand<UpdateDimMergeCommitsParams>(scope, 'dimMergeCommits');
269-
270266
export interface UpdateRefsVisibilityParams {
271267
refs: GraphExcludedRef[];
272268
visible: boolean;

src/webviews/apps/plus/graph/GraphWrapper.tsx

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ export interface GraphWrapperProps {
8181
subscriber: (callback: UpdateStateCallback) => () => void;
8282
onChooseRepository?: () => void;
8383
onColumnsChange?: (colsSettings: GraphColumnsConfig) => void;
84-
onDimMergeCommits?: (dim: boolean) => void;
8584
onDoubleClickRef?: (ref: GraphRef, metadata?: GraphRefMetadataItem) => void;
8685
onDoubleClickRow?: (row: GraphRow, preserveFocus?: boolean) => void;
8786
onMissingAvatars?: (emails: Record<string, string>) => void;
@@ -204,7 +203,6 @@ export function GraphWrapper({
204203
state,
205204
onChooseRepository,
206205
onColumnsChange,
207-
onDimMergeCommits,
208206
onDoubleClickRef,
209207
onDoubleClickRow,
210208
onEnsureRowPromise,
@@ -503,10 +501,11 @@ export function GraphWrapper({
503501
}, [includeOnlyRefsById]);
504502

505503
const hasFilters = useMemo(() => {
506-
if (!isAllBranches) return true;
504+
if (!isAllBranches || graphConfig?.onlyFollowFirstParent) return true;
507505
if (excludeTypes == null) return false;
506+
508507
return Object.values(excludeTypes).includes(true);
509-
}, [excludeTypes, isAllBranches, graphConfig?.dimMergeCommits]);
508+
}, [excludeTypes, isAllBranches, graphConfig?.onlyFollowFirstParent]);
510509

511510
const hasSpecialFilters = useMemo(() => {
512511
return !isAllBranches;
@@ -651,15 +650,27 @@ export function GraphWrapper({
651650
onChooseRepository?.();
652651
};
653652

654-
const handleExcludeTypeChange = (e: Event | FormEvent<HTMLElement>) => {
653+
const handleFilterChange = (e: Event | FormEvent<HTMLElement>) => {
655654
const $el = e.target as HTMLInputElement;
656655

657656
const value = $el.value;
658-
const isLocalBranches = ['branch-all', 'branch-current'].includes(value);
659-
if (!isLocalBranches && !['remotes', 'stashes', 'tags', 'mergeCommits'].includes(value)) return;
660657
const isChecked = $el.checked;
661-
if (value === 'mergeCommits') {
662-
onDimMergeCommits?.(isChecked);
658+
659+
switch (value) {
660+
case 'mergeCommits':
661+
onUpdateGraphConfiguration?.({ dimMergeCommits: isChecked });
662+
return;
663+
664+
case 'onlyFollowFirstParent':
665+
onUpdateGraphConfiguration?.({ onlyFollowFirstParent: isChecked });
666+
return;
667+
}
668+
669+
const isLocalBranches = ['branch-all', 'branch-current'].includes(value);
670+
if (
671+
!isLocalBranches &&
672+
!['remotes', 'stashes', 'tags', 'mergeCommits', 'onlyFollowFirstParent'].includes(value)
673+
) {
663674
return;
664675
}
665676

@@ -1217,7 +1228,7 @@ export function GraphWrapper({
12171228
<MenuItem role="none">
12181229
<VSCodeCheckbox
12191230
value="remotes"
1220-
onChange={handleExcludeTypeChange}
1231+
onChange={handleFilterChange}
12211232
defaultChecked={excludeTypes?.remotes ?? false}
12221233
>
12231234
Hide Remote-only Branches
@@ -1226,7 +1237,7 @@ export function GraphWrapper({
12261237
<MenuItem role="none">
12271238
<VSCodeCheckbox
12281239
value="stashes"
1229-
onChange={handleExcludeTypeChange}
1240+
onChange={handleFilterChange}
12301241
defaultChecked={excludeTypes?.stashes ?? false}
12311242
>
12321243
Hide Stashes
@@ -1237,17 +1248,33 @@ export function GraphWrapper({
12371248
<MenuItem role="none">
12381249
<VSCodeCheckbox
12391250
value="tags"
1240-
onChange={handleExcludeTypeChange}
1251+
onChange={handleFilterChange}
12411252
defaultChecked={excludeTypes?.tags ?? false}
12421253
>
12431254
Hide Tags
12441255
</VSCodeCheckbox>
12451256
</MenuItem>
12461257
<MenuDivider></MenuDivider>
1258+
{repo?.isVirtual !== true && (
1259+
<MenuItem role="none">
1260+
<GlTooltip
1261+
placement="right"
1262+
content="Only follow the first parent of merge commits to provide a more linear history"
1263+
>
1264+
<VSCodeCheckbox
1265+
value="onlyFollowFirstParent"
1266+
onChange={handleFilterChange}
1267+
defaultChecked={graphConfig?.onlyFollowFirstParent ?? false}
1268+
>
1269+
Simplify Merge History
1270+
</VSCodeCheckbox>
1271+
</GlTooltip>
1272+
</MenuItem>
1273+
)}
12471274
<MenuItem role="none">
12481275
<VSCodeCheckbox
12491276
value="mergeCommits"
1250-
onChange={handleExcludeTypeChange}
1277+
onChange={handleFilterChange}
12511278
defaultChecked={graphConfig?.dimMergeCommits ?? false}
12521279
>
12531280
Dim Merge Commit Rows

src/webviews/apps/plus/graph/graph.tsx

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ import {
4242
SearchOpenInViewCommand,
4343
SearchRequest,
4444
UpdateColumnsCommand,
45-
UpdateDimMergeCommitsCommand,
4645
UpdateExcludeTypeCommand,
4746
UpdateGraphConfigurationCommand,
4847
UpdateIncludeOnlyRefsCommand,
@@ -99,7 +98,6 @@ export class GraphApp extends App<State> {
9998
settings => this.onColumnsChanged(settings),
10099
250,
101100
)}
102-
onDimMergeCommits={dim => this.onDimMergeCommits(dim)}
103101
onRefsVisibilityChange={(refs: GraphExcludedRef[], visible: boolean) =>
104102
this.onRefsVisibilityChanged(refs, visible)
105103
}
@@ -529,12 +527,6 @@ export class GraphApp extends App<State> {
529527
this.sendCommand(ChooseRepositoryCommand, undefined);
530528
}
531529

532-
private onDimMergeCommits(dim: boolean) {
533-
this.sendCommand(UpdateDimMergeCommitsCommand, {
534-
dim: dim,
535-
});
536-
}
537-
538530
private onDoubleClickRef(ref: GraphRef, metadata?: GraphRefMetadataItem) {
539531
this.sendCommand(DoubleClickedCommandType, {
540532
type: 'ref',

0 commit comments

Comments
 (0)