文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>代码维护

代码维护

时间:2007-02-05  来源:hello386



简单cvs
简单CVS
一、所要解决的问题
    由于软件项目越来越大,也增加了软件项目管理的难度。在开发组中,每个成员都要保留一个副本,在开发中非常容易引起冲突。CVS 就是为了解决这个问题的。

    a、修改同步,防止一名开发人员的修改覆盖其他人的成果。(check out、read only)

    b、维护不同的版本。(按 version 查找)

    c、可查找历史记录。防止 bug 的再引入。(diff)

    CVS 为了解决这个问题,采用的方式是:

    当开发人员对源代码进行修改时,修改的内容被登记(check in)到了 CVS 仓库(repository)中。仓库中保存了代码的主控副本,以及历次修改的历史信息。它不保存文件的每个版本,而只是简单的记录发生在每个版本间的不同,节省磁盘空间。它能做到:

    a、使开发人员的目录和仓库保持一致。可以把自己的修改提交(commit)给仓库,让仓库更新自己。

    b、允许代码派生。可以进行测试,如果失败,可以消除所做的修改,维持原结果。

    c、检索任何一个版本。

二、使用 CVS:

    a、建立仓库:设置并 export CVSROOT 变量,并设置仓库目录。比如创建 /home/cvsroot 目录,并合理设置权限,在 .bash_profile 中加入:export CVSROOT=$HOME/cvsroot;运行 cvs init;设置让用户输入日志信息的默认的编辑器:export EDITOR=vim。如果使用的是网络,则 CVSROOT 变量的形式是: export CVSROOT=:exit:user@server:/path,比如:export CVSROOT=:exit:david@power/home/projects/repository

    b、导入文件或目录:cvs import filename_or_directory vender_tag release_tag;这三个参数的含义是:在仓库中这些导入的文件所在的目录、供应商标记、发行标记。比如 cvs import step1 david start。导入时的 N 表示所导入的文件都是新文件。

    c、使用时导出文件,用:cvs checkout directory_name;参数含义是仓库中所在的目录。建立新的目录,而不是获取他人的改动

    d、对文件修改后,保存修改到仓库:cvs commit。

    e、如果要获得他人的修改,使用 cvs update,U 表示本地的一个文件已经被更新。如果已经对文件进行了修改,而此是他人已经修改了该文件并提交,cvs 将告诉用户发生冲突和冲突的位置。

    f、添加一个文件:cvs add filename; cvs commit。

    g、删除一个文件:先在本地删除,然后使用 cvs remove file_name; cvs commit。

三、使用标记

    可以使用标记记录某个时刻文件的内容,这在制作发行版本的过程中非常有用:

    cvs tag release1.0

    改动后发现不正常,重新获得这个版本,则使用:cvs checkout -r release1.0

四、测试性代码:

    当其中一个开发者对代码进行改进,但未来结果不能确定时,可以使用 cvs 产生出一个代码的分之,这并不改变主控代码:cvs tag -b for_test。导出该代码的命令是:cvs checkout -r for_test example。由于在已有的目录树中不会使用该分之,因此必须重新建立目录树。如果测试成功,则要求将主控代码和测试代码合并,则先导出主控代码,然后合并:

    cvs checkout;cvs update -jfor_test;cvs commit。


[目录]
automake
    通常情况下,在写完自己代码后,使用 make 命令进行编译。make 命令其实什么也不做,知识读取一个叫 Makefile 的文件,从中获得 dependence and rule,然后调用 gcc 进行编译。但是 Makefile 比较复杂,变化技巧也比较多。对于一个大的工程项目来说,如果没有一个统一的风格,在工程延续的时候改动 Makefile 会很麻烦,也容易出错误。所以这时就有了使用 automake 的需求。使用 automake,只需要掌握一点点规则,定义一些变量,就能自动生成 Makefile。而这些 Makefile 有着统一的格式和结构,便于修改。下面就如何使用 automake 举出一个实际的例子。

2.1 使用 automake 的前提条件


    在使用 automake 前,请先确认在系统中安装了如下软件:

    GNU Automake

    GNU Autoconf

    GNU m4

    perl

    GNU Libtool(如果需要产生 shared library)如果没有的话,请在发行版中找相应的 rpm 包。

2.2 制作 configure 脚本

autoconf 是用来生成自动配置软件源代码脚本(configure)的工具。configure 脚本独立于 autoconf 运行,而且在运行的过程中,不需要用户的干预,通常不需要附带参数。它是用来检验软件必须的参数的。autoconf 从一个列举编译软件时所需要各种参数的模板文件中创建 configure。autoconf 需要 GNU m4 来生成该脚本。

由 autoconf 生成的脚本一般起名为 configure。当运行时,configure 创建了多个文件,并对这些文件中的配置参数赋予适当的值。由 configure 创建生成的文件有:

    1。一个或多个 Makefile,在软件源代码的每个目录中都生成一个 Makefile。

    2。还可选的生成 C 头文件——configurable,包含了各种 #define 声明。

    3。一个名为 config.status 的脚本,当运行时,重新生成上面的文件。

    4。一个名为 config.cache 的脚本,保存运行检测的结果。

    5。一个名为 config.log 的文件,保存有编译器生成的信息,用于调试 configure。

为了让 autoconf 生成 configure 脚本,需要以 configure.in 为参数调用 autoconf。如果要检测自己的各种参数,以作为对 autoconf 的补充,则需要写 aclocal.m4 和 acsite.m4 的文件。如果要使用 C 头文件,需要写 acconfig.h,并且将 autoconf 生成的 config.h.in 同软件一起发行。

your source files --> [autoscan*] --> [configure.scan] --> configure.in


configure.in --. .------> autoconf* -----> configure

                   +---+

[aclocal.m4] --+   `---.

[acsite.m4] ---'       |

                      +--> [autoheader*] -> [config.h.in]

[acconfig.h] ----.     |

                 +-----'

[config.h.top] --+

[config.h.bot] --'


Makefile.in -------------------------------> Makefile.in

Files used in configuring a software package:

                       .-------------> config.cache

configure* ------------+-------------> config.log

                       |

[config.h.in] -.       v            .-> [config.h] -.

               +--> config.status* -+               +--> make*

Makefile.in ---'                    `-> Makefile ---'


编辑 configure.in 文件:

configure.in 文件中包含了对 autoconf 宏的调用,这些宏是用来检测软件所必须的各项参数的。为了能够得到 configure.in 文件,需要使用 autoscan。configure.in 文件中,在进行各项检测前,必须在最开始调用 AC_INIT,在最后调用 AC_OUTPUT。另外有些宏由于检测的关系是和在文件中的位置相关的。最好每一个宏占用一行。


使用 autoscan 创建 configure.in 文件

可以将目录做为参数调用 autoscan,如果不使用参数的化,则认为是当前目录。autoscan 将检查指定目录中的源文件,并创建 configure.scan 文件。在将 configure.scan 改名为 configure.in 文件前,需要手工改动它以进行调整。


使用 autoconf 创建 configure 脚本

不带任何参数的运行 autoconf。autoconf 将使用 m4 宏处理器和 autoconf 宏,来处理处理 configure.in 中的宏。


configure.in 中的宏:

    AC_INIT(在源代码中唯一的一个文件):configure 将检查该文件是否存在,并检查包含它的目录是否存在。

    AC_OUTPUT(文件):指定创建的输出文件。在 configure.in 文件中调用一次。文件名间用空格分开。比如:AC_OUTPUT(Makefile:templates/top.mk lib/Makefile:templates/lib.mk)

在 configure.in 中,有一些被 autoconf 宏预先定义的变量,重要的有如下几个:

    bindir:安装可执行文件的目录。

    includedir:C 头文件目录。

    infodir:info 页安装目录。

    mandir:安装手册页的目录。

    sbindir:为管理员运行该该程序提供的安装路径。

    srcdir:为 Makefile 提供的源代码路径。

    top_srcdir:源代码的最上层目录。

    LIBS:给连接程序的 -l 选项

    LDFLAGS:给连接程序的 stripping(-s)和其他一些选项。

    DEFS:给 C 编译器的 -D 选项。

    CFLAGS:给 C 编译器的 debug 和优化选项。当调用了 AC_PROG_CC 才有效。

    CPPFLAGS:头文件搜索路径(-I)和给 C 预处理器和编译器的其他选项。

    CXXFLAGS:给 C++ 编译器的 debug 和优化选项。当调用了 AC_PROG_CXX 才有效。

如果在同一个目录下编译多个程序的话,使用 AC_CONFIG_SUBDIRS 宏,它的语法是:

    AC_CONFIG_SUBDIRS(DIR....):

其他重要的宏:

    AC_PROG_CC:选择 C 编译器。如果在环境中不设置 CC 的话,则检测 gcc。

    AC_PROG_CXX:选择 C++ 编译器。

参考文献:

    Autoconf.htm
2.3 使用 automake
一般操作

    Automake 工作时,读取一个叫'Makefile.am'的文件,并生成一个'Makefile.in'文件。Makefile.am中定义的宏和目标,会指导automake生成指定的代码。例如,宏'bin_PROGRAMS'将导致编译和连接的目标被生成。

    Makefile.am中包含的目标和定义的宏被拷贝到生成的文件中去,这允许你添加任意代码到生成的Makefile.in文件中去。例如,使一个Automake发布中包含一个非标准的dvs-dist目标,Automake的维护者用它来从它的源码控制系统制作一个发布。

    请注意,GNU生成的扩展名不被Automake所识别,在一个'Makefile.am'中使用这样一个扩展名会导致错误。

    Automake试图以一种聪明的方式将相邻的目标(或变量定义)注释重组。

    通常,Makefile.am中定义的目标会覆盖任何由automake自动生成的有相似名字的这样的目标。尽管这是种被支持的属性,但最好避免这么做,因为有些时候,生成的规则很严格。

    类似的,Makefile.am中定义的变量会覆盖任何由automake自动生成的变量定义。这一特性经常要比目标定义的覆盖能力更常用。请注意,很多automake生成的变量只用于内部使用,在将来发布时他们的名字可能会变化。

    当测试一个变量定义时,Automake降递归的测试在定义中引用的变量。例如,如果Automake看到这段snippet程序中的'foo_SOURCES':

    xs = a.c b.c

    foo_SOURCES = c.c $(xs)

    它将使用文件:'a.c','b.c'和'c.c' 作为foo_SOURCES的内容.

    Automake 也允许不被拷贝到输出的注释形式,所有以'##'开头的行将被Automake 完全忽略.


深度

    Automake 支持三种目录层次:'flat', 'shallow', 'deep'.

    flat: 所有的文件都在一个目录中. 相应的Makefile.am中缺少SUBDIRS宏. termutils 是一个例子.

    deep: 所有的资源都在子目录中,指定曾目录主要包含配置信息.GNU cpio 是一个很好的例子.GNU tar.相应的最顶层Makefile.am中将包含一个SUBDIR宏,但没有其他的宏来定义要创建的对象.

    shallow: 主资源存在于最顶层目录,而不同的部分(典型的,库函数)在子目录中.Automake 就是这样的一个包.


严格性

    当Automake 被GNU包维护者使用时,它的确努力去适应,但不要试图使用所有的GNU惯例.

    目前,Automake 支持三种严格性标准:

    foreign:Automake 将只检查绝对必须的东西.

    gnu:Automake 将尽可能多的检查以适应GNU标准, 这是默认项.

    gnits:Automake 将进行检查,以适应“尚未成文”的Gnits标准。 他们基于GNU标准,但更详尽。除非您是Gnits标准的制定者。建议您最好避免这个选项,指导该标准正式发布。


统一命名规范

    Automake变量一般遵循一套统一的命名规范以很容易的决定如何创建和安装程序(和其他派生对象)。给规范还支持configure时动态决定创建规则。

    在make时,一些变量被用于决定那些对象要被创建。写变量叫做primary variables。例如,PROGRAM变量包括一个要被编译和连接的程序列表。

    另一个变量集用于决定被创建变量被安装到哪里。这些变量以相应的主变量命名,但加一个前缀,表示那些标准目录应被用作安装路径。这些标准目录的名称规定在GNU标准中。Automake用pkglibdir, pkgincludedir 和 pkgdatadir来展开这一列表。他们和没有pkg前缀的版本一样,只不过有‘@PACHAGE@’扩展,PKGLIBDIR被定义为 $(DATADIR)/@PACKAGE@.

    对每一个主变量,有一个EXTRA_前缀的变量。这个变量用于列出所有对象,至于哪些变量被创建,哪些变量不被创建则取决于configure。之所以需要这个变量,是因为Automake必须静态的指导要创建对象的完整列表以便生成一个‘Makefile。in’文件。

    例如,cpio 在configure时决定创建那些程序。一些程序被安装在bindir,一些被安装在sbindir:

    EXTRA_PROGRAMS = mt rmt

    bin_PROGRAMS = cpoi pax

    sbin_PRGRAMS = @PROGRAMS@

    定义没有前缀的主变量是错误的(如:PROGRAMS)。值得注意的是,“dir”在作为构成变量名时会被忽略。一次,我们写成bin_PROGRAMS 而不是bindir_PROGRAMS.

    不是每一种对象都得以安装在每个目录下。Automake 将标记那些他认为是错误的尝试,他也能够诊断一些明显的目录名拼写错误。

    有时标准目录--被Automake使用的--不过用。特别的,有时为了清晰,将对象安装在一些预定义的子目录,是很有用的。Automake允许你增加安装目录。如果以一个变量名(如,zar)加上dir的另一个变量(如,zardir)被定义了,那么他也是合法的。

    例如,如果HTML没支持Automake的一下部分,你就可以用他来安装HTML源文件:

    htmldir = $(prefix)/html

    html_DATA = automake.html

    “noinst”前缀专门指定有问题的对象不被安装。

    “check”前缀表示有问题的对象知道make check命令被执行猜被创建。

    可用的主变量是 'PROGRAMS','LIBRARIES','LISP','SCRIPTS','DATA','HEADERS','MANS'和'TEXINFOS' 导出变量是如何命名的

    有时一个Makefile变量名有一些用户支持的文本导出。例如程序名被重写进Makefile宏名称。Automake读取这些文本,所以他不必遵循命名规则。当生成后引用时名称中的字符除了字母,数字,下划线夺回被转换为下划线。例如,如果你的程序里有sniff-glue,则导出变量名将会是sniff_glue_SOURCES,而不是sniff-glue_SOURCES.


一些例子


一个完整简单的例子

    假设你写了一个名为zardoz的程序。

    第一步,更新你的configure.in文件以包含automake所需的命令。最简单的办法就是在AC_INIT后加一个AM_INIT_AUTOMAKE调用:

    AM_INIT_AUTOMAKE(zardoz, 1.0)

    如果你的程序没有任何复杂的因素。这是最简单的办法。

    现在,你必须重建‘configure’文件。这样做,你必须告诉autoconf如何找到你所用的新宏。最简单的方式是使用aclocal程序来 生成你的‘aclocal.m4’.aclocal让你将你的宏加进‘acincluide.m4’,所以你只需重命名并运行他


    mv aclocal.m4 acinclude.m4

    aclocal

    autoconf


    现在是为你的zardoz写Makefile.am的时候了。zardoz是一个用户程序,所以逆向将他安装在其他用户程序安装的目录。zardoz还有 一些Texinfo文档。你的configure.in脚本使用AC_REPLACE_FUNCS,所以你需要链接‘@LIBOBJS@’

    bin_PROGRAMS = zardoz

    zardoz_SOURCES = main.c head.c float.c vortex9.c gun.c

    zardoz_LDADD = @LIBOBJS@


    info_TEXINFOS = zardoz.texi


    现在你可以运行Automake以生成你的Makefile.in文件。

一个经典的程序

    hello 以其简单和多面幸而闻名。着一段将显示在Hello包Automake如何被使用。

    下面是

    dnl用 autoconf 处理它以产生一个 configure 脚本.

    AC_INIT(src/hello.c)

    AM_INIT_AUTOMAKE(hello, 1.3.11)

    AM_CONFIG_HEADER(config.h)


    dnl Set of available languages

    ALL_LINGUAS="de fr es ko nl no pl pt sl sv"

    dnl Checks for programs.

    AC_PROG_CC

    AC_ISC_POSIX

    dnl Checks for libraries.

    dnl Checks for header files.

    AC_STDC_HEADERS

    AC_HAVE_HEADERS(string.h fcntl.h sys/file.h sys/param.h)

    dnl Checks for library functions.

    AC_FUNC_ALLOCA

    dnl Check for st_blksize in struct stat

    AC_ST_BLKSIZE

    dnl internationalization macros

    AM_GNU_GETTEXT

    AC_OUTPUT([Makefile doc/Makefile intl/Makefile po/Makefile.in \ src/Makefile tests/Makefile tests/hello], [chmod +x tests/hello])

    'AM_'宏由Automake(或Gettext 库)提供;其余的是Autoconf标准宏。

    top-level ‘Makefile.am’:

    EXTRA_DIST = BUGS ChangeLog.O

    SUBDIRS = doc intl po src tests

    --如你所见,这里所有的工作时在子目录中真正完成的.

    --'po' 和 'intl'目录是用 gettextize自动生成的,这里不做进一步讨论.

    在'doc/Makefile.am'文件中我们看到:

    info_TEXINFOS = hello.texi

    hello_TEXINFOS = gpl.texi

    --这已足以创建,安装和发布手册.


    这里是'tests/Makefile.am'文件:

    TESTS = hello

    EXTRA_DIST = hello.in testdata

    --脚本'hello'被configure创建,并且是唯一的测试.make check将运行它.

    最后是,'src/Makefile.am',所有的真正的工作是在这里完成的:

    bin_PROGRAMS = hello

    hello_SOURCES = hello.c version.c getopt.c getopt1.c getopt.h system.h

    hello_LDADD = @INTLLIBS@ @ALLOCA@

    localedir = $(datadir)/locale

    INCLUDES = -I../intl -DLOCALEDIR=\"$(localedir)\"


创建一个'Makefile.in'文件

    要为一个包创建所有的'Makefile.in',在顶层目录运行automake不带参数的程序.automake将自动查找每个适当的'Makefile.am'文件,并声称相应的'Makefile.in'文件.请注意,automake会简要的察看一下包的构成;它假定一个包在顶层只有一个'configure.in'文件.如果你的包有多个'configure.in'文件,那么你必须在每一个含有'configure.in'文件的目录运行一次'automake'程序.

    你可以随意送给automake一个参数;'.am'会加到变量名的后面,并且作为输入文件的文件名.这一特性通常被用来自动重建一个'过时的''Makefile.in'文件.注意,automake必须在最顶级的目录运行,及时仅仅为了重新生成某个子目录中的'Makefile.in'文件.

automake接受以下可选参数:

    -a

    --add-missing

    在某些特殊情况下,Automake需要某些公共文件存在.例如,如果'configure.in'运行 AC_CANONICAL_HOST时,就需要'config.guess'.Automake需要几个这样的文件,这一选项会让automake自动的将一些缺失文件加进包中(如果可能的话).一般的,如果Automake告诉你某个文件不存在,你可以试一试这个选项.

    --amdir = dir

    在dir所制定的目录而不是安装目录下寻找Automake的数据文件,经常用于调试.

    --build-dir = dir

    告诉Automake创建目录在哪里.这一选项只用于将'dependencies'加进一个由make dist生成的'Makefile.in'文件中.

    --cygnus

    将使得所生成的'Makefile.in'文件遵循Cygnus规则,而不是GNU或Gnits规则.

    --foreign

    设置全局严格性为'gnits'.

    --gnu

    设置全局严格性为'gnu'.

    --help

    帮助

    -i

    --include-deps

    将所有自动创建时的依赖信息包括在'Makefile.in'中.通常在制作发行时用到.

    --generate-deps

    创建一个'.dep_segment'文件,它合并了所有的自动生成时的依赖信息,通常用于制作发行.这在维护'SMakefile'或其他平台上的'Makefile'(如Makefile.Dos)时非常有用.它只能与--include-deps, --srcdir-name和 --build-dir 联合使用.注意这一选项不作其他任何处理.

    --no-force

    一般的,automake创建在'configure.in'中提及的所有'Makefile.in'文件.这一选项将导致,automake只更新那些对于与自身相关的东西过了时的'Makefile.in'文件.

    -o dir

    --output-dir = dir

    将生成的'Makefile.in'放在指定的dir目录中.通常,'Makefile.in'放在与之相对应的'Makefile.am'所在目录中的.在制作发布时使用.

    --srcdir-name = dir

    告诉Automake与当前创建动作相关的源文件目录的名字.个选项仅被用于将自动创建时的依赖信息包括在'Makefile.in'中.

    -v

    --verbose

    时Automake打印出正在读取或创建的文件的信息.

    --version

    打印Automake的版本号.


扫描'configure.in'文件

    Automake扫描包的'configure.in'文件来决定某些关于包的信息.'configure.in'中必须定义一些变量并且需要一些autoconf 宏.Automake也会利用'configure.in'文件的信息来定制它的输出.

    Automake还支持一些autoconf宏以使维护更为简单.


配置需求

    满足Automake基本要求的最简单方法是使用'AM_INIT_AUTOMAKE'宏.但如果你愿意,你可以手工来做.


自动生成 aclocale.m4

    Automake包括很多Autoconf宏,其中有些在某些情况下游Automake使用,这些宏必须被定义在你的'aclocal.m4'中.否则,autoconf将看不到他们.

    acloal程序将根据'configure.in'自动生成'aclocal.m4'.这提供了一个方便的途径来得到Automake提供的宏.


Automake所支持的Autoconf宏

    AM_CONFIG_HEADER

    AM_CYGWIN32

    AM_FUNC_STRTOD

    AM_FUNC_ERROR_AT_LINE

    AM_FUNC_MKTIME

    AM_FUNC_OBSTACK

    AM_C_PROTOTYPES

    AM_HEADER_TOCGWINSZ_NEEDS_SYS_IOCTL

    AM_INIT_AUTOMAKE

    AM_PATH_LISPDIR

    AM_PROG_CC_STDC

    AM_PROG_INTALL

    AM_PROG_LEX

    AM_SANITY_CHECK

    AM_SYS_POSIX_TERMIOS

    AM_TYPE_PTRDIFF_T

    AM_WITH_DMALLOC

    AM_WITH_REGEX


编写你自己的aclocal宏

    Aclocal并没有特定的宏机制,因此你可以用你自己的宏来扩展它.这以特性经常被用以制作做那些想让自己的Autoconf宏被其他应用程序使用的库.例如,gettext库支持一个AM_GNU_GETTEXT宏,它可以被任何使用gettext库的包所使用.当该库被安装后,它会安装这个宏,这样,aclocal就能够找到他了.

    宏的名称应以'.m4'结尾,这样的文件将被安装在'$(datadir)/aclocal'中.


最顶层'Makefile.am'

    在non-flat包中,顶层'Makefile.am'必须告诉Automake哪些子目录将被创建.这是通过SUBDIRS变量定义的.

    SUBDIRS宏包含一个子目录列表,以规定各种创建的过程.'Makefile'中很多目标(如,all)将不止运行所在目录中,还要运行于所有指定的子目录中.注意,在SUBDIRS中列出的目录并不需要包含'Makefile.am'文件而只需要'Makefile'文件.这将允许包含位于不使用Automake的包(如,gettext)中的库.另外,SUBDIRS之中的目录必须是当前目录的直接子目录.比如,你不能在SUBDIRS中指定'src/subdir'.

    在deep型的包中,顶层'Makefile.am'文件通常非常短.例如,下面是HELLO发布中的'Makefile.am':


    EXTRA_DIST = BUGS ChangeLog.O README-alpha

    SUBDIRS = doc intl po src tests


    如果你只想创建一个包的子集,你可以覆盖SUBDIRS(就如同GNU inetutils的情形)在你的'Makefile.am'中包括:

    SUBDIRS = @SUBDIRS@

    让后在你的'configure.in'中你可以指定:


    SUBDIRS = "src doc lib po"

    AC_SUBST(SUBDIRS)


    这样做的结果是automake被欺骗了,它会在指定目录创建包,但并不真正绑定那个列表直到运行configure.


    SUBDIRS可以包含配置的替代(如,'@DIRS@');Automake 自己并不真正检测这一变量的内容.

    如果 SUBDIRS 被定义了,那么你的'configure.in' 就必须包含AC_PROG_MAKE_SET.

    SUBDIRS 的使用并不局限于顶层'Makefile.am'.Automake 可被用来构造任意深度的包.


参考文献

    Automake.htm


diff
diff

  diff是生成源码补丁的必备工具。其命令格式为:

 diff [命令行选项] 原始文件 新文件

常用命令行选项如下:

   -r 递归处理目录     -u 输出统一格式(unified format)

   -N patch里包含新文件   -a patch里可以包含二进制文件

  它的输出在stdout上,所以你可能需要把它重定向到一个文件。diff的输出有“传统格式”和“统一格式”之分,现在大都使用统一格式:

  传统格式示例:

   [hahalee@builder]$ diff a.txt b.txt

   1a2

   > here we insert a new line

   3d3

   < why not this third line?

  统一格式示例:

   [hahalee@builder]$ diff -u a.txt b.txt

   --- a.txt Thu Apr 6 15:58:34 2000

   +++ b.txt Thu Apr 6 15:57:53 2000

   @@ -1,3 +1,3 @@

   This is line one

   +here we insert a new line

   and this is line two

   -why not this third line?

  通过比较可以看出,传统格式的patch文件比较小,除了要删除/插入的行外没有冗余信息。统一格式则保存了上下文(缺省是上下各三行,最少需要两行),这样,patch的时候可以允许行号不精确匹配的情况出现。另外,在patch文件的开头明确地用---和+++标示出原始文件和当前文件,也方便阅读。要选用统一格式,用 u 开关。

  通常,我们需要对整个软件包做修改,并生成一个patch文件,下面是典型的操作过程。这里就要用到前面介绍的几个命令行开关了:

  tar xzvf software.tar.gz # 展开原始软件包,其目录为software

  cp _a software software-orig # 做个修改前的备份

  cd software

  [修改,测试……]

  cd ..

  diff _ruNa software-orig software > software-my.patch

  现在我们就可以保存software-my.patch做为这次修改的结果,至于原始软件包,可以不必保存。等到下次需要再修改的时候,可以用patch命令把这个补丁打进原始包,再继续工作。比如是在linux kernel 上做的工作,就不必每次保存几十兆修改后的源码了。这是好处之一,好处之二是维护方便,由于unified patch格式有一定的模糊匹配能力,能减少原软件包升级带来的维护工作量(见后)

patch

  patch命令跟diff配合使用,把生成的补丁应用到现有代码上。常用命令行选项:

  patch [命令行选项] [待patch的文件[patch]]

  -pn patch level(n是数字) -b[后缀] 生成备份,缺省是.orig

为了说明什么是patch level,这里看一个patch文件的头标记。

  diff -ruNa xc.orig/config/cf/Imake.cf xc.bsd/config/cf/Imake.cf

  --- xc.orig/config/cf/Imake.cf Fri Jul 30 12:45:47 1999

  +++ xc.new/config/cf/Imake.cf Fri Jan 21 13:48:44 2000

  这个patch如果直接应用,它会去找xc.orig/config/cf目录下的Imake.cf文件,假如你的源码树的根目录是缺省的xc而不是xc.orig,除了mv xc xc.orig之外,有无简单的方法应用此patch呢?patch level就是为此而设:patch会把目标路径名砍去开头patch level个节(由/分开的部分)。在本例中,可以用下述命令:cd xc; patch _p1 < /pathname/xxx.patch 完成操作。注意,由于没有指定patch文件,patch程序默认从stdin读入,所以用了输入重定向。

  如果patch成功,缺省是不建备份文件的(注:FreeBSD下的patch工具缺省是保存备份),如果你需要,可以加上 b 开关。这样把修改前的文件以“原文件名.orig”的名字做备份。如果你喜欢其它后缀名,也可以用“b 后缀”来指定。

  如果patch失败,patch会把成功的patch行给patch上,同时(无条件)生成备份文件和一个.rej文件。.rej文件里是没有成功提交的patch行,需要手工patch上去。这种情况在原码升级的时候有可能会发生。

  关于二进制文件的说明:binary文件可以原始方式存入patch文件。diff可以生成(加-a选项),patch也可以识别。如果觉得这样的patch文件太难看,解决方法之一是用uuencode处理该binary文件。


rcs
  单个文件的版本控制/管理,适合对少量文件进行版本控制,不适合小组进行项目协作开发。优点:使用简便;缺点:功能有限。RCS常用命令有ci/co/rcsdiff。

  rcs用一个后缀为“,v”的文件保存一文件的内容和所有修改的历史信息,你可以随时取出任意一个版本,用rcs保存程序就不必为不同版本分别备份。下面是一个“,v”文件的例子:

 (太长,忽略。请看演示或自己找一个样本)

  rcs文件里记载了每次更新的日期、作者、还有更新说明(Log)。文件的最新版本内容放在Log之后,再后面是历次版本与其后一版本的差别,按check in的时间做倒序排列。这么做的原因是因为新版本的check out机会大些,倒序排列可优化check out时间。

   ci _ check in,保存新版本

  此命令把指定文件添加到rcs历史文件中,同时把该文件删除。如果当前目录下有个RCS目录,ci会把历史文件存在此处,否则放在当前目录下。

   [hahalee@builder]$ mkdir RCS

   [hahalee@builder]$ ci wood.txt

   RCS/wood.txt,v <-- wood.txt

   enter description, terminated with single '.' or end of file:

   NOTE: This is NOT the log message!

   >> initial checkin #NOTE: 这里是给本次checkin做的说明

   >> .

   initial revision: 1.1

   done

   [hahalee@builder]$ ls -l RCS/

   总共 4

   -r--r--r-- 1 hahalee hahalee 451 Apr 7 07:27 wood.txt,v

  ci也有丰富的命令行选项,比如,可以指定check in的版本号,甚至可以用字符串来做版本号,请查阅ci的manpage。

   co _ check out,取出当前(或任意)版本

常用命令行选项:

  -r[rev] 指定版本的checkout -l[rev] 指定版本,加锁的checkout

  如不加可选的版本号,缺省是最近的版本。如果只需要一份只读的拷贝,用-r(特殊情况,如需要一份只读的当前拷贝,可以不要任何选项)。如需要对checkout的文件进行修改,请用-l选项。常见的操作流程是:

   ci xxx.c; co _l xxx.c; 编辑,测试; ci xxx.c …………

  在每次checkin的时候,版本号会自动在最低位上加1。为了在文件中反映版本控制信息,rcs提供了几个特殊的关键字,这里介绍$Id$和$Log$,其它的请参考info cvs。

  $Id$代表文件的版本标识,由文件名/版本号/最后一次checkin时间/最后一次checkin的用户这几项组成,比如:

$Id: wood.txt,v 1.3 2000/04/07 00:06:52 hahalee Exp $

如果需要更详细的信息,可以用$Log$,$Log$被扩展为该文件的所有修改日期和备注,例:

    /* $Log: wood.txt,v $

    * Revision 1.2 2000/04/07 00:29:12 hahalee

    * This is my second checkin

    *

    * Revision 1.1 2000/04/07 00:28:39 hahalee

    * Initial revision

    * /

  顺便介绍一下ident命令。它的功能比较简单,就是从文件中搜索出RCS标示符并打印出来。可以用ident /usr/sbin/sendmail 来看看。不用说,如果想在最终的binary文件里找到$Id$串,得要把它声明到一个字符串里去。很多程序里这么写:

    #ifndef lint //这里是为了避免lint报告“变量未使用”

    static const char rcsid[] =

   "$Id: bin/sh.c,v 1.15 1999/08/27 23:13:43 wp Exp $"; //这是从 $Id$ 扩展                                                                                                                                                  //出来的

    #endif

   rcsdiff _ 比较revision之间的差异.运行diff命令,生成patch文件

命令行格式:rcsdiff [选项] [-r版本[-r版本]] [diff选项] 文件名

  说明:如果没给出版本号,把上次checkin的内容同当前工作文件比较;如给出了一个版本号,就把那个版本的内容同当前工作文件比较;若给出了两个版本号,则用第一个来跟第二个比较。由于rcsdiff调用diff命令,所有的diff选项都可用。它的输出也是加了额外信息的diff格式内容,可以给patch使用。

  rcs里面还有rcs,rcsclean,rlog,merge,rcsmerge我们没有提到,有的特别简单有的特别繁琐且用得少。其中rcs命令可以用来对rcs文件进行各种精细的维护,最为复杂。


相关阅读 更多 +
排行榜 更多 +
摧毁大厦游戏

摧毁大厦游戏

飞行射击 下载
合并动物城手游版

合并动物城手游版

休闲益智 下载
哈士奇大冒险

哈士奇大冒险

休闲益智 下载