我怎么告诉git总是选择我的本地版本来解决特定文件上的冲突合并?

时间:2009-05-30 00:29:54

标签: git git-merge

假设我通过git存储库与某人合作,并且有一个特定的文件,我从不想接受任何外部更改。

有没有办法让我设置我的本地仓库,以便每当我拉动时不抱怨冲突的合并?我想在合并这个文件时总是选择我的本地版本。

3 个答案:

答案 0 :(得分:134)

在配置文件的特定实例上,我同意Ron's answer
配置应该对您的工作区是“私有的”(因此“忽略”,如“在.gitignore文件中声明”。)
您可能在其中包含标记化值的配置文件模板,以及将config.template文件转换为私有(并忽略)配置文件的脚本。


然而,这个具体的评论并没有回答更广泛的更普遍的问题,即你的问题(!):

  

如何告诉git始终为特定文件中的冲突合并选择我的本地版本?(对于任何文件或文件组)

这种合并是一种“复制合并”,在发生冲突时,您将始终复制文件的“我们的”或“他们的”版本。

  

Brian Vandenberg注意in the comments'ours'和'theirs'用于合并
  对于 rebase ,它们颠倒:请参阅“Why is the meaning of “ours” and “theirs” reversed with git-svn”,其中使用了一个rebase,“git rebase, keeping track of 'local' and 'remote'”)

对于“一个文件”(一般来说,一个文件,不是说“配置”文件,因为它是一个不好的例子),你可以用一个通过合并调用的自定义脚本来实现。 Git会调用该脚本,因为您将定义一个gitattributes value,它定义了一个自定义合并驱动程序

在这种情况下,“自定义合并驱动程序”是一个非常简单的脚本,它基本上将保持当前版本不变,因此允许您始终选择本地版本。


让我们在一个简单的场景中测试一下,在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/

现在,让我们制作两个文件,这两个文件都会有冲突,但会以不同的方式合并。

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

我们将在两个不同的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

现在,让我们尝试将“hisBranch”合并到“myBranch”上,并使用:

  • 合并冲突的手动解决方案
  • {/ 1>}除了,我总是希望保留我的dirWithCopyMerge\b.txt

由于合并发生在“b.txt”中,我们将切换回它,并添加“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 目录中定义了.gitattributes文件(仅在合并将发生的分支中定义:dirWithCopyMerge),我们有一个myBranch文件现在包含合并驱动程序。

.git\config

如果你还没有定义keepMine.sh,并且无论如何都要启动合并,这就是你得到的。

[merge "keepMine"]
        name = always keep mine during merge
        driver = keepMine.sh %O %A %B

没关系:

  • 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 已准备好合并,并且存在冲突
  • a.txt仍未触及,因为合并驱动程序应该处理它(由于其目录中b.txt文件中的指令。)

.gitattributes(或keepMine.sh中为我们的Unix好友定义一个%PATH%。我当然都这样做:我在VirtualBox会话中有一个Ubuntu会话)

commented lrkwz,并在Merge Strategies的“Customizing Git - Git Attributes”部分中进行了描述,您可以使用shell命令$PATH替换shell脚本

true

但在一般情况下,您可以定义脚本文件:

keepMine.sh

git config merge.keepMine.driver true

(这是一个简单的合并驱动程序;)(在这种情况下更简单,使用# 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
(如果您想保留其他版本,只需在true行之前添加:
exit 0
而已。你合并驱动程序将保留版本来自其他分支,覆盖任何本地更改)

现在,让我们从头开始重试合并:

cp -f $3 $2

合并失败... 仅适用于a.txt 编辑a.txt并离开'hisBranch'的行,然后:

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.

让我们检查一下这个合并期间是否保留了b.txt

git add -A
git commit -m "resolve a.txt by accepting hisBranch version"
[myBranch 77bc81f] resolve a.txt by accepting hisBranch version

最后一次提交确实代表完整合并:

type dirWithCopyMerge\b.txt
b
myLineForB

(以Merge开头的行确实证明了这一点)


考虑你可以定义,组合和/或覆盖合并驱动程序,因为Git会:

  • 检查git show -v 77bc81f5e commit 77bc81f5ed585f90fc1ca5e2e1ddef24a6913a1d Merge: ec202aa 658c31c git merge hisBranch Already up-to-date. (与相关路径位于同一目录中):将以目录中的其他<dir>/.gitattributes为准
  • 然后检查.gitattributes(在父目录中),只设置指令(如果尚未设置)
  • 最后检查.gitattributes。此文件用于覆盖树内设置。它将覆盖$GIT_DIR/info/attributes指令。

通过“组合”,我的意思是“聚合”多个合并驱动程序 Nick Green尝试in the comments实际合并合并驱动程序:请参阅“Merge pom's via python git driver” 但是,如his other question中所述,它只适用于冲突(两个分支中的并发修改)。

答案 1 :(得分:0)

我们有多个配置文件,我们永远不会想要覆盖。但是.gitignore和.gitattributes在我们的情况下不起作用。我们的解决方案是将配置文件存储在configs分支中。然后,允许在git合并期间更改文件,但在合并之后立即使用&#34; git checkout分支 - 。&#34;每次合并后从configs分支复制我们的配置文件。 Detailed stackoverflow answer here

答案 2 :(得分:0)

正如@ ciro-santilli所评论的那样,使用.gitattributes进行设置的简单方法是

path/to/file merge=ours

并启用以下策略:

git config --global merge.ours.driver true


(我将其添加为答案,以使其更明显,但将其设为community wiki,以免自己超出用户的信用。请在此处的问号下对他的评论进行投票,以便给他恭喜!)