Often beginner contributors face on their contribution path an issue when a PR contains commits the contributor didn't intend to include in the PR.
Let's assume that you have
- some repo (hereinafter
usptream
repo) forked to your account (hereinafterorigin
repo) - cloned locally (hereinafter local repo)
- added some changes
- committed those to local
master
- pushed changes to
origin/master
Now you can open a PR, and you do. The PR gets reviewed,
conflicts (if any) resolved, and things get merged into upstream
.
Things went smoothly and everybody is happy.
Now you want to contribute even more. So, you do the following:
- add changes
- commit to local
master
- push to
origin/master
- open a new PR
Oh, craps! PR now lists not only intended changes to add
but also commits that's been already merged into master before.
And upstream
maintainers ask you to get rid off those unnecessary
commits.
Ok. You've heard before that you have to use dedicated feature branches. So you trying to fix things you've done the following:
- close the bad PR
- undo the latest commits so
master
is exactly at the commit as it was at upon successful PR - checkout a feature branch (e.g.
feature
) - add changes
- commit to local
feature
- push to
origin/feature
- open a new PR
Oh, craps! The only difference now is that PR
mentions feature
branch instead of master
,
it contains exactly same commits as the last time.
You're in despair. But let's fix it and learn not to step on a rake any more.
Need to understand why it happened.
Let's assume that when you forked the upstream
its history was as follows:
* c4ebbab (origin/master, origin/HEAD, master) Add something else
* 0bb232d Add some code
* c040c31 Initial commit
So you add something and now you've got:
* 323043c Add Important contribution (origin/master, origin/HEAD, master)
* c4ebbab Add something else
* 0bb232d Add some code
* c040c31 Initial commit
Push, open PR, get approved and merged, done.
Now you contribute more which results in:
* 5446203 Add Next contribution (origin/master, origin/HEAD, master)
* 323043c Add Important contribution
* c4ebbab Add something else
* 0bb232d Add some code
* c040c31 Initial commit
Push, open PR, and... craps! Your PR lists commits 5446203
and
323043c
. Why that?
If you take a look at upstream
history you will note
that your commit saying Add Important contribution
has
different hash (this happened beacuse maintainers rebased
your commit(s) onto upstream's master and rebase always
creates a new commit even if the content wasn't changed).
So PR manager finds the most recent commit
that both usptream
and origin
share and adds the
remaining commits to the PR's scope. That's it.
git branch backup-feature
- to keep track of your current feature branch if anygit checkout master
git branch backup-master
- to keep track of yourmaster
- identify the most recent commit that both
usptream
andorigin
share (c4ebbab
in our example) git checkout c4ebbab
- move to the shared commitgit branch -f master
- movemaster
pointer forcedlygit checkout master
git push -f
- updateorigin
forcedly
The force actions above are actually bad practice. Never use those on shared repos unless you clearly understand consequences and your collaborators are aware of these actions.
git remote add upstream upstream-url.git
- add a remotegit pull upstream master
- update your local fromusptream
git push
- update yourorigin
from local
git branch -f feature-branch
- create or forcedly move a feature branch pointergit checkout feature-branch
- switch to the feature branch- add changes and
git commit -am "..."
orgit cherry-pick 5446203
- pick commits as appropriate, where5446203
is a commit containing changes you want to re-apply git push -f
- push feature branch (forcedly for the case you re-used branch name)
Now you are set to open a PR and live normal contributor's life further.
You do not need your back up branches, you also do not need
feature branches once changes get merged into upstream
.
Just remove backup-master
, backup-feature
and feature branches
with git branch -d <branch-name>
and
git push origin --delete <branch-name>
(from remote as well).
Need your changes back? Just sync with upstream/master
to have those back. The concise guide referred to below
covers the complete contribution workflow.
Was this helpful? Please, give this gist a ⭐.
This mean you need to find even earlier (before irreversible entanglements you managed to bring in) shared commit to start over with.
The flight rule No.1 is not to commit to fork's (origin
) master
.
Fork's master
should be updated from upstream
only.
For more details on better contribution workflow read the Contributing to a 3rd party repo for beginners guide
Thanks to Karasb888 for beta-testing and detailed feedback.