Skip to content

Commit f28ba88

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

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
@@ -6191,12 +6191,12 @@
61916191
},
61926192
{
61936193
"command": "gitlens.ai.aiRebaseBranch:graph",
6194-
"title": "AI Recompose branch commits (Preview)...",
6194+
"title": "AI Recompose Branch Commits (Preview)",
61956195
"icon": "$(sparkle)"
61966196
},
61976197
{
61986198
"command": "gitlens.ai.aiRebaseUnpushed:graph",
6199-
"title": "AI Recompose unpushed commits (Preview)...",
6199+
"title": "AI Recompose Unpushed Commits (Preview)",
62006200
"icon": "$(sparkle)"
62016201
},
62026202
{
@@ -6244,6 +6244,11 @@
62446244
"title": "Explain Changes (Preview)",
62456245
"icon": "$(sparkle)"
62466246
},
6247+
{
6248+
"command": "gitlens.ai.explainUnpushed:graph",
6249+
"title": "Explain Unpushed Changes (Preview)",
6250+
"icon": "$(sparkle)"
6251+
},
62476252
{
62486253
"command": "gitlens.ai.explainWip",
62496254
"title": "Explain Working Changes (Preview)...",
@@ -11058,6 +11063,10 @@
1105811063
"command": "gitlens.ai.explainStash:views",
1105911064
"when": "false"
1106011065
},
11066+
{
11067+
"command": "gitlens.ai.explainUnpushed:graph",
11068+
"when": "false"
11069+
},
1106111070
{
1106211071
"command": "gitlens.ai.explainWip",
1106311072
"when": "gitlens:enabled && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled"
@@ -23357,6 +23366,11 @@
2335723366
"when": "webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+(tracking|remote)\\b)/ && gitlens:action:createPullRequest && gitlens:repos:withRemotes",
2335823367
"group": "1_gitlens_actions_3@4"
2335923368
},
23369+
{
23370+
"command": "gitlens.ai.explainUnpushed:graph",
23371+
"when": "webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+ahead\\b)/ && !listMultiSelection && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled",
23372+
"group": "1_gitlens_actions_4@102"
23373+
},
2336023374
{
2336123375
"command": "gitlens.ai.generateChangelogFrom:graph",
2336223376
"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
@@ -708,6 +708,7 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
708708
this.copyWorkingChangesToWorktree,
709709
),
710710
this.host.registerWebviewCommand('gitlens.ai.generateCommitMessage:graph', this.generateCommitMessage),
711+
this.host.registerWebviewCommand('gitlens.ai.explainUnpushed:graph', this.aiExplainUnpushed),
711712
this.host.registerWebviewCommand('gitlens.ai.explainBranch:graph', this.explainBranch),
712713
this.host.registerWebviewCommand('gitlens.ai.explainCommit:graph', this.explainCommit),
713714
this.host.registerWebviewCommand('gitlens.ai.explainStash:graph', this.explainStash),
@@ -3947,6 +3948,25 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
39473948
});
39483949
}
39493950

3951+
@log()
3952+
private aiExplainUnpushed(item?: GraphItemContext) {
3953+
if (isGraphItemRefContext(item, 'branch')) {
3954+
const { ref } = item.webviewItemValue;
3955+
3956+
if (!ref.upstream) {
3957+
return Promise.resolve();
3958+
}
3959+
3960+
return executeCommand<ExplainBranchCommandArgs>('gitlens.ai.explainBranch', {
3961+
repoPath: ref.repoPath,
3962+
ref: ref.ref,
3963+
baseBranch: ref.upstream.name,
3964+
source: { source: 'graph', context: { type: 'branch' } },
3965+
});
3966+
}
3967+
3968+
return Promise.resolve();
3969+
}
39503970
@log()
39513971
private explainBranch(item?: GraphItemContext) {
39523972
const ref = this.getGraphItemRef(item, 'branch');

0 commit comments

Comments
 (0)