使用 git merge
将主题分支“B”合并到“A”时,我遇到了一些冲突。我知道所有的冲突都可以使用“B”中的版本来解决。
我知道 git merge -s ours
。但我想要的是 git merge -s theirs
之类的东西。
为什么不存在?在与现有 git
命令发生冲突合并后,如何获得相同的结果? (git checkout
来自 B 的每个未合并文件)
仅丢弃分支 A 中的任何内容(合并提交点到树的 B 版本)的“解决方案”不是我想要的。
git merge -s their
的可能方式。
git merge -s theirs
(可以通过 git merge -s ours
和临时分支轻松实现),因为 -s ours 完全忽略了 merge-from 分支的更改......
ours
之外还提供 theirs
是 冒犯吗???这是 Git 中高级工程和设计问题之一的症状:不一致。
git merge -s ours
无关。
一个类似的替代方法是接受 theirs
的 --strategy-option
(短格式 -X
)选项。例如:
git checkout branchA
git merge -X theirs branchB
但是,这更等同于 -X ours
而不是 -s ours
。主要区别在于 -X
执行常规递归合并,使用所选一侧解决任何冲突,而 -s ours
将合并更改为完全忽略另一侧。
在某些情况下,使用 -X theirs
而不是假设的 -s theirs
的主要问题是删除文件。在这种情况下,只需使用已删除文件的名称运行 git rm
:
git rm {DELETED-FILE-NAME}
之后,-X theirs
可能会按预期工作。
当然,使用 git rm
命令进行实际删除将首先防止冲突发生。
将分支 B 合并到我们签出的分支 A 中的一种可能且经过测试的解决方案:
# in case branchA is not our current branch
git checkout branchA
# make merge commit but without conflicts!!
# the contents of 'ours' will be discarded later
git merge -s ours branchB
# make temporary branch to merged commit
git branch branchTEMP
# get contents of working tree and index to the one of branchB
git reset --hard branchB
# reset to our merged commit but
# keep contents of working tree and index
git reset --soft branchTEMP
# change the contents of the merged commit
# with the contents of branchB
git commit --amend
# get rid off our temporary branch
git branch -D branchTEMP
# verify that the merge commit contains only contents of branchB
git diff HEAD branchB
要使其自动化,您可以使用 branchA 和 branchB 作为参数将其包装到脚本中。
此解决方案保留合并提交的第一个和第二个父项,就像您对 git merge -s theirs branchB
所期望的一样。
git reset --soft branchA
吗?
branchA
指向的 git reset --hard
更改。
旧版本的 git 允许您使用“他们的”合并策略:
git pull --strategy=theirs remote_branch
但这已被删除,正如 Junio Hamano(Git 维护者)在此消息中所解释的那样。如链接中所述,您可以这样做:
git fetch origin
git reset --hard origin
但请注意,这与实际的合并不同。您的解决方案可能是您真正需要的选项。
git reset --hard origin
如何解决他们的风格合并?如果我想将 BranchB 合并到 BranchA 中(就像在 Alan W. Smith 的回答中一样),我将如何使用 reset
方法来做到这一点?
git reset --hard
进行“他们的”式合并。当然,git reset --hard
不会创建任何合并提交或任何提交。他的观点是我们不应该使用合并来用其他东西替换 HEAD 中的任何内容。不过,我不一定同意。
theirs
被删除,因为理由不完整。它没有考虑到那些代码很好的情况,只是上游是在不同的哲学基础上维护的,所以从这个意义上说是“坏的”,所以一个人确实想跟上上游的最新情况,但是同时保留好的代码“修复”[git & msysgit 由于其不同的目标平台理念而有一些这种“冲突”]
theirs
,因为我不小心更改了两个单独分支中的一些文件,并且想要放弃一个更改,而不必为每个文件手动执行此操作。
目前尚不清楚您想要的结果是什么,因此在答案和他们的评论中对“正确”的执行方式存在一些混淆。我尝试给出一个概述并查看以下三个选项:
尝试合并并使用 B 来解决冲突
这不是“他们的 git merge -s ours
版本”而是“他们的 git merge -X ours
版本”(git merge -s recursive -X ours
的缩写):
git checkout branchA
# also uses -s recursive implicitly
git merge -X theirs branchB
这就是例如 Alan W. Smith's answer 所做的。
仅使用 B 中的内容
这会为两个分支创建一个合并提交,但会丢弃来自 branchA
的所有更改,只保留来自 branchB
的内容。
# Get the content you want to keep.
# If you want to keep branchB at the current commit, you can add --detached,
# else it will be advanced to the merge commit in the next step.
git checkout branchB
# Do the merge an keep current (our) content from branchB we just checked out.
git merge -s ours branchA
# Set branchA to current commit and check it out.
git checkout -B branchA
请注意,合并提交的第一个父级现在来自 branchB
,只有第二个来自 branchA
。这就是例如 Gandalf458's answer 所做的。
仅使用 B 中的内容并保持正确的父顺序
这是真正的“他们的 git merge -s ours
版本”。它的内容与之前的选项相同(即仅来自branchB
的内容),但父级的顺序是正确的,即第一个父级来自branchA
,第二个来自branchB
。
git checkout branchA
# Do a merge commit. The content of this commit does not matter,
# so use a strategy that never fails.
# Note: This advances branchA.
git merge -s ours branchB
# Change working tree and index to desired content.
# --detach ensures branchB will not move when doing the reset in the next step.
git checkout --detach branchB
# Move HEAD to branchA without changing contents of working tree and index.
git reset --soft branchA
# 'attach' HEAD to branchA.
# This ensures branchA will move when doing 'commit --amend'.
git checkout branchA
# Change content of merge commit to current index (i.e. content of branchB).
git commit --amend -C HEAD
这就是 Paul Pladijs's answer 所做的(不需要临时分支)。
特别案例
如果 branchB
的提交是 branchA
的祖先,则 git merge
不起作用(它只是退出并显示“已经是最新的。”这样的消息)。
在这种情况或其他类似/高级情况下,可以使用低级命令 git commit-tree
。
git checkout branchA; git merge -s ours --no-commit branchB; git read-tree -um @ branchB; git commit
-s ours
应始终改为使用。 -s ours
旨在将某些分支保存为已弃用,并且该分支的所有“用户”应快进到另一个分支。将父母置于“正确”(原文如此)的顺序将是相反的。
branchB
合并到 branchA
应始终导致 branchA
成为第一个父项,而 branchB
成为第二个父项。选择的策略应该对此没有影响。因此,模仿(不存在的)策略 -s theirs
将 branchB
合并到 branchA
应该导致 branchA
也成为第一个父级。我同意它可能经常没有用(这就是它不存在的原因),但如果你真的想做 -s theirs
,正确的父顺序是内容等效 -s ours
的逆定义,在我的观点。为什么你还需要它?
从现在开始,我就使用了 Paul Pladijs 的答案。我发现,你可以做一个“正常”的合并,发生冲突,所以你做
git checkout --theirs <file>
通过使用来自其他分支的修订来解决冲突。如果您对每个文件都执行此操作,您将获得与预期相同的行为
git merge <branch> -s theirs
无论如何,努力比合并策略要多! (这是用 git 版本 1.8.0 测试的)
git ls-files --modified | xargs git add
我想这样做是为了在两侧添加合并:/
git ls-files --modified
返回添加的双方文件,所以我想这也是一个可行的解决方案。
git config --global alias.unresolved '!git status --short|egrep "^([DAU])\1"'
-X
是什么意思,-X
和 -s
有什么区别?找不到任何文件。
使用 git merge 合并“A”中的主题分支“B”时,我遇到了一些冲突。我>知道使用“B”中的版本可以解决所有冲突。我知道 git merge -s ours 。但我想要的是像 git merge >-s 他们的东西。
我假设您从 master 创建了一个分支,现在想要合并回 master,覆盖 master 中的任何旧内容。当我看到这篇文章时,这正是我想做的。
做你想做的事,除了先将一个分支合并到另一个分支。我刚做了这个,效果很好。
git checkout Branch
git merge master -s ours
然后,checkout master 并合并你的分支(现在可以顺利进行):
git checkout master
git merge Branch
我解决了我的问题
git checkout -m old
git checkout -b new B
git merge -s ours old
如果您在分支 A 上,请执行以下操作:
git merge -s recursive -X theirs B
在 git 版本 1.7.8 上测试
为什么不存在?
虽然我在“git command for making one branch like another”中提到了如何模拟 git merge -s theirs
,但请注意 Git 2.15(2017 年第四季度)现在更加清晰:
用于合并的“-X
请参阅 Junio C Hamano (gitster
) 的commit c25d98b(2017 年 9 月 25 日)。
(由 commit 4da3e23 中的 Junio C Hamano -- gitster
-- 合并,2017 年 9 月 28 日)
合并策略:避免暗示“-s theirs”存在。-Xours 合并选项的描述有一个括号说明,告诉读者它与 -s ours 有很大不同,这是正确的,但是后面的 -Xtheirs 的描述它漫不经心地说“这与我们的相反”,给人一种错误的印象,即还需要警告读者,它与 -s 他们的非常不同,实际上甚至不存在。
-Xtheirs
是一个应用于递归策略的策略选项。这意味着递归策略仍然会合并任何它可以合并的东西,并且只会在发生冲突时回退到“theirs
”逻辑。
关于 theirs
合并策略是否相关的辩论最近被重新提起in this Sept. 2017 thread。
它承认 older (2008) threads
简而言之,前面的讨论可以总结为“我们不想要'-s theirs',因为它会鼓励错误的工作流程”。
它提到了别名:
mtheirs = !sh -c 'git merge -s ours --no-commit $1 && git read-tree -m -u $1' -
雅罗斯拉夫·哈尔琴科 (Yaroslav Halchenko) 试图再次倡导该策略,but Junio C. Hamano adds:
我们的和他们的不对称的原因是你是你而不是他们——我们的历史和他们的历史的控制权和所有权是不对称的。一旦您决定他们的历史是主线,您宁愿将您的开发线视为分支并朝该方向进行合并,即结果合并的第一个父级是对他们历史的提交,第二个父母是你历史上最后一个坏人。所以你最终会使用“checkout their-history && merge -s ours your-history”来保持第一父母的合理性。到那时,使用“-s ours”不再是缺少“-s theirs”的解决方法。它是所需语义的适当部分,即从幸存的规范历史线的角度来看,您希望保留它所做的,而取消另一条历史线所做的。
正如 Mike Beaton 所评论的,Junio 补充说:
git merge -s ours
git merge -s ours <their-ref>
有效地表示“标记提交到 <their-ref>在他们的分支上作为提交被永久忽略';这很重要,因为如果您随后从其分支的后续状态合并,则将引入他们以后的更改,而不会引入忽略的更改。
要真正正确地进行仅从您要合并的分支中获取输入的合并,您可以这样做
git merge --strategy=ours ref-to-be-merged
git diff --binary ref-to-be-merged | git apply --reverse --index
git commit --amend
在我所知道的任何情况下都不会发生冲突,您不必创建额外的分支,它就像一个正常的合并提交。
然而,这对子模块并不好。
请参阅 Junio Hamano's widely cited answer:如果您要丢弃提交的内容,只需丢弃提交,或者无论如何将其保留在主历史记录之外。为什么将来要打扰每个人从没有提供任何东西的提交中阅读提交消息?
但有时有行政要求,或者可能是其他一些原因。对于那些您确实必须记录无贡献的提交的情况,您需要:
(编辑:哇,我以前有没有弄错这个。这个有效。)
git update-ref HEAD $(
git commit-tree -m 'completely superseding with branchB content' \
-p HEAD -p branchB branchB:
)
git reset --hard
这个使用 git 管道命令 read-tree,但会缩短整体工作流程。
git checkout <base-branch>
git merge --no-commit -s ours <their-branch>
git read-tree -u --reset <their-branch>
git commit
# Check your work!
git diff <their-branch>
'git merge -s theirs branchB' 的等价物(保持父顺序)
https://i.stack.imgur.com/6AFQ5.png
!!!确保您处于清洁状态!
进行合并:
git commit-tree -m "take theirs" -p HEAD -p branchB 'branchB^{tree}'
git reset --hard 36daf519952 # is the output of the prev command
我们做了什么 ?我们创建了一个新的提交,其中两个父母是我们的和他们的,并且提交的内容是 branchB - 他们的
https://i.stack.imgur.com/XlMV5.png
更确切地说:
git commit-tree -m "take theirs" -p HEAD -p 'SOURCE^{commit}' 'SOURCE^{tree}'
我认为你真正想要的是:
git checkout -B mergeBranch branchB
git merge -s ours branchA
git checkout branchA
git merge mergeBranch
git branch -D mergeBranch
这看起来很笨拙,但它应该工作。我真正不喜欢这个解决方案的唯一想法是 git 历史会令人困惑......但至少历史将被完全保留,您不需要为已删除的文件做一些特殊的事情。
这个答案是由 Paul Pladijs 给出的。为了方便起见,我只是接受了他的命令并做了一个 git 别名。
编辑您的 .gitconfig 并添加以下内容:
[alias]
mergetheirs = "!git merge -s ours \"$1\" && git branch temp_THEIRS && git reset --hard \"$1\" && git reset --soft temp_THEIRS && git commit --amend && git branch -D temp_THEIRS"
然后你可以通过运行“git merge -s theirs A”:
git checkout B (optional, just making sure we're on branch B)
git mergetheirs A
这会将您的 newBranch 合并到现有的 baseBranch
git checkout <baseBranch> // this will checkout baseBranch
git merge -s ours <newBranch> // this will simple merge newBranch in baseBranch
git rm -rf . // this will remove all non references files from baseBranch (deleted in newBranch)
git checkout newBranch -- . //this will replace all conflicted files in baseBranch
git commit --amend
添加到您的示例末尾,否则用户可能会看到带有 git log
的合并提交并假设操作已完成。
我最近才需要为共享共同历史的两个独立存储库执行此操作。我开始:
组织/存储库1 主
org/repository2 master
我希望将来自 repository2 master
的所有更改应用到 repository1 master
,接受存储库 2 将进行的所有更改。在 git 的术语中,这个 应该 是一个名为 -s theirs
但它不存在的策略。请注意,因为 -X theirs
的命名方式就像您想要的那样,但它不 相同(它甚至在手册页中也是如此)。
我解决这个问题的方法是转到 repository2
并创建一个新分支 repo1-merge
。在那个分支中,我运行了 git pull git@gitlab.com:Org/repository1 -s ours
,它合并得很好,没有任何问题。然后我把它推到遥控器上。
然后我回到 repository1
并创建一个新分支 repo2-merge
。在该分支中,我运行 git pull git@gitlab.com:Org/repository2 repo1-merge
将完成问题。
最后,您需要在 repository1
中发出合并请求以使其成为新的主节点,或者将其保留为分支。
一个简单直观(在我看来)的两步方法是
git checkout branchB .
git commit -m "Picked up the content from branchB"
其次是
git merge -s ours branchB
(将两个分支标记为合并)
唯一的缺点是它不会从当前分支中删除已在 branchB 中删除的文件。之后两个分支之间的简单差异将显示是否有任何此类文件。
这种方法还可以从之后的修订日志中清楚地看出做了什么 - 以及打算做什么。
不定期副业成功案例分享
theirs
”不同。 -Xtheirs 是应用于递归策略的策略选项。这意味着递归策略仍然会合并任何它可以合并的东西,并且只会在发生冲突时回退到“他们的”逻辑。虽然这是在大多数情况下需要的,就像上面一样,但这与“按原样从分支 B 获取所有内容”不同。无论如何,它会进行真正的合并。git merge -X ours
的反面而不是git merge -s ours
的反面。这个答案应该反映 question 实际上是invalid。