From: Chris Mason Date: Wed, 27 Apr 2005 16:50:59 GMT Subject: Finding file revisions Message-ID: <200504271251.00635.mason@suse.com> Hello everyone, I haven't seen a tool yet to find which changeset modified a given file, so I whipped up something. The basic idea is to: for each changeset in rev-list for each file in diff-tree -r parent changeset match against desired files Is there a faster way? This will scale pretty badly as the tree grows, but I usually only want to search back a few months in the history. So, it might make sense to limit the results by date or commit/tag. Usage: file-changes [-c commit id] file1 ... The file names can be perl regular expressions, and it will match any file starting with the expression listed. So "file-changes fs/ext" will show everything in ext2 and ext3. Example output: diff-tree -r 56022b4d00cae3ff816d3ff05d9f8a80e1517c60 9bd104d712d710d53c35166e40bd5fe24caf893e 8a796b48e757e56b50802c28abf28e0199c45ad9->2db368df614de4799be2d1baffb6563dbe1b8926 fs/ext2/inode.c dbc8fd9bab639b84b8cc94fdbbf850b1e4bf1b2b->a4cd819734ba2eea9d5d21039deca62057f72d44 fs/ext3/inode.c cat-file commit 9bd104d712d710d53c35166e40bd5fe24caf893e tree cd4e40eae003e29c0d3be2aa769c3b572ab1b488 parent 56022b4d00cae3ff816d3ff05d9f8a80e1517c60 author mason 1114617717 -0400 committer mason 1114617717 -0400 comments go here This is meant for cut n' paste. If you find a changeset comment you like, run the diff-tree -r command on the first line to see a diff of the changeset (maybe I should add | diff-tree-helper here?) -chris #!/usr/bin/perl use strict; my $last; my $ret; my $i; my @wanted = (); my $matched; my $argc = scalar(@ARGV); my $commit; sub print_usage() { print STDERR "usage: file-changes [-c commit] file_list\n"; exit(1); } if ($argc < 1) { print_usage(); } for ($i = 0 ; $i < $argc ; $i++) { if ($ARGV[$i] eq "-c") { if ($i == $argc - 1) { print_usage(); } $commit = $ARGV[++$i]; } else { push @wanted, $ARGV[$i]; } } if (!defined($commit)) { $commit = `commit-id`; if ($?) { print STDERR "commit-id failed, try using -c to specify a commit\n"; exit(1); } chomp $commit; } $last = $commit; open(RL, "rev-list $commit|") || die "rev-list failed"; while() { chomp; my $cur = $_; $matched = 0; if ($cur eq $last) { next; } # rev-list gives us the commits from newest to oldest open(DT, "diff-tree -r $cur $last|") || die "diff-tree failed"; while(
) { chomp; my @words = split; my $file = $words[3]; # if the filename has whitespace, suck it in if (scalar(@words) > 4) { if (m/$file(.*)/) { $file .= $1; } } foreach my $m (@wanted) { if ($file =~ m/^$m/) { if (!$matched) { print "diff-tree -r $cur $last\n"; } print "$words[2] $file\n"; $matched = 1; } } } close(DT); if ($?) { $ret = $? >> 8; die "diff-tree failed with $ret"; } if ($matched) { print "cat-file commit $last\n"; open(COMMIT, "cat-file commit $last|") || die "cat-file $last failed"; while() { print " $_"; } close(COMMIT); if ($?) { $ret = $? >> 8; die "cat-file failed with $ret"; } print "\n"; } $last = $cur; } close(RL); if ($?) { $ret = $? >> 8; die "rev-list failed with $ret"; }