-
Notifications
You must be signed in to change notification settings - Fork 80
Git Pull Request Guide
This pull request guide will go over the tasks needed to maintain your PR ready to merge.
Before you contribute to the project, first you need to fork it to your github account
and then clone YOUR fork. You can do this using the github gh
CLI like this:
gh repo fork noobaa/noobaa-core
After your clone is complete, verify that your git remotes look like this (but with your github username instead of mine):
$ git remote -v
origin https://github.com/guymguym/noobaa-core.git (fetch)
origin https://github.com/guymguym/noobaa-core.git (push)
upstream https://github.com/noobaa/noobaa-core.git (fetch)
upstream https://github.com/noobaa/noobaa-core.git (push)
This means that you have 2 remotes defined - origin is YOUR fork on github, and upstream is the main noobaa repo on github. If you don't see the upstream remote you can add it like this:
git remote add upstream https://github.com/noobaa/noobaa-core.git
That's it - your fork is ready to use.
Whenever you are about to use the upstream branch as a base for new work, you will have to fetch new commits from github:
git fetch --all
Notice that this will not update local branches (e.g master), only remote branches (e.g upstream/master and origin/master), so after running that if new commits were added on the upstream, you will be able to list those commits with git log master..upstream/master --oneline
.
A useful variant of the fetch command allows to fast-forward local branches to match remote branches - the following will fetch upstream/master and then try to fast-forward local master to match it - if you keep your local master always "clean" (i.e you never update it from other sources) this will always succeed:
git fetch upstream master:master
After that, you might notice that origin/master is now out of sync with local master and upstream/master. You can then push from local master to origin/master to keep all 3 masters in full sync:
git push origin master:master
Before you are about to start working on your changes, make sure you are checking out a new branch. It is important not to mix your work with the master branches to avoid confusion. Before you create a new branch use fetch so that the new branch will be up to date:
git fetch --all
git checkout -b my-branch upstream/master
You can now work on the new branch and make your changes.
As you work on larger changes, it would be wise to commit your work and push to origin to have another backup of the work on github, and some history in case you need to keep some checkpoints along the way. Whenever you do that use:
git status
git add <files...>
git commit --signoff
Notice that --signoff
is needed for the PR checks to pass - see https://github.com/apps/dco.
At this point you can add short comments on the commits - these will not be used later and are just for your convenience.
Since the upstream keep on changing as you work locally, once in a while you should fetch and rebase your branch on top of the upstream:
git fetch --all
git rebase --signoff upstream/master
Git rebase will apply all your local commits, one by one, on top of the new upstream work. The more commits you have locally, and the more conflicts you have with upstream changes, the harder it gets to rebase. In some cases if you made many changes back and forth and kept checkpoint commits, it might become hard to rebase all those older local commits which are already obsolete - in these cases it is wise to squash the commits first and only then rebase.
Squashing commits means to combine multiple commits into one. The common way to do this is using interactive git rebase:
git fetch --all
git rebase -i --signoff upstream/master
The interactive rebase will open an editor with the list of commits and an action for each one - by default the action is pick
, and in the comment you will see all the possible actions that you can set for every commit. Notice that removing lines from the list of commits will DROP this commit from the resulting branch. To squash you should mark all the commits besides the first one with the s
action. After squashing you will always get a chance to edit the combined commit message to a meaningful message - so use it.
Another way to achieve this is with a soft reset which will reset the HEAD to point to the upstream commit, but leave all the changes on top of it as staged for commit:
git reset --soft upstream/master
git commit --signoff
Make sure your final commit message is looking good and descriptive. If you need to amend it use git commit --amend --signoff
when your git status is clean.
After rebase or squash we cannot simply push to the origin branch as usual because github will refuse to update the remote branch which seems to have a different history than the local branch. For that we need to use the force:
git push -f
Sometimes this can be dangerous to run push -f because it will override the current remote branch implicitly without making sure to which branch you really meant, so there is a similar syntax that allows to force the push by specifying the target branch:
git push origin +my-branch
When you are ready to open a pull-request and review the change, use the gh CLI or web to create a PR:
gh pr create [--web]
After you get review comments and make further code changes, you will again need to commit and rebase and squash. You can refer to this full flow:
git status
git add <files...>
git commit --signoff
git fetch --all
git rebase --signoff upstream/master
git reset --soft upstream/master
git commit --signoff