Add svn-compatible "blame" output format to git-svn
git-svn blame produced output in the format of git blame; in environments where there are scripts that read the output of svn blame, it's useful to be able to use them with the output of git-svn. The git-compatible format is still available using the new "--git-format" option. This also fixes a bug in the initial git-svn blame implementation; it was bombing out on uncommitted local changes. Signed-off-by: Steven Grimm <koreth@midwinter.com> Acked-by: Eric Wong <normalperson@yhbt.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
f4e9f786f7
commit
4be4038153
@ -166,11 +166,18 @@ environment). This command has the same behaviour.
|
|||||||
Any other arguments are passed directly to `git log'
|
Any other arguments are passed directly to `git log'
|
||||||
|
|
||||||
'blame'::
|
'blame'::
|
||||||
Show what revision and author last modified each line of a file. This is
|
Show what revision and author last modified each line of a file. The
|
||||||
identical to `git blame', but SVN revision numbers are shown instead of git
|
output of this mode is format-compatible with the output of
|
||||||
commit hashes.
|
`svn blame' by default. Like the SVN blame command,
|
||||||
|
local uncommitted changes in the working copy are ignored;
|
||||||
|
the version of the file in the HEAD revision is annotated. Unknown
|
||||||
|
arguments are passed directly to git-blame.
|
||||||
+
|
+
|
||||||
All arguments are passed directly to `git blame'.
|
--git-format;;
|
||||||
|
Produce output in the same format as `git blame', but with
|
||||||
|
SVN revision numbers instead of git commit hashes. In this mode,
|
||||||
|
changes that haven't been committed to SVN (including local
|
||||||
|
working-copy edits) are shown as revision 0.
|
||||||
|
|
||||||
--
|
--
|
||||||
'find-rev'::
|
'find-rev'::
|
||||||
|
55
git-svn.perl
55
git-svn.perl
@ -65,7 +65,8 @@ my ($_stdin, $_help, $_edit,
|
|||||||
$_template, $_shared,
|
$_template, $_shared,
|
||||||
$_version, $_fetch_all, $_no_rebase,
|
$_version, $_fetch_all, $_no_rebase,
|
||||||
$_merge, $_strategy, $_dry_run, $_local,
|
$_merge, $_strategy, $_dry_run, $_local,
|
||||||
$_prefix, $_no_checkout, $_url, $_verbose);
|
$_prefix, $_no_checkout, $_url, $_verbose,
|
||||||
|
$_git_format);
|
||||||
$Git::SVN::_follow_parent = 1;
|
$Git::SVN::_follow_parent = 1;
|
||||||
my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
|
my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
|
||||||
'config-dir=s' => \$Git::SVN::Ra::config_dir,
|
'config-dir=s' => \$Git::SVN::Ra::config_dir,
|
||||||
@ -188,7 +189,7 @@ my %cmd = (
|
|||||||
{ 'url' => \$_url, } ],
|
{ 'url' => \$_url, } ],
|
||||||
'blame' => [ \&Git::SVN::Log::cmd_blame,
|
'blame' => [ \&Git::SVN::Log::cmd_blame,
|
||||||
"Show what revision and author last modified each line of a file",
|
"Show what revision and author last modified each line of a file",
|
||||||
{} ],
|
{ 'git-format' => \$_git_format } ],
|
||||||
);
|
);
|
||||||
|
|
||||||
my $cmd;
|
my $cmd;
|
||||||
@ -225,7 +226,7 @@ unless ($cmd && $cmd =~ /(?:clone|init|multi-init)$/) {
|
|||||||
my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd);
|
my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd);
|
||||||
|
|
||||||
read_repo_config(\%opts);
|
read_repo_config(\%opts);
|
||||||
Getopt::Long::Configure('pass_through') if ($cmd && $cmd eq 'log');
|
Getopt::Long::Configure('pass_through') if ($cmd && ($cmd eq 'log' || $cmd eq 'blame'));
|
||||||
my $rv = GetOptions(%opts, 'help|H|h' => \$_help, 'version|V' => \$_version,
|
my $rv = GetOptions(%opts, 'help|H|h' => \$_help, 'version|V' => \$_version,
|
||||||
'minimize-connections' => \$Git::SVN::Migration::_minimize,
|
'minimize-connections' => \$Git::SVN::Migration::_minimize,
|
||||||
'id|i=s' => \$Git::SVN::default_ref_id,
|
'id|i=s' => \$Git::SVN::default_ref_id,
|
||||||
@ -4468,19 +4469,51 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub cmd_blame {
|
sub cmd_blame {
|
||||||
my $path = shift;
|
my $path = pop;
|
||||||
|
|
||||||
config_pager();
|
config_pager();
|
||||||
run_pager();
|
run_pager();
|
||||||
|
|
||||||
my ($fh, $ctx) = command_output_pipe('blame', @_, $path);
|
my ($fh, $ctx, $rev);
|
||||||
while (my $line = <$fh>) {
|
|
||||||
if ($line =~ /^\^?([[:xdigit:]]+)\s/) {
|
if ($_git_format) {
|
||||||
my (undef, $rev, undef) = ::cmt_metadata($1);
|
($fh, $ctx) = command_output_pipe('blame', @_, $path);
|
||||||
$rev = sprintf('%-10s', $rev);
|
while (my $line = <$fh>) {
|
||||||
$line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/;
|
if ($line =~ /^\^?([[:xdigit:]]+)\s/) {
|
||||||
|
# Uncommitted edits show up as a rev ID of
|
||||||
|
# all zeros, which we can't look up with
|
||||||
|
# cmt_metadata
|
||||||
|
if ($1 !~ /^0+$/) {
|
||||||
|
(undef, $rev, undef) =
|
||||||
|
::cmt_metadata($1);
|
||||||
|
$rev = '0' if (!$rev);
|
||||||
|
} else {
|
||||||
|
$rev = '0';
|
||||||
|
}
|
||||||
|
$rev = sprintf('%-10s', $rev);
|
||||||
|
$line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/;
|
||||||
|
}
|
||||||
|
print $line;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
($fh, $ctx) = command_output_pipe('blame', '-p', @_, 'HEAD',
|
||||||
|
'--', $path);
|
||||||
|
my ($sha1);
|
||||||
|
my %authors;
|
||||||
|
while (my $line = <$fh>) {
|
||||||
|
if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) {
|
||||||
|
$sha1 = $1;
|
||||||
|
(undef, $rev, undef) = ::cmt_metadata($1);
|
||||||
|
$rev = '0' if (!$rev);
|
||||||
|
}
|
||||||
|
elsif ($line =~ /^author (.*)/) {
|
||||||
|
$authors{$rev} = $1;
|
||||||
|
$authors{$rev} =~ s/\s/_/g;
|
||||||
|
}
|
||||||
|
elsif ($line =~ /^\t(.*)$/) {
|
||||||
|
printf("%6s %10s %s\n", $rev, $authors{$rev}, $1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
print $line;
|
|
||||||
}
|
}
|
||||||
command_close_pipe($fh, $ctx);
|
command_close_pipe($fh, $ctx);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user