我们有两个分支 - “主人”和“释放”
我们有一个文件,比如fileA
,我们希望在这两个分支上保留不同的版本。
但每一次,我们必须将'释放'合并为'主',我们怎样才能实现,'master'中的fileA
不会被分支'release'中的fileA
覆盖。
Pro Git描述了如何在“Merge Strategies”的8.2 Customizing Git — Git Attributes部分获得这种效果。
Merge Strategies
您还可以使用Git属性告诉Git对项目中的特定文件使用不同的合并策略。一个非常有用的选择是告诉Git在发生冲突时不尝试合并特定文件,而是将合并的一方用于其他人的。
如果项目中的分支已经分歧或是专门的,但是您希望能够将更改合并到其中,并且您希望忽略某些文件,这将非常有用。假设您有一个名为
database.xml
的数据库设置文件,该文件在两个分支中不同,并且您希望在其他分支中合并而不会弄乱数据库文件。您可以设置如下属性:database.xml merge=ours
然后定义一个虚拟
ours
合并策略:$ git config --global merge.ours.driver true
如果您合并到另一个分支,而不是与
database.xml
文件的合并冲突,您会看到如下所示:$ git merge topic Auto-merging database.xml Merge made by recursive.
在这种情况下,
database.xml
会保留您最初的版本。
将它应用于您的情况,首先创建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(-)
没有什么特别的事情发生了:版本控制只是按照它应该在这一点上工作。
现在,我们在master
上实现功能B.
$ 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
合并来自master
的特征B.
$ 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
“Defining a custom merge driver”中的gitattributes documentation部分解释道。
merge.*.driver
变量的值用于构造一个命令来运行以合并祖先的版本(%O
),当前版本(%A
)和其他分支的版本(%B
)。在构建命令行时,这三个标记将替换为保存这些版本内容的临时文件的名称...合并驱动程序应该通过覆盖它来将合并的结果留在以
%A
命名的文件中,如果它设法干净地合并它们,则退出为零状态,如果存在冲突则为非零。
自定义ours
驱动程序几乎不使用这种机器,只有true
command退出零状态。这实现了预期的效果,因为它从fileA
开始,从我们当前所在的分支开始 - 这是我们想要的结果 - 然后在合并覆盖阶段没有做任何事情(即,忽略由%B
命名的其他分支的版本),最后告诉git一切顺利,退出状态成功。
当你想将release分支合并到master时,在master之上的第一个rebase release分支。
这样你的历史就会有一个“干净”的历史。你将避免在树中的所有地方的分支,并得到一个简洁的提交行。
Rebase将把所有“新”内容带入您的主分支。如果更改有冲突,那么您可以忽略文件的“发布”版本(但要注意,如果您的其他文件需要更改),那么合并将没有冲突。
git checkout release
git rebase master
// deal with conflicts during rebase
git checkout -b release.tomerge
git checkout master
git merge release.tomerge