什么是 Git Worktree

Git Worktree 是 Git 2.5 版本引入的一项强大功能,它允许用户在同一个仓库中同时检出多个工作目录。每个 worktree 拥有独立的工作区和暂存区,但共享同一个 .git 对象数据库。这意味着你可以在不切换分支的情况下,同时在多个分支上进行开发工作。

传统的 Git 工作流要求开发者在单一工作目录中通过 git checkoutgit switch 切换分支。这种方式存在明显的局限性:切换分支会导致当前未提交的更改丢失或产生冲突,编辑器中打开的文件需要重新加载,构建缓存可能失效。Worktree 通过创建完全独立的目录结构来解决这些问题。

PinableAgents 充分利用了这一机制,将每个智能体任务隔离在独立的 worktree 中执行。这样做的核心优势在于:即使智能体的代码生成出现错误,也不会影响主工作目录中的任何文件。

为什么需要隔离机制

在 AI 辅助编程的场景中,隔离机制的重要性远超传统开发。智能体生成的代码具有不确定性,一次看似合理的重构可能引入难以察觉的 bug,一次数据库迁移脚本可能破坏现有数据结构。如果这些操作直接在主工作目录中执行,回退代价将非常高昂。

PinableAgents 的隔离策略遵循三个核心原则:

  • 零污染原则:任何智能体的操作都不会修改主工作目录中的任何文件,直到用户明确批准合并。
  • 可审查原则:每个 worktree 中的变更都以标准的 Git diff 形式呈现,用户可以逐行审查每个修改。
  • 可回滚原则:任何阶段都可以一键丢弃 worktree,恢复到任务开始前的状态,没有任何副作用。

将智能体视为一个不可完全信任的协作者。它可能写出优秀的代码,也可能犯错。Worktree 隔离确保你始终保有最终决定权。

Worktree 生命周期

PinableAgents 中的 worktree 遵循严格的四阶段生命周期管理:创建 → 执行 → 验证 → 合并/丢弃。每个阶段都有明确的入口条件和出口条件。

阶段一:创建(Create)

当用户触发一个工作流任务时,编排引擎首先在配置的基础路径下创建一个新的 worktree。分支命名遵循 pinable/<workflow>/<timestamp> 的格式,确保唯一性和可追溯性。

# 内部执行的创建流程
git worktree add ../worktrees/pinable-do-20260225-143022 -b pinable/do/20260225-143022
cd ../worktrees/pinable-do-20260225-143022

阶段二:执行(Execute)

智能体在 worktree 目录中执行所有代码生成和修改操作。此阶段中,智能体可以自由地创建文件、修改代码、运行测试,所有变更都被限制在这个隔离的目录中。编排引擎会实时监控文件变更,并记录到执行日志中。

阶段三:验证(Validate)

执行完成后,系统自动运行一系列验证检查。这些检查包括:语法检查(linting)、单元测试、类型检查以及用户自定义的验证脚本。只有当所有检查通过时,才会进入下一阶段。

阶段四:合并或丢弃(Merge / Discard)

验证通过后,用户可以选择将变更合并回主分支或丢弃整个 worktree。合并操作使用 git merge --no-ff 策略,确保保留完整的分支历史。丢弃操作则清理 worktree 目录和对应的分支引用。

失败时的自动回滚

当验证阶段检测到失败时,PinableAgents 提供两种回滚策略:

策略 行为 适用场景
auto-discard 自动删除 worktree 和分支,不保留任何痕迹 快速迭代、试探性变更
preserve-on-fail 保留 worktree 目录但标记为失败状态,供后续调查 复杂任务调试、问题分析

自动回滚的触发条件包括:测试失败、编译错误、智能体执行超时、以及用户定义的自定义失败条件。回滚操作是原子性的,要么完全回退要么完全不执行,不会留下半完成状态。

# 自动回滚时的内部操作
git worktree remove ../worktrees/pinable-do-20260225-143022 --force
git branch -D pinable/do/20260225-143022
# 日志记录:[ROLLBACK] Task do-20260225-143022 failed validation, worktree removed

配置选项详解

Worktree 隔离行为可以通过 config.json 中的 worktree 字段进行细粒度配置。

{
  "worktree": {
    "base_path": "../.pinable-worktrees",
    "branch_prefix": "pinable",
    "cleanup_policy": "auto-discard",
    "max_parallel": 4,
    "ttl_hours": 48,
    "preserve_on_fail": true,
    "merge_strategy": "no-ff",
    "pre_merge_hooks": ["npm test", "npm run lint"],
    "post_merge_hooks": ["npm run build"]
  }
}
配置项 类型 默认值 说明
base_path string ../.pinable-worktrees Worktree 目录的基础路径,相对于项目根目录
branch_prefix string pinable 自动创建的分支名前缀
cleanup_policy string auto-discard 清理策略:auto-discard 或 preserve-on-fail
max_parallel number 4 允许同时存在的最大 worktree 数量
ttl_hours number 48 未操作的 worktree 自动清理时间(小时)
merge_strategy string no-ff 合并策略:no-ff(保留分支历史)或 squash(压缩提交)

并行 Worktree 与并发任务

PinableAgents 支持同时运行多个 worktree,每个处理独立的任务。这在团队协作或复杂项目中尤其有用。例如,一个智能体在 worktree A 中进行前端组件开发,同时另一个智能体在 worktree B 中编写对应的 API 端点。

并行 worktree 的管理涉及几个关键问题:

  • 资源限制:通过 max_parallel 配置项限制同时存在的 worktree 数量,防止磁盘空间耗尽。
  • 锁管理:Git 内部使用锁文件防止对同一分支的并发操作。PinableAgents 在创建 worktree 前会检查锁状态,避免冲突。
  • 合并顺序:当多个 worktree 同时完成时,系统按照任务优先级和完成时间排定合并顺序,避免合并冲突累积。
# 查看当前活跃的所有 worktree
pinable-agents worktree list

# 输出示例:
# ID                          分支                              状态     创建时间
# do-20260225-143022          pinable/do/20260225-143022        执行中   14:30
# omo-20260225-144510         pinable/omo/20260225-144510       验证中   14:45
# do-20260225-150000          pinable/do/20260225-150000        等待中   15:00

合并回主分支时的冲突解决

当 worktree 中的变更与主分支产生冲突时,PinableAgents 提供三种冲突解决策略:

  1. 交互式解决:系统暂停合并流程,在桌面端展示冲突文件的 diff 视图,由用户手动选择保留哪些变更。这是默认策略。
  2. 智能体辅助:将冲突信息交给专门的代码审查智能体,由其分析冲突上下文并提出解决方案。用户审核后确认。
  3. 自动放弃:当冲突超过设定阈值(默认 5 个文件)时,自动丢弃 worktree 并通知用户重新发起任务。
# 冲突解决的配置
{
  "worktree": {
    "conflict_strategy": "interactive",
    "conflict_threshold": 5,
    "allow_agent_resolve": true
  }
}

实战示例:数据库 Schema 变更

假设你需要让智能体为一个 PostgreSQL 数据库添加新的用户权限表。这是一个高风险操作,因为错误的迁移脚本可能破坏现有数据。以下是使用 worktree 隔离的完整流程:

# 步骤 1:发起任务,系统自动创建 worktree
pinable-agents run do --task "创建 user_permissions 表并编写迁移脚本"

# 步骤 2:智能体在隔离的 worktree 中工作
# - 生成迁移文件 migrations/20260225_add_user_permissions.sql
# - 修改 models/user.go 添加权限关联
# - 编写对应的单元测试

# 步骤 3:自动验证阶段
# - 运行 go build 确认编译通过
# - 运行 go test ./... 确认测试通过
# - 执行 sqlc generate 确认 SQL 语法正确

# 步骤 4:用户审查
pinable-agents worktree diff do-20260225-143022
# 审查通过后合并
pinable-agents worktree merge do-20260225-143022

如果迁移脚本存在语法错误,验证阶段会自动捕获并触发回滚。整个过程中,你的主分支和数据库保持完全不变。

内部使用的 Git 命令

了解 PinableAgents 在底层使用的 Git 命令有助于排查问题和理解运行机制。以下是核心命令清单:

# 创建 worktree
git worktree add <path> -b <branch-name>

# 列出所有 worktree
git worktree list --porcelain

# 移除 worktree
git worktree remove <path> [--force]

# 修剪失效的 worktree 引用
git worktree prune

# 合并 worktree 分支
git merge --no-ff <branch-name> -m "Merge pinable task: <description>"

# 清理分支引用
git branch -d <branch-name>

如果你在使用过程中遇到 worktree 锁定问题,可以运行 git worktree prune 清理失效引用,然后重试。

Worktree 管理最佳实践

经过大量实际项目验证,以下是 worktree 隔离的推荐实践:

  • 设置合理的 TTL:对于快速迭代项目,建议将 ttl_hours 设为 24 小时。对于大型项目,可以延长到 72 小时。过长的 TTL 会浪费磁盘空间。
  • 使用 squash 合并策略:对于小型变更,使用 squash 策略可以保持主分支提交历史的整洁。对于大型特性开发,使用 no-ff 保留完整的开发历程。
  • 定期运行 prune:每周运行 pinable-agents worktree prune 清理失效的 worktree 引用和孤立的分支。
  • 监控磁盘空间:每个 worktree 是主仓库的完整工作副本。对于大型仓库,注意 max_parallel 的设置,避免磁盘空间耗尽。
  • 将 worktree 目录加入 .gitignore:在 .gitignore 中添加 .pinable-worktrees/,防止 worktree 目录被意外提交。
  • 使用 pre_merge_hooks:配置合并前的验证钩子,确保合并到主分支的代码始终通过完整的质量检查。

遵循这些实践,你可以在享受 AI 辅助编程便利性的同时,确保代码库的安全性和完整性。Worktree 隔离是 PinableAgents 安全执行哲学的基石。