文章目录
前言
TortoiseSVN
作为版本控制常用的工具,有一个更为人们熟知的名字 SVN
,客观的讲SVN的门槛相比Git而言还是低一些的,用来存储一些文件并保留历史记录比较方便,但使用SVN还是会经常需要这样那样的问题,特别是当仓库很大的时候,提示的问题往往让初学者、甚至是经常使用的人一脸懵,比如这个 Checksum mismatch for
问题,通常SVN问题都有一个终极解法,那就是重新克隆一份再操作,这就像大多数的电脑问题重启后就能解决一样,不过偶尔有一些情景不适合采用重新克隆的解法,我们就得想一个更精确的办法去解决了。
问题的产生
在克隆一个300多G的库时,报了下面这个错误,总结来说这个错误表述的就是"心有所求而不得",期望得到一个md5是 2c448c9f40b0dd561539b80ec3cfcaa2
的 bundle_103_cp_delafere_e_buff_wuqi.ab
文件,但是下载后的文件计算md5得到的是 a2e41ec2779a23d88b31e4237ad43ceb
,并不是自己想要的,提示如下:
bash
Error: Checksum mismatch for
Error: 'E:\gameproject\prefabs\bundle_103_cp_delafere_e_buff_wuqi.ab':
Error:
Error: expected: 2c448c9f40b0dd561539b80ec3cfcaa2
Error: actual: a2e41ec2779a23d88b31e4237ad43ceb
探索解决方案
先说说网上一些常见的解决办法:
- 删除了整个库,重新克隆下载,这个方法99%可行,但是整个库太大了,我不想重新下载
Clean up
之后继续更新,我试过了不行- 先在出错的文件夹下执行
svn update --set-depth empty
删除文件夹下所有文件,再执行svn update --set-depth infinity
更新,这是流传的最广的解决办法,在我这不行 - 先在
Update to revision...
中选择 Update Depth 为Only this item
更新,然后再选择Fully recursive
更新,原理上和上一步类似,在我这也不行
其实仔细分析这几种解决方案的本质,都是把错误的文件删除掉再重新更新,但是为什么不起作用呢?
从我最终解决问题的方法来看是,针对我遇到的问题,上面提到的一些方法并没有将错误的文件成功删除,简单分析下svn克隆和更新的过程,很可能不准确,但是我不在此处不深究,暂时还用不到这一块。
我们在传输文件时为了保证文件的完整性,经常会用一些摘要算法比如md5、sha1等来计算文件摘要,通过比较文件摘要来判断文件传输是否完整,而SVN这个工具每时每刻都在上传下载传输文件,所以也用到了摘要比对的技术。
以较新的SVN版本为例,是将sha1和md5存到了.svn/wc.db
中(太老的版本md5是存储到文件中的),下载时先更新 wc.db
,然后将原始文件的元文件下载到 .svn/pristine
文件夹中,然后比较这些文件的md5值与 wc.db
记录的md5值是否一致,如果一样就从元文件中提取出真正的文件放到库中,这个文件就算下载完了,如果不一致就会报出上面的错误。
分析过后我们只要找到错误的元文件,删除后重新下载就解决了。
正式的解决方法
首先打开从 .svn/wc.db
中查找的元文件的名字,可以使用你熟悉的工具,我用的是 SQLiteSpy.exe
有图形界面方便一下,最基础的也可以用 sqlite3.exe
这种命令行的工具,执行以下sql语句:
sql
select * from NODES where local_relpath = 'prefabs/bundle_103_cp_delafere_e_buff_wuqi.ab'
执行过后可以查到checksum列的值为 $sha1$f9fd60e244a004cc30fcc83e8e59e7466b3dca6a
,这就是元文件的名字,也可以通过下面的语句查到md5值
sql
select * from PRISTINE where checksum = '$sha1$f9fd60e244a004cc30fcc83e8e59e7466b3dca6a';
结果中md5_checksum列的值为 $md5$2c448c9f40b0dd561539b80ec3cfcaa2
就是报错中提到的那个期望值了。
接下来进入 .svn/pristine/f9
文件夹,删除 f9fd60e244a004cc30fcc83e8e59e7466b3dca6a.svn-base
文件,然后在仓库根目录更新就正常了
背后的故事
问题解决了,那么产生的这种问题的原因是什么呢?为什么会md5值不一致呢?我们知道文件的md5值是根据文件内容计算出来的,下载后的文件md5不是预期的值说明文件内容发生了变化。
我用比较工具对比了正常的文件和出错的文件发现,两个大小都为29949字节的文件,其中有一个字节发生了偏差,正确的文件该字节值为 2F
,而错误的文件对应值为 2E
,就弄错了这一个字节,导致SVN的文件比对报错了。
这一个字节差异产生的原因,可能有很多种,比如传输过程中数据损坏、压缩或加密问题、数据损坏或硬盘问题,我这里大概率是因为下载时机器重启的原因。
这让我想起了7、8年前下载游戏服务器包无法启动的问题,当时下载完启动各种异常,比较文件大小也是一样的,但是计算md5后发现不同,应该也是传输过程中发生了错误。
总结
- SVN遇到的问题有90%都可以通过完整删除后重新克隆下载的方式解决
- 老版本的文件checksum值存储到
.svn/entries
文件中,较新版本的文件将这些值存储在.svn/wc.db
中 - 通过
select * from NODES where local_relpath = 'xxx'
方式可以从.svn/wc.db
中查到文件的 sha1值 - 在
svn/pristine
中找到$sha1$.svn-base
删除即可重新下载了
待到秋来九月八,我花开后百花杀。有些句子在经历了一些事以后,自然而然就有了新的理解,这与儿时死记硬背下来的赏析是完全不同的~