#!/usr/bin/perl # # gmrg This script merges the most recent git branch for a given # name into the master branch. # # The branch name convention is: # # component.NNNNNN # # component - a name provided by the user # NNNNNN - a numerically ascending index number # # usage: # gmrg [options] # # Revision History # 1.0 Initial revision. 140123 # 1.1 No component on command line merges current. 140201 # 1.2 Added license info. 180616 # # # Copyright 2014 Wayne Morrison # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # use strict; use Getopt::Long qw(:config no_ignore_case_always); # # Version information. # my $NAME = "gmrg"; my $VERS = "$NAME version: 1.2"; ############################################################################ # # Options fields. # my %opts = (); # Options. # # Command line arguments. # my @opts = ( 'verbose', # Give verbose output. 'help', # Give a help message. 'Version', # Display the program version. ); my $last = 0; my $verbose = 0; ############################################################################ my $curbranch; # Current branch. $| = 1; main(); exit(0); #----------------------------------------------------------------------------- # Routine: main() # # Purpose: Do the work -- parse args, get the final branch index, and # run the appropriate command. # sub main { my $component; # Component name for branch to merge. my $brind; # Branch's index. # # Munch on the options and arguments. # $component = optsandargs(); # # Get the index number for the branch. # $brind = branchindex($component); printf("last branch: $component.%06d\n",$brind) if($verbose); # # Build the branch name and merge the name's last branch. # $brind = int($brind); merger($component,$brind,''); } #---------------------------------------------------------------------- # Routine: optsandargs() # # Purpose: Parse the command line for options and arguments. # sub optsandargs { my $cur; # Current branch. # # Parse the options. # GetOptions(\%opts,@opts) || usage(); # # Check for some immediate-action options. # usage() if(defined($opts{'help'})); version() if(defined($opts{'Version'})); # # Now set some flags. # $verbose = $opts{'verbose'}; # # Ensure we weren't given too many branches. # usage() if(@ARGV > 1); # # Get the current branch's name. # $cur = `git branch | egrep '^\\*'`; $cur =~ /^\* (.+)\n/; $curbranch = $1; # # Return the current branch's component name if no branch was given. # However, we won't let the master merge with itself. # if(@ARGV == 0) { if($curbranch ne 'master') { $curbranch =~ /^(.+)\.\d+/; return($1); } print STDERR "master can't merge with itself\n"; exit(2); } # # Return the first argument as the component. # return($ARGV[0]); } #---------------------------------------------------------------------- # Routine: branchindex() # # Purpose: Get the branch index for the component's last branch. # sub branchindex { my $component = shift; # Component to find. my @branches = (); # List of component's branches. # # Get a list of our git branches. # open(BRANCHES,"git branch -v|"); # # Look through the branches to find the current branch and a # list of this component's branches. # while() { my $line; # A branch name. # # Get the line, dump the newline. # $line = $_; chomp $line; # # If this is one of our component's branches, we'll # save the branch's index. # if($line =~ /^[\* ] ($component\.(\d+)) +[0-9a-f]+ /) { push @branches, $2; } } # # Let git rest. # close(BRANCHES); # # Sort the branch indices. # (Probably unnecessary, but we'll still do it.) # @branches = sort @branches; # # Return the largest branch index. # return($branches[-1]); } #----------------------------------------------------------------------------- # Routine: merger() # # Purpose: Run the necessary git merge command. # If we aren't in the master branch, we'll move there. # sub merger { my $name = shift; # Branch's base name. my $brind = shift; # Branch index. my $brname; # Branch name. # # Build the branch name. # $brname = sprintf("$name.%06d", $brind); printf("branch name: $name.%06d\n",$brind); # # Ensure the current branch is the master. # if($curbranch ne 'master') { system("git checkout master"); } # # Merge the branch, maybe creating it along the way. # print "(git merge $brname)\n" if($verbose); exec "git merge $brname"; exit($? >> 8); } #---------------------------------------------------------------------- # Routine: version() # # Purpose: Print the version number(s) and exit. # sub version { print STDERR "$VERS\n"; exit(0); } #---------------------------------------------------------------------- # Routine: usage() # # Purpose: Give usage message and exit. # sub usage { print STDERR "usage: gmrg [options] \n"; print STDERR "\n"; print STDERR "\twhere [options] are:\n"; print STDERR "\t\t-verbose\n"; print STDERR "\t\t-help\n"; print STDERR "\t\t-Version\n"; exit(0); } 1; ############################################################################## =pod =head1 NAME B - merge a component's last git branch to the master branch =head1 SYNOPSIS gmrg [options] =head1 DESCRIPTION B merge the final B branch for a given name with the I branch. B works with branch names that follow a standard naming format, which specifies a name and an index number that is appended to the name. When merging a branch with B, the current branch I be "I". The branch names follow this format: name.NNNNNN The "name" portion is specified by the user and the "NNNNNN" index number is calculated by B. The numbers are six digits long, with leading zeroes included. The checked-out, current branch can be merged with the I by not specifying a component on the command line. In this case, B will save the current branch name, check out the I branch, and then merge the the two branches. The B command may be used to easily create branches named in this format. B and B do not use meaningful branch names and they should not be used if meaningful branch names are required. These commands are useful in situations where there are many files being managed by B and many, frequent changes are being made to those files, and creating meaningful branch names is likely to become time-consuming and a hindrance. =head1 OPTIONS B takes the following options: =over 4 =item I<-verbose> This option provides verbose information about B's operation. =item I<-Version> Display the version information for B. =item I<-help> Display a help message. =back =head1 LICENSE Copyright 2014 Wayne Morrison Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =head1 AUTHOR Wayne Morrison, wayne@waynemorrison.com =head1 SEE ALSO B, B =cut