@@ -51,6 +51,8 @@ export type CheckpointServiceOptions = {
5151export class CheckpointService {
5252 private static readonly USER_NAME = "Roo Code"
5353 private static readonly USER_EMAIL = "[email protected] " 54+ private static readonly CHECKPOINT_BRANCH = "roo-code-checkpoints"
55+ private static readonly STASH_BRANCH = "roo-code-stash"
5456
5557 private _currentCheckpoint ?: string
5658
@@ -72,39 +74,6 @@ export class CheckpointService {
7274 private readonly log : ( message : string ) => void ,
7375 ) { }
7476
75- private async pushStash ( ) {
76- const status = await this . git . status ( )
77-
78- if ( status . files . length > 0 ) {
79- await this . git . stash ( [ "-u" ] ) // Includes tracked and untracked files.
80- return true
81- }
82-
83- return false
84- }
85-
86- private async applyStash ( ) {
87- const stashList = await this . git . stashList ( )
88-
89- if ( stashList . all . length > 0 ) {
90- await this . git . stash ( [ "apply" ] ) // Applies the most recent stash only.
91- return true
92- }
93-
94- return false
95- }
96-
97- private async popStash ( ) {
98- const stashList = await this . git . stashList ( )
99-
100- if ( stashList . all . length > 0 ) {
101- await this . git . stash ( [ "pop" , "--index" ] ) // Pops the most recent stash only.
102- return true
103- }
104-
105- return false
106- }
107-
10877 private async ensureBranch ( expectedBranch : string ) {
10978 const branch = await this . git . revparse ( [ "--abbrev-ref" , "HEAD" ] )
11079
@@ -156,84 +125,47 @@ export class CheckpointService {
156125 public async saveCheckpoint ( message : string ) {
157126 await this . ensureBranch ( this . mainBranch )
158127
159- // Attempt to stash pending changes (including untracked files).
160- const pendingChanges = await this . pushStash ( )
161-
162- // Get the latest commit on the hidden branch before we reset it.
163- const latestHash = await this . git . revparse ( [ this . hiddenBranch ] )
164-
165- // Check if there is any diff relative to the latest commit.
166- if ( ! pendingChanges ) {
167- const diff = await this . git . diff ( [ latestHash ] )
168-
169- if ( ! diff ) {
170- this . log ( `[saveCheckpoint] No changes detected, giving up` )
171- return undefined
172- }
173- }
174-
175- await this . git . checkout ( this . hiddenBranch )
176-
177- const reset = async ( ) => {
178- await this . git . reset ( [ "HEAD" , "." ] )
179- await this . git . clean ( [ CleanOptions . FORCE , CleanOptions . RECURSIVE ] )
180- await this . git . reset ( [ "--hard" , latestHash ] )
181- await this . git . checkout ( this . mainBranch )
182- await this . popStash ( )
183- }
128+ // Create temporary branch with all current changes
129+ const tempBranch = `${ CheckpointService . STASH_BRANCH } -${ Date . now ( ) } `
130+ await this . git . checkout ( [ "-b" , tempBranch ] )
184131
185132 try {
186- // Reset hidden branch to match main and apply the pending changes.
187- await this . git . reset ( [ "--hard" , this . mainBranch ] )
188-
189- if ( pendingChanges ) {
190- await this . applyStash ( )
191- }
192-
193- // Using "-A" ensures that deletions are staged as well.
133+ // Stage and commit all changes to temporary branch
194134 await this . git . add ( [ "-A" ] )
195- const diff = await this . git . diff ( [ latestHash ] )
196-
197- if ( ! diff ) {
198- this . log ( `[saveCheckpoint] No changes detected, resetting and giving up` )
199- await reset ( )
200- return undefined
201- }
202-
203- // Otherwise, commit the changes.
204- const status = await this . git . status ( )
205- this . log ( `[saveCheckpoint] Changes detected, committing ${ JSON . stringify ( status ) } ` )
206-
207- // Allow empty commits in order to correctly handle deletion of
208- // untracked files (see unit tests for an example of this).
209- // Additionally, skip pre-commit hooks so that they don't slow
210- // things down or tamper with the contents of the commit.
211- const commit = await this . git . commit ( message , undefined , {
135+ await this . git . commit ( message , undefined , {
212136 "--allow-empty" : null ,
213137 "--no-verify" : null ,
214138 } )
215139
216- await this . git . checkout ( this . mainBranch )
140+ // Get the latest commit on the hidden branch before we reset it
141+ const latestHash = await this . git . revparse ( [ this . hiddenBranch ] )
142+ await this . git . checkout ( this . hiddenBranch )
217143
218- if ( pendingChanges ) {
219- await this . popStash ( )
220- }
144+ try {
145+ // Reset hidden branch to match main and apply the changes
146+ await this . git . reset ( [ "--hard" , this . mainBranch ] )
221147
222- this . currentCheckpoint = commit . commit
148+ // Cherry-pick the temporary commit
149+ const commit = await this . git . raw ( [ "cherry-pick" , tempBranch ] )
223150
224- return commit
225- } catch ( err ) {
226- this . log ( `[saveCheckpoint] Failed to save checkpoint: ${ err instanceof Error ? err . message : String ( err ) } ` )
151+ // Return to main branch and cleanup
152+ await this . git . checkout ( this . mainBranch )
153+ await this . git . branch ( [ "-D" , tempBranch ] )
227154
228- // If we're not on the main branch then we need to trigger a reset
229- // to return to the main branch and restore it's previous state.
230- const currentBranch = await this . git . revparse ( [ "--abbrev-ref" , "HEAD" ] )
231-
232- if ( currentBranch . trim ( ) !== this . mainBranch ) {
233- await reset ( )
155+ this . currentCheckpoint = commit
156+ return { commit }
157+ } catch ( err ) {
158+ // If something went wrong after switching to hidden branch
159+ await this . git . reset ( [ "--hard" , latestHash ] )
160+ await this . git . checkout ( [ "-f" , this . mainBranch ] )
161+ await this . git . branch ( [ "-D" , tempBranch ] )
162+ throw err
234163 }
235-
236- throw err
164+ } catch ( err ) {
165+ // If something went wrong before switching to hidden branch
166+ await this . git . checkout ( [ "-f" , this . mainBranch ] )
167+ await this . git . branch ( [ "-D" , tempBranch ] )
168+ throw new Error ( `Failed to save checkpoint: ${ err instanceof Error ? err . message : String ( err ) } ` )
237169 }
238170 }
239171
0 commit comments