Search code examples
ruby-on-railsgitversion-controlgithubamazon-elastic-beanstalkbeanstalk-svn

Show the latest commit value within a web application?


I have a few Rails applications and I use Git as the version control system. I use either GitHub or Beanstalk as the repository hosts.

What I am trying to is quite simple in theory. Somehow show the latest commit ID number (hash?) in the footer of the web application. So that when I am looking at the web application I can check that it's committed and deployed correctly.

I can imagine there are two methods to tackle this. The first would be a possible feature of Git that allows the output of the commit ID. The second would be a post-commit web hook (both Beanstalk and GitHub allow this).

Has anyone ever found a way to do this, or something similar?

Thanks,

Danny


Solution

  • First, a clarification: post-commit hook cannot add commit-id to file in a commit, because commit id depends on commit of the top tree (representing top directory), id of top tree in turn depends on ids of its members, and id of a file depends on its contents... and this content is to include commit id. Not possible.

    But let's take a look at different solutions:

    Live, server side scripting

    If your web app is deployed live from non-bare git repository (I hope you know what you are doing wrt. pushing into non-bare repository, i.e. repository with checkout / working tree), then your web app can check HEAD by using git rev-parse HEAD (gives SHA-1 of commit), or better git describe --dirty (the --dirty option would make returned string contain information whether you have uncomitted changes in working area), or git describe --always HEAD.

    git rev-parse HEAD gives something like 7611062b4ba6d1ebc4cf3e63c11204a4f5057660, while git describe --dirty gives something like v1.7.3.2-95-g7611062 (which means commit with abbreviated SHA-1 of 7611062, 95 commits after commit tagged 'v1.7.3.2'), but it depends on you tagging releases using annotated tags.

    A variant of this would be to have web app to check HEAD from repository which is somewhere else on the same filesystem, e.g. with git --git-dir=/path/to/.git describe HEAD.

    Sidenote: if you use Ruby, you probably want to use grit library. The equivalent of git rev-parse HEAD version would probably be (untested!):

    require 'grit'
    include Grit
    
    repo = Repo.new("/var/git/app.git")
    head = repo.commits('HEAD', 1)
    
    app_version = head.id
    


    Live, static files served from git checkout

    Edit: section added 2010-10-23 13:33 +0000
    If you serve your files from checkout (worktree) of non-bare git repository (not your situation), you can use 'smudge' and 'clean' commands of filter gitattribute to perform CVS-like keyword expansion on checkout / checkin.

    In .gitattributes file you would define files on which filter attribute should act:

    *.rb filter=commitid
    

    You define filter in git config file (e.g. in .git/config), for example

    [filter "commitid"]
            smudge = sed -e "s/\$Revision: ?\$/\$Revision: $(git rev-parse HEAD)\$/1"
            clean =  sed -e "s/\$Revision: ?[^$]*\$/\$Revision: \$/1"
    

    The smudge filter would replace '$Revision: $' with e.g. '$Revision: v1.7.3.2-95-g7611062' on checkout (this means that checked outfiles would contain this CVS-like keyword expanded). The clean filter would remove expansion when storing file contents in git object database (in git repository); otherwise you would have problems with comparing file etc.


    Deployed with use of git archive

    If you instead deploy your web app, so it doesn't reside in live repository (which has its quirks wrt. pushing into it, and which has possible security drawbacks), and you use git archive somewhere (e.g. to zip app to upload it to your hosting site), you can make use of keyword substitution.

    First you need to tell Git that you want keywords in a file replaced by git archive. You do that by setting export-subst for given file, for example by adding to .gitattributes file

    *.rb export-subst
    

    and then adding to your file that contains/generates page footer e.g

    $Format:%H$
    

    which will be replaced by commit hash (see pretty-formats description e.g. in git-log manpage).


    Deployed, using some deployment script

    If you use some kind of script / scripted mechanism to deploy your web app, you should follow Jefromi advice of having your deploy script embed version information.

    You would have to ask somebody else how to set Capistrano (assuming that you use it for deployment) to post:deployment replace '@@VERSION@@' placeholder in your 'app.rb' file with result of git describe --always HEAD... Git project Makefile uses sed for that.