Skip to content

Commit 108b981

Browse files
committed
Add AI-powered explanation for unpushed branch changes.
(#4443, #4522)
1 parent 340dfb0 commit 108b981

File tree

5 files changed

+71
-12
lines changed

5 files changed

+71
-12
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"

package.json

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6178,12 +6178,12 @@
61786178
},
61796179
{
61806180
"command": "gitlens.ai.aiRebaseBranch:graph",
6181-
"title": "AI Recompose branch commits (Preview)...",
6181+
"title": "AI Recompose Branch Commits (Preview)",
61826182
"icon": "$(sparkle)"
61836183
},
61846184
{
61856185
"command": "gitlens.ai.aiRebaseUnpushed:graph",
6186-
"title": "AI Recompose unpushed commits (Preview)...",
6186+
"title": "AI Recompose Unpushed Commits (Preview)",
61876187
"icon": "$(sparkle)"
61886188
},
61896189
{
@@ -6231,6 +6231,11 @@
62316231
"title": "Explain Changes (Preview)",
62326232
"icon": "$(sparkle)"
62336233
},
6234+
{
6235+
"command": "gitlens.ai.explainUnpushed:graph",
6236+
"title": "Explain Unpushed Changes (Preview)",
6237+
"icon": "$(sparkle)"
6238+
},
62346239
{
62356240
"command": "gitlens.ai.explainWip",
62366241
"title": "Explain Working Changes (Preview)...",
@@ -11028,6 +11033,10 @@
1102811033
"command": "gitlens.ai.explainStash:views",
1102911034
"when": "false"
1103011035
},
11036+
{
11037+
"command": "gitlens.ai.explainUnpushed:graph",
11038+
"when": "false"
11039+
},
1103111040
{
1103211041
"command": "gitlens.ai.explainWip",
1103311042
"when": "gitlens:enabled && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled"
@@ -23319,6 +23328,11 @@
2331923328
"when": "webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+(tracking|remote)\\b)/ && gitlens:action:createPullRequest && gitlens:repos:withRemotes",
2332023329
"group": "1_gitlens_actions_3@4"
2332123330
},
23331+
{
23332+
"command": "gitlens.ai.explainUnpushed:graph",
23333+
"when": "webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+ahead\\b)/ && !listMultiSelection && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled",
23334+
"group": "1_gitlens_actions_4@102"
23335+
},
2332223336
{
2332323337
"command": "gitlens.ai.generateChangelogFrom:graph",
2332423338
"when": "webviewItem =~ /gitlens:(branch|tag)\\b/ && !gitlens:untrusted && gitlens:gk:organization:ai:enabled",

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
@@ -704,6 +704,7 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
704704
this.copyWorkingChangesToWorktree,
705705
),
706706
this.host.registerWebviewCommand('gitlens.ai.generateCommitMessage:graph', this.generateCommitMessage),
707+
this.host.registerWebviewCommand('gitlens.ai.explainUnpushed:graph', this.aiExplainUnpushed),
707708
this.host.registerWebviewCommand('gitlens.ai.explainBranch:graph', this.explainBranch),
708709
this.host.registerWebviewCommand('gitlens.ai.explainCommit:graph', this.explainCommit),
709710
this.host.registerWebviewCommand('gitlens.ai.explainStash:graph', this.explainStash),
@@ -3926,6 +3927,25 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
39263927
});
39273928
}
39283929

3930+
@log()
3931+
private aiExplainUnpushed(item?: GraphItemContext) {
3932+
if (isGraphItemRefContext(item, 'branch')) {
3933+
const { ref } = item.webviewItemValue;
3934+
3935+
if (!ref.upstream) {
3936+
return Promise.resolve();
3937+
}
3938+
3939+
return executeCommand<ExplainBranchCommandArgs>('gitlens.ai.explainBranch', {
3940+
repoPath: ref.repoPath,
3941+
ref: ref.ref,
3942+
baseBranch: ref.upstream.name,
3943+
source: { source: 'graph', context: { type: 'branch' } },
3944+
});
3945+
}
3946+
3947+
return Promise.resolve();
3948+
}
39293949
@log()
39303950
private explainBranch(item?: GraphItemContext) {
39313951
const ref = this.getGraphItemRef(item, 'branch');

0 commit comments

Comments
 (0)