How to script git with perl and Git::Wrapper

If you work with git, eventually you will want to script something that git doesn’t do already and can’t be accomplished with an alias. If you use Perl, the Git::Wrapper module makes scripting git easy.

The big advantage of Git::Wrapper is that it wraps the binary version of git, which keeps your perl and git independent. Upgrade perl and not git? Add Git::Wrapper and you’re done. Upgrade git while keeping your existing perl? No problem. If you get your git from an OS distribution package, but roll your own perl, then Git::Wrapper is for you!

Git::Wrapper just makes it really easy to pass git commands and get back useful data. It really shines on “git log” commands, as it parses each commit message into Git::Wrapper::Log objects with accessors for id, author, date, and message. For everything else, it’s not much more than a wrapper around qx(), but it returns arrays of lines and throws exceptions when things go wrong, which just saves a little time and code.

Here is a short example that I whipped up recently to automate the process of adding a github repository remote for someone when they send me a pull request. (It also uses my Getopt::Lucid module, but as the name suggests, it should be clear what that does.)

#!/usr/bin/env perl
use 5.010;
use strict;
use warnings;
use autodie;
use Git::Wrapper;
use Getopt::Lucid qw/:all/;

# USAGE: github-remote [-r REPO] [NAME]
#     NAME -- a github user name (or defaults to 'dagolden')
#     REPO -- a github repository path (or is parsed out of my private origin repo)

my $opts = Getopt::Lucid->getopt([

my $who = shift @ARGV;

# Get a wrapper for the current directory
my $git = Git::Wrapper->new(".");

# Locate the origin repository URL
my ($origin) = grep { /origin/ } $git->remote("-v");
die "Couldn't determine origin\n" unless $origin;
$origin =~ s/^origin\s+//;
$origin =~ s/\s+\(.*$//;

# Parse out the repository path
my $repo = $opts->get_repo;
unless ( $repo ) {
  ($repo) = $origin =~ m/^[^:]+:(.+)$/;

# Set up someone else's github repo
if ( $who ) { 
  $git->remote("add", $who, "git://${who}/${repo}");
# Or set up my own github mirror
else {
  $git->remote("add", "github", "git\${repo}");

That’s it. I admit the program is a little crufty because of how I manage my repositories with a private origin that I mirror to a github repository, but there’s almost no cruft around interactions with git. Consider this:

$git->remote("add", $who, "git://${who}/${repo}");

If the command fails (if there’s already $who as a remote name), an exception will be thrown. That means I don’t have to write any error handling myself, which is perfect for a simple automation program like this one.