过去如何在两个任意提交之间注入一个提交?


126

假设我在仅限本地的分支上具有以下提交历史记录:

A -- B -- C

如何在A和之间插入新提交B


3
提交称为一个?:)
Antek

关于如何在过去插入新版本而不是提交,我有一个非常相似的问题。
Pavel P

Answers:


177

比在OP的答案中更容易。

  1. git rebase -i <any earlier commit>。这将在您配置的文本编辑器中显示提交列表。
  2. 找到您要插入的提交(假设是a1b2c3d)。在您的编辑器中,将该行更改pickedit
  3. 通过关闭文本编辑器(保存更改)来开始重新设置基准。这样,您会在命令提示符下看到您先前选择的提交(a1b2c3d,就好像刚提交一样
  4. 进行更改和git commit修改,与大多数edits 不同)。这将您选择的提交之后创建一个新的提交。
  5. git rebase --continue。这将重放连续的提交,将新的提交插入正确的位置。

请注意,这将重写历史记录,并破坏尝试拉的其他任何人。


1
这将在提交之后添加新的提交,该提交是在我进行基础修改的提交之后(也是最后一次提交),而不是在我进行基础修改的提交之后。结果就像是我只是想在最后插入一个要提交的更改的新提交一样。我的历史变得A -- B -- C -- D不那么理想了A -- D -- B -- C
XedinUnknown

2
@XedinUnknown:那时您没有正确使用Rebase。
SLaks's

3
现在D可以在任何地方提交。假设我们有A - B - C并且有一些提交D,即使在这个分支中也没有。我们知道它的SHA,但是我们可以做到git rebase -i HEAD~3。现在,在AB pick线之间插入 pick行,表示pick SHA所需的哈希值D。它不必是完整的哈希,而只需是缩短的哈希。 git rebase -i只是樱桃选择pick缓冲区中各行列出的所有提交;他们不必是它为您列出的原始内容。
卡兹(Kaz)

1
@Kaz这看起来是一个不同的有效答案。
BartoszKP

3
甚至更容易,您可以break在编辑器中的两次提交之间使用其自己的行中的关键字(或在第一行中,在指定的提交之前插入一个提交)。
SimonT

30

原来很简单,答案在这里找到。假设你在树枝上branch。执行以下步骤:

  • 要插入新提交(在本例中为commit A)之后,从提交创建一个临时分支:

    git checkout -b temp A
    
  • 执行更改并将其提交,创建一个提交,我们称之为N

    git commit -a -m "Message"
    

    (或git add后跟git commit

  • 在新的提交(在本例中为commit BC)之后,将所需的提交重新部署到新的提交上:

    git rebase temp branch
    

(可能你需要使用-p保存合并,如果有任何-感谢一个不再存在的意见通过ciekawy

  • 删除临时分支:

    git branch -d temp
    

此后,历史记录如下:

A -- N -- B -- C

当然,重新定基时可能会出现一些冲突。

如果您的分支不是仅本地分支,这将引入重写历史记录,因此可能会导致严重的问题。


2
我无法遵循SLaks接受的答案,但这对我有用。在获得所需的提交历史记录之后,我不得不git push --force更改远程仓库。
escapecharacter17年

1
在使用-Xtheirs选项使用rebase时,可以自动正确解决冲突,因此git rebase temp branch -Xtheirs。注入脚本的有用答案!
David C

对于像我这样的菜鸟,我想补充一点后git rebase temp branch,但在此之前git branch -d temp,所有你需要做的是修复和舞台融合的矛盾和问题git rebase --continue,即无需提交任何东西,等等
Pugsley

19

更简单的解决方案:

  1. 在末尾创建新的提交D。现在,您具有:

    A -- B -- C -- D
    
  2. 然后运行:

    $ git rebase -i hash-of-A
    
  3. Git将打开您的编辑器,它将如下所示:

    pick 8668d21 B
    pick 650f1fc C
    pick 74096b9 D
    
  4. 像这样将D移到顶部,然后保存并退出

    pick 74096b9 D
    pick 8668d21 B
    pick 650f1fc C
    
  5. 现在您将拥有:

    A -- D -- B -- C
    

6
不错的主意,但是,当您打算将这些更改添加到C中时,可能很难在C上引入D。到
A。– BartoszKP

我遇到这样的情况,我有3个提交要一起重新建立基础,而中间的一个无关的提交。能够将提交提前或晚移到提交行的下方,这是非常好的。
弗洛雷斯

13

假设提交历史记录为preA -- A -- B -- C,如果要在A和之间插入提交B,则步骤如下:

  1. git rebase -i hash-of-preA

  2. Git将打开您的编辑器。内容可能像这样:

    pick 8668d21 A
    pick 650f1fc B
    pick 74096b9 C
    

    将第一个更改pickedit

    edit 8668d21 A
    pick 650f1fc B
    pick 74096b9 C
    

    保存并退出。

  3. 修改您的代码,然后 git add . && git commit -m "I"

  4. git rebase --continue

现在您的Git提交历史是 preA -- A -- I -- B -- C


如果遇到冲突,Git将在此提交时停止。您可以git diff用来定位冲突标记并解决它们。解决所有冲突后,您需要使用git add <filename>告诉Git冲突已解决,然后重新运行git rebase --continue

如果要撤消变基,请使用git rebase --abort


10

这是一种避免在我阅读的其他答案中看到的变基期间进行“编辑hack”的策略。

通过使用git rebase -i您可以获取自该提交以来的提交列表。只需在文件顶部添加一个“ break”,这将导致重新设置在该点中断。

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这里跑 无论是在变基期间还是在事前创建提交都没有太大区别。
BartoszKP

糟糕,我的意思是避免在改编过程中避免“编辑黑客”,我想我的措辞很差。
axerologementy

对。我的答案也没有使用变基的“编辑”功能。不过,这是另一种有效的方法-谢谢!:-)
BartoszKP

6

这里已经有很多好的答案。我只想通过4个简单的步骤添加“无基准”解决方案。


摘要

git checkout A
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

(可以选择在这里,而不是分离HEAD,我们可以使用创建一个临时分支git checkout -b temp A,在过程结束时需要将其删除。这两种变体都可以正常工作,因为您希望的其他所有方面都保持不变)


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 any potential conflicts between D and these last commits)

     B -- C <<< master
    /
   A -- D -- B' -- C' <<< detached HEAD (or <<< temp <<< HEAD)

(如果需要,可以在这里进行舒适的AB测试)

现在是检查代码,测试需要测试的所有内容的时候了,您还可以比较/比较/检查操作后拥有的内容获得的内容。


4)根据您C和之间的测试C',可以确定还是确定。

(以此类推)4-OK)最后,移动master

git branch -f master HEAD

     B -- C <<< (B and C are candidates for garbage collection)
    /
   A -- D -- B' -- C' <<< master

(或)4-KO)master保持不变

如果您创建了一个临时分支,只需使用删除它git branch -d <name>,但是如果您使用了分离的HEAD路由,则此刻根本不需要执行任何操作,新的提交将在您重新附上HEAD一个分支之后才有资格进行垃圾回收。git checkout master

在这两种情况下(正常或正常),这时只需master再次结帐以重新连接即可HEAD

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.