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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3921708/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 09:16:50  来源:igfitidea点击:

How do I squash two non-consecutive commits?

gitgit-rebase

提问by Nik Reiman

I'm a bit new to the whole rebasing feature within git. Let's say that I made the following commits:

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

A -> B -> C -> D

Afterwards, I realize that Dcontains a fix which depends on some new code added in A, and that these commits belong together. How do I squash A& Dtogether and leave B& Calone?

之后,我意识到D包含一个依赖于在 中添加的一些新代码的修复程序A,并且这些提交属于一起。如何壁球AD一起休假BC孤独?

回答by Rudi

You can run git rebase --interactiveand reorder D before B and squash D into A.

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

Git will open an editor, and you see a file like this, ex: git rebase --interactive HEAD~4

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

Now you change the file that it looks like this:

现在您将文件更改为如下所示:

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

And git will now meld the changes of A and D together into one commit, and put B and C afterwards. When you don't want to keep the commit message of D, instead of squash, you would use the fixupkeyword. For more on fixup, you can consult the git rebasedocs, or check out this questionwhich has some good answers.

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

回答by Nate

Note: You should not change commits that have been pushedto another repo in any way unless you know the consequences.

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

git log --oneline -4

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

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

Type i(Put VIM in insert mode)

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

Change the list to look like this (You don't have to remove or include the commit message). Do not misspell squash!:

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

pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A
squash D

Type Escthen ZZ(Save and exit VIM)

键入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

Type i

类型 i

Change the text to what you want the new commit message to look like. I recommend this be a description of the changes in commit Aand D:

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

new_commit_message_for_A_and_D

Type Escthen ZZ

键入Esc然后ZZ

git log --oneline -4

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

git show E

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

You have now created a new commit E. Commits Aand Dare no longer in your history but are not gone. You can still recover them at this point and for a while by git rebase --hard D(git rebase --hardwill destroy any local changes!).

您现在已经创建了一个新的提交E。提交A并且D不再在您的历史记录中,但并没有消失。此时您仍然可以恢复它们,一段时间后git rebase --hard Dgit rebase --hard将破坏任何本地更改!)。

回答by Adam Johns

For those using SourceTree:

对于那些使用SourceTree 的人

Make sure you haven't already pushed the commits.

确保您尚未推送提交。

  1. Repository > Interactive Rebase...
  2. Drag D (the newer commit) to be directly above A (the older commit)
  3. Make sure commit D is highlighted
  4. Click Squash with previous
  1. 存储库 > 交互式变基...
  2. 将 D(较新的提交)拖到 A(较旧的提交)正上方
  3. 确保提交 D 突出显示
  4. 点击 Squash with previous

回答by Oleksiy Guzenko

Interactive rebase works well until you have big feature branch with 20-30 commits and/or couple of merges from master or/and fixing conflicts while you was commiting in your branch. Even with finding my commits through history and replacing pickwith squashdoesn't worked here. So i was looking for another way and found this article. I did my changes to work this on separate branch:

交互式 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

Before this I got my pull request with about ~30 commits with 2-3 merges from master + fixing conflicts. And after this I got clear PR with one commit.

在此之前,我收到了大约 30 次提交的拉取请求,其中包含 2-3 次来自 master + 修复冲突的合并。在此之后,我通过一次提交获得了明确的 PR。

P.S. here is bash scriptto do this steps in automode.

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

回答by Cotton

$ git checkout master

$ git checkout master

$ git log --oneline

$ git log --oneline

D
C
B
A

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

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

$ git log --oneline

$ git log --oneline

D
A