
no-mistakes 分支同步与推送安全机制深度解析guarded sync、custody recovery 与 force-push 数据保全【免费下载链接】no-mistakesgit push no-mistakes项目地址: https://gitcode.com/GitHub_Trending/no/no-mistakes本篇技术指南聚焦 no-mistakes 项目内部的branch-sync-and-push-safety技能契约见 .agents/skills/branch-sync-and-push-safety/SKILL.md系统讲解其在 AI 驱动 pipeline 场景下的三条安全主线本地分支与远程的受保护同步、Review 之后头部连续性与推送绑定、以及 rebase 基线与 force-push 的数据丢失防护。读完你将理解no-mistakes axi sync一族命令背后的状态机、--recover的精确归还语义以及resolveForcePushDecision如何从根上避免静默丢弃他人代码。一、整体架构一个服务、三种入口sync、axi sync与 TUI 的u动作共享同一个internal/branchsync服务其核心契约在 internal/branchsync/sync.go 中实现唯一的普通 worktree 变更方式一次干净的、受保护的移动——要么是 behind 分支上的严格快进strict fast-forward要么是锚定后重置anchored reset到内容等价的 diverged pipeline 头部前提是本地独有提交已被 pipeline 头部完整承载。被动检查永不联网InspectCached由 CLI/TUI/axi status 渲染只读取本地 Git、持久化 provenance 与只读的 gate 祖先证据绝不 fetch、绝不改动 refs/index/worktree。阻塞状态永不破坏性操作被阻塞的分支状态如blocked_pipeline_owned、blocked_diverged下服务绝不执行 reset、stash、merge、rebase、force、switch、delete 或对外部 remote 的 update。Service结构体sync.go同时暴露了两个可替换的 remote 操作 seamlsRemote/fetchRemote使测试可以在不污染全局状态的前提下注入受控 fake。二、核心状态机状态、关系与安全等级同步契约由三组常量描述它们是 CLI、AXI、TUI 三套展示层的共同语言分支状态State见 sync.go状态含义pipeline_ownedpipeline 正在/曾持有分支头部已移动但未成功推送禁止本地后续提交push_in_progresspush 步骤正在执行behind本地落后于 pipeline 推送绑定synchronized本地与推送绑定完全一致local_ahead本地领先建议走axi run而非同步diverged双方分叉dirtyworktree 不干净remote_advanced/remote_rewritten远端包含绑定之外的提交 / 远端不再等于绑定remote_missing远端分支不存在merged_remote_retained/merged_remote_removedPR 已合并分支保留 / 已被清理closedPR 已关闭offline网络操作失败fail closedtarget_changed推送目标配置被改动ambiguous_context上下文无法唯一判定legacy_unbound无精确推送绑定custody_returned滞留 run 的 custody 已归还user_ownedrun 终止于提交头未移动之前分支本就属于操作者关系Relationsync.goequal、behind、ahead、diverged、unknown。安全等级Safetysync.go仅两种等级允许Apply落地——safe_fast_forward与safe_equivalent_advance见CanApply。三、Refresh 与 Apply只做干净的受保护移动3.1 单操作网络超时预算branch_sync_remote_timeoutRefresh中每次网络 remote 操作都使用从调用方 ctx 派生的独立有界子上下文而不是共享同一个 deadlinesync.go一次慢但成功的git.LsRemote绝不能偷走随后git.FetchRemoteBranchToPrivateRef的预算否则一个可达的远端会被误判为 offline。Apply的最终 live 检查也使用相同的单操作预算。该预算即Service.RemoteTimeoutsync.go只来自操作者全局配置branch_sync_remote_timeout默认值为config.DefaultBranchSyncRemoteTimeout60s见 internal/config/config.go。关键设计点RepoConfig故意没有对应字段——一个被推送进仓库的.no-mistakes.yaml不能通过修改配置来放宽或收紧服务等待网络多久从而防止仓库内容操纵超时预算相关回归测试见TestLoadRepo_BranchSyncRemoteTimeoutIsNotARepoSetting。注意Recover的本地 gate fetch 属于本地仓库间操作不在此网络 deadline 契约内。3.2 Refresh先验证再移动Refresh的流程sync.go可概括为本地检视 → 数据库绑定复检run、generation、pushed head、target fingerprint/kind/ref 全部一致否则blocked_binding_changed→ 带独立超时的ls-remote→ 带独立超时的 fetch 到私有 refrefs/no-mistakes/sync/run→ 校验 fetched live → 校验 live 持久化的 pushed head → 再按 PR 生命周期merged/closed或关系分类落定。它从不更新普通的 remote-tracking ref只把精确的推送 ref 验证进 no-mistakes 私有 ref。3.3 Applyapply 前的多重复检 fail-closed 的两种移动Applysync.go在真正移动之前要连续通过多层防线gate 执行上下文拒绝检查gateContextRefusal防止在 gate 自身的嵌套执行环境里误操作Refresh重新出计划且CanApply必须为真数据库 push binding 复检run、pushed head、generation、ref、target fingerprint/kindinspect复检本地分支/HEAD/cleanliness 未变带超时的最终 livels-remote要求 live pushed head最终前提复检blocked_assumptions_changed关系证明复检equivalent advance 重新执行equivalentDivergence普通快进重新验证祖先关系。移动本身分两种严格快进git merge --ff-only --no-edit pushed由 Git 自身保证不会覆盖未落地的本地工作等价 diverged 推进先把同步前本地 HEAD 锚定到refs/no-mistakes/sync-anchor/run并校验再reset --hard到验证过的 pipeline 头部。成功后还会检查 post-apply 的 worktree 是否仍干净防止 hook 留下脏状态最终才置为synchronized。成功推送的持久化绑定由 internal/pipeline/steps/push.go 写入精确 SHA、免凭据的目标指纹branchsync.TargetFingerprint对 URL 做规范化 sha256见 sync.go、ref 与 generation历史遗留行的可空字段永远不允许从可变的head_sha反推 provenance。结构化的 PR 生命周期merged/closed会退役对应分支。四、Terminal run 的 custody recovery把滞留的分支精确归还当一个 run 进入 TERMINAL 状态且存在未发布的 pipeline 提交moved head时分支被 pipeline 托管却再也不会被发布——必须有一个显式的受保护出口。这就是--recover。4.1 决策矩阵Recover的完整决策矩阵与 fail-safe 规则写在 sync.go 的 doc comment 中P 指 preserved pipeline head即 terminal 验证过的 run head由私有 recovery ref 固定relationworktree默认行为--keep-localequalany本地锚定归还 custody相同aheadany本地锚定归还 custody相同behindclean严格快进到 P归还 custodycustody 留在本地 headgate 以 CAS 重置到它behinddirty拒绝先 commit/stash同上diverged 且 P 含全部本地工作clean锚定 pre-recovery 本地 head 后 fail-closed 移动到 P归还 custody同上diverged 且 P 含全部本地工作dirty拒绝先 commit/stash同上diverged 且 P 不含全部本地工作any拒绝锚定并人工协调 / 受保护 rerun同上P 缺失any拒绝同上4.2 三种基础场景取消且 head 未移动user_ownedTERMINAL run 若从未改变提交头head_sha submitted_head_sha无 push、无 custody 戳选择逻辑会保留它可见避免误报为blocked_wrong_branch并分类为user_owned——无next_action、非阻塞退出、永不表述为可恢复的 custody--recover在此是幂等 no-op不修改任何文件、ref 或数据库行新的axi run或单独授权的直接 push 永不被阻塞见 sync.go。本地可达equal/ahead本地锚定即可不需要 gate 访问但若 gate 可用其既有 recovery ref 必须与记录 head 一致。本地不可达behind/diverged从 run 专属的 gate recovery ref 验证并 fetch preserved head只有干净的 behind worktree 才会被快进。terminalization 固化pipeline 在移除托管 worktree 之前会把每个已验证的未发布 head 固定到refs/no-mistakes/recover/run见 internal/custody/refs.go。恢复时读取该 run 专属 ref 而非要求 gate 分支匹配因此 abort、rebase、pre-push 失败都保持可恢复同时独立移动的 gate 分支不受影响。历史遗留的记录 head 若仍以 dangling gate 对象存在会在恢复时被锚定。4.3preservedContainsLocalWork内容包含性证明而非 patch-id被取消的验证经常留下一个本地分支的 rebase作为 preserved head——同样的逻辑提交换了新 SHAequality 与 ancestry 只能读出分叉。此时干净的 diverged worktree 只有在preservedContainsLocalWork证明P 已包含本地全部变更时才会被采纳sync.go证明方式是可执行的git merge-tree三方合并以merge-base为唯一可靠锚点绝不使用runs.base_sha——那是上一个 gate head对重新推送过的分支会携带本地从未有过的 pipeline 提交将本地分支合并进 preserved head要求结果树恰好等于preserved head 的树它刻意不使用 patch identitypatch ID 丢弃 hunk 位置与空白无法区分真正的重放与对另一个相同代码块的同形状编辑基于它的包含性断言不构成证明一切无法判定的情况都升级处理包括 rebase 的修复轮同时改写了操作者的行——此时没有任何东西能区分有意的 pipeline 修复与被丢弃的改动由操作者决定fail-safe 优先于便利。4.4recoverAdoptPreserved自带守卫的原子移动采纳adopt路径先把 pre-recovery 本地 head 锚定到refs/no-mistakes/recover-local/run然后用 Git 操作自带的失败语义移动分支sync.gogit update-ref branch preserved observed原子 CAS并发提交移动了分支则整体拒绝、零副作用git read-tree -m -u observed preserved拒绝覆盖被修改或未跟踪的工作树文件若拒绝分支通过反向 CAS 回滚。这绝不是先观察再reset --hard的 check-then-act——后者会摧毁观察与执行之间的空隙里落地的一切。doc comment 还明确记录了一个已知的有界 Git 根本限制两条命令之间的并发 checkout 窗口但它不会造成数据丢失包含性证明在移动前已完成、pre-recovery head 保持锚定、custody 永不盖章操作 fail-closed 为报告失败而非虚假成功。4.5--keep-local显式丢弃未发布提交的唯一出口当操作者选择保留 behind/diverged 的本地 head 而不是采纳 preserved head 时--keep-localsync.go绝不触碰 worktree以原子 CAS 把 gate 分支移动到保留的本地 head并发 gate push 获胜则恢复拒绝通过gate 侧的 fetch暂存对象refs/no-mistakes/custody-return/run——绝不是 push因为 push 会触发 gate 的 receive hook 并启动一个新的 pipeline run独立移动过的 gate head 先被固定到refs/no-mistakes/recover-gate/runCAS 永不丢弃它。对于已验证的 recorded head 同时不存在于 worktree 与可访问 gate的场景--recover --keep-local是操作者显式丢弃未发布 pipeline 提交的唯一路径不可验证的 head、不可访问的 gate、冲突的 ref 一律保留人工协调普通--recover仍拒绝。4.6recovery_archives追加式归档的窄路径一个 diverged 的较新 head 还可以通过恰好一条追加式recovery_archives数据库绑定来证明被保存但前提是它的 repository、run、branch、required/preserved heads、原始 archive ref 与 gate recovery ref全部重新验证通过见 sync.go。recoverySourceAvailable是唯一的发现/分类 owner且只提供recover_custody--recover --keep-local——归档 head永远不会被选中作为工作结果。任何类似的未绑定 ref、stale、moved、symbolic、malformed、跨库、歧义记录都 fail closed。五、评审后头部连续性与推送绑定5.1assertPipelineHeadContinuity每个后评审步骤的入口守卫固定 pipeline 顺序Test、Document、Lint、Push、PR、CI中 Review 之后的每一个步骤都在入口调用assertPipelineHeadContinuityinternal/pipeline/steps/common_fix.go它是该语义的唯一 owner比较的是记录的 headsctx.Run.HeadSHA由 daemon 进程内 Run 结构持有、仅由 no-mistakes 的 commit 代码推进与实时的 worktree HEADgit.HeadSHA绝不从可变 worktree 反推锚点否则就是循环且可被击败equal 或 descendant 的 live head 继续backward、sibling旁支与不可验证的 head 在步骤做任何工作之前失败——例如并发的git reset把共享 worktree 拨到丢失已评审提交的旁支文档步骤就不会在 clobber 之上再提交并发布。5.2review_approved_head_sha可验证的不可变推送绑定一次成功完成的完整评审会原子地记录runs.review_approved_head_shaparked、failed、skipped 与历史遗留的评审不携带任何推断的授权。Push 步骤读取这份持久绑定只允许推送恰好该提交或其后代并推送已验证的不可变 SHA而非可变的HEADinternal/pipeline/steps/push.go。任何情况下都不得从runs.head_sha、worktree、gate ref 或远端分支推断评审授权。若评审批准 head 与待推 head 之间失去连续性非 equal/非 descendantassertReviewApprovedPushHead直接拒绝发布——CI 修复路径的处理方式是重新验证而不是绕过发布。六、rebase 基线与 force-push 安全数据丢失防护这个工具存在的全部意义就是不弄丢用户的代码宁可拒绝推送并暴露 finding也不用任何聪明的恢复来冒险完整论证见 internal/pipeline/steps/forcepush.go 的注释。6.1 rebase 基线只来自新鲜权威 refrebase 基线只来自刚 fetch 的权威远端 ref绝不使用本地或陈旧状态。同时构建在未推送的本地默认分支提交之上的分支会以NeedsApprovalAutoFixablefalse暂停detectBundledLocalDefaultCommits#283而不是静默扩大 PR 范围。6.2resolveForcePushDecision唯一的 force-push 路由每一次 force-push 都经过resolveForcePushDecisionforcepush.go它重新读取live 远端 head仅在以下情况放行远端分支不存在newBranch普通 push远端已等于要推的 headupToDate无需推送远端未变仍是lastSeenSHA远端当前所有提交都已被按 patch-id 内容等价并入新 head或属于 run 已知重写的历史^baseSHA。任何其他情况一律拒绝ls-remote/fetch失败也 fail closed——绝不在没有显式锚点的情况下退化为裸--force/--force-with-lease。remoteCommitsNotIncorporatedforcepush.go使用rev-list --cherry-pick干净的 rebase 会重写 SHA 但保留 patch-id因此 pipeline 真正重放过的提交会被识别为已并入而只在远端存在过的提交会被报告为即将被丢弃。6.3lastSeenSHA必须是被观察过的 head而不是 live 远端 tiplastSeenSHA必须保持为 run最后观察/产生的 head——来自当前 run 或先前 run 的推送 provenance或 remote-tracking ref——而绝不是live 远端 tiprebase 步骤只在普通push 时刷新origin/branch不在force push 时刷新CI 修复在本地提交并回到 Review 重新验证后续 Push 步骤负责它们的远端更新与 force-push 安全。两个必须永不回归的历史 bug#281把 lease 锚定到推送前立刻读取的 SHA——它总是通过等于没有任何保护在 force push 时总是 fetch 该分支——这等于重现 #281。6.4 回归测试矩阵相关回归测试的分布与意图可在对应文件与 e2e 中检索验证分支同步网络预算TestRefreshSlowSuccessfulLsRemoteDoesNotStealFetchBudget、TestRefreshSlowButSuccessfulLsRemoteAloneExceedsItsOwnBudgetReportsOffline、TestRefreshRaisedRemoteTimeoutAcceptsTheSameLegitimateSlowLsRemote、TestRefreshParentCancellationStopsFetchAfterLsRemoteSucceeds、TestServiceRemoteTimeoutDefaultsToConfigDefault、TestLoadGlobal_InvalidBranchSyncRemoteTimeoutinternal/branchsync/sync_test.go评审后连续性TestPostReviewStepsRefuseHeadClobberAtEntry、TestPushStep_RefusesPostReviewClobberWithoutLaterPipelineCommit、TestPushStep_BindsRemoteAndDatabaseToVerifiedCommitWhenHEADMovesDuringPush、TestExecutor_FullRereviewReplacesApprovalWithoutAuthorizingParkedRoundforce-push 安全TestPushStep_RefusesToClobberAdvancedUpstreamBranch#305、TestForcePushRun_RefusesToClobberOutOfBandBranchCommit、TestRebaseStep_DetectsUnpushedLocalDefaultBranchCommits#283、TestResolveForcePushDecision_*、TestExecutor_CIRestartRevalidatesBeforePush、TestPushStep_AllowsForcePushAfterMidRunRebaseOverPriorPushedGeneration#837、TestPushStep_AllowsForcePushOnRerunOverPriorRunPushedGeneration#837端到端旅程TestAxiBranchSyncJourney、TestAxiCustodyRecoveryJourney、TestAxiCustodyRecoveryAfterRebaseJourney、TestAxiPrePushAbortUnmovedHeadCustodyJourney。公共操作指引由 internal/skill/skill.go 与 live AXI 字符串持有见 internal/cli/axi_guidance.go并通过make skill重新生成。七、操作命令速查与适用边界场景命令说明查看分支同步状态被动不联网no-mistakes axi status/no-mistakes sync --check只读本地证据与缓存分类执行受保护同步no-mistakes axi sync严格快进或等价 diverged 锚定推进归还滞留 run 的分支 custodyno-mistakes axi sync --recover采纳 gate 保存的 preserved head保留本地 head、显式丢弃未发布提交no-mistakes axi sync --recover --keep-local不触碰 worktreeCAS 移动 gate 分支绑定归档为 keep-local 恢复证据no-mistakes sync --bind-archive-ref ref仅限refs/heads/archive/*的精确提交不修改任何 Git ref提交意图开始新一轮验证no-mistakes axi run --intent what the user set out to accomplishuser_owned/custody_returned之后的标准下一步约束与边界--check与--recover互斥--keep-local必须与--recover同用branch_sync_remote_timeout是全局唯一配置项默认 60s仓库级.no-mistakes.yaml无法覆盖服务只同步发起调用的 worktree并要求检出的是精确分支detached HEAD 直接拒绝Sync/Recover都会先做 gate 嵌套执行上下文拒绝检查。所有路径的共同底色是同一句话——不做任何可能丢失代码的聪明操作无法判定时把决定权交还给操作者。【免费下载链接】no-mistakesgit push no-mistakes项目地址: https://gitcode.com/GitHub_Trending/no/no-mistakes创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考