11

分布式版本控制的三大巨头(Git、Bazaar 和 Mercurial)各自对待分支的方式截然不同。例如,在 Bazaar 中,分支是单独的 repo(实际上是父 repo 的不同副本);在您的文件系统上,不同的分支位于不同的目录中。另一方面,在 Git 中,您可以在同一个 repo 中存在多个分支(因此在文件系统的同一个目录中)。Mercurial 支持这两种行为,后者带有命名分支

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

4

2 回答 2

10

Bazaar 不需要您按照您描述的方式工作。实际上,我两天前已经写了一篇关于它的博客文章。您几乎可以只使用一个工作树,在各个分支之间切换并创建新分支,而无需离开工作树。对此有用的命令是:checkout, switch, branch --switch. 查看 Bazaar 的工作流文档,您会发现几乎可以以任何您想要的方式对其进行配置。

于 2009-10-31T18:53:39.207 回答
6

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


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

Git 词汇表将“分支”定义为一个活跃的开发线。这个想法是在 Git 中实现分支的背后。

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

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

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

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

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

" " 命令显示从分支提示可到达的所有提交,这意味着分支的提示、其父提交、该父提交的父(或父)等。它显示了提交的 DAG 的一部分。git log branch

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


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

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

于 2009-11-01T22:28:20.803 回答