使用 将主题分支“B”合并到“A”git merge
时,我遇到了一些冲突。我知道所有的冲突都可以使用“B”中的版本来解决。
我知道git merge -s ours
。但我想要的是类似的东西git merge -s theirs
。
为什么不存在?git
与现有命令发生冲突合并后,如何获得相同的结果?(git checkout
来自 B 的每个未合并的文件)
仅丢弃分支 A 中的任何内容(合并提交点到树的 B 版本)的“解决方案”不是我想要的。
一个类似的替代方案是--strategy-option
(short form -X
) 选项,它接受theirs
. 例如:
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 允许您使用“他们的”合并策略:
git pull --strategy=theirs remote_branch
但这已被删除,正如Junio Hamano(Git 维护者)在此消息中所解释的那样。如链接中所述,您可以这样做:
git fetch origin
git reset --hard origin
但请注意,这与实际的合并不同。您的解决方案可能是您真正需要的选项。
目前尚不清楚您想要的结果是什么,因此在答案和他们的评论中对“正确”的执行方式存在一些混淆。我尝试给出一个概述并查看以下三个选项:
尝试合并并使用 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 的回答所做的。
仅使用 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
请注意,合并提交的第一个父级现在是 from branchB
,只有第二个是 from branchA
。这就是例如Gandalf458 的回答所做的。
仅使用 B 中的内容并保持正确的父顺序
这是真正的“他们的版本git merge -s ours
”。它的内容与之前的选项相同(即只有 from 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 的回答所做的(不需要临时分支)。
特别案例
如果 , 的提交branchB
是 , 的祖先branchA
,git merge
则不起作用(它只是退出并显示类似“ Already up to date. ”之类的消息)。
git commit-tree
在这种或其他类似/高级的情况下,可以使用低级命令。
从现在开始,我就使用了 Paul Pladijs 的答案。我发现,你可以做一个“正常”的合并,发生冲突,所以你做
git checkout --theirs <file>
通过使用来自其他分支的修订来解决冲突。如果您对每个文件都执行此操作,您将获得与预期相同的行为
git merge <branch> -s theirs
无论如何,努力比合并策略要多!(这是用 git 版本 1.8.0 测试的)
使用 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 a branch like another ”中提到了如何模拟git merge -s theirs
,但请注意 Git 2.15(2017 年第四季度)现在更加清晰:
用于合并的 ' ' 的文档
-X<option>
被误导性地表明-s theirs
存在“”,但事实并非如此。
请参阅Junio C Hamano ( ) 的提交 c25d98b(2017 年 9 月 25 日)。(由Junio C Hamano 合并 -- --在4da3e23 提交中,2017 年 9 月 28 日)gitster
gitster
合并策略:避免暗示“
-s theirs
”存在合并选项的描述
-Xours
有一个括号告诉读者它与 有很大不同-s ours
,这是正确的,但它后面的描述-Xtheirs
不小心说“这是相反的ours
”,给人一种读者也需要的错误印象需要注意的是,它与 非常不同-s theirs
,实际上它甚至不存在。
-Xtheirs
是应用于递归策略的策略选项。这意味着递归策略仍然会合并任何它可以合并的东西,并且只会theirs
在发生冲突时回退到“”逻辑。
最近在 2017 年 9 月的这个帖子中theirs
重新提出了关于合并策略是否相关的辩论。
它承认较旧的(2008)线程
简而言之,前面的讨论可以概括为“我们不想要 '
-s theirs
',因为它会鼓励错误的工作流程”。
它提到了别名:
mtheirs = !sh -c 'git merge -s ours --no-commit $1 && git read-tree -m -u $1' -
雅罗斯拉夫哈尔琴科试图再次倡导该策略,但 Junio C. Hamano 补充道:
我们的和他们的不对称的原因是你是你而不是他们——我们的历史和他们的历史的控制权和所有权是不对称的。
一旦您决定他们的历史是主线,您宁愿将您的开发线视为一个分支并朝该方向进行合并,即结果合并的第一个父级是对他们历史的提交,第二个父母是你历史上最后一个坏人。因此,您最终会使用“
checkout their-history && merge -s ours your-history
”来保持第一父母身份的合理性。到那时,使用“
-s ours
”不再是缺少“-s theirs
”的解决方法。
它是所需语义的适当部分,即从幸存的规范历史线的角度来看,您希望保留它所做的,取消另一条历史线所做的。
正如Mike Beaton所评论的,Junio 补充道:
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 被广泛引用的答案:如果您要丢弃提交的内容,只需丢弃提交,或者无论如何将其保留在主要历史记录之外。为什么将来要打扰每个人从没有提供任何东西的提交中阅读提交消息?
但有时有行政要求,或者可能是其他一些原因。对于那些您确实必须记录无贡献的提交的情况,您需要:
(编辑:哇,我以前有没有弄错这个。这个有效。)
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' 的等价物(保持父顺序)
!!!确保您处于清洁状态!
进行合并:
git commit-tree -m "take theirs" -p HEAD -p branchB 'branchB^{tree}'
git reset --hard 36daf519952 # is the output of the prev command
我们做了什么 ?我们创建了一个新的提交,其中两个父母是我们的和他们的,并且提交的内容是 branchB - 他们的
更确切地说:
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
我最近才需要为共享共同历史的两个独立存储库执行此操作。我开始:
Org/repository1 master
Org/repository2 master
我希望将所有更改repository2 master
应用到repository1 master
,接受 repository2 将进行的所有更改。用 git 的话来说,这应该是一个叫-s theirs
BUT 它不存在的策略。要小心,因为-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 中删除的文件。之后两个分支之间的简单差异将显示是否有任何此类文件。
这种方法还可以从之后的修订日志中清楚地看出做了什么 - 以及打算做什么。