在拉取期间解决 Git 合并冲突以支持其更改
Posted
技术标签:
【中文标题】在拉取期间解决 Git 合并冲突以支持其更改【英文标题】:Resolve Git merge conflicts in favor of their changes during a pull 【发布时间】:2012-05-28 16:11:09 【问题描述】:如何解决 git 合并冲突以支持拉取更改?
基本上,我需要从工作树中删除所有冲突的更改,而不必通过git mergetool
处理所有冲突,同时保持所有无冲突的更改。最好在拉的时候这样做,而不是之后。
【问题讨论】:
git merge -s ours, what about "theirs" 的可能重复项 重复的git pull from remote.. can I force it to overwrite rather than report conflicts? 你可以在那里看到相同的解决方案。 @DanDascalescu 接受的答案没有回答这个问题,所以很明显它不是重复的。另外,另一个问题非常模糊:很难说出所问的内容。总而言之,我不能同意你的看法。你在这有什么意义? @sanmai 你有两个答案——你接受了其中一个。您能否更好地解释您对答案的期望以及您希望在这里提供多少详细信息? @EdwardThomson 好吧,实际上我想为第一个答案提供这个声誉,但如果你问,我可能会等着看是否会出现更好的答案 【参考方案1】:git pull -s recursive -X theirs <remoterepo or other repo>
或者,简单地说,对于默认存储库:
git pull -X theirs
If you're already in conflicted state...
git checkout --theirs path/to/file
【讨论】:
请注意这里的-s recursive
是多余的,因为这是默认的合并策略。所以可以简化为git pull -X theirs
,基本等价于git pull --strategy-option theirs
。
如果我这样做,我最终会回到MERGING
状态。然后我可以git merge --abort
再试一次,但每次我最终都会发生合并。 ......我知道一个变基被推到了我的上游,所以也许这是造成这种情况的原因?
小心git checkout --theirs path/to/file
。在 rebase 期间使用它并得到了意想不到的结果。在文档中找到解释:请注意,在 git rebase 和 git pull --rebase 期间,我们的和他们的可能会出现交换; --ours 给出了更改被重新定位到的分支的版本,而 --theirs 给出了保存正在被重新定位的工作的分支的版本。
请注意,git checkout --theirs/--ours path
手册页声明它适用于未合并的路径。所以如果路径没有冲突,它已经被合并了,这个命令什么也不做。例如,当您想要整个子文件夹的“他们的”版本时,这可能会出现问题。所以在这种情况下,使用git checkout MERGE_HEAD path
或使用提交哈希会更安全。
git pull -X theirs
在存在冲突时创建合并提交(例如,如果另一个提交者将 git push -f
运行到远程)。如果您不想合并提交,请改为运行 git fetch && git reset --hard origin/master
。【参考方案2】:
您可以使用递归“他们的”策略选项:
git merge --strategy-option theirs
来自man:
ours
This option forces conflicting hunks to be auto-resolved cleanly by
favoring our version. Changes from the other tree that do not
conflict with our side are reflected to the merge result.
This should not be confused with the ours merge strategy, which does
not even look at what the other tree contains at all. It discards
everything the other tree did, declaring our history contains all that
happened in it.
theirs
This is opposite of ours.
注意:正如手册页所说,“我们的”合并 strategy-option 与“我们的”合并 strategy 非常不同。
【讨论】:
这里有更详细的解释:lostechies.com/joshuaflanagan/2010/01/29/… 也git checkout --theirs
对单个冲突文件进行操作
如果您已经处于冲突解决状态,这将不起作用。在这种情况下,我认为最好的解决方法是git checkout <ref to theirs> -- the/conflicted.file
;然后git add
他们的变化。
@ThorSummoner 在这种情况下,有 git checkout --theirs path/of/file。这样,您不必手动查找正确的哈希值。
@Ikke 如果你问我,那基本上应该是它自己的答案(以及接受的答案)。【参考方案3】:
如果您已经处于冲突状态,并且您只想接受他们的所有:
git checkout --theirs .
git add .
如果你想反其道而行之:
git checkout --ours .
git add .
这是相当激烈的,所以在做之前确保你真的想像这样清除所有东西。
【讨论】:
或者,不要使用.
并指定文件来代替您要签出的点。不那么“激烈”,而正是你想要做的,大概。
如果文件已从另一个分支中删除,这将不起作用:'git add -u
跳过不受版本控制的文件。
假设情况,一个文件中的三个更改,一个冲突,两个不冲突,此解决方案是否会应用非冲突更改并解决我们的冲突更改?还是只需要我们的版本而忽略他们的不冲突更改?
@pedromarce git checkout --ours
接受我们的所有更改,包括非冲突更改。小心点。【参考方案4】:
好吧,想象一下我刚才所处的场景:
你尝试merge
,或者cherry-pick
,但你被阻止了
$ git cherry-pick 1023e24
error: could not apply 1023e24... [Commit Message]
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
现在,您查看了冲突的文件,并且您真的不想保留您的更改。在我上面的例子中,文件在我的 IDE 自动添加的换行符上发生冲突。要撤消您的更改并接受他们的更改,最简单的方法是:
git checkout --theirs path/to/the/conflicted_file.php
git add path/to/the/conflicted_file.php
这个的反面(用你的版本覆盖传入的版本)是
git checkout --ours path/to/the/conflicted_file.php
git add path/to/the/conflicted_file.php
令人惊讶的是,我在网上找不到这个答案。
【讨论】:
请注意,如果在checkout
和add
之间执行git status
,文件仍显示为“都已修改”。
您知道是否有办法对所有处于冲突状态的文件执行此操作?如果是这样,那将是您答案的一个很好的扩展。
我这样做:git reset --hard
然后git pull [remote server name] [branch name] -Xtheirs
(撤消合并然后将新内容拉到我的内容之上) - 不确定这是否是您想要的。【参考方案5】:
git pull -X theirs
的答案可能会创建一个丑陋的合并提交,或者发出一个
错误:您对以下文件的本地更改将被合并覆盖:
如果您想简单地忽略对来自 repo 的文件的任何本地修改,例如在应该始终是源镜像的客户端上,请运行此命令(将 master
替换为您想要的分支):
git fetch && git reset --hard origin/master
它是如何工作的? git fetch
does git pull
but without merge。然后git reset --hard
使您的工作树与最后一次提交匹配。您对 repo 中文件的所有本地更改都将是 discarded,但新的本地文件将被单独保留。
【讨论】:
+1 -git fetch && git reset --hard remote/branch
解决了我的问题。我需要完全放弃我自己的更改以支持分支的“他们的”状态,但是git pull -X theirs
阻塞了一些移动/重命名的文件。谢谢!
但如果我之后执行git pull
,我会回到冲突状态,可能我不应该拉 git,但为什么不呢?【参考方案6】:
要解决与特定分支中的版本的所有冲突:
git diff --name-only --diff-filter=U | xargs git checkout $branchName
所以,如果您已经处于合并状态,并且您想保留冲突文件的主版本:
git diff --name-only --diff-filter=U | xargs git checkout master
【讨论】:
对于在 windows 上无法访问管道 xargs 的人来说,这是如何翻译的? 它不会完全跳过您的更改吗?甚至那些不处于冲突状态的? 这就是我最终要做的。不幸的是,它随后需要git cherry-pick --continue
或 git commit --allow-empty
命令来提交这些更改,并且似乎没有系统需要该命令,这使得自动化变得很痛苦。我目前正在通过测试 .git/COMMIT_EDITMSG
文件的存在来解决这个问题,但这看起来很老套而且很脆弱,而且我还不相信它总是有效的。
这很好,这意味着如果您手动解决一些问题(并执行git add
),那么您可以通过它批量解决其余问题。 git checkout --ours
/ git checkout --theirs
也很有用。【参考方案7】:
VS Code(集成 Git)IDE 用户:
如果您想接受冲突文件中的所有传入更改,请执行以下步骤。
1. Go to command palette - Ctrl + Shift + P
2. Select the option - Merge Conflict: Accept All Incoming
类似地,您可以使用其他选项,例如 Accept All Both、Accept All Current 等,
【讨论】:
这似乎只适用于单个文件,但并非所有有冲突的文件。【参考方案8】:请注意,有时这会不起作用:
git checkout --ours path/to/file
或
git checkout --他们的路径/到/文件
我这样做了,假设 HEAD 是我们的而 MERGE_HEAD 是他们的
git checkout HEAD -- path/to/file
或:
git checkout MERGE_HEAD -- path/to/file
在我们这样做之后,我们就很好了:
git add .
如果您想了解更多,请在此处查看 torek 的精彩帖子: git checkout --ours does not remove files from unmerged files list
【讨论】:
【参考方案9】:如果您已经处于冲突状态,并且不想一一签出路径。你可以试试
git merge --abort
git pull -X theirs
【讨论】:
【参考方案10】:git checkout --ours/theirs
并不专门解决冲突。它从ours/theirs
签出(获取整个文件)。
假设我们有一个文件foo
,其中包含两个提交/分支/树/任何内容的更改。如果他们引入了冲突以及修改,并且我们想使用 ours
解决冲突 -- 那么使用 checkout --ours foo
将丢弃引入冲突的更改,以及修改。
使用 SED
用他们的解决:
sed -i -e '/^<<<<<<</,/^=======/d' -e '/^>>>>>>>/d' foo
-i
原地修改文件,
/^<<<<<<</,/^=======/d
删除 <<<<<<<
和 =======
(我们的)之间的所有内容
/^>>>>>>>/d
删除剩余的冲突标记
-e
为 SED 指定多个模式
foo
文件
使用我们的解决方案:
sed -i -e '/^<<<<<<</d' -e '/^=======/,/^>>>>>>>/d' foo
我做了一个script,你可以打电话给git resolve -o/-t/-b
。
创建自定义合并工具
您可以创建自定义合并工具。在上述sed
脚本的基础上,您可以在git-config
中添加类似的内容:
[mergetool "ours"]
cmd = "sed -i -e '/^<<<<<<</d' -e '/^=======/,/^>>>>>>>/d' -- $MERGED"
并称之为git mergetool --tool=ours
【讨论】:
我开始在 Git 邮件列表上讨论它以寻求可能的解决方案:public-inbox.org/git/…【参考方案11】:我有一个长期运行的 next-version
分支,其中大量删除了在 develop
上更改的文件、在两个分支的不同位置添加的文件等。
我想将next-version
分支的全部内容放到develop
中,在一个巨大的合并提交中完成。
对我有用的上述命令的组合是:
git merge -X theirs next-version
# lots of files left that were modified on develop but deleted on next-version
git checkout next-version .
# files removed, now add the deletions to the commit
git add .
# still have files that were added on develop; in my case they are all in web/
git rm -r web
不是一个新的答案,只是结合了许多答案中的一些部分,部分是为了确保您可能需要所有这些答案。
【讨论】:
【参考方案12】:来自https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging
这基本上会做一个假合并。它将记录一个新的合并提交 将两个分支都作为父母,但它甚至不会看分支 你正在合并。它只会记录为合并的结果 您当前分支中的确切代码。
$ git merge -s ours mundo
按照“我们的”策略进行合并。
$ git diff HEAD HEAD~
你可以看到我们所在的分支没有区别 以及合并的结果。
这通常很有用,可以基本上诱骗 Git 认为 稍后进行合并时,分支已经合并。例如,说 你分支了一个发布分支并做了一些工作 您将希望在某个时候合并回您的主分支。在 同时需要将 master 上的一些错误修复移植到您的 发布分支。您可以将错误修复分支合并到发布中 分支并将 -s 我们的同一个分支合并到您的主分支中 (即使修复已经存在)所以当你稍后合并 再次发布分支,bugfix没有冲突。
如果我希望 master 反映新主题分支的更改,我发现这种情况很有用。我注意到 -Xtheirs 在某些情况下不会在没有冲突的情况下合并... 例如
$ git merge -Xtheirs topicFoo
CONFLICT (modify/delete): js/search.js deleted in HEAD and modified in topicFoo. Version topicFoo of js/search.js left in tree.
在这种情况下,我找到的解决方案是
$ git checkout topicFoo
来自 topicFoo,首先使用 -s ours 策略合并到 master 中,这将创建只是 topicFoo 状态的假提交。 $ git merge -s 我们的主人
检查创建的合并提交
$ git log
现在检查主分支
$ git checkout master
合并主题分支,但这次使用 -Xtheirs 递归策略,这将为您提供一个具有 topicFoo 状态的主分支。
$ git merge -X theirs topicFoo
【讨论】:
以上是关于在拉取期间解决 Git 合并冲突以支持其更改的主要内容,如果未能解决你的问题,请参考以下文章
git可视化工具Sourcetree使用全攻略(包括各种git冲突解决)