Skip to content

Anthropic built Scion for itself. Carbon Forge is yours →

Carbon Forge
Menu

指南

把一次代码修改和它的文档放进同一个 changeset 落地

一次代码修改和描述它的页面在同一个 changeset 中落地,要么一起,要么都不。本指南带着这样一次修改,从开一条 lane 走到一次落地。

其他语言: English, Español, Português, 日本語, Deutsch, Français, 한국어, Italiano, हिन्दी · 全部中文指南

声明:Carbon Forge 由 100monkeys.ai 开发,因此请把这篇指南当作开发方的说明来读。它由我们的一个 AI 智能体根据公开文档(英文)起草,主要是 Working in lanes 和 Code and files on the substrate,并经公司审阅;这个简体中文版是英文原版指南的译文。下面的每个调用都是文档自己的示例,引文保留英文原文,译文附在旁边。文档没有回答的问题,最后一节会说明。

为什么是一个 changeset

文档首页这样定义这个单位:"A changeset is many writes landed as one: every page, atom, code tree and library entry it names is written in one transaction under one intent, the changeset's intent, or nothing is written"(changeset 是作为一个整体落地的多次写入:它指定的每个页面、atom、代码树和库条目,都在同一个 intent,即 changeset 的 intent 下,在一个事务中写入,否则什么都不写入)(Welcome to Carbon)。代码和文字是同一份记录中的实体,所以读者不会在新代码旁边看到旧页面,回退也会把两者一起退回。

你需要一个能写 lane 和代码树的令牌;文档为这类工作指定的预设是 SCM agent。

第 1 步:弄清 trunk 是否受保护

workspaces.get_settings {}
→ { "workspaceId": "…", "trunkProtected": true, "trunkProtectedEntities": false }

"With trunkProtected, code trees, library entries and changesets go through a lane; with trunkProtectedEntities as well, page and atom edits do too."(开启 trunkProtected 时,代码树、库条目和 changeset 要经过 lane;再开启 trunkProtectedEntities 时,页面和 atom 的编辑也一样。)无论哪种情况,这里用 lane 都合适:文档在 "a change should be seen whole before it lands"(一次修改应在落地前被完整看到)时使用 lane。

第 2 步:为这次修改开一条 lane

lanes.create { "label": "agent/7/fix-login" }

标签由斜杠分隔的小写段组成,在打开的 lane 中唯一。"A lane costs nothing to open and holds no copy, so one per task, or one per agent, is the expected use."(开一条 lane 没有成本,也不持有副本,所以每个任务或每个智能体一条,是预期的用法。)传入 owner,这条 lane 的写入、冲突解决和落地就只归你。

第 3 步:在 lane 上修改代码

trees.apply_patch { "path": "app", "operations": [ { "op": "patch", "entry_path": "src/login.ts", "old_string": "password", "new_string": "magicLink" } ], "intent": "fix: accept magic links", "lane": "agent/7/fix-login" }

把标签作为 lane 传入,"the write is held on the lane as a patch against the trunk"(写入作为针对 trunk 的补丁保存在 lane 上),"the trunk is not written"(trunk 不会被写入)。trees.apply_patch 只发送操作(文件内替换、写入、删除或移动);trees.put 发送代码树的完整条目列表。无论哪种,"the lane keeps only what differs."(lane 只保存不同的部分。)

第 4 步:在同一条 lane 上修改描述它的页面

pages.apply_patch { "pathOrId": "guides/login", "old_string": "Sign in with a password.", "new_string": "Sign in with a magic link.", "lane": "agent/7/fix-login" }

标签相同,所以页面编辑就在代码旁边等待。如果这次修改还要给页面改名,pages.move 也接受 lane,而且 "a rename belongs to the change that needs it."(改名属于需要它的那次修改。)截图也以同样方式,用 library.put_at_path 加上标签放进去。

第 5 步:读出这条 lane 会产生的结果

在读取时传入同一个 lane,"the answer is the trunk as it stands now with the lane's patches applied, composed on the call"(返回的是当前的 trunk 加上 lane 的补丁,在调用时组合而成):页面用 pages.read,代码用 trees.get、trees.diff 或 trees.grep。然后审阅整体:

lanes.diff { "label": "agent/7/fix-login" }
lanes.get { "label": "agent/7/fix-login" }

lanes.diff 返回 "entity by entity, the trunk's section and the lane's"(逐个实体,trunk 的段落和 lane 的段落);lanes.get 返回补丁、冲突和 landable:"open, at least one live patch, no conflict."(处于打开状态,至少有一个有效补丁,没有冲突。)在应用中,/<workspace>/lanes/<label> 显示同样的内容,每个改动的文本文件以 unified diff 显示。读过 lanes.export 并在其 composition 哈希上批准的审阅者,"has approved exactly that change."(批准的正是那一次修改。)

第 6 步:回应冲突

如果这期间有人在 trunk 上改了页面或文件的同一行,补丁就处于冲突状态,而且 "nothing merges by itself."(没有任何东西会自行合并。)lanes.conflicts 给出补丁、原来的段落、trunk 现在的段落,以及改动它的 changeset。用 lanes.resolve 回应,或用 lanes.drop_patch 丢弃补丁。文件内的替换会 "replays on the trunk's current file, so two agents changing different parts of one file both land."(在 trunk 当前的文件上重放,所以修改同一文件不同部分的两个智能体都能落地。)

第 7 步:带着 intent 一次落地

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" }

先运行 dry run,再落地。"Every live patch is replayed as one changeset whose intent is lane agent/7/fix-login: fix: accept magic links"(每个有效补丁被重放为一个 intent 为 lane agent/7/fix-login: fix: accept magic links 的 changeset),在它自己的事务中再次检查,并且 "refused whole, with every conflict named, if anything moved."(只要有任何东西变动,就整体拒绝,并点名每个冲突。)让 intent 以 feat、fix、docs、chore 或 revert 开头,发布说明就会按这个词归类。发送 idempotency_key,超时后的重试会 "answers the first landing's result instead of landing twice."(返回第一次落地的结果,而不是落地两次。)

第 8 步:回读这次落地

打开 /<workspace>/changes/<id>:它显示完整的 intent、执行者、来源 lane、封印和各个条目,代码文件和页面在一起。改动行上的 blame 现在会给出你写的 intent:trees.blame 给出 "each line's revision, changeset, intent, actor and landing lane"(每一行的修订、changeset、intent、执行者和落地 lane)(Code and files)。要一次撤销两者,changesets.revert 会写入一个新的 changeset,恢复这次落地写过的每个实体。

文档没有回答的问题

相关指南

让代码和文档一起落地。