Alien-Factory has a number of projects held on BitBucket and uses Mercurial (Hg) for source control.
Alien-Factory also deploys its web applications to Heroku, which requires the project to be stored in a Git repository.
This article explains how to use Mercurial and Git together for the purpose of deploying projects to Heroku...
Why Not Just Use Git?
If Heroku requires the web application to be stored in Git then you may ask, why not just use a Git repository on BitBucket?
Well, Git is great for distributed file systems, and Mercurial is great for project repositories. And Mercurial, as they proclaim on their website, just works!
Why Not Use Hg-Git?
There is the Hg-Git project, which lets Mercurial push and pull to / from a Git server... But it does not play nicely with Heroku.
So How Then?
Git keeps its files in a .git
directory and Mercurial keeps its files in a .hg
directory. Because of this, you can store your project in both systems at the same time. The general approach is:
- Use any Mercurial repository for source control
- Use Heroku's default Git repository (because you have to)
- Check out both repositories into the same directory
- Ensure both systems ignore each others files
- Commit, push and pull to Mercurial as required
- Only commit and push to Git to deploy the application.
In essence, Git is just used as a deployment mechanism. So when we push to Git, we forcefully push everything and never look back. We use the same Git commands, in a script, that commitd and pushes the entire contents of the current directory to Heroku.
Job done!
Lets look at those steps in detail...
Check out Mercurial and Git
Assuming your project is already in BitBucket's Mercurial and you've created a new Heroku application, you want to check out both projects into the same directory.
As both the Mercurial and Git clone
command will only clone into an empty directory, we check them out into separate directories and manually merge them. Our goal is end up with one directory that contains our project, Mercurial's .hg
directory, and Git's hidden .git
directory.
C:\> hg clone <hg-repo-url> hg-dir ... C:\> heroku git:clone --app <heroku-app-name> git-dir ... C:\> mv git-dir\.git hg-dir\.git 1 dir(s) moved. C:\> rmdir /S git-dir
As you can see, the project was checked out into hg-dir
, and Heroku into git-dir
. The all important .git
directory was then copied into hg-dir
and git-dir
was deleted.
By using the heroku clone
cmd, and not straight Git, we let Heroku do some magic. Otherwise you end up with all sorts of Git problems and have to associate remotes, add keys, etc...
(Note that the Powershell mv
command and not move
because move
cannot move hidden files or folders)
Make them ignore each other
They say ignorance is bliss, and it is no different for these two mortal enemies!
You need to make sure the .hg
and .git
directories are ignored in the relevant systems - otherwise you'll have Mercurial files checked into your Git repo and Git files checked into your Mercurial repo! D'Oh!
Create a .hgignore
file in the root of your project and add the following lines:
syntax: glob .git
Create a .gitignore
file in the root of your project and add the following line:
.hg/
Use Mercurial
Use the Mercurial repository as per normal; using commits to track your changes. Push and pull when you feel like it, and generally ignore the fact that the Git repository exists.
Deploy to Heroku
The only time you should use Git is when you want to deploy (a new version of) your application to Heroku.
Be heavy handed with Git, commit everything at once! Don't even bother with commit messages, I mean, who cares!? We're not using it for source control, we're only using it as a deploy hook for Heroku.
In fact, at Alien-Factory, our only interaction with Git is through this simple deploy-to-heroku.cmd
script:
git add -A git commit -m "Git is!" git push heroku master
Epilogue
To use Mercurial as your source control manager while, at the same time, deploying to Git on Heroku you need to:
- Check out Mercurial and Git into the same directory
- Make them ignore each other
- Use Mercurial as normal
- Push everything to Git to deploy
Have fun!
:)