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, so that these instructions are not needed.
- Create a separate branch for each commit to upstream.
- Don’t use the web
- 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 messages 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 does a forced push. Use with caution!
MAKE A BACKUP BEFORE PROCEEDING
upstream to point to the upstream repo where you forked from:
git remote add upstream https://github.com/user/upstream_repo.git git fetch upstream
DANGER: Replace the master branch from upstream:
# 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
in the future, to refresh your fork with the upstream master
git fetch upstream git pull upstream 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.
git commit --amend --author="gojimmypi <email@example.com>"
Other useful tidbits:
Ensure the execute bit is set for
git add myfile --chmod=+x
I created a script for squashing commits; refresh main/master from upstream, refresh current branch to upstream, squash commits then push force
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
- Change author of commit
- gojimmypi Keeping a fork up to date
- stackoverflow How can I keep the execution permissions when cloning a repository in windows?