合并错误。我该如何解决?

时间:2017-01-11 08:05:13

标签: git merge

我们的仓库中有两个分支,release_1.18feature/remove-duplicate-media

feature/remove-duplicate-media ---> release_1.18的拉取请求包含冲突。负责该功能的开发人员将release_1.18合并回他的功能分支以解决它们(到目前为止很正常)。

History

但是,在这次合并之后,他以某种方式(我们无法弄清楚如何)抛弃了release_1.18中的所有更改,并且只提交了导致冲突的两个文件。

现在,Pull Request feature/remove-duplicate-media ---> release_1.18包含两个分支之间所有更改的所有OPPOSITE。因此,release_1.18中添加的文件现已删除。

我们如何解决这个问题?再次合并release_1.18将无济于事,因为git认为(这在技术上是正确的)已经完成了,并且没有什么可做的。

2 个答案:

答案 0 :(得分:2)

您的意思是从<a href='http://www.domain.com/changepassword.php?user_id=$User_id1'>Create your password here</a> feature/remove-duplicate-media的合并错误合并。

release_1.18

所以你可以通过以下方式删除这个合并:

  A---B---C         release_1.18
 /         \
D---E---F---G       feature/remove-duplicate-media

现在两个分支都将保持状态,就像合并之前一样。然后你可以再次合并。

答案 1 :(得分:1)

TL; DR:无论什么

,我们都会重复合并

Marina - MSFT's answer - 完全放弃合并 - 是一个可能的答案,只有两个可能的答案。

这是因为,正如您在问题中所指出的那样,您无法获得Git to&#34; redo&#34;直接合并,因为它已经在历史中。更确切地说,错误的合并历史。这意味着要 ditch (丢弃)错误合并,您必须重写历史记录。仍然,&#34;抛弃糟糕的合并&#34;是一个可能的答案。

但也有两个部分也是你问题的最终答案。一个是: 您更喜欢哪种提交历史备选方案? 有两种方法:沟通并用良好的合并替换坏合并,或者添加修复提交。第二部分是: 如何获得源代码树,即工作树快照,与良好的合并或修复提交一起? 它&#39 ;第二个问题更难(除非你选择&#34;用合并替换错误的合并&#34;方法并且愿意花一些时间去做)。让我们看看我们是如何到达那里的。

备选方案1:用良好的合并替换坏合并

由于当前的任何内容都不依赖于错误的合并,并且#34;抛弃坏的合并&#34;目前,这是一个相对简单的答案。但这确实意味着你必须让任何选择错误合并的人,跟随你的&#34;重置它,然后用一个好的合并替换它#&# 34;通过用替换来更新他们自己的克隆。

再次绘制它,这里是我们在此建议的图形表示:

...--o-------X   <-- feature/remove-duplicate-media
            /
...--o--o--o

(其中X是错误合并)变为:

...--o-----------G   <-- feature/remove-duplicate-media
            \   /
             X /
            /_/
...--o--o--o

即坏合并X不再有任何标签指向它(之后它最终被垃圾收集掉)。任何有git fetch错误合并X的人都会将他们的存储库中的文件作为remotes/origin/feature/remove-duplicate-media,但如果他们在进行新的提交之前又运行了另一个git fetch使用提交X,他们将获得良好的合并提交G,移动他们自己的remotes/origin/feature/remove-duplicate-media以指向良好提交G,他们会没事的。< / p>

备选方案2:添加&#34;修复&#34;提交

另一个可能的答案是在错误合并之后添加一个良好的提交(合并提交或普通的非合并提交,它赢得了&t; t真的很重要)。也就是说,我们添加了一个新的commit-let,而不是放弃提交X,而是将其调用R进行修复而不是G进行修复,只是为了区分它 - 它的快照(它的树),应该具有在提交X之后。假设我们将其作为普通提交,commit R的图形表示现在看起来像这样:

...--o-------X--R   <-- feature/remove-duplicate-media
            /
...--o--o--o

或者,我们可以将R本身作为合并提交,在这种情况下,图形表示如下所示:

...--o-------X--R   <-- feature/remove-duplicate-media
            /__/
...--o--o--o

R作为合并提交是否有充分的理由?不是真的:既不伤害也不帮助。这是一个关于您希望如何在git log输出中看到它的问题。真正的诀窍是:我们如何获得提交R

如何获取用于良好合并或修复提交的树

如果您git reset离开了错误提交X,则很容易看到如何获得良好的合并提交G:再次运行git merge,这次正确解析合并,并提交。

但是,如果您不想放弃提交X - 如果您想要或需要保留现有历史记录 - 您将如何获得用于修复提交R的相同类型的树?

答案几乎非常简单,一旦你意识到Git是如何工作的:你以与提交R相同的方式为修复提交G 创建本身,通过重复合并。显然你必须在没有错误提交X的分支上执行此操作,但这几乎非常容易搞笑!

让我们再次绘制G个案,但只需更改一次:让错误合并X到位,功能分支指向它。这一次,我还会标记另外两个提交,AB

...--A-----------G   <-- temp
            \   /
             X /   <-- feature/remove-duplicate-media
            /_/
...--o--o--B

我们如何获得此临时分支temp并进行此新合并G?简单:只需检查指向提交temp的新分支A,然后合并提交B。提交A是错误合并X的第一个父级,B是错误合并X的第二个父级,因此配方是:

$ git checkout -b temp feature/remove-duplicate-media^1
$ git merge feature/remove-duplicate-media^2

然后像以前一样解析并提交,我们有好的提交G,作为分支temp的提示。

现在我们只需要在分支G复制 R到修复提交feature/remove-duplicate-media。通常我们可能会使用git cherry-pick来复制提交,但这不适合。有两种方法可以使用常规的旧Git命令或使用管道命令git commit-tree进行复制。

管道命令实际上更容易,更灵活。它允许我们将G复制到普通的单父提交或新的合并提交。要制作R,我们准备一条日志消息:

$ cat > /tmp/log-msg
(write your log message here, ^D to exit cat)

或:

$ vim /tmp/log-msg

或者您想制作日志消息。现在在没有分支的情况下进行提交,就像悬挂的提交对象一样:

$ newid=$(git commit-tree -p feature/remove-duplicate-media \
>   -F /tmp/log-msg temp^{tree})

或:

$ newid=$(git commit-tree -p feature/remove-duplicate-media \
>    -p feature/remove-duplicate-media^2 \
>    -F /tmp/log-msg temp^{tree})

然后将分支feature/remove-duplicate-media快进到新提交:

$ git checkout feature/remove-duplicate-media
$ git merge --ff-only $newid

(注意:这可能会强制您删除一些当前未跟踪的文件,如果它们在更正的合并中被跟踪,尽管它有点不太可能)。

由于$newid的第一个父级 - 可能是其唯一的父级,取决于您在上面使用的命令 - 是feature/remove-duplicate-media的当前提示,因此合并将是快进的作为feature/remove-duplicate-media的提示,您现在拥有通过复制临时提交而进行的新提交。现在您可以删除临时提交的分支名称:

$ git branch -D temp

为了完整起见,如何使用普通的Git命令复制temp

如果您只想将提交R作为普通的单父提交,并希望使用&#34;普通&#34; Git命令,这是如何做到的:

$ git rev-parse --show-cdup

如果打印任意数量的&#34; ../" s,例如&#34; ../../../"或者某些这样的cd,许多../ - es,以便重新运行命令只打印一个空行。 (这里的想法是达到顶级。)或者:

$ cd $(git rev-parse --show-toplevel)

会做同样的事情。然后:

$ git checkout feature/remove-duplicate-media
$ git rm -rf .
$ git checkout -f temp -- .
$ git commit

第一个git checkout到达目标分支并填充索引和工作树。 git rm -rf .删除索引中的所有内容 - 字面上的所有内容 - 以及所有相应的工作树文件。第二个git checkout 从临时合并中重新填充索引和工作树,撤消git rm -rf .的效果(除了文件时间戳最终更新)。最终git commit提交结果。

如前所述,我们可以解决tempHEAD未跟踪的文件中的小问题。这是第二个-fgit checkout的用途。可能没有这样的文件,因此-f是不必要的。您可以将其保留,如果您点击此类文件,请手动将其删除(或隐藏它们)。

有一种类似的方法可以避免稍微可怕(和时间戳改变)git rm -rf .步骤,但它有点复杂。在首先删除当前提交中不在git checkout temp -- .提交中的任何文件之后,我们可以使用temp来更新所有内容,而不是删除所有内容:

$ git diff --no-renames --name-only --diff-filter=R -z HEAD temp | \
> xargs -0 git rm -rf --
$ git checkout -f temp -- .

(您可以在没有xargs的情况下执行此操作,但是您需要跳过-z并且可能会遇到包含嵌入式空白区域的文件名问题。请注意,如果文件名与temp提交中的目录名相对应,我们必须首先执行此删除。

和以前一样,一旦将临时合并复制到已提交的修复提交R,您就可以删除分支temp