Git’s flexibility allows you to use it however you want. Your day-to-day workflow can be as complex or as simple as you decide to make it. Here’s a “simple” workflow that my team and I use.
We have exactly two primary branches in our shared repository at any point in time: a release branch that contains the version of the software that we’re currently shipping to our customers, and a master branch that contains new code for the next release. We create a new release branch at the end of each sprint, and the previous release branch is converted to a tag. The idea is that the current release branch may change while we’re shipping it (a hotfix may be added, for example), but previously-shipped releases are now set in stone. We won’t go back and make changes to them. If a customer has an issue with an older version of the software, we immediately upgrade them to the latest release.
Our local workflow is fairly standard. Everyone maintains a local branch that tracks master, and everyone also has a local “release” branch that tracks the current release branch. We do not make changes directly in either of these branches. Instead, we create a local feature branch off of master when we begin new work:
#Make sure you are on master git checkout master #Pull down the latest changes git pull #Make a branch for your feature! 'C1234' refers to the #card number in Trello, where we track our work. git checkout -b C1234-some-feature
Keeping work isolated this way enables us to change gears quickly should a problem arise that needs to be addressed immediately:
#Oh crap! Major bug found! #Commit to your local feature branch git add -A git commit -m "Check-point: feature is blah blah blah..." #Jump back to master git checkout master #Pull down the latest changes git pull #Make a branch to fix the bug! git checkout -b C1234-some-important-bug
It also allows us to iterate on a feature without creating a lot of noise for the rest of the team:
#Assuming we're on our feature branch... #Do some work... git add -A git commit -m "Feature is coming along nicely..." #Realize you misunderstood something in the spec... git add -A git commit -m "Removed pointless code" #Do more work git add -A git commit -m "Getting closer now" #Undo part of the last commit since it actually broke everything git add -A git commit -m "Rolled out buggy code" #Wrap it up git add -A git commit -m "Feature is complete!"
When we’re finished with a feature, we update our local master branch to ensure we have the latest changes:
#All my code has already been committed to #my feature branch, time to make sure I'm #up-to-date with everyone else! git checkout master git pull
Then we do a rebase to re-apply our changes:
git checkout C1234-some-feature #We'll worry about what to do if this fails in a future post git rebase master
Sidenote: There’s a lot of debate about merge vs. rebase, but I fall solidly in the rebase camp. Just because git will allow your repository history to look like a web doesn’t mean it’s a good idea.
If the feature branch consists of multiple commits, we will usually squash the commits to cut down on noise by doing an interactive rebase:
git checkout C1234-some-feature #Interactive rebase, a command so handy that it #deserves its own post! git rebase master -i
We’ll “pick” the commits we want to keep, then “squash” subsequent commits into them. We’ll typically keep separate commits when it makes the feature easier for another developer to review. I’ll have more about the ‘rebase’ command in the next post.
Why not do an interactive rebase the first time? Because Git still sucks at merging some types of files, such as .csproj files, and sometimes its easier to do a quick cleanup commit at the end to re-include your changes in a project.
Finally, we’ll push the change up to the remote repository:
#All set, push to our shared remote repo (origin) git push origin C1234-some-feature:master
As detractors will point out, this is indeed more steps than “Right-Click, Commit” in TortoiseSVN, but the added flexibility of this workflow offsets any overhead. Plus, if you’re using the right tools, you can actually get really fast at this. I’d bet money that I can usually run through these steps and have my code committed up in less time than it takes TortoiseSVN to figure out what changed.