SVN三方合并过程
三方合并的关键角色
- BASE(基线版本)
- 这是 SVN 在你本地
.svn
目录中存储的文件“参考版本”,通常是你上一次成功update
或commit
之后的状态。 - 它代表了“本地和远程共同拥有的、尚未分化之前”的那一个版本。
- 这是 SVN 在你本地
- WORKING(工作副本当前版本)
- 这是你在本地对文件进行修改后的最新状态。与 BASE 相比,可能新增了一些变动,比如你在第 2 行和第 4 行写了新的内容。
- INCOMING 或 REPO(远程版本/合并源版本)
- 这是从服务器上拉取的最新改动,或者是在分支合并时的另外一条分支修改。与 BASE 相比,可能也有不同之处,比如在第 5 行和第 8 行被他人修改了。
SVN 如何进行自动合并
当你执行 svn update
或 svn merge
时,如果不同人的修改并不冲突(也就是修改发生在不同的行或互不干涉的代码块),SVN 会按照以下步骤自动合并:
- 比较 BASE 与 WORKING(本地差异)
- SVN 会计算出你本地针对 BASE 做了哪些修改。比如:
- 在第 2 行和第 4 行有新增或修改。
- 这些改动可以被视为一个“差异集(diff)”。
- SVN 会计算出你本地针对 BASE 做了哪些修改。比如:
- 比较 BASE 与 INCOMING(远程差异)
- SVN 同样计算远程(或合并源)相对于同一个 BASE 做了哪些修改。比如:
- 在第 5 行和第 8 行有修改。
- 这也是一个“差异集”。
- SVN 同样计算远程(或合并源)相对于同一个 BASE 做了哪些修改。比如:
- 判断修改是否冲突
- SVN 会检查:
- 你在 BASE 到 WORKING 的差异,是否与 BASE 到 INCOMING 的差异在同一行(或同一区段)出现不同的改动。
- 如果改动在不同的行(例如本地改第 2、4 行,远程改第 5、8 行),或者虽然在同一文件但在不相互覆盖的区域(例如本地插入是第 3 行后,远程插入是第 7 行后),SVN 就能把它们“无缝”地合并在一起。
- SVN 会检查:
- 应用合并
- 先对 BASE 应用本地修改(得到一个过渡版本),再对其应用远程修改。
- 最终得到一个既包含你本地改动、又包含远程改动的合并后文件。
- 更新本地基线(BASE)
- 当自动合并顺利完成后,你的工作副本文件会变成“合并后状态”,SVN 也会更新
.svn
里的 BASE,表示本地现在基于这个新状态继续工作。
- 当自动合并顺利完成后,你的工作副本文件会变成“合并后状态”,SVN 也会更新
具体示例
假设原始文件(BASE)有 10 行:
1 | 1: line1 |
- 本地(WORKING): 修改了第 2 行和第 4 行。
- 远程(INCOMING): 修改了第 5 行和第 8 行。
三方合并时,SVN 发现第 2、4 行和第 5、8 行并不重叠(不同的行),所以就直接把两边的改动都合并进来,最后自动生成的文件在本地会是:
1 | 1: line1 |
还是上述文件,再比如:
- **本地(WORKING):**第3行后插入3行。
- 远程(INCOMING): 第11行后插入2行。
三方合并时,4~6 行是本地合并进来的;11~12 行是远程合并进来的。整体文件长度从 10 行变成了 15 行,同时保留了双方对各自行段的改动。
1 | 1: line1 |
这个结果包含了全部有效改动,且无冲突。
合并冲突
冲突原因
如果本地和远程都在相同的行有修改,SVN 无法自动决定哪边才是正确的修改,才会出现冲突(会生成 .mine
, .rXX
, .rYY
文件等)。例如:
- BASE(第 4 行):
System.out.println("Original Base");
- WORKING(第 4 行):
System.out.println("Local changes!");
- INCOMING(第 4 行):
System.out.println("Remote changes!");
因为第 4 行这处的修改“撞”到一起,SVN 就需要你手动选择保留哪个或者合并两者内容。
.suo文件的冲突
.suo 文件(Solution User Options)是 Visual Studio 的用户级别设置文件,通常是二进制格式,根本不适合进行文本差异比对(用 Notepad++ 打开会显示乱码)。这类文件一般只在你本地存储个人或环境相关的配置信息,如断点、调试配置、IDE 窗口布局等,不应该提交到版本库里去。
1. 为什么会出现冲突?
.suo 文件是二进制且易变每次打开/关闭解决方案、调整调试设置或更改 IDE 布局等,.suo 文件都会更新。由于多人协同开发时每个人都有不同的 IDE 环境,.suo 很容易在版本库中反复产生冲突。
文件实质内容无法文本合并
因为 .suo 是二进制,SVN 或 Git 等版本控制系统没法直接对其做出有效的“文本合并”,只能粗暴地提示冲突。你在 Notepad++ 中看到的“乱码”正是二进制数据。
2. 正确的做法
将 .suo 文件移出版本控制
通常我们会将这些用户/机器相关的配置文件(如 .suo、.user、*.userprefs 等)放到忽略列表(svn:ignore、.gitignore 等)里,防止它们被提交到远程仓库。
如果当前版本库里已经有 .suo 文件,建议直接在 SVN 中执行删除 (svn delete),并在 SVN 忽略列表中添加 *.suo,避免后续再被提交。 只保留 .sln / .csproj / .vbproj 等真正需要的项目文件
.sln、.csproj、.vbproj 是项目/解决方案本身的配置信息,一般需要纳入版本管理(会影响实际编译构建)。 .suo、.user 这类仅与个人环境相关,不应入库。
如果一定要处理冲突,若暂时无法删除 .suo,需要先解决当前冲突可以采用“保留任意一方”来强行解决,比如执行: svn resolve --accept mine-full <文件名> (保留本地版本) svn resolve --accept theirs-full <文件名> (保留远程版本) 。最终建议还是通过移除 .suo 来彻底杜绝后续冲突。
小结
- 自动合并原理:只要本地和远程的修改没有在同一个代码片段/行发生冲突,SVN 就能将其并入同一个文件,形成“自动合并”。
- 为什么需要“三方合并”:SVN 需要知道在你上一次成功同步(BASE)的基础上,本地和远程分别修改了哪些部分,以便判断他们是否冲突,或可直接拼合。
- 自动合并成功后:你在本地会直接看到已经合并了双方改动的文件,无需手动处理冲突标记,也无需手动编辑
<<<<<<<
、=======
、>>>>>>>
之类的冲突符号。 - .suo 或者**.user**等文件仅与个人环境相关,不应纳入版本控制。
当 SVN 显示“Auto-merging …”或没有出现冲突提示时,你就可以放心地继续工作,并在需要时 svn commit
将合并后的内容提交到远程仓库。