views:

1245

answers:

4

This posting here (http://stackoverflow.com/questions/156044/how-do-you-manage-database-revisions-on-a-medium-sized-project-with-branches) got me wondering how best to work on a web project using branching and deploying to dev, staging, and production (along with local copies).

We don't have "releases" per se: if a feature is big enough to be noticeable, we push it live (after requisite testing/etc.), otherwise we batch a few up and, when it feels "comfortable", push those live. The goal is to never have a deploy more than once or twice a month or so because a constantly shifting site tends to make the users a bit uneasy.

Here's how we do it, and it feels sort of brittle (currently using svn but considering a switch to git):

  1. Two "branches" - DEV and STAGE with a given release of STAGE marked as TRUNK
  2. Developer checks out a copy of TRUNK for every change and creates a branch for it
  3. Developer works locally, checking in code frequently (just like voting: early and often)
  4. When Developer is comfortable it isn't totally broken, merge the branch with DEV and deploy to the development site.
  5. Repeat 3-4 as necessary until the change is "finished"
  6. Merge change branch with STAGING, deploy to stage site. Do expected final testing.
  7. After some period of time, mark a given revision of STAGE as the TRUNK, and push trunk live
  8. Merge TRUNK changes back down to DEV to keep it in sync

Now, some of these steps have significant complexity hand-waved away and in practice are very difficult to do (TRUNK -> DEV always breaks) so I have to imagine there's a better way.

Thoughts?

+1  A: 

An obvious thought would be more "rebase" (merges back more often from "parent" environment STAGE to "child" environment "DEV" to developer branch) in order to minimize the final impact of TRUNK->DEV, which would be not needed anymore.

I.e, anything done in STAGE, that is bound to go into production at one time (TRUNK) should be merged back as early as possible in DEV and private devs branch, otherwise those late retrofitting merges are always a pain.

BUT, it the above merge workflow is too inconvenient, I would suggest a REBASE branch, based on latest DEV just after a release (new TRUNK). The rebase TRUNK->DEV would become TRUNK->REBASE, where all problems are solved, then a final merge DEV->REBASE to check that any current dev is compatible with the new updated system. A final trivial merge back from REBASE to DEV (and to private dev branches) would complete the process.
The point of a branch is to isolate a development effort that can not be conducted together with other current development efforts. If TRUNK->DEV is too complicated to go along with current DEVs, it need to be isolated. Hence the 'REBASE' branch proposition.

VonC
And I would point out that the second scenario is more convenient with a pre-1.5 svn, since in svn1.4 or less, merges history are not recorded, so frequent merges are more complicated to do.
VonC
A: 

We use SVN in the shop I work at. While we do C++ development, version management is pretty universal. The following is our approach, you can decide what, if any of it, is reasonable for your approach.

For us, ALL development occurs in a branch. We branch for every bug and every feature. Ideally, that branch is devoted ONLY to 1 feature but sometimes that just isn't meant to be.

When work is completed, tested, and "ready" we merge the changes into the trunk. Our rule is that at no point should the trunk ever have broken code in it. If broken code should find its way into the trunk, fixing it becomes priority 1.

Releases are made when the features are all done and merged: a branch for the release is created as is a tag. The tag allows us a shapshot to retrieve if we need to. The branch allows us our previous version support. Fixing bugs in a released version is done by going to that release's branch, branching from it. When all is well, changes are merged back to the release's branch and, if desired, all the way to the trunk.

antik
+2  A: 

Branching is handy if you expect the work to NOT be completed on time, and you do not have a sufficient body of tests to make continuous integration work. I tend to see branch-crazy development in shops where the programming tasks are far too big to complete predictably and so management wants to wait until just before a release to determine what features should ship. If you are doing that kind of work, then you might consider using distributed version control, where EVERY working directory is a branch naturally and you get all the local check-in and local history you can eat without hurting anyone. You can even cross-merge with other developers outside of the trunk.

My preference is when we work in an unstable trunk with branches for release candidates, which are then tagged for release, and which then become the stream for emergency patches. In such a system, you very seldom have more than three branches (last release, current release candidate, unstable trunk). This works if you are doing TDD and have CI on the unstable trunk. And if you require all tasks to be broken down so you can deliver code as often as you desire (usually a task should be only one to two days, and releasable without all the other tasks that compose its feature). So programmers take work, check-out the trunk, do the work, sync up and check in any time all the tests pass. The unstable trunk is always available to branch as a release candidate (if all tests pass) and therefore release becomes a non-event.

Overall, better means: fewer branches, shorter tasks, shorter time to release, more tests.

Tim Ottinger