The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

#!/usr/bin/perl
use strict;
# Copyright 2012 Grant Street Group, All Rights Reserved.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# PODNAME: gitc-sync
# ABSTRACT: Sync up all local branches with the remote
our $VERSION = '0.60'; # VERSION
git
confirm current_branch
guarantee_a_clean_working_directory
);
my $stash = guarantee_a_clean_working_directory();
git "remote update -p origin";
warn "Updating local branches...\n";
my @needs_rebase = update_local_branches();
warn "Packing tags...\n";
git "pack-refs";
my $git_dir = git "rev-parse --git-dir";
if ( -d "$git_dir/refs/tags" ) {
system "find $git_dir/refs/tags -depth -type d -empty -exec rmdir {} \\;";
}
if ( @needs_rebase > 1 ) {
my $branches = join ' and ', @needs_rebase;
warn "\n"
. "$branches have local changes which aren't in the\n"
. "central repository. To bring them up to date, you need to\n"
. "rebase each one with something like this:\n"
. "\n"
. " git checkout master\n"
. " git rebase origin/master\n"
. "\n"
. "Because you've committed directly to multiple branches, gitc\n"
. "can't start the rebase for you automatically\n"
;
}
elsif( @needs_rebase ) {
my $branch = $needs_rebase[0];
warn "\n$branch had local changes and may be outdated\n";
if($stash) {
warn "Since you stashed changes, you'll have to rebase manually\n";
}
elsif ( confirm('Shall I start a rebase for you?') ) {
git "checkout $branch";
exec "git rebase origin/$branch";
}
}
# reinstate any changes present when we started
git "stash apply $stash" if $stash;
exit;
sub branch_exists {
my ($branch) = @_;
our $branches;
if ( not $branches ) {
my %all = map { substr( $_, 2 ) => 1 } git "branch";
$branches = \%all;
}
return $branches->{$branch};
}
# make sure that local branches match upstream branches.
# returns a list of local branches with local changes
sub update_local_branches {
my $current_branch = current_branch;
for my $branch (qw( master test stage prod )) {
my $branch_exists = branch_exists($branch);
my $has_local_commits
= $branch_exists ? git "rev-list -n 1 $branch ^origin/$branch" : '';
if($has_local_commits) {
warn "You've committed directly to $branch. I'll leave it alone.\n";
push @needs_rebase, $branch;
}
elsif ( $branch eq $current_branch ) {
git "reset --hard origin/$branch";
}
elsif ($branch_exists) {
git "update-ref -m 'gitc sync' refs/heads/$branch origin/$branch";
}
else {
git "branch $branch origin/$branch";
}
}
return @needs_rebase;
}
__END__
=pod
=head1 NAME
gitc-sync - Sync up all local branches with the remote
=head1 VERSION
version 0.60
=head1 AUTHOR
Grant Street Group <developers@grantstreet.com>
=head1 COPYRIGHT AND LICENSE
This software is Copyright (c) 2013 by Grant Street Group.
This is free software, licensed under:
The GNU Affero General Public License, Version 3, November 2007
=cut