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

发布于 2024-09-27 05:38:34 字数 263 浏览 0 评论 0原文

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

A -> B -> C -> D

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

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

A -> B -> C -> D

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

罪歌 2024-10-04 05:38:34

您可以运行 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 文档,或查看

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

Git will open an editor, and you see a file like this, ex: 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 fixup keyword. For more on fixup, you can consult the git rebase docs, or check out this question which has some good answers.

森罗 2024-10-04 05:38:34

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

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< /code>

将文本更改为您希望新提交消息的样子。我建议这是提交 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 会破坏任何本地更改!) em>)。

Note: You should not change commits that have been pushed to another repo in any way unless you know the 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

Type i (Put VIM in insert mode)

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

pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A
squash D

Type Esc then ZZ (Save and exit 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

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 A and D:

new_commit_message_for_A_and_D

Type Esc then 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)

You have now created a new commit E. Commits A and D are 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 --hard will destroy any local changes!).

无需解释 2024-10-04 05:38:34

对于使用 SourceTree 的用户:

确保您尚未推送提交。

  1. 存储库>交互式 Rebase...
  2. 将 D(较新的提交)拖到 A(较旧的提交)的正上方
  3. 确保突出显示提交 D
  4. 单击与上一个提交压缩

For those using 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
凉城 2024-10-04 05:38:34

交互式变基工作得很好,直到您拥有具有 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 次提交的拉取请求,其中来自 master 的 2-3 次合并 + 修复冲突。在此之后,我通过一次提交就获得了明确的 PR。

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

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 pick with squash doesn't worked here. So i was looking for another way and found this article.
I did my changes to work this on separate branch:

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.

P.S. here is bash script to do this steps in automode.

冷夜 2024-10-04 05:38:34

$ git checkout master

$ git log --oneline

D
C
B
A

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

$ git log --oneline

D
A

$ git checkout master

$ git log --oneline

D
C
B
A

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

$ git log --oneline

D
A
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文