Skip to content

Commit b6a70a2

Browse files
author
Roo Code
committed
Preserve the state of your git workspace and index when saving checkpoints
1 parent 485e2cd commit b6a70a2

File tree

2 files changed

+59
-2
lines changed

2 files changed

+59
-2
lines changed

src/services/checkpoints/CheckpointService.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import path from "path"
55
import debug from "debug"
66
import simpleGit, { SimpleGit, CleanOptions } from "simple-git"
77

8-
debug.enable("simple-git")
8+
if (process.env.NODE_ENV !== "test") {
9+
debug.enable("simple-git")
10+
}
911

1012
export interface Checkpoint {
1113
hash: string
@@ -94,7 +96,7 @@ export class CheckpointService {
9496
const stashList = await this.git.stashList()
9597

9698
if (stashList.all.length > 0) {
97-
await this.git.stash(["pop"]) // Pops the most recent stash only.
99+
await this.git.stash(["pop", "--index"]) // Pops the most recent stash only.
98100
return true
99101
}
100102

src/services/checkpoints/__tests__/CheckpointService.test.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,61 @@ describe("CheckpointService", () => {
135135
expect(await fs.readFile(testFile, "utf-8")).toBe("Hello, world!")
136136
})
137137

138+
it("preserves workspace and index state after saving checkpoint", async () => {
139+
// Create three files with different states: staged, unstaged, and mixed.
140+
const unstagedFile = path.join(service.baseDir, "unstaged.txt")
141+
const stagedFile = path.join(service.baseDir, "staged.txt")
142+
const mixedFile = path.join(service.baseDir, "mixed.txt")
143+
144+
await fs.writeFile(unstagedFile, "Initial unstaged")
145+
await fs.writeFile(stagedFile, "Initial staged")
146+
await fs.writeFile(mixedFile, "Initial mixed")
147+
await git.add(["."])
148+
const result = await git.commit("Add initial files")
149+
expect(result?.commit).toBeTruthy()
150+
151+
await fs.writeFile(unstagedFile, "Modified unstaged")
152+
153+
await fs.writeFile(stagedFile, "Modified staged")
154+
await git.add([stagedFile])
155+
156+
await fs.writeFile(mixedFile, "Modified mixed - staged")
157+
await git.add([mixedFile])
158+
await fs.writeFile(mixedFile, "Modified mixed - unstaged")
159+
160+
// Save checkpoint.
161+
const commit = await service.saveCheckpoint("Test checkpoint")
162+
expect(commit?.commit).toBeTruthy()
163+
164+
// Verify workspace state is preserved.
165+
const status = await git.status()
166+
167+
// All files should be modified.
168+
expect(status.modified).toContain("unstaged.txt")
169+
expect(status.modified).toContain("staged.txt")
170+
expect(status.modified).toContain("mixed.txt")
171+
172+
// Only staged and mixed files should be staged.
173+
expect(status.staged).not.toContain("unstaged.txt")
174+
expect(status.staged).toContain("staged.txt")
175+
expect(status.staged).toContain("mixed.txt")
176+
177+
// Verify file contents.
178+
expect(await fs.readFile(unstagedFile, "utf-8")).toBe("Modified unstaged")
179+
expect(await fs.readFile(stagedFile, "utf-8")).toBe("Modified staged")
180+
expect(await fs.readFile(mixedFile, "utf-8")).toBe("Modified mixed - unstaged")
181+
182+
// Verify staged changes (--cached shows only staged changes).
183+
const stagedDiff = await git.diff(["--cached", "mixed.txt"])
184+
expect(stagedDiff).toContain("-Initial mixed")
185+
expect(stagedDiff).toContain("+Modified mixed - staged")
186+
187+
// Verify unstaged changes (shows working directory changes).
188+
const unstagedDiff = await git.diff(["mixed.txt"])
189+
expect(unstagedDiff).toContain("-Modified mixed - staged")
190+
expect(unstagedDiff).toContain("+Modified mixed - unstaged")
191+
})
192+
138193
it("does not create a checkpoint if there are no pending changes", async () => {
139194
await fs.writeFile(testFile, "Ahoy, world!")
140195
const commit = await service.saveCheckpoint("First checkpoint")

0 commit comments

Comments
 (0)