今天我們從以下四個方面介紹Git:
1. What is git? Git是一個開源項目,它自己本身就在github上。Git是一個非??焖俚?,可擴展的,分布式版本控制(revision control)系統(tǒng)。Git是一個”stupid content tracker”(簡單記錄內(nèi)容)。 它的command set非常多,有150多個,不僅有high-level的操作,還有到內(nèi)部的full access。Git的command分為兩種:Porcelain和Plumbing。前者包括很多我們常用的命令,如init, add, commit, branch,后者做一些low-level的工作,如hash-object, update-index, write-tree等。 版本控制(SCM)是指管理軟件變化和配置的一個系統(tǒng)。包括管理什么變了以及誰變了它,常用于當(dāng)有一個很大的版本系統(tǒng),擁有很多文件并且修改文件人數(shù)很多的情況。Rollback是非常關(guān)鍵的事情! 上圖第一行是沒有版本控制時文件更改的狀態(tài),第二行是使用版本控制時的情況。 舉一個寫寫沖突的例子。當(dāng)A打開一個文件并做一些修改,B也打開同一文件,做修改并保存。A如何保存文件能保證不丟失B的修改。在Linux系統(tǒng)中,可以用diff和patch。SCM可以大大簡化這些工作。 傳統(tǒng)的SCM原理圖如下: 所有代碼存在Server端。Server端有一個data store,所有的歷史都在data store里。所有人都作為Client,從data store里拿遠(yuǎn)程副本,一個snapshot。在本地更改完后commit上Server。Server端的data store保留原來的數(shù)據(jù),并且將新數(shù)據(jù)改寫為頭部。在每次commit前,re-sync數(shù)據(jù)。 這種系統(tǒng)的不足之處在于,如果re-sync時,snapshot的版本不是Repo上最新的版本時,Server端可能丟失數(shù)據(jù)。因為commit前,所有改動都在Client端,就會出現(xiàn)Single point of failure。比如Client端remove了一個文件,如果文件有本地更改并且沒有及時commit到Server,更改就會丟失?;蛘弋?dāng)Server有failure且沒有備份,那么數(shù)據(jù)歷史信息將丟失。同時有些操作需要連網(wǎng),導(dǎo)致很慢,比如svn當(dāng)你想看version history或者想去做svn diff(看本地更改的內(nèi)容是什么)的時候,會需要聯(lián)網(wǎng)。 下圖是傳統(tǒng)SCM的workflow: 2. Why git is different? 最大的不同在于Git是分布式的。 1) What does distributed even mean? 分布式在于不把所有數(shù)據(jù)存在同一地方。 下圖是git的原理圖: 不同于之前的方式,git在Client端也有database,可以認(rèn)為是在本地的一個緩存。每個clone不是snapshot而是數(shù)據(jù)的全部備份。在最初的clone之后,幾乎所有的操作都是本地的。 好處是沒有Single point of failures。一是本地有database隨時備份可以減少數(shù)據(jù)丟失。由于引入了local db和local commit的概念隨時commit成為了可能。比如之前提到不小心rm了文件的情況,在git里面可以由本地的db回復(fù)。二是當(dāng)Server出錯時,可以把Client數(shù)據(jù)reset成Server數(shù)據(jù)。Git非常快,因為所有數(shù)據(jù)在本地都可以讀取,減少帶寬。Git是可擴展的,branch的數(shù)量可以非常多。 2) What is git’s Version Database? Version Database本質(zhì)上是一個文件系統(tǒng)(content addressable filesystem)。以key-value的形式存儲數(shù)據(jù)。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。產(chǎn)生一個.git目錄,這個目錄結(jié)構(gòu)如下圖: Git里一個重要的概念是Stage area。如下圖所示: Git在add的時候沒有把文件加入repository,但是Blob已經(jīng)存在了。文件只有在Staging area的時候,才能進(jìn)行commit工作。Staging area是一個index文件。 下圖是Git在commit時候的snapshot: 當(dāng)commit時,project的根目錄被hash成了一個tree。有我們創(chuàng)建的文件Hello.txt,它變成一個Blob。commit是整個snapshot的入口。 3) What is missing? 如何找到一個commit?Refs! git HEAD指的是ref,它是一個file,file里存的是一個commit的hash。從hash可以找到commit。 index是一個線性的排序結(jié)構(gòu),按照文件夾目錄名排序。而tree就是樹狀結(jié)構(gòu)。commit的時候改變tree,不commit的時候tree沒有變化。 當(dāng)對代碼進(jìn)行更新并再進(jìn)行一次commit時,如下圖示: 4. How branching/merging works for git? 1)What is branch? Branch只是一個41 byte大小的文件。新建一個branch時只有refs里的head增加了一個41 byte的文件,其他事情都沒有發(fā)生。 2) What is happening on merge? 首先從master和另一個要merge的branch(比如feature)里找到共同的部分 接下來比較找到的兩個commit,只需找到有變化的部分,改變真正的文件,同時考慮conflict的問題: 最后生成一個commit,這個commit有兩個parent指針: 最后我們再回顧一下之前提到的那句話,現(xiàn)在會有更深刻的理解: 本文作者:Shaoke Xu, 更多精彩內(nèi)容,歡迎訪問官網(wǎng) BitTiger.io 或關(guān)注 “論碼農(nóng)的自我修養(yǎng)” 微信公眾號:bit_tiger |
|