There are lots of possible workflows for git, but the simplest one is in my experience also the most effective, and works from small teams to very large ones at Google and Facebook. This is sometimes known as trunk based development and I'll explain how it works below.
- There is one main branch - usually called master.
- This is always green on tests and never broken.
- All new changes are based off master
- There are no separate merge commits
Master/Head can be used as the base for all new changes, and is regularly updated as changes are released by developers. All developers have commit access, and the social contract is such that master is never broken. It can be used as a working release and for internal testing or development, and all new work is based off master. There may be release branches (used for back-porting bug fixes for example), and locally devs use feature branches for changes.
All new changes are based off master, and are usually done in a feature branch, though if small they may be worked on directly. When the change has been tested locally and is ready to go, it is rebased off master (optionally with some commits squashed and tidied up), it is then merged into master, resulting in a simple linear history on master of all work done, with tags to denote different releases. As a result, the master branch looks like this (example taken from the go language project at Google):
There are no merge commits, and no long-lived branches (apart from optional release branches, which exist to back-port bug fixes).
So the process for developing and committing code is:
- Pull latest origin/master
- Rebase feature branch off master
- Make changes to feature branch
- Run tests on feature
- When ready, share for code review
The developer may go through several cycles of this process as the code goes through code review. The process for final merging is:
- Pull latest origin/master
- Rebase feature off master, squashing if required
- Run tests
- Merge into origin/master
Release branches on the go project for example, look like this:
A branch off master at the time of the original release, which holds any new commits specific to that release. These can then be used for bug fix releases to that older code if required (typically on larger projects). Most smaller projects won't have to bother with this and can just get away with tagging releases.
Feature branches can actually be used with trunk based development as well, and often are locally while working on changes, but this style of using git has one important difference - it requires merge commits for merging feature branches in.
Some people like this because it gives a clear indication of when a branch has been checked in, and can make it easier to revert all changes from a branch.
I prefer to drop the historical artefacts which are branches and branch names and instead let commit comments speak for themselves in the history.
It means the repository can end up looking like a particularly kafkaesque subway map:
Another alternative is sometimes known as git flow - this suits a style of development where work continues on development versions of software over weeks or months, which are then after a long time merged onto master as releases. It is not very well suited if you want to practice continuous delivery and release small features frequently. It can be summarised by the following graphic:
Which tells you everything you need to know about gitflow. Image from nvie.com.
Github has introduced an interesting take on using git which requires users to clone (fork) repos, make all their changes, and then submit a pull request back to the original repo.
This does allow developers who have no access to the original repo to work on the code, and submit suggested changes, hence its popularity with open source projects and on github. The downsides are that it may mean changes are worked on in isolation without discussion with the original maintainer, then submitted as a large dump all at once.
I think if you have full control over your development process, it is simpler and more productive to use the trunk based development model, as it lets you release frequently and keep master up to date at all times, and results in a clean git history which is easy to read, and is free of artefacts from the development process. This system works well at the scale of Google as well as for small teams.