Skip to content

Commit f5a5a4e

Browse files
committed
Add AI-powered explanation for unpushed branch changes.
(#4443, #4522)
1 parent 9c04c31 commit f5a5a4e

File tree

6 files changed

+72
-13
lines changed

6 files changed

+72
-13
lines changed

contributions.json

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
}
2525
},
2626
"gitlens.ai.aiRebaseBranch:graph": {
27-
"label": "AI Recompose branch commits (Preview)...",
27+
"label": "AI Recompose Branch Commits (Preview)",
2828
"icon": "$(sparkle)",
2929
"menus": {
3030
"webview/context": [
@@ -37,7 +37,7 @@
3737
}
3838
},
3939
"gitlens.ai.aiRebaseUnpushed:graph": {
40-
"label": "AI Recompose unpushed commits (Preview)...",
40+
"label": "AI Recompose Unpushed Commits (Preview)",
4141
"icon": "$(sparkle)",
4242
"menus": {
4343
"webview/context": [
@@ -139,6 +139,19 @@
139139
]
140140
}
141141
},
142+
"gitlens.ai.explainUnpushed:graph": {
143+
"label": "Explain Unpushed Changes (Preview)",
144+
"icon": "$(sparkle)",
145+
"menus": {
146+
"webview/context": [
147+
{
148+
"when": "webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+ahead\\b)/ && !listMultiSelection && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled",
149+
"group": "1_gitlens_actions_4",
150+
"order": 102
151+
}
152+
]
153+
}
154+
},
142155
"gitlens.ai.explainWip": {
143156
"label": "Explain Working Changes (Preview)...",
144157
"commandPalette": "gitlens:enabled && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled"

docs/telemetry-events.md

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

package.json

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6149,12 +6149,12 @@
61496149
},
61506150
{
61516151
"command": "gitlens.ai.aiRebaseBranch:graph",
6152-
"title": "AI Recompose branch commits (Preview)...",
6152+
"title": "AI Recompose Branch Commits (Preview)",
61536153
"icon": "$(sparkle)"
61546154
},
61556155
{
61566156
"command": "gitlens.ai.aiRebaseUnpushed:graph",
6157-
"title": "AI Recompose unpushed commits (Preview)...",
6157+
"title": "AI Recompose Unpushed Commits (Preview)",
61586158
"icon": "$(sparkle)"
61596159
},
61606160
{
@@ -6202,6 +6202,11 @@
62026202
"title": "Explain Changes (Preview)",
62036203
"icon": "$(sparkle)"
62046204
},
6205+
{
6206+
"command": "gitlens.ai.explainUnpushed:graph",
6207+
"title": "Explain Unpushed Changes (Preview)",
6208+
"icon": "$(sparkle)"
6209+
},
62056210
{
62066211
"command": "gitlens.ai.explainWip",
62076212
"title": "Explain Working Changes (Preview)...",
@@ -10850,6 +10855,10 @@
1085010855
"command": "gitlens.ai.explainStash:views",
1085110856
"when": "false"
1085210857
},
10858+
{
10859+
"command": "gitlens.ai.explainUnpushed:graph",
10860+
"when": "false"
10861+
},
1085310862
{
1085410863
"command": "gitlens.ai.explainWip",
1085510864
"when": "gitlens:enabled && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled"
@@ -22935,6 +22944,11 @@
2293522944
"when": "webviewItem =~ /gitlens:branch\\b/ && !listMultiSelection && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled",
2293622945
"group": "1_gitlens_actions_4@100"
2293722946
},
22947+
{
22948+
"command": "gitlens.ai.explainUnpushed:graph",
22949+
"when": "webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+ahead\\b)/ && !listMultiSelection && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled",
22950+
"group": "1_gitlens_actions_4@102"
22951+
},
2293822952
{
2293922953
"command": "gitlens.graph.openBranchOnRemote",
2294022954
"when": "webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+(tracking|remote)\\b)/ && gitlens:repos:withRemotes",

src/commands/explainBranch.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { ExplainCommandBase } from './explainBase';
1616

1717
export interface ExplainBranchCommandArgs extends ExplainBaseArgs {
1818
ref?: string;
19+
baseBranch?: string;
1920
}
2021

2122
@command()
@@ -67,15 +68,25 @@ export class ExplainBranchCommand extends ExplainCommandBase {
6768
}
6869

6970
// Clarifying the base branch
70-
const baseBranchNameResult = await getBranchMergeTargetName(this.container, branch);
7171
let baseBranch;
72-
if (!baseBranchNameResult.paused) {
73-
baseBranch = await svc.branches.getBranch(baseBranchNameResult.value);
74-
}
75-
76-
if (!baseBranch) {
77-
void showGenericErrorMessage(`Unable to find the base branch for branch ${branch.name}.`);
78-
return;
72+
if (args.baseBranch) {
73+
// Use the provided base branch
74+
baseBranch = await svc.branches.getBranch(args.baseBranch);
75+
if (!baseBranch) {
76+
void showGenericErrorMessage(`Unable to find the specified base branch: ${args.baseBranch}`);
77+
return;
78+
}
79+
} else {
80+
// Fall back to automatic merge target detection
81+
const baseBranchNameResult = await getBranchMergeTargetName(this.container, branch);
82+
if (!baseBranchNameResult.paused) {
83+
baseBranch = await svc.branches.getBranch(baseBranchNameResult.value);
84+
}
85+
86+
if (!baseBranch) {
87+
void showGenericErrorMessage(`Unable to find the base branch for branch ${branch.name}.`);
88+
return;
89+
}
7990
}
8091

8192
// Get the diff between the branch and its upstream or base

src/constants.commands.generated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export type ContributedCommands =
1212
| 'gitlens.ai.explainCommit:views'
1313
| 'gitlens.ai.explainStash:graph'
1414
| 'gitlens.ai.explainStash:views'
15+
| 'gitlens.ai.explainUnpushed:graph'
1516
| 'gitlens.ai.explainWip:graph'
1617
| 'gitlens.ai.explainWip:views'
1718
| 'gitlens.ai.feedback.helpful'

src/webviews/plus/graph/graphWebview.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,7 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
700700
this.copyWorkingChangesToWorktree,
701701
),
702702
this.host.registerWebviewCommand('gitlens.ai.generateCommitMessage:graph', this.generateCommitMessage),
703+
this.host.registerWebviewCommand('gitlens.ai.explainUnpushed:graph', this.aiExplainUnpushed),
703704
this.host.registerWebviewCommand('gitlens.ai.explainBranch:graph', this.explainBranch),
704705
this.host.registerWebviewCommand('gitlens.ai.explainCommit:graph', this.explainCommit),
705706
this.host.registerWebviewCommand('gitlens.ai.explainStash:graph', this.explainStash),
@@ -3893,6 +3894,25 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
38933894
});
38943895
}
38953896

3897+
@log()
3898+
private aiExplainUnpushed(item?: GraphItemContext) {
3899+
if (isGraphItemRefContext(item, 'branch')) {
3900+
const { ref } = item.webviewItemValue;
3901+
3902+
if (!ref.upstream) {
3903+
return Promise.resolve();
3904+
}
3905+
3906+
return executeCommand<ExplainBranchCommandArgs>('gitlens.ai.explainBranch', {
3907+
repoPath: ref.repoPath,
3908+
ref: ref.ref,
3909+
baseBranch: ref.upstream.name,
3910+
source: { source: 'graph', type: 'branch' },
3911+
});
3912+
}
3913+
3914+
return Promise.resolve();
3915+
}
38963916
@log()
38973917
private explainBranch(item?: GraphItemContext) {
38983918
const ref = this.getGraphItemRef(item, 'branch');

0 commit comments

Comments
 (0)