您可以按如下方式进行操作。
首先是通常的序言:
#! /usr/bin/perl
use warnings;
use strict;
Use git for-each-ref收集每个引用的 SHA-1 和名称:
sub refs {
open my $fh, "-|", "git", "for-each-ref",
"--format=%(objectname)\t%(refname:short)"
or die "$0: failed to run git for-each-ref";
my %ref2sha;
while (<$fh>) {
chomp;
my($sha,$ref) = split /\t/;
$ref2sha{$ref} = $sha;
}
\%ref2sha;
}
如果提交是子项HEAD
,可从以下位置到达的提交集HEAD
排除从有问题的提交中可到达的所有内容就是空集。我们可以检查这种关系git rev-list.
sub is_child {
my($ref) = @_;
# git rev-list ^dev master
my $refs = `git rev-list ^$ref HEAD -- 2>&1`;
die "$0: git rev-list-failed.\n$refs" if $?;
$refs !~ /\S/;
}
对于每个 ref 的后代HEAD
但它不等于HEAD
,我们检查来自的路径HEAD
到该参考使用git log。如果路径包含另一个分支的尖端,则 ref 不能是第一级子级。
所有这场挑战的幸存者都是一级子弟。
chomp(my $head = `git rev-parse HEAD 2>&1`);
die "$0: git rev-parse failed.\n$head" if $?;
my $ref2sha = refs;
my %headsha = reverse %$ref2sha;
REF:
foreach my $ref (keys %$ref2sha) {
my $refsha = $ref2sha->{$ref};
next if $refsha eq $head || !is_child $ref;
my @log = `git log --pretty=format:%H ..$ref 2>&1`;
die "$0: git log failed.\n@log" if $?;
for (@log) {
chomp;
next if $_ eq $refsha;
next REF if exists $headsha{$_};
}
print $ref, "\n";
}