后记:
此文是我做为程序员初入职后,面对的第一个专业问题 如何对项目代码进行版本控制管理? 的非正式总结。
显然获取知识的过程并非如书本顺畅地一起呵成,本文记述的就是本人从最开始的一无所知(其实也略有所闻),到最后的轻车熟路的一点过程。
我一直相信 授人以鱼,不如授人以渔 所以这里尽量保留了获取知识的过程,所有没有过于整理,希望能为初入此坑的朋友带来一点参考。
SVN做为版本控制,对于比较专业的开发中,显得有点过时,但其中包含的思想(操作流程、获取知识的过程),不会过时。
同为程序员、学习者、为生活而奋斗的战友、共勉!
先给出文章目录组织
目录
带着问题学习 (自 [2009-05-10 日])
一些“术语”
何为工作拷贝?
何为分支?
一、最初的步骤
1、新建一个版本库
2、建立需要导入到版本库的文件和目录
二、基本命令
获取帮助
关于获取工作拷贝
得到一个工作拷贝
得到一个工作拷贝并放到你的新目录中
关于历史版本
展示当前目录历史信息
展示指定文件的历史
详细展示指定文件的历史
按特定顺序(或指定版本)展示历史信息
查看最新的版本信息
使用带 --revision 的 svn update 和 svn checkout 来回到过去
得到一个指定时间的拷贝
显示一段时间的版本历史信息
关于工作拷贝更新
关于工作拷贝修改
为版本库添加一个新文件
在版本库删除一个文件
在版本库拷贝一个文件
在版本库移动一个文件
关于检查修改
检查自己的修改
检查自己对某个文件的修改
提交你的修改
直接提交某个文件的修改
直接把所有修改的信息提交到版本库
提交时增加描述修改的日志信息
提交时指定描述修改的日志文件
典型的工作周期
1、更新你的工作拷贝
2、做出修改
3、检验修改
4、合并别人的修改到你的工作拷贝
5、提交你的修改
三、进阶命令
关于分支( 自 [2010-01-06 三] )
分支的创建
分支的合并
分支合并常见操作
冲突处理( 自 [2011-01-01 六])
预测冲突
产生冲突
解决冲突
处理冲突常用的操作
四、其他
参考资料:
带着问题学习 (自 [2009-05-10 日]
)
1、什么是SVN?
2、大致的原理?
3、据我所知的命令有
svn checkout
-
svn update
刚开始工作的时候如果没有使用
svn update
那么如果之后使用得了commit
会怎么样?如果之后才使用svn update
那么会怎么样?自己的修改还存在么? -
svn commit
发生冲突的时候
commit
会把自己的修改擦掉吗?
4、我只想知道的功能
- 怎样建立最初的svn工作环境?
- 导出服务器的工作目录到本机?
- 更新服务器的修改以便与本机的工作拷贝同步?
- 提交自己的修改到服务器,并且添加一些说明性的信息?
- 更新本机的拷贝到服务器中一个特定的版本?
- 查看服务器上所有可用的版本的信息?
- 如何处理冲突?
- 从服务器捡出一个指定的版本到独立的一个工作拷贝?
- 在本地工作目录增加、删除了一个文件或者目录,如何让它与服务器的也同步?
- 一般程序员利用svn工作的日常步骤到底是怎么样的?
- 怎样更改文件的名字以及移动工作目录?
5、我好奇的功能
svn checkout
svn update
svn copy
svn add
svn delete
svn commit
svn cat
前面都是废话,这里是正题,慢慢地更新吧。
开始都是最简单的,往后随着应用以及兴趣,会更新。
如下的描述主要针对 Subversion 1.1
。
一些“术语”
何为工作拷贝?
一个工作拷贝就是你本地机器的一个普通的目录,保存一些文件,你可以任意的编辑、编译它们,你的工作拷贝是你的私有工作区。
Subversion
不会自动把你的修改与其他人的合并,也不会把你的修改展示给别人。当你确定要“发布”自己的修改的时候, SVN
会提供相应命令,这样你才能把你的工作和别人的工作合并,并使别人看到你的修改。
通常你的工作拷贝的每一个文件夹里有一个以 .svn
为名的文件夹,它用来帮助 Subversion
来识别哪个文件作个修改,以及哪个文件已经过期等等。
何为分支?
分支( =branches= )就是一份拷贝,对主干( =trunk= )上的拷贝,你把它赋予分支的意义,那么它就是分支。在分支上面工作目的是为了让自己的工作不要影响到别人。
我们需要注意的是在 SVN
中,版本号是全局的,无论分支还是主干,其版本号是唯一全局按序递增的,同一个版本号不可能在多个分支中出现。
一、最初的步骤
SVN存储所有版本控制数据到一个中心版本库。
1、新建一个版本库
$svnadmin create /path/to/repos
$ls /path/to/repos
conf/ dav/ db/ format hooks/ locks/ README.txt
该命令建立一个新目录 /path/to/repos
,包含了一个 Subversion
版本库。请确定这个目录在你的本机上。
2、建立需要导入到版本库的文件和目录
$svn import /tmp/project file:///path/to/repos -m "initial import"
这里, /tmp/project
是你要导入的目录,为了使今后使用清楚,应该包含三个顶级子目录即 branches
, tags
, 和 trunk
。典型目录结构类似如下:
/tmp/project/branches/
/tmp/project/tags/
/tmp/project/trunk/
foo.c
bar.c
Makefile
...
这样,你就可以继续工作了。如 checkout
等。
二、基本命令
获取帮助
$svn help
有关svn所有的信息,都可以通过这条命令获取。
关于获取工作拷贝
得到一个工作拷贝
$svn checkout htttp://svn.example.com/repos/calc
这样你就有了一个 /calc
的个人拷贝,它是从: http://svn.example.com/repos/calc
提取出来的。
得到一个工作拷贝并放到你的新目录中
$svn checkout http://svn.example.com/repos/calc subv
这样工作目录(拷贝) calc
将放到你的新目录( subv
)中。
SVN
可以有多种不同方式访问的 URL
形式:
file:/// 用来访问本地的
http:// 用来访问SVN的Apache的WebDAV协议
https:// 同上,不过用ssl加密
svn:// 用来访问SVN自定义的协议的的
svn+ssh:// 同上,不过用ssh封装
关于历史版本
展示当前目录历史信息
$svn log
这将展示项目各个版本的历史信息,每条记录信息包括谁、在什么时候、改了多少,以及相应的描述修改的日志信息。日志根据时间逆序排列。
展示指定文件的历史
$svn log foo.c
这将展示文件 foo.c
的历史信息。
详细展示指定文件的历史
$svn log --verbose foo.c
这样除了打印你所添加的信息之外还打印一些更为详细的信息比如哪些文件变了等。
按特定顺序(或指定版本)展示历史信息
$svn log -r 5:9
或
$svn log --revision 9:5
或
$svn log -r 8
这里用了 --revision
(即 -r
)选项,前两个分别按照时间顺序和逆序显示版本5和版本9之间的历史;最后一个显示版本8的历史。
注意有时候得到的是空信息,如: svn log -r 2
那不是错,那是说明当前目录在指定版本到现在没被修改过,可以用版本库顶级目录做为参数来查看。
如: svn log -r 2 http://svn.collab.net/repos/svn
查看最新的版本信息
$svn log -r HEAD
这样,显示的是已经提交的最新修改的信息。
使用带 --revision
的 svn update
和 svn checkout
来回到过去
$svn checkout --revision 2
$svn update --revision 2
这会覆盖当前的目录版本吗?还是可以指定 URL
来提取一个独立的版本?
得到一个指定时间的拷贝
$svn checkout --revision {2002-09-08}
或
$svn checkout --revision {15:30}
或
$svn checkout --revision {20020908T1530}
等等。
这里将会提取出离指定时间最近的版本,需要注意的是,假设指定了 2002-09-08
很有可能 2002-09-07
的某个时间更近,因为默认是以日期的0点开始的。
显示一段时间的版本历史信息
$svn log -revision {2002-09-07}:{2009-09-08}
这会找到这个时间的所有历史版本,也可版本号和时期混用表示时间段,不过不推荐这样。
关于工作拷贝更新
$svn update
这样,将会把你的工作拷贝更新为服务器上最新的版本,看到其他人的修改。不用你自己指定, SVN
会识别那些文件需要更新(可能出现的覆盖问题后面有解决方法)。该命令的输出信息将告诉你哪些文件被做了哪些修改到你的工作拷贝。
SVN
对 update
和 commit
可能产生问题的解决:
- 若在工作拷贝里没做修改,且服务器版本库在工作拷贝版本之后也没被提交过其他修改;那么
svn commit
不做任何事,svn update
不做任何事。 - 若在工作拷贝里做过修改,但服务器版本库在修改前工作拷贝的版本后没被提交过其他修改;那么
svn commit
会成功地提交(更新服务器版本库),svn update
不做任何事。 - 若在工作拷贝里没做修改,但服务器版本库在工作拷贝版本之后被提交过其他修改;那么
svn commit
不做任何事,svn update
会把你的工作拷贝版本更新为版本库中最新的。 - 若工作拷贝里做过修改,且服务器版本库在修改前工作拷贝的版本后被提交过其他修改;那么
svn commit
首先会失败并要求update
,svn update
会合并版本库和本地的修改,如果有冲突会询问用户去解决(,之后就继续了??网上答案说是需要手动commit
)。
关于工作拷贝修改
你可以使用任何你喜欢的编辑工具编辑文件,但是你不可以在修改目录结构时不通知 Subversion
。
为版本库添加一个新文件
$touch foo
$svn add foo
这里, foo
是待添加的文件。当然需要 commit
才会使版本库目录结构改变。先用普通 linux
命令在目录中建立了一个 foo
文件,然后通知 svn
要添加这个文件。如果 foo
是一个目录,那么 svn
默认会将 foo
目录下的所有文件也递归地添加进去(若仅添加目录不递归添加下面的文件需要使用 -N
参数)。
在版本库删除一个文件
$svn delete foo
这里, foo
是待删除的文件。当然需要 commit
才会使版本库目录结构改变,不需要非得用 linux
普通命令将 foo
文件删除再进行,只用 svn delete foo
,意思是版本库中“逻辑上”把这个文件删除了,版本库中没有了这文件,而实际在普通的文件系统中还有这个文件,可以重新再添加进去,但是如果 commit
之后文件就从文件系统删除了。
在版本库拷贝一个文件
$svn copy foo bar
这里,建立一个 foo
的拷贝文件: bar
。当然需要 commit
才会使版本库目录结构改变。不需要利用普通 linux
命令 cp
事先建立一个 bar
文件,会自动复制一份在文件系统中。
在版本库移动一个文件
$svn move foo bar
这里的例子相当于把文件 foo
重新命名为 bar
了。当然需要 commit
才会使版本库目录结构改变。不需要事先利用普通 linux
命令 mv
。
关于检查修改
检查自己的修改
$svn status
这个命令不会和版本库通信,其显示的信息是告诉你你的当前工作拷贝将对服务器上的版本库作怎样的修改,在当前工作拷贝的顶级目录运行,默认将递归检查子目录上所有的文件,该命令和 update
不一样,但有些共通之处(指出了变化)。
检查自己对某个文件的修改
$svn status stuff/fish.c
和上面的命令一样,不过指定了一个特定的文件项,那么就仅显示该文件项的信息。
提交你的修改
直接提交某个文件的修改
$svn commit button.c
这样,你就会把自己对 button.c
的修改提交到服务器上去,提交后会使版本库的版本号加1,以后可通过指定号码恢复(其他人的工作拷贝需要他们自己请求更新,才会把服务器上新版本更新到本地,看到你的修改,可能出现的覆盖问题后面有解决方法).
直接把所有修改的信息提交到版本库
$svn commit
由于既没有 --message
(或 -m
),也没有 --file
来描述修改的信息,所以 SVN
会启用一个你喜欢的编辑器来编辑日志描述消息。如果写描述时想要取消提交,那么直接关闭编辑器,不要保存,然后在提示中选a即 abort
,(如果选的是c即 continue
,那么应该就会提交没有描述信息的修改);如果你保存了日志,那么只需要简单删掉所有文本,再次保存。
提交时增加描述修改的日志信息
$svn commit --message "add some infomation"
这里, --message
可以简化为 -m
,后面接的是描述信息的字符串。如果描述信息很短,就可以这样直接再命令行中指定。如果信息多,就需要指定文件,见后面。
提交时指定描述修改的日志文件
$svn commit --file logmsg
这里,利用了 --file
,后面接的就是相应的日志文件。
典型的工作周期
下面给出基于上述命令,在SVN版本控制工具中的基本工作流程。