SVN学习笔记 .

2023-11-10

转载自:http://blog.csdn.net/tengbaichuan/article/details/10632349

------------------ 参考文档 --------------------
官方文档: http://www.subversion.org.cn/svnbook/ 包括可下载的PDF 和一页HTML。
配置文档: 去ubuntu的wiki吧~~ 如果用 svn + ssh 的话,基本不用配置,按下面“快速工作”即可。

------------------ 快速工作: -------------------
1. 建立版本库:
我的方式,是用svn+ssh来访问版本库,这意味着:
不用启动svnserve守护进程,而是由每次ssh连接到版本库时,自动启动svnserve,工作完再退出svnserve进程。这些东西,都是本地的svn调用ssh让它那样做的。而启动的svnserve进程的身份就是ssh用户的身份,而ssh用户来自于系统用户,这就是这种方法的优点:就用系统用户了。

正因为如此,每个用户是否对版本库能读写,就依赖于版本库的权限设置,就是你用svnadmin create生成的文件的权限设置。
我的策略是,为了让某些用户读写版本库,我创建了一个svn用户,和一个svn组,然后在/home/svn下建立版本库。然后把所有需要访问svn的用户,加到svn组中,并设置版本库的所有文件,svn组的人都能够读写。

在版本库机器上,具体如下:
adduser svn            # 创建svn用户和svn组
gpasswd -a fengyi svn # 把fengyi用户加到svn组
svnadmin create /home/svn/buptnic # 创建版本库buptnic
chmod -R g+w /home/svn/buptnic     # 让所有的文件为组可写(因为默认一般是组可读了)
以上两步,也可以改为,先用umask 0002,再用svnadmin 一样的效果。因为默认的umask一般是0022,这会去掉组的写权限。

注意:一旦svnadmin create之后,其他的事情,就应该用svn在工作拷贝机器上做了。———— 要点是,大部分svn的子命令,最终效果都是操作版本库,但是分两种途径。如果子命令带URL的,一般对版本库直接操作,如果不带URL的,一般是先对工作拷贝进行操作,然后用commit使版本库生效。当然,好多命令,即可以带URL,也可以不带,一般都是先update,再更改工作拷贝,再commit。

在工作拷贝机器上,具体如下:
svn mkdir svn+ssh://svn@210.25.137.252/home/svn/buptnic/flow # 建立flow项目目录
svn mkdir svn+ssh://svn@210.25.137.252/home/svn/buptnic/flow/trunk # 建立flow/trunk目录
svn mkdir svn+ssh://svn@210.25.137.252/home/svn/buptnic/flow/branches # 建立flow/branches目录
svn mkdir svn+ssh://svn@210.25.137.252/home/svn/buptnic/flow/tags # 建立flow/tags目录

svn import /home/echo/src svn+ssh://svn@210.25.137.252/home/svn/buptnic/flow/trunk # 将本地的src下的源文件导入到版本库的trunk目录下。注意,trunk是主分支,一般习惯是放任何东西,包括文档,第三方库。

然后,就OK了,你可以找个地方,用fengyi用户做checkout了。
svn checkout svn+ssh://fengyi@210.25.137.252/home/svn/buptnic/flow

注意的是:版本库中,虽然你通过mkdir建立了那些目录,上传了那些文件,但是,你是在/home/svn/buptnic/flow中直接看不到的,它们都放在flow 下的db目录中,是虚拟文件系统里。

2. 用户基本操作原则:
(1) 不管是 版本库 还是 工作拷贝,他们的维护文件,都在他们的文件夹内,所以,如果要删除他们,直接用文件系统的rm即可彻底删除。
(2) 用svn子命令,对版本库的直接操作,必须用一种形式的URL,而不能是普通文件路径,包括在版本库机器上!!!!!但是svnadmin等命令,就是直接用普通文件路径来操作版本库,并要求在版本库机器上执行。
(3) 在工作拷贝的哪个目录执行 svn 子命令,该命令的最后一个参数,默认就是当前目录,这使得命令的效果从当前目录开始作用。
这从每个目录里有一个.svn看得出来,每个目录都有维护文件,都可以单独工作。这也是工作拷贝的不同部分允许不同版本号的基础。
(4) commit只有当当前目录下所有文件的版本号 等于 版本库当前版本号时,才能成功。
工作拷贝的不同部分允许不同版本号,所以,当你commit时,可能当前目录下,比如各个子目录里 的版本号并不同,如果有比版本库低的版本号,commit就不能成功,提示信息是 ... out of date ...,这时,你需要update一次,然后,再commit。当然,其他很多情形,也可能导致这种情况,最典型的就是(5)中文件冲突的情况。
(5) 先在工作拷贝上操作,然后commit到版本库。
除了修改文件以外的任何操作,都用svn子命令完成,比如添加一个文件,创建之后,用svn add添加到本地拷贝。当你觉得本次的工作拷贝工作结束时,可以将其commit到版本库,使得版本库更新到新的revision。
(6) 解决冲突
解决冲突最好的办法,就是两个人不要编辑同一个文件。否则,见下面或资料,你就需要update一次,来合并两人的文件(因为别人先commit了,版本库里的版本号比自己的高,自己不会commit提交成功,需要先update)。如果需要手工解决冲突,见下面的解决办法。
(7) 是的,如果两个分支独立发展太久,则必然改动较大,那merge是会有冲突的,你还是要手动解决。
merge和update冲突时,生成的冲突临时文件名不同,但是源文件,都是被冲突标志标注了的,你只需要改源文件即可。里面<<<到>>>部分,是冲突区域,即svn认为,在这个区域上,两个文件各自发展了自己的修改,所以第一个文件的修改,放到<<<和===中,第二文件的修改,放到===和>>>中,你自己选择,保留哪个修改。如果某个修改为空,即如===和>>>中没有代码,那说明“修改”就是“删除”操作。
所以,当我们把branches的文件merge到trunk时,得考虑清楚了,因为branches在修改bug,而trunk在增加新特性,为了把branches的bug修改通过merge引入trunk,是很可能导致冲突的。
(8) revert 和 merge
revert是在版本内恢复,即:当commit后,就是一个版本了,之后,如果更改了任何东西,但是还没有commit的话,就可以恢复到上次commit后的状态。revert不依靠版本库,仅靠.svn目录来维护信息。
而merge,则是依赖版本库,做的则是版本间的差异比较,从而作用于某个目录。使得内容恢复到某个版本状态。
(9) 忘了的命令,用svn help subcmd 来查阅。
(10) diff, status, log 怎么用阿?
下面是trunk目录下,svn status -v 的输出:
               28       28 fengyi       .                                  
               28       26 fengyi       sheep                              
               28       26 fengyi       sheep/sheep.c                      
               28       20 svn          main.c                             
               28       28 fengyi       cow                                
               28       28 fengyi       cow/main2.c 
注意到:第一列是当前工作拷贝的版本号,是因为在trunk update后导致所有文件的版本号变为最新。但是,后面的一列数字,表明自那个版本号以来,文件没有改过(不保证版本库没有更新)。你用svn log看那个文件,也只能看到那个号版本,看不到当前工作拷贝的版本号(没改,没commit,怎么可能有log!)


-------------------- 笔记 ---------------------

第一章 基本概念
svn就是能够跟踪数据变化的文件服务器 
“拷贝-修改-合并”模型而不是“锁定-修改-解锁”(见保存的图)
每当版本库由用户commit了一个提交,文件系统进入了一个新的状态,叫做一次修订(revision),每一个修订版本被赋予一个独一无二的自然数,commit显然是原子操作。同时,可以看出,版本库没有回退的概念,只有工作拷贝有这个概念,版本库只不过一直在往前走。
(许多其它版本控制系统使用每文件一个修订号的策略,所以会感觉这些概念有点不一样。)
SVN概念中,版本库的修订版本是统一的,就是说,任何时候,每个文件的“修订版本”都是一样的。
但是工作拷贝中经常是“混合修订版本”,因为你只提交一个文件,导致版本库中修订版本加1,这时,你的工作拷贝中这个文件的修订版本也加1,但是工作拷贝中其他的文件,只能维持原版本号,除非你update一次。
这是很有用的一个特性,它允许工作拷贝的任何一个部分在历史中前进或后退。

svn有一个基本原则就是“推”动作不会导致“拉”,反之亦然。


svn commit & svn update 和 四种状态 (是否修改+是否当前)

svn status --verbose 检查“混合修订版本”
svn log 显示一个文件或目录的历史修改信息。

$ svn checkout http://svn.example.com:9834/repos
$ svn checkout file:///path/to/repos
$ svn checkout file://localhost/path/to/repos
C:\> svn checkout file:///X:/path/to/repos

$ svn checkout http://svn.example.com/repos/calc
$ svn commit button.c -m "Fixed a typo in button.c."
$ svn update

Subversion可以通过多种方式访问版本库!! 
   ———— 一个重要意思是说:各种svn的子命令,都可以直接访问版本库。如果你在版本库机器上,那么就用file:///,如果你在自己机器上,就用下面四种方式。
   ———— 但是,你怎么只操作本地的工作拷贝呢,以为你想在本地改,改完后再commit,那就不要加这些东西了,直接是文件名,或者不加就好。
模式    访问方法
file:///     直接版本库访问(本地磁盘)
http://     通过配置Subversion的Apache服务器的WebDAV协议
https://     与http://相似,但是包括SSL加密。
svn://     通过svnserve服务自定义的协议
svn+ssh://     与svn://相似,但通过SSH封装。

但是注意:一般的做法,还是先update,merge,copy等命令把版本库数据弄到工作拷贝,修改好工作拷贝后,再commit,这会导致版本库的进入下一个revision。
如果直接在版本库中操作的,比如copy,delete等,也会使得版本库进入下一个reversion.

第二章 基本使用
svn help SUBCOMMAND
1. 创建版本库
创建新的版本库名 newrepos
$ svnadmin create /usr/local/svn/newrepos
将mytree下未版本化的文件,导入该版本库,文件放在some/project下,没有mytree文件夹了。
$ svn import mytree file:///usr/local/svn/newrepos/some/project -m "Initial import"
注意:import后的路径,可以在版本库上,也可以在自己机器上。一般,可以在自己机器上的代码,直接这样导入服务器上的版本库。
列出newrepos版本库中某文件夹下的文件。
$ svn list file:///usr/local/svn/newrepos/some/project

推荐的版本库布局: 这里有paint和calc两个项目
$ svn list file:///usr/local/svn/repos
/paint/trunk
/paint/branches
/paint/tags
/calc/trunk
/calc/branches
/calc/tags
/vender/vendorlib1/current #供方最新版本
/vender/vendorlib1/1.0      #上次最新版本的快照(svn copy)

注意:文件夹用 svn mkdir 创建。看你在版本库主机上还是工作拷贝主机上,选用上面某一个URL可以对版本库进行操作。

2. 初始化检出
在本地创建一个工作拷贝,这个拷贝可能仅仅是一个版本库中的一个文件夹。
$ svn checkout http://svn.collab.net/repos/svn/trunk
同上,只不过,在本地创建的是subv目录,而不是trunk目录。
$ svn checkout http://svn.collab.net/repos/svn/trunk subv


3. 基本的工作周期
更新你的工作拷贝
            svn update 
做出修改: 只有修改一个文件,可以直接修改,其他任何对文件和目录的操作,均是先通过以下命令在工作拷贝生效,然后,你下次update的时候,才在版本库生效。这种状态,常见英文为: sth is scheduled for addition.(比如这个文件是add处理的)
            svn add foo    (先vim foo,然后用add命令添加)
            svn delete foo (但是只有在update时,版本库和工作拷贝内的删除才会生效)
            svn copy foo bar
            svn move foo bar
        svn mkdir foo (等于mkdir foo; snv add foo)
检验修改: 在你提交你的工作拷贝时,检查一下修改了哪些东西是个好习惯,这不需要网络(不需要和版本库比对)
            svn status (浏览所做的修改,传说中用的最多的命令)
                -v 显示所有文件
                -u 这个文件常用于预测update前的冲突。会联系版本库,看是否工作拷贝里,有过期的文件,以 * 标注。
                        可能的状态码为:
            A   # file is scheduled for addition
            C   # file has textual conflicts from an update
            D   # file is scheduled for deletion
            M   # the content in bar.c has local modifications
                        ?   # 这个文件还没有版本化,你需要用svn add
            svn diff    (检查修改的详细信息,通过 svn diff > patchfile 可以生成补丁文件)
可能会取消一些修改
            svn revert (任何修改,然后用revert就可以撤销任何schedule 的操作,即上次update以来 schedule的操作)
解决冲突(合并别人的修改)
            svn update (只要版本库被别人修改,你铁定不能commit,必须update一次,而update会尝试合并被人修改过的版本库和工作拷贝,生成新的工作拷贝,下面U表示更新(你没有修改,但是版本库被修改),G表示合并(你修改了,版本库也修改了,两者可以合并),C表示冲突(你修改了,版本库修改了,两者不能按照一定规则合并)。如果是C存在,那么你必须解决冲突,svn才能允许你下次commit。如果有冲突,那么对应bar.c 会有三个临时文件被生成,它们是bar.c.mine, bar.c.rR1(你上次update时的文件), bar.c.rR2(版本库中的最新版本号的文件)。这个三个临时文件,会阻止你commit。此时的svn只是要求你考虑下更改冲突的文件,如果考虑好了,用svn resolved bar.c来告诉svn,你改好了,然后resolved会自动删除这三个临时文件,然后,你再commit,就行了!所以,svn只是要求你考虑清楚后,删除这三个文件,它就可以commit了,不管你到底是不是真的改恰当了,这还是你的事,所以,如果不用svn resolved,而是直接删除这三个文件,也是可以commit的。另外,这三个文件,可以用于你查阅,如果愿意的话。
            更改冲突文件,通常可以:直接编辑冲突文件;用bar.c.rR2(R2 > R1)来替换bar.c;或者直接用svn revert来恢复文件到上次update时的状态。如果是前面两种方法,要接上svn resolved来告诉svn,冲突已解决好了,可以允许自己commit了。
                $ svn update
        U INSTALL
        G README
        C bar.c
        Updated to revision 46.
            svn resolved 
提交你的修改
          只有当你的工作拷贝的版本号=版本库版本号时,才能提交成功!!!(小于就得先update,大于是不可能的)
            svn commit -m "message"/ -F logfile


4. 检验历史:
(1) svn log   (从下面就看出每次 commit时 -m 的重要性了,对于追溯很重要)
$ svn log
------------------------------------------------------------------------
r3 | sally | Mon, 15 Jul 2002 18:03:46 -0500 | 1 line
Added include lines and corrected # of cheese slices.
------------------------------------------------------------------------
r2 | harry | Mon, 15 Jul 2002 17:47:57 -0500 | 1 line
Added main() methods.
------------------------------------------------------------------------
r1 | sally | Mon, 15 Jul 2002 17:40:08 -0500 | 1 line
Initial import
------------------------------------------------------------------------

$ svn log -r 5:19    # shows logs 5 through 19 in chronological order
$ svn log -r 19:5    # shows logs 5 through 19 in reverse order
$ svn log -r 8       # shows log for revision 8
$ svn log foo.c
$ svn log http://foo.com/svn/trunk/code/foo.c

注意:
a. 加上 -v 能显示文件和目录的移动和复制 等 “路径修改” 信息,这可以用于找出删除的项目。
b. 如果 svn log -r 8 没有输出信息,那请在后面跟出版本库的路径。

(2) svn diff
$ svn diff                   #比较工作拷贝和.svn中存的上次update时的版本。
$ svn diff -r 3 rules.txt    #比较工作拷贝和版本库3版
$ svn diff -r 2:3 rules.txt #比较版本库的2版和3版。
(3) svn cat
$ svn cat -r 2 rules.txt   #查看版本库2版
(4) svn list
缺省列出的是当前工作拷贝对应的版本库的URL下的东西,当然,你可以直接写出版本库。
$ svn list -v http://svn.collab.net/repos/svn

5. 时间机: ———— 注意:版本库没有回退的概念,只有你的工作拷贝有回退的概念!!
(1) 将工作拷贝,回退到以往某个版本: ———— 但注意,根据commit原理,这种回退的工作拷贝,你是无法commit的了。如果,你原意是想回退后,以后还能继续提交,那应该用svn merge!!!!
$ svn checkout -r 1729 # Checks out a new working copy at r1729
$ svn update -r 1729 # Updates an existing working copy to r1729
(2) 将版本库的1729版本打包。 
$ svn export http://svn.example.com/svn/repos1 -r 1729

6. 清理:
status发现有L的,表明是锁住了,这通常是由于svn上次要修改,所以锁住,但是由于某种原因,进程退出了,所以锁还在,这是用cleanup命令清除即可。
$ svn status
L    somedir
M      somedir/foo.c

$ svn cleanup
$ svn status
M      somedir/foo.c


第三章 高级主题
1. 去掉未版本化的文件:
你当然不想让临时文件扰乱版本库,也让svn方法有svn自身提供的两种方法,见这一章相应部分。我还是觉得复杂。
那就当svn add 和 import时,后面显示指定出文件名,而不是默认让它递归查找所有的文件和目录。
2. 锁定:
如果你想当你update后,就能锁住某些版本库的话。这样使得一些非文本的对象,不会由于交替操作发生错误,如图像处理。
3. 其他很多高级主题。
见章节中。


第四章 分支与合并
当你创建了一个版本库时(svnadmin create),里面的目录和文件可以用 svn copy 或者 svn move来移动。但不能在不同版本库间移动。
1. 分支:
“分支”,没有被SVN赋予特殊的意义,我们称用 svn copy 后的新的目录,为一个分支,但对于svn来讲,只是一个普通目录。
(1) 创建分支:
由于分支是对版本库的操作,所以copy后的两个参数都是版本库URL,如果你在版本库机器上,用file:///一样。
$ svn copy http://svn.example.com/repos/calc/trunk \
           http://svn.example.com/repos/calc/branches/my-calc-branch \
      -m "Creating a private branch of /calc/trunk."
上面,也说明了分支放置的地方,在branches里,新建一个my-calc-branch。以后,也可以在branches里建立其他新的分支。
(2) 版本号还是往前走!
由于svn的一个版本库内部没有“分支”的内建概念,所以不管哪个“分支”被commit了,都会导致版本库的版本号往前走。

2. 合并:
“合并”,即 svn merge 做的事,就是比较版本库中两个版本的区别,并把区别应用于你的工作拷贝。这没有什么限制,两个版本可以是任何两个版本,你的工作拷贝,也可以是你本地的任何一个“分支”。但是,这个命令拿来干嘛呢?? 就是为了使得两个“分支”能够合并一些共同的东西,比如一个分支做了一些错误修改,另一个分支也应该跟着改。但是,这些修改是通过比较哪两个版本,这就要靠你自己判断了,一般是看别人用commit -m参数,提交的说明,比如它说,这次提交,修改了xxx,那你就可以比较这次提交和上次版本的差别,然后应用于自己的工作拷贝,这就是所谓的“合并”。 
如果不能合并,不能合并的文件前,会打印C,就同update一样。这往往表明,你选了错误的两个版本作比较,使得差别不能应用于拷贝。这时,可用svn revert --recursive恢复修改。
另外,merge必须经常做,如果你打算维护两个相关的分支的话。否则,长时间不做,merge起来,会冲突很多,不好解决。

下面是些用法:
$ svn merge -c 344 http://svn.example.com/repos/calc/trunk #默认合并到当前工作目录
$ svn merge -c 344 http://svn.example.com/repos/calc/trunk my-calc-branch
$ svn merge http://svn.example.com/repos/branch1@150 \ #@后面接版本号
            http://svn.example.com/repos/branch2@212 \
            my-working-copy
$ svn merge -r 100:200 http://svn.example.com/repos/trunk my-working-copy
$ svn merge -r 100:200 http://svn.example.com/repos/trunk

不太懂 --ignore-ancestry 的用途,这个用于比较两个不相关的目录树

3. 典型例子:
(1) 把某个branch合并到trunk
先进入工作拷贝里的trunk目录,使得后面svn merge是针对这个工作拷贝。
$ cd calc/trunk
$ svn update
At revision 405.

用于merge的两个版本库版本,是my-calc-branch诞生时的版本341和目前的版本405。注意,这仅仅是对第一次merge,但是如果你后来又修改了分支,你还想merge,那显然,从406到目前的版本即可。最新版本,可用HEAD代替。不知道,就看上面svn update,告诉你最新是405。或者用svn log查询。
$ svn merge -r 341:405 http://svn.example.com/repos/calc/branches/my-calc-branch
U   integer.c
U   button.c
U   Makefile

检查一下状态,不要有冲突的
$ svn status
M   integer.c
M   button.c
M   Makefile

# ...examine the diffs, compile, test, etc...

然后提交,就可以完成合并到trunk。
$ svn commit -m "Merged my-calc-branch changes r341:405 into the trunk."
Sending        integer.c
Sending        button.c
Sending        Makefile
Transmitting file data ...
Committed revision 406.

(2) 恢复工作拷贝到以前版本:
注意是303后面跟302,后面的小,这样就能够使得工作拷贝,回到以前的版本!! 这样之后,是可以commit的,这不同于用checkout和update得到的以前版本,这种情况下无法commit.
$ svn merge -r 303:302 http://svn.example.com/repos/calc/trunk
U integer.c

$ svn status
M integer.c

$ svn diff

# verify that the change is removed


$ svn commit -m "Undoing change committed in r303."
Sending        integer.c
Transmitting file data .
Committed revision 350.

(3) 恢复单个文件到以前版本:
如果你想对单个文件回溯? 那还是用svn copy把,它能够直接把某个版本的文件拷贝到你当前的工作拷贝。如:
拷贝807版本的real.c到工作拷贝的当前目录
$ svn copy -r 807 \
           http://svn.example.com/repos/calc/trunk/real.c ./real.c
查看状态
$ svn status
A +   real.c

提交修改
$ svn commit -m "Resurrected real.c from revision 807, /calc/trunk/real.c."
Adding         real.c
Transmitting file data .
Committed revision 1390.

(4) 当然,你可以选择直接在版本库中恢复文件和文件夹:
这所谓恢复,其实就是进入下一个revision,注意下面例子中revision号的变化。
比如你用这个删除了:
$ svn delete http://svn.example.com/repos/calc/branches/my-calc-branch \
             -m "Removing obsolete branch of calc project."
Committed revision 375.
你可以用这个来恢复:
$ svn copy -r 374 http://svn.example.com/repos/calc/branches/my-calc-branch \
                  http://svn.example.com/repos/calc/branches/my-calc-branch
Committed revision 376.



4. 常用分支模式:
大多数软件存在这样一个生命周期:编码、测试、发布,然后重复。这样有两个问题,第一,开发者需要在质量保证小组测试假定稳定版本时继续开发新特性,新工作在软件测试时不可以中断,第二,小组必须一直支持老的发布版本和软件;如果一个bug在最新的代码中发现,它一定也存在已发布的版本中,客户希望立刻得到错误修正而不必等到新版本发布。

(1) 永久分支:
一般trunk做主分支(给开发者),branches做发布分支(给测试员测试,不允许添加特性,仅做bug修复),tag做打包分支(给用户):
这是版本控制可以做的帮助,典型的过程如下:
    * 开发者提交所有的新特性到主干。 每日的修改提交到/trunk:新特性,bug修正和其他。
    * 这个主干被拷贝到“发布”分支。 当小组认为软件已经做好发布的准备(如,版本1.0)然后/trunk会被拷贝到/branches/1.0。
    * 项目组继续并行工作,一个小组开始对分支进行严酷的测试(一般只允许做bug修复性的提交),同时另一个小组在/trunk继续新的工作(如,添加新特性,准备2.0)。两边发现的bug,可以相互merge。注意,这种分支,也就是“维护某个版本”的由来。即不会添加新特性了,如果OK了,就放到tags里,然后以后有bug,也继续在分支改。
    * 分支已经作了标签并且发布,当测试结束,/branches/1.0作为引用快照已经拷贝到/tags/1.0.0,这个标签被打包发布给客户。
    * 分支多次维护。当继续在/trunk上为版本2.0工作,bug修正继续从/trunk运送到/branches/1.0,如果积累了足够的bug修正,管理部门决定发布1.0.1版本:拷贝/branches/1.0到/tags/1.0.1,标签被打包发布。

整个过程随着软件的成熟不断重复:当2.0完成,一个新的2.0分支被创建,测试、打标签和最终发布,经过许多年,版本库结束了许多版本发布,进入了“维护”模式,许多标签代表了最终的发布版本。
(2) 临时分支:
有时,可能做些trunk的临时分支,以开发某种特性,或做较大更改。
这些分支,一旦开发结束,就merge入主分支,并删除自己。
(3) 供方分支:
显然,我们需要用到别人提供的库。但是,我们怎么用呢?一般是,放到我们的版本库中,准备一个current目录,将其放入,然后做快照到如1.0。然后拷贝到brunch中做使用和定制。然后,一旦有新版本发布,我们想用的话,把最新版本替换current,然后和1.0做比较,用merge将修改应用于brunch中的版本。
目录结构为:
在repos根目录下,再创建一个vender目录,库名叫libcomplex比如,就创建libcomplex目录,在里面再创建current放最新版本,用1.0放上次版本的快照(svn copy)
-------- 从文档上摘抄的例子:---------
也许一个例子有助于我们阐述这个算法,我们会使用这样一个场景,我们的开发团队正在开发一个计算器程序,与一个第三方的复杂数字运算库libcomplex关联。我们从供方分支的初始创建开始,并且导入供方drop,我们会把每株分支目录叫做libcomplex,我们的代码drop会进入到供方分支的子目录current,并且因为svn import创建所有的需要的中间父目录,我们可以使用一个命令完成这一步。

$ svn import /path/to/libcomplex-1.0 \
             http://svn.example.com/repos/vendor/libcomplex/current \
             -m 'importing initial 1.0 vendor drop'


我们现在在/vendor/libcomplex/current有了libcomplex当前版本的代码,现在我们为那个版本作标签(见“标签”一节),然后拷贝它到主要开发分支,我们的拷贝会在calc项目目录创建一个新的目录libcomplex,它是这个我们将要进行自定义的供方数据的拷贝版本。

$ svn copy http://svn.example.com/repos/vendor/libcomplex/current \
           http://svn.example.com/repos/vendor/libcomplex/1.0      \
           -m 'tagging libcomplex-1.0'

$ svn copy http://svn.example.com/repos/vendor/libcomplex/1.0 \
           http://svn.example.com/repos/calc/libcomplex        \
           -m 'bringing libcomplex-1.0 into the main branch'


我们取出我们项目的主分支—现在包括了第一个供方释放的拷贝—我们开始自定义libcomplex的代码,在我们知道之前,我们的libcomplex修改版本是已经与我们的计算器程序完全集成了。 [23]

几周之后,libcomplex得开发者发布了一个新的版本—版本1.1—包括了我们很需要的一些特性和功能。我们很希望升级到这个版本,但不希望失去在当前版本所作的修改。我们本质上会希望把我们当前基线版本是的libcomplex1.0的拷贝替换为libcomplex 1.1,然后把前面自定义的修改应用到新的版本。但是实际上我们通过一个相反的方向解决这个问题,应用libcomplex从版本1.0到1.1的修改到我们修改的拷贝。

为了执行这个升级,我们取出一个我们供方分支的拷贝,替换current目录为新的libcomplex 1.1的代码,我们只是拷贝新文件到存在的文件上,或者是解压缩libcomplex 1.1的打包文件到我们存在的文件和目录。此时的目标是让我们的current目录只保留libcomplex 1.1的代码,并且保证所有的代码在版本控制之下,哦,我们希望在最小的版本控制历史扰动下完成这件事。

完成了这个从1.0到1.1的代码替换,svn status会显示文件的本地修改,或许也包括了一些未版本化或者丢失的文件,如果我们做了我们应该做的事情,未版本化的文件应该都是libcomplex在1.1新引入的文件—我们运行svn add来将它们加入到版本控制。丢失的文件是存在于1.1但是不是在1.1,在这些路径我们运行svn delete。最终一旦我们的current工作拷贝只是包括了libcomplex1.1的代码,我们可以提交这些改变目录和文件的修改。

我们的current分支现在保存了新的供方drop,我们为这个新的版本创建一个新的标签(就像我们为1.0版本drop所作的),然后合并这从个标签前一个版本的区别到主要开发分支。

$ cd working-copies/calc
$ svn merge http://svn.example.com/repos/vendor/libcomplex/1.0      \
            http://svn.example.com/repos/vendor/libcomplex/current \
            libcomplex
… # resolve all the conflicts between their changes and our changes
$ svn commit -m 'merging libcomplex-1.1 into the main branch'





5. 聪明的switch
svn switch可以把工作拷贝的全部或部分,逻辑上转换为 其他分支 的工作拷贝! 这是继前面,一个工作拷贝中可以混合不同版本后,又一种混合方式 ———— 混合不同的分支的部分。 它表现得像update!!
举个例子,你的工作拷贝目录是/calc/trunk,你已经做了很多修改,然后你突然发现应该在分支上修改更好,没问题!你可以使用svn switch使得工作拷贝逻辑上变为分支的工作拷贝,而你本地修改还会保留,你可以测试并提交它们到分支。

如果服务器做了svn move造成文件移动,那么 svn update会?? 必须用svn switch??

6. 建立标签:
标签就是一次正式发行打包。这里再次说明了:标签和分支一样,都是人为的概念,对于svn来说,都是用svn copy制造的“快照”。比如标签就是从trunk拷贝到tags,或者从测试的branch拷贝到tags。

但是,需要用一种方法,来禁止用户提交commit,因为标签概念上,不允许修改了,只是历史沉淀。
怎么做呢??? svn+ssh的话,用基本文件系统的权限来解决吧。
http://hi.baidu.com/00%C6%F3%B6%EC/blog/item/c2bb0245d00dd03786947321.html

、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、


Subversion有一个很标准的目录结构,是这样的。

比如项目是proj,svn地址为svn://proj/,那么标准的svn布局是

svn://proj/|+-trunk+-branches+-tags
这是一个标准的布局,trunk为主开发目录,branches为分支开发目录,tags为tag存档目录(不允许修改)。但是具体这几个目录应该如何使用,svn并没有明确的规范,更多的还是用户自己的习惯。

对于这几个开发目录,一般的使用方法有两种。我更多的是从软件产品的角度出发(比如freebsd),因为互联网的开发模式是完全不一样的。 1.第一种方法,使用trunk作为主要的开发目录
一般的,我们的所有的开发都是基于trunk进行开发,当一个版本/release开发告一段落(开发、测试、文档、制作安装程序、打包等)结束后,代码处于冻结状态(人为规定,可以通过hook来进行管理)。此时应该基于当前冻结的代码库,打tag。当下一个版本/阶段的开发任务开始,继续在trunk进行开发。
此时,如果发现了上一个已发行版本(Released Version)有一些bug,或者一些很急迫的功能要求,而正在开发的版本(Developing Version)无法满足时间要求,这时候就需要在上一个版本上进行修改了。应该基于发行版对应的tag,做相应的分支(branch)进行开发。
例如,刚刚发布1.0,正在开发2.0,此时要在1.0的基础上进行bug修正。
按照时间的顺序

1.0开发完毕,代码冻结 
基于已经冻结的trunk,为release1.0打tag
此时的目录结构为
svn://proj/
+trunk/ (freeze)
+branches/
+tags/
+tag_release_1.0 (copy from trunk) 
2.0开始开发,trunk此时为2.0的开发版 
发现1.0有bug,需要修改,基于1.0的tag做branch
此时的目录结构为
svn://proj/
+trunk/ ( dev 2.0 )
+branches/
+dev_1.0_bugfix (copy from tag/release_1.0)
+tags/
+release_1.0 (copy from trunk) 
在1.0 bugfix branch进行1.0 bugfix开发,在trunk进行2.0开发 
在1.0 bugfix 完成之后,基于dev_1.0_bugfix的branch做release等 
根据需要选择性的把dev_1.0_bugfix这个分支merge回trunk(什么时候进行这步操作,要根据具体情况) 
这是一种很标准的开发模式,很多的公司都是采用这种模式进行开发的。trunk永远是开发的主要目录。

2.第二种方法,在每一个release的branch中进行各自的开发,trunk只做发布使用。
这种开发模式当中,trunk是不承担具体开发任务的,一个版本/阶段的开发任务在开始的时候,根据已经release的版本做新的开发分支,并且基于这个分支进行开发。还是举上面的例子,这里面的时序关系是:

1.0开发,做dev1.0的branch
此时的目录结构
svn://proj/
+trunk/ (不担负开发任务 )
+branches/
+dev_1.0 (copy from trunk)
+tags/ 
1.0开发完成,merge dev1.0到trunk
此时的目录结构
svn://proj/
+trunk/ (merge from branch dev_1.0)
+branches/
+dev_1.0 (开发任务结束,freeze)
+tags/ 
根据trunk做1.0的tag
此时的目录结构
svn://proj/
+trunk/ (merge from branch dev_1.0)
+branches/
+dev_1.0 (开发任务结束,freeze)
+tags/
+tag_release_1.0 (copy from trunk) 
1.0开发,做dev2.0分支
此时的目录结构
svn://proj/
+trunk/ 
+branches/
+dev_1.0 (开发任务结束,freeze)
+dev_2.0 (进行2.0开发)
+tags/
+tag_release_1.0 (copy from trunk) 
1.0有bug,直接在dev1.0的分支上修复
更多 0
 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SVN学习笔记 . 的相关文章

  • 当文件标记为“历史记录已提交”时,svn diff

    我对已合并到工作目录中主干的分支进行了更改 svn stat 显示已更改文件的正确列表 但是 svn stat 输出在计划提交新添加到分支的每个文件的历史记录中包含一个 A src main java com java 当我运行 svn d
  • 如何在 svn 存储库中本地忽略 .git 和 .gitignore?

    我有一个 SVN 工作副本 由 TortoiseSVN 管理 在该工作副本中 我使用 git 进行本地版本控制和分支 当然 我想隐藏svn的 git目录和 gitignore文件 但是 忽略它们意味着将属性添加到不再是本地的存储库中 我不希
  • 如何使用 SVN 通过网络提交单个文件?

    我可以查看整个svn使用以下命令存储库 svn co https myaccount svn beanstalkapp com myapp 但我无法弄清楚提交单个文件的命令 如果我改变成myapp page1 html 我怎样才能只签入那一
  • 比较在 Eclipse Neon 中不工作

    我 最后 尝试从 Mars 2 升级到 Eclipse Neon 安装 SVN 支持和 SVNKit 1 8 14 连接器后 我可以访问我的存储库 然而Compare不管用 如果我右键单击已修改的文件 然后选择与工作副本中的基础进行比较将显
  • 如何“修复”SVN 分支/树冲突?

    我接手了一个软件项目 决定把所有东西都放在SVN下 上Assembla http www assembla com 使用 Tortoise SVN 树干在ROOT下 所以主干包含了整个应用程序 我标记为 1 0 对于我的第一个重要功能 我创
  • svn:修订版本中不存在路径

    我想在颠覆中创建标签 在命令行上我尝试了以下操作 svn复制http myserver mycompany com 8080 svn SVN Main trunk http myserver mycompany com 8080 svn S
  • 使用 svn diff 时如何获取无上下文

    当我从命令行使用 svn diff 时 它会打印出已更改的行 以及前后 3 个未更改的行以获取上下文 我更喜欢只看到没有上下文的更改行 我无法确定任何命令行选项可以让我让它以这种方式运行 默认情况下 标准 diff 和 cvs diff 执
  • 如何在 Mac OS X 10.8 上安装 hg Convert 所需的 python subversion 绑定?

    我正在寻找一种解决方案 最好是干净且简单的 以启用hg convert使用 SVN 存储库在 OS X 10 8 上工作 目前 如果您尝试转换 SVN 存储库 您将得到一个could not load Subversion python b
  • 有谁知道类似于 SVN Time-Lapse View 的 Git 工具 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 SVN Time Lapse View 是一个跨平台查看器 可以下载文件的所有修订版本 并允许您通过拖
  • 如何提取 Mercurial 中变更集的所有已更改文件?

    直到最近 我们一直在网络工作室的所有项目中使用 SVN 并且 Subversive 和 TortoiseSVN 等多个客户端中存在一个非常方便的功能 可以提取在某个版本中更改的所有文件 Mercurial 有没有办法做到这一点 我不在乎它是
  • 如何保持 Subversion 和远程服务器(通过 FTP)同步?

    我们很难保持 Subversion 和 FTP 同步 有时我们忘记提交更改并只是将它们推送到 Web 服务器 我们的 svn 文件夹分散在整个 Web 服务器中 有些东西存在于一个地方而不存在于另一个地方 等等 今天我想花点时间解决这个问题
  • 如何使用 Beyond Compare 3 作为 svn 的 diff3-cmd?

    I saw this https stackoverflow com questions 294286 how to use svn with beyond compare 3帖子解释了如何让 BC3 作为 Subversion 的 dif
  • 如何在 GNU/Linux 上设置 Subversion (SVN) 服务器 - Ubuntu [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一台运行 Ubuntu 的笔记本电脑 我想将其用作 Subversion 服务器 既让我自己在本地承诺 也让其他人远程承诺 要使其
  • 在 Subversion 中,如何取消劫持文件?

    目前 我的团队有一组不应该受到版本控制的文件 但它们确实受到了版本控制 我想从我们的 subversion 存储库中删除它们 并允许每个人保留他们的本地版本 实现这一目标的最佳方法是什么 删除文件会将它们从存储库以及每个人的本地文件系统中删
  • 将 git dcommits 切换到 svn 分支

    I had master dcommit到 和rebase来自 颠覆trunk 我创建了一个中间 Subversion 分支tc 合并来自 2 个不同分支的更改 使用 git branch master git svn branch tc
  • TortoiseSVN:如何从提交中忽略 bin 内容

    我使用 TortoiseSVN 1 7 9 我怎么能够ignore remove内容来自 bin文件夹当我svn commit项目文件夹 我不想提交诸如 dll pdb etc I put dll pdb进入svn 忽略属性 但它不起作用
  • ASP.NET 显示 SVN 修订号

    我在 Stack Overflow 页脚中看到显示了 SVN 修订号 这是自动化的吗 如果是的话 如何在 ASP NET 中实现它 其他语言的解决方案也是可以接受的 确保该文件有 svn keywords Rev Id 然后把 Rev 在那
  • 设置可视化SVN服务器后无法浏览存储库

    我在 Windows 7 x64 系统上安装了 VisualSVN Server 2 1 7 我已使用所有默认选项 安装路径 C Program Files x86 VisualSVN Server 存储库路径 D Repositories
  • Capistrano 部署擦除数据库?

    我已成功使用 Capistrano 将我的应用程序部署到生产环境 但我不明白如何处理我的数据库 我正在使用颠覆和乘客 当我运行 cap 部署时 新部署会重新启动一切 它会清除添加到数据库中的数据 显然 必须有一个解决方案 但我很惊讶没有在网
  • IntelliJ Idea 无法与 svn 更新一起正常工作

    在 IntelliJ Idea Community 版本中进行 svn 更新或比较操作时 我不断遇到相同的错误 svn E175002 Received fatal alert unexpected message svn E175002

随机推荐

  • 【二维费用的完全背包问题】

    前言 简单写一下算法设计与分析这门课的一次实验 原题要求是用0 1背包来做 但是老师要求用完全背包来做 一 完全背包与0 1背包有什么区别 0 1背包 顾名思义对于每件物品只能拿1次或者0次 而完全背包对于每件物品的拿取没有次数限制 二 二
  • beyond compare破解方法

    BeyondCompare4相关操作 1 修改文件C Program Files Beyond Compare 4 BCUnrar dll 这个文件重命名或者直接删除 2 将以下操作保存为bat文件 然后双击运行即可 reg delete
  • java多态-对象多态

    对象多态 动态绑定 动态连接 package com leoworld polymorphism 多态的成员访问特点 A 成员变量 编译看左边 运行看左边 B 成员方法 编译看左边 运行看右边 为什么呢 因为成员方法有重写 而变量没有 C
  • 计算机dvd驱动错误,修正:一个错误发生在弹出的CD/DVD驱动器在Windows 10

    如果您使用的是可移动媒体 比如DVD或USB驱动器 有时您可能会在从系统中删除或弹出它时遇到麻烦 通常 Windows会拒绝当前正在使用的驱动器的请求 这意味着你应该首先关闭程序 应用程序 进程使用驱动器上的内容 然后你应该继续试着弹出驱动
  • 【Software Engineering】【期末复习知识点】【2023春】【仅供参考】

    文章目录 类型 总分占比 出勤 10 平时作业 2 5 10 期中考试 10 期末考试 70 附加分 提问加分 题型 题量 分值 预测 选择 15 2 填空 5 2 软件工程方法学 名词解释 5 2 软件危机 软件生命周期 简答 3 5 综
  • html中表单form的语法结构以及释义

    1 form属性
  • Redis command timed out nested exception is io.lettuce.core.RedisCommandTimeoutException

    报错如下 ERROR org springframework dao QueryTimeoutException Redis command timed out nested exception is io lettuce core Red
  • CSS3 2D转换之位移(translate)、旋转(rotate)、缩放(scale)以及设置旋转和缩放的中心点

    2D转换概述 2D转换可以实现元素的位移 旋转 缩放等效果 2D转换的分类有 移动 translate 旋转 rotate 缩放 scale 2D转换之translate 2D移动translate可以改变元素在页面中的位置 类似定位 移动
  • Eigen:C++中Eigen库的安装与学习

    1 下载地址 http eigen tuxfamily org index php title Main Page 进入上边官方网站进行下载如下所示 找到自己需要的版本下载即可 我下载的是3 3 8 右边的zip 2 解压配置即可 找到你下
  • Kafka配置与使用

    Kafka依赖于zookeeper 因此先配置zookeeeper zookeeper配置 修改 opt bigdata zookeeper conf zoo cfg dataDir data zookeeper 配置zookeeper数据
  • Java实现通过证书访问Https请求

    创建证书管理器类 import java io FileInputStream import java security KeyStore import java security cert CertificateException imp
  • 记录-常见算法的收集

    1 快速排序 找到基准点的位置 既不浪费空间又可以快一点的排序算法 如 6 1 2 7 9 3 4 5 10 8 这10个数进行排序 首先找到一个数作为基准点 一个参照数 为了方便 让第一个数6作为基准点 然后将这个序列中所有比基准数大的数
  • JQ工具2

    JQ工具2 开发工具与关键技术 VS JQ 作者 唐文坚 撰写时间 2020 10 17 jQuery extend deep target object1 objectN 概述 用一个或多个其他对象来扩展一个对象 返回被扩展的对象 如果不
  • C语言经典100例题(47)--宏#define命令练习(2)

    目录 题目 问题分析 代码 运行结果 题目 宏 define命令练习 2 问题分析 如果我们在 define的宏定义的内容过长时 我们的编译器中一行放不下 我们还可以加入续行符 也就是 来进行换行 是否一定需要使用换行符呢 答案是肯定的 如
  • 数组中最大最小值(C语言实现)

    题目描述 从键盘输入n n从键盘输入 n lt 100 个数存放在数组中 输出其中的最大数和最小数及他们对应的下标 输入说明 输入包含2行 第一行只有1个数字表示n 第二行有连续n个数字 其间用半角空格间隔 输出说明 输出只有1行 顺次输出
  • 快速排序及sort的理解

    快速排序 快速排序的思想 1 在数据集中 选择一个元素作为 基准 2 所有小于 基准 的元素都移动到 基准 左边 所有大于 基准 的元素都移动到 基准 右边 3 对 基准 左右两边的子集 递归地重复 1 和 2 直到所有子集的长度都只有1个
  • 按位非‘~’符号的使用

    所谓的按位非就是在数字前加上 的符号 最简单的记忆方法是 a a 1 let a 1 let b a b 2 let a 2 let b a b 3 let a 1 let b a b 0 使用场景 在if判断的时候 if在0的情况下的转换
  • C3-Squid-access.log

    C3 Squid access log 拓扑 DNS 10 0 100 71 Haproxy 10 0 100 82 Squid 10 0 100 72 73 Nginx 10 0 100 75 76 NFS 10 0 100 70 DNS
  • ASP.NET 中得到网站绝对路径的几种方法

    在编写 ASP NET 应用程序的时候 有时为了更好地进行控制静态文件的路径 如在模板页或者用户控件中设置js或者css文件的路径等 采用绝对路径是难免的 下面就是几种获取绝对路径的几种方法 C 代码 VirtualPathUtility
  • SVN学习笔记 .

    转载自 http blog csdn net tengbaichuan article details 10632349 参考文档 官方文档 http www subversion org cn svnbook 包括可下载的PDF 和一页H