用途
upstream-patches 用于管理 Terraform provider 子模块的补丁。其中 upstream/ 是一个指向上游 Terraform provider 的 git 子模块,patches/ 目录包含应用在其上的补丁文件。通过 ./scripts/upstream.sh 脚本可以管理补丁状态,适用于 upgrade-provider 流程或手动补丁维护工作。
默认行为
如果修复的是由现有补丁引入的回归问题,应修改拥有该补丁的提交(amend),而不是新建补丁。除非用户明确要求,否则不要创建新补丁。
命令参考
- ./scripts/upstream.sh init:初始化 upstream 并将补丁应用到工作目录。
- ./scripts/upstream.sh init -f:破坏性地丢弃 checkout/rebase 状态并重新初始化 upstream。
- ./scripts/upstream.sh checkout:创建分支,将补丁作为提交以便编辑。
- ./scripts/upstream.sh rebase -i:交互式编辑补丁提交。
- ./scripts/upstream.sh rebase -o <commit>:将补丁变基到新的上游提交。
- ./scripts/upstream.sh check_in:将提交写回补丁并退出 checkout 模式。
护栏
- 未经 checkout/check_in,切勿直接提交到 upstream/。
- 在 checkout 之外直接编辑 upstream/ 下的内容在 upgrade-provider 期间是临时的,工具会重置子模块状态。
- 除非有意进行原始补丁手术,否则不要手动编辑 patches/*.patch。
- 对于智能体,优先使用非交互式重写流程,而非交互式 rebase。
先找到拥有补丁
在编辑补丁内容之前,先确定拥有该补丁的 patch/commit。
./scripts/upstream.sh checkout
# 按触及的文件路径或唯一 hunk 文本查找候选补丁文件
rg -n "path/to/file|unique_symbol" patches/*.patch
# 可选:检查候选补丁的头部/hunk
sed -n '1,120p' patches/00NN-Example.patch
# 将补丁文件映射到 upstream checkout 分支中的提交
patch=patches/00NN-Example.patch
subject=$(sed -n 's/^Subject: \[PATCH\] //p' "$patch" | head -n1)
cd upstream
git log --oneline pulumi/patch-checkout --grep "$subject"
# 如需要,按触及路径消歧
git log --oneline pulumi/patch-checkout -- path/to/file
cd ..
如果 rg 不可用,使用 grep -En 进行补丁搜索。将 target_sha 设为拥有该补丁的提交,并编辑该提交,而不是 HEAD。
修改现有补丁(首选,非交互式)
./scripts/upstream.sh checkout
cd upstream
target_sha=<owning-commit-sha>
base_sha=$(git rev-parse "${target_sha}^")
tmp_branch="rewrite-${target_sha:0:8}"
# 从目标提交的父提交重建历史
git checkout -b "$tmp_branch" "$base_sha"
git cherry-pick "$target_sha"
# 应用修复并修改目标提交
# ...编辑文件...
git add <files>
git commit --amend --no-edit
# 重放剩余提交
git cherry-pick "${target_sha}..pulumi/patch-checkout"
# 如果 cherry-pick 出现冲突:
# 解决文件
# git add <resolved files>
# git cherry-pick --continue
# 将 checkout 分支移动到重写后的历史
git branch -f pulumi/patch-checkout HEAD
git checkout pulumi/patch-checkout
git branch -D "$tmp_branch"
cd ..
交互式回退方案:
./scripts/upstream.sh checkout
./scripts/upstream.sh rebase -i
# 将目标提交标记为 edit,修改后继续
删除整个补丁
当补丁应被完全删除时使用。
rm patches/00NN-Description.patch
./scripts/upstream.sh checkout
./scripts/upstream.sh check_in
删除补丁的一部分
当只应从现有补丁中删除选定的 hunk/文件时使用。
找到拥有该补丁的 patch/commit(target_sha),使用上述修改工作流。仅从目标提交中还原不需要的更改,然后修改。
修改步骤中的示例:
cd upstream
# 从被修改提交的父提交恢复特定的仅文档文件
git checkout HEAD^ -- path/to/docs-only-file path/to/another-doc-file
git add path/to/docs-only-file path/to/another-doc-file
git commit --amend --no-edit
cd ..
创建新补丁(仅在要求时)
./scripts/upstream.sh checkout
cd upstream
# ...进行更改...
git add <files>
git commit -m "Describe new patch"
cd ..
./scripts/upstream.sh check_in
将补丁变基到新的上游版本
./scripts/upstream.sh checkout
# 变基到新的上游提交
./scripts/upstream.sh rebase -o <new_commit_sha>
# 解决出现的任何冲突
# 写回更新后的补丁文件
./scripts/upstream.sh check_in
验证清单
check_in 之前:
- 确认预期的补丁数量变化(默认 0;完全删除补丁时为 -1)。
- 确认目标补丁应保留(默认是)还是被删除(显式删除场景)。
- 确认你正在编辑拥有该补丁的提交,而不是意外添加新提交。
check_in 之后:
- 验证补丁数量符合预期。
- 在预期保留时,验证目标补丁编号/用途仍然存在。
- 验证没有引入意外的新的 00NN-*.patch。
中断的 Checkout 或 Rebase
默认保留工作成果。检查 git -C upstream status,完成正在进行的 git am/rebase,验证每个补丁都已应用,并在重新运行自动化之前运行 ./scripts/upstream.sh check_in。中断的 checkout 会为每个补丁单独调用 git am,因此后续补丁文件可能尚未被处理。
仅当有意丢弃所有中断的工作时,才使用 ./scripts/upstream.sh init -f。它可能移除冲突解决、补丁提交、操作元数据和未跟踪文件;它不是卡住的 checkout 的常规恢复手段。