DVCS中不同分支模型的优缺点

时间:2009-10-31 18:45:04

标签: git mercurial branch bazaar

分布式版本控制(Git,Bazaar和Mercurial)的三巨头每个都以不同的方式对待分支。例如,在Bazaar,分支机构是独立的回购(实际上是父回购的不同副本);在您的文件系统上,不同的分支存在于不同的目录中。另一方面,在Git中,您可以在同一个repo中存在多个分支(因此在文件系统的同一目录中)。 Mercurial支持both behaviors,后者支持named branches

与这些不同分支模型相关的优缺点是什么?在我看来,Bazaar的一个分支,一个回购的方法使分支比Git的方法更痛苦(例如在Bazaar中使用分支,我必须首先创建分支,然后cd出我当前的工作副本,然后检查出来新的分支,就像我在SVN中那样)。

2 个答案:

答案 0 :(得分:9)

Bazaar不要求您按照您描述的方式工作。我两天前实际上写过a blog post。您只需使用一个工作树即可完成工作,在各个分支之间切换并创建新分支而无需离开工作树。有用的命令是:checkoutswitchbranch --switch。查看Bazaar的workflow文档,您将看到几乎可以以任何方式配置它。

答案 1 :(得分:6)

我不太了解除Git之外的VCS中的分支模型。我想说在任何DVCS中你都可以通过克隆来实现分支(你通过克隆来创建分支)。 Mercurial所谓的“命名分支”(据我所知)实际上提交标签仅被解释为分支,有时需要本地编号的修订来解决歧义。我认为,Mercurial“书签”与Git分支非常相似。具有非常不同分支概念的两个DVCS是MonotoneDarcs。我认为Subversion使用的“通过复制分支”,项目名称和分支名称之间的分离是约定,这是错误的想法。


在Git版本中形成了一个有向提交的非循环图(DAG)。它是针对性的,因为提交有父母。这是一个非常重要的问题:提交的DAG中的边缘是从提交到其父级(或者,在合并提交的情况下,其父级中的两个或更多)。提交图是非循环的,这意味着没有链(没有路径)以相同的对象开始和结束。

Git glossary将“分支”定义为有效的开发线。这个想法是在Git中实现分支的背后。

分支上的最新提交称为该分支的提示。分支的提示由分支头引用,它只是此提交的符号名称。在它的“松散”形式中,这样的分支头(例如对于名为“master”的分支)只是git repository(refs/heads/ dir内).git目录中的某个文件,其中包含对当前提示的引用分支:它的提交的SHA-1标识符(作为十六进制字符串)。

在Git中创建新提交时,当前签出分支的提示会向前移动。换句话说,新提交是在当前分支的顶端创建的,并且分支头进入新提交(有点类似于指向堆栈顶部的指针可能如何前进)。

单个git存储库可以跟踪任意数量的分支,但是您的工作树(如果有的话)只与其中一个(“当前”或“已检出”分支)相关联。当前分支由HEAD指针给出。 HEAD是(通常)指向当前已检出分支(指向分支头名称)的指针,就像分支头是指向分支提示的指针一样。

例如,如果当前签出的分支是“master”,则.git/HEAD文件(表示HEAD)将包含带有ref: refs/heads/master的单个LF终止行(对refs/heads/master的符号引用),和.git/refs/heads/master('master'分支的头部)将包含例如LF终止行0b127cb8ab975e43398a2b449563ccb78c437255,这是'master'分支的尖端的SHA-1标识符(即当前分支不是“打包的”) “:那么你必须看看.git/packed-refs)。

Git中的一些命令,例如“git commit”或“git reset”操作/更改分支头;其他如“git checkout”操纵/改变HEAD(对当前分支的符号引用)。

git log branch”命令显示从分支提示可以访问的所有提交,这意味着分支的提示,其父提交,父提交的父(或父代)等。它显示提交的DAG的一部分。

在Git中删除分支意味着只需删除分支头。这可能意味着某些提交变得“不可见”,无法访问的freom引用(分支和标记),这意味着在某些时候这些提交可能会被垃圾收集并从存储库中删除。但是如果你可以用“git branch -d< branchname>”删除分支那意味着不会丢失任何提交;您可以使用“git branch -D< branchname>”强制删除分支。重命名分支只是重命名分支头,分支头的符号引用(符号名称);分支名称不会保存在提交对象中的任何位置。


Git还有 reflogs 的概念,这是分支提示指向(以及何时)的本地历史记录。例如,如果使用“git commit --amend”修改提交,则分支提示将替换为修改提交,并且HEAD ^将在修改之前和之后成为提交的父级,而在修改之前将在reflog中输入版本在修改之后。如果使用“git reset”重绕历史记录,则reflog将包含倒带前旧分支提示的信息。

简而言之,reflog为git命令提供了额外的安全性和轻松恢复。