日志标签 Git
Gist数据嵌入博客
9月14日
下面嵌入的Ruby代码,来自 gist.github.com
访问 http://gotgit.github.com/gotgithub/ 阅读电子书《GotGitHub》。
版本库中一个大家都要改的文件,又不想每次提交而覆盖,怎么办?
6月10日
一个朋友打来电话,问:“使用Git做版本控制,版本库中一个大家都要改的文件,又不想每次提交而覆盖,怎么办?”
我的手机信号不好,没有听明白到底是什么文件让他的团队/客户如此纠结。我估计是某个IDE软件的项目文件,没有不行,但是IDE工作的时候,这个文件会经常随着本地项目的改动而变化,而且和每个人项目部署的目录相关,因此不同的人这个文件并不一致。我曾经还是一个Windows开发人员的时候,在 VisualStudio 6.0(maybe)中遇到。
我跟他说两个解决方案,一个比较诡异一点,一个比较普世一点。
《Git权威指南》官方网站上线
5月20日
《Git权威指南》已于6月底出版,各大书店和网上书店有售,具体参见官网相关链接。
官方网站地址:http://www.ossxp.com/doc/gotgit/
这个网站是用 Git 维护的,人人皆可参与的哦。
Repo 新增 hack:URL 自动 DotGit 后缀控制等
4月19日
在《Git权威指南》书中提到的 Repo 的 Hack 主要是增加了两条新的子命令,实现脱离 Gerrit 服务器直接向 Git 服务器提交。即:
- 子命令 repo config 用于在清单库(Manifest)设置配置变量。
例如设置 repo.pushurl 配置变量,以便在直接向服务器推送时使用该地址(实际上还要在该地址后面添加版本库名称和 .git 后缀)。 - 子命令 repo push 用于绕过 Gerrit 服务器,直接向 Git 服务器推送。
该命令要参考清单库的 repo.pushurl 配置变量。
最近的使用过程中,又发现有改进的必要,于是做了如下新的开发:
版本库URL自动DotGit后缀控制
发现 FreeMind 在 SourceForge 上的版本库地址不能在地址的后面出现 “.git” 后缀后,必须对 Repo 进行改造,否则无法使用 Repo 克隆不带 “.git” 后缀的 Git 版本库。
新增的 Hack 见 repo@github//ossxp-com上的 这个提交。改进后的 Repo 会读取清单库中 XML 文件的 remote 元素中的 autodotgit 属性,如果该属性设置为 “false” ,则不会在构建 URL 时添加 “.git” 后缀。
例如 freemind-manifest.git 版本库的 default.xml 文件就有这么一段:
<manifest>
<remote name="sf"
fetch="git://freemind.git.sourceforge.net/gitroot/freemind/"
autodotgit="false" />
...加粗显示的 autodotgit 属性可以确保使用该远程版本库服务器克隆版本库时不会自动在URL后添加 “.git” 后缀。
为每个远程版本库服务器设置单独的 pushurl 模板
之前在清单版本库添加一个 repo.pushurl 配置变量,于是就设置了一个全局的 PUSH URL 模板,在执行推送时(repo push),向该配置变量设置的 URL 后面添加版本库路径便形成版本库的地址。
但是之前的这个实现太粗放,如果一个清单文件中使用了多个 remote 元素,设定了不同的远程版本库服务器,一个通用的 PushURL 模板是不存在的。于是做了如下改进。
- 例如为名为 sf (SourceForge) 的远程版本库服务器设置推送地址模板,可以如下:
$ repo config repo.sf.pushurl \ ssh://git@freemind.git.sourceforge.net/gitroot/freemind/
- 为名为 github 的远程版本库服务器设置推送地址模板,如下设置:
$ repo cofnig repo.github.pushurl \ git@github.com:ossxp.com/
如果某个远程版本库服务器没有在清单库中设置 repo.<remote>.pushurl 变量,默认会使用 repo.pushurl 配置变量。
用 repo 管理 Freemind 代码补丁
4月8日
FreeMind 是我几乎每天都会用到的软件,虽说脑图软件不少,但 FreeMind 的文件是纯文本、可版本控制,所以一直是我的最爱。当然为了能更好的进行版本控制,还需要做些改进,就是我在 SourceForge 上建立的 FreeMind-MMX 项目。
最近发现 FreeMind 的代码库由 CVS 迁移到了 Git,这下访问官方代码库可方便多了。但是转换的并非尽善尽美,参见我新浪微博的评论。
之前把我的改进代码连同 FreeMind 代码一并放在公司的代码库中(用Topgit特性分支),如果迁移到新的 FreeMInd 代码库,再放到 Github 上,不知道又要占用多少宝贵的 Github 托管空间。灵机一动,为什么不用 repo —— 由 Andorid 项目引入的多 Git 版本库管理工具?
使用 repo 之后,我在 Github上Freemind 相关版本库占用甚至不到1M!
- 官方版本库地址: git://freemind.git.sourceforge.net/gitroot/freemind/freemind
注意不能有 “.git” 后缀,如果添加后缀则无法克隆。 - Github 上 FreeMind-MMX 的 Manifest 库的网址: https://github.com/ossxp-com/freemind-manifest
- Github 上 FreeMind-MMX 的 代码补丁: https://github.com/ossxp-com/freemind-hacks
自己动手编译改进后的 FreeMind,即 FreeMind-MMX 的方法:
- 使用我改进的 repo,原因见微博上留言。
$ mkdir workspace $ cd workspace $ sudo curl -L -k http://github.com/ossxp-com/repo/raw/master/repo \ > /usr/local/bin/repo $ sudo chmod a+x /usr/local/bin/repo - 使用 Github 上的 FreeMind Manifest 库进行初始化。
$ repo init -u git://github.com/ossxp-com/freemind-manifest.git
- 同步版本库,包括 SourceForge 上的 FreeMind 和 Github 上的 freemind-hacks。
这一步骤时间可能会很长,因为 SourceForge 上 FreeMind 代码库太大(50M)。$ repo sync
- 完成同步后,在当前目录下有一个 build.sh 脚本,执行它完成改进版本 Freemind 的编译和打包。
$ sh build.sh
- 打包后的文件在 post 目录下。如果在 Mac OS X 上打包,还会生成 .dmg 扩展名的软件包。
参考阅读: 《Repo 新增 hack:URL 自动 DotGit 后缀控制等》
Topgit 安装
3月10日
Topgit 用 shell 脚本语言开发,可以安装在所有类Unix环境中,例如 Linux、Mac OS X[1] ,以及Windows下的Cygwin、msysGit等。下面的官方网站链接介绍了Topgit的安装和使用方法:
- http://repo.or.cz/w/topgit.git?a=blob;f=README 。
1. Linux下安装Topgit
安装官方的 Topgit 版本,直接克隆官方的版本库,执行 make 即可:
$ git clone git://repo.or.cz/topgit.git $ cd topgit $ make $ make install
默认会把可执行文件 tg 安装在 $HOME/bin (用户主目录下的 bin 目录)下,如果没有将 ~/bin 加入环境变量 $PATH 中,可能无法执行 tg。
如果具有 root 权限,也可以在编译和安装时向make命令传递prefix环境变量,将 tg 安装在系统目录中。
$ make prefix=/usr $ sudo make prefix=/usr install
我对 Topgit 做了一些增强和改进,在后面的章节将予以介绍。如果想安装改进的版本,需要预先安装 quilt 补丁管理工具,然后进行如下操作。
$ git clone git://github.com/ossxp-com/topgit.git $ cd topgit $ QUILT_PATCHES=debian/patches quilt push -a $ make prefix=/usr $ sudo make prefix=/usr install
如果用的是 Ubuntu 或 Debian Linux 操作系统,还可以这么安装。
(1) 先安装 Debian/Ubuntu 打包依赖的相关工具软件。
$ sudo aptitude install quilt debhelper \ build-essential fakeroot dpkg-dev
(2) 再调用 dpkg-buildpackage 命令,编译出 DEB 包,再安装。
$ git clone git://github.com/ossxp-com/topgit.git $ cd topgit $ dpkg-buildpackage -b -rfakeroot $ sudo dpkg -i ../topgit_*.deb
(3) 安装完毕后,重新加载命令行补齐,可以更方便地使用 tg 命令。
$ . /etc/bash_completion
2. Mac OS X 下安装Topgit
在Mac OS X下安装官方版本的Topgit,在使用中会遇到问题。这是因为Mac OS X下部分shell命令的行为和相应的GNU命令的行为不一致,例如echo、paste和sed命令等。
在Mac OS X下可以使用Homebrew安装所需的GNU工具。如下:
$ brew install gnu-sed $ brew install coreutils $ brew install quilt
然后别忘了安装改造后的Topgit。
$ git clone git://github.com/ossxp-com/topgit.git $ cd topgit $ QUILT_PATCHES=debian/patches quilt push -a $ make prefix=/usr $ sudo make prefix=/usr install
3. Windows下安装Topgit
Windows下的msysGit因为缺乏Topgit依赖的命令行工具,因此很难在msysGit下运行Topgit。
Windows下的msysGit因为缺乏Topgit依赖的命令行工具(如:fgrep, install, make, mkfifo, mktemp, tsort 等),安装和运行Topgit会遇到困难。从安装好的 MSYS[2] 或 MSYS-CN[3]中可以提取所需软件到 msysGit 环境,实现Topgit在msysGit中的安装和运行。
Windows下的Cygwin拥有一个完整的POSIX环境,当安装了所需的工具(quilt 、make等)后,就可以正常的编译和使用Topgit。但是如果克隆的Topgit版本库的工作区文件的换行符是DOS格式换行符(CRLF),在安装过程中会遇到麻烦。从下面地址克隆的Topgit版本库,因为工作区根目录下存在一个.gitattributes[4] 文件,可以保证检出的工作区文件采用Unix格式的换行符(LF)。具体的安装方法同前。
[1] MsysGit的shell环境因缺乏Topgit需要用到的部分命令和编译工具不能安装和运行Topgit。
[1] Mac OS X及BSD中安装的sed命令和Topgit不兼容,需要安装 GNU sed,并使用改造后的Topgit。
[2] http://www.mingw.org/wiki/msys
[3] http://code.google.com/p/msys-cn/
[4] 参见第8篇第40章“40.3 换行符问题”
《GotGit》附录D Git 和 Hg 面对面
3月10日
附录D Git 和 Hg 面对面
D.1 面对面访谈录
Git:你好 Hg,我发现我们真的很像。
Hg:是啊,人们把我们都归类为分布式版本控制工具,所以我们之间的相似度,要比和 CVS、SVN 的相似度高得多了。
Hg:我是用 Python 和少部分的 C 语言实现的,你呢?
Git:我的核心当然是使用 C 语言了,因为 Linus Torvalds 最爱用 C 语言了。我的很多命令还使用了 Shell 脚本和 Perl 语言开发,Python 用的很少。
Hg:大量的使用 C 语言,是你的性能比我高的原因么?
Git:当然不是了,你不也在核心模块使用 C 语言了么?问题的关键在于我的对象库设计的非常优秀。你不要忘了我是谁发明的,可是大名鼎鼎的 Linux 之父 Linus Tolvars,他对 Linux 文件系统可是再熟悉不过的了,所以他能够以文件系统开发者的视角实现我的核心。
Git:还有我的网络传输过程非常直观,可以显示实时的进度,好像我从你那里没有看到。之所以我能够有这样的实现,是因为我使用了“智能协议”。在网络传输的两端都启用了相应的辅助程序,实现差异传输及传输进度的计算和显示。
Hg:是啊,非常的惭愧。当克隆一个比较大的 Hg 版本库时,会出现假死状态,用户不知道克隆操作的进展。(感谢来自台湾的 Willie Wu,指出我的错误)
Hg:实际上我也支持进度显示,不过是通过Progress插件实现的,需要通过修改配置文件启用该插件。
Hg:我有一个特点是 SVN 用户非常喜欢的,就是我的顺序数字版本号。
Git:你的顺序数字版本号只在本地版本库中有效。也就是说,你不能像 SVN 那样将顺序数字版本号作为项目本身的版本号,因为换成另外一个版本库的克隆,那个数字版本号就会不一样了。
Hg:我觉得你的暂存区(stage)的概念太古怪了。我提交的时候,改动的文件会直接提交而不需要什么注册到暂存区的操作。
Git:让读者来作评判吧。如果读者读过本书的第2篇,一定会说 Git 的暂存区帅呆了。
Hg:我只允许用户对最近的一次提交进行回滚撤销,而你(Git)怎么能允许用户撤销任意多次历史提交呢?那样安全么?
Git:这就是的我对象库和引用设计的强大之处,我可以使用 git reset 命令将工作分支进行任意的重置,丢弃任意多的历史。至于安全性,我的重置命令有一个保险,就是 reflog ,我随时可以参照 reflog 的记录来弥补错误的重置。
Hg:我们的 revert 命令好像不同?
Git:你 Hg 的 hg revert 命令和 SVN 的 svn revert 命令相似,是取消本地修改,用原始拷贝覆盖。你的这个操作在我这里是用 git checkout 命令实现的。我也有一个 git revert 命令,但是这个命令是针对某个历史提交进行反向操作,以取消该历史提交的改动的。
Hg:我执行日志查看能够看到文本显示的分支图,你呢?
Git:我需要在日志显示时添加参数,即用命令 git log –graph 。我支持通过建立别名实现简洁的调用,例如建立一个名为 glog 的别名。
Git:我听说你 Hg 不支持分支?
Hg:坦白的说,是的。我虽然也有分支命令,但是分支不是一个独立显示的提交空间,而是各个分支都显示在一起,相当于在版本库中同时拥有多个头,选择哪个分支就相当于把帽子戴在哪个头上面而已。所以我尽量要求我的用户使用克隆来当做分支。(感谢来自台湾的 Willie Wu,指出我的错误)
Hg:你说的是昨天的我,现在有了Bookmarks插件 ,我也拥有和你类似的分支实现。不过传统来讲我还是以克隆来实现分支的。
Git:实际上我的每一个克隆的版本库也相当于独立的分支,但是因为我有强大的分支功能,因此很多用户还没有意识到。使用 Topgit 的用户就应该使用版本库克隆作为 Topgit 本身的分支管理。
Git:还有,因为我对分支的完整支持,使得我可以和 SVN 很好的协同工作。我可以将整个 SVN 转换为本地的 Git 库,但是你 Hg,显然只能每次转换一个分支。
Hg:是的,我要向你多学习。
D.2 Hg 和 Git 命令对照
《GotGit》附录C Git 和 SVN 面对面
3月10日
附录C Git 和 SVN 面对面
C.1 面对面访谈录
Git:我的提交历史本身就是一幅美丽的图画 —— DAG(Directed Acylic Graph, 有向非环图),可以看到各个分支之间的合并关系。而你 SVN,你的提交历史怎么是一条直线呢?要是在重症监护室看到你,还以为你挂掉了呢?
SVN:我觉得挺好,至少我每次提交会有一个全局的版本号,而且我的版本号是递增的。你的版本号不是递增的吧!
Git:你说的对,我的版本号不是一个简单递增的数字,而是一个长达40位的十六进制数字(哈希值),但是可以使用短格式,只要不 冲突。虽然我的提交编号看起来似乎是无序的,但实际上我每一个提交都记录了父提交甚至是双亲或多亲提交,因此可以很容易的从任意一个提交开始建立一条指向 历史提交的跟踪链。
SVN:是啊,我的一个提交和前一个提交有时根本没有关系,例如一个提交是发生在主线/trunk 中的,下一个提交可能就发生在/branches/1.3.x 分支中。你要知道要想画出一个像你那样的分支图,我要做多少工作么?我不容易呀。
Git:我一直很奇怪,你的分支和里程碑怎么看起来和目录一样?我的分支和里程碑名字虽然看起来像是目录,实际上和工作区的目录完全没有关系,只是对提交ID的一个记号而已。
SVN:我一开始觉得我用轻量级拷贝的方式实现分支和里程碑会很酷,也很快。但是我发现很多人在使用我的时候,直接在版本库的根目录下创建文件而不是把文件创建在/trunk 目录下,这就导致这些人无法再创建分支和里程碑了,因为是无法将根目录拷贝到子目录的呀!
Git:那么你是如何对分支合并进行跟踪的呢?我因为有了 DAG 的提交关系图,是很容易看出来分支之间的合并历史,但是你是怎么做到的呢?
SVN:我用了一点小技巧,就是通过属性(svn:mergeinfo)记录了合并的分支名和版本范围,这样再合并的时候,我会根据相关属性确定是否要合并。但是如果经常在子目录下合并,有太多的svn:mergeinfo 属性等待我检查,我会很困扰。还有我的这个功能是在 1.5 以后版本才提供的,因此老版本会破坏这个机制。
SVN:对了,我的属性能干很多事哦,我甚至可以把我的照片作为属性附加在文件上。
Git:这点我承认,你的属性非常强大。其实我也支持属性,只不过实现方式不同罢了。而且我可以通过评注的方式为任意对象(提交、文件、里程碑等)添加评注,也可以实现把照片做为评注附加在文件上,可是这个功能有什么实际用处么?
SVN:我有轻量级拷贝,而我的分支和里程碑就是通过拷贝实现的,很强大哦。
Git:我根本就不需要轻量级拷贝,因为我对文件的保存是和文件路径无关的,我只关心内容。所以相同内容的文件无论它们的文件名相差有多大,在我这里只保存一份。而你 SVN,如果用户忘了用轻量级拷贝,版本库是不是负担很重啊。
SVN:听说你不能针对目录授权,这可是我的强项,所以公司无论大小都在用我作为版本控制系统。
Git:不要说你的授权了,简直是一团糟。虽然这本书的作者为你写了一个图形化的授权管理工具 (http://www.ossxp.com/doc/pysvnmanager/user-guide/user-guide.html)会有所改善, 但是你糟糕的分支和里程碑的实现,会导致授权在新的分支和里程碑中要一一设置,工作量其大无比。虽然泛路径授权是一个解决方案,但是官方并没有提供啊。
Git:说说我的授权吧。如果你认真的读过本书服务器架设的相关章节,你会为我能够提供的按照分支,以及按照路径进行写操作授权而 击掌叫好的。当然我的读操作授权还不能做到很精细,但是可以将版本库拆分成若干小的版本库啊,再用参照本书介绍的各种多版本库协同模式,会找到一个适合的 解决方案的啊。
Git:我的工作区很干净。只在工作区的根目录下有一个 .git 目录,此外再无其他。
SVN:我要在工作区的每一个目录下都放置一个.svn 目录,这个目录在 Linux 下可是隐藏的哦。这个目录下不但有跟踪工作区文件状态的跟踪文件,而且还有每一个文件的原始拷贝呢。这样有的操作就可以脱离网络执行了,例如:差异比较,工作区文件的回滚。
Git:嗯,你要是像我一样再保存多一点内容(整个版本库)就更好了。像你这样在每个工作区子目录下都有一个 .svn 目录,而且每个 .svn 目录下都有文件原始拷贝,在进行内容搜索的时候会搜索出来两份吧,太干扰了。而且你这么做和 CVS 一样有安全风险,造成本地文件名的信息泄漏,千万不要在 Web 服务器上用 SVN 检出哦。
Git:我的操作可以不需要网络。因为我在本地拥有完整的版本库,几乎所有操作都是在本地完成。
SVN:正如前面说到的,我有部分命令可以不需要网络,但是其他绝大多数命令还是要依赖网络的。
CVS:你怎么没有更新(update)命令?还有你为什么老是要执行检出命令(checkout)?对我而言,检出命令只在工作区创建时一次完成的。
Git:你的这个问题怎么和 CVS 问的一样。你的更新(update)命令执行的很慢对么?首先你要用检出命令(checkout)建立工作区,然后你要经常的执行更新(update)命令进行更新,否则容易造成你的更改和他人更改发生冲突。
Git:之所以你需要更新是因为你的版本库在远程啊。别忘了我的版本库是在本地,我的每一步操作工作区和版本库都是同步的,所以更 新操作就没有存在的必要了。而我的检出(checkout)操作一般是用户切换分支,或者从本地版本库检出丢失的文件或覆盖本地错误改动的文件时用到。如 果我没记错的话,你切换分支用的是 svn switch 命令对么?
Git:实际上我也有一个比较耗时的网络操作命令叫做 git fetch 或 git pull ,这两个操作是从远程版本库获取他人改动。一般使用我(Git)做团队协作的时候,会部署一个集中共享的版本库,我就从这个共享的版本库执行拉回操作。也 也许你(SVN)会觉得 git fetch 或 git pull 和你的 svn update 命令更像吧。至于你的检出命令(svn checkout),实际上和我克隆命令(git clone)很相似,只不过我的克隆命令不但创建了本地工作区,而且在本地还复制了和远程版本库一样的本地版本库。
SVN:为什么你的检入命令(commit)命令执行的那么快?
Git:是的,我的检入命令飞一般就执行完了,也是因为版本库就在本地。也许你(SVN)会觉得我的推送命令(git push)和你的检入命令(svn commit)更相像,其实这是一个误会。如果我不做本地提交,是不能通过推送命令(git push)将我的本地的提交共享给(推送给)其他版本库的。你(SVN)每一次提交都要和版本库进行网络通讯,而我可以在本地版本库进行多次提交,直到我 的主人想喝咖啡了才执行一次 git push,将我本地版本库中新的提交推送给远程版本库。
SVN:我能一次检出一个目录,你好像不能吧?
Git:所以我有子模组,以及 repo 等第三方工具,可以帮助我把一个大的版本库拆开多个版本库组合来使用啊。
SVN:我能添加空目录,你好像不能吧!
Git:是的,我现在还不能记录空目录,但是用户往往在空目录下创建一个隐含文件,并将该隐含文件添加到版本库中,也就实现了空目录添加的功能。
C.2 SVN 和 Git 命令对照
《GotGit》附录B Git 与 CVS 面对面
3月10日
附录B Git 与 CVS 面对面
B.1 面对面访谈录
Git:我的提交是原子提交。每次提交都对应于一个目录树(树对象)。因为我的提交ID是对目录树及相关的提交信息建立的一个SHA1哈希值,所以可以保证数据的完整性。
CVS:我承认这是我的软肋,一次错误或冲突的提交会导致部分数据被提交,而部分数据没有提交,版本库完整性被破坏,所以人们才设计出来 Subversion(SVN) 来取代我。
Git:我的分支和里程碑管理非常快捷。因为我的分支和里程碑就是一个记录提交ID的引用,你的呢?
CVS:你怎么又提到别人的痛处了!我的分支和里程碑创建速度还是很快的,…嗯… , 如果在版本库中只有几个文件的话。当然如果版本库的文件的很多,创建分支、里程碑创建就需要花费更多的时间。有些人对此忍无可忍,于是设计出 SVN 来取代我。
Git:其实我不用里程碑都没有关系,因为每一个提交ID就对应于唯一的一个提交状态。
CVS:这也是我做不到的。我没有全局版本号的概念,每一个文件都通过单独的版本号记录其变更历史,所以人们在使用我的时候必须经常地用里程碑 (tag)对我的状态进行标识。还需要提醒一句,如果版本库中文件太多,创建里程碑是很耗时的,因为要一一打开每一个版本库中的文件,在其中记录里程碑和 文件版本的关系。
Git:我的工作区很干净。只在工作区的根目录下有一个 .git 目录,此外再无其他辅助目录或文件。
CVS:我要在工作区的每一个目录下都放置一个 CVS 目录,这个目录下有个Entries 文件很重要,记录了对应工作区文件的检出版本以及时间戳等信息。这样做的好处是可以将工作区移动到任何其他磁盘和目录,依然可以使用,甚至我可以将工作区的一个子目录拿出来,作为独立的工作区。
Git:我也可以将工作区移动到其他磁盘,但是要保证工作区下的 .git 目录和工作区一同移动。也不可以只移动工作区下的一个目录到其他磁盘或目录,那样的话移出的目录就不能工作了。
Git:我的网络传输效率很高。在和其他版本库交互时,对方会告诉我他有什么,我也知道我有什么,因为只对缺失对象的打包传输,所以效率很高而且能够显示传输进度。
CVS:这一点我不行。因为我本地没有文件做对照,所以我在传输的时候不可能做到增量传输。
Git:我甚至可以不需要网络,因为我在本地拥有完整的版本库,几乎所有操作都是在本地完成。
CVS:我的操作处处需要网络,如果版本库是在网络中其他服务器上的话。如果网速比较慢,查看日志、查看历史版本都需要花费很长时间等待。
CVS:你怎么没有更新(update)命令?还有你为什么老是要执行检出命令(checkout)?对我而言,检出命令只在工作区创建时一次完成的。
Git:你的检出命令(checkout)是从远程版本库服务器获取数据完成本地工作区的创建,版本库仍然位于远程的服务器上。你 的更新(update)命令执行的很慢对么?之所以你需要执行更新命令是因为你的版本库在远程啊。别忘了我的版本库是在本地,我的每一步操作工作区和版本 库都是同步的,所以更新操作就没有存在的必要了。而我的检出(checkout)操作是将本地版本库的数据检出到本地工作区,用于恢复本地丢失的文件或错 误改动的文件,也用于切换不同的分支。我也有一个和你的更新(update)操作类似的比较耗时的网络操作命令叫做 git fetch 或 git pull,这两个操作是从别人的版本库获取他人改动。一般使用我(Git)做团队协作的时候,会部署一个集中共享的版本库,我就用这两个命令(git fetch 或 git pull)从共享的版本库执行拉回操作。也也许你(CVS)会觉得 git fetch 或者 git pull 和你的 cvs update 命令更像吧。至于你的检出命令(cvs checkout),实际上和我克隆命令(git clone)很相似,只不过我的克隆命令不但创建了本地工作区,而且在本地还复制了和远程版本库一样的本地版本库。
CVS:为什么你的检入命令(commit)命令执行的那么快?
Git:是的,我的检入命令飞一般就执行完了,也是因为版本库就在本地。也许你(CVS)会觉得我的推送命令(git push)和你的检入命令(cvs commit)更相像,其实这是一个误会。如果我不做本地提交,是不能通过推送命令(git push)将我的本地的提交共享给(推送给)其他版本库的。你(CVS)每一次提交都要和版本库进行网络通讯,而我可以在本地版本库进行多次提交,直到我 的主人想喝咖啡了才执行一次 git push,将我本地版本库中新的提交推送给远程版本库。
CVS:我每一个文件都一个独立的版本号,你有么?
Git:每一个文件一个版本号?这有什么值得夸耀的?我听说你最早是用脚本对 RCS 系统进行封装实现的,所以你每个文件都有一个独立的版本控制,这让你变得很零碎。我听说某些商业版本控制系统也是这样,真糟糕。我的每一次提交都有一个全 球唯一的版本号,这样不但是在本地版本库中是唯一的,和其他人的版本库也不会有冲突。
CVS:我能一次检出一个目录,你好像不能吧?
Git:所以我有子模组,以及 repo 等第三方工具,可以帮助我把一个大的版本库拆开多个版本库组合来使用啊。
CVS:我能添加空目录,你好像不能吧!
Git:是的,我现在还不能记录空目录。但是用户可以在空目录下创建一个隐含文件,并将该隐含文件添加到版本库中,也就实现了空目录添加的功能。你,CVS,目录管理是你的软肋,你很难实现目录的重命名,而目录重命名对我来说是小菜一碟。
B.2 CVS 和 Git 命令对照
《GotGit》附录A Git 命令索引
3月10日
附录A. Git 命令索引
每一个 Git 子命令都和特定目录下的一个名为git-<cmd> 的文件相对应,也就是在这个特定目录下存在的名为git-<cmd> 的可执行文件(有几个脚本文件被其他脚本包含提供相应的函数库,不能单独运行。如git-sh-setup )可以用命令git <cmd> 执行。这个特定的目录的位置可以用下面的命令查看:
$ git --exec-path /usr/lib/git-core/
在这个目录下有150多个可执行文件,也就是说 Git 有非常多的子命令。在如此众多的子命令中,实际上常用的只有三分之一不到,其余的命令或者做为底层命令供其他命令及脚本调用,或者用于某些生僻场合,或者 已经过时但出于兼容性的考虑而仍然健在。下面的表格分门别类的对所有Git命令做一概要性介绍,凡是在本书出现过的命令标以章节号和页码。

最新评论