We can now easily fetch and merge things from heads in the refs/remotes/ hierarchy in remote repositories. The refs/remotes/ hierarchy is likely to become the standard for tracking foreign SCMs, as well as the location of Pull: targets for tracking remote branches in newly cloned repositories. Signed-off-by: Eric Wong <normalperson@yhbt.net> Signed-off-by: Junio C Hamano <junkio@cox.net>
		
			
				
	
	
		
			174 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/perl -w
 | 
						|
#
 | 
						|
# Copyright (c) 2005 Junio C Hamano
 | 
						|
#
 | 
						|
# Read .git/FETCH_HEAD and make a human readable merge message
 | 
						|
# by grouping branches and tags together to form a single line.
 | 
						|
 | 
						|
use strict;
 | 
						|
 | 
						|
my @src;
 | 
						|
my %src;
 | 
						|
sub andjoin {
 | 
						|
	my ($label, $labels, $stuff) = @_;
 | 
						|
	my $l = scalar @$stuff;
 | 
						|
	my $m = '';
 | 
						|
	if ($l == 0) {
 | 
						|
		return ();
 | 
						|
	}
 | 
						|
	if ($l == 1) {
 | 
						|
		$m = "$label$stuff->[0]";
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		$m = ("$labels" .
 | 
						|
		      join (', ', @{$stuff}[0..$l-2]) .
 | 
						|
		      " and $stuff->[-1]");
 | 
						|
	}
 | 
						|
	return ($m);
 | 
						|
}
 | 
						|
 | 
						|
sub repoconfig {
 | 
						|
	my ($val) = qx{git-repo-config --get merge.summary};
 | 
						|
	return $val;
 | 
						|
}
 | 
						|
 | 
						|
sub current_branch {
 | 
						|
	my ($bra) = qx{git-symbolic-ref HEAD};
 | 
						|
	chomp($bra);
 | 
						|
	$bra =~ s|^refs/heads/||;
 | 
						|
	if ($bra ne 'master') {
 | 
						|
		$bra = " into $bra";
 | 
						|
	} else {
 | 
						|
		$bra = "";
 | 
						|
	}
 | 
						|
	return $bra;
 | 
						|
}
 | 
						|
 | 
						|
sub shortlog {
 | 
						|
	my ($tip) = @_;
 | 
						|
	my @result;
 | 
						|
	foreach ( qx{git-log --no-merges --topo-order --pretty=oneline $tip ^HEAD} ) {
 | 
						|
		s/^[0-9a-f]{40}\s+//;
 | 
						|
		push @result, $_;
 | 
						|
	}
 | 
						|
	die "git-log failed\n" if $?;
 | 
						|
	return @result;
 | 
						|
}
 | 
						|
 | 
						|
my @origin = ();
 | 
						|
while (<>) {
 | 
						|
	my ($bname, $tname, $gname, $src, $sha1, $origin);
 | 
						|
	chomp;
 | 
						|
	s/^([0-9a-f]*)	//;
 | 
						|
	$sha1 = $1;
 | 
						|
	next if (/^not-for-merge/);
 | 
						|
	s/^	//;
 | 
						|
	if (s/ of (.*)$//) {
 | 
						|
		$src = $1;
 | 
						|
	} else {
 | 
						|
		# Pulling HEAD
 | 
						|
		$src = $_;
 | 
						|
		$_ = 'HEAD';
 | 
						|
	}
 | 
						|
	if (! exists $src{$src}) {
 | 
						|
		push @src, $src;
 | 
						|
		$src{$src} = {
 | 
						|
			BRANCH => [],
 | 
						|
			TAG => [],
 | 
						|
			R_BRANCH => [],
 | 
						|
			GENERIC => [],
 | 
						|
			# &1 == has HEAD.
 | 
						|
			# &2 == has others.
 | 
						|
			HEAD_STATUS => 0,
 | 
						|
		};
 | 
						|
	}
 | 
						|
	if (/^branch (.*)$/) {
 | 
						|
		$origin = $1;
 | 
						|
		push @{$src{$src}{BRANCH}}, $1;
 | 
						|
		$src{$src}{HEAD_STATUS} |= 2;
 | 
						|
	}
 | 
						|
	elsif (/^tag (.*)$/) {
 | 
						|
		$origin = $_;
 | 
						|
		push @{$src{$src}{TAG}}, $1;
 | 
						|
		$src{$src}{HEAD_STATUS} |= 2;
 | 
						|
	}
 | 
						|
	elsif (/^remote branch (.*)$/) {
 | 
						|
		$origin = $1;
 | 
						|
		push @{$src{$src}{R_BRANCH}}, $1;
 | 
						|
		$src{$src}{HEAD_STATUS} |= 2;
 | 
						|
	}
 | 
						|
	elsif (/^HEAD$/) {
 | 
						|
		$origin = $src;
 | 
						|
		$src{$src}{HEAD_STATUS} |= 1;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		push @{$src{$src}{GENERIC}}, $_;
 | 
						|
		$src{$src}{HEAD_STATUS} |= 2;
 | 
						|
		$origin = $src;
 | 
						|
	}
 | 
						|
	if ($src eq '.' || $src eq $origin) {
 | 
						|
		$origin =~ s/^'(.*)'$/$1/;
 | 
						|
		push @origin, [$sha1, "$origin"];
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		push @origin, [$sha1, "$origin of $src"];
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
my @msg;
 | 
						|
for my $src (@src) {
 | 
						|
	if ($src{$src}{HEAD_STATUS} == 1) {
 | 
						|
		# Only HEAD is fetched, nothing else.
 | 
						|
		push @msg, $src;
 | 
						|
		next;
 | 
						|
	}
 | 
						|
	my @this;
 | 
						|
	if ($src{$src}{HEAD_STATUS} == 3) {
 | 
						|
		# HEAD is fetched among others.
 | 
						|
		push @this, andjoin('', '', ['HEAD']);
 | 
						|
	}
 | 
						|
	push @this, andjoin("branch ", "branches ",
 | 
						|
			   $src{$src}{BRANCH});
 | 
						|
	push @this, andjoin("remote branch ", "remote branches ",
 | 
						|
			   $src{$src}{R_BRANCH});
 | 
						|
	push @this, andjoin("tag ", "tags ",
 | 
						|
			   $src{$src}{TAG});
 | 
						|
	push @this, andjoin("commit ", "commits ",
 | 
						|
			    $src{$src}{GENERIC});
 | 
						|
	my $this = join(', ', @this);
 | 
						|
	if ($src ne '.') {
 | 
						|
		$this .= " of $src";
 | 
						|
	}
 | 
						|
	push @msg, $this;
 | 
						|
}
 | 
						|
 | 
						|
my $into = current_branch();
 | 
						|
 | 
						|
print "Merge ", join("; ", @msg), $into, "\n";
 | 
						|
 | 
						|
if (!repoconfig) {
 | 
						|
	exit(0);
 | 
						|
}
 | 
						|
 | 
						|
# We limit the merge message to the latst 20 or so per each branch.
 | 
						|
my $limit = 20;
 | 
						|
 | 
						|
for (@origin) {
 | 
						|
	my ($sha1, $name) = @$_;
 | 
						|
	my @log = shortlog($sha1);
 | 
						|
	if ($limit + 1 <= @log) {
 | 
						|
		print "\n* $name: (" . scalar(@log) . " commits)\n";
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		print "\n* $name:\n";
 | 
						|
	}
 | 
						|
	my $cnt = 0;
 | 
						|
	for my $log (@log) {
 | 
						|
		if ($limit < ++$cnt) {
 | 
						|
			print "  ...\n";
 | 
						|
			last;
 | 
						|
		}
 | 
						|
		print "  $log";
 | 
						|
	}
 | 
						|
}
 |