mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-10-07 02:58:15 +00:00
Merge 4e9cb4dc3b into c3cae397a1
This commit is contained in:
commit
ebdbe14c26
2 changed files with 77 additions and 0 deletions
|
|
@ -229,6 +229,21 @@ export abstract class ShadowCheckpointService extends EventEmitter {
|
||||||
|
|
||||||
private async getNestedGitRepository(): Promise<string | null> {
|
private async getNestedGitRepository(): Promise<string | null> {
|
||||||
try {
|
try {
|
||||||
|
// First check if the workspace root has its own .git directory.
|
||||||
|
// If the root does NOT have .git, then subdirectory git repos are
|
||||||
|
// independent sibling projects (e.g., frontend and backend repos in
|
||||||
|
// the same parent folder), not truly nested repositories.
|
||||||
|
// In this case, we should allow checkpoints.
|
||||||
|
const rootGitDir = path.join(this.workspaceDir, ".git")
|
||||||
|
const rootHasGit = await fileExistsAtPath(rootGitDir)
|
||||||
|
|
||||||
|
if (!rootHasGit) {
|
||||||
|
this.log(
|
||||||
|
`[${this.constructor.name}#getNestedGitRepository] workspace root has no .git directory, allowing checkpoints with sibling git repositories`,
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
// Find all .git/HEAD files that are not at the root level.
|
// Find all .git/HEAD files that are not at the root level.
|
||||||
const args = ["--files", "--hidden", "--follow", "-g", "**/.git/HEAD", this.workspaceDir]
|
const args = ["--files", "--hidden", "--follow", "-g", "**/.git/HEAD", this.workspaceDir]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -483,6 +483,68 @@ describe.each([[RepoPerTaskCheckpointService, "RepoPerTaskCheckpointService"]])(
|
||||||
await fs.rm(shadowDir, { recursive: true, force: true })
|
await fs.rm(shadowDir, { recursive: true, force: true })
|
||||||
await fs.rm(workspaceDir, { recursive: true, force: true })
|
await fs.rm(workspaceDir, { recursive: true, force: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("succeeds when workspace has no root .git but has sibling git repos in subdirectories", async () => {
|
||||||
|
// This test covers the issue #10636 scenario where a user opens a parent folder
|
||||||
|
// that contains multiple sibling projects (e.g., frontend and backend), each with
|
||||||
|
// their own independent git repositories.
|
||||||
|
|
||||||
|
// Create a new temporary workspace WITHOUT a root .git directory.
|
||||||
|
const shadowDir = path.join(tmpDir, `${prefix}-sibling-git-${Date.now()}`)
|
||||||
|
const workspaceDir = path.join(tmpDir, `workspace-sibling-git-${Date.now()}`)
|
||||||
|
await fs.mkdir(workspaceDir, { recursive: true })
|
||||||
|
|
||||||
|
// Create sibling git repos inside the workspace (simulating frontend/backend structure)
|
||||||
|
const frontendDir = path.join(workspaceDir, "frontend")
|
||||||
|
await fs.mkdir(frontendDir, { recursive: true })
|
||||||
|
const frontendGit = simpleGit(frontendDir)
|
||||||
|
await frontendGit.init()
|
||||||
|
await frontendGit.addConfig("user.name", "Roo Code")
|
||||||
|
await frontendGit.addConfig("user.email", "support@roocode.com")
|
||||||
|
const frontendFile = path.join(frontendDir, "index.ts")
|
||||||
|
await fs.writeFile(frontendFile, "console.log('frontend');")
|
||||||
|
await frontendGit.add(".")
|
||||||
|
await frontendGit.commit("Initial frontend commit")
|
||||||
|
|
||||||
|
const backendDir = path.join(workspaceDir, "backend")
|
||||||
|
await fs.mkdir(backendDir, { recursive: true })
|
||||||
|
const backendGit = simpleGit(backendDir)
|
||||||
|
await backendGit.init()
|
||||||
|
await backendGit.addConfig("user.name", "Roo Code")
|
||||||
|
await backendGit.addConfig("user.email", "support@roocode.com")
|
||||||
|
const backendFile = path.join(backendDir, "server.ts")
|
||||||
|
await fs.writeFile(backendFile, "console.log('backend');")
|
||||||
|
await backendGit.add(".")
|
||||||
|
await backendGit.commit("Initial backend commit")
|
||||||
|
|
||||||
|
// Note: We do NOT create a .git directory at the workspace root
|
||||||
|
// This simulates the user's scenario of opening the parent folder
|
||||||
|
|
||||||
|
// Use klass.create() like other tests do
|
||||||
|
const service = await klass.create({ taskId, shadowDir, workspaceDir, log: () => {} })
|
||||||
|
|
||||||
|
// Verify that initialization succeeds because there's no root .git
|
||||||
|
// The sibling git repos should NOT be considered "nested"
|
||||||
|
await expect(service.initShadowGit()).resolves.not.toThrow()
|
||||||
|
expect(service.isInitialized).toBe(true)
|
||||||
|
expect(service.baseHash).toBeTruthy()
|
||||||
|
|
||||||
|
// Verify we can create a checkpoint with a file in the root workspace
|
||||||
|
// (not inside the sibling repos, to ensure tracking works)
|
||||||
|
const rootFile = path.join(workspaceDir, "readme.txt")
|
||||||
|
await fs.writeFile(rootFile, "Root workspace file")
|
||||||
|
const commit = await service.saveCheckpoint("Add root file")
|
||||||
|
expect(commit?.commit).toBeTruthy()
|
||||||
|
|
||||||
|
// Verify we can restore the checkpoint
|
||||||
|
await fs.writeFile(rootFile, "Modified root file")
|
||||||
|
await service.restoreCheckpoint(commit!.commit)
|
||||||
|
expect(await fs.readFile(rootFile, "utf-8")).toBe("Root workspace file")
|
||||||
|
|
||||||
|
// Clean up.
|
||||||
|
await fs.rm(shadowDir, { recursive: true, force: true })
|
||||||
|
await fs.rm(workspaceDir, { recursive: true, force: true })
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe(`${klass.name}#events`, () => {
|
describe(`${klass.name}#events`, () => {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue