Skip to content
Create a gist now

Instantly share code, notes, and snippets.

Embed URL


Subversion checkout URL

You can clone with
Download ZIP
Rake task for precompiling assets locally before deploying to Heroku
require 'fileutils'
# Warning: The following deploy task will completely overwrite whatever is currently deployed to Heroku.
# The deploy branch is rebased onto master, so the push needs to be forced.
desc "Deploy app to Heroku after precompiling assets"
task :deploy do
deploy_branch = 'heroku'
remote = 'heroku'
deploy_repo_dir = "tmp/heroku_deploy"
# Check branch and working directory. Fail if not on clean master branch.
branch = `branch_name=$(git symbolic-ref HEAD 2>/dev/null); branch_name=${branch_name##refs/heads/}; echo ${branch_name:-HEAD}`.strip
if branch != 'master'
raise "You have checked out the #{branch} branch, please only deploy from the master branch!"
if `git status --porcelain`.present?
raise "You have unstaged or uncommitted changes! Please only deploy from a clean working directory!"
unless File.exists? deploy_repo_dir
# Copy repo to tmp dir so we can continue working while it deploys
@new_repo = true
puts "Copying repo to #{deploy_repo_dir}..."
# Can't copy into self, so copy to /tmp first
FileUtils.cp_r Rails.root.to_s, "/tmp/heroku_deploy" "/tmp/heroku_deploy", Rails.root.join('tmp')
# Change working directory to copied repo
# Create new deploy branch if starting with a fresh repo
if @new_repo
# Set remote to parent git dir, so we can fetch updates on future deploys
system "git remote set-url origin ../.."
system "git checkout -b #{deploy_branch}"
# Allow git to see public/assets
puts "Removing public/assets from .gitignore..."
system 'sed -i '' "/^[\/?]public\/assets/d" .gitignore'
system 'git add .gitignore; git commit -m "Allow git to commit public/assets"'
# Otherwise, we're already on the deploy branch, so fetch any new changes from original repo
system "git fetch origin"
# Rebase onto origin/master.
# This step should never fail, because we are rebasing commits for files
# that should be ignored by the master repo.
unless system "git rebase origin/master"
raise "Rebase Failed! Please delete tmp/heroku_deploy and start again."
# Precompile assets
# Add any extra tasks you want to run here, such as compiling static pages, etc.
# Add all changes and new files
system 'git add -A'
commit_message = "Added precompiled assets"
if @new_repo
# Create new commit for new repo
system "git commit -m '#{commit_message}'", :out => "/dev/null"
# If existing repo, amend previous assets commit
system "git commit --amend -m '#{commit_message}'", :out => "/dev/null"
puts "Commit: #{commit_message}"
# Force push deploy branch to Heroku
puts "Pushing #{deploy_branch} branch to master on #{remote}..."
IO.popen("git push #{remote} #{deploy_branch}:master -f") do |io|
while (line = io.gets) do
puts line

Fantastic work on this and the gem! I would like to share issues I had on Mac OSX 10.6.8 with regular bash shell. Maybe i have some customizations but I got '-n' as the contents of branch when the rake task runs, but it works ok from the shell. So I removed -n from the echo line and added .chomp to the end.

Secondly the sed command didn't work for 2 reasons, the -i needs an non-optional extension and in my gitignore it is public/assets
sed -i '' "/^[\/?]public\/assets/d" .gitignore

I can make a fork, but maybe this is easier?


Hi, thanks very much for the feedback and suggestions! I've changed echo -n ...' to echo ...'.strip, and I've replaced the sed command with your suggestion. Please let me know if you run into any more problems.



I used it with a small change. Rather than origin, I used #{remote} in shell commands because I don't use a separate origin repo, just the Heroku repo.


bash and sh will both use their built-in echo. bash's echo supports the -n flag, but sh does not

 ➔ sh
sh-3.2$ type cho
sh: type: cho: not found
sh-3.2$ type echo
echo is a shell builtin
sh-3.2$ /bin/echo foo
sh-3.2$ echo foo
sh-3.2$ /bin/echo -n foo
foosh-3.echo -n foo
-n foo

(ignore type cho)


@ndbroadbent why not make this rake task a part of the turbo-sprockets-rails3 gem?


great work man! I've a bad case of premature heroku deploying without the assets:precompile - this works great. Love the gem also, well done.


Thanks for this! One suggestion, change the FileUtils.cp_r on line 27 to using the system command:

system "cp -r #{Rails.root} /tmp/heroku_deploy"

I had a socket file in my tmp/ and FileUtils.cp_r() failed with the following error. Only cp -r told me which file.

$ rake deploy
Copying repo to tmp/heroku_deploy...
rake aborted!
cannot handle socket
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:1357:in `copy'
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:465:in `block in copy_entry'
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:1433:in `preorder_traverse'
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:462:in `copy_entry'
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:437:in `block in cp_r'
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:1515:in `block in fu_each_src_dest'
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:1531:in `fu_each_src_dest0'
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:1513:in `fu_each_src_dest'
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:436:in `cp_r'

:+1: @turadg I also had a socket this barfed on.


The sed command didn't work for me, probably because I'm on zsh. Removing the brackets helped: sed -i "" "/^public\/assets/d" .gitignore

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.