带有仅当前跟踪文件的历史复制的新回购

我们目前的数据库有成千上万的提交,而新鲜的克隆传输了近一个数据(有很多jar文件已经被删除了)。 我们希望通过制作一个新的repo来保存完整的历史logging,只保存当前在repo中激活的文件,或者修改当前的repo以清除已删除的文件历史logging。 但我不确定如何在实际的庄园做到这一点。

我已经尝试删除从git历史删除的文件中的脚本:

for del in `cat deleted.txt` do git filter-branch --index-filter "git rm --cached --ignore-unmatch $del" --prune-empty -- --all # The following seems to be necessary every time # because otherwise git won't overwrite refs/original git reset --hard git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d git reflog expire --expire=now --all git gc --aggressive --prune=now done; 

但是鉴于我们在历史上有成千上万的被删除的文件和成千上万的提交,运行这个脚本将是永恒的。 2小时前,我开始只运行一个被删除的文件,而filter-branch命令仍在运行,每次执行一次40,000多个提交,这是一个新的MacBook Pro与SSD驱动器。

我也读过https://help.github.com/articles/remove-sensitive-data页面,但这只适用于删除单个文件。

有没有人能够做到这一点? 我真的想保留目前跟踪的文件的历史,我不知道如果我们不能保持历史,节省空间的好处是否值得创build一个新的回购。

删除一切,恢复你想要的

而不是一次删除一个文件列表, 做几乎相反 ,删除一切,只是恢复你想保留的文件:

 $ git checkout master $ git ls-files > keep-these.txt $ git filter-branch --force --index-filter \ "git rm --ignore-unmatch --cached -qr . ; \ cat $PWD/keep-these.txt | xargs git reset -q \$GIT_COMMIT --" \ --prune-empty --tag-name-filter cat -- --all 

执行起来可能会更快。

清理步骤

一旦整个过程完成, 然后清理:

 $ rm -rf .git/refs/original/ $ git reflog expire --expire=now --all $ git gc --prune=now # optional extra gc. Slow and may not further-reduce the repo size $ git gc --aggressive --prune=now 

比较之前和之后的版本库大小,应该表明一个相当大的减less,当然只有提交触摸保存的文件,再加上合并提交 – 即使是空的( 因为这是如何–prune空作品 ),将在历史上。

$ GIT_COMMIT?

使用$GIT_COMMIT似乎引起了一些混淆, 从gitfilter分支文档 (强调添加):

参数总是使用eval命令在shell上下文中进行评估(出于技术原因,提交filter的值得注意的例外)。 在此之前, $ GIT_COMMIT环境variables将被设置为包含被重写的提交的ID

这意味着git filter-branch将在运行时提供variables,而不是由您提供。 如果使用no-op filter filter命令有任何疑问,可以certificate这一点:

 $ git filter-branch --index-filter "echo current commit is \$GIT_COMMIT" Rewrite d832800a85be9ef4ee6fda2fe4b3b6715c8bb860 (1/xxxxx)current commit is d832800a85be9ef4ee6fda2fe4b3b6715c8bb860 Rewrite cd86555549ac17aeaa28abecaf450b49ce5ae663 (2/xxxxx)current commit is cd86555549ac17aeaa28abecaf450b49ce5ae663 ... 

基于AD7six,保留了重命名的文件历史logging。 (你可以跳过初步的可选部分)

可选的

删除所有遥控器:

 git remote | while read -r line; do (git remote rm "$line"); done 

删除所有标签:

 git tag | xargs git tag -d 

删除所有其他分支:

 git branch | grep -v \* | xargs git branch -D 

删除所有的藏品 :

 git stash clear 

删除所有的子模块configuration和caching :

 git config --local -l | grep submodule | sed -e 's/^\(submodule\.[^.]*\)\(.*\)/\1/g' | while read -r line; do (git config --local --remove-section "$line"); done rm -rf .git/modules/ 

修剪未跟踪的文件历史,保持跟踪的文件历史和重命名

 git ls-files | sed -e 's/^/"/g' -e 's/$/"/g' > keep-these.txt git ls-files | while read -r line; do (git log --follow --raw --diff-filter=R --pretty=format:%H "$line" | while true; do if ! read hash; then break; fi; IFS=$'\t' read mode_etc oldname newname; read blankline; echo $oldname; done); done | sed -e 's/^/"/g' -e 's/$/"/g' >> keep-these.txt git filter-branch --force --index-filter "git rm --ignore-unmatch --cached -qr .; cat \"$PWD/keep-these.txt\" | xargs git reset -q \$GIT_COMMIT --" --prune-empty --tag-name-filter cat -- --all rm keep-these.txt rm -rf .git/refs/original/ git reflog expire --expire=now --all git gc --prune=now 
  • 前两个命令是列出跟踪的文件和跟踪文件的旧名称,用引号保留具有空格的path。
  • 第三个命令是只重写这些文件的提交。
  • 后续的命令是清理历史logging。

可选(不推荐)

重新包装(来自git-gc-aggressive ):

 git repack -a -d --depth=250 --window=250 

只运行一次gitfilter分支

问题中的脚本将处理数千次提交,数千次 – 每次迭代都会执行一次(非常慢)的事情,通常只会在最后完成。 这真的是要永远。

而是运行脚本一次,一次删除所有文件:

 del=`cat deleted.txt` git filter-branch --force --index-filter \ "git rm --cached --ignore-unmatch $del" \ --prune-empty --tag-name-filter cat -- --all 

一旦该过程完成, 然后清理:

 rm -rf .git/refs/original/ git reflog expire --expire=now --all git gc --prune=now # optional extra gc. Slow and may not further-reduce the repo size git gc --aggressive --prune=now 

如果由于文件数量而导致以上失败

如果在deleted.txt中有足够的文件,以致上述命令太大而无法运行,则可以将其重写为如下所示:

 git filter-branch --force --index-filter \ 'cat /abs/path/to/deleted.txt | xargs git rm --cached --ignore-unmatch' \ --prune-empty --tag-name-filter cat -- --all 

(清理步骤是一样的)

这与上面的版本是一样的 – 但删除文件的命令一次只做一次,而不是一次。