针对特定文件的Git合并策略,具体取决于变基/合并

时间:2018-07-11 08:37:01

标签: git maven merge git-merge git-rebase

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

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

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

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

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

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

1 个答案:

答案 0 :(得分:2)

的确,在重新定级期间您将需要“他们的”。这是因为rebase操作实际上是一系列的Cherry-pick,而每个Cherry-pick是一个合并操作,其中HEAD(当前提交)在 target分支上(正在构建) ),而不是指向原始分支(现在正在复制)上的提交。

也就是说,普通合并看起来像这样:

...--o--o--*--o--o    <-- yourbranch (HEAD)
            \
             o--o--o   <-- theirbranch

您运行git merge theirbranch; Git将提交*(合并基础)与您的最终提交进行比较,以查看您的所作所为,然后将*与他们的最终提交进行比较,以查看其所做的事情。然后,Git合并这些更改,并将其全部应用于*,以产生合并:

...--o--o--*--o--o---M    <-- yourbranch (HEAD)
            \       /
             o--o--o   <-- theirbranch

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

但是,当您变基时,您将从以下内容开始:

...--o--o--*--o--o   <-- theirbranch
            \
             A--B--C   <-- yourbranch (HEAD)

您运行git rebase theirbranch,并且Git查找自*以来的提交(这些是您上面的ABC提交)并列出了它们将ID散列到一个临时文件中。 (如果使用交互式变基,您将看到一系列使用这些哈希ID的pick命令。)现在,变基具有ID,它首先通过检出它们的分支来开始实际工作。 ,作为独立的HEAD:

...--o--o--*--o--o   <-- theirbranch, HEAD
            \
             A--B--C   <-- yourbranch

Git然后运行所需的git cherry-pick个调用以复制所有提交,在这种情况下,其中三个。每个cherry-pick是一种特殊的合并,无需进行合并样式的提交即可执行合并操作。合并的结果是精心挑选的提交副本。因此,第一次合并将像以前一样以*作为合并基础,以HEAD提交作为当前提交,并以A作为“其”提交进行合并!

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

假设A复制成功,您现在处于这种状态:

                   A'   <-- HEAD
                  /
...--o--o--*--o--o   <-- theirbranch
            \
             A--B--C   <-- yourbranch

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

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

                   A'-B'-C'   <-- HEAD
                  /
...--o--o--*--o--o   <-- theirbranch
            \
             A--B--C   <-- yourbranch

并且Git现在通过将名称yourbranch从提交C上剥离下来并将其粘贴到最后一个副本C'上来完成重新基准化,在过程中重新附加HEAD:

                   A'-B'-C'   <-- yourbranch (HEAD)
                  /
...--o--o--*--o--o   <-- theirbranch
            \
             A--B--C   [no longer needed]

巨大的警告

这种使用.gitattributes控制使用哪个.mvn/maven.config文件的特殊想法从一开始就注定要失败,原因是:Git进行合并时,Git首先查找在三个提交(合并库,我们的库和他们的库)中的每个文件的原始哈希ID 中。这里总共有5种可能性:

  • 所有三个哈希ID都相同:合并的文件是基础文件,即它们的文件和我们的文件。此时一切都很繁琐:您甚至不需要合并驱动程序!

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

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

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

  • 最后,基础文件与我们的文件不同,我们的文件也与它们不同:Git使用您的合并驱动程序。您的合并驱动程序成功!好吧,只要您确定想要哪个版本(“我们的”或“他们的”),它就可以执行。

在列表中,您将看到.gitattributes驱动程序仅在五种可能情况中的一种起作用。在另外两种情况下不需要。在忽略的五分之二中需要 !因此,在两种(总共五种)情况下,当您希望使用合并驱动程序时将不使用它们。