Proton 版本升级 Rebase 全流程指南:从上游 Wine 迁移补丁的工程实践
【免费下载链接】ProtonCompatibility tool for Steam Play based on Wine and additional components项目地址: https://gitcode.com/gh_mirrors/pr/Proton
导读
Proton 是 Steam Play 的兼容工具,其核心思路是在 Wine 及其组件(如 DXVK、vkd3d-proton、dxvk-nvapi)之上叠加大量自定义补丁,以满足游戏兼容性需求。每当上游 Wine 发布新版本,Proton 维护者都需要执行一次Rebase:把散落在旧版本之上的补丁重新应用到新版本分支上,同时剔除已经被上游收录的补丁。本文基于 docs/REBASING_TIPS.md,系统讲解 Proton 的补丁管理纪律、批量迁移命令、冲突处理脚本与收尾的 prefix 版本号更新机制,并给出仓库源码级佐证。读完本文,你将掌握一套可复制的 Wine rebase 操作流程。
为什么 Proton 需要频繁 Rebase
Proton 并不是简单的 Wine 发行版,它在每个上游版本之上都维护着数量庞大的本地补丁(本仓库的wine/目录即内嵌了带补丁的 Wine 源码树,此外还有dxvk/、vkd3d-proton/、dxvk-nvapi/、wineopenxr/等配套组件)。这些补丁来源有两类:
- 已上游化(upstreamed):已经合入官方 Wine 的补丁;
- 纯本地补丁:因兼容性、时机等原因只存在于 Proton 中的补丁。
Rebase 的核心矛盾在于:新版本 Wine 可能已经包含了部分 Proton 补丁的内容,直接照搬会冲突或冗余;同时纯本地补丁又必须原样保留。因此,维护一套能区分两类补丁、可批量迁移、可安全中断续跑的流程,是每次升级成败的关键。
铁律:cherry-pick 必须区分-x参数
文档首先强调了 Proton 维护者在 cherry-pick 时的纪律:
- 从上游 Winecherry-pick 到 Proton时,必须加
-x参数,这样原始提交 ID 会保留在提交信息中,形成可追溯的"来自上游"标记; - 反之,对于没有上游化的补丁,绝不使用
-x,避免留下误导性的上游关联标记。
这条纪律的意义在 rebase 时兑现:Proton 的提交历史中,凡是带有-x标记(提交信息中带有 "cherry picked from commit ..." 字样)的提交,说明其内容已经在上游存在,新版本 rebase 时可以安全丢弃;而没有该标记的,则是必须继续携带的本地补丁。提交信息本身因此成为 rebase 时的过滤依据。
第一步:列出需要迁移的补丁清单
文档给出了生成"待迁移补丁列表"的核心命令(在 Wine 仓库中执行):
wine$ git log --pretty=oneline --reverse --grep='cherry pick' --invert-grep wine-4.2..proton_4.2逐段拆解这条命令的语义:
git log:遍历提交历史;wine-4.2..proton_4.2:范围限定为从 Wine 基线标签wine-4.2之后、到 Proton 分支proton_4.2为止的提交;--grep='cherry pick'+--invert-grep:排除提交信息中含 "cherry pick" 字样的提交(即排除已上游化、带-x标记的补丁),只留下纯本地补丁;--pretty=oneline --reverse:以一行一条的形式输出,且按时间正序排列,方便后续按顺序逐条应用。
执行后得到的列表即当前版本基线之上需要原样迁移的补丁集合。接下来要做的,就是把这个列表(不带-x)逐一 cherry-pick 到新的 Wine release 标签上,边应用边解决冲突。
第二步:用pick_commits脚本批量迁移补丁
文档提供了一段精心设计的 bash 脚本pick_commits,相比 git 内置的git rebase --onto等手段,它更直观、更易配合人工干预:
#!/bin/bash # Cherry-picks commits from an input file in --pretty=oneline format. # Lines that begin with '#' are ignored. # Aborts when a cherry-pick fails. # Outputs the same input file on stderr, but with '#' prefixed to lines that were successfully cherry-picked. #Usage: # $ pick_commits to_pick 2> ~/to_pick2 # On pick failure, fix conflicts and use "git cherry-pick --continue", or # otherwise fix up the repo as desired. # Edit ~/to_pick2 to comment-out the commit that you fixed. # Continue using the new file: # $ pick_commits to_pick2 2> ~/to_pick # Repeat, alternating between to_pick and to_pick2. broken=0 while read -r l; do f=$(echo -n "$l" | cut '-d ' -f1 -) if [ $broken == 0 -a ${f:0:1} != '#' ]; then echo "Picking $l" git cherry-pick $f 2>&1 if [ $? -ne 0 ]; then echo $l 1>&2 broken=1 else echo '#'$l 1>&2 fi else echo $l 1>&2 fi done < "$1"脚本工作机制解读
- 输入:一个
--pretty=oneline格式的补丁列表文件(即第一步命令的输出); - 注释行跳过:以
#开头的行被忽略,用于标记"已处理/已放弃"的提交; - 顺序执行:逐行取出提交哈希(
cut '-d ' -f1取第一个以空格分隔的字段),执行git cherry-pick; - 失败即停:一旦某个 cherry-pick 失败(
$? -ne 0),把该行原样输出到 stderr 并置broken=1,终止后续操作,避免冲突雪崩; - 成功即标记:成功 picked 的提交,向 stderr 输出时前缀一个
#,实现"处理进度即清单更新"。
标准用法与冲突处理循环
脚本设计成两文件交替的工作流,配合 stderr 重定向实现进度持久化:
$ pick_commits to_pick 2> ~/to_pick2 # 若中途失败: # 1. 手动解决冲突后执行 git cherry-pick --continue,或以其他方式修复仓库状态 # 2. 编辑 ~/to_pick2,把刚才失败的那条提交行加 '#' 注释掉 # 3. 用新文件继续: $ pick_commits to_pick2 2> ~/to_pick # 如此往复,在 to_pick 与 to_pick2 之间交替,直到清单全部处理完毕- 成功被 pick 的提交会以
#开头写回新文件,下次运行时自动跳过; - 失败提交被手动注释后,其余未处理提交可以继续执行,做到任意断点续跑;
- 由于脚本输出"处理后的清单"到 stderr、原始日志到 stdout,重定向互不干扰,文件内容始终是"剩余任务 + 已完成标记"的完整快照。
第三步:Rebase 完成后更新 prefix 版本号
文档明确指出收尾动作:Wine rebase 完成后,更新 proton Python 脚本中的 prefix 版本号,并把 minor 版本重置回 1。
这一要求在仓库源码中得到了完整印证。在 proton 脚本第 44 行:
CURRENT_PREFIX_VERSION="11.0-100"prefix 版本号采用主版本.次版本-前缀号的结构,例如11.0-100。其作用体现在两个关键机制上:
- prefix 版本持久化:
setup_prefix()在 proton 中读取pfx/version文件获得旧版本号;初始化完成后在 proton 将CURRENT_PREFIX_VERSION写入该文件; - 升级判定:
upgrade_pfx()在 proton 中,若旧版本号与CURRENT_PREFIX_VERSION不一致,即触发 prefix 升级逻辑,并打印Upgrading prefix from <旧版本> to <新版本>日志。
正因为每次启动都会比对版本号,每次 rebase 到新 Wine 后都必须提升该版本号,否则旧的 prefix 不会得到重新初始化,新的 Wine/DLL 行为也不会生效。而"重置 minor 版本"指的是:当主版本发生跨越(例如从4.11升到5.0)时,把-之后的子版本号从累加值重新置为1(如4.11-2→5.0-1),从而形成清晰的"大版本归零、小版本递增"的节奏。
源码中还能看到版本号比较的实际逻辑(proton):脚本会将旧版本.旧前缀号与新版本.新前缀号逐一按主版本、次版本比较,若发现当前运行的 Proton 版本低于 prefix 记录版本,会判定为"降级场景",输出Removing newer prefix并清理由旧版本创建的 tracked files 后重建 prefix——这意味着不正确地回退 prefix 版本号会导致 prefix 被重建,用户数据迁移成本很高,进一步说明版本号管理必须谨慎。
与 Rebase 密切相关的仓库资产
执行 rebase 时,以下仓库资产值得配合使用:
- wine/:内嵌的 Wine 源码树,rebase 的主战场;
- dxvk/、vkd3d-proton/、dxvk-nvapi/、wineopenxr/:配套图形与接口组件,其版本往往与 Wine 版本联动,rebase 时通常需要同步升级;
- proton:启动与 prefix 管理入口,
CURRENT_PREFIX_VERSION的所在地; - proton_3.7_tracked_files:历史版本遗留的 tracked files 清单,供旧 prefix 升级路径使用(见 proton 中对 3.7 旧 prefix 的特殊处理);
- Makefile.in 与 Makefile:构建入口,确认 rebase 后各组件版本一致性;
- docs/REBASING_TIPS.md:本文所依据的官方操作文档,建议直接对照阅读。
此外,Proton 的构建和打包依赖 Docker 多阶段镜像(见 docker/proton.Dockerfile.in),其中 Wine 与 LLVM、Mingw 工具链的版本组合也需要在 rebase 时一并核对,必要时参考 docker/README.md 调整镜像构建参数。
总结
一次完整的 Proton Rebase 可以归纳为四个步骤:
- 区分补丁来源:cherry-pick 上游补丁一律加
-x,本地补丁一律不加,让提交信息自带"可丢弃"标记; - 生成迁移清单:用
git log --grep='cherry pick' --invert-grep反向筛选出必须携带的本地补丁; - 批量应用:借助
pick_commits脚本按清单逐条 cherry-pick,冲突时修复后交替使用两份清单文件续跑; - 更新版本号:在 proton 中提升
CURRENT_PREFIX_VERSION并将 minor 重置为 1,触发 prefix 升级,使新 Wine 行为生效。
这套流程的核心价值在于:用统一的提交标记纪律 + 可断点续跑的工具脚本 + 自动触发的 prefix 升级机制,把"升级上游版本"这件高频、高风险的事,变成可控、可复现的工程操作。
【免费下载链接】ProtonCompatibility tool for Steam Play based on Wine and additional components项目地址: https://gitcode.com/gh_mirrors/pr/Proton
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考