diff --git a/src/core/Cline.ts b/src/core/Cline.ts index 3b221eb784..7d7bedcabd 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -3288,12 +3288,7 @@ export class Cline { ]), ) } catch (err) { - this.providerRef - .deref() - ?.log( - `[checkpointDiff] Encountered unexpected error: $${err instanceof Error ? err.message : String(err)}`, - ) - + this.providerRef.deref()?.log("[checkpointDiff] disabling checkpoints for this task") this.checkpointsEnabled = false } } @@ -3315,12 +3310,7 @@ export class Cline { await this.say("checkpoint_saved", commit.commit) } } catch (err) { - this.providerRef - .deref() - ?.log( - `[checkpointSave] Encountered unexpected error: $${err instanceof Error ? err.message : String(err)}`, - ) - + this.providerRef.deref()?.log("[checkpointSave] disabling checkpoints for this task") this.checkpointsEnabled = false } } @@ -3390,12 +3380,7 @@ export class Cline { // Cline instance. this.providerRef.deref()?.cancelTask() } catch (err) { - this.providerRef - .deref() - ?.log( - `[restoreCheckpoint] Encountered unexpected error: $${err instanceof Error ? err.message : String(err)}`, - ) - + this.providerRef.deref()?.log("[checkpointRestore] disabling checkpoints for this task") this.checkpointsEnabled = false } } diff --git a/src/services/checkpoints/CheckpointService.ts b/src/services/checkpoints/CheckpointService.ts index 53f0647a67..c2f57a35ab 100644 --- a/src/services/checkpoints/CheckpointService.ts +++ b/src/services/checkpoints/CheckpointService.ts @@ -132,19 +132,59 @@ export class CheckpointService { stashSha: string force?: boolean }) { - if (force) { - await this.git.checkout(["-f", this.mainBranch]) - } else { - await this.git.checkout(this.mainBranch) + let currentBranch = await this.git.revparse(["--abbrev-ref", "HEAD"]) + + if (currentBranch !== this.mainBranch) { + if (force) { + try { + await this.git.checkout(["-f", this.mainBranch]) + } catch (err) { + this.log( + `[restoreMain] failed to force checkout ${this.mainBranch}: ${err instanceof Error ? err.message : String(err)}`, + ) + } + } else { + try { + await this.git.checkout(this.mainBranch) + } catch (err) { + this.log( + `[restoreMain] failed to checkout ${this.mainBranch}: ${err instanceof Error ? err.message : String(err)}`, + ) + + // Escalate to a forced checkout if we can't checkout the + // main branch under nor + currentBranch = await this.git.revparse(["--abbrev-ref", "HEAD"]) + + if (currentBranch !== this.mainBranch) { + await this.git.checkout(["-f", this.mainBranch]).catch(() => {}) + } + } + } + } + + currentBranch = await this.git.revparse(["--abbrev-ref", "HEAD"]) + + if (currentBranch !== this.mainBranch) { + throw new Error(`Unable to restore ${this.mainBranch}`) } if (stashSha) { this.log(`[restoreMain] applying stash ${stashSha}`) - await this.git.raw(["stash", "apply", "--index", stashSha]) + + try { + await this.git.raw(["stash", "apply", "--index", stashSha]) + } catch (err) { + this.log(`[restoreMain] Failed to apply stash: ${err instanceof Error ? err.message : String(err)}`) + } } - this.log(`[restoreMain] restoring from ${branch}`) - await this.git.raw(["restore", "--source", branch, "--worktree", "--", "."]) + this.log(`[restoreMain] restoring from ${branch} branch`) + + try { + await this.git.raw(["restore", "--source", branch, "--worktree", "--", "."]) + } catch (err) { + this.log(`[restoreMain] Failed to restore branch: ${err instanceof Error ? err.message : String(err)}`) + } } public async saveCheckpoint(message: string) { @@ -172,15 +212,13 @@ export class CheckpointService { */ try { await this.git.add(["-A"]) - const status = await this.git.status() - this.log(`[saveCheckpoint] status: ${JSON.stringify(status)}`) } catch (err) { + this.log( + `[saveCheckpoint] failed in stage stash phase: ${err instanceof Error ? err.message : String(err)}`, + ) await this.git.checkout(["-f", this.mainBranch]) await this.git.branch(["-D", stashBranch]).catch(() => {}) - - throw new Error( - `[saveCheckpoint] Failed in stage stash phase: ${err instanceof Error ? err.message : String(err)}`, - ) + throw err } /** @@ -194,15 +232,15 @@ export class CheckpointService { */ try { // TODO: Add a test to see if empty commits break this. - const tempCommit = await this.git.commit(message, undefined, { "--no-verify": null }) - this.log(`[saveCheckpoint] tempCommit: ${message} -> ${JSON.stringify(tempCommit)}`) + const stashCommit = await this.git.commit(message, undefined, { "--no-verify": null }) + this.log(`[saveCheckpoint] stashCommit: ${message} -> ${JSON.stringify(stashCommit)}`) } catch (err) { + this.log( + `[saveCheckpoint] failed in stash commit phase: ${err instanceof Error ? err.message : String(err)}`, + ) await this.git.checkout(["-f", this.mainBranch]) await this.git.branch(["-D", stashBranch]).catch(() => {}) - - throw new Error( - `[saveCheckpoint] Failed in stash commit phase: ${err instanceof Error ? err.message : String(err)}`, - ) + throw err } /** @@ -219,12 +257,10 @@ export class CheckpointService { try { diff = await this.git.diff([latestSha, stashBranch]) } catch (err) { + this.log(`[saveCheckpoint] failed in diff phase: ${err instanceof Error ? err.message : String(err)}`) await this.restoreMain({ branch: stashBranch, stashSha, force: true }) await this.git.branch(["-D", stashBranch]).catch(() => {}) - - throw new Error( - `[saveCheckpoint] Failed in diff phase: ${err instanceof Error ? err.message : String(err)}`, - ) + throw err } if (!diff) { @@ -249,12 +285,10 @@ export class CheckpointService { await this.git.reset(["--hard", this.mainBranch]) this.log(`[saveCheckpoint] reset ${this.hiddenBranch}`) } catch (err) { + this.log(`[saveCheckpoint] failed in reset phase: ${err instanceof Error ? err.message : String(err)}`) await this.restoreMain({ branch: stashBranch, stashSha, force: true }) await this.git.branch(["-D", stashBranch]).catch(() => {}) - - throw new Error( - `[saveCheckpoint] Failed in reset phase: ${err instanceof Error ? err.message : String(err)}`, - ) + throw err } /** @@ -289,17 +323,18 @@ export class CheckpointService { this.currentCheckpoint = commit this.log(`[saveCheckpoint] cherry-pick commit = ${commit}`) } catch (err) { + this.log( + `[saveCheckpoint] failed in cherry pick phase: ${err instanceof Error ? err.message : String(err)}`, + ) await this.git.reset(["--hard", latestSha]).catch(() => {}) await this.restoreMain({ branch: stashBranch, stashSha, force: true }) await this.git.branch(["-D", stashBranch]).catch(() => {}) - - throw new Error( - `[saveCheckpoint] Failed in cherry pick phase: ${err instanceof Error ? err.message : String(err)}`, - ) + throw err } await this.restoreMain({ branch: stashBranch, stashSha }) await this.git.branch(["-D", stashBranch]) + this.log(`[saveCheckpoint] saved checkpoint ${commit}`) return { commit } }