Git分支简介

在Git中,有个校验和的概念,主要用于验证数据完整性,它是一个40位16进制字符串,使用SHA-1哈希算法生成。校验和也标识了Git中每一个对象。

我们由前一章阅读了解到Git保存的是文件快照而非内容差异变化。而暂存和提取操作中怎么保存文件快照呢?这和对象又有什么关联?

首先,暂存操作(git add)为每一个文件计算出校验和,Git使用Blob对象保存这些文件快照,而文件校验和保存到暂存区。

提交操作(git commit)为每一个子目录计算校验和,然后将该校验和保存为树对象,一个树对象包含了多个Blob对象索引和目录结构信息,接着结合指向树对象的指针和所有提交信息为一个提交对象。除第一个提交对象外,其他提交对象都包含指向上一个提交对象的指针(父对象)。

在这里插入图片描述

从概念视角看,Git分支实质上是指向提交对象的可变指针。初始化(git init)时默认创建分支master或main。每次提交,当前分支都会向前移动,也就是指向新的提交对象

创建分支

根据之前的内容,创建分支也就是创建一个指向当前提交对象的可移动指针。

Git会有一个HEAD指针指向当前分支,当我们创建新分支时,HEAD并不会移动,也就是创建新分支不会切换到新分支。创建一个名为testing的分支的命令是git branch testing,分支情况如下:

在这里插入图片描述

你可以使用git log --oneline --decorate查看各个分支所指对象。

切换分支

切换分支的命令:git checkout <branch-name>

切换分支意味着改变HEAD指针指向。

切换分支有什么用呢?

当我们切换分支后,若进行提交,则原HEAD指向的指针不变,仍指向上一个提交,当前HEAD指向的指针(即当前分支)则指向当前提交。这意味着我们可以新建分支并切换到新分支来开发新功能,等到时机成熟再合并。

Git的分支操作为什么比其他VCS快?

从物理视角看,Git 分支是通过一个特殊的文件存储的。这个文件位于 .git/refs/heads/ 目录下,每个分支对应一个文件。每当你创建一个新的分支或进行提交时,Git 会在这些文件中更新对应的分支信息。每个分支文件实际上包含一个 40 个字符长的 SHA-1 哈希值,这个哈希值指向对应分支的最新提交对象。所以从这个角度来看,分支实际上是一个包含 SHA-1 哈希值的文件。因此,操作Git分支也就是对该文件的修改,当然比直接复制全部目录文件的方法快。

不过,要注意切换分支工作目录会回到切换到的分支的最后一次提交时的状态,所以最好保持一个干净的状态再切换分支。当然也有别的解决方法:暂存和修补提交。

分支的新建与合并

分支的新建与切换可以一步完成:git checkout -b <branch-name>

那什么时候适合新建分支呢?

开发新功能、修复Bug、版本发布、多人协作等...

当我们完成新分支的任务后,可能需要将该分支合并到主分支。合并呢,也会遇到多种情况。比如,

  1. 待合并分支与目标分支是包含关系,其中目标分支是待合并分支的父分支,且从目标分支到待合并分支的提交历史是线性的,这种合并是没有冲突的。完成合并后,当前分支指针指向了待合并分支的最新提交。这称为快进合并(Fast-Forward)。

  2. 待合并分支与目标分支从公共祖先处分叉,这种情况下,带合并分支、目标分支与两者的公共祖先分支三者做合并。与快进合并不同的是,git会做一个新快照并创建一个提交指向它,这称为一次合并提交

  3. 如果你在两个不同的分支中,对同一个文件的同一个地方进行了不同修改,合并它们的时候就会发生合并冲突,git会提示CONFLICT:...,虽然执行合并后,git依然作了合并,但是没有自动创建一个新的合并提交,这就等你去解决冲突来手动提交。你可以使用git status来查看因合并冲突而处于未合并(unmerged)状态的文件。Git会在有冲突的文件处加入标准的冲突解决标记,格式如下:

    <<<<<<< HEAD:文件1
    文件1冲突部分A
    =======
    文件2冲入部分B
    >>>>>>> 待合并分支:文件2
    

    你必须将上面内容替换成A或B之一。
    当然你也可以选择使用图形化工具解决冲突,运行git mergetool命令来查看适合的工具。
    最后,再次使用git status查看冲突是否已解决。

分支管理

# 查看所有分支,*号对应当前分支
$ git branch
 iss53
* master
 testing
# 查看每个分支的最后一次提交,也就是所指向的提交
$ git branch -v
 iss53   93b412c fix javascript issue
* master  7a98805 Merge branch 'iss53'
 testing 782fd34 add scott to the author list in the readmes
# 查看已合并到当前分支的分支列表,该列表中未带*号的都是可以安心删除的
$ git branch --merged
 iss53
* master
# 查看未合并到当前分支的分支列表,这些分支包含了未合并的内容,所以不可删除,但可以`-D`强制删除
$ git branch --no-merged
 testing
# 查看其它分支的合并状态
$ git branch --no-merged testing
 topicA
 featureB