ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SVN提交.so文件被忽略?详解默认忽略规则与三招解法

SVN提交.so文件被忽略?详解默认忽略规则与三招解法 有同事在群里甩了一张截图svn add一个编译好的动态库libopencv.so命令直接报出一串警告提交窗口里翻来覆去找不到这个文件。说实话SVN 用户遇到 .so 文件提交不上去的情况太常见了尤其是从 Git 转过来、或者第一次在项目里加入预编译库的同学第一反应基本都是是不是权限出问题了是不是文件被锁了。实际上原因非常简单就藏在 SVN 的默认忽略规则里。今天把这个问题从现象到原理、从应急处理到团队规范一次性讲透。1. 先说现象.so 文件消失的三种现场1.1 提交窗口里压根没有这个文件最典型的表现是本地编译完生成了libxxx.so文件安安静静躺在磁盘上但在 TortoiseSVN 的提交窗口里就是看不到它。你把整个文件列表翻到底、搜索文件名一无所获。此时右键文件看属性SVN 菜单里甚至没有添加选项文件图标也只是一个普通图标没有绿色的加号也没有蓝色的忽略标记。这一现象会让很多人误以为文件没有加入版本控制——这话对也不对。它确实还没有加入版本控制但更关键的是它已经被客户端主动跳过。跳过的依据就是我们后面要说的忽略规则。注意这里的跳过发生在客户端计算提交候选集的阶段跟服务器、权限、网络都没有关系。也就是说这个问题你在本地就能定性不需要找管理员。1.2 svn add 命令直接给出警告命令行场景更直白。你在项目根目录执行svn add libxxx.so输出的警告大致是这两种格式之一svn: warning: W150002: /path/to/libxxx.so is already under version control svn: warning: W155010: /path/to/libxxx.so is set to be ignored不同 SVN 版本的文案略有差异但共同点是这个文件没有被成功加入。如果你看到ignored或is set to be ignored字样基本就可以锁定问题方向了。还有不少人在这一步被 already under version control 误导以为文件已经在库了于是直接去 commit结果提交列表里还是没有它——因为这条警告的真实含义是说这个路径已经被忽略了SVN 不会再把它列为可提交对象。1.3 仓库里明明有 .so本地却像没这个文件第三种情况稍微绕一点有人检查仓库发现某目录里确实有一个历史版本的.so文件但本地工作副本里怎么找都找不见或者本地明明有修改后提交却提示没有改动。这类问题虽然表面和提交不上去不太一样但需要和忽略规则区分开。先说结论忽略规则只对尚未纳入版本控制的文件生效已经提交进版本库的文件不会被 svn:ignore 或 global-ignores 影响。所以如果仓库里有而你本地没有多半是 checkout 不完整、目录被手动删除过、或者有人用svn rm把它删掉了。而本地有、提交提示无变化则更可能是文件权限、时间戳或大小写路径造成的判断问题。把这条分清能少走很多弯路。1.4 用一条命令给文件验明正身与其靠猜不如直接向 SVN 要状态。在文件所在目录执行svn status libxxx.so如果上面这条什么都不输出再执行svn status --no-ignore libxxx.so正常情况下你会看到一行I libxxx.so。这个I就是 Ignored 的缩写意思是文件在磁盘上没有被纳入版本控制而且被忽略规则挡住了。SVN 状态码的含义值得记一下以后排查问题能用上状态码含义说明?未版本控制文件存在但 SVN 没见过它I被忽略文件存在但被忽略规则屏蔽A已添加已执行 svn add待提交M已修改版本库已有本地改动待提交D已删除已执行 svn delete待提交!缺失版本库有记录但本地文件丢失C冲突更新时发生冲突需要人工处理看到I就不用再往下猜了问题定性完毕。剩下的就是搞清楚到底是谁让它变成了I。2. 根因追踪SVN 的默认忽略规则为什么会盯上 .so2.1 默认配置里躺着一整排编译产物SVN 客户端安装完成之后自带一套global-ignores配置正常情况下你根本不会发现它但它一直在默默起作用。命令行客户端的配置写在~/.subversion/config文件里TortoiseSVN 则放在设置面板中。截取其中默认内容的一部分global-ignores *.o *.lo *.la *.al .libs *.so *.so.[0-9]* *.a *.pyc *.pyo __pycache__ *.rej *~ #*# .#* .svn *~ .swp .DS_Store看到没有*.so和*.so.[0-9]*都在列表里。前者匹配所有.so结尾的文件后者匹配带版本号的动态库比如libxxx.so.1、libxxx.so.1.0。也就是说SVN 从设计之初就没打算让你把.so文件提交上去——它是主动把你挡在外面的。2.2 设计者的考虑源码库不欢迎编译产物那 SVN 为什么要这样设计说到底是历史原因。SVN 的年代网络带宽和磁盘空间都很宝贵版本库对二进制文件的支持又非常糟糕一个文本文件你可以做增量 diff一个.so文件在 SVN 看来就是一坨不知道什么内容的大块头每次改动都要整份存进仓库。一个几十 MB 的动态库团队里十个人各提交一次仓库体积立刻增加几百 MB代价相当可观。所以 SVN 的默认策略是把它们全部当作不该进源码库的编译残留屏蔽掉。这个逻辑在今天依然说得通——绝大多数.so都能通过源码重新构建出来没必要让每个编译产物都污染仓库历史。可以理解为快递柜默认不接收生鲜件不是规定死不能收而是默认不帮你收你真要寄走人工通道说一声就行。2.3 三层忽略机制别再混为一谈真正到了配置层面SVN 的忽略规则其实分三层很多人把它们的用途和生效范围搞混才会越改越乱。配置项配置文件/位置作用范围是否入库说明global-ignores客户端~/.subversion/config或 TortoiseSVN 设置本机全部工作副本否客户端级全局规则svn:ignore目录属性随目录提交当前目录及一级子层不含递归子目录是项目级规则团队成员共享svn:global-ignores版本化属性SVN 1.8递归作用于目录树是适合全项目统一忽略这三层会同时生效规则之间是并集关系只要其中任何一个命中了你的文件路径这个文件就会被忽略。对于.so文件来说最常见的拦截者其实是第一层global-ignores因为它是客户端自带的默认值而团队项目里第二层svn:ignore如果写上了*.so那就是雪上加霜。还有一条关键性质需要单独强调无论哪一层忽略规则都不会影响已经处于版本控制下的文件。换句话说文件一旦成功 add 并 commit之后你改了它、删了它、更新它都不再受忽略规则约束。这也是为什么先强制加入一次能彻底解决某个具体文件的提交问题。2.4 这个坑为什么能流行二十年按理说一个默认配置导致的坑大家踩一次就该记住了。但现实是这个坑在论坛、技术群、搜索栏里反复出现原因有三点第一大部分人从来没打开过~/.subversion/config连global-ignores的存在都不知道第二新版 IDE 和 TortoiseSVN 帮用户藏了很多底层细节文件消失了用户还以为是自己操作问题第三相关资料要么只给一句在忽略里删掉 .so要么讲得很零散很少有人把三层机制一次讲明白。所以你别看这个问题小能把来龙去脉讲清楚的人比想象中少得多。3. 对症下药从应急命令到全局配置的三套解法3.1 最快救急--no-ignore 强制添加如果你只是想尽快把某一个.so文件提交到库并且不想动任何配置用--no-ignore是最直接的办法svn add --no-ignore libxxx.so svn commit -m add libxxx.so第一次执行svn add的时候--no-ignore的作用是告诉 SVN这次添加操作忽略掉所有忽略规则把这个文件给我加进来。 文件加入后svn status会显示A提交完成之后就变成了正常的版本化文件。以后你新生成一个同名文件并覆盖它再提交时完全不需要--no-ignore因为它已经是版本控制下的文件了。这里有三个细节要注意。第一--no-ignore是svn add的参数不是svn commit的参数commit 阶段不需要做任何特殊处理。第二如果你的 SVN 版本比较老1.8 以下可能不认识这个参数那就需要把svn升级到新版本或者先改全局配置再 add。第三如果一次性要添加多个文件可以用svn add --no-ignore *但建议先svn status --no-ignore看清楚都有哪些文件被忽略避免把不需要入库的构建中间产物一股脑加进来。3.2 根治修改 global-ignores让 .so 不再被默认屏蔽如果你们团队经常需要提交.so文件每次都靠--no-ignore就太累了而且容易漏。更干净的做法是修改客户端全局配置把这个后缀从默认忽略列表里放行。TortoiseSVN 用户操作路径在工作副本任意目录右键选择TortoiseSVN - Settings左侧找到General常规在Global ignore pattern全局忽略模式里找到包含.so的那一段删除*.so和*.so.[0-9]*保存配置重新打开提交窗口。命令行用户直接编辑配置文件vim ~/.subversion/config定位到[miscellany]段找到这一行global-ignores *.o *.lo *.la *.al .libs *.so *.so.[0-9]* *.a *.pyc *.pyo __pycache__ *.rej *~ #*# .#* .svn *~ .swp .DS_Store改成下面这样把.so相关项移除其余保留global-ignores *.o *.lo *.la *.al .libs *.a *.pyc *.pyo __pycache__ *.rej *~ #*# .#* .svn *~ .swp .DS_Store保存后新执行的svn status就会把之前被忽略的.so文件显示为?状态。这时再svn add libxxx.so就不会被拒了。这里要给一个忠告修改全局配置要分清楚用途。如果只是某一个项目需要提交 .so我更推荐先不加全局放行而是顺手改掉项目根目录的svn:ignore属性只有当你明确希望以后所有项目都能自由提交 .so时才去动global-ignores。全局放行带来的副作用是那些真正不该入库的构建产物也会开始出现在提交候选列表里需要你手动分辨噪音会增加。提示改完 global-ignores 后图形客户端有时不会立刻刷新状态建议重开提交面板或者切换一下目录再回来。命令行没这个问题。3.3 团队统一用 svn:ignore 定好仓库侧的白名单如果你想让整个团队对 .so 的提交策略保持一致光改自己的客户端配置是不够的因为队友的global-ignores很可能还是默认的。此时要用仓库侧的属性来约束。先看看当前目录已有的 ignore 规则svn propget svn:ignore .如果要新增规则假设你想忽略build/目录但保留 .so 文件可以设置svn propset svn:ignore $build/\n*.o\n*.lo\n .注意svn:ignore是一个多行属性每一行是一条规则。设置完成后需要 commit 一次让属性随目录提交入库svn commit -m update svn:ignore rules这样队友更新代码后也会带上这套规则。但请注意svn:ignore 只影响未版本化的文件而且它不能覆盖客户端 global-ignores 的拦截。也就是说如果队友客户端里global-ignores仍然写着*.so那么他在 add 的时候这个 .so 依然会被忽略。想让所有人都能顺利 add要么大家各自改全局配置要么统一在操作时带--no-ignore。现实中很多团队的解法是改全局配置这件事走一次新人入职文档然后在项目里维护好 svn:ignore两件事配合使用。另外SVN 1.8 之后的版本提供了svn:global-ignores属性可以递归作用于整个目录树比svn:ignore更方便svn propset svn:global-ignores $out/\n*.log\n .如果你们的客户端版本都足够新用这个属性可以少写不少目录级配置。3.4 IDE 里的隐藏开关改完还是看不见文件问题在这很多人配置都改对了打开 IDEA 或 Eclipse 的提交面板还是看不到 .so 文件于是又怀疑人生。实际上IDE 的 SVN 集成插件往往有自己独立的忽略过滤表跟 SVN 命令行的global-ignores不是同一个东西。JetBrains 系IDEA、PyCharm 等Settings/Preferences - Version Control - Ignored Files检查是否引入了*.so规则Eclipse 系SubclipseWindow - Preferences - Team - Ignored ResourcesVS Code 的 SVN 插件多数直接调用命令行 svn因此只受~/.subversion/config影响但也有自己的 files.exclude 干扰视图显示。所以在图形界面排查时别只盯着一处命令行状态码永远是最可靠的。只要svn status --no-ignore显示文件是?或I你就知道 SVN 核心层有没有放行它如果核心层已经放行了但 IDE 不显示再去 IDE 的忽略列表里翻。4. 踩坑复盘一条完整的排查链路从怀疑权限到锁定忽略规则这一节我想把完整的排查思路捋一遍。因为实际工作中用户往往不会直接告诉你文件被忽略了而是丢来一句提交不上去背后可能是忽略、权限、大小写、客户端缓存等多种问题。按下面的链路走基本能覆盖 90% 的情况。4.1 第一步先分清是看不到还是报错拿到问题后先分类现象 A提交列表里找不到文件svn 也没报任何错误 - 大概率是忽略问题现象 Bsvn add 或 svn commit 直接弹出错误 - 先读错误内容是权限Access denied、过期Out of date还是钩子hook拒绝现象 C文件出现在列表里但提交后提示无变化 - 检查文件是不是符号链接、大小写路径、或文件属性被设置成了只读。最容易被带偏的是现象 B 里的权限问题。我见过不止一次同事很笃定地说是 SVN 服务器权限没配好管理员查了半天 log最后发现是客户端忽略规则挡住了文件svn add 一开始就没成功。所以在找别人之前先做一件事执行svn status --no-ignore yourFile.so看状态码。4.2 第二步用 --no-ignore 验证是不是忽略并顺手解决看到I状态后直接用svn add --no-ignore验证svn add --no-ignore libfoo.so如果这条命令执行后svn status里的I变成了A那么问题确认无疑就是忽略规则在拦路。此时如果你只想解决当前文件提交就完事了svn commit -m add prebuilt libfoo.so这个过程的顺序有一个额外好处你先用最小操作证明了根因再决定要不要改配置、改哪层配置不会在确定原因之前就动手乱改全局设置。4.3 第三步如果 add 成功但 commit 仍失败查什么少数情况下A状态出来了但 commit 还是失败。这时错误信息就值钱了Access denied/ForbiddenSVN 服务器侧权限不足找管理员核对路径读写权限Out of date本地工作副本过期先svn update再提交Commit blocked by pre-commit hook服务端 hook 脚本在拒绝常见原因包括文件过大、禁止特定二进制类型、甚至禁止.so后缀。这种就需要管理员看 hook 脚本别自己死磕。还有一个很少人注意但非常坑的点Linux 服务器上的 SVN 仓库路径区分大小写。如果仓库里原来有libFoo.so你本地新增的是libfoo.soSVN 会把它当成完全不同的路径可能在提交时出现疑似找不到目标或文件已存在的诡异错误。用svn info libfoo.so看下 URL一眼就能识别。4.4 第四步改配置之后还看不见文件刷新缓存改完global-ignores后命令行通常立竿见影但图形客户端会有延迟。TortoiseSVN 的提交窗口、文件图标状态、IDE 的版本控制视图都可能保留旧缓存。常见做法是重开提交窗口TortoiseSVN 里执行TortoiseSVN - Refresh/Clean up刷新工作副本状态关闭并重新打开 IDE 项目。这些操作不是玄学而是因为客户端在打开面板时一次性读取了忽略配置并缓存了结果不会实时监听配置文件变更。4.5 第五步把个人解法升级成团队约定如果这个问题在你们团队被问过三次以上就该把它写进 README 或新人文档了。我建议至少写明三点哪些目录/文件类型的 .so 需要入库预编译 SDK、第三方闭源库哪些 .so 一律不入库本地构建产物、build 缓存遇到看不到 .so 文件时的标准操作svn status --no-ignoresvn add --no-ignore以及修改 global-ignores 的入口。把一次性的排查变成可复用的流程能省掉后面大量沟通成本。5. 边界思考.so 文件到底该不该交给 SVN 管5.1 应该入库的 .so无法从源码重现的交付物最典型的就是第三方闭源 SDK。比如厂商只给了你一个libocr.so没有源码你用任何构建工具都编译不出第二个。这种 .so 必须提交到版本库否则新同事加入时拿不到这个文件整个项目都跑不起来。类似的还有特定硬件平台定制的二进制库、授权受限的算法库、需要精确版本匹配的一组动态库。这类文件建议放在独立的目录比如third_party/、libs/下并保持稳定的目录结构。这样做的好处是后续写svn:ignore时可以只针对build/等目录做忽略而不会误伤需要提交的 .so。5.2 不该入库的 .so随时能重新生成的构建产物反过来如果项目有自己的 C/C 源码只要执行一次编译就能生成 .so那就没有理由入库。这种文件每次构建都在变提交只会让仓库体积失控。正确的做法是把它们留在忽略列表里或者放到构建输出目录后用svn:ignore屏蔽。一个更细的判断标准是问自己没有这个文件别人能不能正常工作。如果别人 checkout 后跑一遍构建就能得到它就让它留在版本库之外如果别人 checkout 后缺了它就寸步难行就应该进去。5.3 折中方案目录分区 精确忽略实践下来最顺手的方式是目录分区。比如third_party/放需要入库的预编译 .so只要不把这个目录写进忽略规则文件就能正常提交build/、out/放所有构建产物用svn:ignore整体忽略根目录只忽略常见的中间文件、日志文件不做全局性的一刀切。假设你不想全局放行 .so只想让third_party/下的 .so 能提交那么注意别在根目录的 svn:ignore 里写*.so同时需要在third_party/目录确认没有svn:ignore文件级别规则拦它。如果客户端全局配置里还有*.so那么第一次添加还是得用--no-ignore。5.4 SVN 仓库膨胀的隐忧必须提前想清楚即使 .so 应该入库也要意识到 SVN 对二进制文件并不友好。一个 20MB 的 .so每次修改都会在仓库里完整保留一个新版本没有增量压缩仓库体积增长是线性的。如果这个文件经常变几个月后仓库会变得非常庞杂。我的建议是如果只是偶尔更新一次的预编译库入库问题不大如果是频繁变动的内部库最好另建制品仓库比如专门的文件服务器或 CI 产物存储让构建系统自动上传而不是走版本控制。这个取舍不是能不能提交的问题而是提交后仓库谁受得了的问题。最后说点个人经验。我自己的习惯是开发机上保留默认的 global-ignores不让 .so 出现在日常提交列表里以免混进构建噪音但每一次接第三方 SDK我都会用--no-ignore精确把需要的 .so 加进仓库并在 README 里写清楚为什么这几个二进制文件在库。这样既保证了源码库干净也避免了同事在集成时抓瞎。踩过几次提交不上去的坑之后你会发现SVN 的忽略规则就像一把双刃剑——它替你挡住垃圾文件也会悄悄把你真正需要的文件藏起来。知道它在哪儿、怎么改、什么时候用逃生门比记住一大堆命令有用得多。
返回列表