- 1
//! Git worktree isolation: each isolated run gets its own worktree + branch - 2
//! off HEAD, so mutations never touch the user's checkout. - 3
- 4
use std::path::{Path, PathBuf}; - 5
use std::process::Command; - 6
- 7
#[derive(Debug, thiserror::Error)] - 8
pub enum WorktreeError { - 9
#[error("not a git repository")] - 10
NotARepo, - 11
#[error("git failed: {0}")] - 12
Git(String), - 13
#[error("io error: {0}")] - 14
Io(#[from] std::io::Error), - 15
} - 16
- 17
fn git(repo: &Path, args: &[&str]) -> Result<String, WorktreeError> { - 18
let out = Command::new("git") - 19
.current_dir(repo) - 20
.args(args) - 21
.output() - 22
.map_err(WorktreeError::Io)?; - 23
if !out.status.success() { - 24
return Err(WorktreeError::Git( - 25
String::from_utf8_lossy(&out.stderr).trim().to_string(), - 26
)); - 27
} - 28
Ok(String::from_utf8_lossy(&out.stdout).trim().to_string()) - 29
} - 30
- 31
pub fn is_git_repo(cwd: &Path) -> bool { - 32
Command::new("git") - 33
.current_dir(cwd) - 34
.args(["rev-parse", "--is-inside-work-tree"]) - 35
.output() - 36
.map(|o| o.status.success()) - 37
.unwrap_or(false) - 38
} - 39
- 40
pub struct Worktree { - 41
pub path: PathBuf, - 42
pub branch: String, - 43
} - 44
- 45
/// Creates `.vak/worktrees/<run_id>` on branch `vak/<run_id>`. - 46
pub fn create(repo: &Path, run_id: &str) -> Result<Worktree, WorktreeError> { - 47
if !is_git_repo(repo) { - 48
return Err(WorktreeError::NotARepo); - 49
} - 50
let path = repo.join(".vak/worktrees").join(run_id); - 51
if let Some(parent) = path.parent() { - 52
std::fs::create_dir_all(parent)?; - 53
} - 54
let branch = format!("vak/{run_id}"); - 55
git( - 56
repo, - 57
&[ - 58
"worktree", - 59
"add", - 60
"-b", - 61
&branch, - 62
path.to_string_lossy().as_ref(), - 63
"HEAD", - 64
], - 65
)?; - 66
Ok(Worktree { path, branch }) - 67
} - 68
- 69
/// Removes the worktree and its branch (uncommitted changes are discarded — - 70
/// callers should surface that before calling). - 71
pub fn remove(repo: &Path, wt: &Worktree) -> Result<(), WorktreeError> { - 72
git( - 73
repo, - 74
&[ - 75
"worktree", - 76
"remove", - 77
"--force", - 78
wt.path.to_string_lossy().as_ref(), - 79
], - 80
)?; - 81
git(repo, &["branch", "-D", &wt.branch])?; - 82
Ok(()) - 83
} - 84
Indexing the workspace…
Vakyartha documentation is discovering safe artifacts, anchors, and source references.