3 # Copyright (c) 2006 Junio C Hamano
9 my $topic_pattern = '??*/*';
11 my @stage = qw(next pu);
12 my @mark = ('.', '?', '-', '+');
19 GetOptions("topic=s" => \$topic_pattern,
21 "stage=s" => \@custom_stage,
22 "mark=s" => \@custom_mark,
23 "merges!" => \$merges,
28 if (@custom_stage) { @stage = @custom_stage; }
29 if (@custom_mark) { @mark = @custom_mark; }
30 my @nomerges = $merges ? qw(--no-merges) : ();
35 open(REVS, '-|', qw(git rev-list), @nomerges, @args)
46 my ($bottom, $top, $mask) = @_;
48 open(REVS, '-|', qw(git rev-list --pretty=oneline), @nomerges,
53 my ($sha1, $topic) = /^([0-9a-f]{40}) (.*)$/;
54 push @revs, [$sha1, $topic, $mask];
61 my ($topic, $stage, $in_next) = @_;
62 my @not_in_topic = read_revs_short('^master', "^$topic", "$stage");
64 # @$in_next is what is in $stage but not in $base.
65 # @not_in_topic excludes what came from $topic from @$in_next.
66 # $topic can be rebased if these two set matches, because
67 # no commits in $topic has been merged to $stage yet.
68 if (@not_in_topic != @$in_next) {
69 # we cannot rebase it anymore
72 if (read_revs_short('master', "^$topic")) {
73 # there is something that is in master but not in topic.
76 # topic is up to date.
85 return '' if (!$tests);
86 return '??' if (!exists $atlog_next{$topic});
87 for ($atlog_next{$topic}) {
88 my ($merge, $test) = ('*', '*');
91 } elsif (/conflict (\d+)/) {
98 $test = 'X' if (/test error/);
105 return '' if (!$tests);
106 my $tree = `git rev-parse "$commit^{tree}"`;
108 return "?" if (!exists $atlog_test{$tree});
109 for ($atlog_test{$tree}) {
112 } elsif (/test error/) {
123 open(CONF, '-|', qw(git repo-config --get),
124 "branch.$topic.description")
126 my $it = join('',<CONF>);
134 my @in_next = read_revs_short('^master', $stage[0]);
137 my @topic_pattern = map { "refs/heads/$_" } (@ARGV ? @ARGV : $topic_pattern);
139 open(TOPIC, '-|', qw(git for-each-ref),
140 '--sort=-authordate',
141 '--format=%(objectname) %(authordate) %(refname)',
147 my ($sha1, $date, $topic) = m|^([0-9a-f]{40})\s(.*?)\srefs/heads/(.+)$|
149 push @topic, [$sha1, $date, $topic];
153 if (open(AT, "Meta/AT.log")) {
154 my $next = `git rev-parse --verify refs/heads/next`;
157 if (/^N (.{40}) (.{40}) (.*)$/ && $1 eq $next) {
158 $atlog_next{$2} = $3;
161 if (/^A (.{40}) (.*)/) {
162 $atlog_test{$1} = $2;
169 my @last_merge_to_next = ();
172 my ($sha1, $date, $topic) = @$_;
173 my @revs = read_revs($base, $sha1, (1<<@stage)-1);
174 next unless (@revs || $all);
176 my %revs = map { $_->[0] => $_ } @revs; # fast index
177 for (my $i = 0; $i < @stage; $i++) {
178 for my $item (read_revs_short("^$stage[$i]", $sha1)) {
179 if (exists $revs{$item}) {
180 $revs{$item}[2] &= ~(1 << $i);
187 rebase_marker($sha1, $stage[0], \@in_next);
190 $count = " " . (scalar @revs) . " commits";
193 $count = " 1 commit";
195 print " $topic ($date)$count\n";
196 describe_topic($topic);
197 for my $item (@revs) {
198 my $mark = $item->[2];
200 $mark = $mark[$mark];
203 $mark = test_marker($item->[0]) . $mark;
205 wrap_print("$mark $item->[1]");
212 ~^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
214 ~~^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<