Skip to content
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
229 lines (173 sloc) 5.81 KB
use strict;
use warnings;
package Git::Helpers;
our $VERSION = '0.000019';
use Carp qw( croak );
use Capture::Tiny 'capture_stderr';
use File::pushd qw( pushd );
use Git::Sub;
use Sub::Exporter -setup => {
exports => [
use Try::Tiny qw( catch try );
use URI ();
use URI::FromHash qw( uri );
use URI::Heuristic qw(uf_uristr);
use URI::git ();
sub checkout_root {
my $dir = shift;
my ( $new_dir, $root );
$new_dir = pushd($dir) if $dir;
$dir ||= '.';
# the exception thrown by rev-parse when we're not in a repo is not
# very helpful (see following), so just ditch it in favor of the error
# output.
# "rev_parse error 128 at /home/maxmind/perl5/lib/perl5/Git/ line 30"
my $stderr = capture_stderr {
try { $root = scalar git::rev_parse qw(--show-toplevel) }
croak "Error in $dir: $stderr"
if $stderr;
return $root;
# Works as of 1.6.3:1
sub current_branch_name {
return git::rev_parse( '--abbrev-ref', 'HEAD' );
sub https_remote_url {
my $remote_url = remote_url(shift);
return undef unless $remote_url;
my $branch = shift;
# remove trailing .git
$remote_url =~ s{\.git\z}{};
# remove 'git@' from
$remote_url =~ s{\w*\@}{};
# remove : from
$remote_url =~ s{(\w):(\w)}{$1/$2};
if ($branch) {
$remote_url .= '/tree/' . current_branch_name();
my $uri = URI->new( uf_uristr($remote_url) );
return $uri;
sub is_inside_work_tree {
my $success;
capture_stderr {
try {
$success = git::rev_parse('--is-inside-work-tree');
return $success;
sub ignored_files {
my $dir = shift || '.';
my @success;
my $stderr = capture_stderr {
try {
@success = git::ls_files(
$dir, '--ignored', '--exclude-standard',
croak "Cannot find ignored files in dir: $stderr" if $stderr;
return \@success || [];
sub remote_url {
my $remote = shift || 'origin';
my $url;
my $stderr = capture_stderr {
try {
$url = git::remote( 'get-url', $remote );
catch {
try {
$url = git::config( '--get', "remote.$remote.url" );
return $url;
sub travis_url {
my $remote_url = https_remote_url(shift);
my $url = URI->new($remote_url);
return uri(
scheme => 'https',
host => '',
path => $url->path,
#ABSTRACT: Shortcuts for common Git commands
use Git::Helpers qw(
my $dir = '/path/to/folder/in/git/checkout';
my $root = checkout_root($dir);
my $current_branch = current_branch_name();
my $https_remote_url = https_remote_url();
my $inside_work_tree = is_inside_work_tree();
my $remote_url = remote_url('upstream');
my $travis_url = travis_url();
=head2 checkout_root( $dir )
Gives you the root level of the git checkout which you are currently in.
Optionally accepts a directory parameter. If you provide the directory
parameter, C<checkout_root> will temporarily C<chdir> to this directory and
find the top level of the repository.
This method will throw an exception if it cannot find a git repository at the
directory provided.
=head2 current_branch_name
Returns the name of the current branch.
=head2 https_remote_url( $remote_name, $use_current_branch )
This is a browser-friendly URL for the remote, fixed up in such a way that
GitHub (hopefully) doesn't need to redirect your URL.
Turns into
Turns into
Defaults to using C<origin> as the remote if none is supplied.
Defaults to master branch, but can also display current branch.
my $current_branch_url = https_remote_url( 'origin', 1 );
=head2 ignored_files( $dir )
Returns an arrayref of files which exist in your checkout, but are ignored by
Git. Optionally accepts a directory as an argument. Defaults to ".".
Throws an exception if there has been an error running the command.
=head2 is_inside_work_tree
Returns C<true> if C<git rev-parse --is-inside-work-tree> returns C<true>.
Otherwise returns C<false>. This differs slightly from the behaviour of
C<--is-inside-work-tree> in real life, since it returns C<fatal> rather than
C<false> if run outside of a git repository.
=head2 remote_url( $remote_name )
Returns a URL for the remote you've requested by name. Defaults to 'origin'.
Provides you with the exact URL which git returns. Nothing is fixed up for you.
# defaults to 'origin'
my $remote_url = remote_url();
# $remote_url is now possibly something like one of the following:
# get URL for upstream remote
my $upstream_url = remote_url('upstream');
=head2 travis_url( $remote_name )
Returns a L<> URL for the remote you've requested by name.
Defaults to 'origin'.
# get Travis URL for remote named "origin"
my $origin_travis_url = travis_url();
# get Travis URL for remote named "upstream"
my $upstream_travis_url = travis_url('upstream');
You can’t perform that action at this time.