旧提交编辑后分支的分支

时间:2014-02-11 23:17:56

标签: git

我创建了一个新的分支并开始研究它

Z--A--B--C (master)
          \-D--E (new-branch)

然后我重新编辑旧提交(A),同时仍然在new-branch并且我的分支已经分开

Z--A--B--C (master)
 \-A*--B--C--D--E (new-branch) (A* -> edited commit)

如何将它们融合回以下状态?

Z--A*--B--C (master)
           \-D--E (new-branch)

2 个答案:

答案 0 :(得分:2)

在糟糕的变形之后你的实际状态是这样的:

Z--A--B--C (master)
 \-A*--B*--C*--D*--E* (new-branch)

现在,您可以使用reflog来恢复以前的新分支状态,检查正确的分支,然后执行rebase。另一方面,你最终会得到相同的分叉状态,所以......

你必须改变新分支。这可能很简单:

git rebase master

Git将自动跳过应用提交B *和C *,因为它们可能最终为空(除非提交A触及他们也触及的代码,在这种情况下你会发生冲突)。如果您想确保 rebase提交D *和E *,请限制哪些提交受rebase约束并使用--onto

git rebase --onto master HEAD~2

HEAD~2表示C *并表示rebase操作的边界,即我们将选择D *和E *并将它们应用到master。

答案 1 :(得分:2)

实际上,你有什么后绑定是这个(我会拼写他们B'等而不是B*等,因为这似乎是更常用的写这些方式):

Z - A - B - C   <-- master
  \
    A'- B'- C'- D'- E'  <-- new-branch

这是因为rebase必须复制每个旧提交(或者更确切地说,复制其中的大部分,除了更改的位)以更改其中的任何内容,并在修改提交后{{1}要制作A,它必须复制和修改A',因为新的B不同:B'B'作为其父级,而不是{{1} }}。 (其他一切都是一样的,但更改父级需要进行全新的提交。幸运的是,提交非常小。它们只有父级,时间戳等,提交消息,以及与“树”相关的一个SHA-1提交,git可以重用旧树。)

如果您想保持A'现在的方式并且将其显示在A的历史记录中,则必须重新指向A'提交master处的1}}标签。这将“放弃”提交master 1 (这里的ASCII艺术现在令人不安地拥挤:-)):

C'

这也意味着之前见过你“发布”(或“宣传”)你C意味着任何SHA-1提交Z - A - B - C [abandoned] \ .---------- master A'- B'- C'- D'- E' <-- new-branch 所拥有的其他人,会看到你“重写”历史记录“:提交master根本不在图片中,也不在CC。相反,现在B指向A,其指向master,其指向C',其指向B'

当然,A'也是如此:它过去常常指向Z但现在却指向new-branch

另一方面,也许你真的不想改变E。在这种情况下,您只有两种选择:完全放弃E',或者在提交master后让A'master分歧。

让我们作为一个群体进行讨论(除了最后一个选项,这很简单:什么都不做,这就是你现在拥有的!)。


要重新指向new-branch,有两种简单的方法:

  • 进入分支,然后使用Z,(在大多数操作模式下)将更改分支指向的提交:

    master

    (与git reset一样,在运行之前要非常小心,你在要重新设置的分支上,并且没有未保存的工作树数据。)

  • 在分支上时,使用git checkout master git reset --hard new-branch~2 # point master to commit C' 强制移动它:

    git reset --hard

如果您不想移动git branch -f并且想要放弃git branch -f master new-branch~2 # point master to commit C' 并恢复旧的master,则有多种方法。假设您现在正在使用并且自rebase以来没有做任何事情,特殊引用名称A' 2 将指向原始提交new-branch。换句话说,我们可以更全面地了解原始的后期基础情况:

ORIG_HEAD

所以:

  • 如果你在E并且想要取消你的生活,那么 D - E <-- ORIG_HEAD (copied from new-branch before rebase) / Z - A - B - C <-- master \ A'- B'- C'- D'- E' <-- new-branch 就可以了。 (照常使用与new-branch相同的照顾。)

  • 如果为时已晚,您可以在reflog中找到commit git reset --hard ORIG_HEAD,在原始SHA-1中找到--hard,或者使用像E这样的reflog拼写或git reset --hard或其他。

  • 如果您不介意将new-branch@{yesterday}HEAD@{3}复制到新副本D'E',则可以重新D'' E'' 1}}使用new-branch(我看到的是Magnus Bäck's answer中的较长形式的rebase,在此之前进入)。


1 reflog将保留commit --onto一段时间,因此repo将保留提交,直到reflog条目到期为止。所以它不是完全放弃,或者至少,还没有。

2 当您开始新的rebase时,会设置C“特殊”引用,但也会使用ORIG_HEAD之类的内容。如果您不确定,可以使用git merge或类似内容查看其实际指向的位置。