如何压缩两个非连续的提交?

我对git中的整个重基特性有点陌生。假设我做了以下提交:

A -> B -> C -> D

之后,我意识到D包含一个依赖于在A中添加的一些新代码的修复,并且这些提交属于一起。我如何挤压A &D放在一起,留下B &一个人C吗?

48065 次浏览

你可以运行git rebase --interactive并将D重新排列在B之前,然后将D压缩到A中。

Git会打开一个编辑器,你会看到这样一个文件,例如:git rebase --interactive HEAD~4

pick aaaaaaa Commit A
pick bbbbbbb Commit B
pick ccccccc Commit C
pick ddddddd Commit D


# Rebase aaaaaaa..ddddddd onto 1234567 (4 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

现在你修改文件,它看起来像这样:

pick aaaaaaa Commit A
squash ddddddd Commit D
pick bbbbbbb Commit B
pick ccccccc Commit C

git现在会将A和D的更改合并到一个提交中,然后再提交B和C。当你不想保留D的提交消息时,你可以使用fixup关键字而不是squash。有关fixup的更多信息,您可以咨询git rebase文档,或查看这个问题,其中有一些很好的答案。

$ git checkout master

$ git日志—一行

D
C
B
A

$ git rebase - to HEAD^^^ HEAD^

$ git日志—一行

D
A

注意:你应该以任何方式除非你知道后果 而不是已推送的更改提交到另一个回购。

git log --oneline -4

D commit_message_for_D
C commit_message_for_C
B commit_message_for_B
A commit_message_for_A

git rebase --interactive

pick D commit_message_for_D
pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A

类型i(将VIM置于插入模式)

将列表更改为如下所示(您不必删除或包括提交消息)。不要拼错squash!:

pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A
squash D

输入Esc然后ZZ(保存并退出VIM)

# This is a combination of 2 commits.
# The first commit's message is:


commit_message_for_D


# This is the 2nd commit message:


commit_message_for_A

类型i

将文本更改为您想要的新提交消息的样子。我建议这是对commit AD中的变化的描述:

new_commit_message_for_A_and_D

输入Esc,然后输入ZZ

git log --oneline -4

E new_commit_message_for_A_and_D
C commit_message_for_C
B commit_message_for_B

git show E

(You should see a diff showing a combination of changes from A and D)

现在你已经创建了一个新的提交E。提交AD不再在你的历史记录中,但并没有消失。此时,您仍然可以通过git rebase --hard D (git rebase --hard将破坏任何局部更改!)暂时恢复它们。

对于那些使用SourceTree的人:

确保您还没有推送提交。

  1. 知识库>交互Rebase…
  2. 将D(较新的提交)拖到A(较旧的提交)的正上方
  3. 确保提交D突出显示
  4. 单击Squash with previous
交互式rebase工作得很好,直到你有一个大的特性分支,有20-30次提交和/或从master或/和修复冲突,而你在你的分支中提交。即使通过历史记录查找我的提交并将pick替换为squash在这里也不起作用。所以我正在寻找另一种方式,发现这个文章。 我做了我的改变,工作在单独的分支:

git checkout master
git fetch
git pull
git merge branch-name
git reset origin/master
git branch -D branch-name
git checkout -b branch-name
git add --all
#Do some commit
git push -f --set-upstream origin branch-name

在此之前,我得到了大约30个提交的pull请求,其中2-3个合并来自master +修复冲突。在这之后,我一次就搞定了公关。

附注:这里是bash 脚本来在automode中执行此步骤。