移动创建分支的提交

时间:2019-11-20 21:20:12

标签: git branch rebase

好的,这是交易。我在提交(2f6ea37)的基础上创建了一个分支(master),然后在master的基础上创建了另一个分支(develop)。在开发上进行了更改。问题是,master应该实际上是根据先前的提交(df7992e)而不是(2f6ea37)创建的。

如何在不丢失致力于开发的新内容的情况下更改master的创建位置?

现在是这样:

branch1 --> <2f6ea37> --> <df7992e>
                                   \ 
                                    master
                                          \
                                           develop --> <new_commit>

这是应该的样子:

branch1 --> <2f6ea37> --> <df7992e>
                     \ 
                      master
                            \
                             develop --> <new_commit>

1 个答案:

答案 0 :(得分:1)

TL; DR

您可能只需要三个git branch -f命令即可​​执行所需的操作:

git branch -f master 2f6ea37
git branch -f branch1 df7992e
git branch -f develop 2f6ea37

但是要使用git branch -f来执行此操作,您必须使用这三个名称中的任何一个都不是的分支名称,因此您可能需要一个git reset --hard或其他命令。如果develop已经有其他提交,那么您将遇到更大的问题。请参阅下面的详细说明。

首先(这虽然很小,但这确实很重要),图中的箭头是错误的,因为它们是向前的。 :-) Git向后做所有事情。因此,像df7992e这样的提交会将向后指向其前身2f6ea37

masterdevelop之类的分支名称仅包含一个原始哈希ID,即它们直接指向特定的提交。所以我将其绘制为:

2f6ea37   <-- branch1
    \
  df7992e   <-- master
      \
       C <-D <-E   <-- develop

为避免沉迷于无法读取的哈希ID,我只需致电2f6ea37 Adf7992e B

A   <-- branch1
 \
  B   <-- master
   \
    C--D--E   <-- develop

现在,关于Git中分支名称的问题是,您可以始终将新的哈希ID填充到 any 分支名称中。现在,该分支仅指向您为其提供的哈希ID。

分支名称​​预期随着时间的推移而移动的方式是,以便它们积累新的提交:

A--H   <-- branch1
 \
  B--F--G   <-- master
   \
    C--D--E--I   <-- develop
例如,

已以“预期”方式移动了所有三个分支名称:branch1现在标识具有哈希值H的提交,它指向具有哈希值A的提交,其中{ {1}}之前已确定。这样很好类似的论点适用于其他两个。

您显然希望名称branch1标识提交master,名称A标识提交branch1。 (我们将在下一节中担心B!)您可以通过将正确的哈希ID强制插入每个名称中来实现这一部分:

develop

但是,如果我们将其与之前的状态进行比较,则名称A <-- master \ B <-- branch1 \ C--D--E <-- develop 朝着“错误”的方向移动。它曾经命名为commit master,现在命名为B。名称A已沿“右”方向移动(向前移动,与内部向后指向的箭头相反)。

像这样向后移动分支名称会使其他 Git存储库(和/或其用户)如果看到您的 {{1 }}之前确定提交branch1。请记住,所有Git都共享原始哈希ID,因此,如果其他任何Git都提交了master,他们可能会有一些名字记得它。他们可能有B指向共享提交B的副本,结果,他们也可能有自己的origin/master指向B

如果没有其他人见过这个,那就很好。只需使用master和/或B将正确的哈希ID填充到正确的分支名称中即可。

这里潜在的大刺

最后一个问题是分支名称git branch -f。在这里,我已将其指向提交git reset --hard,其中develop指向E,指向E,指向D。 / p>

我相信,根据您绘制初始图表的方式,目前您真正拥有的东西看起来像这样:

C

也就是说,提交B根本不存在。如果是这样,我们也只需要移动A <-- branch1 \ B <-- master, develop 来直接指向C-D-E,就需要注意的是,将develop“向后移动”与我们将A相同方式:

develop

如果您现在master并进行新的提交A <-- master, develop \ B <-- branch1 ,则新的git checkout develop将指向C

C

此处所附的A表示您已签出的分支目前为 C <-- develop (HEAD) / A <-- master \ B <-- branch1

但是如果您已经拥有现有提交(HEAD)呢?也就是说,如果您当前的图表是:

develop

这里的问题是现有提交C-D-E已经指向现有提交A <-- branch1 \ B <-- master \ C--D--E <-- develop (HEAD) 。提交后,关于任何提交的任何内容都无法更改。因此,您根本无法进行更改 C。在这种情况下,您要做的是 copy B,因此还有CC到新的和改进的提交。它们的新功能和改进之处在于,新的D(我们称为E)指向C,并使用C'作为其源库。同样,新的A指向A,新的D'指向C',这是给我们的:

E'

这也以一种意外的方式移动了名称D':现在,我们不仅备份了 C'-D'-E' <-- develop (HEAD) / A <-- branch1 \ B <-- master \ C--D--E [abandoned] ,我们还备份了develop,然后是{{1 }},然后也是B。 (现有的提交E仍可以通过某些分支名称找到,因此不会被放弃。)

将完成所有这些操作的命令是D。将C牢固地附加到B上后,您将运行:

git rebase

使用原始哈希ID表示排除提交HEAD和更早的提交,向后复制当前提交中的所有提交,新提交在提交develop之后。然后将名称git rebase --onto 2f6ea37 df7992e 指向最后一个这样的复制提交。排除表示要复制的提交集合恰好是正确的集合B,因此我们得到了什么我们在上面画了。

现在是时候使用两个2f6ea37命令交换其他两个分支名称,而我们仍在开发中。或者,我们可以在启动develop之前将其交换。

如果您没有要提交的C-D-E副本但是在git branch -f上怎么办?

假设现在可以通过以下方式绘制实际图片:

git rebase

您可以使用C-D-E交换两个名称developA <-- branch1 \ B <-- master, develop (HEAD) ,而无需以任何方式更改任何其他提交。但是现在您剩下了:

git branch -f

使用branch1会给您一个错误:

master

但是您仍然需要移动A <-- master \ B <-- branch1, develop (HEAD) 。有很多方法可以做到:

  • 使用git branch -f developfatal: Cannot force update the current branch. :这从复制中排除了从develop开始向后的提交,即所有提交;在提交git rebase之后复制零个提交;然后移动您当前的分支名称以指向提交git rebase --onto master branch1

  • 使用BA:这会丢弃索引和工作树中所有正在进行的工作,而是将它们重新设置为与提交A相匹配,然后移动您当前的分支名称git reset指向提交git reset --hard master。这样做的好处是它快速简便,并且可以满足您的需求。缺点是,它会清除您忘记保存在某处的所有正在进行的工作。 rebase命令将警告您。

  • 使用Adevelop。这与rebase和reset命令完全一样有效,但是需要输入三个单独的命令。在某些情况下,它确实能够在索引和工作树中进行未提交的工作(有关详细信息,请参见Checkout another branch when there are uncommitted changes on the current branch)。

结论

分支名称可以很容易地移动。要移动您站立的分支,请下车(A),或使用git checkout或其他偷偷摸摸的方法。请记住,git checkout master; git branch -f develop master; git checkout develop对未完成的工作具有破坏性。

您不能修改任何现有的提交。如果无需此操作即可对分支名称进行调整,则只需调整这些分支名称即可。其他任何人(例如,您提供的其他Git存储库)可能会因“异常”分支名称移动而感到困惑,因此请确保其他Git存储库及其用户已经为此做好了准备。

如果您需要复制一些提交,git checkout将完成这项工作。这也可能以其他跟踪您的分支名称(和提交)的Git可能需要准备的方式来调整分支名称。