如何让SVN正确识别Visual Studio中脱离管控移动的文件?
问题背景
我正在使用Visual Studio 2019搭配Subversion代码库。有时通过Visual Studio移动文件到新位置后,由于SVN未集成到IDE中,无法识别这些移动操作,导致文件在SVN中标记为缺失(!状态),新位置的文件则是未版本化状态(?状态)。
已实现的检测脚本
我编写了一个批处理脚本,可自动检测已移动的文件及其新位置:
@echo off setlocal enabledelayedexpansion :: 检查是否提供了SVN仓库路径 if "%1"=="" ( echo 请提供SVN仓库的路径。 echo 使用方法:%~nx0 path\to\svn\repository exit /b 1 ) :: 初始化变量 set repo_path=%1 pushd "%repo_path%" :: 获取并显示SVN状态中标记为缺失的文件列表 echo 文件名 原路径 新路径 echo ======== ========= ========= for /f "tokens=2 delims= " %%f in ('svn status "%repo_path%" ^| findstr "^! "') do ( set "found=0" set "new_path=已删除" for /f "delims=" %%p in ('dir /s /b "%%~nxf" 2^>nul') do ( if not "%%p"=="!repo_path!\%%f" ( set "found=1" set "new_path=%%p" set "new_path=!new_path:%CD%\=!" ) ) echo %%~nxf %%f !new_path! ) popd endlocal
运行脚本后,可得到类似如下的输出,清晰展示移动的文件信息:
文件名 原路径 新路径 ======== ========= ========= LoggingModel.cs Models\LoggingModel.cs Models\Logging\LoggingModel.cs MainWindowModel.cs Models\MainWindowModel.cs Models\Main\MainWindowModel.cs
尝试过的命令及错误
我直接使用svn move命令时遇到了错误:
尝试命令:
svn move Models/LoggingModel.cs Models/Logging/LoggingModel.cs
收到错误:
svn: E155010: Path 'C:\path\to\repo\Models\Logging\LoggingModel.cs' is not a directory
换用目标目录作为参数:
svn move Models/LoggingModel.cs Models/Logging/
又收到错误:
svn: E150002: Path 'C:\path\to\repo\Models\Logging\LoggingModel.cs' already exists as unversioned node
需求
我需要一套正确的SVN命令序列,实现以下目标:
- 告知SVN文件的新位置
- 保留文件的完整历史记录
- 适配文件已物理移动到新位置的场景
后续我会基于正确的命令扩展批处理脚本,实现自动处理。
补充说明
安装VisualSVN for Visual Studio 2019扩展后,拖拽或剪切粘贴移动文件时,SVN会将操作识别为“删除原文件+新增新文件”,这种方式会丢失文件移动的历史关联。我希望找到更优的方案,比如相关技术社区提到的“先将文件移回原位置,再用svn move重新移动”的思路。
正确的SVN命令处理流程
针对文件已物理移动到新位置的场景,正确的处理步骤如下:
方法一:恢复原文件后执行标准移动(推荐,历史关联最清晰)
- 临时移出新位置的未版本化文件:将新路径下的文件复制到仓库外的临时目录(比如桌面),避免后续操作冲突。
- 恢复原路径的文件:对SVN中标记为缺失的原路径文件执行恢复:
如果原文件已彻底删除,先标记原路径为删除:svn revert "原路径/文件名.cs"svn delete "原路径/文件名.cs" --force - 执行SVN标准移动:使用
svn move将原文件移动到目标路径:svn move "原路径/文件名.cs" "目标路径/" - 覆盖最新文件(可选):如果临时目录中的文件是最新版本,将其覆盖到目标路径的文件上。
- 提交变更:提交移动操作,保留历史记录:
svn commit -m "移动文件:原路径 -> 目标路径"
方法二:事后关联移动历史(无需恢复原文件)
如果不想恢复原文件,可通过以下步骤关联历史:
- 标记原文件为删除:
svn delete "原路径/文件名.cs" --force - 添加新位置的文件到SVN:
svn add --force "新路径/文件名.cs" - 设置属性关联历史:通过
svn:mergeinfo属性关联原文件的历史记录:svn propset svn:mergeinfo "/原路径/文件名.cs:1-HEAD" "新路径/文件名.cs" - 提交变更:
svn commit -m "关联移动文件历史:原路径 -> 新路径"
内容的提问来源于stack exchange,提问作者Foad S. Farimani

