【问题标题】:How to inject a commit between some two arbitrary commits in the past?如何在过去的一些任意提交之间注入一个提交?
【发布时间】:2015-08-31 15:48:46
【问题描述】:

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

A -- B -- C

如何在AB 之间插入新的提交?

【问题讨论】:

  • 我对@9​​87654321@ 有一个非常相似的问题,而不是提交。

标签: git git-rebase


【解决方案1】:

这比 OP 的答案更容易。

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

请注意,这将改写历史,并破坏任何试图拉动的人。

【讨论】:

  • 这在提交之后添加了新的提交,这是在我重新定位到的那个之后(也是最后一次提交),而不是在我重新定位到的那个之后。结果与我在最后简单地使用我想要插入的更改进行新提交一样。我的历史变成了A -- B -- C -- D,而不是想要的A -- D -- B -- C
  • @XedinUnknown:那你没有正确使用 Rebase。
  • 要使用这个答案,首先你必须确定新的提交。在一种情况下,这可能只是小费;我们称之为D,所以我们有A - B - C - D,目标是A - D - B - Cgit rebase -i HEAD~4,然后在编辑器中将提交重新排序为 ADBC 顺序,保存,退出。
  • 现在D 可以在任何地方提交。假设我们有 A - B - C 并且我们有一些提交 D 甚至不在这个分支中。但是我们知道它的 SHA,我们可以做git rebase -i HEAD~3。现在,在 AB pick 行之间,我们插入一个 new pick 行,上面写着 pick SHA,给出所需 D 的哈希值。它不必是完整的散列,只是缩短的散列。 git rebase -i 只是挑选缓冲区中pick 行列出的任何提交;它们不必是它为您列出的原始文件。
  • 更简单的是,您可以在编辑器中在两次提交之间的单独行中使用 break 关键字(或在第一行,在指定的提交之前插入提交)。
【解决方案2】:

原来很简单,找到here的答案。假设你在一个分支branch。执行以下步骤:

  • 在你想插入新的提交之后从提交中创建一个临时分支(在本例中是提交A):

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

    git commit -a -m "Message"
    

    (或git add 后跟git commit

  • 在新提交之后将您想要的提交(在本例中为提交 BC)重新设置为新提交:

    git rebase temp branch
    

(您可能需要使用-p 来保留合并,如果有的话 - 感谢a no longer existing comment ciekawy

  • 删除临时分支:

    git branch -d temp
    

在此之后,历史如下所示:

A -- N -- B -- C

变基时当然会出现一些冲突。

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

【讨论】:

  • 我无法遵循 SLaks 接受的答案,但这对我有用。在获得我想要的提交历史记录后,我不得不 git push --force 更改远程仓库。
  • 当使用 rebase 时,使用 -Xtheirs 选项自动正确解决冲突,所以git rebase temp branch -Xtheirs。注入脚本的有用答案!
  • 对于像我这样的菜鸟,我想在git rebase temp branch 之后,git branch -d temp 之前添加,您所要做的就是修复和暂存合并冲突并发出git rebase --continue,即不需要提交任何东西,等等。
【解决方案3】:

更简单的解决方案:

  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
    

【讨论】:

  • 好主意,但是当您打算进行这些更改时,可能很难在 C 上引入 D。到 A.
  • 我有 3 个提交要一起变基,中间有一个不相关的提交。能够将提交提前或推迟到提交行中,这真是太好了。
【解决方案4】:

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

通过使用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的使用。使许多采摘方式更容易跟踪。
【解决方案5】:

假设commit history是preA -- A -- B -- C,如果要在AB之间插入commit,步骤如下:

  1. git rebase -i hash-of-preA

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

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

    将第一个pick改为edit

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

    保存并退出。

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

  4. git rebase --continue

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


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

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

【讨论】:

    【解决方案6】:

    这里已经有很多很好的答案了。我只是想通过 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 测试)

    现在是检查您的代码、测试任何需要测试的内容的时刻,您还可以比较/比较/检查您拥有什么您将获得什么 操作后,只需交替检查CC'


    4) 根据您在CC' 之间的测试,它是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 &lt;name&gt; 将其删除,但如果您选择分离的 HEAD 路线,此时根本不需要任何操作,新提交将在您重新附加后符合垃圾回收条件HEADgit checkout master

    在这两种情况下(OK 或 KO),此时只需再次签出 master 以重新附加 HEAD

    【讨论】:

      【解决方案7】:

      假设您要插入的提交由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
      

      【讨论】:

      • 您的回答与Matthew's one 极为相似,尽管解释性较差。我猜这是有人投反对票的原因?
      猜你喜欢
      • 2023-02-20
      • 2013-09-10
      • 2010-10-13
      • 1970-01-01
      • 2019-04-22
      • 1970-01-01
      • 1970-01-01
      • 2019-10-27
      • 1970-01-01
      相关资源
      最近更新 更多