373

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?

Mike Pennington
  • 41,899
  • 19
  • 136
  • 174
Rafid
  • 18,991
  • 23
  • 72
  • 108
  • 5
    Possible duplicate of [Change the current branch to master in git](http://stackoverflow.com/questions/2763006/change-the-current-branch-to-master-in-git) – Tomas Kubes Jan 05 '17 at 11:51

14 Answers14

306

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

John Cvelth
  • 522
  • 1
  • 6
  • 19
knittl
  • 246,190
  • 53
  • 318
  • 364
  • 30
    I tried this, and it seems backwards to me? Doesn't this dump the contents of email into staging and not the other way around? – Max Apr 23 '14 at 01:58
  • 31
    @Max I had the same confusion and it caused me a lot of trouble. You need do this command from the newer branch (staging), and then do a normal merge/PR to your old branch (email). – MrGlass Apr 28 '14 at 16:59
  • 3
    somehow git shows "already up-to-date", do you know how to resolve it – Hoang Lam Jun 16 '14 at 03:01
  • @HoangLam: It means the branch is already fully merged (your current branch is an ancestor of the branch to be merged) – knittl Jun 16 '14 at 04:59
  • 8
    Why the `;` at the end of each command? I did without the `;` and it seems to be working. Also this answer is incomplete, the third step is to checkout the old branch (email) and then merge with staging again. – Rosdi Kasim Nov 13 '14 at 03:32
  • 1
    @RosdiKasim: the semicolon doesn't matter much if there is only a single command per line, it just ends the command. And yes, you can merge (fast-forward) or push staging into email. You can also just re-create the email branch from the staging branch (`git branch -f email staging`). You might also delete it, since you don't really need it anymore. – knittl Nov 13 '14 at 07:11
  • 5
    ``git rebase -s theirs `` works as well (no matter which branch you are). Note that in rebase 'theirs' is actually the newbranch because 'ours' is the head we're currently applying the commits to. – Rolf Jun 05 '15 at 10:46
  • 4
    @Rolf: but rebase will get rid of the merge information and flattens history. Not necessarily what you are after. Also not a good idea, if you are working with already-published history. – knittl Jun 05 '15 at 11:00
  • @knittl. Totally agree. However, some people's workflow is to first rebase a feature branch on top of master before merging. In this case, you'll need to do the overwrite during rebase. Off-topic: Rebasing the (local!) branch on top of master has the advantage of resolving conflicts one a per-commit basis rather than in a big merge commit. Also easier to understand the branch history (esp. when visualized). – Rolf Jun 05 '15 at 14:03
  • 1
    The Git documentation is frustratingly ambiguous about how this works. I tried it, and `git merge -s ours` uses the **local** versions for all conflicts, overriding the remote versions. – sudo Jul 18 '15 at 21:27
  • 2
    Surely there should be a more intuitive solution based on `theirs` (that I believe to be the opposite of ours), such as `$ git checkout email; $ git merge -s theirs staging`? – Simon H May 05 '17 at 09:51
  • 3
    Perfect answer. I was worried about if the changes from the other branch that we want to update with this new branch would somehow seep through. But -s ours flag leads to overriding all changes, not just ones that cause a conflict. The -s recursive -X ours has that issue. In short, this answer accurately answers and solves the problem – user3245268 Nov 29 '18 at 22:31
  • @HoangLam You raise a good question: If the current branch is a child of the branch we wish to overwrite, we get the "Already up-to-date" message. In this case, I encouraged students to revert to the [xkcd approach](https://xkcd.com/1597/), but I don't know what down-stream ramifications there may be. – Josiah Yoder Nov 12 '19 at 19:36
  • @Rolf there is no theirs strategy `git checkout develop` ..... `git merge -s theirs newdevelop` -------- `Could not find merge strategy 'theirs'. Available strategies are: octopus ours recursive resolve subtree.` – ThrowableException Jul 22 '20 at 16:56
  • @ThrowableException In my comment, I mentioned ``git rebase`` not ``git merge``. – Rolf Jul 22 '20 at 20:28
  • this does the inverse. I think this should not be the accepted answer. What you want is: `git checkout email` `git merge --strategy-option=theirs staging` This updates the email branch to reflect the files in `staging` branch, but also keeps the previous history of `email` in the email branch (as well as the newer history of `staging`) – lenz Jul 29 '20 at 04:26
  • @lenz there's a big difference between strategy `ours` and strategy options `ours`/`theirs`. Using strategy option (with the default strategy `recursive` as your example`) will only affect automatic conflict resolution. You will not end up with the full state of one branch, but with a mix. In other words: using the strategy does not what OP wants to. Unfortunately there is no `theirs` strategy (not strategy-option!), so you have to merge in the "reverse direction". History is kept with both. Cleaning up the branch labels and commit message afterwards is trivial. – knittl Jul 29 '20 at 05:44
  • Can you expand on “You will not end up with the full state of one branch, but with a mix.” @knittl I did this myself for 2 branches that evolved quite differently. I ran ‘git diff’ afterwards and I have the exact copy of the other branch. In other words did this exactly what I expected it to do for my use case, which seems to be the same as OP. – lenz Jul 29 '20 at 07:05
  • @lenz I've edited my answer to include an example showing that the strategy-option does not solve OPs problem and results in a very different tree compared to using the strategy. – knittl Jul 29 '20 at 15:32
  • @knittl OP said “ I no longer need the old changes in email branch, yet I don't want to delete them”. I think you may have missed the key statement “does not want to delete the old history”. Just wants to write over it. As if forking the staging branch into a new branch, while having access to the history of email branch in the new branch. In your own words “with the strategy we throw away any changes which happened in the other branch”. That’s not the desired outcome. – lenz Jul 29 '20 at 21:25
  • See my answer below. The second part of my answer uses --squash to bring all the changes of the staging branch into a single commit in email branch. From then on, the email branch is identical to the staging branch. – lenz Jul 29 '20 at 21:28
  • Never mind. I get it now. File2 should still contain “original” as to branch A in your example. You’re right, --strategy-option=theirs does not solve this. – lenz Jul 29 '20 at 22:02
  • 1
    Thanks for this. Although it felt backwards to be merging the unwanted branch into the replacement, the result was a perfectly clean single commit. Other constraints I had meant other solutions were not looking good. I was merging a *totally different repository* into replace the base project, and the `master` (production) branch was protected and couldn't be renamed away etc. – dman Jan 27 '21 at 11:47
  • 'our' didn't work. It said my branch was already up to date. – Jason Cheng Jan 28 '21 at 18:01
  • @JasonCheng is that `ours` you meant? – MrR Mar 22 '21 at 12:37
  • This updated command literally does the reverse. It dumps all the changes of `email` into `staging` – Jelle De Loecker Apr 20 '23 at 16:10
  • @JelleDeLoecker have you read the first edit (and tried it) – the one starting with "If you absolutely require the merge parents in the correct order"? Also, branches are ephemeral, just set your branch labels to whatever commit you need them. – knittl Apr 20 '23 at 16:15
132

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sylvain Defresne
  • 42,429
  • 12
  • 75
  • 85
124

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

Brugolo
  • 4,685
  • 3
  • 22
  • 14
  • 12
    Your answer really fit my issue best as I didn't want to reset the HEAD, just state a preference for the newer files in the newer branch when merging things into the older one, and worked without issue! +1 – stoves Dec 07 '15 at 21:25
  • I pushed my branch_new to remote after the "ours merge", and this method worked for me. Was it necessary for me to push? Or would it have worked without? (Wasn't sure if it would use the local branch or remote). Thanks! – aspergillusOryzae Mar 11 '16 at 22:02
  • Why can't you simply do the below? git checkout branch_old git merge -s theirs branch_new Clue taken from http://stackoverflow.com/questions/14275856/git-merging-but-overwriting-changes – Ripu Daman Feb 05 '17 at 20:58
  • It says , could not find merge strategy 'theirs'. – arango_86 Oct 19 '17 at 08:25
  • 1
    Works perfectly for me, has the advantage of not reseting anything – Romain Oct 30 '19 at 16:15
  • Went flawlessly for me, thank you! – moshyfawn May 05 '22 at 21:12
74

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

Shyam Habarakada
  • 15,367
  • 3
  • 36
  • 47
  • 1
    That makes the merge-commit message wrong, but yeah, it works great. – cdunn2001 Jun 05 '12 at 04:57
  • cdunn2001, I'm curious. What was the merge-commit message you were expecting and how did that get messed up with this? – Shyam Habarakada Jun 11 '12 at 05:37
  • It says "Merge remote-tracking branch 'origin/email' into email". It does not mention staging. No big deal though. Just amend the commit, or use `merge -m 'This is not my beautiful house.' -s ours origin/email`. – cdunn2001 Jun 21 '12 at 22:15
  • @ShyamHabarakada , i do as you say , and i get the problem about non-fast-forward update . because nothing happens when i do the 4th step. – kommradHomer Nov 01 '12 at 10:08
  • 4th step requires you to use origin/email, it doesn't work with just local email. – Travis Reeder Jun 06 '13 at 16:48
64

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.

jsarma
  • 1,344
  • 11
  • 19
  • 1
    git push origin email --force didn't worked for me as Step2 left branches diverged. So after Step2, this is what I did: git reset origin/email and then git push – user3505394 Jul 01 '16 at 10:18
  • 12
    This is exactly what was asked in question - "how to overwrite rather than merge". Should be accepted answer. – jozols Feb 23 '18 at 14:18
  • 3
    If you still want to see the stuff in the email branch, just tag it before push, e.g., `git tag old-email-branch`. You will then be able to keep the previous stuff by the tagged version. – Yuci Feb 19 '21 at 14:57
54

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.

mjjf
  • 103
  • 4
B.Neo
  • 599
  • 4
  • 5
  • 10
    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. – Cameron Hudson Sep 30 '19 at 23:16
  • Will this create a problem with multiple people working with the branches? If they git pull email, will they now get the email branch that is its own branch but is identical, if no commits, the same as staging? – james emanon Aug 17 '21 at 04:31
  • I have no idea how this answers the question. – Guildenstern May 01 '23 at 16:06
21

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
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Madhu
  • 2,643
  • 6
  • 19
  • 34
11

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)

Manohar Reddy Poreddy
  • 25,399
  • 9
  • 157
  • 140
10

How about:

git branch -D email
git checkout staging
git checkout -b email
git push origin email --force-with-lease
frandroid
  • 1,343
  • 16
  • 26
Arek S
  • 4,239
  • 4
  • 24
  • 33
  • @emptywalls because it does a force push without warning the user that it can be rejected by the server, nor it explains why it's needed. That said, it's a viable option for a one-developer-project – David Costa Feb 17 '16 at 16:54
  • @DavidCosta why would this get rejected by the server? this is a simple delete email branch & copy staging to email'... So I just want to dump all the contents of 'staging' into 'email' so that they both point to the same commit' - that is exactly what is happening here. – Arek S Feb 18 '16 at 04:18
  • @ArekS it can be refused by a server side hook if the branch is set as "protected" e.g. in GitLab. Problem is that if someone else derived his branch from email before this operation and then tries to push, the references don't match anymore (because some commits simply vanished) – David Costa Feb 18 '16 at 09:27
  • 1
    I edited the original from --force to --force-with-lease, that does the trick in a non-destructive way. – frandroid Aug 11 '16 at 23:34
  • 1
    This is the best way if you just want to blow away a branch and start it clean from the source branch. – Shanerk Dec 21 '18 at 22:05
7

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
lenz
  • 2,193
  • 17
  • 31
  • Reading the [merge docs](https://git-scm.com/docs/git-merge). It looks like we cannot use `--strategy-option=theirs` – cgaldiolo Oct 05 '20 at 12:25
  • didn't work for me. results in conflicts although "theirs" is used. the accepted answer with first reverse merging using -s ours did work though. – Gottfried Jan 19 '21 at 11:06
1
git checkout email
git merge -m "Making email same as staging disregarding any conflicts from email in the process" -s recursive -X theirs staging
Willa
  • 730
  • 1
  • 7
  • 14
  • 2
    This answer would have been clearer to me if the comment was made separate from the merging comment in the command. Explain briefly what -X does and how it affects this merge. Thanks though. Made me look it up :) – noelicus Feb 14 '19 at 10:01
  • @noelicus thanks for the comment and you are right. I might edit the answer in the future. – Willa Feb 27 '19 at 17:23
1

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
Noah Nuebling
  • 219
  • 2
  • 11
0

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)
Jan Kyu Peblik
  • 1,435
  • 14
  • 20
0

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
zjk
  • 2,043
  • 3
  • 28
  • 45