Git

For those readers of my blog who don't live in the rails world I highly recommend checking out Git, a distributed version control system. It has been big in the rails world since early this year for several good reasons:

  • It has distributed and offline functionality
  • Making and merging branches is a breeze - encouraging you to try experiments in branches
  • It uses much less space than alternatives, such as Subversion, and only has one .git folder at the base of your project
  • It's in active development with constant releases of new features (but stable enough to be used for the linux kernel)

The terminology is slightly different from subversion and friends but once you've got used to it you never look back!

Merb was very quick to jump on the git bandwagon and rails followed not much later. Practically this made distributed development a hell of a lot easier, but it also had some nice knock on effects. Patching is now a lot quicker too - you simply fork the project, make a fix and inform the admin who can then choose to merge back into the master (if they see fit). It's made the process for fixing bugs a hell of a lot quicker.

Soon after git came along the fantastic github.com followed making it easy to host remote repositories. And so to the reason for me writing this post - github just launched git pages where you can upload your own page to front your repositories. It's a neat idea and naturally is all managed through a git repository. You simply create your site in a repository, push to github and the deployment is automatic. Although it's only simple HTML pages, it's a great proof of concept of other things that could be possible. My effort can be found here which following the git ethos I just forked from somebody else

Capistrano 2.3, Git and frozen MERB

I had a few issues getting a Capistrano file to work with Git and frozen MERB the last few days. The script below is how I finally cracked it and also has starters and stoppers for Memcached and my forked backgroundrb for MERB.

# Basic deploy details
set :application, "myapp"
set :deploy_to, "/var/www/apps/#{application}"
set :mongrel_conf, "#{deploy_to}/current/config/mongrel_cluster.yml"

# Repository details
set :repository,  "git@ipaddress:reposname.git"
set :scm, "git"
set :scm_passphrase, ""
set :set_branch, "origin/master"
set :git_enable_submodules, 1

# Required to get git password prompt
default_run_options[:pty] = true

# Set the user account to use for deployment and running
set :user, "deploy"
set :use_sudo, false

# Server details
role :app, "mysite.com"
role :web, "mysite.com"
role :db,  "mysite.com", :primary => true

desc "Deploy to the production server"
task :production do
role :app, "mysite.com"
role :web, "mysite.com"
role :db,  "mysite.com", :primary => true
end

desc "Change the database configuration file"
task :after_update_code do
run "mv #{release_path}/config/database.yml.production #{release_path}/config/database.yml"

# Remove code we don't want on the server
run "rm -rf #{release_path}/autotest"
run "rm #{release_path}/config/deploy.rb"
run "rm -rf #{release_path}/coverage"
run "rm -rf #{release_path}/spec"
run "rm -rf #{release_path}/stories"

# Make config directory just readable
run "chmod 700 #{release_path}/config"
run "chmod 400 #{release_path}/config/*"
run "chmod 700 #{release_path}/config/environments"
run "chmod 700 #{release_path}/config/initializers"
run "chmod 400 #{release_path}/config/environments/*"

# Make frozen-merb bin file executable
run "chmod 755 #{release_path}/framework/merb-more/merb-freezer/bin/frozen-merb"
end

# Override db:migrate as it calls rails specific stuff
namespace :deploy do
desc "Migrate the database"
task :migrate, :roles => :db do
run "cd #{release_path}; rake db:migrate MERB_ENV=production"
end
end

# Override the default deploy options to use backgroundrb, memcached and mongrel
namespace :deploy do
namespace :backgroundrb do
desc "Start backgroundrb"
task :start, :roles => :app do
invoke_command "cd /var/www/apps/bablo/current && script/backgroundrb start -- -r production", :via => run_method
end
task :stop, :roles => :app do
invoke_command "cd /var/www/apps/bablo/current && script/backgroundrb stop", :via => run_method
end
end

namespace :memcached do
desc "Start memcached"
task :start, :roles => :app do
run "memcached -l 127.0.0.1 -d -m 96 -p 17898"
end
task :stop, :roles => :app do
run "killall -s TERM memcached"
end
end

namespace :mongrel do
desc "Start mongrel"
task :start, :roles => :app do
invoke_command "cd /var/www/apps/bablo/current && #{release_path}/framework/merb-more/merb-freezer/bin/frozen-merb -d -e production -c 5", :via => run_method
end
desc "Stop mongrel"
task :stop, :roles => :app do
invoke_command "cd /var/www/apps/bablo/current && #{release_path}/framework/merb-more/merb-freezer/bin/frozen-merb -K all", :via => run_method
end
end

desc "Custom restart task for mongrel cluster"
task :restart, :roles => :app, :except => { :no_release => true } do
deploy.backgroundrb.stop
deploy.memcached.stop
deploy.memcached.start
deploy.mongrel.stop
deploy.mongrel.start
deploy.backgroundrb.start # Doesn't work if straight after the stop
end

desc "Custom start task for mongrel cluster"
task :start, :roles => :app do
deploy.backgroundrb.start
deploy.memcached.start
deploy.mongrel.start
end

desc "Custom stop task for mongrel cluster"
task :stop, :roles => :app do
deploy.backgroundrb.stop
deploy.memcached.stop
deploy.mongrel.stop
end
end

I've still not managed to get Git caching working with submodules, so any input on this would be appreciated (it seems to work fine without submodules). 

Updated: Fixed in Capistrano 2.4