Git与CVS面对面 ********************* 面对面访谈录 ============ **Git:我的提交是原子提交。每次提交都对应于一个目录树(树对象)。因为我\ 的提交ID是对目录树及相关的提交信息建立的一个SHA1哈希值,所以可以保证数据\ 的完整性。** CVS:我承认这是我的软肋,一次错误或冲突的提交会导致部分数据被提交,而部\ 分数据没有提交,版本库完整性被破坏,所以人们才设计出来Subversion(SVN)\ 来取代我。 **Git:我的分支和里程碑管理非常快捷。因为我的分支和里程碑就是一个记录提\ 交ID的引用,你的呢?** CVS:你怎么又提到别人的痛处了!我的分支和里程碑创建速度还是很快的,...嗯\ ...,如果在版本库中只有几个文件的话。当然如果版本库的文件的很多,创建分\ 支、里程碑创建就需要花费更多的时间。有些人对此忍无可忍,于是设计出SVN来\ 取代我。 **Git:其实我不用里程碑都没有关系,因为每一个提交ID就对应于唯一的一个提\ 交状态。** CVS:这也是我做不到的。我没有全局版本号的概念,每一个文件都通过单独的版\ 本号记录其变更历史,所以人们在使用我的时候必须经常地用里程碑(tag)对我\ 的状态进行标识。还需要提醒一句,如果版本库中文件太多,创建里程碑是很耗时\ 的,因为要一一打开每一个版本库中的文件,在其中记录里程碑和文件版本的关系。 **Git:我的工作区很干净。只在工作区的根目录下有一个\ :file:`.git`\ 目录,\ 此外再无其他辅助目录或文件。** CVS:我要在工作区的每一个目录下都放置一个CVS目录,这个目录下有个\ :file:`Entries`\ 文件很重要,记录了对应工作区文件的检出版本以及时间戳等\ 信息。这样做的好处是可以将工作区移动到任何其他磁盘和目录,依然可以使用,\ 甚至我可以将工作区的一个子目录拿出来,作为独立的工作区。 **Git:我也可以将工作区移动到其他磁盘,但是要保证工作区下的\ :file:`.git`\ 目录和工作区一同移动。也不可以只移动工作区下的一个目录到其他磁盘或目录,\ 那样的话移出的目录就不能工作了。** **Git:我的网络传输效率很高。在和其他版本库交互时,对方会告诉我他有什么,\ 我也知道我有什么,因为只对缺失对象的打包传输,所以效率很高而且能够显示\ 传输进度。** CVS:这一点我不行。因为我本地没有文件做对照,所以我在传输的时候不可能做\ 到增量传输。 **Git:我甚至可以不需要网络,因为我在本地拥有完整的版本库,几乎所有操作\ 都是在本地完成。** CVS:我的操作处处需要网络,如果版本库是在网络中其他服务器上的话。如果网\ 速比较慢,查看日志、查看历史版本都需要花费很长时间等待。 CVS:你怎么没有更新(update)命令?还有你为什么老是要执行检出命令\ (checkout)?对我而言,检出命令只在工作区创建时一次完成的。 **Git:你的检出命令(checkout)是从远程版本库服务器获取数据完成本地工作\ 区的创建,版本库仍然位于远程的服务器上。你的更新(update)命令执行的很慢\ 对么?之所以你需要执行更新命令是因为你的版本库在远程啊。别忘了我的版本库\ 是在本地,我的每一步操作工作区和版本库都是同步的,所以更新操作就没有存在\ 的必要了。而我的检出(checkout)操作是将本地版本库的数据检出到本地工作区,\ 用于恢复本地丢失的文件或错误改动的文件,也用于切换不同的分支。我也有一\ 个和你的更新(update)操作类似的比较耗时的网络操作命令叫做\ :command:`git fetch`\ 或\ :command:`git pull`\ ,这两个操作是从别人的\ 版本库获取他人改动。一般使用我(Git)做团队协作的时候,会部署一个集中共享\ 的版本库,我就用这两个命令(\ :command:`git fetch`\ 或\ :command:`git pull`\ )\ 从共享的版本库执行拉回操作。也也许你(CVS)会觉得\ :command:`git fetch`\ 或者\ :command:`git pull`\ 和你的\ :command:`cvs update`\ 命令更像吧。至于\ 你的检出命令(\ :command:`cvs checkout`\ ),实际上和我克隆命令\ (\ :command:`git clone`\ )很相似,只不过我的克隆命令不但创建了本地工作区,\ 而且在本地还复制了和远程版本库一样的本地版本库。** CVS:为什么你的检入命令(commit)命令执行的那么快? **Git:是的,我的检入命令飞一般就执行完了,也是因为版本库就在本地。也许\ 你(CVS)会觉得我的推送命令(\ :command:`git push`\ )和你的检入命令\ (\ :command:`cvs commit`\ )更相像,其实这是一个误会。如果我不做本地提交,\ 是不能通过推送命令(\ :command:`git push`\ )将我的本地的提交共享给\ (推送给)其他版本库的。你(CVS)每一次提交都要和版本库进行网络通讯,\ 而我可以在本地版本库进行多次提交,直到我的主人想喝咖啡了才执行一次\ :command:`git push`\ ,将我本地版本库中新的提交推送给远程版本库。** CVS:我每一个文件都一个独立的版本号,你有么? **Git:每一个文件一个版本号?这有什么值得夸耀的?我听说你最早是用脚本对\ RCS系统进行封装实现的,所以你每个文件都有一个独立的版本控制,这让你变得\ 很零碎。我听说某些商业版本控制系统也是这样,真糟糕。我的每一次提交都有一个\ 全球唯一的版本号,这样不但是在本地版本库中是唯一的,和其他人的版本库也不\ 会有冲突。** CVS:我能一次检出一个目录,你好像不能吧? **Git:所以我有子模组,以及repo等第三方工具,可以帮助我把一个大的版本库\ 拆开多个版本库组合来使用啊。** CVS:我能添加空目录,你好像不能吧! **Git:是的,我现在还不能记录空目录。但是用户可以在空目录下创建一个隐含\ 文件,并将该隐含文件添加到版本库中,也就实现了空目录添加的功能。你,CVS,\ 目录管理是你的软肋,你很难实现目录的重命名,而目录重命名对我来说是小菜\ 一碟。** CVS和Git命令对照 ==================== +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 比较项目 | CVS命令 |Git命令 | +=======================+================================================+============================================================+ | URL | :pserver:user@host:/path/to/cvsroot | git://host/path/to/repos.git | | +------------------------------------------------+------------------------------------------------------------+ | | /path/to/cvsroot | ssh://user@host/path/to/repos.git | | +------------------------------------------------+------------------------------------------------------------+ | | | user@host:path/to/repos.git | | +------------------------------------------------+------------------------------------------------------------+ | | | file:///path/to/repos.git | | +------------------------------------------------+------------------------------------------------------------+ | | | /path/to/repos.git | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 版本库初始化 | cvs -d init | git init [--bare] | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 导入数据 | cvs -d import -m ... | git clone; git add .; git commit | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 版本库检出 | cvs -d checkout [-d ] | git clone | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 版本库分支检出 | cvs -d checkout -r | git clone -b | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 工作区更新 | cvs update | git pull | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 更新至历史版本 | cvs update -r | git checkout | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 更新到指定日期 | cvs update -D | git checkout HEAD@'{}' | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 更新至最新提交 | cvs update -A | git checkout master | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 切换至里程碑 | cvs update -r | git checkout | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 切换至分支 | cvs update -r | git checkout | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 还原文件/强制覆盖 | cvs up -C | git checkout -- | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 添加文件 | cvs add | git add | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 添加文件(二进制) | cvs add -kb | git add | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 删除文件 | cvs remove -f | git rm | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 移动文件 | mv ; cvs rm ; cvs add | git mv | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 反删除文件 | cvs add | git add | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 工作区差异比较 | cvs diff -u | git diff | | | +------------------------------------------------------------+ | | | git diff --cached | | | +------------------------------------------------------------+ | | | git diff HEAD | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 版本间差异比较 | cvs diff -u -r -r | git diff -- | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 查看工作区状态 | cvs -n up | git status | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 提交 | cvs commit -m "" | git commit -a -m "" ; git push | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 显示提交日志 | cvs log | less | git log | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 逐行追溯 | cvs annotate | git blame | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 显示里程碑/分支 | cvs status -v | git tag | | | +------------------------------------------------------------+ | | | git branch | | | +------------------------------------------------------------+ | | | git show-ref | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 创建里程碑 | cvs tag [-r ] . | git tag [-m ""] [] | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 删除里程碑 | cvs rtag -d | git tag -d | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 创建分支 | cvs rtag -b -r -b | git branch | | | +------------------------------------------------------------+ | | | git checkout -b | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 删除分支 | cvs rtag -d | git branch -d | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 导出项目文件 | cvs -d export -r | git archive -o | | | +------------------------------------------------------------+ | | | git archive -o --remote= | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 分支合并 | cvs update [-j ] -j ; cvs commit | git merge | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 显示文件列表 | cvs ls | git ls-files | | +------------------------------------------------+------------------------------------------------------------+ | | cvs -d rls -r | git ls-tree | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 更改提交说明 | cvs admin -m : | git commit --amend | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 撤消提交 | cvs admin -o | git reset [ --soft | --hard ] HEAD^ | +-----------------------+------------------------------------------------+------------------------------------------------------------+ | 杂项 | .cvsignore 文件 | .gitignore 文件 | | +------------------------------------------------+------------------------------------------------------------+ | | 参数 -kb 设置二进制模式 | -text 属性 | | +------------------------------------------------+------------------------------------------------------------+ | | 参数 -kv 开启关键字扩展 | export-subst 属性 | +-----------------------+------------------------------------------------+------------------------------------------------------------+