Simple git development workflow


Git and git based platforms have become ubiquitous for versioning in software development. At same time since git is a powerful tools with many features, there is no one official way of using git. Searching for "git branching model" produces articles with sometimes contradictory information, which can be confusing, particularly for new users.

This post aims to summarize standard git practices that are used in open-source projects, and in particular in the scientific Python community. The described workflow is a variation of "Github flow" as was popularized by Github. It aims to be simple, and easy to understand starting point with one recommended way of doing things, while allowing to be adjusted as needed for more complex situations and deployment scenarios.

Main ideas

The general idea of git workflow based on feature branches is illustrated on the following figure.

The main development branch is master which should always contain a working version of the code and be ready to be deployed. To make additions to the code, one would create a new branch for each feature or bug fix being worked on, and make a Pull Request (PR), a request to include the code in master. For instance,

git checkout master
git checkout -b feature-1
# Make code changes
git commit -a -m "Adding feature 1"
git push

Once the Pull Request passes quality controls checks, including automatic checks and manual code review it can be merged into master. It is recommended to use Continious Integration (CI) to automatically run unit tests and code style linters on each commit.

To make releases and deploy, one would create a tag on master, e.g.

git checkout master
git tag v0.1.0
git push origin v0.1.0

Notes:

  • When merging PR you should squash commits ("Merge & Squash" button on Github). This allows to obtain only one commit on master per pull request, which helps keeping history clean, and facilitate backporting of changes to other branches.
  • You should give self explanatory names to feature branches. For instance for a bug fix that fixes overflow error in sparse matrices, the branch name could be fix-overflow-sparse.
  • To synchronize or resolve conflicts in a feature branch, merge master in: git fetch origin && git merge origin/master Don't rebase or rewrite history in PRs, as that would make reviewing consecutive changes in PRs more difficult.
  • Do not forget to always return to master (git checkout master) before creating new branches.

Working with forks, and contributing to open-source projects

It frequently happens that one needs to contribute to a project without having write access to its repository. This is in particular the case for most open-source projects.

In this case Github, Gitlab and other git hosting platforms have a mechanism of forks. That is a to make a copy of the repository to a location that you can edit (origin), from which you can make Pull Requests to the main repository (upstream).

The workflow in this case, illustrated on the following figure is very similar to that of the previous section. One still creates feature branches, except that PRs are made to the upstream repository master branch.

To synchronize your fork's master with changes in the upstream repository, one would do,

git remote add upstream <upstream-repo-url>  # just once
git fetch upstream
git checkout master
git rebase upstream/master

Pull Requests can be synchronized with a similar apporach, except that one would use,

git merge upstream/master

instead of a rebase.

Notes:

  • never make Pull Requests from your forks' master branch, always create a specific feature branch.
  • Once a Pull Request is merged, its branch can be deleted.

Adding release branches

For larger projects, it might be useful to add bug fix releases that don't include new features.

In this case, we can create a release branch originating from the latest release tag. Both new features and bug fixes are first contributed to master, then bug fixes are backported using e.g. git cherry-pick <commit-hash> to the release branch.

Then a new tag is added on the release branch to make a new release.

Conclusions

We have reviewed a simple git workflow that can be used for new projects or to start contributing to open-source projects. For a more detailed discussion about git branching models, see for instance the initial GitLab flow article.