Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Git branch cleaner script - Delete a branches that not exist on remote repository. (perl 5.x)
#! /usr/bin/env perl
# Git branch cleaner ( Delete a branches that not exist on remote repository)
# If you have not ran the 'git fetch --plune' command, please try it before this script.
# Useful case (maybe): If can't delete a branches using 'git fetch --plune' command.
#
# Usage: $ perl git-branch-clean.pl --help
use warnings;
use strict;
use utf8;
use File::Basename qw//;
our $PATH_GIT_BIN = '/usr/bin/git';
our $NAME_SCRIPT = File::Basename::basename($0, '');
our %Config = ( verbose => 0, dry_run => 0, quiet => 0, irrespective_merged => 0, );
# Initialize
init();
# Check for update
my @delete_branches = check_update();
# Delete a branches
clean_branches(@delete_branches);
exit;
sub init {
# Check for git
my $a = `$PATH_GIT_BIN --version`;
unless ($a =~ /git\ version.*/){
error("Not found git: $PATH_GIT_BIN");
}
# Check a parameters
foreach (@ARGV) {
if ($_ =~ /^\-\-verbose$/i || $_ =~ /^\-v$/){
$Config{verbose} = 1;
} elsif ($_ =~ /^\-\-dry\-run$/i || $_ =~ /^\-d$/){
$Config{dry_run} = 1;
} elsif ($_ =~ /^\-\-quiet$/i || $_ =~ /^\-q$/){
$Config{quiet} = 1;
} elsif ($_ =~ /^\-D$/){
$Config{irrespective_merged} = 1;
} elsif ($_ =~ /^\-\-help$/i || $_ =~ /^\-h$/){
print_help();
exit;
}
}
# Show a parameters
foreach (keys %Config) {
my $v = ($Config{$_}) ? 'true' : 'false';
info(" * $_\t: $v");
}
}
sub check_update {
info("Listup local branches...");
my @all_branches = ();
my @leave_branches = ();
my @delete_branches = ();
# List up a branches
my @lines = `$PATH_GIT_BIN branch --list 2>&1`;
foreach my $l (@lines) {
chomp($l);
if($l =~ /^[* ] *(.+)$/){
info(" * $1");
push(@all_branches, $1);
}
}
# Check for branches update
info("Checking for branch updates...");
@lines = `$PATH_GIT_BIN fetch --dry-run --verbose 2>&1`;
if(!@lines || $lines[0] =~ /fatal\:/i || $lines[0] =~ /error\:/i ){
my $a = $lines[0];
chomp($a);
error($a);
}
# Parse the results
foreach my $l (@lines) {
chomp($l);
if($l =~ /From\ .*/){
next;
}
if($l =~ /^ *= *\[[^\]]*\] *(\w*) *-> *(\w*\/\w*)$/){
my $local_branch = $1;
my $remote_branch = $2;
push(@leave_branches, $local_branch);
info(" * Leave branch: ".$local_branch);
}
}
# Filter delete target branches
foreach my $b (@all_branches){
unless(grep { $_ eq $b } @leave_branches){
push(@delete_branches, $b)
}
}
return @delete_branches;
}
sub clean_branches {
my @branches = @_;
unless(@branches){
print "Not found unnecessary branches :)\n";
return;
}
info("Unnecessary (Not exist on remote repository) branches:");
foreach (@branches) {
info(" * $_");
}
my $count_deleted = 0;
info("\nDeleting...");
foreach (@branches) {
my $cmd = "$PATH_GIT_BIN branch ";
if($Config{irrespective_merged}){
$cmd .= "-D"; # Delete a branch irrespective of its merged status.
} else {
$cmd .= "--delete"; # Delete a branch (default)
}
$cmd .= " $_ 2>&1";
if ($Config{dry_run}) {
# Dry-run
unless($Config{quiet}){
print " * Delete the branch '$_' \t - [DRY-RUN] $cmd\n"; # dry run
}
$count_deleted++;
next;
}
# Confirm
unless($Config{quiet}){
print " * Delete the branch '$_' ? [y/n]: ";
my $ans = <STDIN>;
chomp($ans);
unless($ans =~ /y/i){
next;
}
}
# Delete
my $a = `$cmd`;
chomp($a);
if ($a =~ /^Deleted branch/) { # Success
info(" * Deleted \t - $cmd");
$count_deleted++;
} elsif ($a =~ /^error\:.*Not fully merged.*/i){ # Not fully merged
print " * Git error. '$_' is Not fully merged repository.\n";
print " If you are sure you want to delete it, run : 'git branch -D $_'\n";
print " Or, delete the ALL branches that Not fully merged repository, run: '$NAME_SCRIPT -D'\n";
} else { # Other error (Abort)
print "$a\n";
error("Git error, aborted.");
}
}
if($Config{dry_run}){
print "Deleted (DRY-RUN) ". $count_deleted ." branches, Done.\n";
} else {
print "Deleted ". $count_deleted ." branches, Done.\n";
}
}
sub print_help {
print <<EOF;
usage: $NAME_SCRIPT [-h|--help] [-v|--verbose] [-q|--quiet] [-d|--dry-run] [-D]
-h | --help Help message (This message)
-v | --verbose Verbose message mode
-q | --quiet Quiet mode (NOT confirm mode)
-d | --dry-run Dry-run mode
-D Allow delete repository that not fully merged
EOF
}
sub info {
my $mes = shift;
if($Config{verbose}){
print "$mes\n";
}
}
sub error {
my $mes = shift;
print "[ERROR] $mes\n";
exit 1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.