diff options
author | Sean Whitton <spwhitton@spwhitton.name> | 2020-03-23 22:14:59 -0700 |
---|---|---|
committer | Sean Whitton <spwhitton@spwhitton.name> | 2020-03-23 22:15:44 -0700 |
commit | 05add5a36aa5208ffa289540a039621806949c91 (patch) | |
tree | dae51a5b76fff7eca30432a6f39514478b29cb36 /bin/git-push-all | |
parent | 3b02f5e5a24cee5a4a48b03e81bbe02541b86958 (diff) | |
download | dotfiles-05add5a36aa5208ffa289540a039621806949c91.tar.gz |
rewrite git-push-all
Diffstat (limited to 'bin/git-push-all')
-rwxr-xr-x | bin/git-push-all | 102 |
1 files changed, 47 insertions, 55 deletions
diff --git a/bin/git-push-all b/bin/git-push-all index df3f5af3..553f4f03 100755 --- a/bin/git-push-all +++ b/bin/git-push-all @@ -2,7 +2,7 @@ # git-push-all -- intelligently push most branches -# Copyright (C) 2016, 2019 Sean Whitton +# Copyright (C) 2016, 2019, 2020 Sean Whitton # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -17,15 +17,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -# Prerequisites: - -# The Git::Wrapper, Array::Utils, Config::GitLike, and List::MoreUtils -# perl libraries. On a Debian system, -# apt-get install libgit-wrapper-perl libconfig-gitlike-perl \ -# liblist-moreutils-perl libarray-utils-perl - -# Description: - # This script will try to push all your branches to the places they # should be pushed, with --follow-tags. Specifically, for each branch, # @@ -40,65 +31,69 @@ # If a branch is tracking a remote that you cannot push to, be sure to # set at least one of branch.pushRemote and remote.pushDefault. -# TODO --confirm to show what will be pushed to where and ask for confirmation 'branch -> remote#target' +# Enhancement: --confirm to show what will be pushed to where, and ask +# for confirmation: 'branch -> remote#target' +use 5.028; use strict; use warnings; use lib "$ENV{HOME}/src/dotfiles/perl5"; -no warnings "experimental::smartmatch"; use Cwd; -use Array::Utils qw{ array_minus }; use Git::Wrapper; -use Config::GitLike; -use List::MoreUtils qw{ apply }; use Local::Util::Git qw(unpushed_tags); my $git = Git::Wrapper->new(getcwd); -my $config = Config::GitLike->new( confname => 'config' ); -$config->load_file('.git/config'); - -my @branches = apply { s/[ \*]//g } $git->branch; -my @allBranches = apply { s/[ \*]//g } $git->branch({ all => 1 }); -my $pushDefault = $config->get( key => "remote.pushDefault" ); +my @local_branches + = $git->for_each_ref({ format => '%(refname)' }, "refs/heads"); +my %remote_branches = map +($_ => undef), + $git->for_each_ref({ format => '%(refname)' }, "refs/remotes"); +my ($pushDefault) + = $git->config(qw|--local --get --default|, "", "remote.pushDefault"); my %pushes; -foreach my $branch ( @branches ) { - my $pushRemote = $config->get( key => "branch.$branch.pushRemote" ); - my $tracking = $config->get( key => "branch.$branch.remote" ); - - if ( defined $pushRemote ) { - # print "I: pushing $branch to $pushRemote (its pushRemote)\n"; - push @{ $pushes{$pushRemote} }, $branch; - # don't push unless it already exists on the remote: this script - # avoids creating branches - } elsif ( defined $pushDefault - && "remotes/$pushDefault/$branch" ~~ @allBranches ) { - # print "I: pushing $branch to $pushDefault (the remote.pushDefault)\n"; - push @{ $pushes{$pushDefault} }, $branch; - } elsif ( !defined $pushDefault && defined $tracking - && "remotes/$tracking/$branch" ~~ @allBranches ) { - # print "I: pushing $branch to $tracking (probably to its tracking branch)\n"; - push @{ $pushes{$tracking} }, $branch; +foreach my $branch (@local_branches) { + (my $short_branch = $branch) =~ s#^refs/heads/##; + my ($pushRemote) = $git->config(qw|--local --get --default|, + "", "branch.$short_branch.pushRemote"); + my ($tracking) + = $git->for_each_ref({ format => "%(upstream)" }, $branch); + my ($tracking_remote) = $tracking =~ m#refs/remotes/([^/]+)/# if $tracking; + + # note that except in the case of a defined pushRemote we don't + # push unless the branch already exists on the remote: this script + # avoids creating new branches + if ($pushRemote) { + # say "I: pushing $short_branch to $pushRemote (its pushRemote)"; + push $pushes{$pushRemote}->@*, $branch; + } elsif ($pushDefault + and exists $remote_branches{"refs/remotes/$pushDefault/$short_branch"}) + { + # say "I: pushing $short_branch to $pushDefault (the remote.pushDefault)"; + push $pushes{$pushDefault}->@*, $branch; + } elsif (!$pushDefault + and $tracking + and exists $remote_branches{$tracking}) { + # say "I: pushing $short_branch to its tracking branch, $tracking"; + push $pushes{$tracking_remote}->@*, $branch; } else { - print "E: couldn't find anywhere to push $branch\n"; - print "I: maybe you want to \`git branchmove\` it to a remote\n"; + say "E: couldn't find anywhere to push $branch"; + say "I: maybe you want to \`git branchmove\` it to a remote\n"; exit 1; } } -foreach my $remote ( keys %pushes ) { +foreach my $remote (keys %pushes) { # TODO if $remote eq $pushDefault, consider s/follow-// below (and # pushRemote of master branch, if that exists?) # I almost certainly want all tags on that remote (e.g. an alioth repo) - my @branches = @{ $pushes{$remote} }; - if ( "--no-verify" ~~ @ARGV ) { - system "git push --follow-tags --no-verify $remote @branches"; - } else { - system "git push --follow-tags $remote @branches"; - } - exit 1 if ( $? != 0 ); + my @branches = $pushes{$remote}->@*; + my @args = qw(--follow-tags); + push @args, "--no-verify" if grep $_ eq "--no-verify", @ARGV; + + # bypass Git::Wrapper which can hang pushing to salsa + system "git", "push", @args, $remote, @branches; } # Now find any tags that have not been pushed to any remote. @@ -112,13 +107,10 @@ foreach my $remote ( keys %pushes ) { # TODO definitely split out because should be run as a safety catch by # src-unregistered -unless ( "--no-tags" ~~ @ARGV ) { - my @unpushed_tags = unpushed_tags(); - - if ( scalar @unpushed_tags > 0 ) { - print "E: the following tags have not been pushed to any remote:\n"; - print join(", ", @unpushed_tags); - print "\n"; +unless (grep $_ eq "--no-tags", @ARGV) { + if (my @unpushed_tags = unpushed_tags) { + say "E: the following tags have not been pushed to any remote:"; + say join ", ", @unpushed_tags; exit 1; } } |