]>
git.ipfire.org Git - thirdparty/git.git/blob - cook
2 # Maintain "what's cooking" messages
4 my $MASTER = 'master'; # for now
8 my %reverts = ('next' => {
16 my (@u) = grep { $uniq{$_}++ == 0 } sort @_;
18 for (my $i = 0; $i < @u; $i++) {
22 } elsif ($i < @u - 2) {
29 sub describe_relation
{
30 my ($topic_info) = @_;
33 if (exists $topic_info->{'used'}) {
34 push @desc, ("is used by " .
35 phrase_these
(@
{$topic_info->{'used'}}));
38 if (exists $topic_info->{'uses'}) {
39 push @desc, ("uses " .
40 phrase_these
(@
{$topic_info->{'uses'}}));
43 if (0 && exists $topic_info->{'shares'}) {
44 push @desc, ("shares commits with " .
45 phrase_these
(@
{$topic_info->{'shares'}}));
52 return "(this branch " . join("; ", @desc) . ".)";
56 my ($topic, $fork, $forkee, @overlap) = @_;
57 my %ovl = map { $_ => 1 } (@overlap, @
{$topic->{$forkee}{'log'}});
59 push @
{$topic->{$fork}{'uses'}}, $forkee;
60 push @
{$topic->{$forkee}{'used'}}, $fork;
61 @
{$topic->{$fork}{'log'}} = (grep { !exists $ovl{$_} }
62 @
{$topic->{$fork}{'log'}});
66 my ($topic, $one, $two) = @_;
70 qw(git log --abbrev), "--format=%m %h",
71 "$one...$two", "^$MASTER")
72 or die "$!: open log --left-right";
75 my ($sign, $sha1) = /^(.) (.*)/;
78 } elsif ($sign eq '>') {
82 close($fh) or die "$!: close log --left-right";
86 forks_from
($topic, $two, $one);
89 forks_from
($topic, $one, $two);
91 push @
{$topic->{$one}{'shares'}}, $two;
92 push @
{$topic->{$two}{'shares'}}, $one;
96 sub get_message_parent
{
101 open(my $fh, "-|", qw(curl -s),
102 "https://lore.kernel.org/git/" . "$mid" . "/raw");
112 while (<$fh>) { # slurp
116 if (s/^in-reply-to:\s*//i) {
117 while (/\s*<([^<]*)>\s*(.*)/) {
135 qw(git log --notes=amlog --first-parent --format=%N ^master),
138 if (s/^message-id:\s*<(.*)>\s*$/$1/i) {
140 $msgs{$msg} = [get_message_parent($msg)];
146 # Collect parent messages that are not in the series,
147 # as they are likely to be the cover letters.
148 for my $msg (@msgs) {
149 for my $parent (@{$msgs{$msg}}) {
150 if (!exists $msgs{$parent}) {
156 reduce_sources(\@msgs, \%msgs, \%source);
165 # Message-source specific hack
166 my ($msgs_array, $msgs_map, $src_map) = @_;
168 # messages without parent, or a singleton patch
169 if ((! %$src_map && @{$msgs_array}) || (@{$msgs_array} == 1)) {
170 %{$src_map} = ($msgs_array->[0] => 1);
176 for my $msg (keys %$src_map) {
177 if ($msg =~ /^pull\.[^@]*\.gitgitgadget\@/) {
178 push @ggg_source, $msg;
181 if (@ggg_source == 1) {
182 %{$src_map} = ($ggg_source[0] => 1);
189 Inspect the current set of topics
195 'tipdate' => date of the tip commit,
196 'desc' => description string,
197 'log' => [ $commit,... ],
204 my (@base) = ($MASTER, 'next', 'seen');
207 qw(git for-each-ref),
208 "--format=%(refname:short) %(committerdate:iso8601)",
210 or die "$!: open for-each-ref";
216 my ($branch, $date) = /^(\S+) (.*)$/;
218 next if ($branch =~ m
|^../wip
-|);
219 push @topic, $branch;
226 close($fh) or die "$!: close for-each-ref";
228 my %base = map { $_ => undef } @base;
230 my $show_branch_batch = 20;
233 my @t = (@base, splice(@topic, 0, $show_branch_batch));
234 my $header_delim = '-' x
scalar(@t);
235 my $contain_pat = '.' x
scalar(@t);
236 open($fh, '-|', qw(git show-branch --sparse --sha1-name),
237 map { "refs/heads/$_" } @t)
238 or die "$!: open show-branch";
242 if (/^$header_delim$/) {
243 $header_delim = undef;
247 my ($contain, $sha1, $log) =
248 ($_ =~ /^($contain_pat) \[([0-9a-f]+)\] (.*)$/);
250 for (my $i = 0; $i < @t; $i++) {
252 my $sign = substr($contain, $i, 1);
253 next if ($sign eq ' ');
254 next if (substr($contain, 0, 1) ne ' ');
256 if (!exists $commit{$sha1}) {
262 my $co = $commit{$sha1};
263 if (!exists $reverts{$branch}{$sha1}) {
264 $co->{'branch'}{$branch} = 1;
266 next if (exists $base{$branch});
267 push @
{$topic{$branch}{'log'}}, $sha1;
270 close($fh) or die "$!: close show-branch";
274 for my $sha1 (keys %commit) {
276 my $co = $commit{$sha1};
277 if (exists $co->{'branch'}{'next'}) {
279 } elsif (exists $co->{'branch'}{'seen'}) {
284 $co->{'log'} = $sign . ' ' . $co->{'log'};
285 my @t = (sort grep { !exists $base{$_} }
286 keys %{$co->{'branch'}});
292 for my $combo (keys %shared) {
293 my @combo = split(' ', $combo);
294 for (my $i = 0; $i < @combo - 1; $i++) {
295 for (my $j = $i + 1; $j < @combo; $j++) {
296 topic_relation
(\
%topic, $combo[$i], $combo[$j]);
302 qw(git log --first-parent --abbrev),
303 "--format=%ci %h %p :%s", "$MASTER..next")
304 or die "$!: open log $MASTER..next";
306 my ($date, $commit, $parent, $tips);
307 unless (($date, $commit, $parent, $tips) =
308 /^([-0-9]+) ..:..:.. .\d{4} (\S+) (\S+) ([^:]*):/) {
311 for my $tip (split(' ', $tips)) {
312 my $co = $commit{$tip};
313 next unless ($co->{'branch'}{'next'});
314 $co->{'merged'} = " (merged to 'next' on $date at $commit)";
317 close($fh) or die "$!: close log $MASTER..next";
319 for my $branch (keys %topic) {
321 my $n = scalar(@
{$topic{$branch}{'log'}});
323 delete $topic{$branch};
330 my $d = $topic{$branch}{'tipdate'};
331 my $head = "* $branch ($d) $n\n";
333 for (@
{$topic{$branch}{'log'}}) {
334 my $co = $commit{$_};
335 if (exists $co->{'merged'}) {
336 push @desc, $co->{'merged'};
338 push @desc, $commit{$_}->{'log'};
342 @desc = @desc[0..99];
346 my $list = join("\n", map { " " . $_ } @desc);
349 # This is done a bit too early. We grabbed all
350 # under refs/heads/??/* without caring if they are
351 # merged to 'seen' yet, and it is correct because
352 # we want to describe a topic that is in the old
353 # edition that is tentatively kicked out of 'seen'.
354 # However, we do not want to say a topic is used
355 # by a new topic that is not yet in 'seen'!
356 my $relation = describe_relation
($topic{$branch});
357 $topic{$branch}{'desc'} = $head . $list;
359 $topic{$branch}{'desc'} .= "\n $relation";
367 my ($mon, $year, $issue, $dow, $date,
368 $master_at, $next_at, $text) = @_;
370 my $now_string = localtime;
371 my ($current_dow, $current_mon, $current_date, $current_year) =
372 ($now_string =~ /^(\w+) (\w+) (\d+) [\d:]+ (\d+)$/);
374 $mon ||= $current_mon;
375 $year ||= $current_year;
377 $dow ||= $current_dow;
378 $date ||= $current_date;
379 $master_at ||= '0' x
40;
380 $next_at ||= '0' x
40;
382 Here are the topics that have been cooking in my tree. Commits
383 prefixed with '+' are in 'next' (being in 'next' is a sign that a
384 topic is stable enough to be used and are candidate to be in a future
385 release). Commits prefixed with '-' are only in 'seen', and aren't
386 considered "accepted" at all and may be annotated with an URL to a
387 message that raises issues but they are no means exhaustive. A
388 topic without enough support may be discarded after a long period of
391 Copies of the source code to Git live in many repositories, and the
392 following is a list of the ones I push into or their mirrors. Some
393 repositories have only a subset of branches.
395 With maint, master, next, seen, todo:
397 git://git.kernel.org/pub/scm/git/git.git/
398 git://repo.or.cz/alt-git.git/
399 https://kernel.googlesource.com/pub/scm/git/git/
400 https://github.com/git/git/
401 https://gitlab.com/git-vcs/git/
403 With all the integration branches and topics broken out:
405 https://github.com/gitster/git/
407 Even though the preformatted documentation in HTML and man format
408 are not sources, they are published in these repositories for
409 convenience (replace "htmldocs" with "manpages" for the manual
412 git://git.kernel.org/pub/scm/git/git-htmldocs.git/
413 https://github.com/gitster/git-htmldocs.git/
415 Release tarballs are available at:
417 https://www.kernel.org/pub/software/scm/git/
421 To: git\@vger.kernel.org
422 Subject: What's cooking in git.git ($mon $year, #$issue; $dow, $date)
423 X-$MASTER-at: $master_at
425 Bcc: lwn\@lwn.net, gitster\@pobox.com
427 What's cooking in git.git ($mon $year, #$issue; $dow, $date)
428 --------------------------------------------------
432 $text =~ s/\n+\Z/\n/;
436 my $blurb_match = <<'EOF';
437 (?:(?i:\s*[a-z]+: .*|\s.*)\n)*Subject: What's cooking in \S+ \((\w+) (\d+), #(\d+); (\w+), (\d+)\)
438 X-[a-z]*-at: ([0-9a-f]{40})
439 X-next-at: ([0-9a-f]{40})(?:\n(?i:\s*[a-z]+: .*|\s.*))*
441 What's cooking in \S+ \(\1 \2, #\3; \4, \5\)
446 my $blurb = "b..l..u..r..b";
453 my $last_empty = undef;
454 my (@section, %section, @branch, %branch, %description, @leader);
455 my $in_unedited_olde = 0;
459 'section_list' => [],
460 'section_data' => {},
461 'topic_description' => {
464 text
=> blurb_text
(),
470 open ($fh, '<', $fn) or die "$!: open $fn";
474 if ($in_unedited_olde) {
476 $in_unedited_olde = 0;
480 $in_unedited_olde = 1;
483 if ($in_unedited_olde) {
487 if (defined $section && /^-{20,}$/) {
494 if (/^\[(.*)\]\s*$/) {
497 if (!exists $section{$section}) {
498 push @section, $section;
499 $section{$section} = [];
503 if (defined $section && /^\* (\S+) /) {
506 if (!exists $branch{$branch}) {
507 push @branch, [$branch, $section];
508 $branch{$branch} = 1;
510 push @
{$section{$section}}, $branch;
512 if (defined $branch) {
513 my $was_last_empty = $last_empty;
515 if (!exists $description{$branch}) {
516 $description{$branch} = [];
518 if ($was_last_empty) {
519 push @
{$description{$branch}}, "";
521 push @
{$description{$branch}}, $_;
527 for my $branch (keys %description) {
528 my $ary = $description{$branch};
529 if ($branch eq $blurb) {
530 while (@
{$ary} && $ary->[-1] =~ /^-{30,}$/) {
533 $description{$branch} = +{
535 text
=> join("\n", @
{$ary}),
538 my (@desc, @src, @txt) = ();
541 my $elem = shift @
{$ary};
542 last if ($elem eq '');
549 if (/^${lead}source:/) {
556 $description{$branch} = +{
557 desc
=> join("\n", @desc),
558 text
=> join("\n", @txt),
559 src
=> join("\n", @src),
565 section_list
=> \
@section,
566 section_data
=> \
%section,
567 topic_description
=> \
%description,
572 my ($fn, $cooking) = @_;
575 open($fh, '>', $fn) or die "$!: open $fn";
576 print $fh $cooking->{'topic_description'}{$blurb}{'text'};
578 for my $section_name (@
{$cooking->{'section_list'}}) {
579 my $topic_list = $cooking->{'section_data'}{$section_name};
580 next if (!@
{$topic_list});
583 print $fh '-' x
50, "\n";
584 print $fh "[$section_name]\n";
586 for my $topic (@
{$topic_list}) {
587 my $d = $cooking->{'topic_description'}{$topic};
589 print $fh $lead, $d->{'desc'}, "\n";
591 # Final clean-up. No leading or trailing
592 # blank lines, no multi-line gaps.
598 print $fh "\n", $d->{'text'}, "\n";
604 print $fh $d->{'src'}, "\n";
612 my $graduated = "Graduated to '$MASTER'";
613 my $new_topics = 'New Topics';
614 my $discarded = 'Discarded';
615 my $cooking_topics = 'Cooking';
619 my ($fh, $master_at, $next_at, $incremental);
622 qw(git for-each-ref),
623 "--format=%(refname:short) %(objectname)",
624 "refs/heads/$MASTER",
625 "refs/heads/next") or die "$!: open for-each-ref";
627 my ($branch, $at) = /^(\S+) (\S+)$/;
628 if ($branch eq $MASTER) { $master_at = $at; }
629 if ($branch eq 'next') { $next_at = $at; }
631 close($fh) or die "$!: close for-each-ref";
633 $incremental = ((-r
"Meta/whats-cooking.txt") &&
634 system("cd Meta && " .
635 "git diff --quiet --no-ext-diff HEAD -- " .
636 "whats-cooking.txt"));
638 my $now_string = localtime;
639 my ($current_dow, $current_mon, $current_date, $current_year) =
640 ($now_string =~ /^(\w+) (\w+) +(\d+) [\d:]+ (\d+)$/);
642 my $btext = $cooking->{'topic_description'}{$blurb}{'text'};
643 if ($btext !~ s/\A$blurb_match//) {
644 die "match pattern broken?";
646 my ($mon, $year, $issue, $dow, $date) = ($1, $2, $3, $4, $5);
648 if ($current_mon ne $mon || $current_year ne $year) {
650 } elsif (!$incremental) {
652 $issue = sprintf "%02d", ($issue + 1);
655 $year = $current_year;
657 $date = $current_date;
659 $cooking->{'topic_description'}{$blurb}{'text'} =
660 blurb_text
($mon, $year, $issue, $dow, $date,
661 $master_at, $next_at, $btext);
663 # If starting a new issue, move what used to be in
664 # new topics to cooking topics.
666 my $sd = $cooking->{'section_data'};
667 my $sl = $cooking->{'section_list'};
669 if (exists $sd->{$new_topics}) {
670 if (!exists $sd->{$cooking_topics}) {
671 $sd->{$cooking_topics} = [];
672 unshift @
{$sl}, $cooking_topics;
674 unshift @
{$sd->{$cooking_topics}}, @
{$sd->{$new_topics}};
676 $sd->{$new_topics} = [];
683 my ($topic_desc) = @_;
684 for my $line (split(/\n/, $topic_desc)) {
685 if ($line =~ /^ [+-] /) {
696 my $desc = $td->{'desc'};
697 my $text = $td->{'text'};
699 if (!defined $mergetomaster) {
700 my $master = `git describe $MASTER`;
701 if ($master =~ /-rc(\d+)(-\d+-g[0-9a-f]+)?$/ && $1 != 0) {
702 $mergetomaster = "Will cook in 'next'.";
704 $mergetomaster = "Will merge to '$MASTER'.";
708 # If updated description (i.e. the list of patches with
709 # merge trail to 'next') has 'merged to next', then
710 # tweak the topic to be slated to 'master'.
711 # NEEDSWORK: does this work correctly for a half-merged topic?
712 $desc =~ s/\n<<\n.*//s;
713 if ($desc =~ /^ \(merged to 'next'/m) {
714 $text =~ s/^ Will merge (back )?to 'next'\.$/ $mergetomaster/m;
715 $text =~ s/^ Will merge to and (then )?cook in 'next'\.$/ Will cook in 'next'./m;
716 $text =~ s/^ Will merge to 'next' and (then )?to '$MASTER'\.$/ Will merge to '$MASTER'./m;
718 $td->{'text'} = $text;
721 sub tweak_graduated
{
724 # Remove the "Will merge" marker from topics that have graduated.
725 for ($td->{'text'}) {
726 s/\n Will merge to '$MASTER'\.(\n|$)//s;
731 my ($cooking, $current) = @_;
733 # A hash to find <desc, text> with a branch name or $blurb
734 my $td = $cooking->{'topic_description'};
736 # A hash to find a list of $td element given a section name
737 my $sd = $cooking->{'section_data'};
739 # A list of section names
740 my $sl = $cooking->{'section_list'};
742 my (@new_topic, @gone_topic);
744 # Make sure "New Topics" and "Graduated" exists
745 if (!exists $sd->{$new_topics}) {
746 $sd->{$new_topics} = [];
747 unshift @
{$sl}, $new_topics;
750 if (!exists $sd->{$graduated}) {
751 $sd->{$graduated} = [];
752 unshift @
{$sl}, $graduated;
755 my $incremental = update_issue
($cooking);
757 for my $topic (sort keys %{$current}) {
758 if (!exists $td->{$topic}) {
759 # Ignore new topics without anything merged
760 if (topic_in_seen
($current->{$topic}{'desc'})) {
761 push @new_topic, $topic;
762 # lazily find the source for a new topic.
763 $current->{$topic}{'src'} = join("\n", get_source
($topic));
768 # Annotate if the contents of the topic changed
769 my $topic_changed = 0;
770 my $n = $current->{$topic}{'desc'};
771 my $o = $td->{$topic}{'desc'};
774 $td->{$topic}{'desc'} = $n . "\n<<\n" . $o ."\n>>";
775 tweak_willdo
($td->{$topic});
778 # Keep the original source for unchanged topic
779 if ($topic_changed) {
780 # lazily find out the source for the latest round.
781 $current->{$topic}{'src'} = join("\n", get_source
($topic));
783 $n = $current->{$topic}{'src'};
784 $o = $td->{$topic}{'src'};
787 map { s/^\s*//; "-$_"; }
790 map { s/^\s*//; "+$_"; }
792 $td->{$topic}{'src'} = join("\n", "<<", $o, $n, ">>");
797 for my $topic (sort keys %{$td}) {
798 next if ($topic eq $blurb);
799 next if (!$incremental &&
800 grep { $topic eq $_ } @
{$sd->{$graduated}});
801 next if (grep { $topic eq $_ } @
{$sd->{$discarded}});
802 if (!exists $current->{$topic}) {
803 push @gone_topic, $topic;
808 push @
{$sd->{$new_topics}}, $_;
809 $td->{$_}{'desc'} = $current->{$_}{'desc'};
810 $td->{$_}{'src'} = $current->{$_}{'src'};
814 $sd->{$graduated} = [];
818 for my $topic (@gone_topic) {
819 for my $section (@
{$sl}) {
820 my $pre = scalar(@
{$sd->{$section}});
821 @
{$sd->{$section}} = (grep { $_ ne $topic }
823 my $post = scalar(@
{$sd->{$section}});
824 next if ($pre == $post);
828 push @
{$sd->{$graduated}}, $_;
829 tweak_graduated
($td->{$_});
834 ################################################################
837 my ($what, $action, $topic) = @_;
838 if (!exists $what->{$action}) {
839 $what->{$action} = [];
841 push @
{$what->{$action}}, $topic;
848 return if (/^Graduated to/ || /^Discarded$/);
849 return $_ if (/^Stalled$/);
855 sub wildo_flush_topic
{
856 my ($in_section, $what, $topic) = @_;
857 if (defined $topic) {
858 my $action = section_action
($in_section);
860 wildo_queue
($what, $action, $topic);
866 # NEEDSWORK: unify with Reintegrate::annotate_merge
867 if (/^Will (?:\S+ ){0,2}(fast-track|hold|keep|merge|drop|discard|cook|kick|defer|eject|be re-?rolled|wait)[,. ]/ ||
868 /^Not urgent/ || /^Not ready/ || /^Waiting for / || /^Under discussion/ ||
869 /^Can wait in / || /^Still / || /^Stuck / || /^On hold/ || /^Breaks / ||
870 /^Needs? / || /^Expecting / || /^May want to / || /^Under review/) {
873 if (/^I think this is ready for /) {
881 my (%what, $topic, $last_merge_to_next, $in_section, $in_desc);
882 my $too_recent = '9999-99-99';
887 my $old_section = $in_section;
889 wildo_flush_topic
($old_section, \
%what, $topic);
890 $topic = $in_desc = undef;
894 if (/^\* (\S+) \(([-0-9]+)\) (\d+) commits?$/) {
895 wildo_flush_topic
($in_section, \
%what, $topic);
897 # tip-date, next-date, topic, count, seen-count
898 $topic = [$2, $too_recent, $1, $3, 0];
903 if (defined $topic &&
904 ($topic->[1] eq $too_recent) &&
905 ($topic->[4] == 0) &&
906 (/^ \(merged to 'next' on ([-0-9]+)/)) {
909 if (defined $topic && /^ - /) {
913 if (defined $topic && /^$/) {
918 next unless defined $topic && $in_desc;
921 if (wildo_match
($_)) {
922 wildo_queue
(\
%what, $_, $topic);
923 $topic = $in_desc = undef;
926 if (/Originally merged to 'next' on ([-0-9]+)/) {
930 wildo_flush_topic
($in_section, \
%what, $topic);
933 for my $what (sort keys %what) {
934 print "$ipbl$what\n";
935 for $topic (sort { (($a->[1] cmp $b->[1]) ||
936 ($a->[0] cmp $b->[0])) }
938 my ($tip, $next, $name, $count, $seen) = @
$topic;
941 if (($next eq $too_recent) || (0 < $seen)) {
946 $next =~ s
|^\d
{4}-|/|;
949 printf " %s %-60s %s%s %5s\n", $sign, $name, $tip, $next, $count;
955 ################################################################
965 for $str (split(/\n/, $str)) {
966 print "$prefix$str\n";
973 my $cnt = `git rev-list --count @range`;
982 my ($topic, $to_maint, %to_maint, %merged, $in_desc);
985 qw(git rev-list --first-parent -1), $MASTER,
986 qw(-- Documentation/RelNotes RelNotes))
987 or die "$!: open rev-list";
989 close($fh) or die "$!: close rev-list";
991 @ARGV = ("$rev..$MASTER");
994 qw(git log --first-parent --oneline --reverse), @ARGV)
995 or die "$!: open log --first-parent";
997 my ($sha1, $branch) = /^([0-9a-f]+) Merge branch '(.*)'$/;
999 $topic{$branch} = "";
1000 $merged{$branch} = $sha1;
1001 push @topic, $branch;
1003 close($fh) or die "$!: close log --first-parent";
1004 open($fh, "<", "Meta/whats-cooking.txt")
1005 or die "$!: open whats-cooking";
1010 $in_desc = $topic = undef;
1013 if (/^\* (\S+) \([-0-9]+\) \d+ commits?$/) {
1014 if (exists $topic{$1}) {
1018 $in_desc = $topic = undef;
1022 if (defined $topic && /^$/) {
1027 next unless defined $topic && $in_desc;
1030 if (wildo_match
($_)) {
1033 $topic{$topic} .= "$_\n";
1035 close($fh) or die "$!: close whats-cooking";
1037 for $topic (@topic) {
1038 my $merged = $merged{$topic};
1039 my $in_master = havedone_count
("$merged^1..$merged^2");
1040 my $not_in_maint = havedone_count
("maint..$merged^2");
1041 if ($in_master == $not_in_maint) {
1042 $to_maint{$topic} = 1;
1047 for $topic (@topic) {
1048 next if (exists $to_maint{$topic});
1049 havedone_show
($topic, $topic{$topic});
1055 print "-" x
64, "\n";
1058 for $topic (@topic) {
1059 next unless (exists $to_maint{$topic});
1060 havedone_show
($topic, $topic{$topic});
1061 my $sha1 = `git rev-parse --short $topic`;
1063 print " (merge $sha1 $topic later to maint).\n";
1068 ################################################################
1072 my $cooking = read_previous
('Meta/whats-cooking.txt');
1073 my $topic = get_commit
($cooking);
1074 merge_cooking
($cooking, $topic);
1075 write_cooking
('Meta/whats-cooking.txt', $cooking);
1078 ################################################################
1083 my ($wildo, $havedone);
1084 if (!GetOptions
("wildo" => \
$wildo,
1085 "havedone" => \
$havedone)) {
1086 print STDERR
"$0 [--wildo|--havedone]\n";
1093 open($fd, "<", "Meta/whats-cooking.txt");
1094 } elsif (@ARGV != 1) {
1095 print STDERR
"$0 --wildo [filename|HEAD|-]\n";
1097 } elsif ($ARGV[0] eq '-') {
1099 } elsif ($ARGV[0] =~ /^HEAD/) {
1101 qw(git --git-dir=Meta/.git cat-file -p),
1102 "$ARGV[0]:whats-cooking.txt");
1103 } elsif ($ARGV[0] eq ":") {
1105 qw(git --git-dir=Meta/.git cat-file -p),
1106 ":whats-cooking.txt");
1108 open($fd, "<", $ARGV[0]);
1111 } elsif ($havedone) {