解决Git(Team Foundation Server)悖论

时间:2017-01-09 21:45:50

标签: git tfs

这怎么可能?

这两个分支明显不同,但PR说它没有发现差异。

我很难过。并阻止。我不能继续,直到我的代码进入dev,所以这不仅仅是好奇心。

我甚至尝试将MarketReseach2合并到dev中。它告诉我它已经是最新的了。

然而,我可以在Visual Studio中在它们之间来回切换,看看差异。

enter image description here

1 个答案:

答案 0 :(得分:-1)

合并并不代表您认为的含义

问题很简单:合并(作为动词,即作为要采取的动作)并不代表"制作相同的"。这意味着"结合变化"。

让我们退一步吧。我们究竟是什么意思"变化"?无论如何,提交中的内容是什么?并且:What exactly do we mean by "branch"?

你提到:

  

我可以在它们之间来回翻转......并看到......差异

让我们很好地掌握"他们"首先意味着查看关于我们的意思的链接问题" branch"同样,但根据你的图像,"他们"是名称 MarketResearchCampaign2dev。这两个名字实际上转化为两个特定的提交ID:两个丑陋的SHA-1哈希,你的IDE帮助(咳嗽:-))隐藏,这样你就看不到它们了,但事实上它们看起来像{{1}或者其他一些。

隐藏在名称后面的哈希ID,因为哈希ID确实 对人类非常有用,代表特定的提交。每个提交都有自己唯一的哈希ID。但究竟是提交的是什么?

好吧,当你在这两个提交之间来回切换时,你会看到整个文件树:工作树的快照。这是提交内容的一部分。通过提交,您可以访问工作树的快照:您可以检出任何历史提交,并检索与该提交一起使用的已保存工作树。

提交的其余部分是一堆元数据,包括提交者和日志消息,以及 - 对于Git - 父级非常重要的东西提交,即之前的提交特定提交。

父母和分支机构

大多数提交都有一个父级。这些父母以倒退的方式形成项目的历史 - 或项目的某些部分。这让我们(和Git)从最近的提交开始并向后工作:

7b19d86e69d...

名称... <- o <- o <- o <-- dev 指向最近的提交,指向先前的提交,指向另一个提交,依此类推。除了dev命名最新此类提交的关键事实外,我们大多不必担心箭头都是向后的,因此绘制起来更好尽管如此,这些都是这样的:

dev

这让我更容易在树枝上画画。现在...--*--o--o <-- dev \ o--o <-- ziggy 指向最近的dev提交,dev指向最近的ziggy提交。 名称 ziggydev指向一个特定的提交,这些提交指向旧的提交。

请注意,我已使用ziggy标记了一个提交,其中两组向后连接的箭头连接起来。这是理解合并的关键项目之一。

比较提交

当您在两个特定提交之间来回切换时,您会看到不同的文件。 Git可以比较这两个提交 你。从命令行,您只需运行:

*

比较这两个提交。您的IDE也应该有这样做的方法。

但是,更常见的是,您可能希望比较两个不同的分支名称,而不是某个分支上的某个提交,而不是其中一个提交。也就是说,鉴于上面的git diff dev MarketResearchCampaign2 dev,我们可能会将ziggy的提示与dev提示后的提交进行比较:提交dev。这将显示你在进行这两次提交中的第二次时所改变的内容。

我们也可能将这两者中的第一个与提交*本身进行比较。这将显示您从*更改为这两个提交中的第一个。

当然,我们可以将**的提示进行比较。这将显示您在所有提交的所有所做的一切从dev*的提示。

同时,我们可以用同样的方式将dev的提示与之前的提交进行比较。如果我们将ziggy上的最后一次提交与其前一次提交进行比较,则表明我们在那里做了什么。如果我们将ziggy上的最后一次提交与提交ziggy进行比较,那么:嗯,这表明我们在分支*上所做的一切,与提交ziggy相比。

但请查看commit *

的位置

提交*的有趣之处在于它两个分支:它是*和{{}的最新提交1}}还在一起。从那时起,dev已经分歧,有几个新的提交;并且ziggy也有分歧,有几个新的提交。如果我们认为这是一个好主意,我们现在可以重新加入这两行:我们可以让Git找到&#34;自dev&#34;以来我们所做的一切在ziggy,以及&#34;自*&#34;以来我们所做的一切在dev中,并进行重新组合这两者的新提交。

合并的作用是:它发现了一些公共点后的变化。

请注意, commit *之前的任何提交也在两个分支上。使ziggy特殊的事情不仅仅在于它在两个分支上,而在于它是两个分支上的最近提交 1

1 从技术上讲,它是最低的共同祖先&#34;或DAG或有向无环图中的LCA。这种技术性仅在存在多个LCA时才有意义。 LCA中的一个或另一个可能实际上是较新的,但实际上它是拓扑而不是日期。 Git和其他一些VCS处理多LCA情况不同于例如Mercurial。在这种情况下,Git实际上为您提供了合并策略选择:*执行一项操作,*执行另一项操作。但这是一个独立的高级主题。

合并制作新的共同提交点

我们说我们进行合并,并在分支-s recursive上进行:

-s resolve

这个新的合并提交ziggy有一些特殊的东西:它指向的是,而不是一个之前的提交,而是两个。第一个&#34;之前的提交&#34;是...--o--o--o <-- dev \ \ o--o--M <-- ziggy 的旧提示,最右边的M位于底行,第二个是&#34;之前的提交&#34;仍然是!ziggy的一角,最右边的o。{/ p>

现在让我们通过更改一些内容,在dev上进行更多提交。我还要使用o标记ziggy的提示最多提交:

dev

让我们将*的提示(即提交...--o--o--* <-- dev \ \ o--o--M--o--o--o <-- ziggy )与dev的提示进行比较。他们肯定不会匹配:当我们通过合并将*中的内容带入ziggy时,他们甚至不会在{{1}匹配} -vs - dev,因为我们合并 ziggy更改与之前的*更改。现在他们可能会更少匹配。

如果我们现在要求Git再次将M合并到dev,会发生什么?好吧,Git首先要找到两个分支在一起的最新点......那就是ziggy。因此,Git会将devziggy的提示进行比较,以查看我们在*上所做的更改,并将其与我们在*上更改的内容相结合。< / p>

dev dev的提示。什么都没有合并!实际上,整个提交的最顶行都在两个分支上,ziggy再一次只是最近的这样的提交(或者,再次,从技术上来说,它是LCA节点) )。

当Git告诉你没有要合并时,这意味着你选择的两个特定提交,作为他们最近的共同祖先提交,这两个提交之一。 (或者,在最新的Git版本中,如果有 no 常见提交,则会出现不同的错误;较旧的Git版本只是对空树进行两次提交,并像往常一样组合生成的差异。) &#34;合并&#34; 表示&#34;根据某些常见的基本提交结合查看的更改&#34;,必须 在两个端点上针对某些常见的基本提交进行一些更改:公共基础提交不能是两个端点之一。

关于&#34;快进合并&#34;

的附注

在这种情况下:

*

您无法将dev合并到*,但您可以...--o--o--* <-- dev \ \ o--o--M--o--o--o <-- ziggy 合并到dev中。实际上有两种方法可以做到这一点。一个是真正的合并:

ziggy

这会将ziggydev的变化(即无变化)与...--o--o--o------------N <-- dev \ \ / o--o--M--o--o--o <-- ziggy *的变化相结合,从而产生相同的变化文件在*的提示中。也就是说,它结合了“没有变化”和#34;与&#34;一些变化&#34;。结果显然是&#34;匹配*&#34;的提示,所以在这种情况下,它 最终制作一个新提交ziggy,其文件与ziggy提示中的文件完全匹配。 (并且,ziggy的提示成为新的N:新的最近共同提交。)

但是,Git通常不会为这种情况进行合并提交。相反,它意识到将某些东西与某些东西组合在一起会自动产生&#34;某些东西&#34;,即新的提交将与ziggy的尖端完全匹配。因此,毕竟没有理由去做提交ziggy 2 相反,它只是移动分支标签,以便它们都指向相同的 commit:

*

这是一个所谓的&#34;快进&#34;操作(或&#34;快进合并&#34;,虽然没有实际的合并进行)。这里的缺点是这根本不会创建新的合并提交;相反,两个分支标签最终指向相同的提交,直到您在两个分支中的一个或两个上进行新的提交。例如,假设您在ziggy上进行了一次新提交,在N上进行了两次提交:

...--o--o--o
      \     \
       o--o--M--o--o--*   <-- dev, ziggy

因为从来没有实际的合并提交,所以不再可能独立地遵循这两行。如果您使用dev来强制进行真正的提交,那么您将获得提交ziggy并以此结束:

...--o--o--o            o   <-- dev
      \     \          /
       o--o--M--o--o--*--o--o   <-- ziggy

现在可以使用每个提交中的正确(git merge --no-ff)链接来准确地跟踪每个开发阶段的发生位置。

这有关系吗?你决定了!

2 当然,除了 原因之外,正如本节其余部分所述。有时这是一个重要的原因,有时它不是;由你决定它是否重要,如果是的话,强制Git进行真正的合并提交。