做同人企划做到第三年,最容易翻车的环节往往不在美术或者代码,而在“这东西到底谁能用、怎么用、用了要不要回馈”这一层。《卫戍协议:盟约》从最早的一份设定草案,长到现在有代码仓库、素材仓库、外加一堆外部贡献者提交的分支,GPL-3.0许可、素材版权、社区贡献指南这三件事就绕不过去了。我把它当成一次完整的合规梳理来做:代码走什么协议、美术音频归谁、外部素材怎么引入、别人提的补丁怎么收、发布包怎么打包才不留尾巴。这篇写给两类人看——手里有个正在长大的同人企划、开始有人来提PR,或者只是想知道“我把代码开源了是不是素材也就跟着开源了”的创作者。前者能直接抄流程,后者能少踩几个我踩过的坑。
1. 边界从哪划起:为什么代码走 GPL-3.0
1.1 一份代码许可,管不到美术和剧本
先把最容易搞混的一条说透:许可证是贴在“作品”上的,不是贴在“项目”上的。一个企划里通常至少有三类东西——程序代码、自产素材(立绘、UI、音效、剧本文本)、外部引入素材(字体、音效包、开源模型)。这三类东西可以各自挂不同的协议,甚至可以一部分开源一部分保留。
《卫戍协议:盟约》早期犯过一个典型错误:仓库根目录放了一份 GPL-3.0 的 LICENSE,README 里写着“本项目开源”,结果社区里有人直接把立绘拿去做了周边,还说“你们不是开源吗”。这件事的根子不在别人,在我们自己没把边界写在明面上。后来的做法是把仓库拆成两个:covenant-core(纯逻辑代码)和covenant-assets(美术、音频、文本),前者挂 GPL-3.0,后者挂自定义的“同人使用许可”——允许非商业二次创作,禁止直接商用与再分发原始工程文件。
为什么不干脆全挂 GPL-3.0,一了百了?因为 GPL-3.0 是为软件设计的强著佐权协议,它的整套机制(源码提供义务、安装信息、专利授权)放到一张 PNG 上会变得极其别扭。一张立绘的“对应源码”是什么?分层文件?笔刷参数?这在实务上没法操作。所以正确姿势是:代码用它擅长的协议,素材用能表达你真实意图的自定义条款。
1.2 GPL-3.0 到底要求你做什么
很多人对它的印象停留在“传染性”三个字,实际落到操作层面,主要是七条义务。我把它整理成一张对照表,左边是条款含义,右边是你具体要干的活:
| 条款要点 | 通俗理解 | 你要落地的动作 |
|---|---|---|
| 源码提供义务 | 你把编译好的东西发给别人,就得让人能拿到对应源码 | 发布包内附源码,或提供同版本源码的长期可下载地址 |
| 许可证随附 | 收到的人必须知道自己的权利 | 根目录放 LICENSE,每个源文件头部加简短声明 |
| 修改标注 | 改过的文件要看得见改过 | 文件头写修改者与日期,或在 CHANGELOG 记录 |
| 不得附加额外限制 | 不能一边给 GPL 一边加“禁止商用” | 附加条款只能放宽,不能收紧 |
| 专利授权 | 贡献者默认授予专利许可 | 提交时确认无专利障碍,DCO 里体现 |
| 安装信息 | 用户设备上的固件类分发要提供替换方式 | 纯 PC 端项目基本不涉及,嵌入式才要管 |
| 违约终止与恢复 | 违规后改正可恢复授权 | 收到投诉先整改再沟通,别硬扛 |
注意:这里面最容易被忽略的是“修改标注”。很多贡献者改了一个函数就直接提交,文件头什么都没写。这在技术上构成不合规,虽然几乎没人追究,但既然我们对外宣称合规,就得自己先做到。
1.3 为什么不是 MIT 或 Apache-2.0
这个问题被问过很多次。选型的时候我列了一张表,把四个候选协议放在一起对比了三天:
| 协议 | 对下游的约束 | 对本项目的保护 | 适合场景 |
|---|---|---|---|
| MIT | 几乎没有,保留声明即可 | 极弱,改完闭源也行 | 想最大化传播、不在乎回流的工具库 |
| Apache-2.0 | 保留声明与 NOTICE,含专利条款 | 中等 | 有企业用户、需要专利明确授权 |
| MPL-2.0 | 文件级著佐权,改动文件需开源 | 中等偏强 | 想被大项目嵌入但保留核心回流 |
| GPL-3.0 | 整体著佐权,衍生作品需同协议 | 强 | 希望衍生版本必须回到社区 |
选 GPL-3.0 的真实原因很朴素:这个企划的代码本身不值钱,值钱的是它长出来的生态。如果有人基于covenant-core做一个改版分发出去,我们希望那个改版的代码也能回来,而不是变成一个新的封闭分支把用户吸走。这是强著佐权的核心动机,跟道德无关,跟生态策略有关。
代价也要讲清楚:GPL-3.0 会挡掉一部分商业合作。曾经有个做线下展陈的团队想嵌入我们的战斗逻辑做互动装置,看到协议就退了——因为他们的整体系统不开源。这个损失是预期之内的,选之前就要认。
2. 真正的雷区在素材:三层权利归属要分清
2.1 三类素材,三种处理方式
代码协议理清之后,素材才是重灾区。我把企划里的素材按来源分成三层,每层的处理逻辑完全不同:
- 第一层:自产素材。画师、作曲、文案在企划内部产出的东西。核心问题是“职务作品”还是“个人作品”——如果当初没有书面约定,权利默认在创作者个人手上,企划只有使用权。这一点很多同人团队完全没意识到。
- 第二层:社区贡献素材。外部画师投稿的立绘、玩家做的地图、配音爱好者录的语音。核心问题是授权范围,是“仅限本项目使用”还是“允许再分发”。
- 第三层:外部引入素材。字体、音效库、开源模型、第三方图标。核心问题是许可证兼容性——一个 CC BY-NC 的音效包塞进 GPL-3.0 的项目里,会直接产生冲突。
2.2 各层素材的权利与可用范围
| 素材类型 | 权利归属 | 允许的用法 | 最常见的误用 |
|---|---|---|---|
| 内部画师立绘 | 画师个人(无书面转让时) | 企划内使用,需逐张确认是否可商用 | 直接授权给第三方做周边 |
| 社区投稿立绘 | 投稿者,授权范围以投稿协议为准 | 按协议约定,通常是企划内非商业使用 | 默认当成“全权归企划” |
| 字体 | 字体厂商 | 按字体许可,很多仅限个人非商业 | 打包进发布包分发 |
| 音效包 | 原始作者 | 按音效包协议,注意是否要求署名 | 混音后当成原创音轨 |
| 开源模型 | 模型协议 | 按协议,注意商用与再分发条款 | 直接放进素材仓库当自有资产 |
2.3 二次创作能不能做,用四问法判断
社区里最常见的问题是“我能不能拿你们的立绘做个 MAD”“我能不能把 BOSS 改成另一个形态”。每次逐个回复太累,我总结了一个四问法,贡献者和二创作者自己就能判断:
- 我用的是代码还是素材?代码走 GPL-3.0,做衍生分发就要开源;素材走自定义协议,做二创通常没问题,但不能商用。
- 我是自己看还是发给别人?自己本地改,几乎没人管;公开发布就进入分发范畴,义务立刻生效。
- 我改的是“表达”还是“思想”?换一套数值、改一段剧情走向,属于新表达;直接抠图重贴,属于复制。
- 我有没有从中赚钱?这是同人生态里最敏感的一条线,绝大多数企划的底线都画在“非商业”上。
提示:把这四问写进仓库的
FANWORK.md,比在群里反复解释有效得多。文档一次写清,能省掉后面几百次问答。
2.4 建一份能用的素材台账
不做台账,三个月后你绝对想不起来某张背景图是从哪来的。我的做法是建一个assets-manifest.csv,字段控制在九个以内——字段太多没人维护,太少又不够用:
id,file,type,author,source,license,commercial,attribution,added_date A-001,bg_city_night.png,art,内部画师A,自产,internal-nc,no,企划署名,2023-04-11 A-002,ui_click.ogg,audio,社区贡献者B,投稿,community-nc,no,需署名B,2023-06-02 A-003,font_main.ttf,font,外部,官方下载,font-personal,no,需附许可文本,2023-06-20 A-004,model_guard.glb,model,内部建模C,自产,internal-nc,no,企划署名,2023-09-15关键在于license和commercial两列——每引入一个文件,先填这两列,填不出来就说明你还没搞清楚它能不能用,那就先别用。
3. 社区贡献怎么收:从提交到合并的闭环
3.1 DCO 还是 CLA,小团队别硬上 CLA
外部贡献者进来第一件事是确认“他给的东西我们真的能用”。行业里有两条路:DCO(开发者原创声明)和 CLA(贡献者许可协议)。
CLA 是一份需要签字的合同,把贡献者的权利部分转让或授权给项目方,法律效力强,但流程重——每个贡献者都要走一遍签署流程,小项目根本撑不住这个运营成本。DCO 则简单得多,只是在提交信息里加一行Signed-off-by,声明“这份代码是我写的,我有权按项目协议提交”。
《卫戍协议:盟约》选的是 DCO,理由有三条:一是贡献者以个人爱好者为主,让他们签合同会直接劝退一半人;二是项目没有商业实体,CLA 签了也没有主体承接;三是 DCO 配合 GPL-3.0 已经能覆盖绝大多数场景。唯一的短板是遇到明显侵权的提交时举证麻烦,这个风险我们接受。
3.2 仓库结构与分支约定
结构清晰能省掉一半沟通成本。现在的布局大致是这样:
covenant-core/ ├── LICENSE # GPL-3.0 全文 ├── COPYING.NOTES # 为什么选它、素材为何不适用 ├── CONTRIBUTING.md # 贡献流程 ├── FANWORK.md # 二创授权说明 ├── CONTRIBUTORS.md # 署名清单 ├── src/ │ ├── battle/ # 战斗逻辑 │ ├── protocol/ # 协议解析 │ └── ui/ # 界面逻辑(不含美术资源) ├── tools/ # 构建与校验脚本 └── tests/分支上只保留三条长期分支:main(可发布)、dev(集成分支)、gh-pages(文档)。功能分支一律feat/xxx、fix/xxx,合并后即删。这个策略朴素但够用,唯一的要求是main上的每个提交都必须能通过完整构建——发布包就是从main上打的。
3.3 提交规范与自动化检查
光靠文档约束不住人,得让机器来卡。我们做了三层检查:本地提交钩子、CI 流水线、人工评审。
本地这层用 pre-commit,配置大概是这样:
# .pre-commit-config.yaml repos: - repo: local hooks: - id: license-header name: 检查源文件许可证头 entry: python tools/check_header.py language: system files: \.(c|cpp|h|py|js)$ - id: no-binary-in-src name: 禁止二进制文件进 src entry: bash tools/check_binary.sh language: system files: ^src/check_header.py的逻辑很简单,读文件前 15 行,找不到SPDX-License-Identifier: GPL-3.0-or-later就报错。check_binary.sh则是防止有人把一张 PNG 塞进src/目录——这类事情真的发生过,而且发生了两次。
CI 这层加了签名校验,确保每个提交都带Signed-off-by:
# .github/workflows/dco.yml(示意) name: DCO Check on: [pull_request] jobs: check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: 校验签名 run: | git log origin/main..HEAD --pretty=%B | \ grep -q "Signed-off-by:" || \ (echo "缺少 Signed-off-by,请用 git commit -s" && exit 1)3.4 合并前的审核清单
人工评审这一层,我固定用一张表过一遍,不看代码质量先看合规:
| 检查项 | 判断标准 | 不通过怎么处理 |
|---|---|---|
| 是否带签名 | 提交信息含 Signed-off-by | 让贡献者git commit -s --amend |
| 是否引入外部素材 | 提交里有图片、音频、模型文件 | 一律打回,素材走素材仓库单独审 |
| 是否拷贝了外部代码 | 有可疑的大段函数、注释风格突变 | 要求说明来源,必要时替换实现 |
| 是否改动许可证声明 | 文件头被删或被改 | 直接拒绝 |
| 是否引入新依赖 | 构建脚本里出现新包 | 检查依赖协议是否与 GPL-3.0 兼容 |
最后一条特别值得说:依赖协议兼容性是个隐形炸弹。宽松协议(MIT、Apache-2.0、BSD)进 GPL-3.0 一般没问题;但如果是另一个强著佐权协议且条款不兼容,或者带了“仅限非商业”的限制,一旦合并进去,整个项目的授权状态就变浑了。我们的规矩是:新依赖必须单独开一个 PR 说明用途和协议,合并前我先看协议兼容性。
3.5 署名与致谢怎么做得体面
贡献者最在意的往往不是钱,是被看见。CONTRIBUTORS.md我们做成半自动的:一个脚本从 git 历史里抽取作者名和首次提交时间,按时间排序生成初稿,人工补充角色说明(代码、美术、测试、文档、翻译)。每次发版更新一次,跟着发布公告一起发。
这里有个细节:署名不等于版权转让。在 CONTRIBUTORS.md 里列出名字,只是致谢,不改变任何权利归属。为了避免误解,文件开头写了一句“本清单仅为致谢,代码版权归属以各文件头部声明与 LICENSE 为准”。这句话被引用过好几次,说明确实有必要。
4. 分发环节:发布包怎么打才不留尾巴
4.1 源码必须跟着二进制走
GPL-3.0 的核心义务发生在“分发”这一刻。你把编译好的程序发给别人,就得保证对方能拿到对应版本的源码。操作上有两条路:把源码塞进发布包,或者提供一个稳定的、有效期足够长的下载地址。
我们两种都做了,因为只给链接的风险是链接会失效。发布包的目录结构是这样的:
covenant-release-v1.4.2/ ├── bin/ │ └── covenant # 可执行文件 ├── assets/ # 素材,单独许可 │ ├── LICENSE-ASSETS.md │ └── assets-manifest.csv ├── source/ # 完整源码快照 │ ├── LICENSE # GPL-3.0 全文 │ └── ... ├── LICENSE # 顶层说明,指向两份许可 ├── NOTICE # 第三方组件与素材清单 └── README.md4.2 LICENSE 与 NOTICE 怎么组织
顶层 LICENSE 不抄全文,只写一段指引,说明哪部分适用哪份协议,然后把两份完整许可放在对应目录。这样做的原因是:如果顶层只放 GPL-3.0 全文,会给人一种“素材也是 GPL”的错觉,而这正是我们最初踩的坑。
NOTICE 文件里逐条列出第三方组件和素材,格式统一成“名称 / 来源 / 协议 / 用途”四段。举两个条目:
组件:音频解码库(宽松协议) 用途:ogg 格式解码 协议:MIT 说明:完整许可文本见 source/third_party/mit-decode/LICENSE 素材:界面字体 用途:UI 文本渲染 协议:字体厂商个人非商业许可 说明:仅随程序分发,不得单独提取使用4.3 版本迭代与历史存档
有个容易被忽略的点:GPL-3.0 的源码提供义务针对的是你实际分发出去的那个版本,不是最新版。所以每发一个版本,都要留一份不可变的快照。我们的做法是每次打 tag 时同步生成一份source-snapshot-vX.Y.Z.tar.gz,连同校验值一起归档到独立存储,保留期至少三年。
版本号本身也有讲究。我们的规则是:素材变更但代码没变,走修订号(1.4.2 → 1.4.3);代码有功能变更走次版本号;协议或授权条款有任何调整,直接进主版本号,并在发布说明里单独列一段“授权变更”。这条规则不是洁癖,是为了让别人能一眼看出“这次升级会不会影响我的使用权利”。
5. 常见问题与排查实录
5.1 问题速查表
| 现象 | 大概率原因 | 处理方式 |
|---|---|---|
| 有人拿立绘做付费周边 | 素材许可没写清,或没单独声明 | 补 FANWORK.md,公开说明边界,先礼后兵 |
| 贡献者提交里带了一张图 | 不知道素材要走单独仓库 | 打回并引导到素材投稿流程 |
| CI 报缺少签名 | 用了git commit而非-s | 教一次--amend -s,写进 CONTRIBUTING |
| 发布包被投诉缺源码 | 只给了链接且链接失效 | 改为源码内嵌,长期归档 |
| 新依赖协议不兼容 | 合并前没查协议 | 回滚该依赖,找替代或自己实现 |
| 文件头声明被删 | 格式化工具覆盖 | 配置格式化工具保留头部,加 CI 校验 |
5.2 三个印象最深的场景
场景一:字体引发的下架。早期版本里用了一款看起来很普通的字体,打包时直接塞进了assets/。后来有人提醒,那款字体的许可只允许个人非商业使用,且明确禁止再分发字体文件本身。我们连夜换字体、重打包、发公告。教训是:字体是最容易出事的一类素材,因为它看起来“只是个字体”,但它的许可条款往往比美术还严。
场景二:贡献者提交了“借鉴”来的代码。有个 PR 里的战斗判定逻辑写得很漂亮,但函数命名风格和注释习惯跟仓库其他部分完全不搭。追问之后对方承认是参考了另一个项目的实现,虽然没有逐字复制,但结构高度相似。我们最终没有合并,让对方按自己的思路重写了一遍。这件事让我在审核清单里加了一条:代码风格突变本身就是信号。
场景三:素材台账断更。有一段时间赶进度,新加的三十多张图全没登记。三个月后要做一个宣传物料,需要确认每张图能不能商用,结果花了整整两天回溯聊天记录和提交历史。从那以后定了死规矩:素材入库和台账登记必须同一个 PR,不登记不予合并。
5.3 几条不用花钱但很管用的技巧
第一,把授权说明写成“人话版”和“法条版”两份。法条版给认真的人看,人话版给大多数玩家看。我们的FANWORK.md开头就是三句话:代码开源、素材不完全开源、二创非商业随便做。这三句话挡掉了七成的重复提问。
第二,给贡献流程做一个“五分钟上手”文档。新贡献者最怕的不是难,是不知道自己该从哪开始。我们在 CONTRIBUTING 开头列了五类低门槛任务:文档纠错、翻译、测试反馈、数值平衡建议、UI 文案优化。这些都不涉及代码和素材权利,新人做完第一件事就有参与感。
第三,所有涉及授权的沟通留文字记录。群里口头答应“这个图你可以用”,半年后双方都记不清具体范围,这种事太常见。我的做法是:任何素材授权都要求在素材仓库开一个 issue,写清文件、范围、期限,双方确认后关单。这条规矩一开始被嫌麻烦,出过一次纠纷之后就没人抱怨了。
第四,定期做一次“授权体检”。每半年花两个小时,把素材台账、NOTICE 文件、LICENSE 目录对着仓库实际内容核一遍。听起来枯燥,但我确实在这件事上发现过两个遗留问题:一个是某张图的作者在投稿后要求撤回授权,另一个是某个依赖在升级后换了协议。
我自己在这套流程上摸索了挺久,最大的体会是:同人企划的合规不是一道墙,而是一条随项目一起移动的线。项目刚起步时,一份写清边界的 README 就够了;开始有人提 PR 时,得有 DCO 和审核清单;等到有人拿它做二次分发时,发布包结构和版本归档才真正变得重要。不用一上来就把所有东西做全,但每一步都得留痕——留痕这件事,永远是事后补救成本最低的做法。