影刻

魔改一次,跟随一生。

把开源软件的品牌、配置、插件与差异代码保存为一份 Shadow Profile。 上游更新时重放定制层、预估冲突面, 并验证每一条定制是否还活着


merge 干净 ≠ 定制还生效

假设你 fork 了一个项目,在某个列表渲染前加了一层过滤,用来隐藏你不想要的条目:

-      getVisiblePresetEntries(presetEntries, {
+      getVisiblePresetEntries(stripAdPresetEntries(presetEntries), {

半年后上游重构,把 presetEntries 改了名。于是:

  1. git merge —— 干净通过,零冲突
  2. git rerere —— 不工作(没有冲突标记,它没机会介入)
  3. 类型检查 / 编译 —— 全绿
  4. 单元测试 —— 全绿(上游的测试不会测你的定制)
  5. 构建、打包、发版 —— 全部成功
  6. 用户打开软件 —— 你去掉的东西回来了

Copybara、cruft、git rerere、Debian quilt —— 现有工具都在回答 「变更能不能重放」。 没有一个回答 「重放之后,语义还在不在」

ShadowFork 管这个。


实测:侵入面差十倍

同一套工具、同一份方法,衡量两个衍生版相对上游被改动的文件数量。 两者做的事几乎一样:换品牌、改默认值、接自有服务、去掉不要的东西。

衍生版上游侵入文件有断言守护
uu-switchcc-switch2121 / 21
U-Claw 虾盘ClawX21348 / 213

上表由 npm run selfcheck 对真实仓库跑出来后生成,非手写。 数字手写就会腐烂 —— 那正是本项目要治的病。

差异不在下游的能力,在上游的结构: cc-switch 把产品名放在两个配置文件的具名字段里,改 2 个字段即可; ClawX 把它散在 67 个源码文件的字符串中,改到哪算哪,每次跟版都冲突。

由此还量出一条反直觉的结论:改动小 ≠ 不重要。 在一批改动不足 10 行的文件里,只有约三成是纯日志文案, 其余是商业归因 header、云服务注册点、便携化路径、遥测开关、UI 自动化标识 —— 全都属于「被上游覆盖后构建照过、界面照常、功能静默失效」的那一类。

工具:CLI 开源

npm i -g shadowfork

shadowfork verify --profile profile.yaml   # 我的定制还活着吗
shadowfork plan   --profile profile.yaml   # 这次上游更新有多少落在我的冲突面上

verify

对每条定制跑可执行断言。静态检查,毫秒级,不需要构建也不需要跑起来。 断言盯的是语义而非形状 —— 参数还在但函数体里的闸门被删掉,一样报红。

plan

git merge 之前告诉你:这次上游更新有多少落在冲突面上、 多少能自动重放、多少是你改过却没申报的盲区。 跟版是 5 分钟还是 2 小时,不必开盲盒。

MIT 许可。全部命令支持 --json,退出码有文档,可直接接进 CI 与 AI Agent。


协议:写给开源作者

上面那个十倍差距说明:衍生成本主要由上游的结构决定。 于是我们把它写成了一份面向上游作者的规范。

这对上游作者不是慈善 —— fork 你的人跟不上你,你自己也在亏:

下游跟不上后果落在你头上
衍生版停在半年前的版本你修的安全漏洞,他们的用户永远等不到
跟版太贵,索性不跟你的新功能传不到那批用户
衍生版自己打补丁bug 修在他们那儿,永远不回流给你
只能整文件删掉你的赞助你的收入没了,而本来只要一个开关

协议共七条,全部从真实案例逼出来,含一份机器可读的 衍生契约.shadowfork/upstream.yaml)—— 由上游声明哪些是身份、哪些碰不得、从哪扩展、归因在哪。

阅读影刻协议 →


服务:衍生版本的持续维护

自己维护一个长期衍生版,成本不在第一次改造,而在此后每一次跟版。 我们承接这件事。

一次性改造

品牌与图标替换、默认值与接入点调整、功能增减、安装包构建。 交付物包含一份 Shadow Profile —— 它归你, 即使以后不再合作,你也能自己继续跟版。

持续跟随

监控上游发布、给出冲突面报告、重放定制层、跑断言验证、 构建新版本安装包。每次跟版都有一份可核对的 verify 报告, 而不是一句「合好了」。

我们不做的事: 不帮任何人绕过开源许可证;不删除上游版权声明; 不做冒充上游或暗示获得上游背书的产品; GPL/AGPL 系项目的衍生版必须依约开源。

商标 ≠ 版权。MIT 允许修改代码,但项目名与 Logo 通常受商标保护 —— 所以衍生版必须启用自己的品牌,而不是沿用上游的名字。 这既是义务,也是对你自己的保护。

合作咨询:hello@shadowfork.net


案例与下载

uu-switch

衍生自 farion1231/cc-switch(MIT)

AI 模型切换器。相对上游只侵入 21 个文件,其中 97% 的定制代码量是纯新增文件 —— 上游更新几乎总能干净合并。Shadow Profile 完整开源,可作为写自己 Profile 的样板。

下载安装包 · 查看 Profile

感谢上游作者 Jason Young 与 cc-switch 全体贡献者。本项目保留其完整版权声明。

U-Claw 虾盘

衍生自 ValueCell-ai/ClawX

AI 助手桌面端,便携化改造版。侵入 213 个上游文件 —— 真实世界里更常见的那种深度分叉,也是本工具的压力测试对象。 公开的是脱敏 Profile:讲方法,不含商业配置细节。

产品主页 · 查看脱敏 Profile


常见疑问

这是帮人抄开源项目的工具吗?

抄袭者不需要任何工具配合 —— 他们本来就会 fork 然后全局替换,改完就跑。 ShadowFork 服务的是另一批人:想长期维护衍生版、并且愿意持续跟随上游的人。 让他们跟得动,上游的代码才传得远、bug 才回得来。 协议里的「归因位可关而非删除」,也是唯一能让上游在衍生版里保住署名的机制。

和 Copybara、cruft 有什么不同?

那些是下游工具,解决「变更能不能重放」;影刻协议是上游规范, 解决「衍生版为什么一开始就这么难跟」。方向相反,互补而非竞争。 而 ShadowFork 工具本身补的是第三块:重放之后,语义还在不在

为什么不直接用 GitHub 的 Fork?

GitHub 原生 fork 属于同一个 repository network,公开仓库的 fork 仍然公开, 权限与可见性都受上游关系约束。ShadowFork 的「fork」是产品概念上的衍生: 上游镜像只读,产品仓库独立,靠 Shadow Profile 与断言维系两者的关系。