Saturday, August 28, 2010

Combining TDD kata with git branching and merging

I've been learning from Adam Dymitruk recently how to do git branching and merging from the command line. I thought I would codify some of this in a blog post. Since I also am interested in TDD kata, I'm going to try combining the two into a shared TDD/git kata.

To do this, I'll take the first couple of tests from Roy Osherove's Calcualtor kata, and combine them with the practice of git branching and merging. You really don't want to do this unless you already have some comfort with doing Calculator kata; if you are new to the Calculator kata (or to TDD generally) this git configuration will only prove to be a distraction.

However, if you are already comfortable doing the Calculator kata, and want to work on git branching and merging, this will provide some practice.

This blog entry assumes you have the following installed:
* git and the GitBash command-line tool
* Visual Studio 2008 or 2010
* Resharper

This WON'T assume you have access to a git repository on a server, we will fake a "git repo server" on your local hard drive instead.

Setup
1) On your local drive, create a folder to represent your fake git repo server, named something like:
  • c:\FakeGitRepoServer
2) Add a .gitignore file to the root of this directory. The .gitignore file instructs git which configuration files can be ignored/not stored in git. You can create one from this StackOverflow discussion thread. Paste the contents into NotePad, and then save it as c:\FakeGitRepoServer\.gitignore
NOTE   You don't NEED it here for the repository. This is just a convenient place to store it. You'll be copying into each project folder as part of your git configuration.
3) Launch Visual Studio 2008/10 and create a new solution named "TDDKata_Calcuator_2010Aug28" with two class libraries:
  • MyCompName.Kata.Domain
  • MyCompName.Kata.Tests.Unit
3) Add a reference to NUnit.Framework (in the tests project).

4) Launch GitBash.

5) Use the cd command to change to your solution directory. For this blog entry, let's assume that location is:
  • c:\SourceCode\dotNet\TDDKata_Calculator_2010Aug28\
NOTE    The examples in this blog post use relative pathing to move around. Some people find this tiresome. If you'd like a simple alternative, you can specify your paths from the drive root. For example, assuming you are using the C: drive, you could use commands such as:
  • cd /c/SourceCode/dotNet/TDDKata_Calculator_2010Aug28
6) Any new folder that isn't yet set up for git must first be initialized for git. Type: "git init"


You'll observe that the path now includes a branch name, "master" in brackets at the end of the path. In this git/TDD kata, we'll be creating additional branches: a permanent branch named "development", and any number of temporary, feature branches, with names like "myFirstTest". These branches will be merged back into the development branch and discarded as each minor feature reaches a relative degree of solidity (the test passes) and we are ready to move on. No matter how many temporary feature branches we create, we will always return back to (and merge into) the development branch.
NOTE   At the very end of the kata, we will merge the development branch back into the master branch. This is analagous to deployment to production.
NOTE   For a definitive article on git branching for team development, see the article A Successful Git Branching Model.
8) But first things first: Let's get a local copy of our .gitignore file, something we should always do immediately after initializing the folder. To copy the .gitignore file from the folder where you stored it earlier to your current folder, type:
  • cp ../../../FakeGitRepository/.gitignore .


9) Now that git knows which files to ignore, let's have a look at your current situation. Type 'git status'


10) From here, going forward, for basic git checkin, you will use the same 4 git commands over and over:
  • git status  // this updates you on the file status
  • git add . -A    // this adds the files to be tracked
  • git commit -m "my comment" // this commits the file
  • git push  // this moves the commit to the remote repository
11) Let's start by adding the files:


11) Now let's commit those files:


12) At this point, you need to push these files to the git remote repository on the server--but we haven't set that up yet! To do this, change directory to the c:\FakeGitRepoServer:
cd ../../../FakeGitRepository
13) In that directory, create an empty copy (a "bare clone") of your local git directory. The syntax for this is:
git clone --bare ../SourceCode/dotNet/TDDKata_Calculator_2010Aug20/.git



13) Now you can return to your local repository, set up a connection to the new remote repo, and push your files to that repo. To return to your local repository, type:
cd ../SourceCode/dotNet/TDDKataCalculator_2010Aug28/
14) Now, from your source directory, to set up a connection to your remote repository, enter:
git remote add origin /c/FakeGitRepoServer/TDDKata_Calculator_2010Aug28.git

15) As above, you can VIEW your remote settings with:
git remote -v
16) It took awhile to set up that repository--where were you before you started that? -- You were about to push your local commit to the remote repository. Let's do that now:
git push origin master

17) Congratulations--you have your Calculator kata started, and your first set of code changes have been:
  • committed
  • pushed to the master branch on the remote repository
18) Now it's time to learn a little about branching. Our primary branch will be development, so we'll switch to that branch now. We only will merge back development into master branch at the very end of this kata (think of it as final release to production). Enter:
git branch development
git checkout development

Excellent! Setup is complete, we're ready to begin the kata!

TDD Calculator kata with branching and merging

1) Create a new "feature" branch for your first test:
git branch firstTest
git checkout firstTest
2) The git command line should now show that the current branch is firstTest:


3) Switch to Visual Studio, and create your first test. Something like this:


4) Use Resharper to create the Calculator class and move it to the Domain class libary; and get the test to pass.

5) Now use the following 4 commands to  checkin your code to your feature branch:
git add . -A
git commit -m "First test created and passes"
git push origin firstTest
git status
6) Note that when you push your code to the remote repository, that you are pushing it to a parallel branch (firstTest) in the remote repository. This is created on the fly by git if it doesn't already exist.

7) Go back to Visual Studio and run your test again, it should pass.

8) Now return to git, and switch to the development branch:
git checkout development
9) When you return to Visual Studio, you will be asked to Reload screens. Do so.

10) Try running your test. Note that the code has disappeared! This is because the code exists only in your firstTest feature branch at the moment. Since you know the code is solid (the test is passing), it is safe to merge it back to dev. Let's do so:
git merge firstTest

11) Your changes are now merged. Switch to Visual Studio, and reload. (If Visual Studio seems confused about folders or .csproj files, just close and re-open the solution).

12) You should now be able to run your first test while in the development branch; in other words, you have confirmed that the merge was successful.

13) You don't need the feature branch anymore, so delete it:
git branch -d firstTest

14) Would you really create and delete a feature branch for a single test? Probably not; you'd probably do a series of tests to flesh out the feature, then merge them, then delete the feature branch. But the purpose, as always, with a kata is to get comfortable practicing a process and making it intuitive. So let's proceed to create a temporary feature branch for the next for kata tests.

15) Create a new feature branch named secondTest.
git branch secondTest
git checkout secondTest

16) Switch back to Visual Studio, and create your second test, something like:
17) Once again, modify your code until the test passes.

18) Once again, run the following 4 commands to checkin your code and push it to the remote repository (under the feature branch secondTest):

git add . -A
git commit -m "Second test created and passes"
git push origin secondTest
git status

18) Once again, go to git and checkout the development branch:
git checkout development
19) Once again, return to Visual Studio and note that your second test has disappeared.

20) Once again, return to git and merge the branches. (This time, try adding the tag --no-ff, which stands for no-fast-forward. This leaves a little more merge history in your record to view later as necessary):
git merge secondTest --no-ff

21) Once again, go to Visual Studio and confirm that your second test is running (i.e. has been merged) within the development branch.

22) And finally, once again, delete the feature branch secondTest since you no longer need it:
git branch -d secondTest
23) Continue creating feature branches for several more tests. When you are done, as your final step, checkout the master branch, and merge all the changes your have made in the development branch to the master branch.

Conclusion
In this kata you have been familiarizing yourself with the process for combining the TDD process with the git feature branching and merging process.

The key takeaway is the understanding of using git branching as a dynamic process for development, which can be learned effectively as part of working through a TDD kata process that you are already familiar with.