How Disposable Worktree Isolation in no-mistakes Protects Your Local Git Repository
no-mistakes runs every pipeline step inside a temporary Git worktree under ~/.no-mistakes/worktrees/<repo-id>/<run-id>, ensuring that rebases, force-pushes, and temporary commits never touch your local working directory.
Automated CI/CD pipelines often perform destructive Git operations like rebasing and force-pushing, but executing these directly against your local repository risks corrupting branch history or overwriting uncommitted changes. The no-mistakes open-source tool solves this by implementing disposable worktree isolation, a pattern that creates ephemeral Git worktrees for every pipeline execution. This architecture guarantees that all automated operations happen inside a completely separate directory tree that is destroyed after the run, leaving your local Git state pristine.
What Is Disposable Worktree Isolation?
Disposable worktree isolation is a sandboxing strategy that leverages Git’s built-in worktree feature to create temporary checkouts that share the same object database as your real repository but live in entirely separate directories.
The Bare "Gate" Repository Pattern
When no-mistakes initializes a repository, it mirrors your real repo into a bare "gate" repository that acts as the object storage backend. The disposable worktree is then created using standard Git commands:
- The worktree is created with
git worktree addfrom this bare repository - The worktree’s
.gitfile becomes a pointer to the bare repo rather than a full.gitdirectory - All normal Git commands (
git diff,git commit,git rebase,git push) operate on the worktree and never on your original working tree
As documented in internal/pipeline/steps/execution_context.go:18-22, agents receive an explicit prompt explaining this context: "You are running inside an isolated git worktree … the worktree’s .git is a pointer file … treat it as the project’s source of truth." This ensures AI agents and automated scripts understand they are operating inside a disposable environment.
How the Isolation Mechanism Works
The implementation relies on three coordinated components that manage the lifecycle of the temporary worktree from creation to destruction.
Worktree Creation and Path Resolution
Each pipeline run receives a deterministic, unique directory path generated by the WorktreeDir(repoID, runID) function in internal/paths/paths.go:46-48. This places the worktree under:
~/.no-mistakes/worktrees/<repo-id>/<run-id>
By using a function like paths.WithRoot(NMHome).WorktreeDir(repo.ID, run.ID), the system guarantees that parallel runs never share the same filesystem location, preventing cross-run contamination.
Execution Context and the Work Directory
The pipeline executor documented in internal/pipeline/executor.go:111-112 accepts a workDir parameter that points to this temporary worktree. All step implementations—whether running linters, tests, rebases, or pushes—read and write files relative to this directory exclusively.
When steps execute, they launch from this isolated path, meaning:
- File system changes affect only the disposable directory
- Git operations target the temporary checkout's index and HEAD
- The original repository's working tree remains untouched and available for developer use
Cleanup and Disposal
After a run finishes or aborts, the daemon removes the worktree to prevent permanent pollution of the developer's filesystem. According to internal/daemon/daemon.go:287, the cleanup strategy uses:
git worktree remove --force <path>as the primary removal method- A fallback to
os.RemoveAll(wd)if the Git command fails
This ensures that even if Git processes are lingering or permissions issues occur, the temporary directory is obliterated, guaranteeing that no temporary commits, rebased branches, or generated artifacts leak into your local environment.
Safety Guarantees for Local Development
The disposable worktree architecture provides specific protections against common automation risks:
-
Accidental rebases on local branches: Rebase steps fetch
origin/<default>into the worktree and rebase only that temporary checkout. Your localmainor feature branches remain untouched regardless of rebase conflicts or resolutions. -
Safe force-push decisions: The force-push logic (
resolveForcePushDecision) examines the remote HEAD that the worktree last saw, not your local refs. Because the worktree fetches fresh state for each step, force-push safety calculations use live remote data rather than stale local branch positions. -
Process isolation prevents repository locking: All subprocesses launch via
shellenv.ConfigureShellCommand, which places them in separate process groups. When a run cancels, the entire process group (including lingering Git processes) terminates, preventing the worktree from staying locked by zombie processes. -
Filesystem pollution prevention: Any files created by agents—documentation, evidence, or fixes—write into the worktree path. Since the worktree is deleted post-run, your developer working directory remains free of automation debris.
-
Parallel execution safety: Each run receives a unique worktree directory via
paths.WorktreeDir(), ensuring simultaneous pipeline executions never share state or overwrite each other's files.
Implementation Example: Worktree Lifecycle in Go
The following simplified snippet demonstrates how no-mistakes orchestrates the worktree lifecycle:
// 1. Create a worktree for a run
wtDir := paths.WithRoot(NMHome).WorktreeDir(repo.ID, run.ID)
// → ~/.no-mistakes/worktrees/<repo>/<run>
gitCmd(t, wtDir, "worktree", "add", "--detach", wtDir, "origin/"+branch)
// 2. Executor runs steps inside that directory
executor.Execute(ctx, run, repo, wtDir) // workDir = wtDir
// 3. After the run finishes, clean up
gitCmd(ctx, wtDir, "worktree", "remove", "--force", wtDir)
// Fallback if git fails
os.RemoveAll(wtDir)
This pattern appears throughout the codebase, from the production daemon to the end-to-end test harness in internal/e2e/harness.go:367-385, which creates and removes worktrees for test fixtures.
Summary
- no-mistakes creates disposable Git worktrees under
~/.no-mistakes/worktrees/<repo-id>/<run-id>for every pipeline execution. - The worktree points to a bare "gate" repository, ensuring all Git commands operate on the temporary checkout while preserving the original working tree.
- The
WorktreeDir()function ininternal/paths/paths.gogenerates unique, deterministic paths to prevent cross-run contamination. - Cleanup uses
git worktree remove --forcewith anos.RemoveAll()fallback to guarantee deletion even if Git commands fail. - Process groups managed by
shellenv.ConfigureShellCommandprevent repository locking when runs cancel. - This isolation prevents accidental rebases, unsafe force-pushes, and filesystem pollution in your local development environment.
Frequently Asked Questions
Where does no-mistakes store temporary worktrees?
Temporary worktrees live under ~/.no-mistakes/worktrees/<repo-id>/<run-id>, generated by the WorktreeDir(repoID, runID) function in internal/paths/paths.go:46-48. Each run receives a unique directory path to ensure complete isolation from your working repository and from other concurrent runs.
What happens if the worktree cleanup fails?
The daemon in internal/daemon/daemon.go:287 implements a two-stage cleanup. It first attempts git worktree remove --force, and if that Git command fails, it falls back to os.RemoveAll() to forcibly delete the directory. This guarantees that temporary files never persist indefinitely, even if Git processes hold locks or permissions issues occur.
How does the tool ensure agents don't modify my real repository?
Before execution, agents receive a context prompt from internal/pipeline/steps/execution_context.go:18-22 explaining that they operate inside an isolated worktree where the .git file is merely a pointer to a bare repository. The pipeline executor documented in internal/pipeline/executor.go:111-112 passes this worktree path as the sole working directory, ensuring all file operations and Git commands target the disposable location exclusively.
Can multiple pipeline runs execute simultaneously without conflicts?
Yes. Because each run receives its own unique path via paths.WorktreeDir(), parallel executions operate in completely separate directory trees. This prevents file system race conditions and ensures that one run's temporary commits or rebases never interfere with another run's operations or with your local repository state.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →