How can I deploy/push only a subdirectory of my git repo to Heroku?

I had a similar issue. In my case it was never a problem to blow away everything in the heroku repository and replace it with whatever is in my subdirectory. If this is your case you can use the following bash script. Just put it in your Rails app directory.

#!/bin/bash

#change to whichever directory this lives in
cd "$( dirname "$0" )"

#create new git repository and add everything
git init
git add .
git commit -m"init"
git remote add heroku [email protected]:young-rain-5086.git

#pull heroku but then checkback out our current local master and mark everything as merged
git pull heroku master
git checkout --ours .
git add -u
git commit -m"merged"

#push back to heroku, open web browser, and remove git repository
git push heroku master
heroku open
rm -fr .git

#go back to wherever we started.
cd -

I'm sure there are plenty of ways to improve upon this - so feel free to tell me how!


After a long and hard month of trying different things and getting bitten every time I realized,

just because Heroku uses a git repository as a deployment mechanism, you should not treat it as a git repository

it could have been rsync just as well, they went for git, don't get distracted because of this

if you do so, you open up yourself to all kinds of hurt. All of the aforementioned solutions fail miserably somewhere:

  1. it requires something to be done every time, or periodically, or unexpected things happen (pushing submodules, syncing subtrees, ...)
  2. if you use an engine for example to modularize your code, Bundler will eat you alive, it's impossible to describe the amount of frustration I've had with that project during the quest to find a good solution for this
    • you try to add the engine as git repo link + bundle deploy - fail, you need to bundle update every time
    • you try to add the engine as a :path + bundle deploy - fail, the dev team considers :path option as "you're not using Bundler with this gem option" so it'll not bundle for production
    • also, every refresh of the engine wants to update your rails stack -_-
  3. only solution I've found is to use the engine as a /vendor symlink in development, and actually copy the files for production

The solution

The app in question has 4 projects in git root:

  1. api - depending on the profile will run on 2 different heroku hosts - upload and api
  2. web - the website
  3. web-old - the old website, still in migration
  4. common - the common components extracted in an engine

All of the projects have a vendor/common symlink looking at the root of the common engine. When compiling source code for deployment to heroku we need to remove the symlink and rsync it's code to physically be in the vendor folder of each separate host.

  1. accepts a list of hostnames as arguments
  2. runs a git push in your development repo and then runs a clean git pull in a separate folder, making sure no dirty (uncommited) changes are pushed to the hosts automatically
  3. deploys the hosts in parallel - every heroku git repo is pulled, new code is rsynced into the right places, commited with basic push information in the git commit comment,
  4. in the end, we send a ping with curl to tell the hobby hosts to wake up and tail the logs to see if all went wine
  5. plays nice with jenkins too :D (automatic code push to test servers after successful tests)

Works very very nice in the wild with minimal (no?) problems 6 months now

Here's the script https://gist.github.com/bbozo/fafa2bbbf8c7b12d923f

Update 1

@AdamBuczynski, it's never so straightforward.

1st you will always have a production and test environment at the least - and a bunch of function specific clusters at the worse - suddenly 1 folder needs to map to n heroku projects as a pretty basic requirement and it all needs to be organized somehow so that the script "knows" what source you want to deploy where,

2nd you will want to share code between projects - now comes the sync_common part, the shennanigans with symlinks in development being replaced by actual rsynced code on Heroku because Heroku requires a certain folder structure and bundler and rubygems really really really make things ugly very badly if you want to extract the common threads into a gem

3rd you will want to plug in CI and it will change a bit how subfolders and git repo need to be organized, in the end in the simplest possible use case you end up with the aforementioned gist.

In other projects I need to plug in Java builds, when selling software to multiple clients you will need to filter modules that get installed depending on the installation requirements and whatnot,

I should really consider exploring bundling things into a Rakefile or something and do everything that way...


I started with what John Berryman put, but actually it can be simpler if you don't care at all about the heroku git history.

cd bin
git init
git add .
git commit -m"deploy"
git push [email protected]:your-project-name.git -f
rm -fr .git

I guess official git subtree is the best answer, but i had issue getting subtree to work on my mac.


There's an even easier way via git-subtree. Assuming you want to push your folder 'output' as the root to Heroku, you can do:

git subtree push --prefix output heroku master

It appears currently that git-subtree is being included into git-core, but I don't know if that version of git-core has been released yet.

Tags:

Git

Heroku