ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

TortoiseSVN部分Checkout深度解析:只拉取需要的目录不踩坑

TortoiseSVN部分Checkout深度解析:只拉取需要的目录不踩坑 用TortoiseSVN有一段时间了最近接连被好几个同事问到一个问题我只想拉取仓库里的某个子目录为什么TortoiseSVN默认把整个仓库都下载下来了还有一个反过来的问题我想把本地这个Checkout过的目录整个删掉重新拉一份干净的会不会把服务器上其他人提交的代码也误删了这两个问题看似一进一出本质都是对SVN工作副本机制的误解。TortoiseSVN作为Windows平台上最常用的SVN图形客户端大部分人只用到了表面那层右键菜单很多重要的细节被忽略了。今天我把这两件事彻底讲透顺便把部分Checkout之后日常会遇到的那些坑也一并梳理清楚。1. Checkout到底下载了什么工作副本和仓库的关系先说一个最容易混淆的概念Checkout不是“复制一份服务器上的文件”而是“在本地建立一份工作副本”。工作副本和普通文件夹最大的区别在于里面藏了一个.svn隐藏目录这个目录记录了当前文件夹对应的仓库地址、版本号、文件状态等元信息。你在本地看到的所有“绿色勾”“红色感叹号”都是TortoiseSVN对比.svn里的记录和实际文件内容得出来的。仓库Repository在服务器端是唯一的权威数据源。本地工作副本只是一个可编辑的缓存区。你修改文件、增加文件、删除文件操作的都是本地工作副本。只有执行Commit提交之后改动才会真正推送到服务器仓库。理解了这一点很多恐惧就消失了本地目录删了仓库版本库一行数据都不会动。就好比你从图书馆借了一本书回家在书里写写画画之后把书扔了图书馆里的原书不会有任何变化。仓库里的内容只有通过合法的Commit操作才会被修改。TortoiseSVN默认的Checkout行为是把URL指向的整个目录全部拉下来。比如你在仓库浏览器里选中根目录https://svn.example.com/repos/project右键Checkout它默认递归拉取所有子目录和文件。仓库大、文件多的时候这个操作会非常痛苦。尤其是那些满仓库的二进制资源、历史遗留的构建产物、几十兆的日志文件明明不关心却不得不下载。Git里可以用稀疏检出Sparse CheckoutSVN同样有对应的机制而且TortoiseSVN把入口藏得有点深。其实SVN的检出深度控制从命令行时代就有了参数叫--depth支持infinity完全递归、immediates只含直接子项、files只含直接文件不含子目录、empty只检出一个空文件夹。TortoiseSVN其实把这些选项都暴露出来了只是默认值太“友好”很多人没注意到。另外一个重要概念是“稀疏目录”Sparse Directory。如果你检出时选择了Only this item或者Only file children工作副本里就会留下很多“空壳目录”——它们存在于本地工作副本的元数据中但没有实际内容。后续如果你想要某个空壳目录的内容可以单独对该目录执行Update不需要重新Checkout整个仓库。理解了这个机制部分Checkout才能玩得转。2. 部分Checkout的两种常用姿势2.1 直接逼TortoiseSVN只拿当前子目录最简单的一种场景你已经知道要的目录相对仓库根的路径。比如项目结构是/trunk ├── docs ├── src | ├── core | ├── api | └── web └── assets你只关心trunk/src/core那在TortoiseSVN的Checkout对话框里URL栏直接填https://svn.example.com/repos/project/trunk/src/core然后选择本地目录为D:\workspace\project-coreCheckout它就完事了。这种方式的优点是简单直接缺点是脱离了仓库结构。你本地只有一个孤零零的core目录如果想看src下其他兄弟目录还得另外Checkout一个工作副本各目录之间没有整体视图。2.2 用“Depth”控制检出深度保留完整目录骨架更专业的做法是在Checkout时先检出整个trunk但把深度设置为Only this item。这样本地会生成一个trunk文件夹里面什么都没有但已经能和仓库服务器正常通信。这不是一个普通的空文件夹本质上是“已经被SVN管理但没拉取内容的稀疏副本”。接下来进入这个空目录右键TortoiseSVN - Update to Revision在弹出的对话框里Checkout Depth里重新选择深度选项说明Infinity (full recursion)全量递归更新和直接Checkout整个目录等价Immediate children, including folders只拉取当前目录的直接子目录和文件不往更深层递归Only file children只拉取当前目录下的直接文件不包含子目录Only this item只更新当前目录本身不拉任何子内容我刚说的部分Checkout核心思路就是先把根目录以Only this item检出然后对你要的src目录执行一次Update深度选Immediate children, including folders或者干脆选Infinity把src下所有内容拉下来。其他不要的目录如docs、assets保持空壳状态以后想要哪个就在哪个目录上单独Update。这个做法的好处是保留了完整的目录骨架后续扩展很方便。比如你之前只拉取了src/core过了两周需要看src/api了直接在本地稀疏目录里的src/api文件夹上执行Update深度选Infinity它就会自动从服务器拉取这个子目录的内容不需要重新Checkout。实操步骤我总结成一条清单在TortoiseSVN的Checkout对话框里输入仓库根URLCheckout Depth下拉框选择Only this item完成检出。用仓库浏览器或者在Windows资源管理器里进入你真正需要的子目录。右键该目录选择TortoiseSVN - Update to Revision。把Checkout Depth改成Infinity (full recursion)点击Update。重复第2-4步把其他需要的目录也拉下来。2.3 用仓库浏览器先看结构再决定还有一种我强烈推荐的习惯在动手Checkout之前先用Repo Browser仓库浏览器打开远程仓库看你到底需要哪些目录。TortoiseSVN的Repo Browser不仅能看到目录树还能看到每个目录的版本号、提交时间、作者和提交日志。很多时候你会发现自己以为重要的目录其实早就不维护了真正在频繁更新的就那么两三个。看完之后直接在Repo Browser里选择你需要的子目录右键Checkout本地目录自己定义。这样你甚至不需要先检出一个空壳再Update一步到位。3. 删掉本地Checkout目录真的不会动仓库吗这个问题问的人太多了我直接给结论完全不会。本地Checkout目录和仓库之间没有任何自动同步关系。你删掉本地目录服务器仓库里的文件一条都不会少同理你本地改了文件没提交仓库里也是完全没变化。SVN是集中式版本控制所有变更只有通过Commit操作才会上传到服务器。而且Commit只能对已经纳入版本控制的文件路径生效本地目录都没了自然不可能提交什么东西。但是删除本地Checkout目录之前确实有两件事值得确认3.1 本地是否有未提交的修改如果你在本地新建了文件、修改了文件、删除了文件这些状态都还没有同步到仓库只是记录在工作副本的元数据里。一旦你删掉整个目录这些未提交的修改就会永久丢失无法恢复。TortoiseSVN安装目录下有个cache缓存但那不是版本库的内容别指望能从里面找回未提交的文件。正确的操作顺序是先打开TortoiseSVN的Check for modifications看看有没有未提交的更改。如果有先Commit或者至少把修改过的文件备份出来再删除目录。3.2 .svn目录是否被其他进程占用删除本地目录的时候你可能会遇到“无法删除”的提示原因通常是explorer.exe或者某些IDE特别是Visual Studio、Eclipse还占用着工作副本里的文件句柄。碰到这种情况最直接的解决方法是关闭资源管理器和IDE然后再删。如果还删不掉用命令行rmdir /s /q强制删除或者重启电脑再删。很多人在这一步容易踩坑以为自己必须先执行TortoiseSVN的Delete或者Break Lock才有资格删除本地目录其实完全没有必要。TortoiseSVN的Delete是针对同一个工作副本内部的文件删除操作删完之后需要Commit才能把删除动作同步到仓库。它不是为了删除整个工作副本设计的。删除整个工作副本目录直接Windows删除即可。3.3 删除工作副本对服务器端的锁没有影响SVN里的锁Lock机制是用来独占文件修改权的。如果你对某个文件设置了锁然后删除了本地目录这个锁并不会因此消失它依然存在于服务器端直到你或者其他人在仓库浏览器里手动Break Lock。所以“删了本地目录就能释放锁”是一种错误认知很容易导致别人想改文件时被锁卡住。正确的做法是在删除本地目录之前先执行TortoiseSVN的Release locks把你不想要的锁释放掉再删除目录。4. 部分Checkout后的日常操作与避坑4.1 新增的远程目录怎么补到本地部分Checkout之后最经常遇到的场景是同事往trunk/config下新增了一个production子目录你本地根本没有config/production这个目录就算其余部分按时Update这个新目录也不会出现。原因在于稀疏目录的特性Update时SVN只会处理已存在的本地目录和文件对于“未检出的”路径它不会自动创建。解决办法很简单在仓库浏览器里定位到trunk/config选中production目录右键Update to revision到本地。或者在你本地的trunk/config目录上直接右键Update把深度改成Immediate children, including folders它就会拉取所有新增的直接子项。我个人的习惯是每隔一段时间打开TortoiseSVN的Check for modifications但把视图切到Repository页签直接对比本地工作副本和服务器端的差异。它能把服务器上新增的文件夹和文件列出来这样我就知道哪些稀疏目录需要手动补拉不用整个仓库Update。4.2 深度选择不当带来的隐形坑深度选择时Immediate children, including folders这个选项经常被误解。它并不是“所有层级的子目录全部拉下来”而是“当前目录下的直接子目录和直接文件”。如果你在一个深层目录上选择这个深度它只拉一层再下一层还是空壳。这时候如果按F5刷新看到目录存在但进不去、打不开其实是稀疏目录还没拉内容不是权限问题。另外一个常见坑出现在Update to Revision的时候。如果你选择的是具体某个历史版本而不是HEADTortoiseSVN会按照那个版本当时的目录结构来更新。这就可能导致你本地明明有src/web目录但更新到某个老版本之后src/web整个消失了——因为那个版本还没有web目录。这种“消失”仅仅是工作副本切换到了历史状态不是真的丢文件。重新Update到HEAD就能恢复。4.3 部分Checkout后Commit会不会误伤其他目录有人担心我只Checkout了trunk/src/coreCommit的时候会不会把其他自己没有Checkout的目录也带上去答案是不会。Commit的粒度是“当前工作副本内发生变化的文件”你文件夹里根本没Checkout的内容压根不在本地自然不可能被提交。而且SVN的Commit对话框会列出将要提交的文件列表每次提交前花十秒钟扫一眼这个列表养成习惯能避免大量“提交了不该提交的东西”的惨案。但是要留意一个边界情况如果你在部分Checkout的工作副本里手动新建了一个和远程已有目录重名的文件夹Commit时可能会报“directory already exists”之类的冲突。这属于操作失误不是SVN设计问题。解决办法是放弃那个本地新建的文件夹改用Update拉取真正的远程内容。4.4 用命令行实现更精细的稀疏检出很多团队脚本化部署时不会用TortoiseSVN都是直接调SVN命令行的。这里给一段我在自动化脚本里常用的组合# 检出空壳目录相当于Only this item svn checkout --depth empty https://svn.example.com/repos/project/trunk trunk # 进入trunk更新src子目录为完整递归 cd trunk svn update --set-depth infinity src # 只拉取config目录下的直接文件不拉子目录 svn update --set-depth files configsvn update --set-depth这个命令非常实用它可以在任何时候把某个目录的深度改深或改浅。比如你之前把src用infinity拉全了后来发现src/deprecated里的历史代码占了好几个G空间吃紧你可以执行svn update --set-depth empty src/deprecated这样src/deprecated会变回空壳目录但会根据需要保留目录本身让你知道它存在于远程。如果需要恢复再把深度改成infinity就行。这种动态调整能力在TortoiseSVN里没命令行那么直观但对空间敏感型项目非常有用。4.5 避免把部分Checkout和“Switch”混淆还有一个容易搞混的功能是TortoiseSVN的Switch。很多人问“我不是只想拿一个子目录吗用Switch不就行了”Switch的用途是在同一仓库的不同路径之间切换工作副本的分支比如从trunk切到branches/v2或者从branches/v1切到tags/v1.0。它不是用来控制“拿哪些目录”的。部分Checkout改变的是工作副本的“深度”Switch改变的是工作副本的“URL”。两者可以同时使用但不要混为一谈。操作目的典型场景Update Depth调整本地检出深度只拉某几个子目录其他保持空壳Switch切换工作副本对应的远程路径从主干切到分支或从分支切回主干5. 一个老开发者的Checkout习惯和最终提醒最后分享一点我个人多年做SVN维护的经验不涉及任何工具崇拜只说实际工作中怎么用才顺手。第一永远不要一开始就直接Checkout整个仓库。尤其是那种运营了三四年的老项目里面的历史文件、备份、临时文件多得吓人。先开Repo Browser看一眼目录结构只拉必要的路径。部分Checkout不仅在帮你省流量/省磁盘更是在帮你省“打开工作副本时TortoiseSVN扫描文件状态”的时间。你的工作副本里文件越少右键刷新的速度越快尤其是在机械硬盘上这个差距是肉眼可见的。第二建立一个“空壳补充”的标准动作。我推荐的流程永远是检出trunk时选Only this item然后在需要的子目录上单独Update。这个流程虽然多了一步但对后续的项目扩展最友好。因为你保留了一个完整的仓库树骨架同事告诉你“把config目录拷过来看一下”你只需要在config目录上Update而不需要单独建一个工作副本。第三删除本地目录时心中默念三遍SVN仓库在服务器不在我的硬盘。只要你不执行Commit服务器端永远是安全的。但是权利越大责任越大正因为删掉本地目录如此安全你越要警惕“未提交的修改可能跟着一起消失”的风险。第四团队协作里有必要把部分Checkout的约定写进文档。尤其在新人入职的时候一句“项目太大请只Checkoutsrc那个目录结构”能帮人省下半天时间。要是每个人都全量Checkout一次几十G的仓库服务器扛不扛得住我不知道反正公司网络肯定很热闹。如果你已经看到这里说明你对SVN的工作机制确实有需求。别急着手去操作先去仓库浏览器里看看你的项目有没有值得单独拉取的目录。看完你就会发现TortoiseSVN那排右键菜单里真正值得经常用的选项比你想象中少得多。
返回列表