23

I quite like Gitflow branching model

but I'm not sure where to put the TDD cycle - should I simply use a feature branch and commit everytime I either wrote or passed a test (plus after refactoring)? Create a sub-branch and merge "finished" units into the feature branch? Should I commit each failing test or only after having it made pass?

Here's what I currently do, on a feature branch:

  1. Write a test, commit
  2. The test may yield errors due to non-existing interfaces, fix this, amend commit
  3. Make the (now only failing) test pass, amend commit
  4. Refactor, new commit
  5. goto 1
Tobias Kienzler
  • 25,759
  • 22
  • 127
  • 221
  • @shioyama So do you commit new but failing tests or only after they pass? Please feel free to post this as an answer, if you confirm my assumption that already is an answer – Tobias Kienzler Aug 16 '12 at 10:00
  • 1
    To answer your question: I try not to commit anything that breaks the test suite, but my feature branches are not included in my travis-ci file, so if they do fail I don't get an email or anything. That only happens if I merge them (without fixing them) to the develop or master branch. – Chris Salzberg Aug 16 '12 at 11:24

5 Answers5

9

I'm not sure that this is representative, but just speaking as one developer, I use git-flow and here's (roughly) my workflow for a new feature:

  • Create a feature branch
  • Write failing high-level acceptance test (cucumber) that fails with a @wip (work in progress) tag so it is left out of the test suite for now, and commit this to the new branch
  • (Sometimes) write rspec request test for integration testing of edge cases, and commit that to the feature branch
  • Write lower-level tests (rspec/jasmine) for individual components of the feature, and for each roughly-defined "unit", commit to the feature branch
  • When the feature is finished enough that it passes the acceptance test, take off the @wip tag, make sure it passes and commit to the feature branch
  • Merge the feature branch into the develop branch using git merge (and not git flow finish). This leaves the feature branch there so I can update the feature later on if need be.
  • Once the branch is merged in to develop, travis-ci runs the full test suite on it and if there's any problem, I get an email. (I only include the develop and master branches in my .travis.yml file.)

I should say, this is my "ideal" workflow -- in actual practice I break these rules a lot: commit an untested change before writing the test, start working on parts of the feature before actually fleshing out the high-level acceptance test, etc. I am basically the only one committing to the project, so I have the freedom to do that; if you're working in a larger group I think you'd have to be stricter about sticking to whatever workflow you have.

Anyway that's how I do it. I'd be keen on hearing from other people as well, so I've upvoted the question.

UPDATE:

I realized after writing this that there is one sense in which I deviate from the above flow, which is when I'm adding "features" which are not strictly-speaking the normal user-oriented kind (i.e. not things the user would be aware of). For example, early on in developing an app, we decided we wanted to use backbone.js for structuring our js code -- so I created a feature branch for it and added @javascript tags to various existing cucumber features. I merged it back once the branch was roughly able to do (with backbone.js) what the original app was doing with HTML views.

I'm also planning to switch to using require.js, and in this case I'll also create a feature branch for doing this, and once it's done merge it back. There won't be any high-level integration test for it -- as long as the existing tests pass, it's all good.

Chris Salzberg
  • 27,099
  • 4
  • 75
  • 82
  • +1, I'm also a one man group :-7 Also thanks for mentioning cucumber, which I will have a look at (or search for a Python equivalent) – Tobias Kienzler Aug 16 '12 at 13:06
  • 1
    Cucumber is useful in some ways, but recently I've actually started to think that it might be better to do everything in rspec. Have a look at this article: http://jimmycuadra.com/posts/please-don-t-use-cucumber – Chris Salzberg Aug 16 '12 at 21:37
6

I think that a good and simple guideline would be to commit every time you are "green", or at least every test cycle:

  • Either Red -> Green -> Refactor -> Commit
  • or Red -> Green -> Commit -> Refactor -> Commit
Assaf Stone
  • 6,309
  • 1
  • 34
  • 43
  • 2
    I think a commit before Refactoring (your second option) is a bit better since otherwise one risks destroying functional code. And if a bug is discovered later on, there are two implementations in history to check with :-7 – Tobias Kienzler Aug 17 '12 at 13:32
  • I agree that the 2nd option is safer (committing every time you are green), but some people might consider it too much work. If you work in short cycles, you don't really have much opportunity to destroy functional code between RGR iterations. In most cases you can always undo the changes. – Assaf Stone Aug 18 '12 at 08:01
  • Hm, maybe one can even go as far as letting the unit tester automatically create a commit named "green" or "red" or amend if last commit is called that. Then one can still rebase later on... – Tobias Kienzler Aug 18 '12 at 08:15
5

My workflowis very similar, but think about making better use of the staging area.

  1. Write a test, git add.
  2. The test may yield errors due to non-existing interfaces, fix this, git add.
  3. Make the (now only failing) test pass, git commit.
  4. Refactor, git commit amend.
  5. Goto 1.

This enforces the discipline that, at every commit, all tests pass. During stages 1-3 I can roll back to the last git add at any time using git checkout.

Robin Adams
  • 181
  • 1
  • 5
2

The easy way to think about when you should commit is:

  1. Can I describe what I'm committing with a commit message that makes sense?
  2. Are there any reasons I might want to go back to this point or diff from this point?

That means it really depends on the person. If you never find yourself doing a diff at one of the stages, perhaps because you fix it rapidly enough that you can still remember what you changed, then you don't really need to commit. However, there's no harm in it either, except for the time it takes to type the command.

Another alternative if you don't really feel a step warrants a longer-term commit, is to just do a git add. That way, git diff will show you what has changed since the add, and git diff --cached will show you what changed before. This is what I do, because I prefer my commits to be compilable and passing unit tests. That way, it's easy to go back to a known good state.

Karl Bielefeldt
  • 47,314
  • 10
  • 60
  • 94
1

I don't believe there is a commit workflow that is specific to TDD, the only rule I try to abide by that is related is that I try not to push commits with broken tests to the master branch (unless it is already broken). On my feature branches usually only the feature-related tests are tested, but all tests will be vetted when performing the merge back to master. If I know that the commit does leave some of the feature tests broken or some other reason that makes it so, only then I will indicate it as wip. On the more practical side of things, I think there's more benefit in taking extra care to avoid pushing commits to the wrong branches.

prusswan
  • 6,853
  • 4
  • 40
  • 61