git svn dcommit with svn usernames
I'm trying to use git on top of an older subversion repository. We have multiple users working on the new git remote (origin/master) which is a git svn clone of the older repo. The problem is when 开发者_运维技巧we do a git svn dcommit to push changes from the new git repo to the old subversion repo, the commiter's username is lost and instead is replaced by the git svn clone'd user's information. Is there a way to preserve the commiter's info into the subversion upon a dcommit?
You can use git-svn with --add-author-from
and --use-log-author
. The former represents the git author in a From:
line in the commit message, the latter does the reverse transformation.
That said, repository formats matter, and the subversion repository format is poorer than the git one. It doesn't support merging well, or committers vs authors or commit times distinct from push times. git-svn is OK to get the git ui locally, but it can't do much about the data model. Hopefully you'll be able to migrate to a git repository, possibly with an svn frontend (right now there is git-svnserver and github's closed source option).
I know this is a very old topic, but if anyone is interested I added this hack to my local copy of git-svn:
23a24
> use POSIX qw/strftime/;
984a986
> my $ra = Git::SVN::Ra->new($url);
987c989
< ra => Git::SVN::Ra->new($url),
---
> ra => $ra,
995a998,1014
> my $cmt_author = get_commit_entry($d)->{author};
> my $cmt_date = get_commit_entry($d)->{date};
> if ( defined $cmt_author ) {
> foreach my $key ( keys %users ) {
> my $i = index($cmt_author, $users{$key}[1]);
> if ( $i != -1 ) {
> print "Changed author to $key\n";
> $ra->change_rev_prop($cmt_rev, 'svn:author', $key);
> last;
> }
> }
> }
> if ( defined $cmt_date ) {
> $cmt_date = strftime("%Y-%m-%dT%H:%M:%S.000000Z", gmtime($cmt_date));
> print "Changed date to $cmt_date\n";
> $ra->change_rev_prop($cmt_rev, 'svn:date', $cmt_date);
> }
1758c1777
< my %log_entry = ( log => '', tree => get_tree_from_treeish($treeish) );
---
> my %log_entry = ( log => '', tree => get_tree_from_treeish($treeish), author => undef, date => undef );
1768a1788
> my $date;
1774c1794,1797
< $author = $1 if (/^author (.*>)/);
---
> if (/^author (.*>) (\d+) ([\-\+]?\d+)$/o) {
> $author = $1;
> $date = Git::SVN::Log::parse_git_date($2, $3);
> }
1792a1816,1817
> $log_entry{author} = $author || undef;
> $log_entry{date} = $date || undef;
This is against 1.9.1-1 (deb package version on Ubuntu 14.04). It's not configurable, in the sense that if you've got a users.txt file it will use it, and it will always try and set the date. Also if you have multiple SVN accounts for a given git user it will just pick one.
And I'm only just starting to use it in anger, but I think it might do the job, fingers crossed!
Regards Adam
I modified a bit the patch proposed by Adam Sutton so that git svn dcommit
accepts --commit-author
option:
--- ./git-svn.orig 2014-10-09 23:11:40.032767542 +0300
+++ ./git-svn 2014-10-09 23:27:58.252753020 +0300
@@ -116,7 +116,7 @@
$_before, $_after,
$_merge, $_strategy, $_preserve_merges, $_dry_run, $_parents, $_local,
$_prefix, $_no_checkout, $_url, $_verbose,
- $_commit_url, $_tag, $_merge_info, $_interactive);
+ $_commit_url, $_commit_author, $_tag, $_merge_info, $_interactive);
# This is a refactoring artifact so Git::SVN can get at this git-svn switch.
sub opt_prefix { return $_prefix || '' }
@@ -194,6 +194,7 @@
'dry-run|n' => \$_dry_run,
'fetch-all|all' => \$_fetch_all,
'commit-url=s' => \$_commit_url,
+ 'commit-author=s' => \$_commit_author,
'revision|r=i' => \$_revision,
'no-rebase' => \$_no_rebase,
'mergeinfo=s' => \$_merge_info,
@@ -982,6 +983,7 @@
$rewritten_parent);
}
+ my $ra = Git::SVN::Ra->new($url);
my %ed_opts = ( r => $last_rev,
log => get_commit_entry($d)->{log},
ra => $ra,
@@ -993,6 +995,10 @@
editor_cb => sub {
print "Committed r$_[0]\n";
$cmt_rev = $_[0];
+ if (defined($_commit_author)) {
+ print "Changed author to $_commit_author\n";
+ $ra->change_rev_prop($cmt_rev, 'svn:author', $_commit_author);
+ }
},
mergeinfo => $_merge_info,
svn_path => '');
@@ -1790,6 +1796,7 @@
}
print $log_fh $msgbuf or croak $!;
command_close_pipe($msg_fh, $ctx);
+ $log_entry{author} = $author || undef;
}
close $log_fh or croak $!;
Require everyone to use a "signed-off-by" or some other way of including their username in the message of every commit. It's a pretty ugly solution, but AFAIK the only thing you can do without hacking the git-svn source.
This is another slightly modified version from Adam Sutton's Answer It creates a reverse mapping from the authors file and does some extra checking for duplicate and/or missing authors. It also tells you in the input which Git user was mapped to which SVN user for each commit, even when running git svn dcommit --dry-run.
[root@qa-travel-centos git-svn-bridge]# diff scripts/git-svn.orig scripts/git-svn.hacked
23a24
> use POSIX;
963a965,975
>
> #Revert the keys/values from authors into a reverse map.
> #If a duplicate is found(i.e. 2 git users matching 1 svn user) abort the operation.
> my %rev_author_map;
> while (my ($key, @value) = each %users) {
> my $rev_key="$value[0][0] <$value[0][1]>";
> if(exists $rev_author_map{$rev_key}) {
> fatal "Found a duplicate GIT author($rev_key) in the authorsfile. Aborting dcommit!"
> }
> $rev_author_map{$rev_key}=$key
> }
972a985,997
> my $commit_entry = get_commit_entry($d);
> my $cmt_author = $commit_entry->{author};
> my $cmt_date = $commit_entry->{date};
> print "GIT AUTHOR: $cmt_author; \n";
> if(defined $cmt_author) {
> my $svn_author = $rev_author_map{$cmt_author};
> #Here we check if the git commit author matches an author in the authorsfile
> if ((not (defined $svn_author)) || $svn_author eq "") {
> fatal "The git author: $cmt_author was not found in the authors file. Make sure you have commited as a user listed in the authors file. Note:matching is case sensitive.";
> }
> print "SVN AUTHOR: $svn_author\n";
> }
>
984c1009
<
---
> my $ra = Git::SVN::Ra->new($url);
987c1012
< ra => Git::SVN::Ra->new($url),
---
> ra => $ra,
995a1021,1032
> #Here we coerce SVN into accepting the correct user according to the reverse mapping.
> if(defined $cmt_author) {
> my $svn_author = $rev_author_map{$cmt_author};
> print "SVN AUTHOR: $svn_author\n";
> $ra->change_rev_prop($cmt_rev, 'svn:author', $svn_author)
> }
> #Here we coerce SVN into accepting the commit date from Git.
> if ( defined $cmt_date ) {
> $cmt_date = strftime("%Y-%m-%dT%H:%M:%S.000000Z", gmtime($cmt_date));
> print "SVN DATE SET TO: $cmt_date\n";
> $ra->change_rev_prop($cmt_rev, 'svn:date', $cmt_date);
> }
1748c1785
< my %log_entry = ( log => '', tree => get_tree_from_treeish($treeish) );
---
> my %log_entry = ( log => '', tree => get_tree_from_treeish($treeish), author =>undef, date => undef );
1758a1796
> my $date;
1764c1802,1805
< $author = $1 if (/^author (.*>)/);
---
> if(/^author (.*>) (\d+) ([\-\+]?\d+)$/o){
> $author = $1;
> $date = $2;
> }
1782a1824,1825
> $log_entry{author} = $author || undef;
> $log_entry{date} = $date || undef;
Github to the rescue as usual! Their quick overview of git svn goes into user mapping: http://help.github.com/svn-importing/
Basically, you create a file that contains the mappings you want.
精彩评论