Skip to content

先把 SVN 的脑回路切过来

如果你以前主要用 Git,刚进一个 SVN 项目时,最容易出问题的不是命令记不住,而是默认假设错了。

什么时候你必须先把这套逻辑搞明白

  • 新接手一个老项目,仓库还在 SVN 上
  • 团队里有发布分支、热修分支,但大家说的“分支”其实是服务器目录
  • 你明明觉得自己只是本地改改,结果一个 commit 就已经把东西发到中央仓库了

SVN 和 Git 最大的几处差别

1. SVN 是中心化的

在 SVN 里,服务器上的仓库就是事实源头。

  • svn checkout:从服务器拿一个工作副本
  • svn update:把服务器上的最新改动同步到工作副本
  • svn commit:直接把本地改动提交到服务器

也就是说,SVN 没有 Git 那种:

  1. 先本地 commit
  2. 再远程 push

这两段式缓冲。

你在 SVN 里一旦 commit,就已经影响到别人了。

2. 分支本质上是仓库里的目录

很多 SVN 仓库都会约定这三个目录:

text
/trunk
/branches
/tags

通常可以粗暴理解成:

  • trunk:主干
  • branches:功能分支、热修分支
  • tags:发布快照

所以 SVN 的“建分支”,很多时候不是创建一个抽象对象,而是做一次服务器端复制:

shell
svn copy ^/trunk ^/branches/feature-login -m "create feature-login branch"

3. 工作副本是一个有状态的目录

你本地目录里不仅有代码,还有一套 SVN 的元数据。

这也是为什么:

  • 复制整个目录给别人,不等于“正确切分支”
  • 手工挪文件名,不等于“正确重命名”
  • 中途打断更新或合并,工作副本可能会锁住,需要 svn cleanup

4. SVN 的版本号通常是全局递增的

Git 习惯看 commit hash,SVN 更常看修订号,比如 r128r256

这会影响你日常说法:

  • “这个问题在 r186 修了”
  • “先把 r220 挑到发布分支”

如果团队历史上大量使用“版本号”沟通问题,那你最好尽快适应这个语境。

用一天开发流程去理解 SVN

我觉得最容易记的是下面这条线:

  1. checkout 到本地,拿到工作副本
  2. 开工前 update
  3. 改代码,配合 status / diff 看现场
  4. 必要时 add / delete / move
  5. 冲突了先处理,再 commit

这套流程里最关键的一点是:提交前必须确认你现在看到的现场就是你想送上服务器的现场。

因为 SVN 不会像 Git 一样给你很多中间缓冲层。

从 Git 切过来时最容易踩的坑

坑 1:把 commit 当成“本地存档”

在 Git 里这么想没问题;在 SVN 里不对。

SVN 的 commit 是共享动作,不是个人草稿箱。

坑 2:手工改文件名,再让 SVN 自己猜

如果你直接在文件系统里把 a.js 改成 b.js,SVN 往往只会看到:

  • 一个删除
  • 一个未跟踪的新文件

你真正想表达的“重命名”,应该用:

shell
svn move a.js b.js

坑 3:以为回滚成本很低

SVN 当然可以撤销,但没有 Git 那么多“先撤回来再说”的缓冲感。

尤其是:

shell
svn revert -R .

这种命令一旦敲下去,通常就不是靠一条 reflog 能捞回来的。

我对 SVN 的一个简单判断

SVN 不花哨,但也不神秘。

你只要先接受三件事:

  • 中央仓库是唯一事实源
  • 分支就是仓库目录
  • 工作副本要保持干净、可解释

后面的日常命令其实并不难。