使用git merge将主题分支“ B”合并到“ A”时,出现了一些冲突。我知道所有冲突都可以使用“ B”中的版本解决。

我知道git merge -s ours。但是我想要的是类似git merge -s theirs的东西。

为什么不存在?与现有的git命令发生冲突合并后,如何获得相同的结果? (git checkout来自B的每个未合并的文件)

更新:我只是在寻找不希望从分支A(树的B版本的合并提交点)中丢弃任何内容的“解决方案”。 br />

评论

另请参见以下答案:stackoverflow.com/questions/928646/…-将示例更改为使用版本B而不是版本A是很简单的。

请参阅SO answer git命令,以使一个分支像另一个分支一样,以模拟git merge -s它们的所有当前可能方法。

因此,您并不是真正在寻找git merge -s他们的(可以轻松地通过git merge -s ours和一个临时分支来实现),因为-s ours完全忽略了merge-from分支的更改...

@Torek-Git开发人员真的发现除了我们的产品之外还提供他们的产品是一种冒犯吗???这是Git中的高级工程和设计问题之一:不一致。

@jww这里的问题不在于“ git merge -s ours”令人反感,而在于它违反直觉。您可以从OP的问题中看到,如果要添加这样的功能,当他实际想要做的是“ git merge -s递归-X他们的”时,他会错误地使用它。通常要合并另一个分支,使其与另一个分支上的版本冲突,但是用另一个分支完全覆盖当前分支,而完全放弃当前更改是一个例外情况。

#1 楼

-X选项添加到theirs。例如:

git checkout branchA
git merge -X theirs branchB


一切都会以所需的方式合并。

我所见的唯一引起问题的是是否删除了文件来自branchB。如果除git之外的其他操作删除,它们将显示为冲突。

修复很容易。只需使用已删除的任何文件的名称运行git rm

git rm {DELETED-FILE-NAME}


之后,-X theirs应该可以正常工作。

当然,使用git rm命令进行实际的删除将首先避免发生冲突。


注意:还存在一个较长格式的选项。

要使用它,请替换:

-X theirs


替换为:

--strategy-option=theirs


评论


请参阅下面的其他答案,以获得对原始问题的更好解决方案(Paul Pladijs)。

–马尔科姆
13年7月16日在13:54



值得注意的是,这与“合并策略”不同。 -Xtheirs是应用于递归策略的策略选项。这意味着递归策略仍将合并所有可能的内容,并且仅在发生冲突时才退回到“其”逻辑中。尽管这是在大多数情况下(如上所述)所需要的,但这与“仅从分支B中获取所有内容”不同。无论如何,它执行真正的合并。

–Timur
13-10-14在11:57



它也可以与其他命令一起使用。我只是做了一个'git cherry-pick sha1 -X他们的'。谢谢!

– Max Hohenegger
14-10-17在15:33

这是一个糟糕的答案,因为它看起来正确,但实际上是错误的。 “ git merge -s他们的”不会做“ git merge -s他们的”。它不会用合并分支的内容替换当前分支。它更喜欢“他们的”更改,但仅在发生冲突的情况下。因此,所产生的提交可能与“他们的”分支完全不同。这不是问题发布者所想到的。

–伊凡·克里瓦科夫(Ivan Krivyakov)
17年6月16日在1:28

@ user3338098:是的,您是对的。我重新阅读了这个问题,它也不是很好。不幸的是,造成混乱的根本原因不是答案,甚至不是问题。 git作者的设计选择是为合并策略和合并策略“递归”选择相同的名称“我们的”。实际上,这种情况下的混乱是不可避免的。

–伊凡·克里瓦科夫(Ivan Krivyakov)
17年9月2日,下午2:43

#2 楼

将branchB合并到我们已签出的branchA中的可能且经过测试的解决方案:

 # 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的期望一样。

评论


问:为什么需要branchTEMP?你不可以git reset --soft branchA吗?

– cdunn2001
2012年6月27日在21:11

@ cdunn2001:我以某种方式想了同样的事情,但没有。注意git reset --hard提交了branchA指向的更改。

–伊藤刚
2012年11月9日19:37

很抱歉提出一个愚蠢的问题,但是为什么-xtheirs这种方法更好?优点/缺点是什么

–chrispepper1989
15年2月10日在10:19

@ chrispepper1989 -x它们的冲突只会影响冲突,如果可以干净地应用我们的一大块冲突,它将进入最终的合并。在这种情况下,如最后一条命令所示,无论是否存在冲突,我们都将获得与branchB完全相同的合并。

– UncleZeiv
2015年5月5日16:37

@UncleZeiv感谢您的解释,因此基本上执行“其”操作将保留无冲突的更改和文件,从而导致生成的int代码与拉出的代码不同。

–chrispepper1989
15年5月18日在9:35

#3 楼

较早版本的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方法来做到这一点?

–詹姆斯·麦克马洪
2012-09-20 14:23



@詹姆士·麦克马洪(James McMahon):Junio C Hamano的观点不是git reset –很难做到“他们”的合并。当然,git reset --hard不会创建任何合并提交或与此相关的任何提交。他的观点是,我们不应使用合并将HEAD中的任何内容替换为其他内容。不过,我不一定同意。

–伊藤刚
2012年11月9日19:44



遗憾的是,他们的理由不完整而被删除。它没有考虑到代码良好的情况,只是上游是在不同的哲学基础上进行维护的,因此从某种意义上说是“不好的”,因此人们都希望两者都与上游保持最新,但是同时保留一个良好的代码“修复程序” [git和msysgit由于目标平台的理念不同而具有一些这种“冲突”]

–菲利普·奥克利(Philip Oakley)
13年8月5日在19:53



它还缺少我现在坚持使用的用例,我与其他人共享一个分支,而我们俩碰巧同时推送更改(在不同文件上)。因此,我想破坏我在本地拥有的所有旧版本,而改用他的较新版本。他想对我更新的文件执行相同的操作。没有什么可以“重置”的。当每个文件约为20个文件时,检出每个文件的解决方案不切实际。

– zeitlin
15年9月24日在18:50

我真的不懂这种哲学。我之所以使用它们,是因为我不小心在两个单独的分支中更改了一些文件,并希望放弃对一个文件的更改而不必手动对每个文件进行更改。

– sudo
18-4-10在23:03



#4 楼

目前尚不清楚您期望的结果是什么,因此在答案及其评论中对“正确”的实现方式有些困惑。我尝试给出一个概述,并查看以下三个选项:

尝试合并并使用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
 


请注意,合并现在提交的第一个父级是branchB的父级,只有第二个父级来自branchA。这就是例如Gandalf458的答案是肯定的。

仅使用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的回答(不需要临时分支)。

评论


选项3的较干净版本:git checkout branchA; git merge -s我们的--no-commit branchB; git read-tree -um @ branchB; git提交

– jthill
16年5月21日在18:22

@jthill:虽然您的版本更加简洁,但它也使用了低级(“管道”)命令读取树,普通的git用户可能不习惯(至少我不是;-))。答案中的解决方案仅使用大多数git用户应该知道的高级(“瓷器”)命令。我更喜欢它们,但是仍然感谢您的版本!

– siegi
16年5月21日在18:56

您能解释倒数第二个步骤(结帐branchA)吗?似乎它不应该在那里。

–帕特里克(Patrick)
16年6月17日在2:44

@Patrick,这是必需的步骤。如果您跳过它,则将获得相同的提交,但没有分支指向该提交。因此,一旦切换到另一个提交/分支,您对上一个命令(…commit --amend…)所做的提交就会“丢失”。我计划在有时间的时候在此答案中添加一些图形说明。…;-)

– siegi
16年6月17日在11:35

#5 楼

从现在开始,我一直使用Paul Pladijs的答案。我发现,您可以执行“常规”合并,发生冲突,因此您可以使用其他分支的修订来解决冲突。

git checkout --theirs <file>


通过使用另一个分支的修订来解决冲突。如果对每个文件执行此操作,则将具有与

git merge <branch> -s theirs


相同的行为,无论如何,与合并策略相比,所做的工作要多! (这已在git版本1.8.0中进行了测试)

评论


如果可以检索文件列表,那就太好了。例如,git ls-files --modified | xargs git add我想这样做是为了在两边添加合并:/

– andho
2012年11月26日8:02



实际上git返回带有git ls-files --modified的双面文件中添加的内容,所以我想这也是可行的解决方案。

– andho
2012年11月26日上午8:06

也感谢您添加此内容。通常,在逐个文件的基础上不需要它。另外,git status在最底部显示“ Unmerged Paths”。要获取未解析路径的列表,我使用以下别名:git config --global alias.unresolved'!git status --short | egrep“ ^([DAU])\ 1”'

–梅尔文
2015年1月10日于17:22

-X的含义是什么,-X和-s的区别是什么?找不到任何文档。

–雷阳
4月22日下午6:20

#6 楼

我使用

git checkout -m old
git checkout -b new B
git merge -s ours old

解决了我的问题

评论


来自“旧”分支的分支“ B”

– elmarco
2010-2-22在17:07



#7 楼


当使用git merge在“ A”中合并主题分支“ B”时,出现一些冲突。我>知道所有冲突都可以使用“ B”中的版本解决。
我知道git merge -s ours。但是我想要的是像git merge> -s它们的东西。

我假设您创建了master的分支,现在想合并回master,覆盖其中的所有旧内容主。这正是我遇到这篇文章时想要做的。
完全按照您想要做的去做,除了首先将一个分支合并到另一个分支中。我只是这样做了,所以效果很好。
git checkout Branch
git merge master -s ours

然后,结帐母版并将您的分支合并到其中(现在它将顺利进行):
git checkout master
git merge Branch


评论


谢谢。到目前为止,这应该是最简单,最正确的答案。如果您的分支落后于master或与master发生冲突,则将其分支工作合并并使一切正常,然后再将所有内容合并回master。

– StackHola
3月14日14:19

#8 楼

如果您在分支A上,请执行以下操作:

git merge -s recursive -X theirs B


在git版本1.7.8上进行了测试

#9 楼

要真正正确地进行合并,只合并您要合并的分支中的输入,就可以执行

git merge --strategy=ours ref-to-be-merged

git diff --binary ref-to-be-merged | git apply --reverse --index

git commit --amend

在我所知的任何情况下都不会发生冲突,您不必创建其他分支,并且它的行为就像正常的合并提交。

但是,子模块。

评论


-R在这里做什么?

– P. Myer Nore
15年6月30日在12:14

这样,您将丢失文件“移动和更改”的历史记录。我对吗?

– elysch
16年4月19日在22:43

-R是--reverse,我将答案更新为更多自我说明。

–伊利亚·林恩(Elijah Lynn)
17年7月20日在23:18



如果您要合并的文件在传入分支中被删除,这似乎不起作用。

–解决J
17年9月17日在16:53

#10 楼


为什么不存在?


我在“使一个分支像另一个分支的git命令”中提到如何模拟git merge -s theirs,请注意,Git 2.15(2017年第四季度)现在更加清晰:


用于合并的“ -X<option>”文档被误导了
,以表明“ -s theirs”存在,事实并非如此。


请参阅Junio C Hamano(gitster)提交的c25d98b(2017年9月25日)(由Junio C Hamano合并-gitster-在commit 4da3e23中提交,2017年9月28日)


merge-strategies:避免暗示“ -s theirs”存在。

-Xours merge选项的描述带有圆括号
,告诉读者它与-s ours非常不同,
是正确的,但是后面的-Xtheirs的描述
粗心地说“这与ours相反”,给人一种错误的
印象,也需要警告读者,这是非常错误的
与q4312079不同q,实际上甚至不存在。


-s theirs是应用于递归策略的策略选项。这意味着递归策略仍将合并所有内容,并且只有在发生冲突的情况下才退回到“ -Xtheirs”逻辑。

有关theirs合并策略是否相关的争论被带回了
它承认较旧的(2008)线程。



总之,前面的讨论可以总结为“我们不想'theirs'因为它会导致错误的工作流程”。


它提到了别名:

mtheirs = !sh -c 'git merge -s ours --no-commit  && git read-tree -m -u ' -


雅罗斯拉夫·哈尔琴科(Yaroslav Halchenko)尝试再次倡导该策略,但Junio C. Hamano补充:


我们和他们之间不对称的原因是因为你是你而不是他们---我们历史及其历史的控制和所有权不是对称的。

一旦确定他们的历史记录是主线,您就希望将自己的开发线视为分支,并在该方向上进行合并,即,结果合并的第一个父项是对他们的历史的提交,第二个父母是您历史上的最后一个坏人。因此,您最终将使用“ -s theirs”来
使初生父母保持明智。

此时,使用“ checkout their-history && merge -s ours your-history”不再是缺少“ -s ours”的解决方法这是所需语义的适当部分,即,从尚存的规范历史行的角度来看,您想要保留其所做的事情,从而使其他历史行所做的事情无效。


Juno补充说,正如Mike Beaton所评论的那样:


-s theirs有效地表示“在其分支上由git merge -s ours <their-ref>组成的标记提交被视为永久忽略的提交”;这很重要,因为,如果您随后从其分支的较新状态进行合并,则将引入其较晚的更改,而不会引入被忽略的更改。


评论


这是一个有用的答案,但是它没有提及我刚刚从Junio C中理解的一个关键点。Hamano的答案:git merge -s我们的有效地表示“标记提交由在其分支上,因为它们将被永久忽略”;这很重要,因为如果您随后从其分支的较后状态进行合并,则将引入其较晚的更改,而不会引入被忽略的更改。

– MikeBeaton
19/09/12在13:17



@MikeBeaton谢谢。我已将您的评论包含在答案中,以提高知名度。

–VonC
19年9月12日14:38在

#11 楼

请参见Junio Hamano广为引用的答案:如果要丢弃已提交的内容,则只丢弃这些提交,或者无论如何都应将其排除在主要历史记录之外。为什么以后要打扰每个人都从没有提供内容的提交中读取提交消息?

但是有时存在管理要求,或者也许还有其他原因。对于那些确实必须记录不做任何贡献的提交的情况,您想要:

(编辑:哇,我以前设法弄错了吗。这个可行。)

git update-ref HEAD $(
        git commit-tree -m 'completely superseding with branchB content' \
                        -p HEAD -p branchB    branchB:
)
git reset --hard


#12 楼

这使用了git plumbing命令读取树,但使整体工作流程缩短了。

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>


#13 楼

等价(保留父顺序)与'git merge -s他们的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}'


#14 楼

保罗·普拉迪斯(Paul Pladijs)给出了这个答案。为了方便起见,我只是接受了他的命令并为其添加了git别名。

编辑.gitconfig并添加以下内容:

[alias]
    mergetheirs = "!git merge -s ours \"\" && git branch temp_THEIRS && git reset --hard \"\" && git reset --soft temp_THEIRS && git commit --amend && git branch -D temp_THEIRS"


那么您可以通过运行以下命令“ git merge -s thems A”:

git checkout B (optional, just making sure we're on branch B)
git mergetheirs A


#15 楼

这会将您的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的合并提交并假定操作已完成。

– Michael R
15年4月22日在18:55

#16 楼

我认为您真正想要的是:

git checkout -B mergeBranch branchB
git merge -s ours branchA
git checkout branchA
git merge mergeBranch
git branch -D mergeBranch


这看起来很笨拙,但应该可以。我真正不喜欢此解决方案的唯一想法是git历史记录会令人困惑...但是至少历史记录将被完全保留,并且您不需要为已删除的文件做一些特殊的事情。

#17 楼

我最近刚刚需要对两个共享相同历史记录的独立存储库执行此操作。我从以下内容开始:


Org/repository1 master
Org/repository2 master

我希望将repository2 master的所有更改应用于repository1 master,并接受repository2所做的所有更改。用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中发出合并请求以使其成为新的主服务器,或者只是将其保留为分支。 br />

#18 楼

一种简单而直观的方法(在我看来)是以下两个步骤:

git checkout branchB .
git commit -m "Picked up the content from branchB"


接着是

git merge -s ours branchB


(将两个分支标记为合并的)

唯一的缺点是它不会从当前分支中删除在branchB中已删除的文件。之后,将在两个分支之间进行简单的比较,以显示是否存在任何此类文件。

此方法还可以从修订日志中清楚地知道执行了哪些操作以及打算执行的操作。

评论


这对于原始问题可能是正确的,但是OP在2008年以一种错误的方式更新了该问题。

–user3338098
19年1月25日在17:02

@ user3338098是的,太可惜了,他们留下了误导性的标题,只是在问题正文的末尾拍了一个不太明显的更新……。因为此答案确实正确回答了标题问题。

– RomainValeri
19-10-24在22:32



我完全同意@RomainValeri

–AppleCiderGuy
5月28日19:10