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

我知道git merge -s ours 。 但我想要的是像git merge -s theirs这样的东西。

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

更新:从分支A(合并提交点到树的B版本)丢弃任何东西的“解决方案”不是我想要的。


#1楼

如果你在分支A上做:

git merge -s recursive -X theirs B

测试了git版本1.7.8


#2楼

我从现在开始使用Paul Pladijs的答案。 我发现,你可以做一个“正常”合并,发生冲突,所以你这样做

git checkout --theirs <file>

通过使用来自其他分支的修订来解决冲突。 如果对每个文件执行此操作,则会产生与预期相同的行为

git merge <branch> -s theirs

无论如何,努力比合并策略更多! (这是用git版本1.8.0测试的)


#3楼

这将在现有的baseBranch中合并你的newBranch

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

#4楼

请参阅Junio Hamano广泛引用的答案 :如果您要丢弃已提交的内容,只需丢弃提交内容,或者无论如何都要将其保留在主要历史记录之外。 为什么在将来阅读提交来自无法提供的提交的消息时会困扰每个人?

但有时候有行政要求,或者其他一些原因。 对于那些你真的需要记录没有贡献的提交的情况,你想要:

(编辑:哇,我以前设法弄错了。这个有效。)

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

#5楼

我解决了我的问题

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

#6楼

较旧版本的git允许您使用“他们的”合并策略:

git pull --strategy=theirs remote_branch

但是这已被删除,正如Junio Hamano (Git维护者)在此消息中所解释的那样。 如链接中所述,您可以这样做:

git fetch origin
git reset --hard origin

但要注意,这与实际合并不同。 您的解决方案可能是您真正想要的选择。


#7楼

当使用git merge在“A”中合并主题分支“B”时,我会遇到一些冲突。 我>知道使用“B”中的版本可以解决所有冲突。

我知道git merge-是我们的。 但我想要的是像git merge> -s他们的东西。

我假设你创建了一个master的分支,现在想要合并回master,覆盖master中的任何旧东西。 当我遇到这篇文章时,这正是我想要做的。

完全按照你想做的去做,除了首先将一个分支合并到另一个分支。 我刚刚这样做了,效果很好。

git checkout Branch
git merge master -s ours

然后,结帐主人并合并你的分支(它现在将顺利):

git checkout master
git merge Branch

#8楼

要真正正确地执行合并, 需要合并您正在合并的分支的输入即可

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

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

git commit --amend

在我知道的任何场景中都不会发生冲突,您不必进行额外的分支,它就像普通的合并提交一样。

但是,这对子模块不起作用。


#9楼

目前还不完全清楚你期望的结果是什么,所以对于在答案和评论中这样做的“正确”方式存在一些困惑。 我尝试概述并查看以下三个选项:

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


#10楼

这个使用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>

#11楼

-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

#12楼

我想你真正想要的是:

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

这看起来很笨拙,但应该有效。 唯一认为我真的不喜欢这个解决方案的是git历史会令人困惑......但至少历史记录将被完全保留,你不需要为删除的文件做一些特别的事情。


#13楼

我最近需要为两个共享历史记录的独立存储库执行此操作。 我开始时:

  • 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将完成问题。

最后,您需要在repository1发出合并请求以使其成为新的主服务器,或者只是将其保留为分支。


#14楼

它为什么不存在?

虽然我在“ git命令中为一个分支创建另一个分支 ”如何模拟git merge -s theirs ,但请注意Git 2.15(2017年第四季度)现在更清晰了:

用于合并的' -X<option> '的文档被误导性地写成表明存在“ -s theirs ”,但事实并非如此。

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

合并策略:避免暗示“ -s theirs ”存在

-Xours merge选项的描述有一个括号注释,告诉读者它与-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' -

Yaroslav Halchenko试图再次倡导这一战略, 但Junio C. Hamano补充道

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

一旦你确定他们的历史是主线,你宁愿把你的开发线视为一个侧分支并在那个方向上进行合并,即生成的合并的第一个父是他们的历史提交和第二个父母是你历史上最后一个坏人。 所以你最终会使用“ checkout their-history && merge -s ours your-history ”来保持第一父母身份的合理性。

在这一点上,使用“ -s ours ”不再是缺乏“ -s theirs ”的解决方法。
它是所需语义的一个适当部分,即从幸存的规范历史路线的角度来看,你想要保留它所做的事情,使其他历史路线的作用无效


#15楼

一种可行且经过测试的解决方案,用于将branchB合并到我们的签出分支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


#16楼

等价(保持父订单)'git merge -s the their branchB'

合并前: 在此输入图像描述

! 确保你处于干净状态!

合并:

git commit-tree -m "take theirs" -p HEAD -p branchB 'branchB^{tree}'
git reset --hard 36daf519952 # is the output of the prev command

我们做了什么 ? 我们创建了一个新的提交,我们和他们的两个父母和他们的提交的contnet是branchB - 他们的

合并后: 在此输入图像描述

更确切地说:

git commit-tree -m "take theirs" -p HEAD -p 'SOURCE^{commit}' 'SOURCE^{tree}'

#17楼

一个简单直观的(在我看来)两步走的方法是

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

其次是

git merge -s ours branchB

(这标志着两个分支合并)

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

这种方法也从修订日志中明确了所做的事情 - 以及预期的内容。


#18楼

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
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐