When things go really sideways and the GitHub master branch of a fork is so terribly messed up and the changes are not even desired, there’s hope!
- Keep the forked
main) branch clean from incremental merge or update commits, to not need these instructions.
- Create a separate branch for each commit to upstream
- Don’t use the web “fetch upstream` button
- BACKUP your local GitHub repo before doing enything presented here.
How I got into this mess: some time ago, I had forked a repo. No big deal. Occasionally I would keep my fork updated by clicking the
button on the GitHub web site:
Don’t do this!!
The problem with doing the
fetch upstream is that it adds that to your commit history. No big deal right? As that’s actually part of, well, the history.
The issue is when you want to contribute to that upstream repo, and the maintainers politely and expectedly ask to “please squash your commits”. Easy enough?
Nope. If there are merge commits and you try to squash, GitHub gives an error:
The first time this happened, I was able to reset the head and fetch from the upstream repo without too much problem. Easily said, it actually took quite some time.
So when I encountered what seemed to be the same problem, I tried the same solution. No joy. It was a much longer period of time with meges and commits, and a total of 15 commits that were simply impossible to squash. So I tried to fix it. Here’s what I started with:
The ironic thing is I actually only wanted to make 2 tiny changes to two files:
My attempts to “fix” that didn’t go so well. I ended up with over a thousand commits that I didn’t want. Somehow my name ended up associated with ALL of the commits from the point I tried to undo. from way back last summer. sigh.
The most radical
git --untangle-mess I’ve ever done was to replace the entire main (master) branch with the upstream contents.
Once again, SO to the rescue: How to replace master branch in Git, entirely, from another branch - the
second answer, using
git branch -m, but checking out the upstream master:
DANGER: This completely wipes out the master branch and doed a forced push. Use with caution!
MAKE A BACKUP BEFORE PROCEEDING
upstream to point to the upstream repo where you forked from.
# you should be starting with a fresh git clone on the master branch # checkout the upstream master git checkout upstream/master # create and switch to a branch called newmaster git switch -c newmaster # set the upstream origin to new master git push --set-upstream origin newmaster # move the master branch to oldmaster git branch -m master oldmaster1 # move the new master (the checkout from upstread) to master git branch -m newmaster master # force push these changes git push -f origin master
Hopefully this will work for others. It did for me. I’ll never again work on anything but my own branches. Lesson learned.
In the end, I did finally create my clean PR.
Resources, Inspiration, Credits, and Other Links
- git rebase docs
git resetideas: Squash my last X commits together using Git
- more on
git reset: Delete commits from a branch in Git
- still more
git reset: How to permanently remove few commits from remote branch
- Overwrite everything in master with another branch in git
- Clean up a fork and restart it from the upstream