如何在从SVN转换到Git时修改提交信息?

3

我目前正在Github上镜像一个现有的SVN仓库。对于初始克隆,我执行了以下操作:

git svn --authors-prog=fixsvnauthors clone http://closure-compiler.googlecode.com/svn/

为了每小时更新存储库,我这样做:
git svn --authors-prog=fixsvnauthors rebase
fixsvnauthors 将SVN用户名称(电子邮件地址)映射到Git用户名。 我的问题是这个SVN存储库似乎有一个奇怪的提交消息策略。 其中大部分都以空行开头。 Github不喜欢这样做。 所有提交消息摘要都为空,这非常令人恼火。

因此,在克隆期间修复作者是否有一种好方法可以修复提交消息? 我只想修剪提交消息,以便Github正确读取它们。 在git-svn文档中找不到类似这样的东西,但也许我错过了什么。 那么我该如何做呢?

3个回答

1
我创建了一个Git补丁,用于在git-svn中实现--messages-prog参数,该参数可用于指定在从SVN拉取更改时过滤提交消息的程序。对我来说非常有效。我将补丁发送到了Git邮件列表,但没有得到任何反应。也许这个补丁对某些人有用,所以我在这里发布它:
From: Klaus Reimer <k@ailis.de>
Date: Sat, 26 May 2012 17:56:42 +0200
Subject: [PATCH] Implement --messages-prog parameter in git-svn

Some SVN repositories have strange policies for commit messages requiring an
empty line at the top of the commit message.  When you clone these
repositories with Git to mirror them on GitHub then no commit message
summaries are displayed at all at GitHub because they use the first line for
it (Which is empty).  You always have to open the commit message details
instead which is pretty annoying.  With the --messages-prog parameter you
can specify a program which can modify the SVN commit message before
committing it into the Git repo.  This works like the --authors-prog
parameter with the only difference that the commit message is piped into the
specified program instead of being passed to it as a command-line argument.

The same could be achieved by a "trim" feature but specifying a program
which can modify any aspect of a commit message is much more flexible.

Signed-off-by: Klaus Reimer <k@ailis.de>
---
 Documentation/git-svn.txt        |  5 +++++
 git-svn.perl                     | 26 +++++++++++++++++++++++++-
 t/t9147-git-svn-messages-prog.sh | 40 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 70 insertions(+), 1 deletion(-)
 create mode 100755 t/t9147-git-svn-messages-prog.sh

diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index cfe8d2b..7289246 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -546,6 +546,11 @@ config key: svn.authorsfile
    expected to return a single line of the form "Name <email>",
    which will be treated as if included in the authors file.

+--messages-prog=<filename>::
+   If this option is specified, each SVN commit message is piped
+   through the given program. The output of this program is then
+   used as the new commit message instead.
+
 -q::
 --quiet::
    Make 'git svn' less verbose. Specify a second time to make it
diff --git a/git-svn.perl b/git-svn.perl
index c84842f..514c888 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -6,7 +6,7 @@ use warnings;
 use strict;
 use vars qw/   $AUTHOR $VERSION
        $sha1 $sha1_short $_revision $_repository
-       $_q $_authors $_authors_prog %users/;
+       $_q $_authors $_authors_prog $_messages_prog %users/;
 $AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
 $VERSION = '@@GIT_VERSION@@';

@@ -120,6 +120,7 @@ my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
 my %fc_opts = ( 'follow-parent|follow!' => \$Git::SVN::_follow_parent,
        'authors-file|A=s' => \$_authors,
        'authors-prog=s' => \$_authors_prog,
+       'messages-prog=s' => \$_messages_prog,
        'repack:i' => \$Git::SVN::_repack,
        'noMetadata' => \$Git::SVN::_no_metadata,
        'useSvmProps' => \$Git::SVN::_use_svm_props,
@@ -359,6 +360,9 @@ load_authors() if $_authors;
 if (defined $_authors_prog) {
    $_authors_prog = "'" . File::Spec->rel2abs($_authors_prog) . "'";
 }
+if (defined $_messages_prog) {
+   $_messages_prog = "'" . File::Spec->rel2abs($_messages_prog) . "'";
+}

 unless ($cmd =~ /^(?:clone|init|multi-init|commit-diff)$/) {
    Git::SVN::Migration::migration_check();
@@ -2051,6 +2055,7 @@ use vars qw/$default_repo_id $default_ref_id $_no_metadata $_follow_parent
 use Carp qw/croak/;
 use File::Path qw/mkpath/;
 use File::Copy qw/copy/;
+use IPC::Open2;
 use IPC::Open3;
 use Time::Local;
 use Memoize;  # core since 5.8.0, Jul 2002
@@ -3409,6 +3414,22 @@ sub other_gs {
    $gs
 }

+sub call_messages_prog {
+   my ($orig_message) = @_;
+   my ($pid, $in, $out);
+   
+   $pid = open2($in, $out, $::_messages_prog)  
+       or die "$::_messages_prog failed with exit code $?\n";
+   print $out $orig_message;
+   close($out);
+   my ($message) = "";
+   while (<$in>) {
+       $message .= $_;
+   }
+   close($in);
+   return $message;    
+}
+
 sub call_authors_prog {
    my ($orig_author) = @_;
    $orig_author = command_oneline('rev-parse', '--sq-quote', $orig_author);
@@ -3809,6 +3830,9 @@ sub make_log_entry {

    $log_entry{date} = parse_svn_date($log_entry{date});
    $log_entry{log} .= "\n";
+   if (defined $::_messages_prog) {
+       $log_entry{log} = call_messages_prog($log_entry{log});
+   }
    my $author = $log_entry{author} = check_author($log_entry{author});
    my ($name, $email) = defined $::users{$author} ? @{$::users{$author}}
                               : ($author, undef);
diff --git a/t/t9147-git-svn-messages-prog.sh b/t/t9147-git-svn-messages-prog.sh
new file mode 100755
index 0000000..ebb42b0
--- /dev/null
+++ b/t/t9147-git-svn-messages-prog.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+test_description='git svn messages prog tests'
+
+. ./lib-git-svn.sh
+
+cat > svn-messages-prog <<'EOF'
+#!/bin/sh
+sed s/foo/bar/g
+EOF
+chmod +x svn-messages-prog
+
+test_expect_success 'setup svnrepo' '
+   svn mkdir -m "Unchanged message" "$svnrepo"/a
+   svn mkdir -m "Changed message: foo" "$svnrepo"/b
+   '
+
+test_expect_success 'import messages with prog' '
+   git svn clone --messages-prog=./svn-messages-prog \
+       "$svnrepo" x
+   '
+
+test_expect_success 'imported 2 revisions successfully' '
+   (
+       cd x
+       test "`git rev-list refs/remotes/git-svn | wc -l`" -eq 2
+   )
+   '
+
+test_expect_success 'messages-prog ran correctly' '
+   (
+       cd x
+       git rev-list -1 --pretty=raw refs/remotes/git-svn~1 | \
+         grep "^    Unchanged message" &&
+       git rev-list -1 --pretty=raw refs/remotes/git-svn~0 | \
+         grep "^    Changed message: bar"
+   )
+   '
+
+test_done
-- 1.7.10.2.605.gbefc5ed.dirty 

0

我没有找到解决方案,允许您在第一次导入后保留git-svn链接。


对于一次性导入,我认为最好将这种修复作为单独的步骤,在git-svn导入之后进行。
理论上,git嫁接可以用来将原始git存储库中的后续git-svn导入附加到您修复的git存储库中。
然而,git svn dcommit(导出回svn存储库)可能不起作用。

为了确保处理和修复所有分支的所有提交,您可以使用一个

git filter-branch -f --msg-filter 'yourScript.sh' --tag-name-filter cat -- --all

如 "跨多个分支重写 git 提交消息历史" 中所述

filter-branch 功能强大,有许多选项。
在这种情况下,我只想重写提交消息,因此我使用了 --msg-filter 选项:它将每个消息传输到 shell 命令并用该命令的输出替换它。
与重新基于单个编辑的提交不同,这种方法允许您以编程方式编辑所有提交消息。

如果您有任何标签,则应添加 --tag-name-filter cat
这会更新标签以指向修改后的提交。如果标签已签名,则更加复杂。


但这会改写历史。我将无法再使用 git svn rebase 从 SVN 仓库中拉取新的修订版本。 - kayahr
@kayahr true:这仅适用于一次性导入。我已经编辑了答案,以使其更清晰。 - VonC

0

导入完成后,您还可以替换空消息。

git filter-branch --msg-filter '<path>\SetDefaultMessage.pl'

SetDefaultMessage.pl的位置在哪里

#!/usr/bin/perl

my $data = "";    
while(<STDIN>) {
    $data .= $_;
}

if($data =~ /^\s*$/) { $data="-\n"; }
print "$data";

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接