A Git Workflow is a recipe or recommendation for how to use Git to accomplish work in a consistent and productive manner. When working with a team on a Git managed project, it's important to make sure the team is all in agreement on how the flow of changes will be applied. To ensure the team is on the same page, an agreed upon Git workflow should be developed or selected.
- Centralized Workflow
- Feature Branch Workflow
- Gitflow Workflow
- Forking Workflow
The Centralized Workflow uses a central repository to serve as the single point-of-entry for all changes to the project. The default development branch is called master and all changes are committed into this branch. This workflow doesn't require any other branches besides master.
First, someone needs to create the central repository on a server. Central repositories should always be bare repositories (they shouldn't have a working directory), which can be created as follows:
ssh user@host git init --bare /path/to/repo.git
Note that the .git extension is conventionally appended to the repository name to indicate that it's a bare repository.
Next, each developer creates a local copy of the entire project. This is accomplished via the git clone command:
git clone ssh://user@host/path/to/repo.git
When you clone a repository, Git automatically adds a shortcut called origin that points back to the "parent" repository, under the assumption that you'll want to interact with it further on down the road.
Once the repository is cloned locally, a developer can make changes using the standard Git commit process: edit, stage, and commit.
git status # View the state of the repo
git add <some-file> # Stage a file
git commit # Commit a file</some-file>
Remember that since these commands create local commits, you can repeat this process as many times as you want without worrying about what's going on in the central repository.
Once the local repository has new changes committed. These change will need to be pushed to share with other developers on the project.
git push origin master
This command will push the new committed changes to the central repository. When pushing changes to the central repository, it is possible that updates from another developer have been previously pushed that contain code which conflict with the intended push updates. Git will output a message indicating this conflict. In this situation, git pull will first need to be executed. This conflict scenario will be expanded on in the following section.
The central repository represents the official project, so its commit history should be treated as sacred and immutable. If a developer's local commits diverge from the central repository, Git will refuse to push their changes because this would overwrite official commits.
Before the developer can publish their feature, they need to fetch the updated central commits and rebase their changes on top of them.
If local changes directly conflict with upstream commits, Git will pause the rebasing process and give you a chance to manually resolve the conflicts. The nice thing about Git is that it uses the same git status and git add commands for both generating commits and resolving merge conflicts. This makes it easy for new developers to manage their own merges. Plus, if they get themselves into trouble, Git makes it very easy to abort the entire rebase and try again (or go find help).
As you can see, it's possible to replicate a traditional Subversion development environment using only a handful of Git commands. This is great for transitioning teams off of SVN, but it doesn't leverage the distributed nature of Git.
The Centralized Workflow is great for small teams. The conflict resolution process detailed above can form a bottleneck as your team scales in size.
The Feature Branch Workflow assumes a central repository, and master represents the official project history. Instead of committing directly on their local master branch, developers create a new branch every time they start work on a new feature. Git makes no technical distinction between the master branch and feature branches, so developers can edit, stage, and commit changes to a feature branch.
All feature branches are created off the latest code state of a project. This guide assumes this is maintained and updated in the master branch.
git checkout master
git fetch origin
git reset --hard origin/master
This switches the repo to the master branch, pulls the latest commits and resets the repo's local copy of master to match the latest version.
Use a separate branch for each feature or issue you work on. After creating a branch, check it out locally so that any changes you make will be on that branch.
git checkout -b new-feature
This checks out a branch called new-feature based on master, and the -b flag tells Git to create the branch if it doesn't already exist.
On this branch, edit, stage, and commit changes in the usual fashion, building up the feature with as many commits as necessary. Work on the feature and make commits like you would any time you use Git. When ready, push your commits, updating the feature branch.
git status
git add <some-file>
git commit
It's a good idea to push the feature branch up to the central repository. This serves as a convenient backup, when collaborating with other developers, this would give them access to view commits to the new branch.
git push -u origin new-feature
This command pushes new-feature to the central repository (origin), and the -u flag adds it as a remote tracking branch. After setting up the tracking branch, git push can be invoked without any parameters to automatically push the new-feature branch to the central repository. To get feedback on the new feature branch, create a pull request in a repository management solution. From there, you can add reviewers and make sure everything is good to go before merging.
Now teammates comment and approve the pushed commits. Resolve their comments locally, commit, and push the suggested changes. Your updates appear in the pull request.
Before you merge, you may have to resolve merge conflicts if others have made changes to the repo. When your pull request is approved and conflict-free, you can add your code to the master branch.
Some key associations to make with the Feature Branch Workflow are:
- Focused on branching patterns
- Can be leveraged by other repo oriented workflows
- Promotes collaboration with team members through pull requests and merge reviews
The Gitflow Workflow defines a strict branching model designed around the project release. This provides a robust framework for managing larger projects. It assigns very specific roles to different branches and defines how and when they should interact. In addition to feature branches, it uses individual branches for preparing, maintaining, and recording releases.
Instead of a single master branch, this workflow uses two branches to record the history of the project. The master branch stores the official release history, and the develop branch serves as an integration branch for features. It's also convenient to tag all commits in the master branch with a version number.
The first step is to complement the default master with a develop branch. A simple way to do this is for one developer to create an empty develop branch locally and push it to the server:
git branch develop
git push -u origin develop
This branch will contain the complete history of the project, whereas master will contain an abridged version. Other developers should now clone the central repository and create a tracking branch for develop.
Each new feature should reside in its own branch, which can be pushed to the central repository for backup/collaboration. But, instead of branching off of master, feature branches use develop as their parent branch. When a feature is complete, it gets merged back into develop. Features should never interact directly with master.
Note that feature branches combined with the develop branch is, for all intents and purposes, the Feature Branch Workflow. But, the Gitflow Workflow doesn't stop there.
Feature branches are generally created off to the latest develop branch.
git checkout develop
git checkout -b feature_branch
Continue your work and use Git like you normally would.
When you've done with the development work on the feature, the next step is to merge the feature_branch into develop.
git checkout develop
git merge feature_branch
Once develop has acquired enough features for a release (or a predetermined release date is approaching), you fork a release branch off of develop. Creating this branch starts the next release cycle, so no new features can be added after this point-only bug fixes, documentation generation, and other release-oriented tasks should go in this branch. Once it's ready to ship, the release branch gets merged into master and tagged with a version number. In addition, it should be merged back into develop, which may have progressed since the release was initiated.
Making release branches is another straightforward branching operation. Like feature branches, release branches are based on the develop branch. A new release branch can be created using the following methods.
git checkout develop
git checkout -b release/0.1.0
git checkout develop
git merge release/0.1.0
Maintenance or "hotfix" branches are used to quickly patch production releases. Hotfix branches are a lot like release branches and feature branches except they're based on master instead of develop. This is the only branch that should fork directly off of master. As soon as the fix is complete, it should be merged into both master and develop (or the current release branch), and master should be tagged with an updated version number.
Having a dedicated line of development for bug fixes lets your team address issues without interrupting the rest of the workflow or waiting for the next release cycle. You can think of maintenance branches as ad hoc release branches that work directly with master. A hotfix branch can be created using the following methods:
git checkout master
git checkout -b hotfix_branch
Similar to finishing a release branch, a hotfix branch gets merged into both master and develop.
git checkout master
git merge hotfix_branch
git checkout develop
git merge hotfix_branch
git branch -D hotfix_branch
Some key takeaways to know about Gitflow are:
- The workflow is great for a release-based software workflow.
- Gitflow offers a dedicated channel for hotfixes to production.
The Forking Workflow is fundamentally different than other popular Git workflows. Instead of using a single server-side repository to act as the "central" codebase, it gives every developer their own server-side repository. This means that each contributor has not one, but two Git repositories: a private local one and a public server-side one. The Forking Workflow is most often seen in public open source projects.
All new developers to a Forking Workflow project need to fork the official repository. As previously stated, forking is just a standard git clone operation. It's possible to do this by SSH'ing into the server and running git clone to copy it to another location on the server. Popular Git hosting services like Bitbucket, offer repo forking features that automate this step.
Next each developer needs to clone their own public forked repository. They can do this with the familiar git clone command.
Assuming the use of Bitbucket to host these repositories, developers on a project should have their own Bitbucket account and they should clone their forked copy of the repository with:
git clone https://[email protected]/user/repo.git
Whereas other Git workflows use a single origin remote that points to the central repository, the Forking Workflow requires two remotes-one for the official repository, and one for the developer's personal server-side repository. While you can call these remotes anything you want, a common convention is to use origin as the remote for your forked repository (this will be created automatically when you run git clone) and upstream for the official repository.
git remote add upstreamhttps://bitbucket.org/maintainer/repo
You'll need to create the upstream remote yourself using the above command. This will let you easily keep your local repository up-to-date as the official project progresses. Note that if your upstream repository has authentication enabled (i.e., it's not open source), you'll need to supply a username, like so:
git remote add upstream https://[email protected]/maintainer/repo.git
This requires users to supply a valid password before cloning or pulling from the official codebase.
In the developer's local copy of the forked repository they can edit code, commit changes, and create branches just like in other Git workflows:
git checkout -b some-feature
# Edit some code
git commit -a -m "Add first draft of some feature"
All of their changes will be entirely private until they push it to their public repository. And, if the official project has moved forward, they can access new commits with git pull:
git pull upstream master
Since developers should be working in a dedicated feature branch, this should generally result in a fast-forward merge.
Once a developer is ready to share their new feature, they need to do two things. First, they have to make their contribution accessible to other developers by pushing it to their public repository. Their origin remote should already be set up, so all they should have to do is the following:
git push origin feature-branch
This diverges from the other workflows in that the origin remote points to the developer's personal server-side repository, not the main codebase.
Second, they need to notify the project maintainer that they want to merge their feature into the official codebase. Bitbucket provides a "pull request" button that leads to a form asking you to specify which branch you want to merge into the official repository. Typically, you'll want to integrate your feature branch into the upstream remote's master branch.
The Forking Workflow helps a maintainer of a project open up the repository to contributions from any developer without having to manually manage authorization settings for each individual contributor. This gives the maintainer more of a "pull" style workflow. Most commonly used in open-source projects, the Forking Workflow can also be applied to private business workflows to give more authoritative control over what is merged into a release. This can be useful in teams that have Deploy Managers or strict release cycles.