]>
Commit | Line | Data |
---|---|---|
1 | #!/usr/bin/perl -w | |
2 | # | |
3 | # Copyright (c) 2005 Martin Langhoff | |
4 | # | |
5 | # Walk the tags and find if they match a commit | |
6 | # expects a SHA1 of a commit. Option -t enables | |
7 | # searching trees too. | |
8 | # | |
9 | ||
10 | use strict; | |
11 | use File::Basename; | |
12 | use File::Find; | |
13 | use Getopt::Std; | |
14 | ||
15 | my $git_dir = $ENV{GIT_DIR} || '.git'; | |
16 | $git_dir =~ s|/$||; # chomp trailing slash | |
17 | ||
18 | # options | |
19 | our $opt_t; | |
20 | getopts("t") || usage(); | |
21 | ||
22 | my @tagfiles = `find $git_dir/refs/tags -follow -type f`; # haystack | |
23 | my $target = shift @ARGV; # needle | |
24 | unless ($target) { | |
25 | usage(); | |
26 | } | |
27 | ||
28 | # drive the processing from the find hook | |
29 | # slower, safer (?) than the find utility | |
30 | find( { wanted => \&process, | |
31 | no_chdir => 1, | |
32 | follow => 1, | |
33 | }, "$git_dir/refs/tags"); | |
34 | ||
35 | ||
36 | sub process { | |
37 | my ($dev,$ino,$mode,$nlink,$uid,$gid); | |
38 | ||
39 | # process only regular files | |
40 | unless ((($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) && -f _) { | |
41 | return 1; # ignored anyway | |
42 | } | |
43 | ||
44 | my $tagfile = $_; | |
45 | chomp $tagfile; | |
46 | my $tagname = substr($tagfile, length($git_dir.'/refs/tags/')); | |
47 | ||
48 | my $tagid = quickread($tagfile); | |
49 | chomp $tagid; | |
50 | ||
51 | # is it just a soft tag? | |
52 | if ($tagid eq $target) { | |
53 | print "$tagname\n"; | |
54 | return 1; # done with this tag | |
55 | } | |
56 | ||
57 | # grab the first 2 lines (the whole tag could be large) | |
58 | my $tagobj = `git-cat-file tag $tagid | head -n2 `; | |
59 | if ($tagobj =~ m/^type commit$/m) { # only deal with commits | |
60 | ||
61 | if ($tagobj =~ m/^object $target$/m) { # match on the commit | |
62 | print "$tagname\n"; | |
63 | ||
64 | } elsif ( $opt_t && # follow the commit | |
65 | $tagobj =~ m/^object (\S+)$/m) { # and try to match trees | |
66 | my $commitid = $1; | |
67 | my $commitobj = `git-cat-file commit $commitid | head -n1`; | |
68 | chomp $commitobj; | |
69 | $commitobj =~ m/^tree (\S+)$/; | |
70 | my $treeid = $1; | |
71 | if ($target eq $treeid) { | |
72 | print "$tagname\n"; | |
73 | } | |
74 | } | |
75 | } | |
76 | } | |
77 | ||
78 | sub quickread { | |
79 | my $file = shift; | |
80 | local $/; # undef: slurp mode | |
81 | open FILE, "<$file" | |
82 | or die "Cannot open $file : $!"; | |
83 | my $content = <FILE>; | |
84 | close FILE; | |
85 | return $content; | |
86 | } | |
87 | ||
88 | sub usage { | |
89 | print STDERR <<END; | |
90 | Usage: ${\basename $0} # find tags for a commit or tree | |
91 | [ -t ] <commit-or-tree-sha1> | |
92 | END | |
93 | exit(1); | |
94 | } |