乐趣区

关于git:深入浅出git二分支

在开发软件的时候, 可能很多人会同时为同一个软件开发性能或者修复 bug, 然而如果都在主分支来进行开发, 引起抵触的概率将会大大增加, 而且也不利于保护, 如果你同时批改多个 bug 该怎么办? 所幸,git 的分支性能很好的帮忙咱们解决了这个问题, 它能够帮忙咱们同时进行多个性能的开发和版本治理.
请在浏览这篇文章之前, 务必先浏览深入浅出 git——数据模型, 这样能力更好的帮忙你了解 git 中的分支. 想晓得为什么 git 中新建一个分支那么快, 代价那么小吗? 接下来咱们就来揭开分支神秘的面纱。

这次我会只显示 commit objects 来简化它, 并且为了让它更容易了解我会给他们取个别名来代替本来的测验和. 所以对于提交记录, 咱们会失去一个像上面这样的图.

相熟图论的应该留神到了下面的是一个有向无环图 (DAG), 这意味着从一个节点开始沿着边的方向不会通过雷同的节点.
在咱们的例图中能够清晰的发现存在三个不同的分支, 咱们别离用红色 (蕴含 A,B,C,D,E), 蓝色(A,B,F,G), 以及绿色(A,B,H,I,J) 来标记它们

这就是定义分支的一种形式 - 蕴含所有的提交列表. 然而这不是 git 应用的形式,git 应用更简略更便宜的形式,git 只跟踪分支上的最初一次提交, 而不是持有某个分支的所有列表并更新它们, 只须要晓得分支的最初一次提交, 而后依据图的有向边就能够获取整个提交列表. 例如要定义咱们的蓝色分支, 只须要晓得蓝色分支的最初一次提交是 G, 如果咱们须要蓝色分支蕴含的所有提交的列表, 就从 G 沿着图有向边遍历即可.

这就是 git 治理分支的形式, 通过放弃执行提交记录的指针即可, 接下来咱们会进行一个演示.
首先通过 git init 初始化一个空仓库, 而后查看.git 目录下存在的文件

.git
|-- HEAD
|-- config
|-- description
|-- hooks
|   |-- applypatch-msg.sample
|   |-- commit-msg.sample
|   |-- fsmonitor-watchman.sample
|   |-- post-update.sample
|   |-- pre-applypatch.sample
|   |-- pre-commit.sample
|   |-- pre-push.sample
|   |-- pre-rebase.sample
|   |-- pre-receive.sample
|   |-- prepare-commit-msg.sample
|   |-- update.sample
|-- info
|   -- exclude
|-- objects
|   |-- info
|   |-- pack
|-- refs
    |-- heads
    |-- tags

这次咱们关注 refs 这个子目录, 这个中央是 git 保留分支指针的地儿. 当咱们没有提交任何货色的时候,refs目录下只存在两个空目录, 当初咱们提交几个文件

echo "Hello Java" > helloJava.txt
git add .
git commit -m "Hello Java Commit"
echo "Hello Php" > helloPhp.txt
git add .
git commit -m "Hello Php Commit"
echo "Hello Python" > helloPython.txt
git add .
git commit -m "Hello Python Commit"

当咱们执行 git branch 的时候咱们能够看到上面这样的输入

* master

意味着咱们当初处于 master 分支上 (这个是当咱们第一次提交的时候 git 主动给咱们创立的), 此时refs 目录下是这样

.git/refs
|-- heads
|   `-- master
`-- tags

咱们看到 refs/heads 子目录中有一个文件,它就像咱们的分支一样被命名为 master, 咱们应用 cat 命令查看下文件内容

$ cat .git/refs/heads/master
49cd903b2bf247de040118ce60d1931ff587e801

而应用 git log 命令咱们能够看到咱们的提交记录是这样的

commit 49cd903b2bf247de040118ce60d1931ff587e801 (HEAD -> master)
Author: zhu.yang <zhu.yang@xxx.com>
Date:   Tue Jan 8 17:48:36 2019 +0800
    Hello Python Commit

commit dd7c1bc9c125067f5658bcc6bc35567d07bc4f35
Author: zhu.yang <zhu.yang@xxx.com>
Date:   Tue Jan 8 17:48:31 2019 +0800
    Hello Php Commit

commit c6bd5c991dbcf9c50bbab682796ab3e06672f5a7
Author: zhu.yang <zhu.yang@xxx.com>
Date:   Tue Jan 8 17:48:30 2019 +0800
    Hello Java Commit

从下面能够看进去一个分支仅仅只是一个文本文件, 其中记录了这个分支最初一次提交的校验和. 也就是指向 commit 的一个指针

当初咱们新建一个 feature 分支并切换到新建的这个分支下面

git checkout -b feature

应用 tree 命令在来看看.git/refs 的样子

.git/refs
|-- heads
|   |-- feature
|   |-- master
|-- tags

同样的咱们应用 cat 命令查看下.git/refs/heads/feature 文件的校验和

$ cat  .git/refs/heads/feature
49cd903b2bf247de040118ce60d1931ff587e801

咱们会发现和 master 文件中的内容统一, 当初为止咱们没有往 feature 分支提交任何内容

这就是 git 创立一个分支那么快以及不便的起因所在,git 仅仅只是创立了一个蕴含最近一次提交校验和的文件而已.

当初咱们的仓库外面就有 2 个分支了, 然而 git 怎么晓得咱们以后检出的分支是哪个分支呢? 这里其实存在一个非凡的指针叫做HEAD, 它之所以非凡是因为它并不指向具体的 commit object, 而是指向分支,git 应用它来跟踪最近检出的分支.

$ cat .git/HEAD
ref: refs/heads/feature

如果咱们执行

git checkout master

而后查看 HEAD, 会发现以后分支是 master, 而后 HEAD 会指向 master

$ cat .git/HEAD
ref: refs/heads/master

这就是 git 的分支模型, 很简略然而很重要, 理解它有助于了解在这个图上的其余操作(merge,rebase,checkout,revert…)。

退出移动版