How do I 'overwrite', rather than 'merge', a branch on another branch in Git?

前端 未结 13 1312
广开言路
广开言路 2020-11-27 08:51

I have two branches, email and staging. staging is the latest one and I no longer need the old changes in email branch, y

相关标签:
13条回答
  • 2020-11-27 09:40
    git checkout email
    git merge -m "Making email same as staging disregarding any conflicts from email in the process" -s recursive -X theirs staging
    
    0 讨论(0)
  • 2020-11-27 09:41

    I wanted to merge two branches so that all the contents in old_branch to be updated with the contents from new_branch

    For me this worked like a charm:

    $ git checkout new_branch
    $ git merge -m 'merge message' -s ours origin/old_branch
    $ git checkout old_branch
    $ git merge new_branch
    $ git push origin old_branch
    
    0 讨论(0)
  • 2020-11-27 09:42

    The other answers gave me the right clues, but they didn't completely help.

    Here's what worked for me:

    $ git checkout email
    $ git tag old-email-branch # This is optional
    $ git reset --hard staging
    $
    $ # Using a custom commit message for the merge below
    $ git merge -m 'Merge -s our where _ours_ is the branch staging' -s ours origin/email
    $ git push origin email
    

    Without the fourth step of merging with the ours strategy, the push is considered a non-fast-forward update and will be rejected (by GitHub).

    0 讨论(0)
  • 2020-11-27 09:45

    You can use the 'ours' merge strategy:

    $ git checkout staging
    $ git merge -s ours email # Merge branches, but use our (=staging) branch head
    $ git checkout email
    $ git merge staging
    

    EDIT 2020-07-30:

    I thought a bit more about this question and possible solutions. If you absolutely require the merge parents in the correct order, need perform this action with a single command line invocation, and don't mind running plumbing commands, you can do the following:

    $ git checkout A
    $ git merge --ff-only $(git commit-tree -m "Throw away branch 'A'" -p A -p B B^{tree})
    

    This basically acts like the (non-existent) merge -s theirs strategy. You can find the resulting history in the plumbing branch of the demo repository

    Not very readable and not as easy to remember compared to the -s ours switch, but it does the job. The resulting tree is again the same as branch B:

    $ git rev-parse A^{tree} B^{tree} HEAD^{tree}
    3859ea064e85b2291d189e798bfa1bff87f51f3e
    0389f8f2a3e560b639d82597a7bc5489a4c96d44
    0389f8f2a3e560b639d82597a7bc5489a4c96d44
    

    EDIT 2020-07-29:

    There seems to be a lot of confusion as to what the difference between -s ours and -X ours (equivalent to -s recursive --strategy-option ours) is. Here's a small example to show the two results from using the strategy vs the strategy option. I also recommend reading the question and answers of (Git Merging) When to use 'ours' strategy, 'ours' option and 'theirs' option?

    First, setup a repository with 2 branches and 3 commits (1 base commit, and 1 commit per branch). You can find the sample repository on GitHub

    $ git init
    $ echo 'original' | tee file1 file2 file3
    $ git commit -m 'initial commit'
    $ git branch A
    $ git branch B
    $ git checkout A
    $ echo 'A' > file1
    $ git commit -m 'change on branch A' file1
    $ git checkout B
    $ echo 'B' > file2
    $ git commit -m 'change on branch B' file2
    

    Now, let's try the strategy option (doesn't really matter if we use theirs or ours for this explanation):

    $ git merge -X ours A
    $ cat file*
    A
    B
    original
    

    We end up with a merge of both branches' contents (branch "strategy-option" in the sample repo). Compare that to using the merge strategy (re-init your repository or reset branch, before executing the next steps):

    $ git merge -s ours A
    $ cat file*
    original
    B
    original
    

    The result is quite different (branch "merge-strategy" in the sample repo). With the strategy option, we get a merge result of both branches, with the strategy we throw away any changes which happened in the other branch.

    You will also notice that the commit created by the merge-strategy in fact points to the exact same tree than the latest commit of "our" branch, while the strategy-option created a new, previously unseen tree:

    $ git rev-parse A^{tree} B^{tree} merge-strategy^{tree} strategy-option^{tree}
    3859ea064e85b2291d189e798bfa1bff87f51f3e
    0389f8f2a3e560b639d82597a7bc5489a4c96d44
    0389f8f2a3e560b639d82597a7bc5489a4c96d44
    5b09d34a37a183723b409d25268c8cb4d073206e
    

    OP indeed asked for "I no longer need the old changes in […] branch" and "So I just want to dump all the contents of [A] into [B]", which is not possible to do with a strategy option. Using the 'ours' merge strategy is one possibility of many, but likely the easiest (other possibilities include using low level commands of Git such as write-tree and commit-tree).

    0 讨论(0)
  • 2020-11-27 09:45

    What you want is this (actually the exact inverse of the currently accepted answer):

    git checkout email
    git merge --strategy-option=theirs staging  
    

    What this does is:

    • email branch files will now be exactly the same as staging branch
    • email branch's history will be maintained
    • staging branch's history will be added to email history

    As added value, if you don't want all of staging branch's history, you can use squash to summarize it into a single commit message.

    git checkout email
    git merge --squash --strategy-option=theirs staging  
    git commit -m "Single commit message for squash branch's history here'
    

    So in summary, what this second version does is:

    • email branch files will now be exactly the same as staging branch
    • email branch's history will be maintained
    • A single commit will be added on top of email branch's history. This commit will represent ALL the changes that took place in the staging branch
    0 讨论(0)
  • 2020-11-27 09:48

    This one doesn't alter the original newer branch, and gives you the opportunity to make further modifications before final commit.

    git checkout new -b tmp
    git merge -s ours old -m 'irrelevant'
    git checkout old
    git merge --squash tmp
    git branch -D tmp
    #do any other stuff you want
    git add -A; git commit -m 'foo' #commit (or however you like)
    
    0 讨论(0)
提交回复
热议问题