svn老出现多余的文件

早上打开IDE,出现还没写几行代码,多余的文版本控制面板里又冒出来七八个不认识的出现文件。.idea/、多余的文*.iml、出现target/、多余的文node_modules/,出现甚至还有.DS_Store。多余的文明明上次提交前专门清理过,出现怎么又来了?多余的文这不是第一次了,也不会是出现最后一次——除非你真正搞清楚SVN为什么总爱把这些东西翻出来。

问题出在SVN的多余的文工作机制上。它不像Git那样有个本地暂存区让你先过滤一遍,出现SVN直接盯着你的多余的文工作副本目录。只要文件在目录里,出现`svn status`就会把它标成`?`。你没告诉它忽略,它就默认你迟早要提交。更麻烦的是,如果团队里有人手滑提交过一次,那这个文件就进了版本库,之后每个人更新都会拉下来,像野草一样除不干净。

我见过最典型的一个案例:一个五人小组,项目根目录下有个`logs/`文件夹,本来约定不提交。结果某天一个同事用`svn add .`一把梭,把当天生成的十几个日志文件全加进去了。后面其他人更新,本地也出现了这些日志。有人删掉,下次更新又回来——因为版本库里已经有了。折腾了半个月,最后是管理员用`svn delete`从仓库里彻底移除,再让每个人清理本地副本才解决。

那怎么防?第一道防线是`svn:ignore`属性。注意,这个属性是设在目录上的,不是设在文件上。比如你想忽略所有`.class`文件,就在对应目录执行:

svn propset svn:ignore "*.class" . svn propset svn:ignore "target .idea *.iml" .

换行分隔多个模式。设完记得提交这个属性变更,否则只对你本机生效。很多人漏了这一步,然后抱怨“我明明设了忽略,怎么同事那边还是冒出来”。

但`svn:ignore`有个坑:它只对当前目录生效,不递归。子目录里的垃圾文件得单独设。项目大了以后,一个个目录去设很烦。这时候可以用`svn propedit svn:ignore .`来编辑,或者写个脚本批量处理。我自己的习惯是在项目根目录放一个`svn-ignore.txt`,记录所有要忽略的模式,然后用`svn propset -F`批量应用。

第二道防线是全局忽略。在`~/.subversion/config`文件里找到`global-ignores`那一行,去掉注释,加上你常用的模式:

global-ignores = *.o *.lo *.la *.al .libs *.so *.so.[0-9]* *.a *.pyc *.pyo __pycache__ *.class *.jar *.war *.ear target .idea *.iml .DS_Store node_modules

这个配置只影响你本机,不会提交到仓库。好处是新建项目不用每次都设`svn:ignore`,坏处是团队里每个人得自己配。所以正规做法还是两者结合:全局忽略兜底,项目级`svn:ignore`保证一致性。

还有一种情况:文件已经被提交了,现在想忽略。光设`svn:ignore`没用,因为文件已经在版本控制下。得先`svn delete --keep-local`把它从仓库删掉但保留本地文件,提交后再设忽略。顺序反了的话,文件会被重新加回来。

最后说一个观察:很多人用图形化SVN客户端,比如TortoiseSVN,它有个“加入忽略列表”的右键菜单,很方便。但方便的东西容易让人不假思索。我见过有人把`src/`目录整个忽略了,就因为里面有个临时文件。结果新加的源文件死活提交不上去,查了半天才发现是忽略规则写太宽。忽略列表不是垃圾桶,写之前最好看一眼模式匹配的范围。

SVN的多余文件问题,说到底就是“默认不忽略”的设计哲学带来的副作用。Git用`.gitignore`文件,清晰、可版本化、团队共享。SVN的`svn:ignore`是属性,分散在各个目录,容易漏。但既然用了SVN,就只能按它的规矩来:设属性、提交属性、全局配置兜底、定期检查`svn status`。别指望一劳永逸,每次拉新分支或者新同事加入,都可能有新的“惊喜”。