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!

TL;DR

  • Keep the forked master (preferably named 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 fetch upstream button.
  • BACKUP your local GitHub repo before doing enything presented here.

git train wreck image

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 Fetch upstream button on the GitHub web site:

github_fetch_upstream

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:

github_unable_to_squash_merge_commits

Now what?

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:

github_merge_mess.png

The ironic thing is I actually only wanted to make 2 tiny changes to two files:

github_merge_mess_desired_commit.png

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

Configure your 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 <jim@wolfssl.com>"

Other useful tidbits:

Ensure the execute bit is set for myfile:

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