Pulling specific files from a commit using Git

I ran into a situation today where I needed to grab a specific version of two files from one branch in our repository and merge it into another branch. Normally I would use cherry-pick for this sort of thing but when you are working with developers who arent used to the way of Git, that can be hard. Especially in our situation where most of them are used to Subversion so they make changes to many different files over the period of hours or worse yet, days before they commit their changes.

So in this particular case, I found the commit where the files I needed lived and wouldnt you know it, there were about 12 files in this commit and I only needed 2 of them. So a regular cherry-pick wouldnt work for me in this situation. So how do we pull only the files we need out of that commit and into our current branch? We use our old friend, git checkout to specify the commit and the file path/names we want and check them out into our current branch like this:

git checkoutĀ 6dd17ab5c81b53caa803fb2fae245a89367a2b2e path/to/myfile.cfm

That grabs the file referenced from the commit specified by the SHA and brings them into our current branch.

Super easy!

Deploying ColdFusion Apps With Capistrano Part 3

Hopefully by now you have had a chance to play around with Capistrano and had a chance to deploy one of your apps. If you have and your anything like me, Im sure you ran into a situation where you needed to have a bit more flexibility in your deployment. Since most of the apps I deploy are written using the ColdFusion on Wheels framework, there are a few files that I dont want to deploy to production. So using that as an example, Im going to walk you through setting up and using shared files in your deployments.

Lets use our environment.cfm file as our example. This file simply tells our application what mode it should be running in. On my local workstation, Im typically running in design mode so all of my debugging info is displayed and nothing is cached. But when I deploy that to production, I dont want to push that file up with a value of ‘design‘ setting the environment, I want to keep it in ‘production‘ mode. So lets looks at how we accomplish this.

Remember our directory structure on the server after deployments looks like this:

/site
    releases/
    shared/

So inside our shared directory, lets create a directory called config.

Now that we have a place to hold our config file, we need to copy our config to the server and make sure its set to production mode. I’ll leave that method up to you since everyones method might be different. I simply used FTP to copy my file up and then used VIM to alter the file and change it to put the application in production mode.

Now I have a path like this shared/config/environment.cfm that will match the location of the config file in my application. Thats pretty much all you have to do on the server to set this up. So now lets see how Capistrano can link to that config each time it deploys a new copy of our application.

Here is what our deploy task looked like after part 2:

# this tells capistrano what to do when you deploy
namespace :deploy do

  desc <<-DESC
  A macro-task that updates the code and fixes the symlink.
  DESC
  task :default do
    transaction do
      update_code
      symlink
    end
  end

  task :update_code, :except => { :no_release => true } do
    on_rollback { run "rm -rf #{release_path}; true" }
    strategy.deploy!
  end

  task :after_deploy do
    cleanup
  end
end

Notice all the sections that are prefixed with task? Those blocks of code actually tell Capistrano what to do during deployment. The very first one is default and is run first by Capistrano when you tell it to deploy. Inside the transaction you can see the list of tasks its going to run and each of those tasks relates to a method defined in that namespace block. So in order to tell Capistrano to link our freshly deployed copy to the shared config file we just created on our server, we need to create a new task and tell the default target to run it during deployment. Here is an updated look at the recipe with our new symlink_shared task added to it.

# this tells capistrano what to do when you deploy
namespace :deploy do

  desc <<-DESC
  A macro-task that updates the code and fixes the symlink.
  DESC
  task :default do
    transaction do
      update_code
      symlink
      symlink_shared
    end
  end

  task :update_code, :except => { :no_release => true } do
    on_rollback { run "rm -rf #{release_path}; true" }
    strategy.deploy!
  end

  desc "Symlink shared configs and folders on each release."
  task :symlink_shared do
    run "ln -nfs #{shared_path}/config/environment.cfm #{release_path}/config/environment.cfm"
  end

  task :after_deploy do
    cleanup
  end
end

All we are telling Capistrano to do is run a command on the server to create a symlink in our release path pointing to our shared/config/environment.cfm file. In order for that to run, notice we added the symlink_shared target to the default deploy task at the end of the transaction list since we want to do that last. Dont let the existing symlink task in the transaction throw you off, thats a built in task that tells Capistrano to symlink your new release version to current like we saw in part 2.

Now all you have to do is redeploy your app and your all set. No more having to worry about accidentally setting your application to the wrong environment.

There are all sorts of things you can do like this in your deployments. I have linked to shared assets directories, uploaded files directories, all kinds of stuff. Its just a clean way to deploy and have each release point to something on the server that will not change.

If you have any questions regarding this type of deployment, feel free to post a comment and I will do anything I can to help you out.

Deploying ColdFusion Apps With Capistrano Part 2

In my last post, I covered the basics of what we are trying to accomplish and some basic requirements and setup. Hopefully by now, even you Windows users have Ruby installed and the needed gems, because the fun stuff is about to begin.

The project Im deploying uses Git for SCM and lives on GitHub so Im going to focus on that as the repository to pull releases from. You can just as easily use SVN if you want with a minor tweak to your Capistrano deploy config.

Configuring Your Site

This is where all the configuration happens. Although for a basic deployment, there isnt alot of configuration. First off, you have to create your config files. Fortunately, Capistrano will do that for us. Change directory into the root or your application and type:

$ capify .

This will create a directory and two files, /Capfile, /config/, and /config/deploy.rb. These are really the only config files needed for deployment but we have to tweak them a bit since we arent using Rails.
Open up Capfile in your favorite text editor and replace its contents with the following:

require 'rubygems'
require 'railsless-deploy'
load 'config/deploy' if respond_to?(:namespace)

This basically just tells Capistrano to use the railsless-deploy gem that we installed earlier for deployments as well as tell it where our deploy.rb (recipe) is located. Its common for the /config/deploy.rb file to be referred to as a recipe so those will be used interchangeably.

Next, open the config/deploy.rb file and set it up like this example:

#replace with your servers information
set :domain, "mydomain.com"
set :user, "sshuser"

# this name should be the same as the deployment directory on the server
set :application, "site"

set :scm, :git
set :branch, "master"

# specify a hosted repository
set :repository,  "git@github.com:githubusername/myproject.git"

# or you can use the path to your local repository
#set :repository,  "file://#{File.expand_path('.')}"

server "#{domain}", :app, :web, :db, :primary => true

set :deploy_via, :copy
set :copy_exclude, [".git", ".DS_Store"]

# set this to the deployment path on your server
set :deploy_to, "/home/#{user}/public_html/#{application}"

set :keep_releases, 3
set :git_shallow_clone, 1

ssh_options[:paranoid] = false
ssh_options[:forward_agent] = true
set :use_sudo, false

# this tells capistrano what to do when you deploy
namespace :deploy do

  desc <<-DESC
  A macro-task that updates the code and fixes the symlink.
  DESC
  task :default do
    transaction do
      update_code
      symlink
    end
  end

  task :update_code, :except => { :no_release => true } do
    on_rollback { run "rm -rf #{release_path}; true" }
    strategy.deploy!
  end

  task :after_deploy do
    cleanup
  end
end

As you can see, there are several options available for deployment and you can alter the recipe to use SVN if you need, etc. The Capistrano wiki has some great documentation on all of the options available to you.

Server Setup

Now that you have your application ready to deploy, we need to tackle a couple small tasks on the server to get it ready to have our app deployed to it. Again, Im deploying to an Ubuntu server so I will be showing you the commandline way of doing it.

SSH onto your server and make sure that the deployment path that you set in your recipe exists:

$ mkdir /home/user/public_html/site

Now, on your workstation, you can allow Capistrano to setup the directory structure it uses for deployments. While still in the root directory of your site, simply type:

$ cap deploy:setup

Capistrano will go to work on your server for you and run several tasks. Primarily what you should take note of is the directory structure it creates for you. It will look like this:

site/
    releases/
    shared/

What this does is allows Capistrano to keep the number of releases you specified in your recipe in the releases directory so you can easily roll them back if need be. The shared directory is used for holding files that do not change from deployments such as uploaded images or config files. I use it to store my environment.cfm config for my CFWheels applications so when I deploy, it always points to the production environment.

Once that is done, your ready to deploy your application. On your workstation, type the following command:

$ cap deploy

This will grab the latest copy of your application from your SCM repository and deploy it to the releases directory. The other thing it does is create a symlink on your server called current/. This symlink is recreated each time you deploy your site to point to the latest released copy under the releases directory.

You have one more task on the server that has to be done in order for this to all come together. If your website root path is pointing to /home/user/public_html or something similar, you will need to repoint this to your current symlink, /home/user/public_html/site/current. This sets the doc root for your application and your site should be up and running.

After making some changes to your site and your ready to deploy the latest version, simply type cap deploy in your site root again and Capistrano will create a new folder under releases and push the latest code there. Then it recreates the current symlink and your site will be up and running the latest version. How simple is that?

Somethings Wrong, I Need to Rollback!

So in your last release you found a problem in your application, no problem. You can instantly rollback your server to the previous version by simply typing the following command on your workstation inside your applications root folder:

$ cap deploy:rollback

This will completely remove the failed last release and repoint the symlink to the previous release.

Whats Next?

If your running a simple web app or site, this should probably suffice for most of your needs. But for something that involves a little more configuration, etc. I will be doing a 3rd part to this post soon that will cover creating additional deployment tasks in your recipe to handle things like creating symlinks to shared config files, cleanup tasks and all sorts of goodies.

Stay tuned…

Deploying ColdFusion Apps With Capistrano Part 1

I love developing in ColdFusion, but one of the reasons I spend time learning other languages/frameworks is so I can get a feel for what things others are doing that could help make our jobs a little easier. Lets face it, the ColdFusion community is a little slow to progress sometimes and there is alot of innovation happening in other communities.

One of those areas is application deployment. There have been a few attempts in the past using Ant to help automate deployment. I even wrote a CF based deployment tool that used Ant under the covers and would auto-version and tag your builds and push them to your deployment servers from SVN about 5 years ago. All of the Ant based solutions have had their strengths and weaknesses and are certainly better than FTP’ing to your server and pushing files. However, after working on a few Ruby on Rails projects, I knew there had to be a better way.

There is a deployment tool used by alot of Rubyists called Capistrano. Its a gem that runs locally on your workstation and can handle a wide array of deployment tasks. It sets up a nice structure to easily allow you to rollback your deployments if you need to as well as run several server side tasks as part of your deployment. I never gave much thought (other than pure envy) to Capistrano as it was tightly coupled to rails deployments. Until now.

I recently found a gem called railsless-deploy developed by Lee Hambley. It simply allows you to use Capistrano to deploy your application without it being a Rails app. So I thought, if I dont need Rails, perhaps the application being deployed doesnt need to be a Ruby app, which means I might be able to deploy a CF app with it! So with much enthusiasm I set out to see what I could do with it.

I was amazed at how easily I was able to start deploying a CFWheels application that I had been working on up to one of my Rackspace Cloud instances. Once the initial configuration was done, deploying a new version was as easy as typing $ cap deploy in the terminal. Capistrano would grab the latest release from GitHub and deploy it to my cloud server, symlink a few config files for me that are shared and save the last 3 releases on the server. How great is that?!

There are a few things you will need to use Capistrano to deploy and I will list them here as well as a basic setup. In part 2 of this post, I will walk you through configuring your application for deployment, setting up your server and deploying your code.

What you’ll need

Since capistrano is a gem, you will need Ruby installed. If your developing on a Mac, you should have it installed already. If you are on Windows, you will have to install Ruby for this to work. There are quite a few blog posts on installing Ruby on Windows, so I will let you handle that on your own.

You will also need SSH access to your server and your server should have a POSIX compatible shell. Most Linux servers should be fine for this. If you are deploying to Windows, I understand there is an extension to Capistrano called capistrano_winrm that may work for you but I havent tried it out.

My workstation is running Mac OS X 10.6 with Ruby 1.9.2 and Git. My server is a Rackspace Cloud Instance running Ubuntu Server 10.10 but any Linux flavor should be fine.

Installation

Once you have ruby and rubygems installed, setup is easy. Simply open your command prompt and install the 2 gems:

$ gem install capistrano
$ gem install railsless-deploy

Thats it, your ready to start configuring your application for deployment and we will do just that in part 2 of this post.

Great Intro To Git

I have been asked by several folks lately in the ColdFusion community about Git. It seems that alot of the CF developers are so in-grained with SVN that they either wont consider Git or are afraid of it. Not sure which is the case. But I will say that Git has completely changed the way I look at source control. Ric Roberts has posted a really nice intro to Git that anyone interested in Git should have a look at.
Im planning to do a presentation on Git for the Online CF Meetup as soon as I get time to get the slides together so hopefully that will help de-mystify Git for some of you as well.

Deployment Gotchas – Git And Capistrano

Im just starting to take the leap with Capistrano and so far Im loving it. It simplifies deployment task down to a single command-line call. In my book, that beats syncing the FTP, manually running migrations, etc. One issue I ran into last night though, was during my deployment, I clone my git repository to get the latest version of the application. Thats baked into Capistrano, very simple stuff. However, I kept getting an error that ‘git-index-pack‘ was not a git command.
I spent literally hours googling, reading mailing-list archives, tweaking, updating git, reinstaliing git, etc. Nothing I did made one bit of difference. Being up until 5am probably didnt help me to think clearly either. So after a few hours sleep, I started investigating again. This time it hit me. It hit me like an Amtrak train at full speed.
I host on my own dedicated servers, with that being the case, I have my CentOS servers setup to use Jail-Shell by default for all new accounts in the web group. I completely forgot to change the shell for my deployment user so of course git was failing! Doh!
As soon as I changed the default shell for that user to bash and ran ‘cap deploy:update‘ it worked like a charm!
So if you are deploying to a shared host and running into this issue, make sure to check your shell. I know there are hosts out there that will Jail-Shell you by default.

Installing Git on CentOS 5

I have made the switch from SVN to Git for all of my projects and I’m loving it. So I decided as part of my deployment process, I would install Git on my server and use Git to fetch the release code to the deployment folder. This is alot like I did with Subversion, using svn export to push a tagged release to the server. Installing Git was quite simple even though there is no package for CentOS 5 yet. Here is the process I used to set it up.

The following packages are dependancies for Git, so make sure they are installed.

$: yum installĀ zlib-devel
$: yum install openssl-devel
$: yum install perl
$: yum install cpio
$: yum install expat-devel
$: yum install gettext-devel

Next, if you do not already have Curl installed, follow the next step to get it up and running.

$: wget http://curl.haxx.se/download/curl-7.18.0.tar.gz
$: tar xzvf curl-7.18.0.tar.gz
$: cd curl-7.18.0
$: ./configure
$: make
$: make install

Next, make sure /usr/local/lib is in your ld.so.conf, this is required for git-http-push to correctly link up to the Curl version you are installing.

$: vi /etc/ld.so.conf

(Insert the following)

/usr/local/lib

Save the file, then run:

$: ldconfig

Now download and install Git

$: wget http://www.codemonkey.org.uk/projects/git-snapshots/git/git-latest.tar.gz
$: tar xzvf git-latest.tar.gz
$: cd git-{date}
$: autoconf
$: ./configure --with-curl=/usr/local
$: make
$: make install

Thats all there is to it! Simple enough. I will post a follow up on how I actually deploy using Git in the near future.

Skweegee Has Moved To GitHub

I have decided to take the plunge headfirst with git. Im really digging the distributed nature of it and the fact that I can make small commits to my local repo, then squash them into one atomic commit and push that to the master. It seems to really fit my workflow better.
Due to this switch, I have moved the Skweegee SVN repository over to GitHub. Importing it from SVN wasnt trivial as the GitHub importer failed constantly without telling me why. So I found svn2git and installed the gem. This made it pretty simple and it kept all of the history.
The Skweegee repo can be found here
The SVN repo is still up for now but will not be committed to unless I can find a way to mirror my git commits back to SVN automatically. If I cant, I will pull the SVN repo down later this month.