2016-09-16 116 views
3

我意外地推送了一些大文件的提交,然后将其恢复。但它会导致任何人拉这个分支来获取历史中的这些文件,所以我决定删除或挤压这两个提交。但是,有些分支已经被合并了。我不知道如何让“git rebase -i”保持分支结构。git - 从合并分支中移除提交

历史现在看起来像:

H - new commits 
| 
G - merge 
| \ 
| F - commits on another branch 
| | 
E | - some other commits 
| | 
D | - corrected B 
| | 
C | - revert B 
| | 
B | - huge files 
|/
A - early commit 

我可以将其更改为以下?

h - new commits 
| 
g - merge 
| \ 
| F - commits on another branch 
| | 
e | - some other commits 
| | 
d | - corrected B 
|/
A - early commit 
+0

有另一方重做合并的可能吗? –

+0

@TimBiegeleisen是的,但必须保持结构。 – Xiao

+0

交互式重新分配并移除“巨大文件”和“还原B”。然后重新合并。最后,挑选出新的承诺。 –

回答

2

是的你可以但你不应该

这将需要你重写历史记录,并替换服务器上的已推送历史记录(这需要强制推送,并且通常会导致所有人都对你大喊)

但是,如果你真的想然后git filter-branch是你想要使用,很像在this SO answer。所以你会这样做:

git filter-branch --commit-filter ' 
    if [ "$GIT_COMMIT" = "<your commit to remove here>" ] 
    then 
     skip_commit "[email protected]"; 
    else 
     git commit-tree "[email protected]"; 
    fi' HEAD 

还有几个例子here

+0

太棒了,这就是我要找的。这是一个内部回购,而不是让别人做强制拉回的问题。 – Xiao

0

不,你不能。

每个提交的散列不仅包括索引中所有文件的散列内容,还包括提交父项的散列。

“已更正的B”将具有与现在不同的父项。这将改变散列。

可以解决这个问题,但是不可能避免强制推送修复程序,并且一旦完成,每个人都会强制拉它。

唯一真正的方法来解决,这将是以下过程:

git checkout A 

退房父提交,支分叉之前。然后,创建两个工作分支:

git checkout -b corrected-mainline 
git checkout -b corrected-fork 

您现在处于纠正叉分支。现在,在这个分支上,你应该能够git cherry-pick所有提交到F提交,跳过提交巨大的文件,并恢复。如果这些提交中的任何一个是合并,则执行相同的合并。

现在,做了corrected-mainline分支

git checkout corrected-mainline 

同一现在,git cherry-pick所有的主线分支的提交,直到最后的G合并之前提交。然后,与corrected-fork分支合并。现在这是您更正的G合并提交。

完成樱桃采摘任何提交最初在您的图中的G之上,完成您最初的分支上的最后一个提交。

此时,您的工作分支的内容应与原始分支的内容相同。验证是否如此。

然后,删除您的原始分支,将您的工作分支重命名为其名称。或者,使用git reset --hard将原始分支重置为您更正的工作分支。

然后做一个git push --force,推动你纠正的分支。当然,任何拉动分支的人最终都会受到拉力。

+0

我正在使用'git filter-branch'。感谢您的回答。 – Xiao