git merge后文件丢失

时间:2016-08-03 19:07:50

标签: git github merge git-merge

我已经阅读过有关此问题的其他问题,但是我的本地git中丢失文件的情况很简单。

我克隆了一个存储库:

 git clone https://github.com/uruddarraju/kubernetes
 cd kubernetes/

我使用以下命令对项目kubernetes进行了上游提取:

 git remote add upstrm https://github.com/kubernetes/kubernetes
 git fetch upstrm

这带来了一堆标签如下:

uruddarraju$ git tag
v1.3.2-beta.0
v1.3.3
v1.3.3-beta.0
v1.3.4

我正在尝试将v1.3.4合并到分支tess或远程源

git merge v1.3.4

我必须解决很多合并冲突,但有趣的是我也看到添加到upstrm / v1.3.4的新文件现在在本地文件系统中丢失了,我看不到该文件处于git状态。

这怎么可能?我期待这些文件作为合并的一部分添加,但显然它们不是。

uruddarraju$ ls pkg/genericapiserver/
resource_encoding_config.go

我正在寻找文件resource_config.go 我放弃了合并并检查了v1.3.4以验证该分支中是否存在该文件:

uruddarraju$ git checkout -b merege1.3 v1.3.4
uruddarraju$ ls pkg/genericapiserver
resource_config.go
resource_config_test.go
resource_encoding_config.go

我在两个分支上做了一个git diff,我清楚地看到这些文件已经在upstrm / v1.3.4中添加了 我在v1.3.4上运行了以下内容

uruddarraju$ git diff master --name-status
A       pkg/genericapiserver/resource_config.go
A       pkg/genericapiserver/resource_config_test.go
A       pkg/genericapiserver/resource_encoding_config.go

当我做相反的事情时,我正在掌握并使用v1.3.4做差异,我看到了:

uruddarraju$ git diff v1.3.4 --name-status
D       pkg/genericapiserver/resource_config.go
D       pkg/genericapiserver/resource_config_test.go
D       pkg/genericapiserver/resource_encoding_config.go

编辑1:

合并基础如下所示:

uruddarraju$ git merge-base --all HEAD v1.3.4
812b9a47d6625b0fd02af18f9b147720f3c6bfce

编辑2:

我也看到以下警告:

warning: inexact rename detection was skipped due to too many files.
warning: you may want to set your merge.renamelimit variable to at least 4292 and retry the command.

我显然遗漏了一些东西。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:2)

git merge做什么

在Git中,merge操作用于将第二行开发结合到第一行开发中。

假设Alice和Bob都在编写一些代码。它们以代码的通用版本开头。 Alice添加了一个新功能,Bob添加了一个不同的新功能。

在此过程中,Alice可能会创建或删除文件,或修改现有文件。同样,Bob可能会创建或删除文件。让我们说,只是为了论证,Alice能够在不添加或删除任何文件的情况下进行所有更改,但Bob添加文件n(对于新文件)并删除文件o (旧)。

Alice和Bob都提交了他们的更改 - 可能是一次提交,也许提交了多次 - 并且Alice将她的工作推回到origin,以便Bob可以看到它。

现在假设Bob决定合并Alice的工作,即获取她所做的更改。他可能会跑:

$ git fetch origin

这可以让Bob以名称origin/alice获得Alice的提交到Bob的存储库中。 (实际名称取决于Alice在做git push时使用的内容。)

接下来,鲍勃会跑:

$ git merge origin/alice

此合并必须首先找到合并基础:Alice和Bob分歧并进行不同提交的点。让我们假设Bob在分支bob上,并绘制提交图,以便我们可以看到这个"合并基础"是:

...--o--*--o--o--B     <-- bob
         \
          o--o--o--A   <-- origin/alice

在这种情况下,Alice通过进行四次提交来构建她的功能,这些提交添加和删除了没有新文件,但可能修改了一些现有文件。 Bob通过三次提交构建了他的功能,其中一些提交了新文件(new)和/或删除了现有文件(old)。合并基础是我标记为*的提交,Alice和Bob的分支提示分别是AB

Git的工作是结合 Alice的更改,来自未添加或删除任何文件但修改了某些文件的四个提交, plus Bob的更改,来自添加和删除文件的三个提交。如果一切顺利 - 如果没有要解决的冲突 - 最终结果仍然会有一个新文件new和一个已删除的文件old,并且Bob将获得一个新的合并提交< / em> M

...--o--*--o--o--B---M   <-- bob
         \          /
          o--o--o--A     <-- origin/alice

在此合并之前和之后,如果Bob要求Git提交提交BA,他会看到一些已删除的文件和一些已添加的文件。 这些不是Alice添加或删除的文件;相反,这些是Bob自己添加和删除的文件。

你的具体案例,与鲍勃的

鲍勃可能不会对此有任何疑问,因为他可能记得他做了什么。但是,在你的情况下,更像是在Bob离开小组之后出现并且现在正试图合并Alice和Bob的变化,而不知道Bob做了什么。 / p>

由于我们现在知道(来自git merge-base命令输出)只有一个合并库,我们可以使用三点语法与git diff进行比较一个合并基础到两个分支提示。实际上,这将让我们弄清楚Bob做了什么&#34;并且&#34;弄清楚Alice做了什么&#34;。

您的提交图可能比上面示例中的提交图复杂得多,但至少 ,您的任务是相同的:您有两个特定的提交AB你正在合并,其中commit B是你当前分支的HEAD提交,提交A是你用名称v1.3.4识别的那个}。所以你有:

...--o--*--o--o--B     <-- HEAD
         \
          o--o--o--A   <-- v1.3.4

(旁白:即使v1.3.4是一个标记,它也可以在这里工作。分支名称HEAD和你当前的分支名称一样,所以我用它代替分支名称。)

提交*是合并基础 - 哈希为812b9a47d6625b0fd02af18f9b147720f3c6bfce的基础。我们可以运行这两个git diff命令:

git diff 812b9a47d6625b0fd02af18f9b147720f3c6bfce HEAD
git diff 812b9a47d6625b0fd02af18f9b147720f3c6bfce v1.3.4

这需要输入哈希(或复制粘贴)。相反,我们可以使用这种更短的形式:

git diff v1.3.4...HEAD
git diff HEAD...v1.3.4

因为只有一个合并库(812b9a47d6625b0fd02af18f9b147720f3c6bfce),所以这两组命令做同样的事情。第一个显示我们&#34;我们做了什么&#34;第二个显示了我们&#34;他们做了什么&#34;。 Git将尝试将这两组变化结合起来。

(请注意,我们可以将--name-status和/或--stat添加到这些diff命令中,以获得更改的更短摘要,而不是完整的差异。这可能对您的情况有用。)

当你遇到冲突时(正如你所做的那样),这只是意味着Git无法协调他们的&#34;改变(来自第二个差异)&#34;我们的&#34;变化(来自第一个差异)。如果他们的更改包括添加文件,Git就没有问题:它会添加这些文件。它们不会从合并结果中遗漏。但据推测,这里发生的事情是&#34;我们&#34; (在&#34;我们的&#34;分支)删除了文件。

据推测,我们不需要这些文件,但是在我们通过合并添加到代码中的更改中,执行需要这些文件。 Git不知道这个--Git不知道任何代码意味着什么。我们只需要将这些文件恢复为某种合适的形式,并在必要时修复我们的代码,以允许这些文件存在;或者我们将不得不修改他们的代码,以便在没有这些文件的情况下工作;或两者的某种组合。

除此之外:如果没有一个合并基础

拥有两个或更多合并基础,甚至没有合并基础是很少见的,但并非不可能。在这种情况下,git merge知道该怎么做,但git diff没有。如果遇到这种情况,简单的git diff A...B; git diff B...A方法将无法(完全)向您显示合并过程的输入。没有简单的方法来处理这种情况。在使用git merge-base --all样式差异来确定git diff A...B是什么之前,最好检查(使用git merge)以确保不会干扰这一点。看到。