特定文件的 Git 合并策略取决于 rebase / merge

Fra*_*rot 1 git merge git-merge git-rebase maven

我正在寻找一种方法,使 git对特定文件使用特定的合并策略(我们的/他们的) ,具体取决于我是合并还是重新调整我的功能分支。

让我解释一下:假设我有一个功能分支“fb”,其中更改了文件“.mvn/maven.config”。如果我将 master 合并到“fb”中,我想保留我的文件,因此使用“我们的”策略(我可以在 .gitattributes 文件中定义它)。但是,如果我将“fb”重新设置为 master(而不是合并),我仍然想保留“fb”分支的“.mvn/maven.config”,所以我应该使用“他们的”策略,因为据我了解,merge 和 rebase 之间策略的含义是相反的。

问题是:有没有一种简单的方法来定义智能合并策略?

我已经看到了“git merge driver”的概念,但据我所知,合并驱动程序无法判断它是合并还是变基,因此无法推断是否使用我们的 VS 他们的。

我是否必须告诉我的队友没有解决方案,迫使他们每次都小心谨慎,手动手动选择合适的策略?

注意:我添加了“maven”标签,因为任何使用 git 和 maven 的人在保留 .mvn/maven.config 文件时可能会遇到同样的问题

tor*_*rek 5

确实,在变基期间您需要“他们的”。这是因为变基操作实际上是一系列的cherry-pick,并且每个cherry-pick都是一个合并操作,其中您的HEAD(当前提交)位于目标分支(正在构建)上,而不是指向原始分支上的提交(现在正在复制)。

\n\n

也就是说,正常的合并如下所示:

\n\n
...--o--o--*--o--o    <-- yourbranch (HEAD)\n            \\\n             o--o--o   <-- theirbranch\n
Run Code Online (Sandbox Code Playgroud)\n\n

你跑git merge theirbranch; Git 将提交*\xe2\x80\x94 合并基 \xe2\x80\x94 与您的最终提交进行比较,以了解您做了什么,然后*与它们的最终提交进行比较,以了解它们做了什么。然后 Git 组合这些更改,将它们全部应用到*,以生成合并:

\n\n
...--o--o--*--o--o---M    <-- yourbranch (HEAD)\n            \\       /\n             o--o--o   <-- theirbranch\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果您提供了.gitattributes定义的合并驱动程序,则可以让 Git 获取您的.mvn/maven.config\xe2\x80\x94 版本,但这里有一个巨大的警告;见下文。

\n\n

然而,当你变基时,你会从以下开始:

\n\n
...--o--o--*--o--o   <-- theirbranch\n            \\\n             A--B--C   <-- yourbranch (HEAD)\n
Run Code Online (Sandbox Code Playgroud)\n\n

您运行,Git 会找到自\xe2\x80\x94git rebase theirbranch以来的提交,这些是您的, , 并在上面\xe2\x80\x94 上提交,并将它们的哈希 ID 列出到临时文件中。(如果您使用交互式 rebase,您将看到一系列使用这些哈希 ID 的命令。)现在 rebase 有了 ID,它首先检查它们的分支(作为分离的 HEAD)来开始真正的工作:*ABCpick

\n\n
...--o--o--*--o--o   <-- theirbranch, HEAD\n            \\\n             A--B--C   <-- yourbranch\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后,Git 根据需要运行尽可能多的git cherry-pick调用来复制所有提交\xe2\x80\x94(在本例中为三个)。每个cherry-pick都是一种特殊的合并,执行合并操作而不进行合并式提交。合并的结果是精心挑选的提交的副本。因此,第一次合并*像以前一样作为合并基础进行操作,HEAD一如既往地将提交作为当前提交,并将提交A作为要合并的“他们的”提交!

\n\n

因此,在这种情况下,您希望自定义.gitattributes驱动程序采用“他们的”版本.mvn/maven.config,因为“他们的”版本(在 commit 中A)实际上是您的版本。不过,我之前提到的那个巨大警告现在变得更大了!

\n\n

假设A复制成功,你现在处于这样的状态:

\n\n
                   A\'   <-- HEAD\n                  /\n...--o--o--*--o--o   <-- theirbranch\n            \\\n             A--B--C   <-- yourbranch\n
Run Code Online (Sandbox Code Playgroud)\n\n

Git 现在运行第二次cherry-pick,这意味着第二次合并操作:这次的合并基础是 commit A;你的HEAD提交是你自己的副本A\';而“他们的”提交就是您的提交B。现在,只要您在第一个选择中选择了正确的一个, 可以安全地选择其中一个。.mvn/maven.config

\n\n

rebase 也会在提交时重复此操作C,以构建C\'在 之上B\'。这次的合并基础将是 commit B。与复制 commit 的过程一样B,您可以在这里使用其中之一.mvn/maven.config。完成此副本后,您将拥有:

\n\n
                   A\'-B\'-C\'   <-- HEAD\n                  /\n...--o--o--*--o--o   <-- theirbranch\n            \\\n             A--B--C   <-- yourbranch\n
Run Code Online (Sandbox Code Playgroud)\n\n

yourbranch现在,Git 通过从commit 中剥离名称C并将其粘贴到最后一个副本上来完成变基C\',并在此过程中重新附加您的 HEAD:

\n\n
                   A\'-B\'-C\'   <-- yourbranch (HEAD)\n                  /\n...--o--o--*--o--o   <-- theirbranch\n            \\\n             A--B--C   [no longer needed]\n
Run Code Online (Sandbox Code Playgroud)\n\n

巨大的警告

\n\n

.gitattributes这种使用来控制使用哪个文件的特殊想法.mvn/maven.config,至少部分地从一开始就因为不同的原因而注定要失败:当 Git 进行合并时,Git 首先查看三个文件中每个文件的原始哈希 ID。提交(合并基地、我们的和他们的)。这里一共有5种可能:

\n\n
    \n
  • 所有三个哈希ID都是相同的:合并的文件是基础文件,这是他们的文件和我们的文件。此时一切都非常美妙:您甚至不需要合并驱动程序!

  • \n
  • 基本文件与他们的相同,但与我们的不同:Git 只获取我们的文件。Git 完全忽略你的合并驱动程序。使用合并驱动程序的想法失败了(好吧,除非您想要“我们的”,但即使没有合并驱动程序也会发生这种情况)。

  • \n
  • 基本文件与我们的相同,但与他们的不同:Git 只是获取他们的文件。Git 完全忽略你的合并驱动程序。与前面的情况一样,使用合并驱动程序的想法失败了。

  • \n
  • 基本文件与我们或他们的不同,但我们和他们的相同:Git 只是获取我们的文件(它已经就位,因此对 Git 来说更容易)。Git 完全忽略你的合并驱动程序。这对于我们的情况来说是可以的,因为我们双方(我们的和他们的)都做了相同的更改,但是要保留基本版本的合并驱动程序在这里会失败。

  • \n
  • 最后,基本文件与我们的不同,我们的也与他们的不同:Git 使用您的合并驱动程序。您的合并驱动程序成功了!好吧,只要你弄清楚你想要哪个版本(“我们的”或“他们的”)就可以了。

  • \n
\n\n

浏览该列表,您会发现您的.gitattributes驱动程序仅在五种可能情况中的一种情况下工作。另外两种情况不需要它。在被忽略的五个中,有两个需要它的!因此,当您希望使用合并驱动程序时,有两种(总共五种)情况不会使用您的合并驱动程序。

\n