Merge branch 'ap/svn'
authorJunio C Hamano <gitster@pobox.com>
Sun, 25 May 2008 20:37:25 +0000 (13:37 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 25 May 2008 20:37:25 +0000 (13:37 -0700)
* ap/svn:
git-svn: add test for --add-author-from and --use-log-author
git-svn: add documentation for --add-author-from option.
git-svn: Add --add-author-from option.
git-svn: add documentation for --use-log-author option.

1  2 
Documentation/git-svn.txt
git-svn.perl
index 3eae1ebb7dc104fd51c5e25d163ec33ab7b61ef1,acd77eb3b2dd188d48f4961c59be82b287470c77..c9e4efe7f4678ecc0beb87b387c71a7ebd0efc71
@@@ -61,6 -61,16 +61,16 @@@ COMMAND
        Set the 'useSvnsyncProps' option in the [svn-remote] config.
  --rewrite-root=<URL>;;
        Set the 'rewriteRoot' option in the [svn-remote] config.
+ --use-log-author;;
+       When retrieving svn commits into git (as part of fetch, rebase, or
+       dcommit operations), look for the first From: or Signed-off-by: line
+       in the log message and use that as the author string.
+ --add-author-from;;
+       When committing to svn from git (as part of commit or dcommit
+       operations), if the existing log message doesn't already have a
+       From: or Signed-off-by: line, append a From: line based on the
+       git commit's author string.  If you use this, then --use-log-author
+       will retrieve a valid author string for all commits.
  --username=<USER>;;
        For transports that SVN handles authentication for (http,
        https, and plain svn), specify the username.  For other
@@@ -166,18 -176,11 +176,18 @@@ environment). This command has the sam
  Any other arguments are passed directly to `git log'
  
  'blame'::
 -       Show what revision and author last modified each line of a file. This is
 -       identical to `git blame', but SVN revision numbers are shown instead of git
 -       commit hashes.
 +       Show what revision and author last modified each line of a file. The
 +       output of this mode is format-compatible with the output of
 +       `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'::
        commit.  All merging is assumed to have taken place
        independently of git-svn functions.
  
 +'create-ignore'::
 +      Recursively finds the svn:ignore property on directories and
 +      creates matching .gitignore files. The resulting files are staged to
 +      be committed, but are not committed. Use -r/--revision to refer to a
 +      specfic revision.
 +
  'show-ignore'::
        Recursively finds and lists the svn:ignore property on
        directories.  The output is suitable for appending to
        argument.  Use the --url option to output only the value of the
        'URL:' field.
  
 +'proplist'::
 +      Lists the properties stored in the Subversion repository about a
 +      given file or directory.  Use -r/--revision to refer to a specific
 +      Subversion revision.
 +
 +'propget'::
 +      Gets the Subversion property given as the first argument, for a
 +      file.  A specific revision can be specified with -r/--revision.
 +
 +'show-externals'::
 +      Shows the Subversion externals.  Use -r/--revision to specify a
 +      specific revision.
 +
  --
  
  OPTIONS
diff --combined git-svn.perl
index 2c53f39aefa0131cb15ab679e6b2633622c000a1,262acd9b365aba6ce5a0e1623e95cefd9c867a45..0e61897b9ecc255d3d22d016b46c90d3a30e9f38
@@@ -65,8 -65,7 +65,8 @@@ my ($_stdin, $_help, $_edit
        $_template, $_shared,
        $_version, $_fetch_all, $_no_rebase,
        $_merge, $_strategy, $_dry_run, $_local,
 -      $_prefix, $_no_checkout, $_url, $_verbose);
 +      $_prefix, $_no_checkout, $_url, $_verbose,
 +      $_git_format);
  $Git::SVN::_follow_parent = 1;
  my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
                      'config-dir=s' => \$Git::SVN::Ra::config_dir,
@@@ -83,6 -82,7 +83,7 @@@ my %fc_opts = ( 'follow-parent|follow!
                'repack-flags|repack-args|repack-opts=s' =>
                   \$Git::SVN::_repack_flags,
                'use-log-author' => \$Git::SVN::_use_log_author,
+               'add-author-from' => \$Git::SVN::_add_author_from,
                %remote_opts );
  
  my ($_trunk, $_tags, $_branches, $_stdlayout);
@@@ -189,7 -189,7 +190,7 @@@ my %cmd = 
                    { 'url' => \$_url, } ],
        'blame' => [ \&Git::SVN::Log::cmd_blame,
                    "Show what revision and author last modified each line of a file",
 -                  {} ],
 +                  { 'git-format' => \$_git_format } ],
  );
  
  my $cmd;
@@@ -226,7 -226,7 +227,7 @@@ unless ($cmd && $cmd =~ /(?:clone|init|
  my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd);
  
  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,
                      'minimize-connections' => \$Git::SVN::Migration::_minimize,
                      'id|i=s' => \$Git::SVN::default_ref_id,
@@@ -615,7 -615,7 +616,7 @@@ sub cmd_create_ignore 
                print GITIGNORE "$s\n";
                close(GITIGNORE)
                  or fatal("Failed to close `$ignore': $!");
 -              command_noisy('add', $ignore);
 +              command_noisy('add', '-f', $ignore);
        });
  }
  
@@@ -1012,17 -1012,28 +1013,28 @@@ sub get_commit_entry 
                my ($msg_fh, $ctx) = command_output_pipe('cat-file',
                                                         $type, $treeish);
                my $in_msg = 0;
+               my $author;
+               my $saw_from = 0;
                while (<$msg_fh>) {
                        if (!$in_msg) {
                                $in_msg = 1 if (/^\s*$/);
+                               $author = $1 if (/^author (.*>)/);
                        } elsif (/^git-svn-id: /) {
                                # skip this for now, we regenerate the
                                # correct one on re-fetch anyways
                                # TODO: set *:merge properties or like...
                        } else {
+                               if (/^From:/ || /^Signed-off-by:/) {
+                                       $saw_from = 1;
+                               }
                                print $log_fh $_ or croak $!;
                        }
                }
+               if ($Git::SVN::_add_author_from && defined($author)
+                   && !$saw_from) {
+                       print $log_fh "\nFrom: $author\n"
+                             or croak $!;
+               }
                command_close_pipe($msg_fh, $ctx);
        }
        close $log_fh or croak $!;
@@@ -1249,7 -1260,7 +1261,7 @@@ use constant rev_map_fmt => 'NH40'
  use vars qw/$default_repo_id $default_ref_id $_no_metadata $_follow_parent
              $_repack $_repack_flags $_use_svm_props $_head
              $_use_svnsync_props $no_reuse_existing $_minimize_url
-           $_use_log_author/;
+           $_use_log_author $_add_author_from/;
  use Carp qw/croak/;
  use File::Path qw/mkpath/;
  use File::Copy qw/copy/;
@@@ -3674,7 -3685,7 +3686,7 @@@ sub escape_uri_only 
        my ($uri) = @_;
        my @tmp;
        foreach (split m{/}, $uri) {
 -              s/([^\w.%-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
 +              s/([^\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
                push @tmp, $_;
        }
        join('/', @tmp);
  }
  
  sub cmd_blame {
 -      my $path = shift;
 +      my $path = pop;
  
        config_pager();
        run_pager();
  
 -      my ($fh, $ctx) = command_output_pipe('blame', @_, $path);
 -      while (my $line = <$fh>) {
 -              if ($line =~ /^\^?([[:xdigit:]]+)\s/) {
 -                      my (undef, $rev, undef) = ::cmt_metadata($1);
 -                      $rev = sprintf('%-10s', $rev);
 -                      $line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/;
 +      my ($fh, $ctx, $rev);
 +
 +      if ($_git_format) {
 +              ($fh, $ctx) = command_output_pipe('blame', @_, $path);
 +              while (my $line = <$fh>) {
 +                      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);
  }