仓库被封禁
在 2018 年 2 月 20 日,我们的开源项目放在 GitHub 上的仓库由于收到了 DMCA Takedown 投诉被封禁,仓库处于不可访问状态。此时在 GitHub 上访问该仓库时,会显示一个公开消息,表明该仓库被封禁的原因。
按照 GitHub DMCA 的规则,GitHub 在确认投诉有效后,会给该仓库的管理员发送一封邮件,提示该仓库需要在 24 小时内清理被投诉的内容,并回复 GitHub 才行——否则,该仓库会被封禁,禁止任何访问和数据导出。
我们在收到该 Takedown 投诉后,会有 24 小时的时间来响应,但由于过年期间,仓库拥有者没有及时看到邮件,未能及时发现这么严重的通知。因此,在过了 24 小时后, Github 按照 DMCA 的规则,进行了仓库的封禁。
仓库被封禁后,我们发现无法访问。根据封禁消息的提示,发现原来之前仓库内的某个文件出了问题,侵犯了原作者的版权。原作者向 Github 发送了 DMCA 投诉。而由于我们的未及时处理,导致了仓库的最终被封。当我们发现被封时,已经是深夜了。
紧急商讨方案
在被封禁后,由于已经超过了 24 小时时限,在这个阶段下, GitHub 的文档中给出的解决方案仅有请求 GitHub 来删除该仓库并根据自己手里的仓库数据重建的方案。但对我们来说,这种方案是不可接受的,因为这种方案会导致丢失所有的 issue、PR、Wiki,以及你本地的仓库和远程的仓库之间的版本差异。
我们在群内先找了更新最全的 fork,找到了一个群友提供的,和上游只差 2 个提交的版本,并将其保存下来,作为最后的自救手段。
此外,在查询 DMCA 的过程中,我了解到 DMCA 除了有 DMCA Takedown 以外,还有一个 DMCA Counter Notice,用于反向解除 DMCA 封禁。
DMCA Counter Notice
DMCA Counter Notice 用于向服务商发起申诉,说明 DMCA Takedown 投诉为恶意投诉且并无版权问题。
延展阅读
https://help.github.com/articles/guide-to-submitting-a-dmca-counter-notice/
当时考虑到我们已经错过了窗口期,没办法删除 GitHub 上仓库中的特定文件,所以想通过 DMCA Counter Notice 来解除封禁。
为此,我通过 Github 发给我们的邮件,找到了那份侵权文件,并在他的网站中找到了版权拥有者的邮件,发送邮件说明情况,看看能否通过付费获得授权。但其是挪威人,存在时差,所以我们只能边等待,边想办法。
山重水复疑无路,柳暗花明又一村
在准备 DMCA Counter Notice 时,我们又向 Github 发送了邮件,说明了中国春节的特殊情况,导致我们没有来得及处理文件,请求给我们一个机会让我们处理这些文件。但是迟迟没有回应,无奈之下,多位成员又以成员身份向 GitHub 发送邮件,请求给予帮助。
令人惊奇的是,经过大约 9 个小时的等待,仓库拥有者的请求邮件似乎开小差了,而各位成员的请求邮件得到了响应。Github 回信给大家说,根据其规则,给出了额外的 24 小时窗口期,让我们处理这些文件(后来经过仔细查阅 GitHub 的 DMCA Takedown 规则,对这种错过了第一次窗口期的情况,可以给予第二个,也是最后一个窗口期)。但是这个开启额外的窗口期,需要仓库的拥有者向 GitHub 发送邮件请求。
然后,我们就以仓库拥有者的身份再次向 GitHub 发送了请求,可能是由于时差的原因,又是几个小时没有回应。
与此同时,我们也收到了版权拥有者的回复。很遗憾,原作者不愿意授权,也不打算收费。好在 Github 给的额外窗口期,让我们有了改正错误的机会。
还好,在焦急的等待之中,我们终于收到了 GitHub 的回复,并同时恢复了仓库的访问——宝贵的 24 小时窗口期。
使用 BFG 处理文件
得到了窗口期后,我们开始处理仓库内的文件。
首先,你得清除了现在还在仓库里面的文件,然后再使用下面的方面来清除提交历史中的数据。
推荐阅读
以下文章建议按顺序阅读
https://help.github.com/articles/removing-sensitive-data-from-a-repository/
https://rtyley.github.io/bfg-repo-cleaner/
删除 Git 仓库的历史数据有多种方法,一种是使用 git filter-branch
来处理,但是速度极慢。另外一种就是使用 BFG 来处理,我们采用的是 BFG 来处理(BFG 是git filter-branch
首字母的逆转)。
BFG 需要 Java 的运行环境,如果无法运行,请检查你的本地 Java 环境是否安装,或高于 Java 7 。
Java 6 需要使用 bfg v1.12.3版本
BFG 的处理过程比较简单,首先,你需要下载 BFG。
wget http://repo1.maven.org/maven2/com/madgag/bfg/1.13.0/bfg-1.13.0.jar
然后克隆你的仓库到本地,比如 bestony/test
。
git clone --mirror git://github.com/bestony/test.git
克隆时用不用 --mirror
模式都可以,但是后续命令上会有所差距,所以我还是推荐大家使用镜像模式,毕竟按照官方的文档走,出现了问题也好搜索。(镜像模式克隆的仓库和远程仓库完全一样,但是不能直接看到仓库里面的文件,而且也不能允许 git
的各种命令)
克隆到本地后,执行 BFG 命令来处理文件。
cd test.git
java -jar bfg.jar --delete-files "filename"
这里需要注意的是,
filename
不支持目录路径,只能是文件名,而不能是dir/filename
这样的形式,所以添加参数时你要注意这个。对于有同样名字的文件却想只删除某个目录的情况,可能就没有办法了。此外,默认情况下, BFG 不会处理最新的提交,它认为你的最新提交应该是干净的(不包含需要删除的敏感数据),如果你要删除的文件是最新的提交(比如你最新的一个提交是删除那些敏感数据),可以加入
--no-blob-protection
参数来强制清除,也可以再添加一个提交,使包含了要被删除文件的提交不是最新的提交。java -jar bfg.jar --delete-files "filename" --no-blob-protection
BFG 处理完成后,会提示你使用 git
命令进行垃圾回收,你需要执行如下命令来操作:
cd test.git # 进入目标目录
git reflog expire --expire=now --all && git gc --prune=now --aggressive # 垃圾回收
这里需要注意的是,如果你删除多个文件,每次删除后执行和多个文件都删除后效果一样,所以建议你删除多个文件后再进行垃圾回收,会更省时一些。
处理完成后,将数据推送到远端即可(需要关闭 GitHub 上仓库设置里面对强制推送的防护):
git push
执行完成后,就可以到远端上去看了,你的文件会被删除,相关的提交不会被删除,但是提交里面不包含该文件了。
在推送时,可能会提示你有些更改被拒绝了,这些更改如果是和 Pull Request 有关的,你可以不需要在意,这是 GitHub 自身的问题。Github 设定 Pull Request 是只读不可改的。所以我们无法修改这些信息。
具体可以参考 https://github.com/rtyley/bfg-repo-cleaner/issues/36
至此,我们将文件进行了删除处理,并清除了相关的数据。
后续处理
在完成文件及历史数据的删除后,我们将我们的删除结果回复了 Github ,等待 Github 的确认。GitHub 会在 24 小时收到该回复后,会通知投诉方进行确认。如果投诉方无异议,此事就此结束,不会再有下一步动作。如果有异议,则会重新进行此流程。
此外,由于 GitHub 存在垃圾缓存回收的时间差,所以你推送到 GitHub 上的数据虽然并无需要被删除的文件,但是依旧在一定时间内可以看到。这种缓存只能请 GitHub 自行操作删除。此外,与要删除的文件相关的 Pull Request 也需要 GitHub 来删除——因为用户是没有权限删除 Pull Request 的。这些请求也可以一并发给 GitHub 来操作(但似乎 GitHub 并不热衷执行这些请求,只要被投诉的文件访问不到即可,也就是说,如果没有被投诉历史数据,其实或许并不用大动干戈清理历史……)。
这种清除操作还有一个副作用就是,所有之前 fork 的仓库,由于主仓库被封禁而导致各个 fork 仓库的 remote 意外地变为另外一个仓库(该仓库是最早的一个 fork 仓库)。而主仓库恢复之后,我们并没有找到好的办法将 remote 恢复回原来的主仓库。因此,需要所有成员重新 fork 主仓库并从缓慢的 GitHub 克隆到本地。
余思
这个惊魂事件当中,我们首先要反思的是,我们对版权问题的认识不足,这是一切问题的根源。因此,这之后,我们对既有数据进行了排查。
其次,GitHub 在这种事件的处置上,我们认为也并不够好。这么严重的处置(整个库封禁),仅仅通过一份普通的邮件通知,而且仅仅给出 24 小时的时间窗口。而 GitHub 其实掌握了仓库拥有者的更可靠、更及时的联系方式,比如说手机短信,也完全可以在 GitHub 的网页界面上以显目的方式提醒。另外,虽然 DMCA 规则中提到了可以容情第二个时间窗口,但是似乎这个附加窗口期是后来才改变的政策,在前面的流程说明中并未提及,很容易忽视。
其三,由于封禁会导致对该仓库的所有访问均不可进行,这不仅包括了提交数据,也包括了并没有存在于 Git 仓库中的 issue、PR 和 Wiki 等数据,而 GitHub 不会让你在封禁的情况下有机会导出这些数据。所以,有机会的话,各种数据还是有个备份的好。
最后,感谢在这个事件中,所有不离不弃支持我们的成员,感谢小白进行的仓库清理工作。
相关阅读
- https://blog.kongfanjian.com/2015/03/02/%E6%B0%B8%E4%B9%85%E5%88%A0%E9%99%A4git%E4%BB%93%E5%BA%93%E4%B8%AD%E7%9A%84%E6%96%87%E4%BB%B6%E4%B8%8E%E5%8E%86%E5%8F%B2%E8%AE%B0%E5%BD%95/
- https://changkun.us/archives/2017/11/239/
- http://debugtalk.com/post/clean-sensitive-data-from-git-history-commits/
- http://www.voidcn.com/article/p-njmjnwov-bgk.html
- http://www.vicviz.com/githubshang-de-min-gan-shu-ju-de-shan-chu/
- https://lightless.me/archives/remove-sensitive-data-on-github.html
- http://blog.csdn.net/duandianR/article/details/78843582
- https://www.clock.co.uk/insight/deleting-a-git-commit
- https://www.jacoballred.com/web-dev/use-bfg-to-completely-remove-a-file-from-your-git-repo/
- https://community.atlassian.com/t5/Questions/BFG-for-a-Noob/qaq-p/350944
- https://w3guy.com/remove-git-commit-history/