The size of the team determines how you use Git. Let’s define teams as small (up to 2 members), medium (5 to 9 members) and large (>9 members).
Each team member has a role of either Repository Contributor or Maintainer: Contributors only have read access to the repository. They are allowed to clone it but not commit to it. They contribute by submitting pull requests. Maintainers inherit the role of Contributors and additionally have write access, meaning they can commit. They are also responsible to integrate pull requests.
In small teams each member is a Maintainer with full read/write access to the repository. Ideally they do mutual code reviews.
In Midsized teams you have two or three Maintainers which are often the most senior members of the team. They review pull requests coming from Contributors.
Large teams of developers have many Maintainers which are assigned to repositories of sub projects within an overarching project. Contributors will feed their changes to those Maintainers via pull requests.
In some large teams (such as Linux development) a Benevolent Dictator Workflow is used: Contributors submit pull requests to Maintainers which in turn submit pull requests to the Dictator Repository.
Master and Develop are commonly long running branches that remain open and receive regular merges. Feature branches are short lived branches created for a particular feature. They get merged in Developer branch. Hotfix branches are created off of the Master to quickly apply a patch to a production environment. They are then merged into other long running branches.
In a Trunk-Based development (TBD) workflow there is only one long running branch (the trunk) which is used for pulling, syncing and merging. Occasional Release branches are allowed. In general branching from trunk, such as when using a feature branch, is not acceptable. With few exceptions developers commit directly to trunk. The selling point behind TBD is that it reduces problems that would occur when merging long-lived branches, such as breaking the build, duplicate work and incompatible changes. To make TBD work you have to commit small commits on a daily basis. You have to organize your work in small tasks. The goal is to have trunk as close to release-ready as possible. Every time the build is broke, teams do anything to fix it. This workflow profits from a tightly integrated CI/CD infrastructure, which does not deploy broken builds or rolls back to a previous version automatically.
Git Flow workflow is based around releases using two long lived branches Master and Develop. Master is a copy of the current production code and is tightly controlled by Maintainers that only allow changes via Pull Requests. Develop is the parent branch of feature branches that should be short lived. When enough features are developed a Release branch is created. Bugfixing in Release can be done in parallel with new work being performed in Develop. Release is merged into Master after the code is sent to production. Finally Develop is synced with Release. Additionally Hotfix branches are created from Master to fix production bugs and are finally merged back into Master and Develop. Master and Develop must be access protected to only allow Maintainers to merge.
You can use standard Git commands but it is recommended to install GitFlow scripts that make working with GitFlow much simpler. After installation you run
git init and
git flow init. The latter installs git hooks and also gives you the chance to define custom branch names for GitFlow.
A Feature branch is where your work for a specific feature is done.
Here are some reasons why we should not simply want all our work done on the main branch:
- It is difficult to track your work on the main branch, separation from one feature to the other is difficult
- Difficult to manage merges. Imaging you only want to have specific features in the main branch, then you would have to cherry pick your commits
- It is difficult to back out: What if you find out half-way that your approach of implementing the feature was wrong? It is difficult if not impossible to undo all your changes that you already committed to the main branch
- Without feature branches it is difficult to experiment with features
A developer starts a feature with
git flow feature start feature-name and commits changes as usual. To make the feature branch available on the remote repository the developer runs
git flow feature publish feature-name.
A reviewer could now run
git flow feature track feature-name to pull the remote branch, track it locally and switch to it – all with one command. Reviewer can now commit changes and
git push the changes back to the remote repository.
The developer can now
git pull changes made by the reviewer. Once the feature is done the developer runs
git flow feature finish feature-name which will merge the feature back into develop as well as check out develop. This command also deletes the feature branch locally and remotely! But it still exists locally for reviewer who has to delete it with
git branch -d feature-name.
git flow release start release-name will create a release branch and check it out locally. To set up a tracking branch and pushing it remotely you run
git flow release publish release-name.
Developer can pull and check out the release with
git flow release track 'release-name'. Bugfixes are committed and
git push as usual. The release has to be merged into develop with
git checkout develop and
git merge release/release-name. You need to
git push those local changes to the remote repository.
git flow release finish release-name will merge the changes into local master branch, tag the release, merge it back into local develop, delete the release locally and remotely and switch back to develop. Now
git checkout master and
git push --tags, because we also want to push the tags.
git flow hotfix start hotfix-name will create
hotfix/hotfix-name based on master and switch to it. Developer commit hotfix and run
git flow hotfix finish hotfix-name which will merge the hotfix into master, tag the hotfix, merge it back into develop, locally delete it and switch to branch develop. Now push those local changes of two branches to remote with
git push --all origin.