Skip to content

Worktree

worktree

GitWorktreeTool — add, remove, and list git worktrees.

GitWorktreeTool

Bases: AXMTool

Add, remove, or list git worktrees.

Registered as git_worktree via axm.tools entry point.

Source code in packages/axm-git/src/axm_git/tools/worktree.py
Python
class GitWorktreeTool(AXMTool):
    """Add, remove, or list git worktrees.

    Registered as ``git_worktree`` via axm.tools entry point.
    """

    @property
    def name(self) -> str:
        """Tool name used for MCP registration."""
        return "git_worktree"

    def execute(  # type: ignore[override]
        self,
        *,
        action: str,
        path: str = ".",
        branch: str | None = None,
        base: str | None = None,
        force: bool = False,
        **kwargs: object,
    ) -> ToolResult:
        """Manage git worktrees.

        Args:
            action: One of ``add``, ``remove``, ``list``.
            path: For ``add``/``remove``: worktree path.
                  For ``list``: repository path.
            branch: Branch name for ``add`` action.
            base: Base ref for ``add`` (default: the repo's resolved
                  default branch).
            force: Force removal for ``remove`` action.

        Returns:
            ToolResult with worktree data on success.
        """
        resolved = Path(path).resolve()

        match action:
            case "list":
                return self._list(resolved)
            case "add":
                return self._add(
                    resolved,
                    branch=branch,
                    base=base or resolve_default_branch(resolved),
                )
            case "remove":
                return self._remove(resolved, force=force)
            case _:
                error = f"Invalid action {action!r}. Use 'add', 'remove', or 'list'."
                return ToolResult(
                    success=False,
                    error=error,
                    text=render_failure_text(error=error, data=None),
                )

    def _list(self, path: Path) -> ToolResult:
        """List all worktrees."""
        git_root = find_git_root(path)
        if git_root is None:
            return _not_a_repo_result(path)

        try:
            result = run_git(["worktree", "list", "--porcelain"], git_root)
        except subprocess.TimeoutExpired as exc:
            return timeout_error_result(exc)
        if result.returncode != 0:
            return _git_error_result(result)

        worktrees = _parse_worktree_porcelain(result.stdout)
        data: dict[str, object] = {"worktrees": worktrees}
        return ToolResult(success=True, data=data, text=render_list_text(data))

    def _add(
        self,
        path: Path,
        *,
        branch: str | None,
        base: str,
    ) -> ToolResult:
        """Add a new worktree."""
        git_root = find_git_root(path)
        if git_root is None:
            return _not_a_repo_result(path)

        cmd: list[str] = ["worktree", "add"]
        if branch:
            cmd.extend(["-b", branch])
        cmd.append(str(path))
        cmd.append(base)

        try:
            result = run_git(cmd, git_root)
        except subprocess.TimeoutExpired as exc:
            return timeout_error_result(exc)
        if result.returncode != 0:
            return _git_error_result(result)

        data: dict[str, object] = {
            "path": str(path),
            "branch": branch or base,
            "base": base,
        }
        return ToolResult(success=True, data=data, text=render_add_text(data))

    def _remove(self, path: Path, *, force: bool) -> ToolResult:
        """Remove an existing worktree."""
        git_root = find_git_root(path)
        if git_root is None:
            return _not_a_repo_result(path)

        cmd: list[str] = ["worktree", "remove", str(path)]
        if force:
            cmd.append("--force")

        try:
            result = run_git(cmd, git_root)
        except subprocess.TimeoutExpired as exc:
            return timeout_error_result(exc)
        if result.returncode != 0:
            return _git_error_result(result)

        data: dict[str, object] = {"removed": str(path)}
        return ToolResult(success=True, data=data, text=render_remove_text(data))
name property

Tool name used for MCP registration.

execute(*, action, path='.', branch=None, base=None, force=False, **kwargs)

Manage git worktrees.

Parameters:

Name Type Description Default
action str

One of add, remove, list.

required
path str

For add/remove: worktree path. For list: repository path.

'.'
branch str | None

Branch name for add action.

None
base str | None

Base ref for add (default: the repo's resolved default branch).

None
force bool

Force removal for remove action.

False

Returns:

Type Description
ToolResult

ToolResult with worktree data on success.

Source code in packages/axm-git/src/axm_git/tools/worktree.py
Python
def execute(  # type: ignore[override]
    self,
    *,
    action: str,
    path: str = ".",
    branch: str | None = None,
    base: str | None = None,
    force: bool = False,
    **kwargs: object,
) -> ToolResult:
    """Manage git worktrees.

    Args:
        action: One of ``add``, ``remove``, ``list``.
        path: For ``add``/``remove``: worktree path.
              For ``list``: repository path.
        branch: Branch name for ``add`` action.
        base: Base ref for ``add`` (default: the repo's resolved
              default branch).
        force: Force removal for ``remove`` action.

    Returns:
        ToolResult with worktree data on success.
    """
    resolved = Path(path).resolve()

    match action:
        case "list":
            return self._list(resolved)
        case "add":
            return self._add(
                resolved,
                branch=branch,
                base=base or resolve_default_branch(resolved),
            )
        case "remove":
            return self._remove(resolved, force=force)
        case _:
            error = f"Invalid action {action!r}. Use 'add', 'remove', or 'list'."
            return ToolResult(
                success=False,
                error=error,
                text=render_failure_text(error=error, data=None),
            )