首页 文章

是否有“他们的”版本的“git merge -s ours”?

提问于
浏览
706

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

我知道 git merge -s ours . 但我想要的是 git merge -s theirs .

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

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

18 回答

  • 80

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

    git checkout --theirs <file>
    

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

    git merge <branch> -s theirs
    

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

  • 2

    要真正正确地执行合并,只需要合并您正在合并的分支的输入,您可以这样做

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

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

    git commit --amend

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

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

  • 0

    我解决了我的问题

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

    这将在现有的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
    
  • 48

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

    合并前:
    enter image description here

    !确保你处于干净状态!

    合并:

    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 - 他们的

    合并后:
    enter image description here

    更确切地说:

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

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

    git pull --strategy=theirs remote_branch
    

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

    git fetch origin
    git reset --hard origin
    

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

  • 21

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

    为什么不存在?

    虽然我在“git command for making one branch like another”中提到如何模拟 git merge -s theirs ,但请注意Git 2.15(2017年第4季度)现在更清晰:

    用于合并的'-X <option>'的文档被误导性地写成表明存在“-s他们的”,但实际情况并非如此 .

    commit c25d98b(2017年9月25日)Junio C Hamano (gitster) .
    (由Junio C Hamano合并 - gitster - in commit 4da3e23,2017年9月28日)

    合并策略:避免暗示“-s他们的”存在-Xours merge选项的描述有一个括号注释告诉读者它与-s我们是非常不同的,这是正确的,但是-Xtheirs的描述跟着它不小心说“这与我们的相反”,给人一种错觉,即读者也需要被警告它与他们的非常不同,实际上甚至不存在 .

    -Xtheirs 是应用于递归策略的策略选项 . 这意味着递归策略仍然可以合并任何东西,并且只有在发生冲突时才会回退到“ theirs ”逻辑 .

    关于 theirs 合并策略是否有针对性的辩论最近被提起in this Sept. 2017 thread .
    它承认older (2008) threads

    简而言之,之前的讨论可以概括为“我们不要' - 他们的',因为它鼓励错误的工作流程” .

    它提到了别名:

    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 our our your-history”来保持第一父母身份的合理性 . 在这一点上,使用“-s our”不再是缺乏“-s theirs”的解决方法 . 它是所需语义的一个适当部分,即从幸存的规范历史路线的角度来看,你想要保留它所做的事情,使其他历史记录的作用无效 .

  • 55

    更新

    虽然第二个答案回答了OP的原始问题,但它没有反映OP问题的更新意图 .


    您正在寻找的是与_272000_命令相反的_272000_命令的反面, git merge -s recursive -X ours 命令是 git merge -s recursive -X theirs


    原始答案

    给予原始分支

    *    0123456 (HEAD->A, origin/A)
    | *  1234556 (origin/B, B)
    |/
    *    ??????? (common root)
    

    将分支B合并为A而忽略分支A的状态,然后首先进行常规合并

    git merge -s ours B    (this is the opposite of what we want)
    

    这导致了

    *    2345678 (HEAD->A) Merge branch 'B' into A    (all wrong)
    |\
    * |  0123456 (origin/A)
    | *  1234567 (origin/B, B)
    |/
    *    ??????? (common root)
    

    不要推送这个合并,因为提交ID会改变(并且这两种方式都是错误的)现在我们可以将 ours 策略更改为 theirs 策略

    不要忘记记下合并的提交ID,因为在下次硬重置后它将不可用 . (如果你忘了不会造成任何伤害,但你必须重新硬复位回 A 并重新开始) .

    git reset --hard B    (this is what we want the merge to look like (the merge can now only be referenced by the commit id `2345678`))
    git reset --soft 2345678    (without changing any files go back to the merge)
    git commit --amend    (branch B is now the final version of the merge)
    

    现在我们有

    *    3456789 (HEAD->A) Merge branch 'B' into A    (correctly ignores changes from 0123456)
    |\
    * |  0123456 (origin/A)
    | *  1234567 (origin/B, B)
    |/
    *    ??????? (common root)
    
    $ diff HEAD B
    [... no changes ...]
    git push
    

    DONE

    当一位同事将我的更改 A 应用到他的独立分支 B 而不合并时,我需要这样做,这使我能够接受他在我的分支上的修改 .

  • 826

    -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
    
  • 13

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

    Try merge and use B for conflicts

    这不是“ git merge -s ours " but the "他们的版本为 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的确如此 .

    Use content from B only

    这会为两个分支创建合并提交,但会丢弃 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呢 .

    Use content from B only and keep correct parent order

    这是真正的“他们的 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所做的(不需要临时分支) .

  • 6

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

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

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

    git checkout Branch
    git merge master -s ours
    

    然后,checkout master并合并你的分支(它现在会很顺利):

    git checkout master
    git merge Branch
    
  • 8

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

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

    其次是

    git merge -s ours branchB
    

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

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

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

  • 185

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

    • 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 中发出合并请求以使其成为新的主服务器,或者只是将其保留为分支 .

  • -1

    请参阅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
    
  • 0

    可行且经过测试的解决方案将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 的期望一样 .

  • 1

    如果你在分支A上做:

    git merge -s recursive -X theirs B
    

    测试了git版本1.7.8

  • 0

    我想你真正想要的是:

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

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

相关问题