How do I recover/resynchronise after someone pushes a rebase or a reset to a published branch?

Aristotle Pagaltzis picture Aristotle Pagaltzis · Nov 3, 2010 · Viewed 15.5k times · Source

We have all heard that one should never rebase published work, that it’s dangerous, etc. However, I have not seen any recipes posted for how to deal with the situation in case a rebase is published.

Now, do note that this is only really feasible if the repository is only cloned by a known (and preferably small) group of people, so that whoever pushes the rebase or reset can notify everyone else that they will need to pay attention next time they fetch(!).

One obvious solution that I have seen will work if you have no local commits on foo and it gets rebased:

git fetch
git checkout foo
git reset --hard origin/foo

This will simply throw away the local state of foo in favour of its history as per the remote repository.

But how does one deal with the situation if one has committed substantial local changes on that branch?

Answer

Aristotle Pagaltzis picture Aristotle Pagaltzis · Nov 3, 2010

Getting back in synch after a pushed rebase is really not that complicated in most cases.

git checkout foo
git branch old-foo origin/foo # BEFORE fetching!!
git fetch
git rebase --onto origin/foo old-foo foo
git branch -D old-foo

Ie. first you set up a bookmark for where the remote branch originally was, then you use that to replay your local commits from that point onward onto rebased remote branch.

Rebasing is like violence: if it doesn’t solve your problem, you just need more of it. ☺

You can do this without the bookmark of course, if you look up the pre-rebase origin/foo commit ID, and use that.

This is also how you deal with the situation where you forgot to make a bookmark before fetching. Nothing is lost – you just need to check the reflog for the remote branch:

git reflog show origin/foo | awk '
    PRINT_NEXT==1 { print $1; exit }
    /fetch: forced-update/ { PRINT_NEXT=1 }'

This will print the commit ID that origin/foo pointed to before the most recent fetch that changed its history.

You can then simply

git rebase --onto origin/foo $commit foo