魔改一次,跟随一生。
把开源软件的品牌、配置、插件与差异代码保存为一份 Shadow Profile。 上游更新时重放定制层、预估冲突面, 并验证每一条定制是否还活着。
假设你 fork 了一个项目,在某个列表渲染前加了一层过滤,用来隐藏你不想要的条目:
- getVisiblePresetEntries(presetEntries, {
+ getVisiblePresetEntries(stripAdPresetEntries(presetEntries), {
半年后上游重构,把 presetEntries 改了名。于是:
git merge —— 干净通过,零冲突git rerere —— 不工作(没有冲突标记,它没机会介入)Copybara、cruft、git rerere、Debian quilt —— 现有工具都在回答 「变更能不能重放」。 没有一个回答 「重放之后,语义还在不在」。
ShadowFork 管这个。
同一套工具、同一份方法,衡量两个衍生版相对上游被改动的文件数量。 两者做的事几乎一样:换品牌、改默认值、接自有服务、去掉不要的东西。
| 衍生版 | 上游 | 侵入文件 | 有断言守护 |
|---|---|---|---|
| uu-switch | cc-switch | 21 | 21 / 21 |
| U-Claw 虾盘 | ClawX | 213 | 48 / 213 |
上表由 npm run selfcheck 对真实仓库跑出来后生成,非手写。
数字手写就会腐烂 —— 那正是本项目要治的病。
差异不在下游的能力,在上游的结构: cc-switch 把产品名放在两个配置文件的具名字段里,改 2 个字段即可; ClawX 把它散在 67 个源码文件的字符串中,改到哪算哪,每次跟版都冲突。
npm i -g shadowfork shadowfork verify --profile profile.yaml # 我的定制还活着吗 shadowfork plan --profile profile.yaml # 这次上游更新有多少落在我的冲突面上
对每条定制跑可执行断言。静态检查,毫秒级,不需要构建也不需要跑起来。 断言盯的是语义而非形状 —— 参数还在但函数体里的闸门被删掉,一样报红。
在 git merge 之前告诉你:这次上游更新有多少落在冲突面上、
多少能自动重放、多少是你改过却没申报的盲区。
跟版是 5 分钟还是 2 小时,不必开盲盒。
MIT 许可。全部命令支持 --json,退出码有文档,可直接接进 CI 与 AI Agent。
上面那个十倍差距说明:衍生成本主要由上游的结构决定。 于是我们把它写成了一份面向上游作者的规范。
这对上游作者不是慈善 —— fork 你的人跟不上你,你自己也在亏:
| 下游跟不上 | 后果落在你头上 |
|---|---|
| 衍生版停在半年前的版本 | 你修的安全漏洞,他们的用户永远等不到 |
| 跟版太贵,索性不跟 | 你的新功能传不到那批用户 |
| 衍生版自己打补丁 | bug 修在他们那儿,永远不回流给你 |
| 只能整文件删掉你的赞助 | 你的收入没了,而本来只要一个开关 |
协议共七条,全部从真实案例逼出来,含一份机器可读的
衍生契约(.shadowfork/upstream.yaml)——
由上游声明哪些是身份、哪些碰不得、从哪扩展、归因在哪。
自己维护一个长期衍生版,成本不在第一次改造,而在此后每一次跟版。 我们承接这件事。
品牌与图标替换、默认值与接入点调整、功能增减、安装包构建。 交付物包含一份 Shadow Profile —— 它归你, 即使以后不再合作,你也能自己继续跟版。
监控上游发布、给出冲突面报告、重放定制层、跑断言验证、 构建新版本安装包。每次跟版都有一份可核对的 verify 报告, 而不是一句「合好了」。
合作咨询:hello@shadowfork.net
衍生自 farion1231/cc-switch(MIT)
AI 模型切换器。相对上游只侵入 21 个文件,其中 97% 的定制代码量是纯新增文件 —— 上游更新几乎总能干净合并。Shadow Profile 完整开源,可作为写自己 Profile 的样板。
感谢上游作者 Jason Young 与 cc-switch 全体贡献者。本项目保留其完整版权声明。
AI 助手桌面端,便携化改造版。侵入 213 个上游文件 —— 真实世界里更常见的那种深度分叉,也是本工具的压力测试对象。 公开的是脱敏 Profile:讲方法,不含商业配置细节。
抄袭者不需要任何工具配合 —— 他们本来就会 fork 然后全局替换,改完就跑。 ShadowFork 服务的是另一批人:想长期维护衍生版、并且愿意持续跟随上游的人。 让他们跟得动,上游的代码才传得远、bug 才回得来。 协议里的「归因位可关而非删除」,也是唯一能让上游在衍生版里保住署名的机制。
那些是下游工具,解决「变更能不能重放」;影刻协议是上游规范, 解决「衍生版为什么一开始就这么难跟」。方向相反,互补而非竞争。 而 ShadowFork 工具本身补的是第三块:重放之后,语义还在不在。
GitHub 原生 fork 属于同一个 repository network,公开仓库的 fork 仍然公开, 权限与可见性都受上游关系约束。ShadowFork 的「fork」是产品概念上的衍生: 上游镜像只读,产品仓库独立,靠 Shadow Profile 与断言维系两者的关系。