除了 Git,我对 VCS 中的分支模型了解不多。我想说的是,在任何 DVCS 中,您都可以通过克隆来实现分支(通过克隆来创建分支)。Mercurial 所谓的“命名分支”(据我所知)实际上提交标签仅被解释为分支,有时需要对修订进行本地编号以解决歧义。我认为,Mercurial“书签”与 Git 分支非常相似。具有非常不同的分支概念的两个 DVCS 是Monotone和Darcs。我认为 Subversion 使用的“通过复制进行分支”,项目名称和分支名称之间的分隔是约定俗成的,是一个错误的想法。
在 Git 中,修订形成了提交的有向无环图 (DAG)。它是定向的,因为提交有父母。这是一个非常重要的问题:提交的 DAG 中的边是从提交到其父级(或者,在合并提交的情况下,是两个或多个其父级)。提交图是非循环的,这意味着没有以相同对象开始和结束的链(没有路径)。
Git 词汇表将“分支”定义为一个活跃的开发线。这个想法是在 Git 中实现分支的背后。
分支上的最新提交称为该分支的尖端。分支的尖端由分支 head引用,这只是此提交的符号名称。在其“松散”形式中,这样的分支头(例如,名为“master”的分支)只是refs/heads/
git 存储库(在.git
dir 内)目录中某处的文件,其中包含对当前分支尖端的引用:它的 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 命令提供了额外的安全性和轻松恢复。