@Chiang
2020-04-11T14:15:10.000000Z
字数 1447
阅读 537
Git
2020-04
为了真正理解 Git 处理分支的方式,我们需要回顾一下 Git 是如何保存数据的。
或许你还记得 起步 的内容, Git 保存的不是文件的变化或者差异,而是一系列不同时刻的 快照 。
在进行提交操作时,Git 会保存一个提交对象(commit object)。 知道了 Git 保存数据的方式,我们可以很自然的想到——该提交对象会包含一个指向暂存内容快照的指针。 但不仅仅是这样,该提交对象还包含了作者的姓名和邮箱、提交时输入的信息以及指向它的父对象的指针。 首次提交产生的提交对象没有父对象,普通提交操作产生的提交对象有一个父对象, 而由多个分支合并产生的提交对象有多个父对象,
为了更加形象地说明,我们假设现在有一个工作目录,里面包含了三个将要被暂存和提交的文件。 暂存操作会为每一个文件计算校验和(使用我们在 起步 中提到的 SHA-1 哈希算法),然后会把当前版本的文件快照保存到 Git 仓库中 (Git 使用 blob 对象来保存它们),最终将校验和加入到暂存区域等待提交:
当使用 git commit 进行提交操作时,Git 会先计算每一个子目录(本例中只有项目根目录)的校验和, 然后在 Git 仓库中这些校验和保存为树对象。随后,Git 便会创建一个提交对象, 它除了包含上面提到的那些信息外,还包含指向这个树对象(项目根目录)的指针。 如此一来,Git 就可以在需要的时候重现此次保存的快照。
现在,Git 仓库中有五个对象:三个 blob 对象(保存着文件快照)、一个 树 对象 (记录着目录结构和 blob 对象索引)以及一个 提交 对象(包含着指向前述树对象的指针和所有提交信息)。
git add .
git commit -m '提交信息'
Git 的 master 分支并不是一个特殊分支。 它就跟其它分支完全没有区别。 之所以几乎每一个仓库都有 master 分支,是因为 git init 命令默认创建它,并且大多数人都懒得去改动它。
# 这会在当前所在的提交对象上创建一个指针。
git branch testing
两个指向相同提交历史的分支
那么,Git 又是怎么知道当前在哪一个分支上呢? 也很简单,它有一个名为 HEAD
的特殊指针。 请注意它和许多其它版本控制系统(如 Subversion 或 CVS)里的 HEAD
概念完全不同。 在 Git 中,它是一个指针,指向当前所在的本地分支(译注:将 HEAD 想象为当前分支的别名)。 在本例中,你仍然在 master
分支上。 因为 git branch
命令仅仅 创建
一个新分支,并不会自动切换到新分支中去。
HEAD 指向当前所在的分支
你可以简单地使用 git log 命令查看各个分支当前所指的对象。 提供这一功能的参数是 --decorate。
git log --online --decorate
要切换到一个已存在的分支,你需要使用 git checkout 命令。 我们现在切换到新创建的 testing 分支去:
git checkout
这样 HEAD
就指向 testing
分支了。
你可以简单地使用 git log
命令查看分叉历史。 运行 git log --oneline --decorate --graph --all
,它会输出你的提交历史、各个分支的指向以及项目的分支分叉情况。
git log --oneline --decorate --graph --all
创建新分支的同时切换过去
通常我们会在创建一个新分支后立即切换过去,这可以用 git checkout -b 一条命令搞定。
git checkout -b <newbranchname>
参考资料:
git-scm.com
分支管理