Engineering February 2, 2017 5 min read

Extending git with Ruby

Extending git with Ruby

At Runtime Revolution all our projects use git as part of the development workflow, which is why I think its important to find ways of extending git to make our lives easier. There are two built in ways for extending git: git hooks and git commands. We can use these to improve our workflow by automating any repetitive steps like:

  1. Checking that the projects dependencies are up to date when we pull new code.
  2. Triggering a deploy when new code is pushed.
  3. Synching branch naming with your project management tool
  4. Anything that you can imagine or is useful to you, really!

In this blog post I’ll do a quick explanation on both of them followed by some practical examples written in ruby.

Git hooks and where to find them

If you want something to trigger on an action you take on git (like pulling, pushing, checkout, etc…) hooks are what you’re looking for. They can be used to run bundle install after a pull, or lint your code to reject a push.
To create a hook all you need to do is place a binary in your repos hook directory $REPO_DIR/.git/hooks/with the name of the event you want to hook to.

Git has a bunch of hooks available and depending on what you want to automate you have to pick the right hook. For instance, if you want to run bundle install every time you pull new code, you’d use the post-merge hook, this hook is run after a merge is completed.

To see this in action, just create a file named post-merge and add it to .git/hooks/. Make sure to give it run permissions(chmod +x $REPO_DIR/.git/hooks/post_merge) and paste the following contents:

Code
bundle check || bundle install

Now there’s no more need to check if new gems have been added to the project every time you do a git pull. Other git hooks let you stop something from happening, the pre-push hook, for example, lets you stop a push if the hook fails by returning a non-zero value.

Setting them up as ruby scripts

This is cool and all but I hate writing shell scripts. By adding #!/bin/env ruby to the top of the file you can use a ruby script instead of a shell script (also don’t forget to give the file run permissions (chmod +x file_name).

Example #1: Getting the pull request link for the current branch:
Now for the promised practical example, bitbucket has a fancy feature that github is missing where it logs the url for the PR you’re working on every time you push. What we’re going for is this flow:

Code
% git push
Create a New Pull Request: https://github.com/empire/deathstar/compare/DS-101-fix-obvious-weakspot% git push
Current Pull Request is: https://github.com/empire/deathstar/pull/1

This can be achieved with a pre-push hook, by the following snippet <sidenote> it depends on the git-pulls gem</sidenote>:

[Code snippet — Medium embed: create_pull_request.rb]

Git commands and how to write them

The other extension point for git, custom git commands, is just as simple to set up. Git comes with several built in command: git push, git pull, git commit. But we can extend it with our own commands like: git fetch-coffee,git buy-groceries, etc..
To do this all you need is to have a binary in your path with the proper name. Basically if you want to have a git command available you just need to have a binary file in your PATH called git-command and git will pick it up.

Lets start with a simple hello world command that prints Hello Git World!!(Very Original) when you callgit hello. To get something like:

Code
% git hello
Hello Git World!!(Very Original)

create a file called git-hello (with run permissions) and with the following content:

Code
#!/bin/env ruby
puts "Hello Git World!!(Very Original)"

All thats left to do is make sure that git-hello is in your PATH and you have your first git command.

Example #2: git command to generate branch name from a ticket title
If you use an issue tracker(which you should) like JIRA, PivotalTracker or asana, one common convention is to identify branches with the ticket that they address. This helps the ticketing system match a ticket with the corresponding work on github, for this example we’re going to use JIRA. The usage flow we want is something like this:

Code
% git ticket DS-101
DS-101-fix-obvious-weakspot (copied to clipboard)

When we run git ticket with the id of the ticket we started working on, the command fetches the tickets title from from JIRA and generates a branch name off it. The branch name is copied to the clipboard and outputs so we check it doesn’t look weird.
To access the rest api provided by JIRA we need to have the credentials and url stored somewhere, the git config command is perfect for this. It’s a key/value store that is tied to the git repo which can fallback to a global config (set with the --globalflag). The following code snippet implements the git ticket command :

[Code snippet — Medium embed: git-ticket.rb]

This was a very superficial view of some of the extension points that we can use in git, and how we can use them with ruby to make our lives easier. Hopefully it’ll help you out with improving your development workflow without having to meddle in shell scripting and bash wizardry.

Further Reading

If I’ve got your interest piqued here’s some links you can follow up.

Has this sparked any ideas on what could be improved in your workflow? We’d love to hear how you’d use these! Comment below with your experiences!

At Runtime Revolution I’m always applying what I learn to make our work easier. I believe by automating tedious and repetitive tasks from developers it makes them less error prone and lets the developers focus on whats important, delivering our clients ideas reliably and swiftly while maintaining developer happiness.

Runtime RevolutionWe are Rails, mobile and product development experts. We can build your product or work with you on your project.www.runtime-revolution.com