写目录
- 1. 客户端
- 1.1 相关功能菜单
- 1.1.1 `create patch`
- 1.1.2 `apply patch`
- 1.2 本次commit生成patch
- 1.3 多条commit合成patch
- 2. 命令行
- 2.1 相关命令
- 2.1.1 `svn log`
- 2.1.2 `svn diff`
- 2.1.3 `svn patch`
- 2.2 本次commit生成patch
- 2.3 多条commit合成patch
- 3. 参考资料
1. 客户端
1.1 相关功能菜单
使用的SVN客户端为TortoiseSVN。
在working copy的根目录或单个文件上,右键菜单中,有create patch和apply patch两个功能,分别用于创建patch和使用patch。
1.1.1 create patch
在提交修改前,使用create patch可以生成一个或者多个修改过的文件和当前版本差异的patch(支持目录树)。通常情况下,create patch能把修改保存为.patch
或.diff
文件,.patch
或.diff
文件中记录了发生这个patch的版本号以及具体修改的内容。针对某个文件或某几个文件的若干种修改,可以生成多个.patch
或.diff
文件。
1.1.2 apply patch
生成patch后,可以通过apply patch将.patch
或.diff
文件应用到对应版本的working copy中以复刻修改操作。同一个项目/文件夹下,可以选择应用需要的patch,通常来说,应用一个patch时文件版本和生成这个patch时文件的版本是一致的;如果不一致,也可以强制应用,svn会自动进行diff(这时候需要手动合并)。linux下,可以使用系统的patch命令来应用patch,eg: patch -p0 <
。
1.2 本次commit生成patch
在working copy的修改提交前,可以利用前面介绍的客户端自带的create patch功能,将本次代码修改生成一个patch。然后在任何与修改前同版本的working copy上,通过apply patch将生成的patch进行应用以实现复刻。这么做的优点是只需要维护一个基线版版本,任何基于此的修改和定制不需要维护单独一个全量副本,而是基线+patch的形式,便于维护。
但是目前我所使用的SVN客户端上发现,这么好用的create/apply功能,居然在commit之后就无法生成patch了,你必须在commit之前先create patch,也不能将提交历史中的某个commit生成patch,而后者是开发过程中更常见的场景,于是搜了一些资料,试图寻找将历史提交记录中的某个或连续多个commit生成一个patch的方法。
1.3 多条commit合成patch
SVN客户端中没有找到对应的功能菜单,在网上找到一个解决方案create-svn-patch-after-commit,说是在历史记录中,选中若干个commit,然后右键菜单中找到show differences as unified diff
,但是照此方案只能看到diff内容,也不知道怎么根据这个去生成patch文件。
简单地将diff内容复制粘贴到后缀为.patch
的文件中,然后尝试在working copy上apply patch,结果是失败的。这个方案还没在我用的SVN客户端上实践成功过,理论上是可行的,不知道是否是字符编码的问题。这个链接中有人提到svn diff
可以在任意两个版本之间生成patch,值得一试。
2. 命令行
2.1 相关命令
前面介绍了使用GUI进行patch的种种限制,要发挥svn完整的能力,还得靠命令行。下面介绍的方法是本人实践后确认可行的,通过强大的diff命令几乎可以实现任何patch。完整的生成和使用patch的流程,需要涉及到以下几个命令,分别做简单介绍:
2.1.1 svn log
方法介绍:
log: Show the log messages for a set of revision(s) and/or path(s).
usage: 1. log [PATH][@REV]
2. log URL[@REV] [PATH...]
这个命令可以用GUI界面替代,不过还是可以了解下。
参数介绍:
[PATH]
:指定查看对象,默认是.
即当前路径;[@REV]
:指定具体某次commitID;URL
:指定查看远程仓库的对象;
使用示例:
svn log
svn log
svn log @42
svn log /repo/project/
svn log /repo/project
svn log /repo/project@50
2.1.2 svn diff
方法介绍:
diff (di): Display the differences between two revisions or paths.
usage: 1. diff [-c M | -r N[:M]] [TARGET[@REV]...]
2. diff [-r N[:M]] --old=OLD-TGT[@OLDREV] [--new=NEW-TGT[@NEWREV]] \
[PATH...]
3. diff OLD-URL[@OLDREV] NEW-URL[@NEWREV]
参数说明(所有参数都不是必填项,所以注意默认值的含义):
-r N[:M]
:指定比较范围,可以是commitID或commitID范围,比如:-r 100
,-r 100:110
,不填则是指working copy与本地stash之间比较;-c M
:与-r N[:M]
是二选一关系,-c M
等价于-r M-1:M
,-c -M
等价于-r M:M-1
;TARGET[@REV]...
:指定比较对象,可以是目录、文件或者URL,...
说明可以指定0个或多个,同时,如果是URL,那么必须指定-r N[:M]
中的N,且M默认为HEAD;
常见场景:
#【重要】对比工作文件与缓存在.svn的“原始”拷贝:
svn diff
#【重要】显示工作文件和服务器版本2的不同:
svn diff -r 2
#【重要】显示分支br1的版本2和版本3的不同:
svn diff file:///home/wwl/svn_repos/branches/br1 -r 2:3
#【重要】显示文件在2版本和6版本的区别
svn diff -r 2:6
#【重要】对比分支br1和trunk区别(2个url)
svn diff file:///home/wwl/svn_repos/branches/br1 file:///home/wwl/svn_repos/trunk
#【了解】直接使用svn diff 显示的不是很清晰,如果本机装了其他的图形diff工具(例如meld)命令行调用:
svn diff --diff-cmd meld
#【了解】svn在1.7版本支持了git方式显示diff
svn diff --git
#【了解】xml方式显示diff
svn diff --xml
利用diff命令生成.diff
或.patch
文件:
# 任何一条diff命令(--git和--xml除外)把结果重定向到文件保存起来即可
svn diff -r 2 >
2.1.3 svn patch
patch: Apply a patch to a working copy.
usage: patch PATCHFILE [WCPATH]
这个命令也比较简单,也可以用GUI去替代使用。
参数介绍:
[PATCHFILE]
:指定patch文件,可以是.diff
或者.patch
,可以用diff命令生成;[WCPATH]
:working copy path,指定具体要应用patch的工作目录,默认是当前目录;
2.2 本次commit生成patch
根据上面diff命令的说明和示例,这就很简单了:
# 情况一:未commit。直接获取本次改动并生成diff(patch也行)
svn diff >
# 情况二:已经commit。那么先通过svn log或者GUI界面查看最新一次的commitID,然后执行:
svn diff -r commitID >
2.3 多条commit合成patch
# 情况一:连续的commit合成patch
svn diff -r commit1:commit2 >
# 情况二:间断的commit,在每个连续的commit片段上都生成一个个patch,然后按顺序依次应用
3. 参考资料
- SVN Book // svn patch
- SVN diff 笔记