Foxtrot Merge:如何解决

时间:2019-07-18 08:54:31

标签: git bitbucket git-merge git-pull

我一直在从事一个项目,并一直将代码推送到远程git存储库上的dev分支。同时,在我需要获取的master分支中引入了一些更改。所以我用下面的路线: 1-git checkout主 2-git pull 3-git checkout my_dev_branch 4-git merge master

现在,当我将对拉取请求的更改提交给master时,它表明我执行的合并是foxtrot合并。我应该还原还是重置此较早的合并提交,然后从主服务器手动获取那些更改。还是对此有其他解决方案。

当前,我一直希望仅在合并之前恢复到提交,但是本文“ https://mirrors.edge.kernel.org/pub/software/scm/git/docs/howto/revert-a-faulty-merge.txt”中的文章呈现了一种令人沮丧和复杂的画面。我不希望它这么复杂。 这个答案(How to revert a merge commit that's already pushed to remote branch?)足够好吗? 谢谢大家。

2 个答案:

答案 0 :(得分:2)

首先,您列出的命令本身不会导致“ foxtrot合并”。 (另请参见GIT: How can I prevent foxtrot merges in my 'master' branch?)如果您有其中之一,则必须在完成以下操作后,可能已经通过git mergemasterorigin/master运行git pull您自己的master上的提交。 (这是您自己制作的master部分,不会在您的命令序列中显示。)

无论如何,您确实不想还原合并。这样就使合并保持原样,并添加了另一个提交,该提交的作用是撤销合并对源的影响。正是第二次非合并提交导致链接的kernel.org页面中的后续混乱。如果您执行执行此还原操作,最终将得到的是狐步合并,然后是更多的提交(包括还原),然后是以后无论如何都要重新合并的内容。因此,狐步步合并仍然存在!

总的来说,狐步舞合并并不是那么糟糕。他们只是将主线作为功能的 second 父级,而不是作为功能的 first 父级,但是谁说的是 > main 行放在首位?如果您改变看法,也许您的功能毕竟是主线,而其他所有人都称之为“主线”的东西实际上就是辅助功能。狐步舞合并的全部就是:改变视角,声称​​ you 是主线,而 they 是辅助功能。

但是,如果您不喜欢那样,那么唯一的解决方法就是重写自己的历史记录。由于它是您的历史记录[您的合并声明您的提交是您的主线],因此可能可以,不仅与您而且对其他所有人一样。如果已获得您的提交的其他所有人(您的历史记录)尚未依赖并基于这些提交,则 可以。如果他们依赖并基于这些提交,那么仍然可以:其他所有同事或同事都可以接受重做您重写自己的历史后,他们的工作?

如果所有这些都是真的-如果没有其他人依赖您的历史记录,或者所有依赖它的人都愿意做更多的工作,以便他们可以处理您对历史的重写,那么您就是要做的很清楚:从您的master删除您的狐步舞合并。这需要仔细使用git reset,并了解Git分支的实际工作方式,git merge的功能以及分支名称的方式不是关键。关键是提交图

进行新的提交将添加到图形中,并更新您“在”上的任何分支名称(即git status表示“在分支__上”),以便该分支名称标识新的提交。新提交的父级(对于大多数提交而言,是单数)是之前分支尖端的提交。如果新提交是合并提交,则新提交的父级(复数)是分支尖端的提交(通常),然后是 second 父级-您说要合并时指定的提交。

也就是说,Git中的分支只是一连串提交:

... <-F <-G <-H   <--master

名称 master会记住一个哈希ID,在这种情况下,HH代表了实际的哈希ID,这很丑陋一串以十六进制表示的160位数字,虽然不是,但它看起来是随机的)。提交H是分支上的 last 提交。 Git使用master中的哈希ID来查找实际的提交。提交H本身包含(即记住)Git用于查找提交G的父哈希ID G。提交G记住F; Git使用此哈希ID查找实际的提交F。重复此过程,让Git往后走,一次提交一次,以查找所有“在”分支上的提交-更确切地说,从可到达到分支名称。

当分支名称或提交包含其他提交的哈希ID时,我们说分支名称(或提交)指向它们包含其哈希ID的提交。因此,分支名称​​指向一个(单个)提交。该提交 是分支的尖端。那只是Git对“分支”的定义。

如果您对某些文件进行了某些更改,然后git commit进行了更改,则新快照将获得一个新的且唯一的大丑陋哈希ID,我们可以将其称为I。新的提交I记录哈希ID H,因此I指向H。然后,Git将I的提交哈希ID写入名称master中,以便master指向I

... <-F <-G <-H <-I   <--master

这就是分支的成长方式。

以正确的方式使用git reset时,您会告诉Git:更改master,以便使其指向我的新提交I,而不是指向H提交I实际上并没有消失:它仍然存在,并像以前一样漂浮在太空中。但是,如果master是您唯一的名称,那么现在很难找到其哈希ID。 (您已经记住了吗?:-))现在,您不再需要master指向II指向H,而是 now

             I
            /
...--F--G--H   <-- master

这也是摆脱狐步舞合并的方式。假设您开始使用:

...--F--G--H   <-- master

其他人添加了他们的IJ提交给他们的 master(您的git fetch记得作为您的origin/master):

...--F--G--H   <-- master
            \
             I--J   <-- origin/master

您可以通过合并自己的feature/tall向主控添加新的提交,甚至可能是其中的整个字符串:

             K--L   <-- feature/tall
            /    \
...--F--G--H------M   <-- master
            \
             I--J   <-- origin/master

在这里,您的合并提交M已将H作为其第一父级(“主线”)共享,并将您的提交L作为其第二父级(您的功能)。然后,将新的提交N添加到侧分支中,以使其J(即您的master的{​​{1}})进入分支,因为您的origin/master是主行:

M

他们的 K--L <-- feature/tall / \ ...--F--G--H------M--N <-- master \ / I-----J <-- origin/master 现在是一个分支,就像您的J一样,因为 main 行运行feature/tallN,{{ 1}},MH,...,直接沿着主线返回-第一对父母的顺序。

如果您想让主线回到G,则必须完全消除您的合并F。这需要使您的J再次指向M。您可以这样做:

master

然后我们可以(大致)绘制为:

H

请注意,所有提交仍然存在-git checkout master git reset --hard <hash-of-H> 仍然像以前一样返回到 L <-- feature/tall / \ K ,-M-----N /_/ / ...--F--G--H <-------- master \ / I-----J <-- origin/master N,而M仍然返回到两个{{1} }和J一样,但是没有 name 导致M,因此无法找到HL。因此,我们可以将它们从图形中删除:

N

现在您需要做的就是将N向前和向下滑动到M,您可以使用 K--L <-- feature/tall / ...--F--G--H <-- master \ I--J <-- origin/master 进行此操作:

master

我们现在可以重画甚至更少的内容:

J

您现在可以发出拉取请求,即,其他人为您运行git merge --ff-only origin/master的请求,其中您建议进行新的合并-我们可以称之为如果需要,请再次 K--L <-- feature/tall / ...--F--G--H \ I--J <-- master, origin/master -作为其第一父级,提交 K--L <-- feature/tall / ...--F--G--H--I--J <-- master, origin/master ,作为其第二父级,提交git merge:非狐步合并将主线称为“主线”,而将功能称为“功能”。

这些东西 很难。理解它的诀窍是,提交哈希ID 是通用的:它们在全局上是唯一的,并且每个存储库都会获取您的提交,并通过哈希ID来获取它们。您的Git和Joe的Git,Katherine的Git,Larry的Git等,都同意commit M是commit J 。它永远不会有任何其他哈希ID。但是您的Git使用的名称(您的分支名称)是您的您的。它们不需要出现在任何其他存储库中。 他们使用的名称-他们的 L他们的 H,依此类推-将显示在您的 Git就像您的 Hmaster,依此类推。正在运行:

develop

让您的Git调用其Git,一如既往地通过哈希ID来获取任何新提交,然后根据名称更新您的您的 origin/master名称。是origin/develop获取他们的提交并更新您的远程跟踪名称,即git fetch

当您运行origin/*或让Bitbucket或GitHub为您执行此操作时, 会创建一个新的提交-它会自动获取一个新的唯一哈希ID-这就是新的合并提交,它记录第一个父级(“主行”)和第二个父级(“功能”),均使用其哈希ID 。任何名称,无论它们是您的分支名称,例如{{1 }}或fetch之类的远程跟踪名称,在您实际拥有并保留 commit 及其唯一的哈希ID后就变得无关紧要。

换句话说:名称查找提交。只有提交才是真正重要的。名称仅在找到提交的时间,时间和原因才重要。

(另请参见how to avoid foxtrot merge in git。尤其是评论。)

答案 1 :(得分:0)

branches

在上图中,将分支 release/dev 合并到 GM-1166-SQS... 将导致 Foxtrot 合并。 要解决这个问题,只需首先在分支 GM-1166-SQS-... 上添加一个虚拟提交并推送它。 现在,如果您在 GM-1166-.. 中合并 release/dev,则不会出现 Foxtrot 错误。
这也是一种防止狐步舞错误的方法。

换句话说,如果分支 A 合并到分支 B,那么如果您需要合并 C 到 A,首先在分支 A 上做一个虚拟提交,然后才将 C 合并到 A。现在你不会得到 Foxtrot 合并时推。