我如何告诉 git 总是选择我的本地版本来合并特定文件上的冲突?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/928646/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I tell git to always select my local version for conflicted merges on a specific file?
提问by saffsd
Say I'm collaborating with someone via a git repository, and there is a particular file that I never want to accept any external changes to.
假设我正在通过 git 存储库与某人合作,并且有一个特定的文件,我不想接受任何外部更改。
Is there any way for me to set up my local repo to not complain about a conflicted merge every time I git pull? I'd like to always select my local version when merging this file.
有什么方法可以让我设置本地存储库,以免每次 git pull 时都抱怨合并冲突?我想在合并这个文件时总是选择我的本地版本。
回答by VonC
On the specific instance of a config file, I would agree with Ron's answer:
a config should be "private" to your workspace (hence "ignored", as in "declared in a .gitignore
file").
You may have a config file templatewith tokenized valuesin it, and a script transforming that config.template
file into a private (and ignored) config file.
在配置文件的特定实例上,我同意Ron 的回答:
配置应该对您的工作区“私有”(因此“忽略”,如“在.gitignore
文件中声明”)。
您可能有一个包含标记化值的配置文件模板,以及一个将该文件转换为私有(并被忽略)的配置文件的脚本。config.template
However, that specific remark does not answer what is a broader more general question, i.e. your question(!):
但是,该特定评论并没有回答更广泛更普遍的问题,即您的问题(!):
How do I tell git to always select my local version for conflicted merges on a specific file ?(for any file or group of file)
我如何告诉 git 总是为特定文件上的冲突合并选择我的本地版本?(对于任何文件或文件组)
This kind of merge is a "copy merge", in which you will always copy 'ours' or 'theirs' version of a file whenever there is a conflict.
这种合并是“复制合并”,在这种合并中,只要出现冲突,您将始终复制文件的“我们的”或“他们的”版本。
(as Brian Vandenbergnotes in the comments, '
ours
' and 'theirs
' are here used for a merge.
They are reversedfor a rebase: see "Why is the meaning of “ours” and “theirs” reversed with git-svn
", which uses a rebase, "git rebase
, keeping track of 'local' and 'remote'")
(如布赖恩·范登堡笔记中的注释,“
ours
”和“theirs
”在这里用于合并。
它们是颠倒的底垫:看“Why is the meaning of “ours” and “theirs” reversed with git-svn
”,它采用了变基“git rebase
随时追踪‘本地’和‘远程’” )
For "a file" (a file in general, not speaking of a "config" file, since it is a bad example), you would achieve that with a custom script called through merges.
Git will call that script because you will have define a gitattributesvalue, which defines a custom merge driver.
对于“文件”(一般来说是一个文件,而不是“配置”文件,因为它是一个不好的例子),您可以使用通过合并调用的自定义脚本来实现。
Git 将调用该脚本,因为您将定义一个gitattributes值,该值定义了一个自定义合并驱动程序。
The "custom merge driver" is, in this case, a very simple script which basically will keep unchanged the current version, hence allowing you to always select your local version.
在这种情况下,“自定义合并驱动程序”是一个非常简单的脚本,它基本上将保持当前版本不变,因此允许您始终选择本地版本。
echo 'path/to/file merge=ours' >> .gitattributes
git config --global merge.ours.driver true
Let's test that in a simple scenario, with a msysgit 1.6.3 on Windows, in a mere DOS session:
让我们在一个简单的场景中测试一下,在 Windows 上使用 msysgit 1.6.3,在一个 DOS 会话中:
cd f:\prog\git\test
mkdir copyMerge\dirWithConflicts
mkdir copyMerge\dirWithCopyMerge
cd copyMerge
git init
Initialized empty Git repository in F:/prog/git/test/copyMerge/.git/
Now, let's make two files, which will both have conflicts, but which will be merged differently.
现在,让我们制作两个文件,它们都会有冲突,但会以不同的方式合并。
echo a > dirWithConflicts\a.txt
echo b > dirWithCopyMerge\b.txt
git add -A
git commit -m "first commit with 2 directories and 2 files"
[master (root-commit) 0adaf8e] first commit with 2 directories and 2 files
We will introduce a "conflict" in the content of both those files in two different git branches:
我们将在两个不同的 git 分支中的这两个文件的内容中引入“冲突”:
git checkout -b myBranch
Switched to a new branch 'myBranch'
echo myLineForA >> dirWithConflicts\a.txt
echo myLineForB >> dirWithCopyMerge\b.txt
git add -A
git commit -m "add modification in myBranch"
[myBranch 97eac61] add modification in myBranch
git checkout master
Switched to branch 'master'
git checkout -b hisBranch
Switched to a new branch 'hisBranch'
echo hisLineForA >> dirWithConflicts\a.txt
echo hisLineForB >> dirWithCopyMerge\b.txt
git add -A
git commit -m "add modification in hisBranch"
[hisBranch 658c31c] add modification in hisBranch
Now, let's try to merge "hisBranch" upon "myBranch", with:
现在,让我们尝试将“hisBranch”合并到“myBranch”上:
- manual resolution for conflicting merges
- exceptfor
dirWithCopyMerge\b.txt
where I always want to keep myversion ofb.txt
.
- 手动解决冲突合并
- 除外的
dirWithCopyMerge\b.txt
,我一直想保持我的版本b.txt
。
Since the merge occurs in 'MyBranch
', we will switch back to it, and add the 'gitattributes
' directives which will customize the merge behavior.
由于合并发生在 ' MyBranch
',我们将切换回它,并添加gitattributes
将自定义合并行为的 ' ' 指令。
git checkout myBranch
Switched to branch 'myBranch'
echo b.txt merge=keepMine > dirWithCopyMerge\.gitattributes
git config merge.keepMine.name "always keep mine during merge"
git config merge.keepMine.driver "keepMine.sh %O %A %B"
git add -A
git commit -m "prepare myBranch with .gitattributes merge strategy"
[myBranch ec202aa] prepare myBranch with .gitattributes merge strategy
We have a .gitattributes
file defined in the dirWithCopyMerge
directory (defined only in the branch where the merge will occurs: myBranch
), and we have a .git\config
file which now contains a merge driver.
我们.gitattributes
在dirWithCopyMerge
目录中定义了一个文件(仅在合并将发生的分支中定义:)myBranch
,我们有一个.git\config
文件,现在包含一个合并驱动程序。
[merge "keepMine"]
name = always keep mine during merge
driver = keepMine.sh %O %A %B
If you do not yet define keepMine.sh, and launch the merge anyway, here is what you get.
如果您还没有定义 keepMine.sh,并且无论如何都要启动合并,这就是您所得到的。
git merge hisBranch
sh: keepMine.sh: command not found
fatal: Failed to execute internal merge
git st
# On branch myBranch
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: dirWithConflicts/a.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
type dirWithConflicts\a.txt
a
<<<<<<< HEAD:dirWithConflicts/a.txt
myLineForA
=======
hisLineForA
>>>>>>> hisBranch:dirWithConflicts/a.txt
That is fine:
那没关系:
a.txt
is ready to be merged and has conflict in itb.txt
is still untouched, since the merge driver is supposed to take care of it (due to the directive in the.gitattributes
file in its directory).
a.txt
已准备好合并并存在冲突b.txt
仍然保持不变,因为合并驱动程序应该处理它(由于.gitattributes
其目录中文件中的指令)。
Define a keepMine.sh
anywhere in your %PATH%
(or $PATH
for our Unix friend. I do both of course: I have an Ubuntu session in a VirtualBox session)
定义keepMine.sh
你的任何地方%PATH%
(或$PATH
我们的Unix的朋友我当然都:我有一个VirtualBox的会话的会话的Ubuntu)
As commentedby lrkwz, and described in the "Merge Strategies" section of Customizing Git - Git Attributes, you can replace the shell script with the shell command true
.
正如lrkwz所评论的以及自定义 Git-Git 属性的“合并策略”部分所述,您可以用 shell 命令替换 shell 脚本。true
git config merge.keepMine.driver true
But in the general case, you can define a script file:
但一般情况下,你可以定义一个脚本文件:
keepMine.sh
保持我的.sh
# I want to keep MY version when there is a conflict
# Nothing to do: %A (the second parameter) already contains my version
# Just indicate the merge has been successfully "resolved" with the exit status
exit 0
(that was one simple merge driver ;) (Even simpler in that case, use true
)
(If you wanted to keep the other version, just add before the exit 0
line:cp -f $3 $2
.
That's it. You merge driver would aways keep the version coming from the other branch, overriding any local change)
(那是一个简单的合并驱动程序;)(在这种情况下更简单,使用true
)
(如果您想保留另一个版本,只需exit 0
在行前添加:cp -f $3 $2
。
就是这样。您合并驱动程序将使版本来自另一个版本分支,覆盖任何本地更改)
Now, let's retry the merge from the beginning:
现在,让我们从头开始重试合并:
git reset --hard
HEAD is now at ec202aa prepare myBranch with .gitattributes merge strategy
git merge hisBranch
Auto-merging dirWithConflicts/a.txt
CONFLICT (content): Merge conflict in dirWithConflicts/a.txt
Auto-merging dirWithCopyMerge/b.txt
Automatic merge failed; fix conflicts and then commit the result.
The merge fails... only for a.txt.
Edit a.txt and leave the line from 'hisBranch', then:
合并失败...仅适用于 a.txt。
编辑 a.txt 并保留 'hisBranch' 中的行,然后:
git add -A
git commit -m "resolve a.txt by accepting hisBranch version"
[myBranch 77bc81f] resolve a.txt by accepting hisBranch version
Let's check that b.txt has been preserved during this merge
让我们检查 b.txt 在这次合并过程中是否被保留
type dirWithCopyMerge\b.txt
b
myLineForB
The last commit does represent the fullmerge:
最后一次提交确实代表了完全合并:
git show -v 77bc81f5e
commit 77bc81f5ed585f90fc1ca5e2e1ddef24a6913a1d
Merge: ec202aa 658c31c
git merge hisBranch
Already up-to-date.
(The line beginning with Merge does prove that)
(以 Merge 开头的行确实证明了这一点)
Consider you can define, combine and/or overwrite merge driver, as Git will:
考虑您可以定义、组合和/或覆盖合并驱动程序,因为 Git 将:
- examine
<dir>/.gitattributes
(which is in the same directory as the path in question): will prevail upon the other.gitattributes
in directories - Then it examines
.gitattributes
(which is in the parent directory), will only set directives if not already set - Finally it examines
$GIT_DIR/info/attributes
. This file is used to override the in-tree settings. It will overwrite<dir>/.gitattributes
directives.
- 检查
<dir>/.gitattributes
(与相关路径在同一目录中):将优先.gitattributes
于目录中的另一个 - 然后它检查
.gitattributes
(在父目录中),如果尚未设置,将只设置指令 - 最后它检查
$GIT_DIR/info/attributes
. 此文件用于覆盖树内设置。它将覆盖<dir>/.gitattributes
指令。
By "combining", I mean "aggregate" multiple merge driver.
Nick Greentries, in the comments, to actually combine merge drivers: see "Merge pom's via python git driver".
However, as mentioned in his other question, it only works in case of conflicts (concurrent modification in both branches).
通过“组合”,我的意思是“聚合”多个合并驱动程序。
Nick Green在评论中尝试实际组合合并驱动程序:请参阅“通过 python git 驱动程序合并 pom”。
然而,正如他在另一个问题中提到的,它只在发生冲突的情况下有效(两个分支中的并发修改)。
回答by Greg Dubicki
As @ciro-santilli has commented, the simple way to do it to use .gitattributes
with settings it:
正如@ciro-santilli 所评论的那样,使用.gitattributes
设置它的简单方法是:
path/to/file merge=ours
and enable this strategy with:
并通过以下方式启用此策略:
git config --global merge.ours.driver true
(I am adding this as an answer to make it more visible but making it a Community Wiki to not try to get above user's credits for myself. Please upvote his comment under the Q here to give him kudos!)
(我将其添加为答案以使其更显眼,但使其成为社区 Wiki,不要试图为自己获得超过用户的积分。请在此处的 Q 下为他的评论点赞,以给他点赞!)
回答by HamletHub
We have multiple config files that we never want overwritten. However .gitignore and .gitattributes did not work in our situation. Our solution was to store the config files in a configs branch. Then, allow the files to be changed during the git merge, but immediately following the merge use the "git checkout branch -- ." to copy our config files from the configs branch after every merge. Detailed stackoverflow answer here
我们有多个我们不想覆盖的配置文件。然而 .gitignore 和 .gitattributes 在我们的情况下不起作用。我们的解决方案是将配置文件存储在 configs 分支中。然后,允许在 git 合并期间更改文件,但在合并之后立即使用“git checkout branch --”。在每次合并后从 configs 分支复制我们的配置文件。 详细的stackoverflow答案在这里