git svn fetch error: 182135 = 1234abcdef already exists! Why are we refetching it?
2018年9月14日症状
我有一个SVN仓库和Git-SVN仓库,两者进行同步。SVN仓库里面有几个提交时间戳不正确,同步到Git-SVN仓库后,时间戳也是不正确的。我手动修复了SVN仓库里的提交时间戳,如图1,然后如何修复Git-SVN仓库里的提交时间戳?
影响
提交时间戳错误可能是微不足道的,但它会影响Git时间搜索功能。例如,在TortoiseGit里搜索1/1/2018到9/14/2018的提交,TortoiseGit就不会显示63a958bd
之前的提交。因为Git发现63a958bd
的时间戳突然变成1969年,便认为之后的提交都是不感兴趣的,作为优化,便不再继续搜索了。
解决方法
运行git svn reset -p 182135
,182135是最早的要修复的提交,所以把git-svn设置成182135的parent,即182134。然后运行git svn fetch
。
按道理应该能正确运行,但是上述命令却提示错误
gqqnbig MINGW64 /c/LoansPQ2-Git-SVN (master)
$ git svn reset 182134
r182134 = c6a305c34c3aef88f086f9b00c91dfd840f9e573 (refs/remotes/git-svn)
gqqnbig MINGW64 /c/LoansPQ2-Git-SVN (master)
$ git svn fetch
Index mismatch: 5570880225692ca3ab9ff3d9d2b2859e37653249 != d10fc78290e99d8e263a647787c6826c39866125
rereading c6a305c34c3aef88f086f9b00c91dfd840f9e573
182135 = 4261a2eb954c1a2907dc2ec4c4691e0a417ad729 already exists! Why are we refetching it?
at C:/Program Files/Git/mingw64/share/perl5/Git/SVN/Ra.pm line 476.
尝试解决
具体错误原因我不是很了解,我一开始以为因为存在4261a2eb这个提交,但发现实际上不存在。我猜可能需要垃圾回收,运行了git gc
和git svn gc
都没用。
我尝试设置svn.ignore-path
忽略r182135修改的文件,制造一个SHA1不同的提交,但也没用。
成功解决
我研究一下Git源代码看看到底是怎么回事。”Why are we refetching it?”存在于C:\Program Files\Git\mingw64\share\perl5\Git\SVN.pm,
sub do_git_commit {
my ($self, $log_entry) = @_;
my $lr = $self->last_rev;
if (defined $lr && $lr >= $log_entry->{revision}) {
die "Last fetched revision of ", $self->refname,
" was r$lr, but we are about to fetch: ",
"r$log_entry->{revision}!\n";
}
if (my $c = $self->rev_map_get($log_entry->{revision})) {
croak "$log_entry->{revision} = $c already exists! ",
"Why are we refetching it?\n";
}
my $old_env = set_commit_header_env($log_entry);
my $tree = $log_entry->{tree};
if (!defined $tree) {
$tree = $self->tmp_index_do(sub {
command_oneline('write-tree') });
}
......
}
我把抛出错误的那几行注释掉,再运行git svn fetch,就可以成功获取提交了。然后,记得把文件改回来。
反思
我的这个方法可以算是奇技淫巧,问题的本质应该是git-svn在检查重复对象时没有考虑时间戳。正确的方法应该要考虑时间戳,再计算SHA1。鉴于Git是开源项目,应该有空修改一下并发起一个拉取请求。