forked from OTRS/module-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
git-find-file.pl
executable file
·140 lines (110 loc) · 4.27 KB
/
git-find-file.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/usr/bin/perl
# --
# module-tools/git-find-file.pl - script to locate a file in the git history
# Copyright (C) 2001-2012 OTRS AG, http://otrs.org/
# --
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU AFFERO General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# or see http://www.gnu.org/licenses/agpl.txt.
# --
=head1 NAME
git-find-file.pl - script to to locate a file in the git history
=head1 SYNOPSIS
git-find-file.pl -f <filename in repository> -t <target file to locate>
=head1 DESCRIPTION
=head1 SUBROUTINES
=over 4
=cut
use strict;
use warnings;
use Getopt::Std;
use String::Similarity;
use File::Spec;
use vars qw($VERSION);
$VERSION = qw($Revision: 1.30 $) [1];
# get options
my %Opts = ();
getopt('fth', \%Opts);
# set default
if (!$Opts{f} || !$Opts{t}) {
$Opts{'h'} = 1;
}
# show the help screen
if ( $Opts{'h'} ) {
print <<EOF;
Copyright (C) 2001-2013 OTRS AG, http://otrs.org/
usage: git-find-file.pl -f <filename in repository> -t <target file to locate>
EOF
exit 1;
}
# Try to split $Opts{f} into the git repository path and the relative filename
# inside of this repository.
my @Directories = split('/', $Opts{f});
splice(@Directories, 0, 1) if $Directories[0] eq '';
my ($RepositoryDirectory, $RelativeFilename);
COUNTER:
for my $Counter (1 .. scalar @Directories) {
my $Directory = "/" . File::Spec->catfile(@Directories[0 .. $Counter - 1]);
if (-d "$Directory/.git") {
$RepositoryDirectory = $Directory;
$RelativeFilename = File::Spec->catfile(@Directories[$Counter .. $#Directories]);
last COUNTER;
}
}
if (!$RepositoryDirectory) {
die "Could not find a git repository in path $Opts{f}.\n";
}
# Change to git repository directory.
chdir($RepositoryDirectory) || die "Could not change working directory to RepositoryDirectory. $!";
# Get all revisions for the requested file
my @FileRevisions = split(/\n/, `git rev-list --all $RelativeFilename`);
print "Found " . (scalar @FileRevisions) . " existing revisions in git history.\n";
# Get the file contents for all revisions.
my %FileContents;
for my $FileRevision (@FileRevisions) {
$FileContents{$FileRevision} = `git show $FileRevision:$RelativeFilename 2>1`;
}
# Get the content of the target file that should be found in the history
open( my $TargetFileHandle, '<', $Opts{t} ) || die "Can't open '$Opts{t}': $!\n";
my $TargetFileContents = do { local $/; <$TargetFileHandle> };
close $TargetFileHandle;
print "Checking for direct matches in git history...\n";
my $DirectMatch;
for my $FileRevision (@FileRevisions) {
# There is one thing that went wrong in the CVS->git migration.
# The format of dates in CVS keyword expansion was YYYY/MM/DD,
# during the git migration it was changed to YYYY-MM-DD.
# Compare against both versions to be able to find a file that comes
# from git or from older CVS directly.
my $FileContentCVS = $FileContents{$FileRevision};
$FileContentCVS =~ s{(\$ (?:Id:|Date:) .*? \d{4})-(\d{2})-(\d{2} .*? \$)}{$1/$2/$3}xmsg;
if ($TargetFileContents eq $FileContents{$FileRevision}
|| $TargetFileContents eq $FileContentCVS
) {
print $FileRevision . "\n";
$DirectMatch++;
}
}
exit 0 if $DirectMatch;
print "No direct matches found, checking similiarity index...\n";
my %SimilarityIndex;
for my $FileRevision (@FileRevisions) {
my $Similarity = similarity($TargetFileContents, $FileContents{$FileRevision});
$SimilarityIndex{ $FileRevision } = $Similarity;
}
my @SimilarVersions = sort { $SimilarityIndex{$b} <=> $SimilarityIndex{$a} } keys %SimilarityIndex;
for my $FileRevision (splice @SimilarVersions, 0, 10) {
print "$FileRevision " . sprintf("%.3f", $SimilarityIndex{$FileRevision} * 100) . "\n";
}
exit 0;