Git.pm: Better error handling
[git/vmiklos.git] / git-fmt-merge-msg.perl
blobbe2a48cf65949ba16b354e476dd39f5c334f1b25
1 #!/usr/bin/perl -w
3 # Copyright (c) 2005 Junio C Hamano
5 # Read .git/FETCH_HEAD and make a human readable merge message
6 # by grouping branches and tags together to form a single line.
8 use strict;
9 use Git;
11 my $repo = Git->repository();
13 my @src;
14 my %src;
15 sub andjoin {
16 my ($label, $labels, $stuff) = @_;
17 my $l = scalar @$stuff;
18 my $m = '';
19 if ($l == 0) {
20 return ();
22 if ($l == 1) {
23 $m = "$label$stuff->[0]";
25 else {
26 $m = ("$labels" .
27 join (', ', @{$stuff}[0..$l-2]) .
28 " and $stuff->[-1]");
30 return ($m);
33 sub repoconfig {
34 my ($val) = $repo->command_oneline('repo-config', '--get', 'merge.summary');
35 return $val;
38 sub current_branch {
39 my ($bra) = $repo->command_oneline('symbolic-ref', 'HEAD');
40 $bra =~ s|^refs/heads/||;
41 if ($bra ne 'master') {
42 $bra = " into $bra";
43 } else {
44 $bra = "";
46 return $bra;
49 sub shortlog {
50 my ($tip) = @_;
51 my @result;
52 foreach ($repo->command('log', '--no-merges', '--topo-order', '--pretty=oneline', $tip, '^HEAD')) {
53 s/^[0-9a-f]{40}\s+//;
54 push @result, $_;
56 return @result;
59 my @origin = ();
60 while (<>) {
61 my ($bname, $tname, $gname, $src, $sha1, $origin);
62 chomp;
63 s/^([0-9a-f]*) //;
64 $sha1 = $1;
65 next if (/^not-for-merge/);
66 s/^ //;
67 if (s/ of (.*)$//) {
68 $src = $1;
69 } else {
70 # Pulling HEAD
71 $src = $_;
72 $_ = 'HEAD';
74 if (! exists $src{$src}) {
75 push @src, $src;
76 $src{$src} = {
77 BRANCH => [],
78 TAG => [],
79 R_BRANCH => [],
80 GENERIC => [],
81 # &1 == has HEAD.
82 # &2 == has others.
83 HEAD_STATUS => 0,
86 if (/^branch (.*)$/) {
87 $origin = $1;
88 push @{$src{$src}{BRANCH}}, $1;
89 $src{$src}{HEAD_STATUS} |= 2;
91 elsif (/^tag (.*)$/) {
92 $origin = $_;
93 push @{$src{$src}{TAG}}, $1;
94 $src{$src}{HEAD_STATUS} |= 2;
96 elsif (/^remote branch (.*)$/) {
97 $origin = $1;
98 push @{$src{$src}{R_BRANCH}}, $1;
99 $src{$src}{HEAD_STATUS} |= 2;
101 elsif (/^HEAD$/) {
102 $origin = $src;
103 $src{$src}{HEAD_STATUS} |= 1;
105 else {
106 push @{$src{$src}{GENERIC}}, $_;
107 $src{$src}{HEAD_STATUS} |= 2;
108 $origin = $src;
110 if ($src eq '.' || $src eq $origin) {
111 $origin =~ s/^'(.*)'$/$1/;
112 push @origin, [$sha1, "$origin"];
114 else {
115 push @origin, [$sha1, "$origin of $src"];
119 my @msg;
120 for my $src (@src) {
121 if ($src{$src}{HEAD_STATUS} == 1) {
122 # Only HEAD is fetched, nothing else.
123 push @msg, $src;
124 next;
126 my @this;
127 if ($src{$src}{HEAD_STATUS} == 3) {
128 # HEAD is fetched among others.
129 push @this, andjoin('', '', ['HEAD']);
131 push @this, andjoin("branch ", "branches ",
132 $src{$src}{BRANCH});
133 push @this, andjoin("remote branch ", "remote branches ",
134 $src{$src}{R_BRANCH});
135 push @this, andjoin("tag ", "tags ",
136 $src{$src}{TAG});
137 push @this, andjoin("commit ", "commits ",
138 $src{$src}{GENERIC});
139 my $this = join(', ', @this);
140 if ($src ne '.') {
141 $this .= " of $src";
143 push @msg, $this;
146 my $into = current_branch();
148 print "Merge ", join("; ", @msg), $into, "\n";
150 if (!repoconfig) {
151 exit(0);
154 # We limit the merge message to the latst 20 or so per each branch.
155 my $limit = 20;
157 for (@origin) {
158 my ($sha1, $name) = @$_;
159 my @log = shortlog($sha1);
160 if ($limit + 1 <= @log) {
161 print "\n* $name: (" . scalar(@log) . " commits)\n";
163 else {
164 print "\n* $name:\n";
166 my $cnt = 0;
167 for my $log (@log) {
168 if ($limit < ++$cnt) {
169 print " ...\n";
170 last;
172 print " $log\n";