Git 在 Sourcetree 中合并不会获取所有提交的文件并弄乱工作副本

Git merge in Sourcetree doesn´t take all committed files and messes up working copy

我无法解决以下问题。

我们有 2 名编码员在同一个项目上工作。

有 1 个我们都推送的主分支。

在合并中没有您在下图中看到的 5 个提交:

过去合并考虑了紫色分支中提交的所有文件。

现在不同的是,我们第一次合并冲突时我们都接触过一个文件。

合并后Git似乎没有考虑下图中紫色分支的任何文件:

我的队友决定让他的 AppModel.php 覆盖以解决冲突。

现在我们不知道为什么 Git 没有像往常一样工作,甚至不知道如何 redo/retry 合并。

感谢您的宝贵时间和帮助:)

这位:

My teammate decided to let his AppModel.php overwrite to get the conflict solved.

几乎可以肯定是全部问题。

我在下面写了一篇关于 git merge 的解释,解释了为什么(几乎可以肯定)这是整个问题以及你应该如何进行合并,但现在你需要做的,因为这些提交已发布,1 只是将您自己的更改重新插入为新提交,例如,您可以通过 git cherry-pick 来完成。您在挑选时会遇到一个或多个合并冲突,您可以通过正确的方式解决(而不是只采用整个文件的一个或另一个版本)。

我不使用这些工具的大多数 GUI 版本,因此以下假设您使用的是命令行。

要挑选您之前的提交(以便 "replay" 它们),您需要为每个提交命名。一种方法是使用原始 SHA-1 ID,上面没有显示——我可以看到一个,fa434c6e39,但看不到其余的——但是如果你把它们放在你面前(在 window,写下来,随便),如果它们只是 12, 3,4, and5`(显然它们不是,它们很长40 个字符的字符串):

$ git cherry-pick 1
$ git cherry-pick 2
...
$ git cherry-pick 5

将它们带入。或者您可以将其合并为一个命令:

$ git cherry-pick 1 2 3 4 5

不过,还有另一种更具象征意义的命名方式,使用 gitrevisions 语法:

$ git cherry-pick master^2~5..master^2

甚至不需要查找原始 SHA-1 ID。此方法的一个缺点是这些名称 相对于 指向 master 的位置,因此这假定 master 当前指向错误的合并。这里 master^2 是错误合并的第二个父级,这是您最近的合并前提交。从这次提交开始,我们退回 5 步,然后使用 .. 语法,然后再次 select 那个特定的提交。因此,图表的范围 selected 是您所做的 5 次提交。

(请注意,我们在这里依赖于您恰好进行了 5 次提交的事实,但我们可以在上面的图形显示中看到它们——两个改进和三个错误修复,所以我们知道这是正确的。)

每个 cherry-pick 指示 git 找到您在该提交中更改的内容,现在只需再次执行:在特定提交与其父提交之间进行差异,然后立即重新应用该差异.


1有一个替代方案:你可以重置("remove")坏的合并,用好的合并替换它,然后"force-push" 结果。但是,如果 这样做,那么 已经选择了错误合并的其他人 必须从 public 中选择你的更改存储库,并将他们他们所做的任何后续更改移动到新的更正合并中。如果 "everyone else" 只是另一个做出错误合并的人,这实际上可能是处理问题的更好方法。但是如果你这样做了,确保他知道你在做这件事,否则他可能只会恢复错误的合并。他还需要删除 他的 错误合并副本!

未发布提交的情况下——例如,如果你做了一个合并,然后在测试结果时,你发现合并是错误的——你可以这样做这 "remove the bad merge and retry" 东西(或使用 git commit --amend)安全。删除已发布的提交之所以不好,恰恰是因为它会为其他选择已发布提交的人做更多的工作。如果提交未发布,则没有其他人拥有它,因此您不会为其他人做更多的工作。


合并如何工作,以及为什么会出错

当你要求git合并两条开发线时,比如这样:

*    Neue Funktion: Mediathe...
| *  IMPROVEMENT: Pins der K...
| *  IMPROVEMENT: Mailsedung...
| *  BUGFIX: Bewerten und An...
| *  BUGFIX: Anfrage-Buttons...
| *  BUGFIX: Anfrage-Buttons...
|/
*    BUGFIX: Anfrage löschen...

它首先确定 "merge common base",即两条线的分叉点。在这种情况下,这是 BUGFIX: Anfrage löschen geht nicht 提交。

接下来,git 执行两个 git diff。一种是从公共基到当前分支的尖端:在本例中,从 Anfrage löschen...Neue Funktion: Mediathe...。这些是自基地以来的 "your" 变化。 (请记住,在这种情况下,"you" 是另一个人,即执行错误合并的人。)第二个差异是从公共基础到待合并分支的尖端:在这种情况下,从 Anfrage löschen...Pins der Karte...。这些是 "his" 变化。

(自己尝试:找到合并基础的提交 ID,然后 运行 git diff <commit-ID-of-base> <other-commit-ID>。对要合并的两个提交中的每一个都执行此操作。)

最后,git 看看这两个差异。无论您在哪里做了他们没有做的更改,git 都会接受您的更改。只要他们做了您没有做的更改,git 就会接受他们的更改。如果您和他们更改了 相同 文件的 相同 行,git 声明一个 "conflict".

在发生冲突的情况下,git 写入包含 两组更改 的文件(并且,可选地,从基础:要查看这些行,请在 git 配置中设置 merge.conflictstyle = diff3 选项。)然后它要求您(用户)编辑文件和 select 正确 个更改,以可能的更改为准。

如果您只是使用您(或他们)的文件版本,git 假设您查看并决定不再需要他们(或您的)更改。

另请注意,当 git 认为不存在冲突时,并不意味着合并结果是正确的。这只是意味着您所做的是更改文件中的行或他们没有触及的位置。例如,假设您的软件有一个错误,可以通过两种方式中的一种(但不是两种)修复,即向函数 f1 添加一行,或从函数 f2 中删除一行。进一步假设您执行了 remove-from-f2 而他们执行了 add-to-f1。 Git 将比较您的两次更改,看看他们更改了您单独留下的内容,而您更改了他们单独留下的内容,然后进行 both 更改。这会产生一个新的不同的错误 — 但就 git 而言,这是合并的正确方法。