假设我有这样的树:
... -- a -- b -- c -- d -- ...
\
e -- a -- k
我希望它变得只是
... -- a -- b -- c -- d -- ...
我知道如何将分支名称附加到“e”。我知道我要做的事情会改变历史,这很糟糕。另外我想我需要使用像rebase或filter-branch这样的东西。但究竟是什么 - 我迷路了。
确定。情况如下:我现在有一个相当大的树(像这样)
s -- p -- r
/
a -- b -- c -- d -- e --- g -- w
\ \
t -- p -- l y -- k
但是在我的第一次提交中(比如前面的“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'
其中b'在没有二进制文件的情况下提交。所以我不能合并。我不希望这整个树在历史上重复。
答案 0 :(得分:35)
导入具有多年历史记录的Subversion存储库后,我遇到了类似的问题,包括来自大量二进制资产的膨胀。在git: shrinking Subversion import中,我描述了将我的git repo从4.5 GiB修剪到大约100 MiB。
假设您要删除“Delete media files” (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
documentation涵盖了--prune-empty
选项。
<强>
--prune-empty
强>
某些类型的过滤器将生成空提交,使树保持不变。此开关允许git-filter-branch
忽略此类提交...
使用此选项意味着您的重写历史记录不会包含“删除媒体文件”提交,因为它不再影响树。媒体文件永远不会在新历史记录中创建。
此时,由于另一个documented behavior,您会在存储库中看到重复。
原始引用(如果与重写的引用不同)将存储在命名空间
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伪参考并使用grep -v
将其删除。对于其余部分,我们使用Perl去除refs/remotes/origin/
前缀,并为每个运行一个命令形式
$ git push -f origin refs/remotes/origin/BRANCH:BRANCH
答案 1 :(得分:1)
您可以再次使用git filter-branch ,但这次使用--parent-filter选项。有了这个,您可以通过将其父引用设置为空来取消链接提交。我认为你可以使用--commit-filter选项用于相同的目的。这会在你的仓库中留下很多不同的松散物体,所以你需要做git gc --prune = now。
以下是如何使用--parent-filter删除父项的示例 http://git.661346.n2.nabble.com/purging-unwanted-history-td1507638.html
答案 2 :(得分:0)
尝试:
git branch -d name
您可能需要使用此代码:
git branch -D name
答案 3 :(得分:0)
您可以使用git branch -D branch_name
删除分支,并使用git push remote_name :branch_name
删除远程分支。
提交将在您的存储库中保持未引用一段时间(请参阅git gc doc),但只会在您稍后意识到您犯了错误时使用磁盘空间。
由于您删除了远程分支,因此新git clone
不应检索未引用的提交。
答案 4 :(得分:-2)
从您的示例中,您可以尝试git rebase b b'
?