Ale*_*nov 17 git git-filter-branch git-branch
假设我有这样的树:
... -- a -- b -- c -- d -- ...
\
e -- a -- k
Run Code Online (Sandbox Code Playgroud)
我希望它变得公正
... -- a -- b -- c -- d -- ...
Run Code Online (Sandbox Code Playgroud)
我知道如何将分支名称附加到"e".我知道我要做的事情会改变历史,这很糟糕.另外我想我需要使用像rebase或filter-branch这样的东西.但究竟是什么 - 我迷路了.
好.情况如下:我现在有一棵相当大的树(像这样)
s -- p -- r
/
a -- b -- c -- d -- e --- g -- w
\ \
t -- p -- l y -- k
Run Code Online (Sandbox Code Playgroud)
但是在我的第一次提交中(比如前面的"b"),我添加了二进制文件,这使整个回购非常繁重.所以我决定把它们带走.我用filter-branch做了.现在,从第二次提交开始,我有两个长的提交分支.
s -- p -- r
/
a -- b -- c -- d -- e --- g -- w
\ \ \
\ t -- p -- l y -- k
\
\ s'-- p'-- r'
\ /
b'-- c'-- d'-- e'--- g'-- w'
\ \
t'-- p'-- l' y'-- k'
Run Code Online (Sandbox Code Playgroud)
其中b'在没有二进制文件的情况下提交.所以我不能合并.我不希望这整块树在历史上重复.
Gre*_*con 37
在导入具有多年历史的Subversion存储库之后,我遇到了类似的问题,其中存在来自大量二进制资产的膨胀.在git:收缩Subversion导入中,我描述了将我的git repo从4.5 GiB修剪到大约100 MiB.
假设您要从所有提交中删除"删除媒体文件"(6fe87d)中删除的文件,您可以将我的博客文章中的方法调整到您的回购:
$ git filter-branch -d /dev/shm/git --index-filter \ "git rm --cached -f --ignore-unmatch media/Optika.1.3.?.*; \ git rm --cached -f --ignore-unmatch media/lens.svg; \ git rm --cached -f --ignore-unmatch media/lens_simulation.swf; \ git rm --cached -f --ignore-unmatch media/v.html" \ --tag-name-filter cat --prune-empty -- --all
你的github repo没有任何标签,但我包含一个标签名称过滤器,以防你有私人标签.
该git filter-branch文档涵盖了该--prune-empty选项.
--prune-empty
某些类型的过滤器将生成空提交,使树保持不变.此开关允许git-filter-branch忽略此类提交...
使用此选项意味着您的重写历史记录将不包含"删除媒体文件"提交,因为它不再影响树.永远不会在新历史记录中创建媒体文件.
此时,由于另一个记录的行为,您将在存储库中看到重复.
原始引用(如果与重写的引用不同)将存储在命名空间中
refs/original/.
如果您对新重写的历史记录感到满意,请删除备份副本.
$ git for-each-ref --format="%(refname)" refs/original/ | \ xargs -n 1 git update-ref -d
Git对保护你的工作保持警惕,所以即使所有这些故意重写和删除reflog都会使旧的提交保持活力.用一系列两个命令清除它们:
$ git reflog expire --verbose --expire=0 --all $ git gc --prune=0
现在您的本地存储库已准备就绪,但您需要将更新推送到GitHub.你可以一次做一个.对于一个本地分公司,比如大师,你就跑了
$ git push -f origin master
假设您没有本地issue5分支.您的克隆仍然有一个名为origin/issue5的引用,它跟踪它在GitHub存储库中的位置.运行git filter-branch也会修改所有原点引用,因此您可以在没有分支的情况下更新GitHub.
$ git push -f origin origin/issue5:issue5
如果所有本地分支都与GitHub上的各自提交匹配(即,没有未提交的提交),则可以执行批量更新.
$ git for-each-ref --format="%(refname)" refs/remotes/origin/ | \
grep -v 'HEAD$' | perl -pe 's,^refs/remotes/origin/,,' | \
xargs -n 1 -I '{}' git push -f origin 'refs/remotes/origin/{}:{}'
第一阶段的输出是一个重新命名列表:
$ git for-each-ref --format="%(refname)" refs/remotes/origin/ refs/remotes/origin/HEAD refs/remotes/origin/issue2 refs/remotes/origin/issue3 refs/remotes/origin/issue5 refs/remotes/origin/master refs/remotes/origin/section_merge refs/remotes/origin/side-media-icons refs/remotes/origin/side-pane-splitter refs/remotes/origin/side-popup refs/remotes/origin/v2
我们不希望HEAD伪ref并将其删除grep -v.对于其余部分,我们使用Perl去除refs/remotes/origin/前缀,并为每个运行表单的命令
$ git push -f origin refs/remotes/origin/BRANCH:BRANCH