Skip to main content

WorktreeManager

Struct WorktreeManager 

Source
pub struct WorktreeManager<R: GitRunner> { /* private fields */ }
Expand description

Manages the full lifecycle of per-subagent git worktrees.

WorktreeManager is parameterised over a GitRunner so that unit tests can inject a FakeGitRunner (defined in the test module) without touching the file system. Production code uses DefaultWorktreeManager.

§Concurrency

The internal handle list is guarded by a std::sync::Mutex. All methods acquire this lock for the minimum necessary duration — they never hold the lock across an .await on an external resource.

§TODO

TODO(critic D1): concurrent per-agent cwd isolation requires child-process bgIsolation or full ToolExecutor cwd-threading; in-process MVP is concurrency-1 only.

Implementations§

Source§

impl<R: GitRunner> WorktreeManager<R>

Source

pub fn new( repo_root: PathBuf, config: WorktreeConfig, runner: R, ) -> Result<Self, WorktreeError>

Creates a new manager, validating the repository root and canonicalising the worktree root directory.

The worktree root directory is created if it does not yet exist.

§Errors
§Examples
use std::path::PathBuf;
use zeph_config::WorktreeConfig;
use zeph_worktree::{DefaultWorktreeManager, git_runner::DefaultGitRunner};

let mgr = DefaultWorktreeManager::new(
    PathBuf::from("/path/to/repo"),
    WorktreeConfig::default(),
    DefaultGitRunner::new(),
)?;
Source

pub fn repo_root(&self) -> &Path

Returns the repository root this manager was constructed with.

Source

pub async fn create( &self, subagent_id: &str, ) -> Result<WorktreeHandle, WorktreeError>

Creates a new worktree for subagent_id according to the configured base_ref strategy.

The branch name is "{branch_prefix}{subagent_id}". The path on disk is "{root}/{subagent_id}".

§TODO

TODO(critic D2): head worktree does not include parent uncommitted changes by design; revisit if users need stash-based propagation.

§Errors
§Examples
let handle = mgr.create("agent-42").await?;
println!("Worktree at {:?} on branch {}", handle.path, handle.branch_name);
Source

pub async fn remove( &self, handle: &WorktreeHandle, prune_branch: bool, ) -> Result<(), WorktreeError>

Removes the worktree identified by handle.

If prune_branch is true, also deletes the git branch after removing the worktree directory.

§Errors

Returns WorktreeError::GitCommand if either git command fails.

§Examples
mgr.remove(&handle, false).await?;
Source

pub fn list(&self) -> Vec<WorktreeHandle>

Returns a snapshot of the in-memory handle list for the current session.

This list only contains worktrees created in the current process. To discover worktrees that exist in the git registry but not in memory (e.g. after a crash), use reconcile.

§Examples
let handles = mgr.list();
println!("{} active worktrees", handles.len());
Source

pub async fn reconcile(&self) -> Result<Vec<WorktreeHandle>, WorktreeError>

Reads the git worktree registry and returns handles for worktrees that exist on disk but are not in the current session’s in-memory list.

This is used at startup (and via worktree clean) to recover from a previous crash that left stale worktrees behind.

§Errors

Returns WorktreeError::GitCommand if git worktree list fails.

§Examples
let stale = mgr.reconcile().await?;
for h in &stale {
    println!("stale worktree: {:?}", h.path);
}

Auto Trait Implementations§

§

impl<R> !Freeze for WorktreeManager<R>

§

impl<R> RefUnwindSafe for WorktreeManager<R>
where R: RefUnwindSafe,

§

impl<R> Send for WorktreeManager<R>

§

impl<R> Sync for WorktreeManager<R>

§

impl<R> Unpin for WorktreeManager<R>
where R: Unpin,

§

impl<R> UnsafeUnpin for WorktreeManager<R>
where R: UnsafeUnpin,

§

impl<R> UnwindSafe for WorktreeManager<R>
where R: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more