Chinaunix首页 | 论坛 | 博客
  • 博客访问: 701299
  • 博文数量: 108
  • 博客积分: 3236
  • 博客等级: 中校
  • 技术积分: 906
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-04 21:23
文章分类

全部博文(108)

文章存档

2011年(33)

2010年(75)

我的朋友

分类: C/C++

2011-02-09 17:48:01

前奏

svn作为一款极其优秀的开源版本控制系统,应用广泛,从组织到个人遍及各行各业。因此学习和熟练掌握它,对提高我们日常工作效率和数据安全非常重要,尤其对开发人员协同管理Project的文档,代码,各类图等,能达到事半功倍的效果。不必再每天完成工作后,打包工程目录,备份每天的版本;也不用几个人堆在一起效率低下地手工合计代码;也不用担心偶尔因忘记打包,而丢失宝贵的数据资料。现在笔者已经养成完全使用svn管理日常的一些小项目,即使是个人使用,因为实在是不想每次都打包了,然后找数据再去一堆压缩包里去找。

svn有Win和Linux的版本,这里讲的是后者,而且主要是命令行操作(不过通过命令行或者能更加理解svn的工作方式和原理),前者有乌龟这类图形工具,虽功能不全,但操作也确实简单。

需求分析

为了避免手工管理一个我们日益变大的项目,于是我们选择svn,让程序为我们自动控制版本并记录下更改记录。但每当使用import子命令将工程导入到svn时,我们遇到一个极其恶的问题:将本地的工程目录全部提交上去之后,但是这个原始工程目录却不是工作拷贝,于是我还得把这个原始工作目录删掉,重新从版本库中checkout出来一个拷贝。这太不爽了,暂且不论这个工程占多大磁盘空间,明明有这个工程,只是缺少版本控制信息,有必要就删掉而重新检出整个工程么。于是我在google再google,但始终没有找到解决方法,后来了解到,svn本来就没有考虑过这个问题,貌似就只能删掉原始工程目录,而重新从库中检出一个带版本控制信息的一模一样的工程。

Solution

可能是因为个人有某种强迫症,偶还是一如继往地寻找方法企图解决这个问题,现在终于使用了一个小技巧搞定了,目前市场上还没有见到过这种方法,完全自创哦。方法如下(依然以最经典的helloworld工程为例) :

1. cd进入helloworld工程所在目录
2. 递归导入工程到版本库:
svn import helloworld svn://localhost/project -m "Just Test this Trick."
3. 执行最关键的命令(参数--depth=empty是精髓,它只初始化版本控制信息,不检出任何文件):
svn co --depth=empty svn://localhost/project helloworld
4. 然后进入工程目录:
cd helloworld
5. 执行命令:
svn st
然后显示所有文件前全带?号,因为此时这些文件还不在版本控制管辖范围内。
6. 因此我们将它们全部加入:
svn add *
现在所有文件前全显示为A标记,即为Add状态。
7. 为了与版本库一致,执行update命令(其实此时这些文件与现在版本库中是一模一样的,因为我们才刚刚提交完,没有作任何更改,此举是为了“骗过”svn):
svn up *
此时更新必然会有冲突,而且还是100%,程序提示“在 “xxx” 中发现冲突。选择: (p) 推迟,(mf) 全用我的,(tf) 全用他人的,(h) 使用帮助以得到更多选项:”,这时我们一定要选“(mf) 全用我的“,即输入mf,否则我们前面的工作就没有意义了。
8. 这时再用如下命令:
svn st
svn ci
命令均无显示,因为无状态变化,现在这个原始工程已经“转变“成一个work copy了。现在开始工作吧^_^。



--------------------------------俺是分隔线----------------------------------------
以下是我个人曾经的学习笔记,很乱,如果能用上,则看看,高手们就忽略掉它的存在吧。




sudo apt-get install subversion

#sudo apt-get install libapache2-svn(这个是和apache配合使用的,如果不打算使用apache则可不安装)

完成安装后,给系统添加一个用户组(如svn),把想要加入这个组的加一下(至少要把你自己加进吧)

# Add group
sudo addgroup svn
# Append user z as the supplemental Groups to group svn
sudo usermod -G svn -a z

cd svnroot/
mkdir zigbee_paper
sudo chown -R root:svn zigbee_paper/
sudo svnadmin create /home/z/public/share/svnroot/zigbee_paper/

$ svnserve -d --foreground -r /home/svn
# -d -- daemon mode
# --foreground -- run in foreground (useful for debugging)
# -r -- root of directory to serve
# svnserve --daemon --root=#SVNPATH/repos --listen-port=3690
注:不推荐使用root用户启动服务,默认端口号为3690

设置为随系统自动启动

编写启动脚本文件,命名为svn,放到 /etc/init.d/ 中

#!/bin/sh
# description: svnserve auto start-stop script.
#

# svn command home
svn_home=/usr/bin

# svn repository home

svn_repository=/home/svn

# svn owner
svn_owner=root

###
if [ ! -f "$svn_home/svnserve" ]
then
echo "svnserver startup: cannot start"
exit
fi
case "$1" in
'start')
echo "starting svnserve..."
su - $svn_owner -c "$svn_home/svnserve -d -r $svn_repository"
# if the user of script is root,can use the command below
# $svn_home/svnserve -d -r /svn
echo "start svnserve finished!"
;;
'stop')
echo "stoping svnserve..."
su - $svn_owner -c "$svn_home/killall svnserve"
echo "stop svnserve finished!"
;;
'restart')
echo "restarting svnserve..."
$0 stop
$0 start
;;
*)
echo "usage: svn { start | stop | restart } "
exit 1
esac
exit 0


更改启动脚本文件属性
sudo chmod 755 /etc/init.d/svn


制作符号链接
sudo ln -s /etc/init.d/svn /etc/rc1.d/K99svn
sudo ln -s /etc/init.d/svn /etc/rc2.d/S99svn


注:
rc1,rc2,rc3,rc4,rc5,rc6 文件夹中的文件,是不同运行级别的文件,根据不同的场景,系统会自动执行不同文件夹中的文件;
K 为不执行的文件,S 为执行的文件,执行的时候,按照K或者S后面的序号,从小到大逐一执行,一般自己建立的脚本,序号都命名为 99,可以有多个
执行K文件,实际上是调用脚本中的stop命令;执行S开头的文件,实际上是调用文件中的start命令
S40以后,才是系统网络配置完成的时刻。序号要调整到40后面

SVN 1.5会更加灵活,通过-N选项将会多余,我们使用–depth选项代替它,根据规格,–depth的可能值有:
–depth=empty: 更新不会拉出任何不存在的文件或目录
–depth=files: 更新会拉出所有的文件,但不包括子目录
–depth=immediates: 更新会拉入所有不存在的文件或子目录;但子目录的设置为depth=empty。
–depth=infinity: 更新会拉入所有不存在的文件和目录,子目录的设置为depth=infinity,与目前的缺省更新行为方式相同。

我们可以这样操作:

A 通过命令行操作

1、检出目录images
svn co --depth=empty http://www.iusesvn.com/project1/images images_work_dir

这样就在本地形成了一个工作拷贝目录images_work_dir

2、进入images_work_dir目录,单独更新logo.jpg
svn up logo.jpg

这样,我们就单独检出了logo.jpg,后面就可以对这个文件进行修改、提交等操作。


这三个命令(svn status、svn diff和 svn revert)都可以在没有网络的情况下工作,这让你在没有网络连接时的管理修改过程更加简单,像在飞机上旅行,乘坐火车往返或是在海滩上奋力工作时。

Subversion通过在.svn管理区域使用原始的版本缓存来做到这一点,这使得恢复本地版本而不必访问网络,这个缓存(叫做“text-base”)也允许Subversion可以根据原始版本生成一个压缩的增量(“区别”) 提交.
svn revert ITEM的效果与删除ITEM然后执行svn update -r BASE ITEM完全一样,但是,如果你使用svn revert它不必通知版本库就可以恢复文件。


svn update
$ svn update
U INSTALL
G README
C bar.c
Updated to revision 50.
U和G没必要关心,文件干净的接受了版本库的变化,文件标示为U表明本地没有修改,文件已经根据版本库更新。G标示合并,标示本地已经修改过,与版本库没有重迭的地方,已经合并。但是C表示冲突,说明服务器上的改动同你的改动冲突了,你需要自己手工去解决。

svn status可能返回的状态码(注意,#之后的不是svn status打印的)。
L some_dir # svn已经在.svn目录锁定了some_dir
M bar.c # bar.c的内容已经在本地修改过了
M baz.c # baz.c属性有修改,但没有内容修改
X 3rd_party # 这个目录是外部定义的一部分
? foo.o # svn并没有管理foo.o
! some_dir # svn管理这个,但它可能丢失或者不完
~ qux # 作为file/dir/link进行了版本控制,但类型已经改变
I .screenrc # svn不管理这个,配置确定要忽略它
A + moved_dir # 包含历史的添加,历史记录了它的来历
M + moved_dir/README # 包含历史的添加,并有了本地修改
D stuff/fish.c # 这个文件预定要删除
A stuff/loot/bloo.h # 这个文件预定要添加
C stuff/loot/lump.c # 这个文件在更新时发生冲突

C stuff/loot/glub.c # 文件在更新时发生属性冲突
R xyz.c # 这个文件预定要被替换
S stuff/squawk # 这个文件已经跳转到了分支
K dog.jpg # 文件在本地锁定;有锁定令牌
O cat.jpg # 文件在版本库被其他用户锁定
B bird.jpg # 文件本地锁定,但锁定发生错误
T fish.jpg # 文件本地锁定,但锁定丢失

在这种格式下,svn status打印五列字符,紧跟一些空格,接着是文件或者目录名。第一列告诉一个文件的状态或它的内容,返回代码解释如下:
A item

文件、目录或是符号链item预定加入到版本库。
C item

文件item发生冲突,在从服务器更新时与本地版本发生交迭,在你提交到版本库前,必须手工的解决冲突。
D item

文件、目录或是符号链item预定从版本库中删除。
M item

文件item的内容被修改了。
R item

文件、目录或是符号链item预定将要替换版本库中的item,这意味着这个对象首先要被删除,另外一个同名的对象将要被添加,所有的操作发生在一个修订版本。
X item

目录没有版本化,但是与Subversion的外部定义关联,关于外部定义,可以看“外部定义”一节。
? item

文件、目录或是符号链item不在版本控制之下,你可以通过使用svn status的--quiet(-q)参数或父目录的svn:ignore属性忽略这个问题,关于忽略文件的使用,见“svn:ignore”一节。
! item

文件、目录或是符号链item在版本控制之下,但是已经丢失或者不完整,这可能因为使用非Subversion命令删除造成的,如果是一个目录,有可能是检出或是更新时的中断造成的,使用svn update可以重新从版本库获得文件或者目录,也可以使用svn revert file恢复原来的文件。
~ item

文件、目录或是符号链item在版本库已经存在,但你的工作拷贝中的是另一个。举一个例子,你删除了一个版本库的文件,新建了一个在原来的位置,而且整个过程中没有使用svn delete或是svn add。
I item

文件、目录或是符号链item不在版本控制下,Subversion已经配置好了会在svn add、svn import和svn status命令忽略这个文件,关于忽略文件,见“svn:ignore”一节。注意,这个符号只会在使用svn status的参数--no-ignore时才会出现—否则这个文件会被忽略且不会显示!


Collision:

小于号、等于号和大于号串是冲突标记,并不是冲突的数据,你一定要确定这些内容在下次提交之前得到删除,前两组标志中间的内容是你在冲突区所做的修改:
<<<<<<< .mine
Salami
Mortadella
Prosciutto
=======

后两组之间的是Sally提交的修改冲突:
=======
Sauerkraut
Grilled Chicken
>>>>>>> .r2


svn import temp/ file:///home/z/public/share/svnroot/test/
在导入数据之后,你会发现原先的目录树并没有纳入版本控制,为了开始工作,你还是要运行svn checkout得到一个干净的目录树工作拷贝。

global-ignores选项是一个空格分隔的列表,用来描述Subversion在它们版本化之前不想显示的文件和目录,缺省值是*.o *.lo *.la #*# .*.rej *.rej .*~ *~ .#* .DS_Store。
svn status,svn add和svn import命令也会忽略匹配这个列表的文件,你可以用单个的--no-ignore命令行参数来覆盖这个选项。
1、Linux命令行下将文件checkout到本地目录

svn checkout path(path是服务器上的目录)

例如:svn checkout svn://192.168.1.1/pro/domain

简写:svn co

2、Linux命令行下往版本库中添加新的文件

svn add file

例如:svn add test.php(添加test.php)

svn add *.php(添加当前目录下所有的php文件)

3、Linux命令行下将改动的文件提交到版本库

svn commit -m “LogMessage“ [-N] [--no-unlock] PATH(如果选择了保持锁,就使用–no-unlock开关)

例如:svn commit -m “add test file for my test“ test.php

简写:svn ci

4、Linux命令行下的加锁/解锁

svn lock -m “LockMessage“ [--force] PATH

例如:svn lock -m “lock test file“ test.php

svn unlock PATH

5、Linux命令行下更新到某个版本

svn update -r m path

例如:

svn update如果后面没有目录,默认将当前目录以及子目录下的所有文件都更新到最新版本。

svn update -r 200 test.php(将版本库中的文件test.php还原到版本200)

svn update test.php(更新,与版本库同步。如果在提交的时候提示过期的话,是因为冲突,需要先update,修改文件,然后清除svn resolved,最后再提交commit)

简写:svn up

6、Linux命令行下查看文件或者目录状态

1)svn status path(目录下的文件和子目录的状态,正常状态不显示)

【?:不在svn的控制中;M:内容被修改;C:发生冲突;A:预定加入到版本库;K:被锁定】

2)svn status -v path(显示文件和子目录状态)

第一列保持相同,第二列显示工作版本号,第三和第四列显示最后一次修改的版本号和修改人。

注:svn status、svn diff和 svn revert这三条命令在没有网络的情况下也可以执行的,原因是svn在本地的.svn中保留了本地版本的原始拷贝。

简写:svn st

7、Linux命令行下删除文件

svn delete path -m “delete test fle“

例如:svn delete svn://192.168.1.1/pro/domain/test.php -m “delete test file”

或者直接svn delete test.php 然后再svn ci -m ‘delete test file‘,推荐使用这种

简写:svn (del, remove, rm)

8、Linux命令行下查看日志

svn log path

例如:svn log test.php 显示这个文件的所有修改记录,及其版本号的变化

9、Linux命令行下查看文件详细信息

svn info path

例如:svn info test.php

10、Linux命令行下比较差异

svn diff path(将修改的文件与基础版本比较)

例如:svn diff test.php

svn diff -r m:n path(对版本m和版本n比较差异)

例如:svn diff -r 200:201 test.php

简写:svn di

11、Linux命令行下将两个版本之间的差异合并到当前文件

svn merge -r m:n path

例如:svn merge -r 200:205 test.php(将版本200与205之间的差异合并到当前文件,但是一般都会产生冲突,需要处理一下)



12、Linux命令行下SVN 帮助

svn help

svn help ci

以上是常用命令,下面写几个不经常用的

13、Linux命令行下版本库下的文件和目录列表

svn list path

显示path目录下的所有属于版本库的文件和目录

简写:svn ls

14、Linux命令行下创建纳入版本控制下的新目录

svn mkdir: 创建纳入版本控制下的新目录。

用法: 1、mkdir PATH…

2、mkdir URL…

创建版本控制的目录。

1、每一个以工作副本 PATH 指定的目录,都会创建在本地端,并且加入新增调度,以待下一次的提交。

2、每个以URL指定的目录,都会透过立即提交于仓库中创建.在这两个情况下,所有的中间目录都必须事先存在。

15、Linux命令行下恢复本地修改

svn revert: 恢复原始未改变的工作副本文件 (恢复大部份的本地修改)。revert:

用法: revert PATH…

注意: 本子命令不会存取网络,并且会解除冲突的状况。但是它不会恢复被删除的目录

16、Linux命令行下代码库URL变更

svn switch (sw): 更新工作副本至不同的URL。

用法: 1、switch URL [PATH]

2、switch –relocate FROM TO [PATH...]

1、更新你的工作副本,映射到一个新的URL,其行为跟“svn update”很像,也会将服务器上文件与本地文件合并。这是将工作副本对应到同一仓库中某个分支或者标记的方法。

2、改写工作副本的URL元数据,以反映单纯的URL上的改变。当仓库的根URL变动(比如方案名或是主机名称变动),但是工作副本仍旧对映到同一仓库的同一目录时使用这个命令更新工作副本与仓库的对应关系。

17、Linux命令行下解决冲突

svn resolved: 移除工作副本的目录或文件的“冲突”状态。

用法: resolved PATH…

注意: 本子命令不会依语法来解决冲突或是移除冲突标记;它只是移除冲突的相关文件,然后让 PATH 可以再次提交。

18、Linux命令行下输出指定文件或URL的内容。

svn cat 目标[@版本]…如果指定了版本,将从指定的版本开始查找。

svn cat -r PREV filename > filename (PREV 是上一版本,也可以写具体版本号,这样输出结果是可以提交的)


典型的工作周期:
*更新你的工作拷贝
o svn update
*做出修改
o svn add
o svn delete
o svn copy
o svn move
*检验修改
o svn status
o svn diff
o svn revert
*合并别人的修改到工作拷贝
o svn update
o svn resolved
*提交你的修改
o svn commit


客户端在使用类似svn,http://这种网络协议访问资源时(即通过svnserve进程),会通过一定的权限验证,这种验证是通过资源的一些配置文件设定的。如在本例中,这些配置文件放在了/usr/local/svn/test/conf/下,包括三个authz,passwd,svnserve.conf。这三个文件的配置就不详谈了。另外的几种客户端方式如http也不介绍了,svnbook上去看,都有。

如果想通过网络方式,即svn,http等访问(推荐使用这种方式,而不是file://方式),必须要把svnserve进程启动,如果你不小心把机器重新启动了,一定要手动把它再启动一边。




删除项目:
svnadmin dump E:\repos\project1 > aaa.dump
cat aaa.dump | svndumpfilter exclude /tags/beta1 > bbb.dump
svnadmin create E:\repos\project1_new
svnadmin load E:\repos\project1_new < bbb.dump

1. export 出所有文件,删除你想要删除的
2. 删除代码库,用 svn create 命令重建之
3. 导入
这样不能保留历史版本




配置中文环境:

1.编辑/var/lib/locales/supported.d/*
格式参考 /usr/share/i18n/SUPPORTED
vi /var/lib/locales/supported.d/local
vi /var/lib/locales/supported.d/zh
vi /var/lib/locales/supported.d/en

如:
more /var/lib/locales/supported.d/local
zh_CN.UTF-8 UTF-8
en_US.UTF-8 UTF-8
zh_CN.GB18030 GB18030

2.生成locale(自动保存在/usr/lib/locale/中)
locale-gen

3.修改locale
vi /etc/environment

LANG="zh_CN.UTF-8"
改成
LANG="zh_CN.GB18030"

more /etc/environment
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11:
/usr/games"
#LANG="zh_CN.UTF-8"
LANG="zh_CN.GB18030"
LANGUAGE="zh_CN:zh:en_US:en"
CLASSPATH=.:/usr/lib/jvm/java-1.5.0-sun/lib
JAVA_HOME=/usr/lib/jvm/java-1.5.0-sun

4.重新启动或切换下运行级别,查看locale
root@1006:~# locale
LANG=zh_CN.GB18030
LANGUAGE=zh_CN:zh:en_US:en
LC_CTYPE="zh_CN.GB18030"
LC_NUMERIC="zh_CN.GB18030"
LC_TIME="zh_CN.GB18030"
LC_COLLATE="zh_CN.GB18030"
LC_MONETARY="zh_CN.GB18030"
LC_MESSAGES="zh_CN.GB18030"
LC_PAPER="zh_CN.GB18030"
LC_NAME="zh_CN.GB18030"
LC_ADDRESS="zh_CN.GB18030"
LC_TELEPHONE="zh_CN.GB18030"
LC_MEASUREMENT="zh_CN.GB18030"
LC_IDENTIFICATION="zh_CN.GB18030"
LC_ALL=


#!/bin/sh
export LANG=zh_CN.UTF-8
export LC_ALL=zh_CN.UTF-8
/usr/bin/svn update /var/www/html --username=weiqi --password=******
阅读(7698) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~