Last active
August 20, 2016 13:29
-
-
Save mugifly/6451502 to your computer and use it in GitHub Desktop.
Git branch cleaner script - Delete a branches that not exist on remote repository. (perl 5.x)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /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