【发布时间】:2015-08-31 15:48:46
【问题描述】:
假设我的本地分支上有以下提交历史记录:
A -- B -- C
如何在A 和B 之间插入新的提交?
【问题讨论】:
-
我对@987654321@ 有一个非常相似的问题,而不是提交。
标签: git git-rebase
假设我的本地分支上有以下提交历史记录:
A -- B -- C
如何在A 和B 之间插入新的提交?
【问题讨论】:
标签: git git-rebase
这比 OP 的答案更容易。
git rebase -i <any earlier commit>。这会在您配置的文本编辑器中显示提交列表。a1b2c3d)。在您的编辑器中,针对该行,将 pick 更改为 edit。a1b2c3d)就像刚刚提交一样。git commit(不修改,不像大多数edits)。这会在您选择的提交之后创建一个新的提交。git rebase --continue。这会重放连续的提交,将您的新提交插入正确的位置。请注意,这将改写历史,并破坏任何试图拉动的人。
【讨论】:
A -- B -- C -- D,而不是想要的A -- D -- B -- C。
D,所以我们有A - B - C - D,目标是A - D - B - C。 git rebase -i HEAD~4,然后在编辑器中将提交重新排序为 ADBC 顺序,保存,退出。
D 可以在任何地方提交。假设我们有 A - B - C 并且我们有一些提交 D 甚至不在这个分支中。但是我们知道它的 SHA,我们可以做git rebase -i HEAD~3。现在,在 A 和 B pick 行之间,我们插入一个 new pick 行,上面写着 pick SHA,给出所需 D 的哈希值。它不必是完整的散列,只是缩短的散列。 git rebase -i 只是挑选缓冲区中pick 行列出的任何提交;它们不必是它为您列出的原始文件。
break 关键字(或在第一行,在指定的提交之前插入提交)。
原来很简单,找到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 来保留合并,如果有的话 - 感谢a no longer existing comment ciekawy)
删除临时分支:
git branch -d temp
在此之后,历史如下所示:
A -- N -- B -- C
变基时当然会出现一些冲突。
如果您的分支不是本地分支,这将引入重写历史记录,因此可能会导致严重问题。
【讨论】:
git push --force 更改远程仓库。
git rebase temp branch -Xtheirs。注入脚本的有用答案!
git rebase temp branch 之后,git branch -d temp 之前添加,您所要做的就是修复和暂存合并冲突并发出git rebase --continue,即不需要提交任何东西,等等。
更简单的解决方案:
最后创建你的新提交,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
【讨论】:
这是一种避免在我读过的其他答案中看到的变基期间进行“编辑黑客”的策略。
通过使用git rebase -i,您可以获得自该提交以来的提交列表。
只需在文件顶部添加一个“break”,这将导致 rebase 在该点中断。
break
pick <B's hash> <B's commit message>
pick <C's hash> <C's commit message>
一旦启动,git rebase 现在将停在“中断”点。
您现在可以编辑文件并正常创建提交。
然后,您可以使用git rebase --continue 继续变基。这可能会导致您必须解决的冲突。如果您迷路了,别忘了您可以随时使用git rebase --abort 中止。
这个策略可以概括为在任何地方插入一个提交,只需将“break”放在你要插入一个提交的位置。
改写历史后,别忘了git push -f。关于其他人获取您的分支的常见警告适用。
【讨论】:
rebase -i的使用。使许多采摘方式更容易跟踪。
假设commit history是preA -- A -- B -- C,如果要在A和B之间插入commit,步骤如下:
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。
【讨论】:
这里已经有很多很好的答案了。我只是想通过 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 的副本(即使中间有更多提交,命令也是一样的,因为这是选择一系列提交) p>
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 路线,此时根本不需要任何操作,新提交将在您重新附加后符合垃圾回收条件HEAD 和 git checkout master
在这两种情况下(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
【讨论】: