今天我们从以下四个方面介绍Git:
What is git
Why is git so different
How git stores data
How branching/merging works for git
1. What is git?
Git是一个开源项目,它自己本身就在github上。Git是一个非常快速的,可扩展的,分布式版本控制(revision control)系统。Git是一个”stupid content tracker”(简单记录内容)。
它的command set非常多,有150多个,不仅有high-level的操作,还有到内部的full access。Git的command分为两种:Porcelain和Plumbing。前者包括很多我们常用的命令,如init, add, commit, branch,后者做一些low-level的工作,如hash-object, update-index, write-tree等。
版本控制(SCM)是指管理软件变化和配置的一个系统。包括管理什么变了以及谁变了它,常用于当有一个很大的版本系统,拥有很多文件并且修改文件人数很多的情况。Rollback是非常关键的事情!
上图第一行是没有版本控制时文件更改的状态,第二行是使用版本控制时的情况。
举一个写写冲突的例子。当A打开一个文件并做一些修改,B也打开同一文件,做修改并保存。A如何保存文件能保证不丢失B的修改。在Linux系统中,可以用diff和patch。SCM可以大大简化这些工作。
传统的SCM原理图如下:
所有代码存在Server端。Server端有一个data store,所有的历史都在data store里。所有人都作为Client,从data store里拿远程副本,一个snapshot。在本地更改完后commit上Server。Server端的data store保留原来的数据,并且将新数据改写为头部。在每次commit前,re-sync数据。
这种系统的不足之处在于,如果re-sync时,snapshot的版本不是Repo上最新的版本时,Server端可能丢失数据。因为commit前,所有改动都在Client端,就会出现Single point of failure。比如Client端remove了一个文件,如果文件有本地更改并且没有及时commit到Server,更改就会丢失。或者当Server有failure且没有备份,那么数据历史信息将丢失。同时有些操作需要连网,导致很慢,比如svn当你想看version history或者想去做svn diff(看本地更改的内容是什么)的时候,会需要联网。
下图是传统SCM的workflow:
2. Why git is different?
最大的不同在于Git是分布式的。
1) What does distributed even mean?
分布式在于不把所有数据存在同一地方。
下图是git的原理图:
不同于之前的方式,git在Client端也有database,可以认为是在本地的一个缓存。每个clone不是snapshot而是数据的全部备份。在最初的clone之后,几乎所有的操作都是本地的。
好处是没有Single point of failures。一是本地有database随时备份可以减少数据丢失。由于引入了local db和local commit的概念随时commit成为了可能。比如之前提到不小心rm了文件的情况,在git里面可以由本地的db回复。二是当Server出错时,可以把Client数据reset成Server数据。Git非常快,因为所有数据在本地都可以读取,减少带宽。Git是可扩展的,branch的数量可以非常多。
2) What is git’s Version Database?
Version Database本质上是一个文件系统(content addressable filesystem)。以key-value的形式存储数据。Key使用SHA-1 hash,有20 bytes,40 hex。Value是binary files,占用空间更小,包括三种:
(1)Commits:真正的 git commits。commit就是一个snapshot
(2)Trees:Directories(structure of file system)
(3)Blobs:content of files/data
3. How git stores data
下图是一个简单git使用流程:
第一个init新建一个repository。产生一个.git目录,这个目录结构如下图:
Git里一个重要的概念是Stage area。如下图所示:
Git在add的时候没有把文件加入repository,但是Blob已经存在了。文件只有在Staging area的时候,才能进行commit工作。Staging area是一个index文件。
下图是Git在commit时候的snapshot:
当commit时,project的根目录被hash成了一个tree。有我们创建的文件Hello.txt,它变成一个Blob。commit是整个snapshot的入口。
3) What is missing?
如何找到一个commit?Refs!
git HEAD指的是ref,它是一个file,file里存的是一个commit的hash。从hash可以找到commit。
index是一个线性的排序结构,按照文件夹目录名排序。而tree就是树状结构。commit的时候改变tree,不commit的时候tree没有变化。
当对代码进行更新并再进行一次commit时,如下图示:
4. How branching/merging works for git?
1)What is branch?
Branch只是一个41 byte大小的文件。新建一个branch时只有refs里的head增加了一个41 byte的文件,其他事情都没有发生。
2) What is happening on merge?
首先从master和另一个要merge的branch(比如feature)里找到共同的部分
接下来比较找到的两个commit,只需找到有变化的部分,改变真正的文件,同时考虑conflict的问题:
最后生成一个commit,这个commit有两个parent指针:
最后我们再回顾一下之前提到的那句话,现在会有更深刻的理解:
本文作者:Shaoke Xu, 更多精彩内容,欢迎访问官网 BitTiger.io 或关注 “论码农的自我修养” 微信公众号:bit_tiger