Git Workflow
by GitBucket
Last updated
Was this helpful?
by GitBucket
Last updated
Was this helpful?
A Git Workflow is a recipe or recommendation for how to use Git to accomplish work in a consistent and productive manner. Git workflows encourage users to leverage Git effectively and consistently. Git offers a lot of flexibility in how users manage changes. Given Git's focus on flexibility, there is no standardized process on how to interact with Git. 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. There are several publicized Git workflows that may be a good fit for your team. Here, weβll be discussing some of these workflow options.
The array of possible workflows can make it hard to know where to begin when implementing Git in the workplace. This page provides a starting point by surveying the most common Git workflows for software teams.
As you read through, remember that these workflows are designed to be guidelines rather than concrete rules. We want to show you whatβs possible, so you can mix and match aspects from different workflows to suit your individual needs.
When evaluating a workflow for your team, it's most important that you consider your teamβs culture. You want the workflow to enhance the effectiveness of your team and not be a burden that limits productivity. Some things to consider when evaluating a Git workflow are:
Does this workflow scale with team size?
Is it easy to undo mistakes and errors with this workflow?
Does this workflow impose any new unnecessary cognitive overhead to the team?
β
The Centralized Workflow is a great Git workflow for teams transitioning from SVN. Like Subversion, the Centralized Workflow uses a central repository to serve as the single point-of-entry for all changes to the project. Instead of trunk
, 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
.β
Transitioning to a distributed version control system may seem like a daunting task, but you donβt have to change your existing workflow to take advantage of Git. Your team can develop projects in the exact same way as they do with Subversion.β
However, using Git to power your development workflow presents a few advantages over SVN. First, it gives every developer their own local copy of the entire project. This isolated environment lets each developer work independently of all other changes to a project - they can add commits to their local repository and completely forget about upstream developments until it's convenient for them.β
Second, it gives you access to Gitβs robust branching and merging model. Unlike SVN, Git branches are designed to be a fail-safe mechanism for integrating code and sharing changes between repositories. The Centralized Workflow is similar to other workflows in its utilization of a remote server-side hosted repository that developers push and pull form. Compared to other workflows, the Centralized Workflow has no defined pull request or forking patterns. A Centralized Workflow is generally better suited for teams migrating from SVN to Git and smaller size teams.β
β
Developers start by cloning the central repository. In their own local copies of the project, they edit files and commit changes as they would with SVN; however, these new commits are stored locally - theyβre completely isolated from the central repository. This lets developers defer synchronizing upstream until theyβre at a convenient break point.β
To publish changes to the official project, developers "push" their local master
branch to the central repository. This is the equivalent of svn commit
, except that it adds all of the local commits that arenβt already in the central master
branch.β
Git Workflow: Initialize Central Bare Repositoryβ
First, someone needs to create the central repository on a server. If itβs a new project, you can initialize an empty repository. Otherwise, youβll need to import an existing Git or SVN repository.β
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
β
Be sure to use a valid SSH username for user
, the domain or IP address of your server for host
, and the location where you'd like to store your repo for /path/to/repo.git
. Note that the .git
extension is conventionally appended to the repository name to indicate that itβs a bare repository.β
β
Central repositories are often created through 3rd party Git hosting services like Bitbucket Cloud or Bitbucket Server. The process of initializing a bare repository discussed above is handled for you by the hosting service. The hosting service will then provide an address for the central repository to access from your local 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. If youβre not familiar with the staging area, itβs a way to prepare a commit without having to include every change in the working directory. This lets you create highly focused commits, even if youβve made a lot of local changes.
β
Remember that since these commands create local commits, John can repeat this process as many times as he wants without worrying about whatβs going on in the central repository. This can be very useful for large features that need to be broken down into simpler, more atomic chunks.β
β
Once the local repository has new changes committed. These change will need to be pushed to share with other developers on the project.
β
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.β
β
Before the developer can publish their feature, they need to fetch the updated central commits and rebase their changes on top of them. This is like saying, βI want to add my changes to what everyone else has already done.β The result is a perfectly linear history, just like in traditional SVN workflows.β
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).β
β
Letβs take a general example at how a typical small team would collaborate using this workflow. Weβll see how two developers, John and Mary, can work on separate features and share their contributions via a centralized repository.β
In his local repository, John can develop features using the standard Git commit process: edit, stage, and commit.β
Remember that since these commands create local commits, John can repeat this process as many times as he wants without worrying about whatβs going on in the central repository.β
Meanwhile, Mary is working on her own feature in her own local repository using the same edit/stage/commit process. Like John, she doesnβt care whatβs going on in the central repository, and she really doesnβt care what John is doing in his local repository, since all local repositories are private.β
Once John finishes his feature, he should publish his local commits to the central repository so other team members can access it. He can do this with the git push
command, like so:
β
Remember that origin
is the remote connection to the central repository that Git created when John cloned it. The master
argument tells Git to try to make the origin
βs master
branch look like his local master
branch. Since the central repository hasnβt been updated since John cloned it, this wonβt result in any conflicts and the push will work as expected.β
Letβs see what happens if Mary tries to push her feature after John has successfully published his changes to the central repository. She can use the exact same push command:
β
But, since her local history has diverged from the central repository, Git will refuse the request with a rather verbose error message:
β
This prevents Mary from overwriting official commits. She needs to pull Johnβs updates into her repository, integrate them with her local changes, and then try again.β
Mary can use git pull
to incorporate upstream changes into her repository. This command is sort of like svn update
βit pulls the entire upstream commit history into Maryβs local repository and tries to integrate it with her local commits:
β
The pull would still work if you forgot this option, but you would wind up with a superfluous βmerge commitβ every time someone needed to synchronize with the central repository. For this workflow, itβs always better to rebase instead of generating a merge commit.β
Rebasing works by transferring each local commit to the updated master
branch one at a time. This means that you catch merge conflicts on a commit-by-commit basis rather than resolving all of them in one massive merge commit. This keeps your commits as focused as possible and makes for a clean project history. In turn, this makes it much easier to figure out where bugs were introduced and, if necessary, to roll back changes with minimal impact on the project.β
If Mary and John are working on unrelated features, itβs unlikely that the rebasing process will generate conflicts. But if it does, Git will pause the rebase at the current commit and output the following message, along with some relevant instructions:
The great thing about Git is that anyone can resolve their own merge conflicts. In our example, Mary would simply run a git status
to see where the problem is. Conflicted files will appear in the Unmerged paths section:
β
Then, sheβll edit the file(s) to her liking. Once sheβs happy with the result, she can stage the file(s) in the usual fashion and let git rebase
do the rest:
β
And thatβs all there is to it. Git will move on to the next commit and repeat the process for any other commits that generate conflicts.β
If you get to this point and realize and you have no idea whatβs going on, donβt panic. Just execute the following command and youβll be right back to where you started:
β
After sheβs done synchronizing with the central repository, Mary will be able to publish her changes successfully:
β
β
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. If your team is comfortable with the Centralized Workflow but wants to streamline its collaboration efforts, it's definitely worth exploring the benefits of the Feature Branch Workflow. By dedicating an isolated branch to each feature, itβs possible to initiate in-depth discussions around new additions before integrating them into the official project.β
β
The Centralized Workflow is essentially a building block for other Git workflows. Most popular Git workflows will have some sort of centralized repo that individual developers will push and pull from. Below we will briefly discuss some other popular Git workflows. These extended workflows offer more specialized patterns in regard to managing branches for feature development, hot fixes, and eventual release.β
β
Feature Branching is a logical extension of Centralized Workflow. The core idea behind the Feature Branch Workflow is that all feature development should take place in a dedicated branch instead of the master
branch. This encapsulation makes it easy for multiple developers to work on a particular feature without disturbing the main codebase. It also means the master
branch should never contain broken code, which is a huge advantage for continuous integration environments.β
β
The Gitflow Workflow was first published in a highly regarded 2010 blog post from Vincent Driessen at nvie. The Gitflow Workflow defines a strict branching model designed around the project release. This workflow doesnβt add any new concepts or commands beyond whatβs required for the Feature Branch Workflow. Instead, it assigns very specific roles to different branches and defines how and when they should interact.β
β
The Forking Workflow is fundamentally different than the other workflows discussed in this tutorial. Instead of using a single server-side repository to act as the βcentralβ codebase, it gives every developer a 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.β
β
There is no one size fits all Git workflow. As previously stated, itβs important to develop a Git workflow that is a productivity enhancement for your team. In addition to team culture, a workflow should also complement business culture. Git features like branches and tags should complement your businessβs release schedule. If your team is using task tracking project management software you may want to use branches that correspond with tasks in progress. In addition, some guidelines to consider when deciding on a workflow are:β
β
The longer a branch lives separate from the production branch, the higher the risk for merge conflicts and deployment challenges. Short-lived branches promote cleaner merges and deploys.β
β
Itβs important to have a workflow that helps proactively prevent merges that will have to be reverted. A workflow that tests a branch before allowing it to be merged into the master
branch is an example. However, accidents do happen. That being said, itβs beneficial to have a workflow that allows for easy reverts that will not disrupt the flow for other team members.β
β
A workflow should complement your businessβs software development release cycle. If you plan to release multiple times a day, you will want to keep your master
branch stable. If your release schedule is less frequent, you may want to consider using Git tags to tag a branch to a version.β
β
In this document we discussed Git workflows. We took an in-depth look at a Centralized Workflow with practical examples. Expanding on the Centralized Workflow we discussed additional specialized workflows. Some key takeaways from this document are:β
There is no one-size-fits-all Git workflow
A workflow should be simple and enhance the productivity of your team
Your business requirements should help shape your Git workflow
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.Git Workflows: Managing conflictsβ
Git Workflows: Edit Stage Commit Feature Processβ
Git Workflows: Edit Stage Commit Featureβ
Git Workflows: Publish Featureβ
Git Workflows: Push Command Errorβ
Git Workflows: Git Pull Rebaseβ
The --rebase
option tells Git to move all of Maryβs commits to the tip of the master
branch after synchronising it with the changes from the central repository, as shown below:Git workflows: Rebasing to Masterβ
Git Workflows: Rebasing on Commitsβ
Git workflows: Conflict Resolutionβ
Git Workflows: Synchronize Central Repoβ