git remove file from revision history
March 18th, 2009
Comments off
最近学习 git,真是非常强大,非常不好用的软件。
一个常见的需求:有一个文件,包含敏感信息,不小心加进git库里面去了。希望从源码库的所有历史记录中删除该文件的所有版本。
其他的源码管理系统也会有类似的功能。如果是 CVS,就到源码库目录下直接删除 RCS 文件。如果是 Subversion,则是用 svnadmin dump 之后,用 import filter 再倒入。
git-filter-branch 命令包含各种回溯修改 revision history 的功能,经过尝试,获得心得若干:
- 首先,git 的命令可扩展性很强,但对初学者来说,要记忆的命令太长,像看天书;
- 其次,git 往往一个命令完成不了任务,需要多个命令配合,但文档对此语焉不详,初学者无所适从;
- 最后,也是最难的,git 中概念太多,名字非常不直观,从传统源码管理的层次理解起来台阶太高。
为此,写了几个 bash function,封装 git 的上述功能。用法如下
- git-rewrite-commits exclude_files_list:将文件从 reivision history 中删除,可指定要删除的目录;
- git-prune-commits:上面的命令执行之后,可能出现空的 commit 对象,用这个命令可以清空这类对象;
- git-rewrite-msg regex:regex 是可被 sed 接受的正则表达式,用该命令修改所有的 commit 注释;
如果直接使用 filter-branch 从 git 历史中删除文件,会将工作拷贝中的文件也删除。而如果只是想把清除 git 库中的敏感文件,用户可能希望保留工作拷贝中的这些文件。使用 git-rewrite-commits 可以起到保留要删除的文件的效果。
另外,由于 git 是分布式源码管理,用这种做法因此光删除一个库中的文件历史并不够。为了避免下游的库将删除后的敏感文件又 push 回来,应该对 git 库的所有副本执行相同的清除操作,这样才保险。
附:相关 bash 脚本,加入 .bashrc 中生效
function git-remove-refs() { if [ -z $@ ] ; then echo "Usage: git-remove-refs refs_name" return fi git for-each-ref --format="%(refname)" refs/$1 | xargs -I Ref bash -c "echo removing git ref: Ref; git update-ref -d Ref" } function git-backup-files() { FILES=`git ls-files $@` for File in $FILES do echo save backup for $File done GIT_BACKUP_TMP=`tempfile`.tar.gz tar czf $GIT_BACKUP_TMP $FILES echo backup file saved at $GIT_BACKUP_TMP } function git-restore-files() { if [ -f $GIT_BACKUP_TMP ] ; then echo backup file $GIT_BACKUP_TMP restored tar xzf $GIT_BACKUP_TMP unset GIT_BACKUP_TMP fi } function git-rewrite-commits() { if [ -z $@ ] ; then echo "Usage: git-rewrite-commits files_to_remove" return fi git-backup-files $@ git filter-branch --index-filter "git ls-files -z $@ | git update-index --remove -z --stdin" git-remove-refs original git-restore-files } function git-prune-commits() { if [ ! -z $@ ] ; then echo "Usage: git-prune-commits" return fi git filter-branch --prune-empty git-remove-refs original } function git-rewrite-msg() { if [ -z $@ ] ; then echo "Usage: git-rewrite-msg regex_pattern" return fi git filter-branch --msg-filter "sed -e \"$1\"" git-remove-refs original }
Recent Comments