在git中重新定位后,历史会不会消失

时间:2014-01-22 03:42:58

标签: git version-control

假设我有三个提交的主分支

A--B----C

我创建了新的分支dev并在那里创建了3个提交

A--B----C------C1------C2
         \
          E---F----G

现在我像这样与大师合并

git merge dev --squash

现在我认为新图表是这样但不确定

A--B----C------C1------C2--------M----
         \                      /    
          E---F----G-----------/

之后我需要将dev分支与master合并以获得c1和c2

所以它会像这样

A--B----C------C1------C2--------M----
         \                      / \   
          E---F----G-----------/----m2 ---H--I

devmaster将并行

我想知道

  1. 在提交E F G
  2. 之后,个人提交历史记录是否会出现在dev分支中
  3. 我想知道如果我使用rebase而不是合并两个分支应该并行的话,图表是什么

  4. 如果对第一个问题的答案是肯定的,那么如果我使用rebase命令,个别历史记录提交将会消失

2 个答案:

答案 0 :(得分:4)

让我用一些标签重新绘制第二张图:

A--B--C-----C1----C2    <-- master
       \
        E--F----G    <-- dev

(我假设C1C2仅代表master EFG上发生的一些提交被添加到dev)。

如果你现在在master并运行git merge dev --squash(然后提交结果:--squash禁止最后提交步骤),你得到 this ,这与你画的非常不同:

A--B--C-----C1----C2---M    <-- master
       \
        E--F----G    <-- dev

如果您在没有 git merge的情况下运行--squash ,您将获得所绘制的内容。 --squash标志将引用文档:

  

生成工作树和索引状态,就像真正合并一样              发生了(合并信息除外),但实际上并没有              提交或移动HEAD,或记录$ GIT_DIR / MERGE_HEAD 到              导致下一个git commit命令创建合并提交。

换句话说,壁球合并根本不是合并(这就是为什么我有,呃,&#34;问题&#34;有一些git&#39的术语:-) ...一些结账结帐,有些不是;有些合并是合并,有些则不合并;分支只是分支提示,除非它们不是,等等!)。 A&#34;壁球合并&#34;确实使用底层合并代码来确定下一个提交的内容应该是什么,但是如果你进行实际提交(上面标有M的那个),它只是一个普通的非合并提交,完成工作 - 提交的更改EG,并将这些更改复制到C2中的最新版本。把它想象为&#34;有人向你发送差异,将版本C与版本G进行比较,然后手动将所有这些更改插入版本C2并提交(应该可能被称为C3,但我们称之为M而不是#34;。


如果您想要真正的合并,请在不使用 --squash的情况下进行合并。这实际上会给你你画的东西,我将在这里重新绘制:

A--B--C-----C1----C2---M    <-- master
       \              /
        E--F----G----/      <-- dev

(标签dev仍然指向提交G。)

接下来,如果您想要了解C1C2中的更改并将其放在dev上,您可以执行以下两项操作之一:

git checkout dev && git merge master

或:

git checkout dev && git merge --no-ff master

这里的区别在于您是否获得了您提交的提交m2。如果没有--no-ff,git会观察到devmaster的合并会产生提交M,只会将dev标签移到指向M的位置:

A--B--C-----C1----C2---M    <-- dev, master
       \              /
        E--F----G----/

但是使用--no-ff,合并必须产生一个新的,不同的合并提交(同一个树,但是不同的提交,但是具有不同的父年龄):

A--B--C-----C1----C2---M    <-- master
       \               X
        E--F----G------m2   <-- dev

此处合并MC2作为其第一个父级,G作为其第二个父级。这表明它是G2(&#34;非第一个&#34;父级)合并到master(第一个父级)。另一方面,合并m2作为第一个父项G,第二个父项C2

换句话说,树(工作目录)是相同的,父项的 set (list-ignoring-order)是相同的,甚至提交消息和时间戳也可以是相同的:但是父母的顺序是不同的,仅此就足以保证这些将是不同的提交。


你问题的标题是关于变基,而不是合并。 Rebase完全是一个不同的操作。让我们说你在分行dev上运行git rebase master

要做一个rebase,git的作用是什么(实质上 - 应用了一些优化,以及一些带有merge提交的极端情况),简单地说是&#34; cherry pick&#34;每个分支都会提交,并应用那些&#34;樱桃&#34;到其他一些分支。让我们回到第一张图:

A--B--C--C1--C2    <-- master
       \
        E--F--G    <-- dev

这里的想法是&#34;选择&#34;提交E,然后F,然后G并按顺序应用它们。让我们首先将E复制到E',应用于C2之上:

                E'
               /
A--B--C--C1--C2    <-- master
       \
        E--F--G    <-- dev

接下来,我们将F复制到F',如下所示:

                E'--F'
               /
A--B--C--C1--C2    <-- master
       \
        E--F--G    <-- dev

还有一个承诺要复制GG'

                E'--F'--G'
               /
A--B--C--C1--C2    <-- master
       \
        E--F--G    <-- dev

除了一件事之外我们都完成了:我们需要一个新的提交链标签。我们称之为dev!糟糕,等等,我们已经有了一个标签dev。好吧,让我们剥离旧的dev标签,然后将其粘贴到新的G'上:

                E'--F'--G'   <-- dev
               /
A--B--C--C1--C2    <-- master
       \
        E--F--G

Voila,git rebase完成了。这就是它的作用:将旧提交复制到新提交。

旧的会发生什么?嗯,他们是我所说的&#34;被遗弃的&#34;。它们仍在您的存储库中,但它们的唯一标签仅存储在&#34; reflogs&#34;中。 reflog条目将使它们保持30天左右的默认到期超时。 (它是可配置的,实际上有两种不同的超时,但最好将其视为&#34;一个月左右的时间&#34;。)因此,在大约一个月内,git将垃圾收集废弃的提交。

有时候,重新定位是错误的,因为它为共享你的git repo的其他人创造了更多的工作(直接,或者更有可能,在你推动工作的某个中央存储库中)。假设其他人提交了EG,他们做了更多工作,并在H之上提交了G。然后,您将E复制到G,然后放弃原来的EG。您现在已经他们的工作,提交H,需要更多工作:例如,他们可能需要在您的H上重新定位G'

如果没有其他人通过E进行您的提交G,您可以确定您没有为不存在的其他人做任何额外的工作。一个rebase只会影响,所以大多数&#34;坏&#34;走了。


最后,对于rebase vs merge(以及是否合并,是否以及何时使用--no-ff)vs&#34;压缩合并并放弃原始开发链&#34; vs any-else-you-can-up-up-with。在git中进行提交,并使用合并,挑选和重新定位等操作它们的整个想法是让它更容易维护工作。所有摆弄提交图表都是毫无意义的,除非它使维护实际工作变得更容易。

答案 1 :(得分:0)

我会尽力解释......

当您在dev:

之上重新设置master时
A--B----C-----E---F----G-------------C1------C2
         \                      /    
          E---F----G-----------/

之后你可以从master拉到dev而不会发生冲突

当你在master上重新开发dev时:

A--B----C------C1------C2----
         \                        
          ----C1------C2------E---F----G-----------

之后你可以从dev拉到没有冲突的主人

当您重新定位dev分支而不是更改master时,确定第二个变体要好得多......