Git - 两个分支上同一个文件有不同版本,合并时不想覆盖其中一个版本

26
我们有两个分支 -- 'master' 和 'release'
还有一个文件,比如说 fileA,我们想要在这两个分支上保留不同的版本。
但每次我们都要将 'release' 合并到 'master',我们该如何做才能使 'master' 中的 fileA 不会被分支 'release' 中的 fileA 覆盖?

可能已经在这里得到了答案:(https://dev59.com/Zm865IYBdhLWcg3wU9CI) - halafi
1个回答

19

Pro Git8.2自定义Git——Git属性“合并策略”部分描述了如何实现这种效果。

Merge Strategies

You can also use Git attributes to tell Git to use different merge strategies for specific files in your project. One very useful option is to tell Git to not try to merge specific files when they have conflicts, but rather to use your side of the merge over someone else’s.

This is helpful if a branch in your project has diverged or is specialized, but you want to be able to merge changes back in from it, and you want to ignore certain files. Say you have a database settings file called database.xml that is different in two branches, and you want to merge in your other branch without messing up the database file. You can set up an attribute like this:

database.xml merge=ours

And then define a dummy ours merge strategy with:

$ git config --global merge.ours.driver true

If you merge in the other branch, instead of having merge conflicts with the database.xml file, you see something like this:

$ git merge topic
Auto-merging database.xml
Merge made by recursive.

In this case, database.xml stays at whatever version you originally had.

应用到你的情况中,首先创建fileA
$ echo 'master fileA' > fileA
$ git add fileA ; git commit -m "master fileA"
[master (root-commit) fba9f1a] master fileA
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 fileA

使它特殊。

$ echo fileA merge=ours > .gitattributes
$ git add .gitattributes ; git commit -m 'fileA merge=ours'
[master 98e056f] fileA merge=ours
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 .gitattributes
$ git config --global merge.ours.driver true

现在我们创建一个代表性的release分支。
$ git checkout -b release
Switched to a new branch 'release'
$ echo 'release fileA' > fileA
$ git add fileA ; git commit -m 'release fileA'
[release 53f3564] release fileA
 1 files changed, 1 insertions(+), 1 deletions(-)

目前还没有发生什么特别的事情:版本控制只是按照预期工作。

现在,我们将功能B实现到master上。

$ git checkout master
Switched to branch 'master'
$ touch featureB ; echo 'With Feature B' >> fileA
$ git add featureB fileA ; git commit -m 'Feature B'
[master 443030f] Feature B
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 featureB

请保持冷静。

这里是我们特殊的合并驱动器发挥作用的地方。我们的英雄想要将来自master的新代码合并到release中。首先切换分支。

$ git checkout release
Switched to branch 'release'

验证一下fileA是否包含我们期望的内容。

$ cat fileA
release fileA

合并 Feature Bmaster
$ git merge master
Auto-merging fileA
Merge made by recursive.
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 featureB

Auto-merging fileA 是一种特殊情况的暗示。确切地说:

$ cat fileA
release fileA

如何运作

gitattributes文档中的“定义自定义合并驱动程序”部分解释了。

merge.*.driver变量的值用于构建一个命令,以合并祖先版本(%O)、当前版本(%A)和其他分支版本(%B)。当构建命令行时,这三个标记将被替换为保存这些版本内容的临时文件的名称...

期望合并驱动程序通过覆盖名为%A的文件来保留合并结果,并在成功合并时退出零状态或在存在冲突时退出非零状态。

自定义ours驱动程序几乎不使用此机制,只使用true命令以退出零状态。这样做可以达到所需的效果,因为它从我们当前所在的任何分支的fileA开始 - 这是我们想要的结果 - 然后在合并覆盖阶段(,忽略由%B指定的其他分支版本),最后告诉git一切都很好,成功退出状态。


感谢您精彩的解释,这正是我一直在寻找的,您拯救了我的一天 @GregBacon - Chirag Chhuchha
@ChiragKhatri 不用谢!我很高兴我的回答有所帮助。 - Greg Bacon
.gitattributes 用于设置合并策略,但某些 Git 主机(例如 Azure DevOps Repos)仍不支持它,因此当您打开 PR 时,仍会出现合并冲突,因为服务器不使用 .gitattributes 进行合并 :/ - geominded

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接