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

时间:2010-10-13 07:52:55

标签: git git-rebase

我对git中的整个rebasing功能有点新意。假设我做了以下提交:

A -> B -> C -> D

之后,我意识到D包含一个修复程序,它取决于A中添加的一些新代码,并且这些提交属于一起。我该如何压制A& D B并离开C&仅{{1}}?

5 个答案:

答案 0 :(得分:186)

您可以运行git rebase --interactive并在B之前重新排序D并将D压缩为A。

Git会打开一个编辑器,你会看到一个这样的文件:

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的提交消息,也可以使用“fix”关键字。

答案 1 :(得分:41)

注意:除非您知道consequences ,否则不应以任何方式将已推送的提交更改为其他回购。

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

将文本更改为您希望新提交消息的样子。我建议这是对提交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会消除所有本地更改!)。

答案 2 :(得分:3)

对于使用SourceTree的人:

确保您尚未推送提交。

  1. 存储库>互动重建......
  2. 将D(较新的提交)拖到A(较旧的提交)
  3. 的正上方
  4. 确保提交D突出显示
  5. 点击Squash with previous

答案 3 :(得分:1)

交互式重载可以很好地工作,直到您拥有具有20-30次提交和/或来自主服务器的几次合并和/或在分支中提交时解决冲突的大型功能分支。即使通过历史查找我的提交并用pick替换squash也不起作用。因此,我正在寻找另一种方法,并找到了此article。 我进行了更改,以在单独的分支上进行此操作:

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次提交的请求请求,其中有2-3次来自主服务器+修复冲突。在此之后,我一次提交就获得了明确的PR。

P.S。这是bash script,可在自动模式下执行此步骤。

答案 4 :(得分:-1)

$ git checkout master

$ git log --oneline

D
C
B
A

$ git rebase --onto HEAD ^^^ HEAD ^

$ git log --oneline

D
A