仓库被封禁
在 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 投诉为恶意投诉且并无版权问题。
延展阅读
当时考虑到我们已经错过了窗口期,没办法删除 GitHub 上仓库中的特定文件,所以想通过 DMCA Counter Notice 来解除封禁。
为此,我通过 Github 发给我们的邮件,找到了那份侵权文件,并在他的网站中找到了版权拥有者的邮件,发送邮件说明情况,看看能否通过付费获得授权。但其是挪威人,存在时差,所以我们只能边等待,边想办法。
山重水复疑无路,柳暗花明又一村
在准备 DMCA Counter Notice 时,我们又向 Github 发送了邮件,说明了中国春节的特殊情况,导致我们没有来得及处理文件,请求给我们一个机会让我们处理这些文件。但是迟迟没有回应,无奈之下,多位成员又以成员身份向 GitHub 发送邮件,请求给予帮助。
令人惊奇的是,经过大约 9 个小时的等待,仓库拥有者的请求邮件似乎开小差了,而各位成员的请求邮件得到了响应。Github 回信给大家说,根据其规则,给出了额外的 24 小时窗口期,让我们处理这些文件(后来经过仔细查阅 GitHub 的 DMCA Takedown 规则,对这种错过了第一次窗口期的情况,可以给予第二个,也是最后一个窗口期)。但是这个开启额外的窗口期,需要仓库的拥有者向 GitHub 发送邮件请求。
然后,我们就以仓库拥有者的身份再次向 GitHub 发送了请求,可能是由于时差的原因,又是几个小时没有回应。
与此同时,我们也收到了版权拥有者的回复。很遗憾,原作者不愿意授权,也不打算收费。好在 Github 给的额外窗口期,让我们有了改正错误的机会。
还好,在焦急的等待之中,我们终于收到了 GitHub 的回复,并同时恢复了仓库的访问——宝贵的 24 小时窗口期。
使用 BFG 处理文件
得到了窗口期后,我们开始处理仓库内的文件。
首先,你得清除了现在还在仓库里面的文件,然后再使用下面的方面来清除提交历史中的数据。
推荐阅读
以下文章建议按顺序阅读
删除 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 是只读不可改的。所以我们无法修改这些信息。
至此,我们将文件进行了删除处理,并清除了相关的数据。
后续处理
在完成文件及历史数据的删除后,我们将我们的删除结果回复了 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/
发表回复