如何压缩中间有合并提交的提交?
How to squash commits which have merge-commit in between?
我正在开发一个功能分支。
- 进行了多次提交。压缩提交。
- 已将更改推送到远程分支。有冲突。
- 合并了来自 master 的更改,解决了功能分支上的冲突。
git fetch origin master
git merge FETCH_HEAD
- 已手动解决冲突。
git commit
git push
- 我又做了一个承诺。
所以,当前的提交历史看起来是这样的。
从当前到旧:
- 提交 3
- 提交 M yyy(已合并)
- 提交 2
在将我的功能分支合并到 master 之前,如何将 3 个以上的提交压缩为 1 个?
您可以 rebase -i
从 commit 2
的父级(即您分支的 master
上的提交开始。您可能需要重新解决冲突你进入合并提交。
所以如果你的历史看起来像
* D commit 3 (HEAD)
* M merge
/|
| * C commit 2
* | B commit on master
|/
* A (master)
从 git rebase -i A
开始。您将看到包括 master
和 your_branch
的提交列表,但不包括合并提交。 pick
第一个(B
或 C
,取决于时间)和 squash
其余的。
就我而言,我开始使用一个有多个提交的分支,然后与 main/source 分支合并,然后是更多提交,我想压缩所有提交,但保留了 运行由于合并提交而陷入错误:
错误:提交是合并,但没有给出 -m 选项。
->C1->C2->M(与源分支合并)->C3->C4
可能有更好的方法(我期待学习),但经过大量阅读和反复试验后我最终做的是创建一个复制分支以供参考,然后将当前分支恢复到 C1,
reset --hard (C1 hash)
然后挑选 C2、C3、C4,然后压扁,然后变基...导致:
M->C
(只有一个提交已经用源重新定位!)
我希望这对遇到同样问题的其他人有所帮助。
您可以使用我专门为此任务创建的工具:
https://github.com/sheerun/git-squash
只需合并master分支,然后运行压缩命令:
git merge master
git squash master
我发现不必重新解决冲突的唯一方法是:
给定分支主要和分支工作,执行以下步骤:
git checkout -b work-squashed `git merge-base main work`
这将从您合并到工作分支中的最后一个主要提交创建一个新分支。
git diff work-squashed...work | patch -p1
这会获取并应用到工作目录的所有更改,这些更改是在合并到工作中的 main 上的最后一次提交与工作分支的尖端之间的。 换句话说,所有工作,包括已解决的冲突。
此时您需要处理工作分支上的文件added/removed,因为补丁不是git。它不知道 git 正在跟踪哪些文件。因此,您需要 git add/git rm 直到所有文件都被占用。然后,您只需将更改作为单个提交提交即可。
我在使用 Github UI 提交代码更改时遇到了这个问题,然后在本地提交了更改(不更新本地克隆),然后尝试推送本地提交到产地。结果创建了合并提交。
master
\
remote-branch --- commit #1 ---------------MergeCommit
^
| |
local-branch -------------- commit #2 ---
从同源分支checkout一个新分支,cherry-pick all提交除了merge-commit,然后push分支
master
\
new-branch --------------------------------------- Squash-commits
^ ^
| | < Cherry-pick > |
previous-branch -----commit #1 --------- commit #2
请注意,我们从中分叉的原始分支是相同的,即 master
。
cherry-picking 的过程对于 IntelliJ 用户来说很简单。结果,新分支将不会有合并提交。
假设功能分支被称为 feature
并且主分支被称为 main
:
从 main
创建一个临时分支:
git checkout -b temp main
压缩 feature
中的分支:
git merge --squash feature
提交更改(提交消息包含所有压缩的提交消息):
git commit
回到feature
分支,指向temp
分支:
git checkout feature
git reset --hard temp
删除临时分支:
git branch -d temp
- 在本地获取 PR:
gh pr checkout 1938
- 添加
upstream
以告知您将从何处获取更改
git remote add upstream git@github.com:minio/console.git
fetch
从 upstream
获取所有新更改
git fetch upstream
rebase
特别的样子,看:
git rebase -i upstream/master
You will see
pick 18eea859 add csr under tenant details
# Rebase 3bfdbb5e..01964c30 onto 3bfdbb5e (1 command)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
# commit's log message, unless -C is used, in which case
# keep only this commit's message; -c is same as -C but
# opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified); use -c <commit> to reword the commit message
#
# 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.
#
- 只是不要更改
pick
就这样吧,如果您 select squash
或 reword
对于这种特殊情况,它将不起作用。您真正想要的只是重新调整您的更改并从您的 PR 中删除合并提交,所以只需按原样保存文件并获取以下内容:
$ git rebase -i upstream/master
Successfully rebased and updated refs/heads/add-csr-under-tenant-details.
- 现在可以推送了:
git push -f
- 被压扁,或者实际上是变基,中间没有更多的合并提交:
我正在开发一个功能分支。
- 进行了多次提交。压缩提交。
- 已将更改推送到远程分支。有冲突。
- 合并了来自 master 的更改,解决了功能分支上的冲突。
git fetch origin master
git merge FETCH_HEAD
- 已手动解决冲突。
git commit
git push
- 我又做了一个承诺。
所以,当前的提交历史看起来是这样的。 从当前到旧:
- 提交 3
- 提交 M yyy(已合并)
- 提交 2
在将我的功能分支合并到 master 之前,如何将 3 个以上的提交压缩为 1 个?
您可以 rebase -i
从 commit 2
的父级(即您分支的 master
上的提交开始。您可能需要重新解决冲突你进入合并提交。
所以如果你的历史看起来像
* D commit 3 (HEAD)
* M merge
/|
| * C commit 2
* | B commit on master
|/
* A (master)
从 git rebase -i A
开始。您将看到包括 master
和 your_branch
的提交列表,但不包括合并提交。 pick
第一个(B
或 C
,取决于时间)和 squash
其余的。
就我而言,我开始使用一个有多个提交的分支,然后与 main/source 分支合并,然后是更多提交,我想压缩所有提交,但保留了 运行由于合并提交而陷入错误:
错误:提交是合并,但没有给出 -m 选项。
->C1->C2->M(与源分支合并)->C3->C4
可能有更好的方法(我期待学习),但经过大量阅读和反复试验后我最终做的是创建一个复制分支以供参考,然后将当前分支恢复到 C1,
reset --hard (C1 hash)
然后挑选 C2、C3、C4,然后压扁,然后变基...导致:
M->C
(只有一个提交已经用源重新定位!)
我希望这对遇到同样问题的其他人有所帮助。
您可以使用我专门为此任务创建的工具:
https://github.com/sheerun/git-squash
只需合并master分支,然后运行压缩命令:
git merge master
git squash master
我发现不必重新解决冲突的唯一方法是:
给定分支主要和分支工作,执行以下步骤:
git checkout -b work-squashed `git merge-base main work`
这将从您合并到工作分支中的最后一个主要提交创建一个新分支。
git diff work-squashed...work | patch -p1
这会获取并应用到工作目录的所有更改,这些更改是在合并到工作中的 main 上的最后一次提交与工作分支的尖端之间的。 换句话说,所有工作,包括已解决的冲突。
此时您需要处理工作分支上的文件added/removed,因为补丁不是git。它不知道 git 正在跟踪哪些文件。因此,您需要 git add/git rm 直到所有文件都被占用。然后,您只需将更改作为单个提交提交即可。
我在使用 Github UI 提交代码更改时遇到了这个问题,然后在本地提交了更改(不更新本地克隆),然后尝试推送本地提交到产地。结果创建了合并提交。
master
\
remote-branch --- commit #1 ---------------MergeCommit
^
| |
local-branch -------------- commit #2 ---
从同源分支checkout一个新分支,cherry-pick all提交除了merge-commit,然后push分支
master
\
new-branch --------------------------------------- Squash-commits
^ ^
| | < Cherry-pick > |
previous-branch -----commit #1 --------- commit #2
请注意,我们从中分叉的原始分支是相同的,即 master
。
cherry-picking 的过程对于 IntelliJ 用户来说很简单。结果,新分支将不会有合并提交。
假设功能分支被称为 feature
并且主分支被称为 main
:
从 main
创建一个临时分支:
git checkout -b temp main
压缩 feature
中的分支:
git merge --squash feature
提交更改(提交消息包含所有压缩的提交消息):
git commit
回到feature
分支,指向temp
分支:
git checkout feature
git reset --hard temp
删除临时分支:
git branch -d temp
- 在本地获取 PR:
gh pr checkout 1938
- 添加
upstream
以告知您将从何处获取更改
git remote add upstream git@github.com:minio/console.git
fetch
从upstream
获取所有新更改
git fetch upstream
rebase
特别的样子,看:
git rebase -i upstream/master
You will see
pick 18eea859 add csr under tenant details
# Rebase 3bfdbb5e..01964c30 onto 3bfdbb5e (1 command)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
# commit's log message, unless -C is used, in which case
# keep only this commit's message; -c is same as -C but
# opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified); use -c <commit> to reword the commit message
#
# 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.
#
- 只是不要更改
pick
就这样吧,如果您 selectsquash
或reword
对于这种特殊情况,它将不起作用。您真正想要的只是重新调整您的更改并从您的 PR 中删除合并提交,所以只需按原样保存文件并获取以下内容:
$ git rebase -i upstream/master
Successfully rebased and updated refs/heads/add-csr-under-tenant-details.
- 现在可以推送了:
git push -f
- 被压扁,或者实际上是变基,中间没有更多的合并提交: