修复git双重提交历史记录问题

21

前几天我不得不运行git filter-branch。我按照github上的指示去做,但是出了些问题。我认为团队中的某个人没有在本地分支上运行rebase,而是合并了更改。自那时以来,提交日志中充满了重复提交,例如:

commit b0c03ec925c0b97150594a99861d8f21fd3ab22d
Author: XXX
Date:   Wed Mar 19 17:01:52 2014 -0400

    Removed most clearfixs in templates

commit f30c21d21b5ea715a99b0844793cb4b5f5df97a1
Author: XXX
Date:   Wed Mar 19 17:01:52 2014 -0400

    Removed most clearfixs in templates

commit 2346be43d0e02d3987331f0a9eeb2f12cd698ede
Author: XXX
Date:   Wed Mar 19 16:40:26 2014 -0400

    new redirect logic

commit 1383070b31bde1aaa9eda7c2a9bcb598dd72247b
Merge: d1e2eb6 94e07fe
Author: XXX
Date:   Wed Mar 19 16:28:41 2014 -0400

    Merge branch 'develop' of github.com:xxx/xxx into develop

commit 79ce7824688cf2a71efd9ff82e3c7a71d53af229
Merge: 6079061 1ed3967
Author: XXX
Date:   Wed Mar 19 16:28:41 2014 -0400

    Merge branch 'develop' of github.com:xxx/xxx into develop

commit d1e2eb645a4fe2a1b3986082d0409b4075a0dbc9
Author: XXX
Date:   Wed Mar 19 16:28:36 2014 -0400

    Fixed broken responsiveness for companies listing page and code refactoring.

commit 6079061f6ef1f856f94d92bc0fdacf18854b8a89
Author: XXX
Date:   Wed Mar 19 16:28:36 2014 -0400

    Fixed broken responsiveness for companies listing page and code refactoring.

奇怪的是,并非所有提交都是重复的,比如上面的"新重定向逻辑"。我能做些什么来解决这个问题吗?虽然相对温和,但现在我们的提交历史看起来很烂。这篇SO帖子建议保持原样,但为了后人着想,我宁愿有一个干净的提交历史。

2个回答

25
完成这个任务的命令是:
git rebase -i HEAD~7

这将打开您的编辑器,并显示类似下面的内容:

pick f392171 Removed most clearfixs in templates
pick ba9dd9a Removed most clearfixs in templates
pick df71a27 Unew redirect logic
pick 79ce782 Merge branch 'develop' of github.com:xxx/xxx into develop
pick 1383070 Merge branch 'develop' of github.com:xxx/xxx into develop
...

现在你可以告诉Git每次提交(commit)应该做什么。让我们保留提交(f392171),也就是我们添加功能的那个提交。我们将把后面两个提交合并到第一个提交中,这样就只剩下干净的一个提交了。

将你的文件更改为以下内容:

pick f392171 Removed most clearfixs in templates
squash ba9dd9a Removed most clearfixs in templates
pick df71a27 Unew redirect logic
pick 79ce782 Merge branch 'develop' of github.com:xxx/xxx into develop
squash 1383070 Merge branch 'develop' of github.com:xxx/xxx into develop

当您保存并退出编辑器时,Git将应用所有两个更改,然后将您放回编辑器以合并三个提交消息。
# This is a combination of  commits.
# The first commit's message is:
Removed most clearfixs in templates

# This is the 2nd commit message:

Removed most clearfixs in templates

编辑完成后,保存并退出。Git将把提交的内容压缩成一个。完成!

接着你需要进行:

git push origin your-branch -f

强制将本地提交的更改推送到远程分支。

注意:您必须对每个重复的提交进行压缩(squash)。


1
当我运行这个程序时,重复的提交不会相邻。例如对于“在模板中删除大多数clearfixs”,一个在第4512行,另一个在6683行。有没有办法解决这个问题?我还担心可能存在两个具有相同消息但内容不同的提交的情况,在这种情况下,我们不想压缩。有没有一种方法来检查这个问题? - ysimonson
我不明白你的第一个问题...你能更详细地解释一下吗?否则,要重命名提交,你必须使用'edit'而不是squash,保存文件,然后使用git commit --amend。这将打开一个编辑器,你需要用新的提交名称保存文件。 - VAIRIX
关于第一个问题,git log 显示的双重提交是相邻的,但是通过这个 rebase 命令生成的日志文件不会 - 它们在日志文件中的位置会非常不同。对于第二个问题,我们在历史过程中有一些具有相同消息但变更非常不同的提交 - 例如合并提交通常具有相同的消息。我不太关心将它们重命名,而是想检查哪些是冗余的。也许有一种方法可以显示日志文件中更改的摘要吗? - ysimonson
我想到的是,你可以先改变提交顺序,先聚集那些想要压缩的人。要改变顺序,只需在打开 git rebase -i 的文件中交换提交的行即可。另一方面,为了判断提交是否相等,我会使用 gitg 工具,检查具有相同名称的提交,并验证这些提交是否具有相同的更改。我不知道是否有任何自动比较工具。 - VAIRIX

5

@VAIRIX的答案非常好,但是在一些复杂情况下,重复提交并不会相邻出现,所以压缩不会有帮助。

因此,考虑以下历史记录(假设a~是a的副本):

 # h
 # g
 # f
 # c~
 # b~
 # a~
 # e
 # d
 # c
 # b
 # a

需要执行的命令:(根据 @VAIRIX 的回答或下面的内容进行rebase操作)

git rebase master -i (最好使用 git rebase -i HEAD~n 以避免重新设置基础引起的头痛)

现在! 1)将重复提交压缩为以下形式:

 pick h
 pick g
 pick f
 pick c~
 s b~
 s a~
 pick e
 pick d
 pick c
 pick b
 pick a

现在,这将压缩你在c中的提交。
 # h
 # g
 # f
 # c~ (having changes of a~ and b~)
 # e
 # d
 # c
 # b
 # a

在我的情况下,c~ 是 c 的反向提交,所以我只需要再次执行该过程,但现在不是使用 squash 和 s,而是使用删除提交和 d
 pick h
 pick g
 pick f
 d c~ (having changes of a~ and b~)
 pick e
 pick d
 pick c
 pick b
 pick a

现在,你的历史记录将删除所有重复的提交。现在,你可以使用git diff与之前存在重复提交的远程分支进行比较。如果你操作正确,就不应该出现任何差异。

这个过程可能会稍微有些冗长,但是你可以确信没有漏掉任何提交。


2
+1 给你的用户名 :D。是的,一个人应该非常小心地挑选和丢弃,还要使用提交数量来开始压缩。HEAD~10 或类似的东西。 - Tarandeep Singh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接