Git Workflow Skill · v1Git 工作流 Skill · v1
For projects where the upstream is protected (MR / PR only) and the build is heavy or pollutes the tree. One command sets up a gateway repo that pushes and a satellite repo that builds — the build tree is physically unable to reach the remote. 适用于上游分支受保护(必须走 MR / PR)且编译重、会污染工作树的项目。一条命令搭起 gateway 仓库负责 push 和 satellite 仓库只读编译——编译树在物理上够不到远程。
Most git workflows assume you trust yourself not to push the wrong thing. On a heavy project — Android builds, Yocto images, multi-gigabyte datasets — you stop trusting yourself the hundredth time git status returns sixty lines of unrelated artefacts. A tired afternoon, one wrong git push, and the whole team is rolling back.
大多数 git 工作流的前提是:你信得过自己不会把错东西推出去。但在重型项目上——Android 编译、Yocto 镜像、多 GB 数据集——当 git status 第一百次返回 60 行无关产物,你就开始信不过自己了。一个疲惫的下午,一条错误的 git push,整个团队回滚半天。
This skill removes the choice. The tree that compiles is not the tree that pushes. They are two directories, each with its own origin, and the build tree's origin never left your laptop.
这个 skill 把“选择”拿掉了。编译的目录不等于推代码的目录。是两个目录,各自有自己的 origin,而编译目录的 origin 从来没离开过你的笔记本。
The whole skill exists to make this command boring — so you can forget it, and trust the shape. 这个 skill 存在的全部意义,就是让这条命令变得无聊——你可以忘掉它,信任这个结构。
Three nodes, two clones, one direction of push. The satellite's origin points at the local gateway — no protocol path to upstream exists from the build tree.
三个节点,两份 clone,一条 push 方向。satellite 的 origin 指向本地的 gateway——编译树到上游根本不存在协议通路。
Four yes/no questions. Three or more "yes" means the pattern earns its weight. Otherwise a single repo or a git worktree is the right tool — this skill would add ceremony you don't need.
4 道是非题。≥ 3 个 yes 这个模式的额外工程量才划得来。不到 3 个 yes,单仓库或者 git worktree 更合适,本 skill 会是多余的复杂度。
MR / PR required, direct push rejected by the host. Check in the hosting UI (GitLab "Protected branches", GitHub "Branch protection rules"). 必须走 MR / PR,直接 push 被托管平台拒。托管后台看(GitLab "Protected branches"、GitHub "Branch protection rules")。
Look at CI timing and du -sh out/ build/. Heavy builds are what make the separate satellite tree pay for itself.
看 CI 时长和 du -sh out/ build/。编译重,satellite 独立工作树的开销才值得。
.git/objects hardlinks, but git-lfs payloads and large binary submodules do not — they really cost 2× on disk. Budget for it.
.git/objects 会 hardlink,但 git-lfs 对象和大型二进制 submodule 不会——真的 2× 占盘。预算时考虑进去。
Build artefacts never pollute git status; an accidental git push from the build tree can't even reach upstream.
编译产物永远不污染 git status;从编译树误跑 git push 也够不到上游。
Three or more "yes" — use this skill. Fewer — see the comparison table for the better-fitting alternative. ≥ 3 个 yes — 用本 skill。少于 3 个 — 去看对比表挑更合适的方案。
One invocation. Eight parameters. Every value is documented inline — no magic, no hidden state. 一条命令,8 个参数,每个值都有行内注释 —— 无魔法,无隐藏状态。
scripts/bootstrap.sh \ --remote git@gitlab.example.com:team/project.git \ --upstream-branch release \ --push-branch feature/alice-auth \ --gateway-dir ~/projects/foo-work \ --satellite-dir ~/projects/foo-verify \ --user-email alice@example.com \ --user-name alice # gateway/ — edit here, pushes to your personal branch— 在这里改代码,push 到你的个人分支 # satellite/ — build here, fetch from gateway, push is DISABLED— 在这里编译,从 gateway fetch,push 被禁用
After bootstrap finishes, three checks must pass. Each one verifies a separate layer — protocol, git config, hook. Any single layer holds; three together is belt, braces, and a shoulder strap. bootstrap 完成后跑 3 道检查。每道验证一层——协议层、git 配置层、hook 层。任意单层都够用,三层叠加是三重保险。
Load-bearing · Layer 1主防线 · 第 1 层
Satellite origin points at the local gateway path. There is no network route from the build tree to upstream — you can't push what you can't reach.
Satellite origin 指向本地 gateway 路径。编译树到上游没有网络路由——够不到,就推不了。
cd satellite/ && git push # → "does not accept"
Satellite's push URL is overwritten to the literal string DISABLED. Even a malformed config edit still yields a fast, readable error instead of a silent attempt.
Satellite 的 push URL 覆盖为字符串 DISABLED。哪怕配置被误改,也报错直接清晰,不会静默尝试。
cd satellite/ && git remote -v # → "origin ... (push): DISABLED"
Gateway runs a pre-push hook that rejects any push whose remote ref matches the protected-branch regex. Catches finger-slips like git push origin main.
Gateway 的 pre-push hook 在推保护分支时拒绝。接住类似 git push origin main 的手滑误操作。
cd gateway/ && \ git push origin release --dry-run # → "REJECTED: protected branch"
Optional · reproducibility gate 可选 · reproducibility 关卡
Pass --clean-verify-dir=<path> (ideally on a cold HDD or a separate machine) and bootstrap.sh adds a third clone plus a pre-push gate: every push is refused unless a from-scratch full build has stamped the exact commit.
加 --clean-verify-dir=<path>(推荐冷 HDD / 异机器),bootstrap.sh 会加第 3 仓 + 一道 pre-push 关卡:没经过从零全量编 stamp 的 commit 推不出去。
scripts/bootstrap.sh \ --remote git@gitlab.example.com:team/project.git \ --upstream-branch release \ --push-branch feature/alice-auth \ --gateway-dir ~/projects/foo-work \ --satellite-dir ~/projects/foo-verify \ --clean-verify-dir /mnt/hdd/foo-clean-verify \ --user-email alice@example.com \ --user-name alice # adds Step 5b (clone clean-verify) + Step 6b (configure pushurl=DISABLED on origin + upstream)追加 Step 5b(clone clean-verify)+ Step 6b(origin + upstream 双重 pushurl=DISABLED) # adds Gate D post-setup + passes --enforce-clean-verify to install-hooks.sh追加 Gate D 验证 + 自动给 install-hooks.sh 传 --enforce-clean-verify
scripts/clean-verify-run.sh \ --gateway-dir ~/projects/foo-work \ --clean-verify-dir /mnt/hdd/foo-clean-verify \ --push-branch feature/alice-auth \ --build-cmd 'make -j$(nproc) all test' \ --yes # 1. fetch + reset --hard from gateway 2. git clean -fdx 3. run --build-cmd1. 从 gateway fetch + reset --hard 2. git clean -fdx 3. 跑 --build-cmd # 4. on pass: write gateway/.git/last-clean-verify 5. next git push is allowed4. 通过则写 stamp 5. 下一次 git push 才放行 # emergency bypass: git push --push-option=allow-unverified紧急 bypass: git push --push-option=allow-unverified
#include旧产物掩盖了缺的 #includeclean-verify-run.sh要养成跑 clean-verify-run.sh 的习惯
Pass --clean-verify-dir to gated-dual-clone-audit too and it adds 4 extra gates: S9-S11 (exists, is git repo, stamp present) + C9a-c (origin at gateway, pushurls all DISABLED) + B4 (push actually rejected). 26 gates total in 3-clone mode.
给 gated-dual-clone-audit 传 --clean-verify-dir 就自动扩 4 gate:S9-S11(存在、是 git 仓、stamp 有)+ C9a-c(origin 指 gateway、两 pushurl 都 DISABLED)+ B4(push 实际被拒)。3 仓模式共 26 gate。
Quick reference — each row scores one practical dimension. Pick the column that fits your constraints; don't force the pattern to fit you. 速查表——每行打一个实际维度的分。按约束挑列,不要硬套模式。
| Dimension维度 | Dual-clone (this)双 clone(本方案) | git worktreegit worktree |
Single repo单仓库 |
|---|---|---|---|
| Disk cost盘占用 | 2× tree; .git hardlinked2× 工作树;.git hardlink |
1× .git + N× tree1× .git + N× 工作树 |
1× total1× 总 |
| LFS / binary submoduleLFS / 大二进制 submodule | 2× (no hardlink)2×(不 hardlink) | 1× | 1× |
| Physical push isolation物理防误推 | Yes — satellite origin is local有——satellite origin 是本地 | No — shared remote无——共享 remote | No无 |
Build pollutes git status编译污染 git status |
Isolated隔离 | Isolated隔离 | Polluted污染 |
| Cross-machine migration跨机迁移 | Medium (re-install hooks)中(要重装 hook) | Low低 | Low低 |
| Shared-machine safety共用机器的安全 | Safe安全 | Risky有风险 | Risky有风险 |
| Client-hook bypass risk客户端 hook 被绕风险 | Low — protocol barrier低——有协议层保护 | Full完全暴露 | Full完全暴露 |