Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git rebase complication

Tags:

git

Our off-shore developers accidentally merged a release branch into master before we were ready to release. This left us with no master branch, and no ability to release hotfixes. I tried to fix this with a rebase, but don't quite understand what happened, I'm hoping someone can explain it. (And if there was a better way to do this)

Release branch was created from master (at point A),
several feature branches merged into it (creating point B). - so far so good.
Release branch merged into master (bad!) fast-forwarding master to point B.
work done on master (hotfixes, correct) bringing master to point C (from B).
work done on Release (bugfixes, correct) bringing Release to point D (from B).

what I wanted to achieve was to bring the changes from B to C onto point A, so that the changes from A to B are not included in point C any more (but point D remains unchanged).

I created a new branch from point A (new_Master), and did this:
git rebase --onto new_Master Release master

That did what I wanted, ie created a few new changesets after point A on new_Master (bringing it to point E), but it left the new_Master branch at point A, and I could not figure out how to move the label up to the new HEAD. It also left the master branch at the old point C, but I was expecting it to roll back to point B at least, as those changes aren't supposed to be there at all any more. So I've ended up with two checkins that represent the same changes, one set a child of A, and one a child of B.

Questions: 1) How do I move the new_Master label to point E.
2) How do I commit and push these changes to get them to the rest of the team?
3) Why does master still sit at point C? (And why does point C still exist at all?)
4) How can I get the master label to move to point E (if possible) - which is on a different branch now?
5) This is clearly not how this was supposed to be done - so what was the right way to fix the mistake made by merging Release into master?

Original graph
C D (Master C, Release D)
3 |
| 2
B/
1
A

Final graph
E
3
| C D (Master C, Release D)
| 3 |
| | 2
| B/
| 1
|/
A (new_Master)

Where I was trying to be:

E (Master, ideally, I'd be happy with new_Master pointing here))
3
| D (Release)
| 2
| B
| 1
A/

like image 315
Ryno Avatar asked Feb 22 '26 09:02

Ryno


1 Answers

1) git checkout new_Master followed by git reset --hard <sha1 of E>.

2) Depends what you want to share with your team. If you just want to share the new brach new_Master then you can obviously do something like git push origin new_Master, although I'm guessing you're more interested in getting master back to how it should be on the main repo? If so, you can do the following (with all the usual warnings about rebasing publicly visible branches)

Forcibly overwrite the broken master in your main repo with your new, correct new_Master (again, be doubly sure you know what's happening here)

git push origin new_Master:master -f

Then, get each person using the repo to do the following at home:

git checkout master
git reset --hard <sha1 of A>
git pull origin master

This will leave them with a master branch that looks like your new new_Master branch.

3) git rebase --onto new_Master release master should've changed master to point to E. I'm not sure what happened here.

4) git reset --hard <sha1 of E> while on master. Note that you wont be able to push master in your local repo into your shared repo as the histories will have diverged (see 2)

5) Yep. Here we go:

Get onto master so we can make a branch from it

git checkout master 

Create a branch from C so we don't lose the reference to it in the next step

git branch master_backup 

Move master back to A. We won't lose C because of the last step.

git reset --hard <sha1 for A>

Then add the changes from B to C onto master. Here the release master_backup specifies "Find the common ancestor of release and master_backup (B) and take all commits from there up until wherever master_backup is pointing (C)"

git rebase --onto master release master_backup
git checkout master
get merge master_backup

master now contains everything up to A, as well as the commits introduced between B and C. release, as far as I can tell, should still be exactly where you want it to be and require no changes.

like image 192
Shaun O'Keefe Avatar answered Feb 24 '26 22:02

Shaun O'Keefe