This document contains some guidelines on how we use git and GitHub at QuantStack.
TODO
TODO
You will need to do the following every time you start working on an existing project, this needs to be done only once.
First, you need to create a fork of the original project, which we call upstream, under your Github account, we will call this fork origin.
For example, if you want to start contributing to Voila, go to https://github.com/voila-dashboards/voila and press the fork button then select your username.
Now that you forked the project, you will need to clone it on your computer in order to start hacking. To do this, you will need to run the following command (replacing username by your Github name):
This will create a local voila
directory containing your copy of the Voila repository.
git remote
Now you need to tell git what is the upstream repository.
If you run git remote -v
, you should now see the upstream and origin urls:
Now that your local clone is setup, you can start hacking!
Important!
You should never commit changes to the master
(or main
) branch, unless you are making a release, but we'll come to it later.
When adding a new feature or adding a bug-fix, the first thing to do is create a new branch:
A set of good rules to follow for branches:
Now that your branch is created you can start hacking. I cannot help you in this section ;)
You can visualize your current work with:
This will show you the files that are tracked by git and their status (modified/deleted), it will also show you the list of files that are here but not tracked by git:
You can also see a diff with:
To stage a file for a commit, you can do
I recommend not using git add .
, because this will add all untracked files which is usually not what you want.
If you added a file by mistake, you can remove it from the stage index with the following:
Now you can commit your work. In order to commit all staged files you can just do:
This will prompt for a commit message. It is important to give a meaningful commit message that explains what it does (e.g. "Fix bug" does not explain what it does, "Fix missing positional argument in sqrt function" is better).
You can also commit and fill the commit message with a single command:
In the case where you have too many files modified, it is very annoying to stage files one by one, instead you can ask git to commit all of your work:
This will commit all tracked files and discard untracked files.
It is possible that you want to modify the message in your latest commit, or you want to add additional changes to it.
The --amend
option is very useful in that case.
Say you forgot to add your changes to the setup.py
file in your latest commit, you can just do:
This will prompt you for a commit message, you will see the old message and be able to modify it.
git
provides a command to list the commits of your branch:
You can hit ENTER
to scroll down. Use :q
to exit.
Once you've commited all your changes, it is time to push them to your fork:
You can now go to the Github upstream repo (for instance https://github.com/voila-dashboards/voila), you should see a yellow rectangle allowing you to open a pull request, you can now click on "Compare & pull request".
If not, go the Github origin repo (i.e. your fork), select your branch in the dropdown menu on the left, then contribute and Open a Pull Request.
Explain what your Pull Request (PR) is about, you can reference issues or sometimes just follow the PR template provided by the repo. Then validate to open the PR.
Once the maintainers of the project have merged the PR, your changes are available in the master (or main) branch of the project. It is time to update both your fork and your local clone:
You can now safely delete the branch you used for hacking:
It may happen that your branch <branch_name>
gets outdated and is behind master
by a number of important commits (e.g. commits that fix the CI). In that case, maintainers may ask you to "rebase" your branch in order to update your PR before it can be merged.
Rebasing on master
means applying all your commits on top of the current state of master
. Rebasing also gives the opportunity to edit/reorder/squash commits.
In order to rebase, you will first need to update your master
branch:
Then, check out your dev branch again, and rebase it:
Git will try to apply each commit from <branch_name>
to the master branch.
When a commit leads to a conflict that git cannot resolve by itself, the rebase process stops in an intermediate state, waiting for you to solve it. You will need to follow the next section on resolving conflicts, then resume the rebase:
Then solve the conflicts and save the file(s). When all the conflicts are solved, you can resume the rebase process:
After rebasing, you need to push the changes to your fork:
Do not forget the -f
option (for --force
, otherwise git will output the following error message:
If you want to abort the rebase process (for any reason), just run
This will restore the original state of <branch_name>
You may read some doc where people merge master
into <branch_name>
instead of rebasing <branch_name>
onto master
. We consider it as bad practice as it introduces meaningless merge commits and may make future rebase more complicated. Therefore git merge
is highly discouraged at QuantStack.
Sometimes Github will complain it cannot open/merge a PR because your changes conflict with the files in the master branch. This is because some changes were merged into master after you created your branch and you started hacking. To solve this issue, you need to follow steps from the earlier section on "rebasing", then you will need to solve the conflicts locally when the rebase step prompts for solving conflicts.
To start the tool to solve conflict, run:
This will opened the merge tool you configured in .gitconfig
.
Git will create a merge commit with your changes, and open a prompt so that you can enter a commit message.
NB: if you cannot solve the conflicts because you don't understand the changes made in master, then you should probably abort the rebase and ask for help to the author of the changes.
There are many reasons for removing commits from a branch: you pushed a lot of commits to debug and fix some CI errors, you want to gather commits together because they are related, etc.
First, checkout your branch:
Then you will perform an interactive rebase:
Git will open a window listing all the commits of your branches that are not in the master branch. Then you can tell git what to do with each commit:
Many other options are available and are described in the comment under the list of commits. When you are happy, save and exit. This will terminate the rebase.
NB: keep in mind than an interactive rebase is a rebase; therefore, if there are conflicts with the branch you rebase on, you will have to solve them to complete the rebase process.
NB: if you have a lot of commits in your branch and you know you only need to work on the last 5 commits, you can run the following
instead of rebasing on master. Git will display only the last five commits in the prompt instead of all the commits in your branch since master.
Assume you created a branch for experimenting, let's call it exp_branch
. Then you created another branch to develop a new feature, let's call it feat_branch
. At some point, you realize that there is a commit in exp_branch
that you need in feat_branch
. You can pick the commit in feat_branch
thanks to the cherry-pick
feature.
First you need to get the hash of the commit.
Then you can pick the commit in your feat_branch
:
You don't need to provide the full hash of the commit, most of the times the first characters are enough.
Assume you developed a feature in a dedicated branch, named base_feature
. Then you started developing another feature in another branch, advanced_feature
. At some point, you realise that advanced_feature
needs everything form base_feature
. Besides, opening a single PR with all the changes instead of one per branch would make more sense.
What you can do is rebase the advanced_feature
branch on top of the base_feature
branch. This way, the advanced_feature
will contain the commits from the base_feature
branch, followed by its own commits.
If you pushed your branch before rebasing, you will need to force the next push:
You can now safely delete the base_feature
branch:
Notice the -D
instead of -d
. With -d
, git would complain that the branch has not been merged into master and would prevent its deletion. -D
forces git to delete it..
TODO
You can modify your git config to improve your workflow. Your .gitconfig
file should be located in your $HOME
directory.
You can tell git which is your favorite editor for editing commit messages.
For example, if you want to use vim
:
For slow-typists and lazy people, you can create your set of alias so you have less to type. It is up to you to decide for your aliases, but as an example I will give away my config:
This allows me to type git co master
instead of git checkout master
.
trainings