TL;DR—here’s what I’ll do.
When my PR receives a maintainer’s approval, the commits from my fork will happily live inside the original repository; all is good. However, there are cases when a maintainer merges not via a merge commit, but by squashing or rebasing my changes.1
During a rebase, commits are “rewritten” even with the same diff. Git cannot put two and two together, so it will treat my commits as unique.
Now, when I make a new Pull Request for a different issue, those commits will persist! In Github, this messes the Pull Request interface (i.e., “why do I have commits for fixing Issue 1 when this PR is about Issue 2?”).
To add, Github’s “Fetch upstream” button performs a merge, making further Pull Requests dirty and riddled with stray commits—the worst case is to delete my fork and copy it again.
What I do
What I do is maintain a link to the original repository and track the changes from there. Before making a PR, I make sure to rebase those new changes to my fork.
First, let’s create a link to the original remote. You can call it
orig or whatever you want:
$ git remote add upstream https://github.com/com/original/original.git
You now have two remotes: one for your fork, and one for the original
repository. If you run
git remote -v, you will see the following:
$ git remote -v origin https://github.com/myusername/myfork.git (fetch) origin https://github.com/myusername/myfork.git (push) upstream https://github.com/original/original.git (fetch) upstream https://github.com/original/original.git (push)
Then, I track the remote branches by fetching them from the upstream:
$ git fetch upstream
Lastly, I go back to my fork’s default branch (usually it’s
main) then rebase the upstream’s changes to this branch.
$ git checkout main $ git rebase upstream/main
To fully sync my fork, I push the changes from my local to my remote:
$ git push origin +main
+ sign means that it’s a force push. It overwrites whatever you have in
your remote and rewrites the history to be similar as the original repo. You
will achieve similar results if you pass an
-f parameter like so:
# Same as above $ git push -f origin main
And that’s it! Our fork is now fully-synced with the original repository. The commits should match one-to-one, without merge commits nor strays .2 This is helpful to ensure that my fork is up-to-date with the codebase.
Hope you learned something new today!