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([
  Param('repo|r'),
]);

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 ) {
  # me@git.example.com:my-repo-name.git
  ($repo) = $origin =~ m/^[^:]+:(.+)$/;
}

# Set up someone else's github repo
if ( $who ) { 
  $git->remote("add", $who, "git://github.com/${who}/${repo}");
}
# Or set up my own github mirror
else {
  $git->remote("add", "github", "git\@github.com:dagolden/${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://github.com/${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.

This entry was posted in git, perl programming and tagged , . Bookmark the permalink. Both comments and trackbacks are currently closed.

2 Comments

  1. mihir
    Posted February 23, 2012 at 11:16 am | Permalink

    Hello,

    I need to write a script in perl using git. i need to have a mechanism that can clone all the repositories to your local machine and as you enter your input. script should get that input and compare it to all the repos, branches and pattern.

    If the input matches to any repos, branches, pattern or file. It should list the name of repos--branches--file.

    Could you please help me how can i do this?

    • Posted February 23, 2012 at 11:42 am | Permalink

      I'm glad my script is inspiring, but unfortunately, I can't help with individual projects. You might try asking on a more general forum like http://stackoverflow.com/

© 2009-2014 David Golden All Rights Reserved