238

我对 git 中的整个变基功能有点陌生。假设我做了以下提交:

A -> B -> C -> D

之后,我意识到它D包含一个依赖于添加的一些新代码的修复A,并且这些提交属于一起。我如何将A&D挤在一起,然后B独自C离开?

4

5 回答 5

344

您可以git rebase --interactive在 B 之前运行和重新排序 D 并将 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 的提交消息时squash,您将使用fixup关键字而不是 。有关更多信息fixup,您可以查阅git rebase文档,或查看这个问题,其中有一些很好的答案。

于 2010-10-13T07:55:49.283 回答
47

注意:除非您知道后果,否则不应以任何方式更改已推送到另一个 repo 的提交。

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

将文本更改为您希望新提交消息的外观。我建议这是对提交更改的描述,A并且D

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 Dgit rebase --hard将破坏任何本地更改!)恢复它们。

于 2013-06-21T15:43:15.957 回答
3

对于那些使用SourceTree的人:

确保您尚未推送提交。

  1. 存储库 > 交互式变基...
  2. 将 D(较新的提交)拖动到 A(较旧的提交)的正上方
  3. 确保突出显示提交 D
  4. 点击Squash with previous
于 2016-04-15T13:34:39.697 回答
1

交互式 rebase 可以很好地工作,直到您拥有具有 20-30 次提交和/或来自 master 的几次合并的大特性分支或/并在您在分支中提交时修复冲突。即使通过历史找到我的提交并替换picksquash在这里也不起作用。所以我在寻找另一种方式并找到了这篇文章。我进行了更改以在单独的分支上进行此操作:

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 次合并来自 master + 修复冲突。在此之后,我通过一次提交获得了明确的 PR。

PS 这里是在自动模式下执行此步骤的bash脚本。

于 2018-10-10T06:47:33.213 回答
-1

$ git结账大师

$ git log --oneline

D
C
B
A

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

$ git log --oneline

D
A
于 2010-10-13T11:17:57.657 回答