Redsandro
Redsandro

Reputation: 11356

Github: Fetch and rebase fork on forked master

I've created a fork of a project, and added ~40 commits to our master. At some point in time I thoughtlessly rewrote history with a forced push because I couldn't push "for no reason at all" and sometimes you just want to see the world burn.

Now everything is fine, but the last ~100 commits on upstream that are also on my repo are no longer considered the same: I'm seeing "240 commits ahead" in stead of "40 commits ahead".

Is it possible to fetch the upstream master and rebase our master's commits on it, and force-push it back to our master so that ours and theirs are in sync for all previous commits except mine? If so, how? Please be specific.

Upvotes: 2

Views: 1391

Answers (1)

joanis
joanis

Reputation: 12221

I assume you have a clean sandbox where origin points to your fork, and you have access to the upstream repo via a different URL. I also assume origin/master and master in your sandbox are in sync.

With these assumptions, this should work:

git remote add upstream <upstream_url>
git fetch upstream
git checkout master
git rebase upstream/master

Hopefully the rebase will work and not introduce any duplicate commits. If it doesn't, it might even highlight why you had to force push in the first place.

Before you start the rebase, git log --graph --decorate --all (or gitk -all or any other visual Git log replacement that shows the full graph) might show you why you had trouble.

EDIT: an alternative and more conservative approach is to use git cherry-pick. The rebase solution relies on Git recognizing that the history that should be common consists of commits already present on upstream/master. But instead of rebasing, you can identify the parent of the 1st commit you want to keep, let's say origin/master~40 if you really have exactly 40 commits to keep, and add those commit at the end of upstream/master:

git remote add upstream <upstream_url>
git fetch upstream
git checkout master
git reset --hard upstream/master
git cherry-pick origin/master~40..origin/master

This gives you a new master that explicitly starts at upstream/master and adds just the new history you want.

Note the --hard in git reset --hard upstream/master: as pointed out by OP in the comments, this is needed to make sure you start from a clean state before cherry-picking. But first make sure you didn't have anything uncommitted you wanted to save.

Sanity check: after the cherry-pick (or the rebase), git diff master origin/master should return nothing, or again point you to other problems you need to handle. END EDIT

Once the rebase or cherry-pick is complete and you've thoroughly convinced yourself this new history is what you want to keep:

git push -f origin master

should bring your fork back to having just 40 commits ahead of upstream.

Caveat: I did not test the rebase solution, but I'm fairly confident it should work, based on your description of the situation. I've used the cherry-pick solution with success is similar situations, however. If you try either method, please report back on your success or anything wrong that would need adjustment.

Upvotes: 2

Related Questions