Foxtrot Merge:如何解决

Ali*_*. K 4 git bitbucket git-pull git-merge

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

现在,当我将我对拉取请求的更改提交到 master 时,它表明我执行的合并是 foxtrot 合并。我是否应该恢复或重置这个较早的合并提交,然后手动从 master.js 中获取这些更改。或者有没有其他可用的解决方案。

目前,我一直希望在合并之前恢复到提交,但这篇文章在这里“ https://mirrors.edge.kernel.org/pub/software/scm/git/docs/howto/revert-a-faulty- merge.txt ” 呈现出一幅相当阴郁而复杂的画面。我不希望它是一项复杂的任务。这个答案(如何恢复已经推送到远程分支的合并提交?)是否足够好?谢谢你们。

tor*_*rek 10

首先,您列出的命令本身不会导致“foxtrot 合并”。(另请参阅GIT:我如何防止在我的“主”分支中发生 Foxtrot 合并?)如果您有其中之一,那么您自己进行提交之后,您必须git merge从您的运行master到您的origin/master,可能是通过。(这个 make-a-commit-on-your-own-部分没有显示在您的命令序列中。)git pullmastermaster

无论如何,您真的不想恢复合并。这将合并保留在原位,并添加另一个提交,该提交具有撤消合并对源的影响的效果。正是这第二次非合并提交导致了链接的 kernel.org 页面中的后续混乱。如果你这样做了恢复,你最终会得到一个 Foxtrot 合并,然后是更多的提交,包括恢复,然后是你以后必须做的任何事情来重新合并合并。所以狐步舞合并仍然存在!

一般来说,狐步舞合并并不是那么糟糕。他们只是让主线作为一个特征的第二个父级,而不是作为一个特征的第一个父级——但谁又能说哪条线首先是主线呢?如果换个角度看,也许你的特征毕竟主线,而其他人一直称之为“主线”的实际上是副特征。这就是狐步舞合并的全部内容:视角的改变,声称是主线,而他们是副线。

但如果你不喜欢那样,唯一真正的治疗方法就是重写你自己的历史。因为这是你的历史——你的合并声明你的提交是你的主线——这可能没问题,不仅对你,对其他人也是如此。如果获得您的提交(您的历史记录)的其他人尚未依赖并建立在这些提交上,那没关系。如果他们根据,建设,这些提交,它可能仍然是确定:都是这些其他同事或同事确定与重做自己的工作,你改写自己的历史后?

如果这一切都是真的——如果没有其他人依赖你的历史,或者所有依赖它的人都愿意做更多的工作,以便他们能够处理你对历史的重写——那么你要做的是清除:删除从您的狐步舞的合并master。这需要仔细使用git reset,并了解 Git 分支如何真正工作、做什么git merge以及分支名称如何不是关键。关键是提交图

进行新的提交会添加到图表中,并更新您“在”上的任何分支名称——在某种意义上git status说“在分支 ___”——以便该分支名称标识新的提交。新提交的母公司奇异的,在大多数的情况下提交,是犯那之前的分支的末端。如果新提交的是一个合并提交,新提交的父母,复数,是犯下这该分支的前尖(像往常一样),然后,作为第二父母的时候,你要合并说你指定的提交。

也就是说,Git 中的一个分支只是一个提交链:

... <-F <-G <-H   <--master
Run Code Online (Sandbox Code Playgroud)

这个名字 master记住了一个散列 ID,在这种情况下,H(H代表实际的散列 ID,它是一个 160 位数字的十六进制表示的大而丑陋的字符串,它看起来是随机的,虽然它不是)。提交H是分支上的最后一次提交。Git 使用哈希 ID inmaster来查找实际提交。CommitH本身包含,即记住,GGit 用来查找 commit的父哈希 ID G。CommitG记住它的父级F;Git 使用此哈希 ID 来查找实际提交F。这个过程重复,Git 向后遍历链,一次一个提交,以找到所有“开启”的提交——更准确地说,可以从——分支名称。

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

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

... <-F <-G <-H <-I   <--master
Run Code Online (Sandbox Code Playgroud)

这就是分支的生长方式。

当你使用git reset(以正确的方式)时,你告诉 Git: Changemaster以便它不是指向我的新提交I,而是指向回H CommitI实际上并没有消失:它仍然存在,就像漂浮在太空中一样。但是如果它master是你唯一的名字,那么现在很难找到它的哈希 ID。(?你有这记忆:-))现在,而不是master指向II指向H现在您有:

             I
            /
...--F--G--H   <-- master
Run Code Online (Sandbox Code Playgroud)

这也是您摆脱狐步舞合并的方法。假设你开始于:

...--F--G--H   <-- master
Run Code Online (Sandbox Code Playgroud)

其他人添加了他们的新内容IJ承诺他们的 master(你git fetch记得是你的origin/master):

...--F--G--H   <-- master
            \
             I--J   <-- origin/master
Run Code Online (Sandbox Code Playgroud)

你向你的主人添加一个新的提交,甚至可能是一整串,也许是通过合并你自己的feature/tall

             K--L   <-- feature/tall
            /    \
...--F--G--H------M   <-- master
            \
             I--J   <-- origin/master
Run Code Online (Sandbox Code Playgroud)

在这里,您的合并提交MH作为其第一个父项(“主线”)共享,而您的提交已L作为其第二个父项(您的功能)共享。然后你添加一个新的提交N,使他们的J,他们的master,是你的origin/master,进入一个分支,因为你M是你的主线:

             K--L   <-- feature/tall
            /    \
...--F--G--H------M--N   <-- master
            \       /
             I-----J   <-- origin/master
Run Code Online (Sandbox Code Playgroud)

他们J现在是一个侧枝,就像你的feature/tall,因为线路运行NMHGF,...,沿第一父母的主线-序列直背。

如果您想将主线视为返回通过J,则必须完全消除您的合并M。这需要再次强调你的master观点H。你可以这样做:

git checkout master
git reset --hard <hash-of-H>
Run Code Online (Sandbox Code Playgroud)

然后我们可以(杂乱地)将其绘制为:

               L   <-- feature/tall
              / \
             K ,-M-----N
            /_/       /
...--F--G--H   <-------- master
            \       /
             I-----J   <-- origin/master
Run Code Online (Sandbox Code Playgroud)

请注意,所有提交都还在那里——仍然像以前N一样回到MJ,并且M仍然像以前一样回到两者HL之前——但是没有导致 的名称N因此无法找到NM。因此,我们可以将它们从图中删除:

             K--L   <-- feature/tall
            /
...--F--G--H   <-- master
            \
             I--J   <-- origin/master
Run Code Online (Sandbox Code Playgroud)

现在您需要做的就是将您的master前后滑动到J,您可以使用git merge --ff-only origin/master

             K--L   <-- feature/tall
            /
...--F--G--H
            \
             I--J   <-- master, origin/master
Run Code Online (Sandbox Code Playgroud)

我们现在可以更轻松地重绘:

             K--L   <-- feature/tall
            /
...--F--G--H--I--J   <-- master, origin/master
Run Code Online (Sandbox Code Playgroud)

您现在已准备好发出拉取请求,即其他git merge人为您运行的请求,在该请求中您提议进行新的合并——M如果我们愿意,我们可以再次调用它——它将作为它的第一个父级 commit J,并且作为它的第二个父级, commit L:一个非狐步合并将主线称为“主线”而您的功能称为“功能”。

这东西有点困难。理解它的技巧是提交哈希 ID是通用的:它们是全局唯一的,并且每个获取您提交的存储库都通过它们的哈希 ID 获取它们。你的 Git、Joe 的 Git、Katherine 的 Git、Larry 的 Git 等等,都同意 commitH是 commit H。它从来没有任何其他哈希 ID。但是名字你的Git使用,您的分支名称,是你的。它们不需要出现在任何其他存储库中。他们使用的名称——他们的 master他们的 develop等等——将在你的Git 中显示为你的 origin/masterorigin/develop, 等等。跑步:

git fetch
Run Code Online (Sandbox Code Playgroud)

让你的 Git 调用他们的 Git,获取任何新的提交——一如既往地通过哈希 ID——然后根据他们的名字更新 名字。这是可以吸引他们的提交和更新远程跟踪的名字,你的。origin/*fetchorigin/*

当你运行git merge --no-ff,或者让 Bitbucket 或 GitHub 为你做这件事时,会创建一个新的提交——它会自动获得一个新的、唯一的哈希 ID——并且是新的合并提交记录第一个父级——“主线”——和第二个父级,“特性,全部由它们的哈希 ID 决定。任何名称,无论是像您的分支名称master还是像远程跟踪的名称origin/master,一旦您实际拥有并使用其唯一的哈希 ID保留提交,就变得无关紧要。

换句话说:名称查找提交。只有提交才真正重要。名称仅在它们找到提交时、何时以及因为它们找到提交时才重要。

(另请参阅如何避免在 git 中进行 foxtrot 合并。尤其是注释。)