@@ -174,6 +174,176 @@ export class GenerateRebaseCommand extends GlCommandBase {
174174 }
175175}
176176
177+ @command ( )
178+ export class UndoGenerateRebaseCommand extends GlCommandBase {
179+ constructor ( private readonly container : Container ) {
180+ super ( 'gitlens.ai.undoGenerateRebase' ) ;
181+ }
182+
183+ protected override preExecute ( context : CommandContext , args ?: UndoGenerateRebaseCommandArgs ) : Promise < void > {
184+ if ( isCommandContextViewNodeHasWorktree ( context ) ) {
185+ args = { ...args } ;
186+ args . repoPath = context . node . worktree . path ;
187+ args . source = args . source ?? { source : 'view' } ;
188+ } else if ( isCommandContextViewNodeHasRepository ( context ) ) {
189+ args = { ...args } ;
190+ args . repoPath = context . node . repo . path ;
191+ args . source = args . source ?? { source : 'view' } ;
192+ } else if ( isCommandContextViewNodeHasRepoPath ( context ) ) {
193+ args = { ...args } ;
194+ args . repoPath = context . node . repoPath ;
195+ args . source = args . source ?? { source : 'view' } ;
196+ }
197+
198+ return this . execute ( args ) ;
199+ }
200+
201+ async execute ( args ?: UndoGenerateRebaseCommandArgs ) : Promise < void > {
202+ try {
203+ if ( ! args ?. undoCommand ) {
204+ Logger . error ( undefined , 'UndoGenerateRebaseCommand' , 'execute' , 'Missing undoCommand parameter' ) ;
205+ void window . showErrorMessage ( 'Unable to undo: Missing command information' ) ;
206+ return ;
207+ }
208+
209+ if ( args . undoCommand === 'gitlens.ai.generateRebase' ) {
210+ await this . undoGenerateRebase ( args ) ;
211+ } else if ( args . undoCommand === 'gitlens.ai.generateCommits' ) {
212+ await this . undoGenerateCommits ( args ) ;
213+ } else {
214+ const unknownCommand = args . undoCommand as string ;
215+ Logger . error (
216+ undefined ,
217+ 'UndoGenerateRebaseCommand' ,
218+ 'execute' ,
219+ `Unknown undoCommand: ${ unknownCommand } ` ,
220+ ) ;
221+ void window . showErrorMessage ( `Unable to undo: Unknown command ${ unknownCommand } ` ) ;
222+ }
223+ } catch ( ex ) {
224+ Logger . error ( ex , 'UndoGenerateRebaseCommand' , 'execute' ) ;
225+ void showGenericErrorMessage ( 'Unable to undo operation' ) ;
226+ }
227+ }
228+
229+ private async undoGenerateRebase ( args : UndoGenerateRebaseCommandArgs ) : Promise < void > {
230+ // Check required parameters
231+ if ( ! args . repoPath || ! args . generatedBranchName ) {
232+ Logger . error (
233+ undefined ,
234+ 'UndoGenerateRebaseCommand' ,
235+ 'undoGenerateRebase' ,
236+ 'Missing required parameters: repoPath or generatedBranchName' ,
237+ ) ;
238+ void window . showErrorMessage ( 'Unable to undo rebase: Missing required information' ) ;
239+ return ;
240+ }
241+
242+ const svc = this . container . git . getRepositoryService ( args . repoPath ) ;
243+
244+ // Warn user and ask for confirmation
245+ const confirm = { title : 'Delete Branch' } ;
246+ const cancel = { title : 'Cancel' , isCloseAffordance : true } ;
247+ const result = await window . showWarningMessage (
248+ `This will delete the branch '${ args . generatedBranchName } '. This action cannot be undone.\n\nAre you sure you want to continue?` ,
249+ { modal : true } ,
250+ confirm ,
251+ cancel ,
252+ ) ;
253+
254+ if ( result !== confirm ) return ;
255+
256+ try {
257+ // Try to delete the branch
258+ await svc . branches . deleteLocalBranch ?.( args . generatedBranchName , { force : true } ) ;
259+ void window . showInformationMessage (
260+ `Successfully deleted branch '${ args . generatedBranchName } '. Undo completed.` ,
261+ ) ;
262+ } catch ( ex ) {
263+ Logger . error ( ex , 'UndoGenerateRebaseCommand' , 'undoGenerateRebase' ) ;
264+
265+ // Check if it's because the user is on the branch or other specific errors
266+ const errorMessage = ex instanceof Error ? ex . message : String ( ex ) ;
267+ if ( errorMessage . includes ( 'checked out' ) || errorMessage . includes ( 'current branch' ) ) {
268+ void window . showErrorMessage (
269+ `Cannot delete branch '${ args . generatedBranchName } ' because it is currently checked out.` ,
270+ ) ;
271+ } else {
272+ void window . showErrorMessage ( `Failed to delete branch '${ args . generatedBranchName } ': ${ errorMessage } ` ) ;
273+ }
274+ }
275+ }
276+
277+ private async undoGenerateCommits ( args : UndoGenerateRebaseCommandArgs ) : Promise < void > {
278+ // Check required parameters
279+ if ( ! args . repoPath || ! args . generatedHeadRef || ! args . previousHeadRef || ! args . generatedStashRef ) {
280+ Logger . error (
281+ undefined ,
282+ 'UndoGenerateRebaseCommand' ,
283+ 'undoGenerateCommits' ,
284+ 'Missing required parameters: repoPath, generatedHeadRef, previousHeadRef, or generatedStashRef' ,
285+ ) ;
286+ void window . showErrorMessage ( 'Unable to undo commits: Missing required information' ) ;
287+ return ;
288+ }
289+
290+ const svc = this . container . git . getRepositoryService ( args . repoPath ) ;
291+
292+ try {
293+ // Check if current HEAD matches the generated HEAD
294+ const log = await svc . commits . getLog ( undefined , { limit : 1 } ) ;
295+ const currentCommit = log ?. commits . values ( ) . next ( ) . value ;
296+ if ( ! currentCommit || currentCommit . sha !== args . generatedHeadRef . ref ) {
297+ void window . showErrorMessage (
298+ 'Cannot undo commits: Your HEAD reference has changed since the commits were generated. Please ensure you are on the correct commit.' ,
299+ ) ;
300+ return ;
301+ }
302+
303+ // Warn user and ask for confirmation
304+ const confirm = { title : 'Undo Commits' } ;
305+ const cancel = { title : 'Cancel' , isCloseAffordance : true } ;
306+ const result = await window . showWarningMessage (
307+ `This will reset your current branch to ${ args . previousHeadRef . ref } and restore your previous working changes. Any work done after generating commits will be lost.\n\nAre you sure you want to continue?` ,
308+ { modal : true } ,
309+ confirm ,
310+ cancel ,
311+ ) ;
312+
313+ if ( result !== confirm ) return ;
314+
315+ // Check if there are working tree changes and stash them
316+ const status = await svc . status . getStatus ( ) ;
317+ if ( status ?. files && status . files . length > 0 ) {
318+ await svc . stash ?. saveStash ( undefined , undefined , { includeUntracked : true } ) ;
319+ }
320+
321+ // Reset hard to the previous HEAD
322+ await svc . reset ( args . previousHeadRef . ref , { hard : true } ) ;
323+
324+ // Apply the generated stash
325+ try {
326+ await svc . stash ?. applyStash ( args . generatedStashRef . ref ) ;
327+ } catch ( ex ) {
328+ Logger . error ( ex , 'UndoGenerateRebaseCommand' , 'undoGenerateCommits' , 'Failed to apply stash' ) ;
329+ void window . showWarningMessage (
330+ `Reset completed, but failed to apply the original stash: ${
331+ ex instanceof Error ? ex . message : String ( ex )
332+ } `,
333+ ) ;
334+ return ;
335+ }
336+
337+ void window . showInformationMessage (
338+ 'Successfully undid the generated commits and restored your previous working changes. Undo completed.' ,
339+ ) ;
340+ } catch ( ex ) {
341+ Logger . error ( ex , 'UndoGenerateRebaseCommand' , 'undoGenerateCommits' ) ;
342+ void window . showErrorMessage ( `Failed to undo commits: ${ ex instanceof Error ? ex . message : String ( ex ) } ` ) ;
343+ }
344+ }
345+ }
346+
177347export async function generateRebase (
178348 container : Container ,
179349 svc : GitRepositoryService ,
0 commit comments