git - 从合并分支中删除提交

git - remove commits from merged branch

我不小心推送了一些大文件的提交,然后将其还原。但这会导致任何拉动此分支的人都在历史记录中获取这些文件,因此我决定删除或压缩这两个提交。但是,合并了一些分支。我不知道如何"git rebase -i"保持分支结构。

历史现在看起来像:

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

不,你不能。

每个提交的哈希值不仅包括索引中所有文件的哈希值,还包括提交的 parents.

的哈希值

"Corrected B" 将会有一个与现在不同的 parent。那会改变散列。

可以修复此问题,但无法避免 force-pushing 修复,并在完成后让每个人 force-pull 它。

解决此问题的唯一真正方法是以下过程:

 git checkout A

在分支分支之前检查 parent 提交。然后,创建两个工作分支:

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

您现在位于 corrected-fork 分支。现在,在这个分支上,您应该能够 git cherry-pick 直到 F 提交的所有提交,跳过带有大文件的提交及其还原。如果这些提交中的任何一个是合并,则执行相同的合并。

现在,在 corrected-mainline 分支上做同样的事情

 git checkout corrected-mainline

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

完成 cherry-picking 图表中最初位于 G 之上的所有提交,以原始分支上的最后一次提交结束。

此时,你的工作分支的内容应该和你原来的分支的内容是一样的。验证是这样。

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

然后执行 git push --force,将您更正的分支向上推。当然,任何拉动分支的人最终都会得到 force-pull.

是的你可以但你不应该

会要求你重写历史,替换掉服务器上已经推送的历史(需要强行推送,经常会被大家骂).

但如果您真的想要,那么 git filter-branch 就是您想要使用的,就像 this SO answer 中一样。所以你会做这样的事情:

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

还有几个例子here