使用--ours/--theirs解决Git所有文件的冲突

170

有没有一种使用checkout --ours--theirs解决所有文件冲突的方法?我知道你可以为单个文件这样做,但找不到一种处理所有文件的方法。


10
git checkout --ours -- . 这个命令有效吗?其中的“.”表示当前目录,如果在工作目录根目录应用,则表示整个工作目录。不确定是否可以与 --ours 标志一起使用,也不知道它如何处理已删除或重命名文件的冲突。 - user456814
@Cupcake 我已经成功使用过它。也许这应该是一个答案? - Pedro Gimeno
如果有人正在寻找在Visual Studio中执行此操作的答案,请查看以下链接: https://dev59.com/SGgv5IYBdhLWcg3wTvE-#74605102 - Ash K
7个回答

117

只需在工作目录中使用grep命令,并通过xargs命令发送输出:

grep -lr '<<<<<<<' . | xargs git checkout --ours

或者

grep -lr '<<<<<<<' . | xargs git checkout --theirs

这是如何工作的: grep 将递归地(使用 -r 标志)搜索当前目录(.)和子目录中的每个文件,查找冲突标记(字符串“<<<<<<<”)。 -l--files-with-matches 标志使 grep 仅输出找到字符串的文件名。扫描在第一次匹配后停止,因此每个匹配的文件仅输出一次。
然后将匹配的文件名 pipedxargs,一个实用程序,将管道输入流分解为 git checkout --ours--theirs 的单个参数。
更多信息请参见 at this link

既然每次在命令行中输入这个命令都很不方便,如果你发现自己经常使用它,为你选择的shell创建一个别名可能是个不错的主意:Bash通常是常用的。

这种方法应该适用于至少Git版本2.4.x


22
除了使用grep命令外,我认为也可以使用git diff --name-only --diff-filter=U来实现。 - Thai
11
如果你的项目非常大,那么使用 git status | grep both | awk '{print $3}' | xargs git checkout --[theirs|ours]' 比使用grep更快。该命令用于Git中,可以根据需要选择使用"theirs"或"ours"选项,并检出文件。 - joshbodily
1
@joshbodily 不错。我的项目并不是那么庞大,以至于我不会注意到差异,但我可以看出它会更快,特别是如果与目录中的总文件数相比,只有少数文件发生了变化——这应该是正常提交的情况。 - Dmitri
1
请注意,这对于重命名/重命名冲突无效,例如CONFLICT(rename/rename):在分支“HEAD”中将“a.txt”->“c.txt”重命名为“a.txt”->“b.txt”在“master”中。 - Borek Bernard
1
另一个选项是:git status --porcelain | egrep '^UU' | cut -d ' ' -f 2 |xargs git checkout --[theirs|ours] - Zitrax
显示剩余7条评论

85
您可以在使用git merge时选择-Xours-Xtheirs来进行合并。因此:

  1. 中止当前的合并(例如使用git reset --hard HEAD
  2. 使用您喜欢的策略进行合并(git merge -Xoursgit merge -Xtheirs

免责声明:当然,您可以只选择一个选项,要么是-Xours,要么是-Xtheirs,如需使用不同的策略,请逐个文件进行选择。

我不知道是否有一种方法可以在checkout命令中选择,但我认为这不是非常有用的:如果您想要针对不同的文件选择不同的解决方案,则使用checkout命令选择策略很有用,否则请采用合并策略方法。


谢谢,我不知道他们在合并时有“--ours”和“--theirs”。看起来,在合并时它们实际上不是“-s”策略的一部分,而是“-X”递归选项的一部分。“-s”版本的ours只是替换所有文件而不进行合并,而theirs不存在。 - exe163
Git v1.9.4 中没有 --theirs--ours 选项。一种解决方法是使用 git merge -s recursive -Xtheirs BRANCH 命令。 - fbmd
“--theirs”和“--ours”在git 2.2.0中都不可用。要么我的答案不够精确,要么它们只适用于旧版本的git(这个答案在IT时代已经很老了)。正确的方法是使用“-X”。我会相应地更新。 - ThanksForAllTheFish
从版本2.4.0开始,--ours和--theirs仍然可用。请参考http://git-scm.com/docs/git-checkout。 - Dmitri
尝试过这个命令,但是出现了“自动合并失败,修复冲突”的错误。很明显这个命令没有按照预期工作,我建议避免使用它——太多漏洞了。 - Adam
同样适用于 rebase,尽管 ourstheirs 的身份被交换了(Xours 表示保留正在被 rebase 的分支的更改 )。 - ijoseph

62

git checkout --[ours/theirs] .会做你想要的事情,只要你在所有冲突的根目录中。ours/theirs只影响未合并的文件,因此您不必特别查找冲突。


5
对我来说,似乎无法递归到子目录中。 - Daniel Baughman
5
我收到了“错误:路径 'foo/bar/blah' 没有我们的版本”的提示。 - Robin Green
我正在使用 git 版本 2.16.2.windows.1,它对我来说完美无缺。谢谢! - Pankwood
3
您可以使用 git restore [--ours] [--theirs] [--staged] <pathspec> 命令,其中 --ours 表示使用当前分支的版本替换指定文件,--theirs 表示使用其他分支的版本替换指定文件,而 --staged 则表示使用暂存区域的版本替换指定文件。 - Dylan Kendal
6
$ git checkout --ours 的意思是“使用我们的版本”,但在切换分支时却无法使用“--ours/--theirs”选项。该错误提示为:fatal: '--ours/--theirs' cannot be used with switching branches。这段代码运行在git版本2.31.1和hub版本2.14.2上。 - Vladimir Vukanac

43
git diff --name-only --diff-filter=U | xargs git checkout --theirs

看起来能够完成任务。请注意,您必须切换到 git repo 的根目录才能实现此操作。


5
我认为这个答案比得票最多的那个更好,因为(1)它适用于所有文件,而不仅仅是工作目录;(2)它不会在搜索冲突标记时产生任何脆弱性。此处的“git diff”命令列出了所有未合并的路径,这正是我们要检出的内容。 - bchurchill
不错!我一直担心 grep 冲突标记的可靠性。 - 00-BBB
我从上面的答案中准确地拼凑了这个。同意这是最干净和最高效的方法(对于较大的项目,特别是具有相当大的“node_modules”文件夹的JS项目,“grep”选项实际上是不可行的)。最终,我将这些别名添加到了我的“.bashrc”文件中:alias git-co-ours="git diff --name-only --diff-filter=U | xargs git checkout --ours" alias git-co-theirs="git diff --name-only --diff-filter=U | xargs git checkout --theirs" - ericsoco
你可以在git diff命令后面加上--relative参数,使得路径变为相对路径,这样就可以在任何子目录下使用了。 - undefined

26

情景1

如果有其他人想要简单地用另一个分支的内容(例如master)覆盖掉一个分支中的所有内容,有一种更简单的方法:

git merge origin/master --strategy=ours

--strategy选项也适用于git pull。)
感谢https://dev59.com/rXM_5IYBdhLWcg3wn0vT#1295232场景2 对于相反的情况,请参见是否有“git merge -s ours”的“theirs”版本? 更新 对于场景2,链接的答案建议使用:
git checkout branchA
git merge -X theirs branchB

我发现这并不完全是--strategy=ours的反向操作,你可能仍然会遇到合并冲突(在某些情况下,可能会保留你实际上想要删除的另一个分支的代码)。所以,如果你想要一个真正与git merge other-branch --strategy=ours相反的解决方案,最好的方法是分两步来进行(两次合并)。假设你的目标是用branch-b的内容替换branch-a,那么第一步应该是这样做:
git checkout branch-b
git fetch branch-a
git merge branch-a --strategy=ours

现在分支-b已经准备好无冲突地合并到分支-a了。此时,如果你正在使用类似Github的工具,你可以发起一个合并请求将分支-b合并到分支-a。或者如果不需要同行评审,你可以直接进行合并:
git checkout branch-a
git merge branch-b

# Cleanup - delete branch-b (if desired)
git branch -d branch-b
git push origin --delete branch-b

4
function gitcheckoutall() {
    git diff --name-only --diff-filter=U | sed 's/^/"/;s/$/"/' | xargs git checkout --$1
}

我在.zshrc文件中添加了此功能。

使用方式如下: gitcheckoutall theirsgitcheckoutall ours


0
这只是其中之一...
git checkout --ours .
git checkout --theirs .

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