如何在过去的两个任意提交之间注入一个提交?
How to inject a commit between some two arbitrary commits in the past?
假设我的本地分支有以下提交历史:
A -- B -- C
如何在 A
和 B
之间插入新提交?
原来很简单,答案找到了here。假设您在分支 branch
上。执行这些步骤:
在要插入新提交后从提交创建一个临时分支(在本例中为提交 A
):
git checkout -b temp A
执行更改并提交它们,创建一个提交,我们称之为 N
:
git commit -a -m "Message"
(或 git add
后接 git commit
)
将新提交(在本例中为提交 B
和 C
)之后的提交重新设置为新提交的基础:
git rebase temp branch
(可能您需要使用 -p
来保留合并,如果有的话 - 感谢 by ciekawy)
删除临时分支:
git branch -d temp
在此之后,历史如下所示:
A -- N -- B -- C
当然有可能rebase的时候会出现一些冲突
如果您的分支不是本地的,这将引入重写历史,因此可能会导致严重的问题。
它比 OP 的答案更容易。
git rebase -i <any earlier commit>
。这会在您配置的文本编辑器中显示提交列表。
- 找到您要在其后插入的提交(假设它是
a1b2c3d
)。在您的编辑器中,对于该行,将 pick
更改为 edit
.
- 关闭文本编辑器开始变基(保存更改)。这会让您在命令提示符下看到您之前选择的提交 (
a1b2c3d
) 就好像它刚刚被提交一样.
- 进行更改并
git commit
(不修改,不像大多数edit
s)。这会在您选择的 之后创建一个新的提交。
git rebase --continue
。这会重播连续的提交,将您的新提交插入正确的位置。
请注意,这将改写历史,并破坏任何试图拉动的人。
假设提交历史为preA -- A -- B -- C
,如果要在A
和B
之间插入一个提交,步骤如下:
git rebase -i hash-of-preA
Git 将打开您的编辑器。内容可能是这样的:
pick 8668d21 A
pick 650f1fc B
pick 74096b9 C
将第一个pick
改为edit
:
edit 8668d21 A
pick 650f1fc B
pick 74096b9 C
保存并退出。
修改你的代码然后git add . && git commit -m "I"
git rebase --continue
现在你的 Git 提交历史是 preA -- A -- I -- B -- C
如果遇到冲突,Git 将在此提交处停止。您可以使用 git diff
来定位冲突标记并解决它们。解决所有冲突后,需要用git add <filename>
告诉Git冲突已经解决,然后重新运行git rebase --continue
.
如果要撤消变基,请使用git rebase --abort
。
更简单的解决方案:
在最后创建你的新提交,D。现在你有:
A -- B -- C -- D
然后运行:
$ git rebase -i hash-of-A
Git 将打开您的编辑器,它看起来像这样:
pick 8668d21 B
pick 650f1fc C
pick 74096b9 D
就这样把D移到最上面,然后保存退出
pick 74096b9 D
pick 8668d21 B
pick 650f1fc C
现在您将拥有:
A -- D -- B -- C
这是一种避免在我读过的其他答案中看到的变基期间执行 "edit hack" 的策略。
通过使用 git rebase -i
,您可以获得自该提交以来的提交列表。
只需在文件顶部添加一个 "break",这将导致 rebase 在该点中断。
break
pick <B's hash> <B's commit message>
pick <C's hash> <C's commit message>
启动后,git rebase
现在将停在 "break" 点。
您现在可以编辑您的文件并正常创建您的提交。
然后您可以使用 git rebase --continue
继续变基。这可能会导致您必须解决的冲突。如果您迷路了,请不要忘记您可以随时使用 git rebase --abort
.
中止
这个策略可以概括为在任何地方插入提交,只需将 "break" 放在要插入提交的位置。
改写历史后,别忘了git push -f
。有关其他人获取您的分支的常见警告适用。
这里已经有很多好的答案了。我只是想通过 4 个简单的步骤添加一个“无变基”解决方案。
总结
git checkout A
# <<< modify your files at this point
git commit -am "Message for commit D"
git cherry-pick A..C
git branch -f master HEAD
说明
(注意:此解决方案的一个优点是,直到最后一步,当您 100% 确定您对最终结果没问题时,您才接触您的分支,因此您有一个非常方便的 允许AB测试的“预确认”步骤。)
初始状态(我假设 master
为您的分支名称)
A -- B -- C <<< master <<< HEAD
1) 首先将 HEAD 指向正确的位置
git checkout A
B -- C <<< master
/
A <<< detached HEAD
(可选地,我们可以用 git checkout -b temp A
创建一个临时分支,而不是分离 HEAD,我们需要在过程结束时删除它。两种变体都可以,按你喜欢的方式做,因为其他一切都保持不变)
2) 创建要插入的新提交D
# at this point, make the changes you wanted to insert between A and B, then
git commit -am "Message for commit D"
B -- C <<< master
/
A -- D <<< detached HEAD (or <<< temp <<< HEAD)
3) 然后带上最后丢失的提交 B 和 C 的副本(即使中间有更多提交,命令也是相同的,因为这是选择一个范围提交)
git cherry-pick A..C
# (if any, resolve potential conflicts between D and these last commits)
B -- C <<< master
/
A -- D -- B' -- C' <<< detached HEAD (or <<< temp <<< HEAD)
(如果需要,可以在这里进行舒适的 AB 测试)
现在是检查您的代码、测试任何需要测试的东西的时候了,您还可以比较/比较/检查您拥有的和操作后你会得到什么,只需通过交替检查 C
或 C'
.
4) 根据你在C
和C'
之间的测试,要么OK,要么KO。
(EITHER) 4-OK) 最后,移动 master
的 ref
git branch -f master HEAD
B -- C <<< (B and C are candidates for garbage collection)
/
A -- D -- B' -- C' <<< master
(OR) 4-KO) 保持master
不变
如果您创建了一个临时分支,只需使用 git branch -d <name>
将其删除,但如果您使用分离的 HEAD 路由,此时根本不需要任何操作,新提交将有资格进行垃圾收集在你用 git checkout master
重新连接 HEAD
之后
在这两种情况下(OK 或 KO),此时只需再次检查 master
以重新附加 HEAD
。
鉴于您要插入的提交由 D
标识:
# Temporarily append the commit you want to insert to the end
git cherry-pick D
# Results in D -- A -- B -- C
# Start interactive rebase
git rebase -i B^
# Let's imagine that this is what the rebase prompt looks like:
# pick B Third commit
# pick A Second commit
# pick D First commit
# Then reorder the commits:
# pick B Third commit
# pick D First commit
# pick A Second commit
# Save and exit
# After completing the rebase you will find
# A -- D -- B -- C
假设我的本地分支有以下提交历史:
A -- B -- C
如何在 A
和 B
之间插入新提交?
原来很简单,答案找到了here。假设您在分支 branch
上。执行这些步骤:
在要插入新提交后从提交创建一个临时分支(在本例中为提交
A
):git checkout -b temp A
执行更改并提交它们,创建一个提交,我们称之为
N
:git commit -a -m "Message"
(或
git add
后接git commit
)将新提交(在本例中为提交
B
和C
)之后的提交重新设置为新提交的基础:git rebase temp branch
(可能您需要使用 -p
来保留合并,如果有的话 - 感谢
删除临时分支:
git branch -d temp
在此之后,历史如下所示:
A -- N -- B -- C
当然有可能rebase的时候会出现一些冲突
如果您的分支不是本地的,这将引入重写历史,因此可能会导致严重的问题。
它比 OP 的答案更容易。
git rebase -i <any earlier commit>
。这会在您配置的文本编辑器中显示提交列表。- 找到您要在其后插入的提交(假设它是
a1b2c3d
)。在您的编辑器中,对于该行,将pick
更改为edit
. - 关闭文本编辑器开始变基(保存更改)。这会让您在命令提示符下看到您之前选择的提交 (
a1b2c3d
) 就好像它刚刚被提交一样. - 进行更改并
git commit
(不修改,不像大多数edit
s)。这会在您选择的 之后创建一个新的提交。 git rebase --continue
。这会重播连续的提交,将您的新提交插入正确的位置。
请注意,这将改写历史,并破坏任何试图拉动的人。
假设提交历史为preA -- A -- B -- C
,如果要在A
和B
之间插入一个提交,步骤如下:
git rebase -i hash-of-preA
Git 将打开您的编辑器。内容可能是这样的:
pick 8668d21 A pick 650f1fc B pick 74096b9 C
将第一个
pick
改为edit
:edit 8668d21 A pick 650f1fc B pick 74096b9 C
保存并退出。
修改你的代码然后
git add . && git commit -m "I"
git rebase --continue
现在你的 Git 提交历史是 preA -- A -- I -- B -- C
如果遇到冲突,Git 将在此提交处停止。您可以使用 git diff
来定位冲突标记并解决它们。解决所有冲突后,需要用git add <filename>
告诉Git冲突已经解决,然后重新运行git rebase --continue
.
如果要撤消变基,请使用git rebase --abort
。
更简单的解决方案:
在最后创建你的新提交,D。现在你有:
A -- B -- C -- D
然后运行:
$ git rebase -i hash-of-A
Git 将打开您的编辑器,它看起来像这样:
pick 8668d21 B pick 650f1fc C pick 74096b9 D
就这样把D移到最上面,然后保存退出
pick 74096b9 D pick 8668d21 B pick 650f1fc C
现在您将拥有:
A -- D -- B -- C
这是一种避免在我读过的其他答案中看到的变基期间执行 "edit hack" 的策略。
通过使用 git rebase -i
,您可以获得自该提交以来的提交列表。
只需在文件顶部添加一个 "break",这将导致 rebase 在该点中断。
break
pick <B's hash> <B's commit message>
pick <C's hash> <C's commit message>
启动后,git rebase
现在将停在 "break" 点。
您现在可以编辑您的文件并正常创建您的提交。
然后您可以使用 git rebase --continue
继续变基。这可能会导致您必须解决的冲突。如果您迷路了,请不要忘记您可以随时使用 git rebase --abort
.
这个策略可以概括为在任何地方插入提交,只需将 "break" 放在要插入提交的位置。
改写历史后,别忘了git push -f
。有关其他人获取您的分支的常见警告适用。
这里已经有很多好的答案了。我只是想通过 4 个简单的步骤添加一个“无变基”解决方案。
总结
git checkout A
# <<< modify your files at this point
git commit -am "Message for commit D"
git cherry-pick A..C
git branch -f master HEAD
说明
(注意:此解决方案的一个优点是,直到最后一步,当您 100% 确定您对最终结果没问题时,您才接触您的分支,因此您有一个非常方便的 允许AB测试的“预确认”步骤。)
初始状态(我假设 master
为您的分支名称)
A -- B -- C <<< master <<< HEAD
1) 首先将 HEAD 指向正确的位置
git checkout A
B -- C <<< master
/
A <<< detached HEAD
(可选地,我们可以用 git checkout -b temp A
创建一个临时分支,而不是分离 HEAD,我们需要在过程结束时删除它。两种变体都可以,按你喜欢的方式做,因为其他一切都保持不变)
2) 创建要插入的新提交D
# at this point, make the changes you wanted to insert between A and B, then
git commit -am "Message for commit D"
B -- C <<< master
/
A -- D <<< detached HEAD (or <<< temp <<< HEAD)
3) 然后带上最后丢失的提交 B 和 C 的副本(即使中间有更多提交,命令也是相同的,因为这是选择一个范围提交)
git cherry-pick A..C
# (if any, resolve potential conflicts between D and these last commits)
B -- C <<< master
/
A -- D -- B' -- C' <<< detached HEAD (or <<< temp <<< HEAD)
(如果需要,可以在这里进行舒适的 AB 测试)
现在是检查您的代码、测试任何需要测试的东西的时候了,您还可以比较/比较/检查您拥有的和操作后你会得到什么,只需通过交替检查 C
或 C'
.
4) 根据你在C
和C'
之间的测试,要么OK,要么KO。
(EITHER) 4-OK) 最后,移动 master
git branch -f master HEAD
B -- C <<< (B and C are candidates for garbage collection)
/
A -- D -- B' -- C' <<< master
(OR) 4-KO) 保持master
不变
如果您创建了一个临时分支,只需使用 git branch -d <name>
将其删除,但如果您使用分离的 HEAD 路由,此时根本不需要任何操作,新提交将有资格进行垃圾收集在你用 git checkout master
HEAD
之后
在这两种情况下(OK 或 KO),此时只需再次检查 master
以重新附加 HEAD
。
鉴于您要插入的提交由 D
标识:
# Temporarily append the commit you want to insert to the end
git cherry-pick D
# Results in D -- A -- B -- C
# Start interactive rebase
git rebase -i B^
# Let's imagine that this is what the rebase prompt looks like:
# pick B Third commit
# pick A Second commit
# pick D First commit
# Then reorder the commits:
# pick B Third commit
# pick D First commit
# pick A Second commit
# Save and exit
# After completing the rebase you will find
# A -- D -- B -- C