首页 / 教育学习

开源协议选错被要求公开代码,停手后该按什么顺序回退

开源协议选错被要求公开代码,停手后该按什么顺序回退

上周有位读者发来一张截图:他把公司内部工具打包成 Docker 镜像挂到公开仓库,开源仓库根目录放了一份从别的协议选错项目复制来的 MIT 许可证。三天后收到一封邮件,被求对方指出镜像里含有一个 GPL 项目的公开二进制,要求他按 GPL 提供完整对应源码。代码他第一反应是停手「赶紧把 LICENSE 改成 GPL 再补个说明」,问我这样能不能补救。后该回退答案是顺序:不能这样操作,而且这一步会让局面更糟。开源

先给结论:在开源协议这件事上做错或反复改错之后,协议选错第一动作不是被求「改文件」,而是公开停手、回退、代码换人评估。停手下面按这个顺序讲清楚每一步在做什么。后该回退

先把仓库冻结,别再提交任何 LICENSE 改动

失败后的常见冲动是立刻动手修。但许可证是随版本记录生效的:Git 历史里每一次 LICENSE 变更都留下时间戳,公开仓库的 fork 和镜像站也会同步。你改一次,对方就多一条「明知故犯」的证据链。正确顺序是先冻结:把仓库设为 private,或者在 README 顶部加一行「本仓库暂时关闭访问,待许可证合规复核」,暂停 CI 自动发布。不要删仓库,删除会被理解为销毁证据,反而放大问题。

冻结期间只做一件事:把当前状态的清单拉出来。包括仓库里每个第三方目录、vendor 目录、Dockerfile 里 apt 或 npm 装的依赖、二进制文件来源。这一步不需要判断协议,只需要列事实。很多人的失败不是选错协议,而是根本不知道自己的交付物里混进了什么。

回退到「最后一个干净版本」,而不是改当前版本

开源协议常识里有一条容易被忽略:协议约束的是「分发行为」,而不是「文件里写了什么字」。MIT 改 GPL 不会让过去的分发变成合规,只会让未来版本多一层矛盾。所以回退的目标不是把 LICENSE 改成对的,而是找到最后一次分发时不包含争议组件的提交,从那里重新开始。

具体做法:用 git log --follow 追某个争议文件的引入提交,确认它是在哪次 release 后进入主干。如果争议组件是后来才加的,回退到它之前的分支点,重新打标签发布,同时在 release note 里写明「此前版本已撤回」。如果争议组件从一开始就在,回退就没有意义,这时必须走下一步。

回退不是逃避。它的价值在于把「持续分发」这个动作停下来,让问题从「正在侵权」变成「历史版本待处理」。两者在沟通时的分量完全不同。

换人:让不写代码的人去和协议方或法务对话

反复失败的人往往是同一个:一边写代码,一边自己判断协议。这不行。开源协议的判断需要两样东西——对许可证文本的逐条阅读,和对业务分发方式的完整了解。同一个人同时干这两件事,容易把「我觉得没问题」当成结论。

换人的具体做法是:把清单交给法务、合规岗,或者至少交给一个不参与该项目开发、但熟悉许可证文本的同事。如果公司没有这类角色,直接联系许可证持有方或项目维护者,说明情况并询问补救路径。GPL 类项目通常有明确的合规联系人,Apache 基金会和 Linux 基金会也提供公开的合规资料。不要自己写一封「我错了求放过」的邮件,那既没有法律效力,也容易说错话。

换人还有一层意思:如果这个项目本来就不该由个人维护,就把它交给有发布流程的团队。个人仓库没有 review,没有依赖扫描,也没有 release 前的许可证检查,反复出错是结构问题,不是态度问题。

重启时只做三件小事,别做大重构

停手、回退、换人之后,重启阶段不要急着「把整个项目重写一遍」。做三件小事就够了。第一,给仓库加依赖扫描,CI 里跑一次许可证检查,让混入的协议在合并前就暴露。第二,在 CONTRIBUTING 里写清楚:新增依赖必须注明来源和许可证,vendor 目录不接受来源不明的二进制。第三,把 LICENSE 文件的修改权限收归一个人或一个流程,其他人只能提议不能直接改。

这三件事的共同点是「让错误在发生前被拦住」,而不是「发生后再改文件」。开源协议常识真正难的地方不在背许可证条文,而在承认自己判断不了的时候及时停手。停手不是认输,是把问题交给能处理它的人。回退不是倒退,是把持续分发的动作先按住。换人不是推责,是让判断和开发分开。重启之后再回头看,你会发现当初那封邮件其实是提醒,不是判决。

作者:节气时间