Is there a “theirs” version of “git merge -s ours”?

前端 未结 18 1502
傲寒
傲寒 2020-11-22 06:42

When merging topic branch \"B\" into \"A\" using git merge, I get some conflicts. I know all the conflicts can be solved using the version in \"B\".

I a

相关标签:
18条回答
  • 2020-11-22 07:06

    When merging topic branch "B" in "A" using git merge, I get some conflicts. I >know all the conflicts can be solved using the version in "B".

    I am aware of git merge -s ours. But what I want is something like git merge >-s their.

    I'm assuming that you created a branch off of master and now want to merge back into master, overriding any of the old stuff in master. That's exactly what I wanted to do when I came across this post.

    Do exactly what it is you want to do, Except merge the one branch into the other first. I just did this, and it worked great.

    git checkout Branch
    git merge master -s ours
    

    Then, checkout master and merge your branch in it (it will go smoothly now):

    git checkout master
    git merge Branch
    
    0 讨论(0)
  • 2020-11-22 07:07

    The equivalent(which keep parent order) to 'git merge -s theirs branchB'

    Before merge:

    !!! Make sure you are in clean state !!!

    Do the merge:

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

    What we did ? We created a new commit which two parents ours and theirs and the contnet of the commit is branchB - theirs

    After merge:

    More precisely:

    git commit-tree -m "take theirs" -p HEAD -p 'SOURCE^{commit}' 'SOURCE^{tree}'
    
    0 讨论(0)
  • 2020-11-22 07:08

    Add the -X option to theirs. For example:

    git checkout branchA
    git merge -X theirs branchB
    

    Everything will merge in the desired way.

    The only thing I've seen cause problems is if files were deleted from branchB. They show up as conflicts if something other than git did the removal.

    The fix is easy. Just run git rm with the name of any files that were deleted:

    git rm {DELETED-FILE-NAME}
    

    After that, the -X theirs should work as expected.

    Of course, doing the actual removal with the git rm command will prevent the conflict from happening in the first place.


    Note: A longer form option also exists.

    To use it, replace:

    -X theirs
    

    with:

    --strategy-option=theirs
    
    0 讨论(0)
  • 2020-11-22 07:08

    It is not entirely clear what your desired outcome is, so there is some confusion about the "correct" way of doing it in the answers and their comments. I try to give an overview and see the following three options:

    Try merge and use B for conflicts

    This is not the "theirs version for git merge -s ours" but the "theirs version for git merge -X ours" (which is short for git merge -s recursive -X ours):

    git checkout branchA
    # also uses -s recursive implicitly
    git merge -X theirs branchB
    

    This is what e.g. Alan W. Smith's answer does.

    Use content from B only

    This creates a merge commit for both branches but discards all changes from branchA and only keeps the contents from 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
    

    Note that the merge commits first parent now is that from branchB and only the second is from branchA. This is what e.g. Gandalf458's answer does.

    Use content from B only and keep correct parent order

    This is the real "theirs version for git merge -s ours". It has the same content as in the option before (i.e. only that from branchB) but the order of parents is correct, i.e. the first parent comes from branchA and the second from 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
    

    This is what Paul Pladijs's answer does (without requiring a temporary branch).

    0 讨论(0)
  • 2020-11-22 07:09

    If you are on branch A do:

    git merge -s recursive -X theirs B
    

    Tested on git version 1.7.8

    0 讨论(0)
  • 2020-11-22 07:09

    Why doesn't it exist?

    While I mention in "git command for making one branch like another" how to simulate git merge -s theirs, note that Git 2.15 (Q4 2017) is now clearer:

    The documentation for '-X<option>' for merges was misleadingly written to suggest that "-s theirs" exists, which is not the case.

    See commit c25d98b (25 Sep 2017) by Junio C Hamano (gitster).
    (Merged by Junio C Hamano -- gitster -- in commit 4da3e23, 28 Sep 2017)

    merge-strategies: avoid implying that "-s theirs" exists

    The description of -Xours merge option has a parenthetical note that tells the readers that it is very different from -s ours, which is correct, but the description of -Xtheirs that follows it carelessly says "this is the opposite of ours", giving a false impression that the readers also need to be warned that it is very different from -s theirs, which in reality does not even exist.

    -Xtheirs is a strategy option applied to recursive strategy. This means that recursive strategy will still merge anything it can, and will only fall back to "theirs" logic in case of conflicts.

    That debate for the pertinence or not of a theirs merge strategy was brought back recently in this Sept. 2017 thread.
    It acknowledges older (2008) threads

    In short, the previous discussion can be summarized to "we don't want '-s theirs' as it encourages the wrong workflow".

    It mentions the alias:

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

    Yaroslav Halchenko tries to advocate once more for that strategy, but Junio C. Hamano adds:

    The reason why ours and theirs are not symmetric is because you are you and not them---the control and ownership of our history and their history is not symmetric.

    Once you decide that their history is the mainline, you'd rather want to treat your line of development as a side branch and make a merge in that direction, i.e. the first parent of the resulting merge is a commit on their history and the second parent is the last bad one of your history. So you would end up using "checkout their-history && merge -s ours your-history" to keep the first-parenthood sensible.

    And at that point, use of "-s ours" is no longer a workaround for lack of "-s theirs".
    It is a proper part of the desired semantics, i.e. from the point of view of the surviving canonical history line, you want to preserve what it did, nullifying what the other line of history did.

    Junio adds, as commented by Mike Beaton:

    git merge -s ours <their-ref> effectively says 'mark commits made up to <their-ref> on their branch as commits to be permanently ignored';
    and this matters because, if you subsequently merge from later states of their branch, their later changes will be brought in without the ignored changes ever being brought in.

    0 讨论(0)
提交回复
热议问题