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

GitGit Merge

Git Problem Overview


I have two branches, email and staging. staging is the latest one and I no longer need the old changes in email branch, yet I don't want to delete them.

So I just want to dump all the contents of staging into email so that they both point to the same commit. Is that possible?

Git Solutions


Solution 1 - Git

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 to 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 (the latter being equivalent to -s recursive --strategy-option ours) is. Here's a small example to show the two results from using these two methods. I also recommend reading the question and answers of https://stackoverflow.com/questions/45402742/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).

Solution 2 - Git

If you just want the two branches 'email' and 'staging' to be the same, you can tag the 'email' branch, then reset the 'email' branch to the 'staging' one:

$ git checkout email
$ git tag old-email-branch
$ git reset --hard staging

You can also rebase the 'staging' branch on the 'email' branch. But the result will contains the modification of the two branches.

Solution 3 - Git

I've seen several answers and that's the only procedure that let me fix that without any conflicts.

If you want all changes from branch_new in branch_old, then:

git checkout branch_new
git merge -s ours branch_old
git checkout branch_old
git merge branch_new

once applied those four commands you can push the branch_old without any problem

Solution 4 - Git

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).

Solution 5 - Git

If you're like me and you don't want to deal with merging, you can do the above steps, except use force instead of merge, because it will create a distracting log paper trail:

git checkout email
git reset --hard staging
git push origin email --force

Note: This is only if you REALLY never want to see the stuff in email again.

Solution 6 - Git

>WARNING: This deletes all commits on the email branch. It's like deleting the email branch and creating it anew at the head of the staging branch.

The easiest way to do it:

//the branch you want to overwrite
git checkout email 

//reset to the new branch
git reset --hard origin/staging

// push to remote
git push -f

Now the email branch and the staging are the same.

Solution 7 - Git

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








Solution 8 - Git

How about:

git branch -D email
git checkout staging
git checkout -b email
git push origin email --force-with-lease

Solution 9 - Git

Other answers looked incomplete.
I have tried below in full, and it worked fine.

NOTE:

  1. Make a copy of your repository before you try below, to be on safe side.

Details:

  1. All development happens in dev branch
  2. qa branch is just the same copy of dev
  3. Time to time, dev code needs to be moved/overwrite to qa branch

so we need to overwrite qa branch, from dev branch

Part 1:
With below commands, old qa has been updated to newer dev:

git checkout dev
git merge -s ours qa
git checkout qa
git merge dev
git push

Automatic comment for last push gives below:

// Output:
//  *<MYNAME> Merge branch 'qa' into dev,*  

This comment looks reverse, because above sequence also looks reverse

Part 2:

Below are unexpected, new local commits in dev, the unnecessary ones
so, we need to throw away, and make dev untouched.

git checkout dev

// Output:
//  Switched to branch 'dev'  
//  Your branch is ahead of 'origin/dev' by 15 commits.  
//  (use "git push" to publish your local commits)


git reset --hard origin/dev  

//  Now we threw away the unexpected commits

Part 3:
Verify everything is as expected:

git status  

// Output:
//  *On branch dev  
//  Your branch is up-to-date with 'origin/dev'.  
//  nothing to commit, working tree clean*  

That's all.

  1. old qa is now overwritten by new dev branch code
  2. local is clean (remote origin/dev is untouched)

Solution 10 - Git

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

Solution 11 - Git

git checkout email
git merge -m "Making email same as staging disregarding any conflicts from email in the process" -s recursive -X theirs staging

Solution 12 - Git

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)

Solution 13 - Git

I tried @knittl's write-tree/commit-tree approach.

branch-a: the kept branch

branch-b: the abandoned branch

// goto branch-a branch
$ git checkout branch-a

$ git write-tree
6fa6989240d2fc6490f8215682a20c63dac5560a // echo tree id? I guess

$ git commit-tree  -p branch-a -p branch-b 6fa6989240d2fc6490f8215682a20c63dac5560a
<type some commit message end with Ctrl-d>
20bc36a2b0f2537ed11328d1aedd9c3cff2e87e9 // echo new commit id

$ git reset --hard 20bc36a2b0f2537ed11328d1aedd9c3cff2e87e9

Solution 14 - Git

This will merge two branches old and new and choose the new version on every merge conflict:

git checkout old
git merge new
git checkout --theirs .
git add .
git commit

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRafidView Question on Stackoverflow
Solution 1 - GitknittlView Answer on Stackoverflow
Solution 2 - GitSylvain DefresneView Answer on Stackoverflow
Solution 3 - GitBrugoloView Answer on Stackoverflow
Solution 4 - GitShyam HabarakadaView Answer on Stackoverflow
Solution 5 - GitjsarmaView Answer on Stackoverflow
Solution 6 - GitB.NeoView Answer on Stackoverflow
Solution 7 - GitMadhuView Answer on Stackoverflow
Solution 8 - GitArek SView Answer on Stackoverflow
Solution 9 - GitManohar Reddy PoreddyView Answer on Stackoverflow
Solution 10 - GitlenzView Answer on Stackoverflow
Solution 11 - GitWillaView Answer on Stackoverflow
Solution 12 - GitJan Kyu PeblikView Answer on Stackoverflow
Solution 13 - GitzjkView Answer on Stackoverflow
Solution 14 - GitNoah NueblingView Answer on Stackoverflow