当前位置: 技术问答>linux和unix
关于CVS
来源: 互联网 发布时间:2015-03-14
本文导语: 谁用过CVS,请问怎么用?能干什么?装在什么系统下,谁能系统告知一下,谢谢 | 使用 CVS CVS 是什么? CVS 代表协作版本系统;这是一个将一组文件放在层次目录树中以保持同步的系统...
谁用过CVS,请问怎么用?能干什么?装在什么系统下,谁能系统告知一下,谢谢
|
使用 CVS
CVS 是什么?
CVS 代表协作版本系统;这是一个将一组文件放在层次目录树中以保持同步的系统。人们可以从 CVS 服务器上更新他们的本地层次树副本,并将修改的结果或新文件发回;或者删除旧文件。
CVS 基于客户端/服务器的行为使得其可容纳多用户,构成网络也很方便。这一特性使得 CVS 成为位于不同地点的人同时处理数据文件(特别是程序的源代码)时的首选。
所有重要的免费软件项目都使用 CVS 作为其程序员之间的中心点,以便能够综合各程序员的改进和更改。这些项目包括: Gnome, KDE, The GIMP, Wine, 等等。
所以,理所当然的,MandrakeSoft 也使用 CVS 作为其自身的开发管理平台。
要使用 CVS,你需要连接到服务器,然后制作你所需要的 CVS 模块的本地副本。下次你就只需要更新自上次连接后发生的变化。
这非常简单,你只需要 cvs 包(该包存在于标准 Linux-Mandrake 发放版本中)以及足够的磁盘空间来存储你所需要的内容。
要通知 cvs 你想要连接到哪个服务器,以什么身份登录,想要哪个 CVS 头;你需要定义 CVSROOT 变量,像这样:
export CVS_RSH=ssh
export CVSROOT=:ext:anoncvs@cvs.mandrakesoft.com:/cooker
如果你想要连接到服务器 linux-mandrake.com,以 anoncvs 的身份及密码 cvs 登录,并请求与 CVS 头 /cooker 相关的内容(在给定服务器上可能有多个)。
你需要创建你需要的层次的全新副本。假定你需要获得 po 层次树,你可以输入:
cvs -z3 checkout po
(-zX 意味着使用压缩;在交换纯文本文件时非常有用;你可以使用较大的数值获得更高的压缩比,较小的数值获得更少的压缩比。但是要注意,越高的压缩比就会给你的 CPU 和服务器的处理器带来更多的压力。)
你将会在 stdout 上看到许多输入消息,而文件就在这时复制到了你本地的硬盘上。
下次你就不需要执行 cvs checkout 了;只需 cvs login(不要忘了 CVSROOT 环境变量),然后执行 cvs 升级,如下:
cd po
cvs -z3 update -d
请注意,我更改为 po 目录;这样做的原因是我发现使用 -d 的方法更加容易。-d 的含义是创建并获得自上次登录后 CVS 服务器上任何新增的目录。-zX 与 cvs checkout 时的含义相同。
现在,使用这些简单的命令你就可以获得你拥有 CVS 读访问权的任何项目的快照了。但是不要滥用;要维护这样一个服务,要花费很多带宽和服务器资源;如果你获得程序源代码什么用也没有,就不必登录并下载了。不过另一方面,如果你真的想要为免费软件世界做点什么的话,你就有理由在正是版本发布之前提出你的建议、改善等等。当然,你不必是程序员,现在更为缺少的是翻译者,作家,美工等等。
如果你有对 CVS 的写权限,你就可以上传发送你的更改。
你可做的修改共有三种:
修改已有文件:只是更改文件(编辑、或者完全用其它文件覆盖,等等)。
添加新文件/目录:你需要复制这些文件(或者创建这些目录)然后执行 cvs add 新文件或目录 来说明你想要添加的新内容。
删除文件/目录:你需要先将其从本地删除,然后执行 cvs delete 删除的文件或目录 (在这里的 cvs delete 命令中无法像 add 命令那样使用自动完成或者 *? 通配符,这真的十分烦人)
然后,输入 cvs -z3 commit (此处的 -zX 还是代表相同的意思)你所作的更改就会被提交到服务器。接下来会出现你喜爱的编辑器(用 EDITOR 环境变量定义的),你可以对你所作的修改写一些描述(这些描述将会保留在 CVS 服务器的日志上,如果出现问题的话想要推倒也很容易)。
请注意,如果服务器上的文件版本比你想要提交的文件要新话,将会发生错误;所以推荐你在提交前执行一次 cvs update。
CVS 是什么?
CVS 代表协作版本系统;这是一个将一组文件放在层次目录树中以保持同步的系统。人们可以从 CVS 服务器上更新他们的本地层次树副本,并将修改的结果或新文件发回;或者删除旧文件。
CVS 基于客户端/服务器的行为使得其可容纳多用户,构成网络也很方便。这一特性使得 CVS 成为位于不同地点的人同时处理数据文件(特别是程序的源代码)时的首选。
所有重要的免费软件项目都使用 CVS 作为其程序员之间的中心点,以便能够综合各程序员的改进和更改。这些项目包括: Gnome, KDE, The GIMP, Wine, 等等。
所以,理所当然的,MandrakeSoft 也使用 CVS 作为其自身的开发管理平台。
要使用 CVS,你需要连接到服务器,然后制作你所需要的 CVS 模块的本地副本。下次你就只需要更新自上次连接后发生的变化。
这非常简单,你只需要 cvs 包(该包存在于标准 Linux-Mandrake 发放版本中)以及足够的磁盘空间来存储你所需要的内容。
要通知 cvs 你想要连接到哪个服务器,以什么身份登录,想要哪个 CVS 头;你需要定义 CVSROOT 变量,像这样:
export CVS_RSH=ssh
export CVSROOT=:ext:anoncvs@cvs.mandrakesoft.com:/cooker
如果你想要连接到服务器 linux-mandrake.com,以 anoncvs 的身份及密码 cvs 登录,并请求与 CVS 头 /cooker 相关的内容(在给定服务器上可能有多个)。
你需要创建你需要的层次的全新副本。假定你需要获得 po 层次树,你可以输入:
cvs -z3 checkout po
(-zX 意味着使用压缩;在交换纯文本文件时非常有用;你可以使用较大的数值获得更高的压缩比,较小的数值获得更少的压缩比。但是要注意,越高的压缩比就会给你的 CPU 和服务器的处理器带来更多的压力。)
你将会在 stdout 上看到许多输入消息,而文件就在这时复制到了你本地的硬盘上。
下次你就不需要执行 cvs checkout 了;只需 cvs login(不要忘了 CVSROOT 环境变量),然后执行 cvs 升级,如下:
cd po
cvs -z3 update -d
请注意,我更改为 po 目录;这样做的原因是我发现使用 -d 的方法更加容易。-d 的含义是创建并获得自上次登录后 CVS 服务器上任何新增的目录。-zX 与 cvs checkout 时的含义相同。
现在,使用这些简单的命令你就可以获得你拥有 CVS 读访问权的任何项目的快照了。但是不要滥用;要维护这样一个服务,要花费很多带宽和服务器资源;如果你获得程序源代码什么用也没有,就不必登录并下载了。不过另一方面,如果你真的想要为免费软件世界做点什么的话,你就有理由在正是版本发布之前提出你的建议、改善等等。当然,你不必是程序员,现在更为缺少的是翻译者,作家,美工等等。
如果你有对 CVS 的写权限,你就可以上传发送你的更改。
你可做的修改共有三种:
修改已有文件:只是更改文件(编辑、或者完全用其它文件覆盖,等等)。
添加新文件/目录:你需要复制这些文件(或者创建这些目录)然后执行 cvs add 新文件或目录 来说明你想要添加的新内容。
删除文件/目录:你需要先将其从本地删除,然后执行 cvs delete 删除的文件或目录 (在这里的 cvs delete 命令中无法像 add 命令那样使用自动完成或者 *? 通配符,这真的十分烦人)
然后,输入 cvs -z3 commit (此处的 -zX 还是代表相同的意思)你所作的更改就会被提交到服务器。接下来会出现你喜爱的编辑器(用 EDITOR 环境变量定义的),你可以对你所作的修改写一些描述(这些描述将会保留在 CVS 服务器的日志上,如果出现问题的话想要推倒也很容易)。
请注意,如果服务器上的文件版本比你想要提交的文件要新话,将会发生错误;所以推荐你在提交前执行一次 cvs update。
|
CVS是一个版本控制系统,用于在多人开发环境下的源码的维护.从理论上
CVS可以维护任意的文本文档的开发,而不是局限于程序设计.
CVS用copy-midify-merge变化表支持对文件的同时访问和修改.
在UNIX环境理,CVS的使用一般是以命令行方式,也有一些GUI的前端工具,如TKCVS等.
CVS的使用有两种方式,一是本机使用, 一是远程执行.这里现说本机使用.
CVS的命令格式是:
cvs [cvs的选项] cvs-command [command 选项]
如:
cvs commit
cvs -d /usr/local/cvsroot init
cvs update
cvs -H command (列出命令command的使用方法)
运行CVS不需要特殊的权限, 只是在多人时需要设定大家都有读写权.(见后)
注意:使用CVS管理源代码,对于代码的获得,更新,应通过CVS命令来完成.
下面从一个项目开始.
一,开始项目
用CVS来管理原代码,首先要创建一个"仓库"(repository),"仓库"简单来说是
一个目录结构,它包括乐要管理的原代码和用于管理原代码的各种管理文件.
使用CVS命令init:
先设置环境变量CVSROOT,指向仓库的绝对路径,然后调用CVS的init命令
bash$ CVSROOT=/usr/local/cvsroot;export CVSROOT
bash$ cvs init
bash$ ls -l $CVSROOT
也可以用CVS参数-d path来覆盖$CVSROOT的值
bash$ cvs -d /usr/local/cvsroot init
许多CVS的命令允许用这种方式指定cvs的根目录.
二,添加文件,目录到仓库
我们要将需要管理的文件加入仓库,并命名
CVS命令import (此命令应只用一次, 以后用cvs add)
例如, 将当前目录下的src/*加入:
bash$ cvs import -m "init implement" myproject myvtag mtrtag
-m 指定log message
myproject : 仓库名
myvtag: vendor tag
myrtag: release tag
三,设置权限
源码管理员应对仓库下的文件和目录设置恰当的许可权限来控制访问.
所有的RCS文件(以,v结尾)是只读方式,仓库中的目录应当对使用者有写权,以便允许
其更改.
仓库设好后,就可以利用CVS的命令来管理.(包括对项目,对源代码)
一般的常用的命令:
cvs checkout
从仓库中得到某版本的代码.在本地产生一个copy
cvs update
从仓库中更新本地的代码
cvs commit
将本地修改后的代码提交仓库,并产生新版本.
cvs add
添加新的文件到仓库,在cvs commit命令后生效.
一般的流程是
cvs checkout or cvs update
用你喜欢的编辑器修改本地copy
cvs commit
提交修改.
在介绍CVS命令之前,先说点别的
如以前说,仓库内除乐源文件外,还包括一系列的管理文件.位于$CVSROOT/CVSROOT
修改管理文件的方法等同于源代码文件,利用CVS命令提取和修改.
下面描述每个文件的用途:
checkoutlist 支持CVSROOT目录的其它管理文件,允许为各种CVS命令定置信息
commitinfo 在cvs commit命令执行时,这个文件指定乐文件提交时执行的命令
cvswrappers 定义乐一个包装程序当文件登记或检取时就会执行.
editinfo 允许你在commit命令启动前在日志信息被记录后执行的脚本
history 跟踪所有影响仓库的命令
loginfo 类似coimmitinfo, 只是在文件提交后执行
modules 允许为一组文件定义一个符号,否则必须为每一个要引用的文件
指定部分路径名(相对于$CVSROOT)
nitify 控制从"watch"来的通知."watch"由"cvs watch add"和"cvs edit"
设置
rcsinfo 为commit log回话指定一个模板.
taginfo 定义乐在任意"tag"操作后执行的程序.
CVS的环境变量
CVS使用乐几个环境变量
CVSROOT 仓库根目录的完整路径名
CVSREAD 如果设置,表明在checkout操作时所有的文件都置成只读
CVSBIN CVS利用乐很多RCS的命令,指定乐RCS工具的路径
CVSEDITOR 指定用户书写日志信息所使用的编辑器
CVS_RSH 启动一个远程CVS服务器时,所使用的shell的名称
CVS_SERVER 决定"cvs server"的名字,缺省是CVS
CVSWRAPPERS cvswrapper脚本, 用来指定包装文件名.
关键字
管理源文件的一种技术叫"关键字替换".在每次执行"cvs commit"操作后
源文件的某些关键字会被替换为可用的词
$AUTHOR$ 用户名
$Data$ 登记时的时间
$Header$ 标准的首部,包含RCS的完整路径名,日期,作者
$Id$ 除RCS文件名不完整外与$Header$同.
$Log$ 包含RCS的完整路径名,版本号,日期,作者和在提交时提供的日志信息.
$RCSfile$ 包含RCS的文件名,不包括路径名
$Revision$ 分配的版本号
$Source$ RCS文件的完整名
$State$ 分配的版本的状态,由 cvs admin -s 分配.
例:
在cvs commit之前,main.c里有
static char *rcsid="$Id$";
执行cvs commit后
main.c的改行变为:
static char *rcsid="$Id: main.c,v 1.2 1999/04/29 15:10:14 trimblef Exp$";
下面开始说说CVS的命令
我们已下面仓库的数据为例
$CVSROOT
--CVSROOT
--project
--src
--main
--main.c
--main.h
--print
--print.c
--print.h
--term
--term.c
--term.h
CVS checkout 命令
从仓库提取指定的文件到当前目录,并建立同样的结构,并创建CVS目录
例
bash$ cvs checkout project
bash$ cvs checkout project/src/main
为使用便利,我们可以对一个目录建一个缩写,方法是修改$CVSROOT/CVSROOT/下的
modules文件.(当然是用cvs 命令完成)
cvs checkout CVSROOT/modules
cd CVSROOT
vi modules
我们在文件尾加上
src project/src
print project/src/print
cvs commit
以后我们就可以用cvs checkout print来代替
cvs checkout project/src/print
cvs checkout命令缺省是得到最新版本.我们也可以得到某一个老版本
cvs checkout -r 1.1 print
将print的1.1版的代码取出.
cvs checkout的详细用法见cvs -H checkout的输出.
CVS commit 命令
在对文件的修改完成后,用cvs commit提交到仓库.
cvs commit -m "Update by xxxxx" project
cvs commit -m "Update main.c" main.c
提交完成后,当前的版本号会更新,如原来为1.1,现为1.2. 这两个版本都在
仓库的主干(maintrunk)上.
-m选项可以记录有关提交的注释.如果没有指定-m选项,在环境变量CVSEDITOR
中指定的编辑器被调用(vi是缺省的),提示键入文本,修改记录注释.
CVS update
CVS允许多人同时对一个文件进行修改.
假设泥正在修改文件的一部分,现想合并更新自己的本地拷贝(checkout)和
另一个人所做的修改(已经放在仓库里),可用cvs update
cvs update
CVS tag , CVS rtag
创建分支可以使用户对一些文件进行修改而不会影响主干(当commit时).
创建分支首先为拟修改的某些文件创建一个标签(tag),标签是赋于一个文件或一组文件的符号.在源代码的生命周期里,组成一组模块的文件被赋于相同的标签.
创建标签:在工作目录里执行cvs tag
例: 为src创建标签:
cvs checkout src
cvs tag release-1-0
标签创建后, 就可以为其创建一个分支:
cvs rtag -b -r release-1-0 release-1-0-path print
-b :创建分支
-r release-1-0 :指定存在的标签
releas-1-0-patch:分支
print: 模块名
合并
使用cvs update -j 选项可以将分支上的改变与本地文件拷贝合并.
cvs update -j release-1-0 print.c
cvs release
对源文件作必要修改后, 可以用cvs release 删除本地工作拷贝
并通知其他开发者这个模块不再使用.
cvs release -d print
-d : 删除
print: 目录
冲突
由于CVS允许多人同时修改同一文件,冲突是不可避免的.例如当两人
同时修改同一文件的同一行时.
这时,如用cvs update 更新,CVS检测到冲突的存在,它会将冲突的代码
用""标识.这时需手工处理这段代码.与引起
冲突的开发者协商,并对文件修改后即可用cvs commit提交.
cvs的最好的帮助是man手册.
CVS可以维护任意的文本文档的开发,而不是局限于程序设计.
CVS用copy-midify-merge变化表支持对文件的同时访问和修改.
在UNIX环境理,CVS的使用一般是以命令行方式,也有一些GUI的前端工具,如TKCVS等.
CVS的使用有两种方式,一是本机使用, 一是远程执行.这里现说本机使用.
CVS的命令格式是:
cvs [cvs的选项] cvs-command [command 选项]
如:
cvs commit
cvs -d /usr/local/cvsroot init
cvs update
cvs -H command (列出命令command的使用方法)
运行CVS不需要特殊的权限, 只是在多人时需要设定大家都有读写权.(见后)
注意:使用CVS管理源代码,对于代码的获得,更新,应通过CVS命令来完成.
下面从一个项目开始.
一,开始项目
用CVS来管理原代码,首先要创建一个"仓库"(repository),"仓库"简单来说是
一个目录结构,它包括乐要管理的原代码和用于管理原代码的各种管理文件.
使用CVS命令init:
先设置环境变量CVSROOT,指向仓库的绝对路径,然后调用CVS的init命令
bash$ CVSROOT=/usr/local/cvsroot;export CVSROOT
bash$ cvs init
bash$ ls -l $CVSROOT
也可以用CVS参数-d path来覆盖$CVSROOT的值
bash$ cvs -d /usr/local/cvsroot init
许多CVS的命令允许用这种方式指定cvs的根目录.
二,添加文件,目录到仓库
我们要将需要管理的文件加入仓库,并命名
CVS命令import (此命令应只用一次, 以后用cvs add)
例如, 将当前目录下的src/*加入:
bash$ cvs import -m "init implement" myproject myvtag mtrtag
-m 指定log message
myproject : 仓库名
myvtag: vendor tag
myrtag: release tag
三,设置权限
源码管理员应对仓库下的文件和目录设置恰当的许可权限来控制访问.
所有的RCS文件(以,v结尾)是只读方式,仓库中的目录应当对使用者有写权,以便允许
其更改.
仓库设好后,就可以利用CVS的命令来管理.(包括对项目,对源代码)
一般的常用的命令:
cvs checkout
从仓库中得到某版本的代码.在本地产生一个copy
cvs update
从仓库中更新本地的代码
cvs commit
将本地修改后的代码提交仓库,并产生新版本.
cvs add
添加新的文件到仓库,在cvs commit命令后生效.
一般的流程是
cvs checkout or cvs update
用你喜欢的编辑器修改本地copy
cvs commit
提交修改.
在介绍CVS命令之前,先说点别的
如以前说,仓库内除乐源文件外,还包括一系列的管理文件.位于$CVSROOT/CVSROOT
修改管理文件的方法等同于源代码文件,利用CVS命令提取和修改.
下面描述每个文件的用途:
checkoutlist 支持CVSROOT目录的其它管理文件,允许为各种CVS命令定置信息
commitinfo 在cvs commit命令执行时,这个文件指定乐文件提交时执行的命令
cvswrappers 定义乐一个包装程序当文件登记或检取时就会执行.
editinfo 允许你在commit命令启动前在日志信息被记录后执行的脚本
history 跟踪所有影响仓库的命令
loginfo 类似coimmitinfo, 只是在文件提交后执行
modules 允许为一组文件定义一个符号,否则必须为每一个要引用的文件
指定部分路径名(相对于$CVSROOT)
nitify 控制从"watch"来的通知."watch"由"cvs watch add"和"cvs edit"
设置
rcsinfo 为commit log回话指定一个模板.
taginfo 定义乐在任意"tag"操作后执行的程序.
CVS的环境变量
CVS使用乐几个环境变量
CVSROOT 仓库根目录的完整路径名
CVSREAD 如果设置,表明在checkout操作时所有的文件都置成只读
CVSBIN CVS利用乐很多RCS的命令,指定乐RCS工具的路径
CVSEDITOR 指定用户书写日志信息所使用的编辑器
CVS_RSH 启动一个远程CVS服务器时,所使用的shell的名称
CVS_SERVER 决定"cvs server"的名字,缺省是CVS
CVSWRAPPERS cvswrapper脚本, 用来指定包装文件名.
关键字
管理源文件的一种技术叫"关键字替换".在每次执行"cvs commit"操作后
源文件的某些关键字会被替换为可用的词
$AUTHOR$ 用户名
$Data$ 登记时的时间
$Header$ 标准的首部,包含RCS的完整路径名,日期,作者
$Id$ 除RCS文件名不完整外与$Header$同.
$Log$ 包含RCS的完整路径名,版本号,日期,作者和在提交时提供的日志信息.
$RCSfile$ 包含RCS的文件名,不包括路径名
$Revision$ 分配的版本号
$Source$ RCS文件的完整名
$State$ 分配的版本的状态,由 cvs admin -s 分配.
例:
在cvs commit之前,main.c里有
static char *rcsid="$Id$";
执行cvs commit后
main.c的改行变为:
static char *rcsid="$Id: main.c,v 1.2 1999/04/29 15:10:14 trimblef Exp$";
下面开始说说CVS的命令
我们已下面仓库的数据为例
$CVSROOT
--CVSROOT
--project
--src
--main
--main.c
--main.h
--print.c
--print.h
--term
--term.c
--term.h
CVS checkout 命令
从仓库提取指定的文件到当前目录,并建立同样的结构,并创建CVS目录
例
bash$ cvs checkout project
bash$ cvs checkout project/src/main
为使用便利,我们可以对一个目录建一个缩写,方法是修改$CVSROOT/CVSROOT/下的
modules文件.(当然是用cvs 命令完成)
cvs checkout CVSROOT/modules
cd CVSROOT
vi modules
我们在文件尾加上
src project/src
print project/src/print
cvs commit
以后我们就可以用cvs checkout print来代替
cvs checkout project/src/print
cvs checkout命令缺省是得到最新版本.我们也可以得到某一个老版本
cvs checkout -r 1.1 print
将print的1.1版的代码取出.
cvs checkout的详细用法见cvs -H checkout的输出.
CVS commit 命令
在对文件的修改完成后,用cvs commit提交到仓库.
cvs commit -m "Update by xxxxx" project
cvs commit -m "Update main.c" main.c
提交完成后,当前的版本号会更新,如原来为1.1,现为1.2. 这两个版本都在
仓库的主干(maintrunk)上.
-m选项可以记录有关提交的注释.如果没有指定-m选项,在环境变量CVSEDITOR
中指定的编辑器被调用(vi是缺省的),提示键入文本,修改记录注释.
CVS update
CVS允许多人同时对一个文件进行修改.
假设泥正在修改文件的一部分,现想合并更新自己的本地拷贝(checkout)和
另一个人所做的修改(已经放在仓库里),可用cvs update
cvs update
CVS tag , CVS rtag
创建分支可以使用户对一些文件进行修改而不会影响主干(当commit时).
创建分支首先为拟修改的某些文件创建一个标签(tag),标签是赋于一个文件或一组文件的符号.在源代码的生命周期里,组成一组模块的文件被赋于相同的标签.
创建标签:在工作目录里执行cvs tag
例: 为src创建标签:
cvs checkout src
cvs tag release-1-0
标签创建后, 就可以为其创建一个分支:
cvs rtag -b -r release-1-0 release-1-0-path print
-b :创建分支
-r release-1-0 :指定存在的标签
releas-1-0-patch:分支
print: 模块名
合并
使用cvs update -j 选项可以将分支上的改变与本地文件拷贝合并.
cvs update -j release-1-0 print.c
cvs release
对源文件作必要修改后, 可以用cvs release 删除本地工作拷贝
并通知其他开发者这个模块不再使用.
cvs release -d print
-d : 删除
print: 目录
冲突
由于CVS允许多人同时修改同一文件,冲突是不可避免的.例如当两人
同时修改同一文件的同一行时.
这时,如用cvs update 更新,CVS检测到冲突的存在,它会将冲突的代码
用""标识.这时需手工处理这段代码.与引起
冲突的开发者协商,并对文件修改后即可用cvs commit提交.
cvs的最好的帮助是man手册.
|
可以看看
http://www.chedong.com/tech/cvs_card.html
http://www.chedong.com/tech/cvs_card.html
|
http://www.chedong.com/tech/cvs_card.html
您可能感兴趣的文章:
本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。
本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。