其他语言: English, Español, Português, 日本語, Deutsch, Français, 한국어, Italiano, हिन्दी · 全部中文指南
声明:Carbon Forge 由 100monkeys.ai 开发,因此请把这篇指南当作开发方的说明来读。它由我们的一个 AI 智能体根据公开文档(英文)起草,主要是 Working in lanes 的第 6 到第 8 步和 Lanes 目录页,并经公司审阅;这个简体中文版是英文原版指南的译文。每个调用都是文档自己的示例,引文保留英文原文,译文附在旁边。文档没有回答的问题,最后一节会说明。
了解什么算冲突
lane 是覆盖在 trunk 之上的一组补丁,在它上面的每次读取,都是把 trunk 的现状和这些补丁组合起来。补丁处于冲突,是指 "when it no longer applies to the trunk: its old text no longer matches or matches twice"(它不再能应用到 trunk 上:它的旧文本不再匹配,或者匹配了两次),或者 trunk 改动了补丁所替换的树条目或库条目。仍然能应用的补丁不算冲突,即使 trunk 改了同一节;读取会把它报告为一个移动过的节,"worth a reviewer's look, not a conflict."(值得审阅者看一眼,但不是冲突。)两个智能体修改同一个文件的不同部分,两者都会落地。本指南其余部分遵循的规则是:"Nothing merges by itself."(没有什么会自己合并。)
发现某条 lane 处于冲突中
lanes.get 返回 landable,只有当 lane 是打开的、至少有一个有效补丁且没有冲突时它才为 true。在应用中,lane 的页面 /<workspace>/lanes/<label> 有一个 Conflicts 标签页。不想轮询的话,当 trunk 上的一次落地首次让 lane 进入冲突时,lane.conflict webhook 事件会写明这条 lane 以及它冲突行的路径。
阅读冲突
lanes.conflicts { "label": "agent/7/fix-login" } 每一行都带着合并者需要的东西:补丁本身;补丁生成时该节的样子;trunk 上该节现在的样子;lane 组合后的视图;以及移动了它的 changeset,每个都带有 intent、执行者和落地它的 lane。对代码树,该行还会附上每个冲突文件的统一 diff;对有语法的语言,还会附上一份不同的顶层定义的参考列表,它 "decides nothing"(什么也不决定)。这个工具只读,只需要 viewer 角色。在应用中,Conflicts 标签页显示 trunk 文本和 lane 文本,以及回答每一项的确切调用,"ready to copy, while the page itself decides nothing."(可以直接复制,而页面本身什么也不决定。)
回答文本冲突
lanes.resolve { "patch_id": "…", "note": "kept both sign-in options", "old_string": "…", "new_string": "…" } 回答是一个新补丁,附带 1 到 1,024 个字符的说明,写明原因。它 "matched against the trunk as it stands now and bound to the hash of that state."(与 trunk 的现状匹配,并绑定到该状态的哈希。)旧补丁作为历史保留,标记为 superseded。树冲突用同样的方式回答,使用 upserts、removals 或 patches;库条目则用 sha256。按顺序回答:同一实体上较晚的补丁要等较早的那个解决之后。
或者丢弃补丁
lanes.drop_patch { "patch_id": "…" } 当 trunk 已经做了补丁想做的事,或者补丁不再需要时,就把它丢弃。如果补丁所针对的实体已经不存在,文档的拒绝信息会让你丢弃补丁,而不是解决它。
回答移动冲突
lanes.resolve { "patch_id": "…", "note": "kept the trunk's rename and moved on from it", "to_path": "guides/sign-in" } 重命名页面的 lane 会在以下情况下冲突:trunk 之后也移动了同一个页面,trunk 现在占用了新路径,或者页面已不存在。用 to_path 回答,标题需要改变时再加 title。解决方案绑定到 trunk 现在的路径,所以之后 trunk 的移动也会让它过时。
回答组装工作中的冲突
lanes.merge { "from": "agent/8/tests", "into": "agent/7/fix-login", "intent": "assemble the login fix" } 主导智能体在落地前把几个智能体的 lane 汇集到一条里。以这种方式带过来的补丁,在接收方 lane 改动了它所改动的内容时会冲突,lanes.conflicts 会以 moved_by 写明它现在所依赖的接收方 lane 的较早补丁。它的解决方案回答的是接收方 lane 的视图,而不只是 trunk。
落地,先做一次 dry run
lanes.land { "label": "agent/7/fix-login", "intent": "fix: accept magic links", "dry_run": true }
lanes.land { "label": "agent/7/fix-login", "intent": "fix: accept magic links" } 落地会在它自己的事务中再次检查,只要有任何东西移动过,就整体拒绝,并写明每个冲突。一个解决方案回答的是 trunk 的一个确切状态;如果 trunk 在落地前移动了那一节,解决方案就会过时,落地会被拒绝,信息是:
resolution <id> was resolved against <hash>; the trunk's section is now <hash> 这时重新读取 lanes.conflicts,回答新的状态。在带有落地规则的受保护 trunk 上,记住批准之后的任何解决方案都会让那些批准 "count for nothing"(全部作废),所以批准要在最后一次回答之后。带上 idempotency_key 发送落地请求,超时后的重试会返回第一次落地的结果,而不会落地两次。
如果一条 lane 同时带着代码修改和它的文档,请阅读我们的指南 把一次代码修改和它的文档放进同一个 changeset 落地。
文档没有回答的问题
- 无法找回基础节时该怎么办。冲突行最多往回查 200 个修订来找它,否则报告
unknown;文档没有说从那里如何回答。 dry_run落地返回什么。指南给出了调用,但没有给出它的响应。lane.conflict事件除了 lane 和路径之外还带有什么。