git的學(xué)習(xí)與使用

git的學(xué)習(xí)與使用

1疯淫、git簡介

1.1 git歷史

Git是一個免費開源的分布式版本控制系統(tǒng)(DVCS)族购。

Git誕生于一個極富紛爭大舉創(chuàng)新的年代尤仍。Linux內(nèi)核開源項目有著為數(shù)眾廣的參與者超凳。絕大多數(shù)的Linux內(nèi)核維護工作都花在了提交補丁和保存歸檔的繁瑣事務(wù)上(1991-2002年間)侨糟。到2002年税朴,整個項目組開始啟用分布式版本控制系統(tǒng)BitKeeper來管理和維護代碼回季。

到了2005年家制,開發(fā)BitKeeper的商業(yè)公司同Linux內(nèi)核開源社區(qū)的合作關(guān)系結(jié)束,他們收回了免費使用BitKeeper的權(quán)力泡一。這就迫使Linux開源社區(qū)(特別是Linux的締造者Linus Torvalds)不得不吸取教訓(xùn)颤殴,只有開發(fā)一套屬于自己的版本控制系統(tǒng)才不至于重蹈覆轍。

自誕生于2005年以來鼻忠,Git日臻成熟完善涵但,在高度易用的同時,仍然保留著初期設(shè)定的目標(biāo)帖蔓。它的速度飛快矮瘟,極其適合管理大項目,它還有著令人難以置信的非線性分支管理系統(tǒng)塑娇,可以應(yīng)付各種復(fù)雜的項目開發(fā)需求澈侠。

1.2 git與svn比較

1.2.1 分布式與集中式版本控制

Git是Linus用C實現(xiàn)的一個分布式版本控制工具,注意這里對分布式的強調(diào)埋酬。不同于Git哨啃,像Perforce、SVN和CVS這類版本控制工具都是集中式的写妥。

1拳球、集中式版本控制

所謂集中式的版本控制,就是在一個系統(tǒng)中只有一個機器是服務(wù)端珍特,其他機器全是客戶端祝峻。

SVN版本控制為例,在一個系統(tǒng)中會有一個SVN服務(wù)器次坡,所有的代碼以及版本信息都保存在這個服務(wù)器上呼猪。每個客戶端可以從服務(wù)器獲取一份代碼,然后在本地修改砸琅,最后submit修改的代碼。

這里可以看出集中式的控制版本存在一些問題:

  • 網(wǎng)絡(luò)依賴性強轴踱,工作環(huán)境保持網(wǎng)絡(luò)連接症脂,如果網(wǎng)絡(luò)斷掉了,所有的客戶端就無法工作了淫僻。
  • 安全性較弱诱篷,所有的代碼以及版本信息保存在服務(wù)器中,一旦服務(wù)器掛掉了雳灵,代碼和版本控制信息就丟失了棕所。

2、分布式版本控制

在分布式版本控制系統(tǒng)中悯辙,沒有服務(wù)端/客戶端的概念琳省,每臺機器都是一個服務(wù)器迎吵。也就是說,在分布式本版控制系統(tǒng)中针贬,每臺機器都有一份代碼击费,并且有代碼的版本信息。

對比SVN可以看出其相應(yīng)的一些優(yōu)勢:

  • 每臺機器都是一臺服務(wù)器桦他,無需依賴網(wǎng)絡(luò)就可以幫自己的更新提交到本地服務(wù)器蔫巩,支持離線工作。當(dāng)有網(wǎng)絡(luò)環(huán)境的時候快压,就可以把更新推送給其他服務(wù)器圆仔。
  • 安全性高,每臺機器都有代碼以及版本信息的維護蔫劣,所有即使某些機器掛掉了荧缘,代碼依然是安全的。

在git中拦宣,同步的方式有很多種截粗,可以把自己的更新推送給別人,也可以生成一個diff的patch鸵隧,通過郵件方式把這個patch發(fā)送給別人绸罗。這些可以在之后的章節(jié)介紹。

雖然分布式控制版本沒有服務(wù)器的概念豆瘫,但是在一般的一個git系統(tǒng)中珊蟀,為了方便大家交換和更新,會找一臺機器作為中心服務(wù)器外驱,這臺機器的目的只是為了大家方便交換和更新代碼育灸。即使這臺中心服務(wù)器掛了,大家依舊可以繼續(xù)工作昵宇,只是相互之間交換比較麻煩磅崭。

1.2.2 版本控制的原理

git和其他版本控制系統(tǒng)的主要差別在于:git只關(guān)心文件數(shù)據(jù)的整體是否發(fā)生變化,而大多數(shù)其他系統(tǒng)則只關(guān)心文件內(nèi)容的具體差異瓦哎。這類系統(tǒng)(CVS砸喻,Subversion蒋譬,Perforce割岛,Bazaar 等等)每次記錄有哪些文件作了更新剂买,以及都更新了哪些行的什么內(nèi)容

1费坊、svn

SVN是一個增量式的版本控制,它不會講各個版本的副本都完整的保存下來附井,而只會記錄下版本之間的差異,然后按照順序更新或者恢復(fù)特定版本的數(shù)據(jù)两残。這使得服務(wù)端的存儲量會非常低永毅。

2、git

git早版本控制時只關(guān)心文件數(shù)據(jù)的整體是否發(fā)生變化人弓,并不保存這些前后變化的差異數(shù)據(jù)沼死。實際上,git更像是把變化的文件做快照后崔赌,記錄在一個微型的文件系統(tǒng)中意蛀。每次提交更新時,它會縱覽一遍所有文件的指紋信息并對文件作一快照健芭,然后保存一個指向這次快照的索引县钥。為提高性能,若文件沒有變化慈迈,git不會再次保存若贮,而只是對上次保存的快照做一鏈接。簡單來說痒留,如下圖:

git快照存儲

這是git同其它系統(tǒng)的重要區(qū)別次氨,他完全顛覆了傳統(tǒng)版本控制的思路涡扼,并對各個環(huán)節(jié)的實現(xiàn)做了新的設(shè)計垮抗。git更像是一個小型的文件系統(tǒng)陆盘,但它同時還提供了許多以此為基礎(chǔ)的超強工具,而不只是一個簡單的VCS熊锭。

1.3 git主要特點前述

1弧轧、如上:分布式快照記錄,與其它版本集中式差異比較的版本控制有本質(zhì)差異碗殷。

2、近乎所有操作都是本地進行速缨,不需要聯(lián)網(wǎng)锌妻。

在git中的絕大數(shù)操作都只需要訪問本地文件和資源,不用連網(wǎng)旬牲。但用SVN的話仿粹,差不多所有的操作都需要連接網(wǎng)絡(luò)搁吓。因為git在本地磁盤上就保存著多有當(dāng)前項目的歷史更新,所以處理起來飛快吭历。

3堕仔、時刻保持?jǐn)?shù)據(jù)的完整性。

在保存到git之前晌区,所有的數(shù)據(jù)都要進行內(nèi)容的較檢和(checksum)計算摩骨,并將此結(jié)果作為數(shù)據(jù)的唯一標(biāo)識和索引。換句話說朗若,不可能在修改了文件或目錄之后恼五,git一無所知。這項特性作為git的設(shè)計哲學(xué)哭懈,建立在整體架構(gòu)的最底層灾馒。所以文件在傳輸時不完整或磁盤損壞導(dǎo)致文件缺失,git都能第一時間察覺遣总。

git使用SHA-1算法計算數(shù)據(jù)的較檢和睬罗,通過對文件的內(nèi)容或目錄的結(jié)構(gòu)計算出一個SHA-1的hash值。作為指紋字符串旭斥,該字符串由40個十六進制的字符組成容达,看起來如下,這個在之后會有說明琉预。

24b9da6552252987aa493b52f8696cd6d3b00373

實際上董饰,保存在git數(shù)據(jù)庫的東西都是靠此hash值來索引的,而不是靠文件名圆米。

4卒暂、多數(shù)操作僅添加數(shù)據(jù)

常用的git操作僅僅是把數(shù)據(jù)添加到數(shù)據(jù)庫中。因為任何一種不可逆的操作娄帖,比如刪除數(shù)據(jù)也祠,都會使回退或重現(xiàn)歷史版本變得困難重重。在別的VCS中近速,若還未提交更新诈嘿,就有可能丟失或混淆一些修改的內(nèi)容,但在git里削葱,一旦提交之后就完全不用擔(dān)心數(shù)據(jù)丟失奖亚,特別是養(yǎng)成定期推送到其它倉庫的習(xí)慣時。

5析砸、文件的三種狀態(tài)

對于任何一個文件昔字,都有三種狀態(tài):已提交(committed)、已修改(modified)首繁、已暫存(staged)作郭。

  • 已提交:該文件已被安全存儲到本地數(shù)據(jù)庫中陨囊。
  • 已修改:已經(jīng)修改此文件,但還沒有提交保存夹攒。
  • 已暫存:已修改的文件放在了下次要提交保存的列表中蜘醋。

由此我們可以看到git管理項目時,文件流轉(zhuǎn)的三個工作區(qū)域:git的工作目錄咏尝、暫存區(qū)域即本地倉庫压语。

git工作的三個區(qū)域

git控制的版本系統(tǒng),每個項目都會有一個git目錄(如果git clone 出來状土,其中.git目錄无蜂;如果git clone --bare的話,新建目錄本身就是git目錄)蒙谓,它是git用來保存元數(shù)據(jù)和對象數(shù)據(jù)庫的地方斥季。該目錄非常重要,每次克隆鏡像倉庫的時候累驮,實際上就是拷貝其中的數(shù)據(jù)酣倾。

從項目上取出某個版本的所有文件和目錄,用以開始后續(xù)的工作叫做工作目錄谤专。這些文件實際上都是從git目錄中的壓縮對象數(shù)據(jù)庫中提取出來的躁锡,以后就可以在工作目錄中對這些文件進行編輯。

所謂的暫存區(qū)域只不過是個簡單的文件置侍,一般都放在git目錄中映之,有時候人們會把這個文件叫做索引文件,不過標(biāo)準(zhǔn)的說法還是叫暫存區(qū)域蜡坊。

git基本的工作流程如下:

a杠输、新建或檢出一份項目代碼到工作目錄。

b秕衙、在工作目錄中對某些文件做修改蠢甲。

c、對修改的文件做快照据忘,然后保存到暫存區(qū)域鹦牛。

d、提交更新勇吊,將保存在暫存區(qū)域的文件快照永久轉(zhuǎn)存到git目錄中曼追。

從上面我們可以看出從文件所處的位置來判斷文件的狀態(tài):

  • 已提交:git目錄中保存著特定版本的文件。
  • 已暫存:文件做了修改且已放在暫存區(qū)域汉规。
  • 已修改:文件自上次取出后拉鹃,做了修改但還沒放到暫存區(qū)域里。

2鲫忍、git安裝與配置

2.1 git的安裝

git主要有兩種安裝方式:一種是通過源代碼來安裝膏燕;另一種是使用為特定平臺預(yù)編譯好的安裝包。

2.1.1 源代碼安裝

源代碼安裝有許多好處悟民,至少可以安裝使用最新版本的git坝辫。git的每個版本都在嘗試不斷改進用戶的體驗,所以通過源代碼編譯安裝最新版本最好射亏。

git源碼下載地址近忙。

下載完成后編譯并安裝。

[root@localhost ~] wget https://www.kernel.org/pub/software/scm/git/git-2.9.5.tar.gz
[root@localhost ~]# tar -zxvf git-manpages-2.9.5.tar.gz 
[root@localhost ~]# cd git-2.9.5/
[root@localhost ~]# ./configure --prefix=/usr/local/git
[root@localhost ~]# make && make install

然后就可以使用git命令了智润,不能使用再配置下軟連接及舍。

[root@localhost ~]# cd /usr/bin
[root@localhost bin]# ln -s /usr/local/git/bin/git ./git

2.1.2 各平臺安裝

1、linux安裝

直接使用系統(tǒng)提供的包管理工具窟绷。

[root@localhost ~]# yum install git

2锯玛、mac上面安裝(借鑒)

a、圖形化git的安裝工具

http://sourceforge.net/projects/git-osx-installer/

b兼蜈、MacPorts(http://www.macports.org)安裝攘残。如果已經(jīng)裝好了MacPorts,用下面的命令安裝Git:

[root@localhost ~]# sudo port install git-core +svn +doc +bash_completion +gitweb

3为狸、windows上面安裝

有項目名為msysGit提供了安裝包(https://git-for-windows.github.io)下載歼郭,然后按默認(rèn)選項安裝即可。

2.2 git的配置(可略)

一般在新的系統(tǒng)上辐棒,我們都需要先配置下自己的git安裝環(huán)境病曾。配置工作只需要一次,以后升級還會沿用現(xiàn)在的配置漾根。當(dāng)然泰涂,如果需要,可以隨時用相同的命令修改已有的配置立叛。

1负敏、用戶信息

[root@localhost test]# git config --global user.name "yourname"
[root@localhost test]# git config --global user.email "youremail"

如果使用了--global選項,那么更改的配置文件是位于用戶主目錄下的那個秘蛇,以后所有的額項目都會使用這里配置的用戶信息其做。如果想要在某個特定的項目中使用其它名字或電郵,只要去掉--global選項重新配置即可赁还,新的設(shè)定保存在當(dāng)前項目的.git/config文件里妖泄。

2、配置級別

git共三個配置級別:

  • --local艘策、高優(yōu)先級蹈胡,只影響本倉庫,文件尾.git/config
  • --global、中優(yōu)先級罚渐,影響到素有當(dāng)前用戶的git倉庫却汉,文件為~/.gitconfig
  • --system、低優(yōu)先級荷并,影響全系統(tǒng)的git倉庫合砂,文件為/etc/gitconfig

3、查看配置信息

[root@localhost test]# git config --list
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true

3源织、git通用概念

在介紹下面的部分翩伪,有必要說下git的通用概念,這些將會對下面的操作有理解幫助谈息。

在git中缘屹,每個版本庫都叫做一個倉庫(repository),每個倉庫可以簡單的理解為一個目錄侠仇,這個目錄里面的所有文件都通過git來實現(xiàn)版本管理轻姿,git都能跟蹤記錄在該目錄中發(fā)生的所有更新。

假設(shè)我們新建一個倉庫test(repository)傅瞻,那么在這個test目錄中就會有.git的文件夾踢代,這個文件夾非常重要,所有的版本信息嗅骄、更新紀(jì)錄及git進行倉庫管理的相關(guān)信息全部都保存在這個文件夾里面胳挎。所以,不修改或刪除其中的文件溺森,以免造成數(shù)據(jù)的丟失慕爬。

[root@localhost test]# ls -al
總用量 0
drwxr-xr-x  2 root root  6 10月 24 14:04 .
drwxr-xr-x. 6 root root 59 10月 23 19:02 ..
[root@localhost test]# git init
初始化空的 Git 倉庫于 /home/test/.git/
[root@localhost test]# ls -al
總用量 0
drwxr-xr-x  3 root root  17 10月 24 14:04 .
drwxr-xr-x. 6 root root  59 10月 23 19:02 ..
drwxr-xr-x  7 root root 111 10月 24 14:04 .git

進一步參考下面的圖,大概展示了需要了解的基本知識屏积。

git目錄說明医窿。

根據(jù)上圖,再給出簡要說明:

  • Directory:使用git管理的一個目錄炊林,也就是一個倉庫姥卢,包含我們的工作空間git的管理空間
  • Workspace:從倉庫中chenkout出來的渣聚,需要通過git進行版本控制的目錄和文件独榴,這些目錄和文件組成了工作空間
  • .git:存放git管理信息的目錄奕枝,初始化倉庫時自動創(chuàng)建棺榔。
  • Index/Stage:暫存區(qū)或叫做待提交更新區(qū);在提交至repo之前隘道,我們可以把所有的更新放在暫存區(qū)症歇。
  • Local Repo:本地倉庫郎笆,一個存放在本地的版本庫;HEAD會指示當(dāng)前的開發(fā)分支(branch)忘晤。
  • Stash:工作狀態(tài)保存棧宛蚓,用于保存/恢復(fù)WorkSpace的臨時狀態(tài)。

4德频、本地倉庫操作(單機)

新建test目錄苍息,然后通過git init就可以初始化一個新的倉庫,此時會產(chǎn)生一個.git文件夾壹置,這個就是前面提到的git管理信息的目錄。下面會大概介紹git一般的工作流程表谊。

4.1 添加

現(xiàn)在在倉庫中新建文件content1.txt钞护,內(nèi)容為f1 content1

[root@localhost test]# git status
位于分支 master

初始提交

未跟蹤的文件:
  (使用 "git add <文件>..." 以包含要提交的內(nèi)容)

    content1.txt

提交為空爆办,但是存在尚未跟蹤的文件(使用 "git add" 建立跟蹤)

command 1难咕、git status

git status:可以查看workspace的狀態(tài),可以看到輸出顯示content1.txt未被git跟蹤距辆,然后提示可以使用git add把文件添加到暫存區(qū)以建立跟蹤余佃。

這里文件的第一個狀態(tài):處于工作區(qū)(workspace)中,暫存區(qū)(stage)沒有跨算,倉庫(repo)沒有爆土。

command 2、git add

git add file[/path]:可以將文件從工作區(qū)更新到暫存區(qū)诸蚕。使用git add content1.txt步势,然后繼續(xù)查看worksace的狀態(tài),這時發(fā)現(xiàn)文件已經(jīng)被存放在了暫存區(qū)背犯。

[root@localhost test]# git add content1.txt
[root@localhost test]# git status
位于分支 master

初始提交

要提交的變更:
  (使用 "git rm --cached <文件>..." 以取消暫存)

    新文件:   content1.txt

這里文件的第二個狀態(tài):工作區(qū)(workspace)坏瘩、暫存區(qū)(stage)有,倉庫(repo)沒有漠魏。

command 3倔矾、git commit

git commit:將暫存區(qū)文件提交到倉庫中。最后我們可以使用git commit -m content1.txt柱锹,然后繼續(xù)查看worksace的狀態(tài)哪自,這時發(fā)現(xiàn)文件已經(jīng)被存放在了倉庫中。

[root@localhost test]# git commit -m 'comtent1'
[master(根提交) 36f5265] comtent1

 1 file changed, 1 insertion(+)
 create mode 100644 content1.txt

[root@localhost test]# git status
位于分支 master
nothing to commit, working tree clean

這里文件的第三個狀態(tài):工作區(qū)(workspace)奕纫、暫存區(qū)(stage)提陶、倉庫(repo)都有。

通過上面的操作匹层,文件content1.txt成功被添加到了倉庫中隙笆。

4.1.1 git查看

下面作為觸探锌蓄,供后面講述git存儲原理使用。

[root@localhost test]# fing .git/objects/
bash: fing: 未找到命令...
[root@localhost test]# find .git/objects/
.git/objects/
.git/objects/pack
.git/objects/info
.git/objects/de
.git/objects/de/35f338a9d7d8d4faeea0b693f0494932748de5
.git/objects/2e
.git/objects/2e/688748738147fbf159038d82224e9ef728d3cc
.git/objects/36
.git/objects/36/f526581e2d29e5e6eaec7bcfaa51315d5de8b4
[root@localhost test]# git cat-file -t de35f338a9d7d8d4faeea0b693f0494932748de5
blob
[root@localhost test]# git cat-file -t 2e688748738147fbf159038d82224e9ef728d3cc
tree
[root@localhost test]# git cat-file -t 36f526581e2d29e5e6eaec7bcfaa51315d5de8b4
commit
[root@localhost test]# git cat-file -p 36f526581e2d29e5e6eaec7bcfaa51315d5de8b4
tree 2e688748738147fbf159038d82224e9ef728d3cc
author root <root@localhost.localdomain> 1508831813 +0800
committer root <root@localhost.localdomain> 1508831813 +0800

comtent1
[root@localhost test]# git cat-file -p 36f526581e2d29e5e6eaec7bcfaa51315d5de8b4
tree 2e688748738147fbf159038d82224e9ef728d3cc
author root <root@localhost.localdomain> 1508831813 +0800
committer root <root@localhost.localdomain> 1508831813 +0800

comtent1
[root@localhost test]# git cat-file -p de35f338a9d7d8d4faeea0b693f0494932748de5
f1 content1

4.2 更新

下面對content1.txt文件進行修改撑柔,內(nèi)容為f1 content1 now the file has been modified.瘸爽。修改完后,查看workspace的狀態(tài)铅忿,提示文件已經(jīng)修改但未提交剪决。

[root@localhost test]# git status
位于分支 master
尚未暫存以備提交的變更:
  (使用 "git add <文件>..." 更新要提交的內(nèi)容)
  (使用 "git checkout -- <文件>..." 丟棄工作區(qū)的改動)

    修改:     content1.txt

修改尚未加入提交(使用 "git add" 和/或 "git commit -a")

同樣,通過git add檀训、commit的操作柑潦,我們可以把工作區(qū)(workspace)文件的更新先存放到暫存區(qū),然后從暫存區(qū)(stage)提交到倉庫(repo)中峻凫。

[root@localhost test]# git add content1.txt
[root@localhost test]# git commit -m 'modified content1.txt' content1.txt
[master 2c4ee67] modified content1.txt

    git commit --amend --reset-author

 1 file changed, 2 insertions(+), 1 deletion(-)

4.2.1 git查看

[root@localhost test]# find .git/objects/
.git/objects/
.git/objects/pack
.git/objects/info
.git/objects/de
.git/objects/de/35f338a9d7d8d4faeea0b693f0494932748de5
.git/objects/2e
.git/objects/2e/688748738147fbf159038d82224e9ef728d3cc
.git/objects/36
.git/objects/36/f526581e2d29e5e6eaec7bcfaa51315d5de8b4
.git/objects/0b
.git/objects/0b/0a0c1d103a155ace75fc2e4738dfe64e3ee4a0
.git/objects/2f
.git/objects/2f/327c9eae9421634ff69b51a3edc4725e8c5703
.git/objects/2c
.git/objects/2c/4ee671dbbf37360e6b6b724d2c4f11d9d111ad
[root@localhost test]# git cat-file -t 0b0a0c1d103a155ace75fc2e4738dfe64e3ee4a0
blob
[root@localhost test]# git cat-file -t 2f327c9eae9421634ff69b51a3edc4725e8c5703
tree
[root@localhost test]# git cat-file -t 2c4ee671dbbf37360e6b6b724d2c4f11d9d111ad
commit
[root@localhost test]# git cat-file -p 2c4ee671dbbf37360e6b6b724d2c4f11d9d111ad
tree 2f327c9eae9421634ff69b51a3edc4725e8c5703
parent 36f526581e2d29e5e6eaec7bcfaa51315d5de8b4
author root <root@localhost.localdomain> 1508832742 +0800
committer root <root@localhost.localdomain> 1508832742 +0800

modified content1.txt
[root@localhost test]# git cat-file -p 2f327c9eae9421634ff69b51a3edc4725e8c5703
100644 blob 0b0a0c1d103a155ace75fc2e4738dfe64e3ee4a0    content1.txt
[root@localhost test]# git cat-file -p 0b0a0c1d103a155ace75fc2e4738dfe64e3ee4a0
f1 content1 
now the file has been modified.

4.2.2 文件版本對比

1渗鬼、工作區(qū)和暫存區(qū)

command 4、git diff

git diff :查看工作區(qū)和暫存區(qū)的文件的差異情況荧琼,當(dāng)我們把更新add到Stage中譬胎,diff就不會有任何輸出了。

[root@localhost test]# git diff

現(xiàn)修改文件內(nèi)容為f1 content1 now the file has been modified. git giff命锄。

[root@localhost test]# git diff
diff --git a/content1.txt b/content1.txt
index 0b0a0c1..cbbe1be 100644
--- a/content1.txt
+++ b/content1.txt
@@ -1,2 +1,3 @@
 f1 content1 
 now the file has been modified.
+git diff

2堰乔、工作區(qū)與倉庫

當(dāng)然我們也可以把工作區(qū)的文件跟倉庫中的文件做差異對比。

[root@localhost test]# git diff HEAD~1
diff --git a/content1.txt b/content1.txt
index de35f33..0b0a0c1 100644
--- a/content1.txt
+++ b/content1.txt
@@ -1 +1,2 @@
-f1 content1
+f1 content1 
+now the file has been modified.

4.3 撤銷更新

根據(jù)前面對git操作的了解脐恩,我們可以智道更新可能存在于三個地方镐侯,工作區(qū)(workspace)、暫存區(qū)(stage)和倉庫(repo)被盈。下面就分別界山怎么撤銷這些更新析孽。

確認(rèn)我們現(xiàn)在工作區(qū)(workspace)、暫存區(qū)(stage)和倉庫(repo)的文件內(nèi)容一致為:f1 content1 now the file has been modified.只怎。

4.3.1 撤銷工作區(qū)中的更新

先修改文件content1.txt內(nèi)容為new content1袜瞬,查看狀態(tài)。

[root@localhost test]# git status
位于分支 master
尚未暫存以備提交的變更:
  (使用 "git add <文件>..." 更新要提交的內(nèi)容)
  (使用 "git checkout -- <文件>..." 丟棄工作區(qū)的改動)

    修改:     content1.txt

修改尚未加入提交(使用 "git add" 和/或 "git commit -a")

command 5身堡、git checkout -- <file>

可以看到上面工作區(qū)狀態(tài)有提示:(使用 "git checkout -- <文件>..." 丟棄工作區(qū)的改動)邓尤,這里注意它的格式,'--'左右空格要保留贴谎。

[root@localhost test]# git checkout  -- content1.txt
[root@localhost test]# vim content1.txt 
[root@localhost test]# git status 
位于分支 master
nothing to commit, working tree clean

注意:使用這種方法的時候要慎重汞扎,因為通過這種方法撤銷后,工作區(qū)之前所作的修改將無法挽回擅这。

4.3.2 撤銷暫存區(qū)中的更新

先修改文件content1.txt內(nèi)容為new content1 stage澈魄,之后再git add提交,再查看狀態(tài)仲翎。

[root@localhost test]# git add content1.txt
[root@localhost test]# git status 
位于分支 master
要提交的變更:
  (使用 "git reset HEAD <文件>..." 以取消暫存)

    修改:     content1.txt

從輸出中提示我們可以通過git reset HEAD <file>…把暫存區(qū)的更新移出到工作區(qū)中痹扇。

command 5铛漓、git reset HEAD <file>…

[root@localhost test]# git reset HEAD content1.txt
重置后取消暫存的變更:
M   content1.txt
[root@localhost test]# git status 
位于分支 master
尚未暫存以備提交的變更:
  (使用 "git add <文件>..." 更新要提交的內(nèi)容)
  (使用 "git checkout -- <文件>..." 丟棄工作區(qū)的改動)

    修改:     content1.txt

注意:若撤銷前,文件又被修改鲫构,此操作只是將相應(yīng)文件從暫存區(qū)移除浓恶,不會影響到工作區(qū)最新的已被修改文件。

4.3.3 撤銷倉庫中的更新

介紹repo的更新之前结笨,我們可以先看下git log這個命令包晰。

command 6、git log

git log:可以查看commit的歷史記錄炕吸。

[root@localhost test]# git log
commit 2c4ee671dbbf37360e6b6b724d2c4f11d9d111ad
Author: root <root@localhost.localdomain>
Date:   Tue Oct 24 16:12:22 2017 +0800

    modified content1.txt

commit 36f526581e2d29e5e6eaec7bcfaa51315d5de8b4
Author: root <root@localhost.localdomain>
Date:   Tue Oct 24 15:56:53 2017 +0800

    comtent1

假設(shè)我們要撤銷修改文件的那次提交伐憾,即倉庫中要只留有一次提交版本,內(nèi)容為f1 content1算途。

有兩種方式:使用HEAD指針和使用commit id塞耕。

command 7、git reset --hard

1嘴瓤、HEAD指針

當(dāng)前版本,我們使用HEAD^莉钙,那么再前一個版本可以使用HEAD^^廓脆,如果想回退到更早的提交,可以使用HEAD~n磁玉。(也就是停忿,HEAD=HEAD~1,HEAD^=HEAD~2)

2蚊伞、commit id

即根據(jù)文件內(nèi)容或目錄結(jié)構(gòu)計算得出的40位16進制hash值席赂。

git reset --hard HEAD^                          # 前一個版本

等價:

git reset --hard 36f526581e2d29e5e6eaec7bcfaa51315d5de8b4 # 前一個版本

[root@localhost test]# git reset --hard 2c4ee671dbbf37360e6b6b724d2c4f11d9d111ad
HEAD 現(xiàn)在位于 2c4ee67 modified content1.txt
[root@localhost test]# git log
commit 2c4ee671dbbf37360e6b6b724d2c4f11d9d111ad
Author: root <root@localhost.localdomain>
Date:   Tue Oct 24 16:12:22 2017 +0800

    modified content1.txt

commit 36f526581e2d29e5e6eaec7bcfaa51315d5de8b4
Author: root <root@localhost.localdomain>
Date:   Tue Oct 24 15:56:53 2017 +0800

    comtent1
[root@localhost test]# git reset --hard HEAD^
HEAD 現(xiàn)在位于 36f5265 comtent1
[root@localhost test]# git log
commit 36f526581e2d29e5e6eaec7bcfaa51315d5de8b4
Author: root <root@localhost.localdomain>
Date:   Tue Oct 24 15:56:53 2017 +0800

    comtent1

此時查看工作區(qū)文件,內(nèi)容已經(jīng)變成最初的狀態(tài)时迫,內(nèi)容為:f1 content颅停。

4.3.4 倉庫版本的恢復(fù)

假設(shè)現(xiàn)在你又想要恢復(fù)內(nèi)容為f1 content1 now the file has been modified.這個提交了,當(dāng)然git是支持這樣的操作掠拳。

command 8癞揉、git reflog

git refloggit log只是包括了當(dāng)前分支中的commit記錄,而git reflog中會記錄這個倉庫所有分支的所有更新記錄溺欧,包括已經(jīng)撤銷的更新喊熟。

[root@localhost test]# git reflog
36f5265 HEAD@{0}: reset: moving to HEAD^
2c4ee67 HEAD@{1}: commit: modified content1.txt
36f5265 HEAD@{2}: commit (initial): comtent1

我們可以使用下面的命令:

git reset --hard HEAD@{1}

等價于:

git reset --hard 2c4ee67

[root@localhost test]# git reset --hard HEAD@{1}
HEAD 現(xiàn)在位于 2c4ee67 modified content1.txt

[root@localhost test]# git log
commit 2c4ee671dbbf37360e6b6b724d2c4f11d9d111ad
Author: root <root@localhost.localdomain>
Date:   Tue Oct 24 16:12:22 2017 +0800

    modified content1.txt

commit 36f526581e2d29e5e6eaec7bcfaa51315d5de8b4
Author: root <root@localhost.localdomain>
Date:   Tue Oct 24 15:56:53 2017 +0800

    comtent1

恩、最后content1.txt的內(nèi)容還是內(nèi)容為f1 content1 now the file has been modified.姐刁。

–hard和–soft

前面在使用reset來撤銷更新的時候芥牌,我們都是使用的“–hard”選項,其實與之對應(yīng)的還有一個“–soft”選項聂使,區(qū)別如下:

  • –hard:撤銷并刪除相應(yīng)的更新壁拉。
  • –soft:撤銷相應(yīng)的更新谬俄,把這些更新的內(nèi)容放的Stage中。

4.4 刪除文件

在Git中扇商,如果我們要刪除一個文件凤瘦,可以使用下面的命令,“git rm”相比“rm”只是多了一步,把這次刪除的更新發(fā)到Stage中案铺。

rm <file>                   # 這個在linux下直接變成要刪除文件蔬芥。

git rm <file>

command 9、rm <file>

[root@localhost test]# git rm content1.txt
rm 'content1.txt'
[root@localhost test]# git status
位于分支 master
要提交的變更:
  (使用 "git reset HEAD <文件>..." 以取消暫存)

    刪除:     content1.txt

[root@localhost test]# git commit -m 'delete content1.txt'
[master 86c41ea] delete content1.txt
 Committer: root <root@localhost.localdomain>
您的姓名和郵件地址基于登錄名和主機名進行了自動設(shè)置控汉。請檢查它們正確
與否笔诵。您可以對其進行設(shè)置以免再出現(xiàn)本提示信息。運行如下命令在編輯器
中編輯您的配置文件:

    git config --global --edit

設(shè)置完畢后姑子,您可以用下面的命令來修正本次提交所使用的用戶身份:

    git commit --amend --reset-author

 1 file changed, 2 deletions(-)
 delete mode 100644 content1.txt
[root@localhost test]# git log
commit 86c41eade0390d2a9c15ba3385ccdce9bca73cbf
Author: root <root@localhost.localdomain>
Date:   Tue Oct 24 17:17:33 2017 +0800

    delete content1.txt

commit 2c4ee671dbbf37360e6b6b724d2c4f11d9d111ad
Author: root <root@localhost.localdomain>
Date:   Tue Oct 24 16:12:22 2017 +0800

    modified content1.txt

commit 36f526581e2d29e5e6eaec7bcfaa51315d5de8b4
Author: root <root@localhost.localdomain>
Date:   Tue Oct 24 15:56:53 2017 +0800

    comtent1

4.5 操作總結(jié)圖

git基本操作圖

5乎婿、git對象模型

5.1 git對象

在git系統(tǒng)中有4種類型的對象,所有的git操作都是基于這四種類型的對象街佑。

  • blob:用來保存文件內(nèi)容的對象谢翎。
  • tree:可以理解為一個關(guān)系對象樹,它管理一些tree和blob對象沐旨。
  • commit:只指向一個tree森逮,他用來標(biāo)記項目某一個特定時間點的狀態(tài)。它包括一些關(guān)于時間點的元數(shù)據(jù)磁携,如時間戳褒侧、最近一次提交的作者、指向上次提交(初始commit沒有這一項)谊迄。
  • tag:給某個提交(commit)增添一個標(biāo)記闷供。

5.2 SHA1哈希值

前面介紹了git對象實例,在git系統(tǒng)中统诺,每個git對象都有一個特殊的ID來代表這個對象歪脏。這個特殊的ID就是我們所說的哈希值。

SHA1哈希值就通過SHA1算法計算出來的哈希值篙议,對于內(nèi)容不同的對象唾糯,會有不同的哈希值,它是40位長的16進制字符表示的字符串鬼贱。

5.3 git對象模型實例

重溫下1.2.2 版本控制的原理章節(jié)移怯,git的版本控制原理可能會對你理解下面的內(nèi)容有所幫助。

1这难、初始化新建gitob倉庫舟误,新建file.txt文件,內(nèi)容為content1姻乓。由工作區(qū)將file.txt提交到暫存區(qū)嵌溢,再提交到倉庫眯牧。生成了三個對象:blob(ac3e272)、tree(922e768)赖草、commit(43d5d50)学少。

[root@localhost home]# mkdir gitob
[root@localhost home]# cd gitob/
[root@localhost gitob]# git init 
初始化空的 Git 倉庫于 /home/gitob/.git/
[root@localhost gitob]# find .git/objects/
.git/objects/
.git/objects/pack
.git/objects/info
[root@localhost gitob]# echo "content1" >> file.txt
[root@localhost gitob]# git add file.txt
[root@localhost gitob]# git commit -m 'file content1'
[master(根提交) 43d5d50] file content1
 Committer: root <root@localhost.localdomain>
 1 file changed, 1 insertion(+)
 create mode 100644 file.txt
[root@localhost gitob]# find .git/objects/
.git/objects/
.git/objects/pack
.git/objects/info
.git/objects/ac
.git/objects/ac/3e272b72bbf89def8657766b855d0656630ed4
.git/objects/92
.git/objects/92/2e7684388b51938e7442eb310513d8a965971d
.git/objects/43
.git/objects/43/d5d5076eaa085fef9f26fbd807d5babc58eb5a
[root@localhost gitob]# git log --pretty=raw
commit 43d5d5076eaa085fef9f26fbd807d5babc58eb5a
tree 922e7684388b51938e7442eb310513d8a965971d
author root <root@localhost.localdomain> 1508845030 +0800
committer root <root@localhost.localdomain> 1508845030 +0800

    file content1

[root@localhost gitob]# git cat-file -p 922e7684388b51938e7442eb310513d8a965971d
100644 blob ac3e272b72bbf89def8657766b855d0656630ed4    file.txt
[root@localhost gitob]# git cat-file -p ac3e272b72bbf89def8657766b855d0656630ed4
content1

2、這一步對file.txt做出追加修改秧骑,內(nèi)容為content2版确。由工作區(qū)將file.txt提交到暫存區(qū),再提交到倉庫乎折。生成了三個對象:blob(fa8797f)绒疗、tree(fa0bbc8)、commit(336400b)骂澄,這里注意查看commit歷史時吓蘑,它又又有一個屬性parent 43d5d50指向上面那個commit對象。

[root@localhost gitob]# echo 'content2' >> file.txt
[root@localhost gitob]# ll
總用量 4
-rw-r--r-- 1 root root 18 10月 24 20:02 file.txt
[root@localhost gitob]# git add file.txt
[root@localhost gitob]# git commit -m 'comment2'
[master 336400b] comment2
 Committer: root <root@localhost.localdomain>

 1 file changed, 1 insertion(+)

[root@localhost gitob]# git log --pretty=raw
commit 336400b0b36e8f6cfe683fa5127bad6fb235060c
tree fa0bbc8e85135d5ed51a4f13ec9227917d8f4b57
parent 43d5d5076eaa085fef9f26fbd807d5babc58eb5a
author root <root@localhost.localdomain> 1508846561 +0800
committer root <root@localhost.localdomain> 1508846561 +0800

    comment2

commit 43d5d5076eaa085fef9f26fbd807d5babc58eb5a
tree 922e7684388b51938e7442eb310513d8a965971d
author root <root@localhost.localdomain> 1508845030 +0800
committer root <root@localhost.localdomain> 1508845030 +0800

    file content1

[root@localhost gitob]# git cat-file -p fa0bbc8e85135d5ed51a4f13ec9227917d8f4b57
100644 blob fa8797f68cd826a3ac7713bdfdb9ddb43b146752    file.txt
[root@localhost gitob]# git cat-file -p fa8797f68cd826a3ac7713bdfdb9ddb43b146752
content1

3坟冲、這一步新建newfile.txt磨镶,內(nèi)容為content3;新建advance文件夾健提;在advance下棋嘲,新建test.txt,內(nèi)容為content4矩桂;新建file.txt,內(nèi)容為content5痪伦;再提交到暫存區(qū)侄榴,再提交到倉庫。生成了6個對象:blob(27d10cc)网沾、tree(4a5ca33)癞蚕、commit(406ad4f),這里注意查看commit歷史時辉哥,它又又有一個屬性parent 336400b指向上面修改文件之后的那個commit對象桦山。tree(4a5ca33)又包含tree(494b5f9)、blob(7f3886d)醋旦、blob(9cce852)恒水。

[root@localhost gitob]# echo 'content3' >> newfile.txt
[root@localhost gitob]# mkdir advance
[root@localhost gitob]# echo 'content4' >> ./advance/test.txt
[root@localhost gitob]# echo 'content5' >> ./advance/file.txt

[root@localhost gitob]# git add .
[root@localhost gitob]# git commit -m 'third op' .
[master 406ad4f] third op
 Committer: root <root@localhost.localdomain>

 3 files changed, 3 insertions(+)
 create mode 100644 advance/file.txt
 create mode 100644 advance/test.txt
 create mode 100644 newfile.txt

[root@localhost gitob]# git log --pretty=raw
commit 406ad4f261d9f2ced79f8b73b9b8a5a0adfdc9e1
tree 4a5ca33cc59ec2b01900e65ec75266090ccc8a7a
parent 336400b0b36e8f6cfe683fa5127bad6fb235060c
author root <root@localhost.localdomain> 1508847505 +0800
committer root <root@localhost.localdomain> 1508847505 +0800

    third op

commit 336400b0b36e8f6cfe683fa5127bad6fb235060c
tree fa0bbc8e85135d5ed51a4f13ec9227917d8f4b57
parent 43d5d5076eaa085fef9f26fbd807d5babc58eb5a
author root <root@localhost.localdomain> 1508846561 +0800
committer root <root@localhost.localdomain> 1508846561 +0800

    comment2

commit 43d5d5076eaa085fef9f26fbd807d5babc58eb5a
tree 922e7684388b51938e7442eb310513d8a965971d
author root <root@localhost.localdomain> 1508845030 +0800
committer root <root@localhost.localdomain> 1508845030 +0800

    file content1

[root@localhost gitob]# git cat-file -p 4a5ca33cc59ec2b01900e65ec75266090ccc8a7a
040000 tree 494b5f973f06cc02664b393e4fc0b174dde85218    advance
100644 blob fa8797f68cd826a3ac7713bdfdb9ddb43b146752    file.txt
100644 blob 27d10cc8d0f10540c1fce1aa6de5e8f3e6b655ba    newfile.txt
[root@localhost gitob]# git cat-file -p 494b5f973f06cc02664b393e4fc0b174dde85218
100644 blob 7f3886d9cc49b5817001f0fc16c637290e4200b0    file.txt
100644 blob 9cce8524a4871530843e41906f1c3e07af4849de    test.txt
[root@localhost gitob]# git cat-file -p 27d10cc8d0f10540c1fce1aa6de5e8f3e6b655ba
content3
[root@localhost gitob]# git cat-file -p 7f3886d9cc49b5817001f0fc16c637290e4200b0
content5
[root@localhost gitob]# git cat-file -p 9cce8524a4871530843e41906f1c3e07af4849de
content4

4、關(guān)系示意圖

git對象模型

git對象模型就像是git系統(tǒng)特有的文件系統(tǒng)饲齐,以特定的方式存儲更新的內(nèi)容钉凌、元數(shù)據(jù)以及版本歷史信息。

6捂人、探索倉庫.git目錄

6.1 git目錄基本介紹

下面探索git目錄御雕,這里接著5矢沿、git對象結(jié)構(gòu)模型里面的文件進行。

[root@localhost gitob]# ls -al
總用量 8
drwxr-xr-x  4 root root  64 10月 24 20:16 .
drwxr-xr-x. 7 root root  71 10月 24 19:30 ..
drwxr-xr-x  2 root root  36 10月 24 20:17 advance
-rw-r--r--  1 root root  18 10月 24 20:02 file.txt
drwxr-xr-x  8 root root 155 10月 24 20:18 .git
-rw-r--r--  1 root root   9 10月 24 20:16 newfile.txt
[root@localhost .git]# ls -al
總用量 24
drwxr-xr-x  8 root root  155 10月 24 20:18 .
drwxr-xr-x  4 root root   64 10月 24 20:16 ..
drwxr-xr-x  2 root root    6 10月 24 19:32 branches
-rw-r--r--  1 root root    9 10月 24 20:18 COMMIT_EDITMSG
-rw-r--r--  1 root root   92 10月 24 19:32 config
-rw-r--r--  1 root root   73 10月 24 19:32 description
-rw-r--r--  1 root root   23 10月 24 19:32 HEAD
drwxr-xr-x  2 root root 4096 10月 24 19:32 hooks
-rw-r--r--  1 root root  409 10月 24 20:18 index
drwxr-xr-x  2 root root   20 10月 24 19:32 info
drwxr-xr-x  3 root root   28 10月 24 19:37 logs
drwxr-xr-x 15 root root  127 10月 24 20:18 objects
drwxr-xr-x  4 root root   29 10月 24 19:32 refs

對于這些文件和目錄酸纲,先進行一些基本的描述捣鲸,在之后有更詳細的介紹。

  • (d)hooks:這個目錄存放一些shell腳本闽坡,可以設(shè)置特定的git命令發(fā)出后響應(yīng)的腳本栽惶,在搭建gitweb或其它git托管系統(tǒng)經(jīng)常用到,即鉤子无午。

  • (d)info:包含一些倉庫的信息媒役。

  • (d)logs:保存所有更新的引用記錄。

  • (d)objects:所有的git對象都會放在這個目錄中宪迟,對象的hash值的前兩位是文件夾的名稱酣衷,后38位作為對象的文件名。這里注意完整的hash值仍是40位整的次泽。

  • (d)refs:這個目錄一般包含三個子目錄:heads穿仪、remotes和tags,heads中的文件標(biāo)識了項目中各個分支指向的當(dāng)前commit意荤。

  • (d)branches:存放一個倉庫的各個分支啊片。

  • (f)COMMIT_EDITMSG:保存最新的commit messsage,git系統(tǒng)不會用到這個文件夾玖像,只是給用戶的一個參考紫谷。

  • (f)config:倉庫的配置文件。

  • (f)description:倉庫的描述信息捐寥,主要給gitweb等git托管系統(tǒng)使用泞辐。

  • (f)HEAD:這個文件包含了一個當(dāng)前分支(branch)的作用遥昧,通過這個文件git可以找到下一次commmit的parent。

  • (f)index:這個文件就是我們前面提到的暫存區(qū)(stage),是一個二進制文件晚碾。

6.2 git引用

git引用是非常重要的概念浆劲,對于理解分支智袭、HEAD指針以及reflog非常有幫助逻族。

git系統(tǒng)中的分支名、遠程分支名束昵、tag等都是指向某個commit的引用拔稳,比如master分支,origin/master妻怎,命名為v1.0的tag等都是引用壳炎,它們通過保存某個commit的SHA1哈希值指向某個commit。

6.2.1 重新認(rèn)識HEAD

HEAD也是一個一用,一般情況下間接指向你當(dāng)前所在的分支的最新的commit上匿辩。HEAD跟git中一般的引用不同腰耙,它并不包含某個commit的SHA1哈希值,而是包含當(dāng)前所在的分支铲球,所以HEAD直接指向當(dāng)前所在的分支挺庞,然后簡介指向當(dāng)前分支的最新提交。

下面實例解釋上面的內(nèi)容稼病,首先查看‘.git/HEAD’的內(nèi)容选侨。

[root@localhost gitob]# cat .git/HEAD 
ref: refs/heads/master

這里表示HEAD指向一個master分支的引用,然后我們可以根據(jù)引用路徑打開‘.git/refs/heads/master’文件然走,內(nèi)容如下:

[root@localhost gitob]# cat .git/refs/heads/master 
406ad4f261d9f2ced79f8b73b9b8a5a0adfdc9e1

我們利用git log查看各個commit的哈希值援制,可以看出上面的commit正是指向master分支上最新的提交406ad4f261d9f2ced79f8b73b9b8a5a0adfdc9e1

[root@localhost gitob]# git log
commit 406ad4f261d9f2ced79f8b73b9b8a5a0adfdc9e1
Author: root <root@localhost.localdomain>
Date:   Tue Oct 24 20:18:25 2017 +0800

    third op

commit 336400b0b36e8f6cfe683fa5127bad6fb235060c
Author: root <root@localhost.localdomain>
Date:   Tue Oct 24 20:02:41 2017 +0800

    comment2

commit 43d5d5076eaa085fef9f26fbd807d5babc58eb5a
Author: root <root@localhost.localdomain>
Date:   Tue Oct 24 19:37:10 2017 +0800

    file content1

所以所有的內(nèi)容環(huán)環(huán)相扣芍瑞,我們通過HEAD找到當(dāng)前分支晨仑,然后通過當(dāng)前分支的引用找到最新的commit,然后通過commit找到整個對象關(guān)系模型拆檬,對應(yīng)下圖洪己。

git對象模型之HEAD

6.2.2 引用與分支

分支在下節(jié)會描述,這節(jié)直接先使用竟贯,下面會大概介紹下引用與分支的關(guān)系答捕。

[root@localhost gitob]# git branch bugfix           # 新建分支
[root@localhost gitob]# git checkout bugfix         # 切換到bugfix分支
切換到分支 'bugfix'

在上面我們新建了一個bugfix的分支,然后切換到了這個分支中屑那,那我們再次查看refs/heads/目錄可以看到除了master分支外拱镐,又多出一個bugfix的分支文件,其文件的內(nèi)容也是一個哈希值持际。

[root@localhost gitob]# cd .git/refs/heads/         # 查看ref/heads目錄中的分支
[root@localhost heads]# ll
總用量 8
-rw-r--r-- 1 root root 41 10月 26 13:36 bugfix
-rw-r--r-- 1 root root 41 10月 24 20:18 master
[root@localhost heads]# cd -
/home/gitob

通過git show-ref --heads命令就可以看到所有的頭痢站。

[root@localhost gitob]# git show-ref --heads        # 查看所有的分支頭
406ad4f261d9f2ced79f8b73b9b8a5a0adfdc9e1 refs/heads/bugfix
406ad4f261d9f2ced79f8b73b9b8a5a0adfdc9e1 refs/heads/master

根據(jù)前面的概念,HEAD指向當(dāng)前分支的最新提交选酗,即現(xiàn)在我們查看HEAD值的話就是下面這樣。

[root@localhost gitob]# cat .git/HEAD               # 當(dāng)前頭指向分支
ref: refs/heads/bugfix

6.2.3 再看reflog

在第4節(jié)中岳枷,已經(jīng)說過如何根據(jù)reflog去得到一個commit的哈希值芒填,然后把repo退回到指定的版本狀態(tài)。

下面我們切到.git/logs文件夾空繁,可以看到這個文件夾也有一個HEAD文件和refs目錄殿衰,這些就是記錄reflog的地方。

查看HEAD文件的內(nèi)容盛泡,會發(fā)現(xiàn)這個文件將會包含所有分支的reflog記錄闷祥。

[root@localhost gitob]# cd .git/logs/
[root@localhost logs]# vim HEAD 

0000000000000000000000000000000000000000 43d5d5076eaa085fef9f26fbd807d5babc58eb5a root <root@localhost.localdomain> 1508845030 +0800    commit (initial): file content1
43d5d5076eaa085fef9f26fbd807d5babc58eb5a 336400b0b36e8f6cfe683fa5127bad6fb235060c root <root@localhost.localdomain> 1508846561 +0800    commit: comment2
336400b0b36e8f6cfe683fa5127bad6fb235060c 406ad4f261d9f2ced79f8b73b9b8a5a0adfdc9e1 root <root@localhost.localdomain> 1508847505 +0800    commit: third op
406ad4f261d9f2ced79f8b73b9b8a5a0adfdc9e1 406ad4f261d9f2ced79f8b73b9b8a5a0adfdc9e1 root <root@localhost.localdomain> 1508996182 +0800    checkout: moving from master to bugfix

進入.git/logs/refs/heads目錄,同樣會有master和bugfix兩個文件,兩個文件將會保存各自分支的reflog記錄凯砍。內(nèi)容記錄分別如下:

[root@localhost heads]# cat master 
0000000000000000000000000000000000000000 43d5d5076eaa085fef9f26fbd807d5babc58eb5a root <root@localhost.localdomain> 1508845030 +0800    commit (initial): file content1
43d5d5076eaa085fef9f26fbd807d5babc58eb5a 336400b0b36e8f6cfe683fa5127bad6fb235060c root <root@localhost.localdomain> 1508846561 +0800    commit: comment2
336400b0b36e8f6cfe683fa5127bad6fb235060c 406ad4f261d9f2ced79f8b73b9b8a5a0adfdc9e1 root <root@localhost.localdomain> 1508847505 +0800    commit: third op
[root@localhost heads]# cat bugfix 
0000000000000000000000000000000000000000 406ad4f261d9f2ced79f8b73b9b8a5a0adfdc9e1 root <root@localhost.localdomain> 1508996177 +0800    branch: Created from master

6.2.4 索引(index)

前面說過index/stage箱硕,就是更新的暫存區(qū),下面就來看下index文件悟衩。這里已經(jīng)將當(dāng)前分支恢復(fù)到了master剧罩。

index(索引)是一個存放了以排序路徑的二進制文件,并且每個路徑都對應(yīng)一個SHA1哈希值座泳,在git系統(tǒng)中惠昔,可以通過git ls-files --stage來查看index文件的內(nèi)容。

[root@localhost .git]# git ls-files --stage
100644 7f3886d9cc49b5817001f0fc16c637290e4200b0 0   advance/file.txt
100644 9cce8524a4871530843e41906f1c3e07af4849de 0   advance/test.txt
100644 fa8797f68cd826a3ac7713bdfdb9ddb43b146752 0   file.txt
100644 27d10cc8d0f10540c1fce1aa6de5e8f3e6b655ba 0   newfile.txt

從上面的結(jié)果可以看出挑势,所有的記錄都對應(yīng)倉庫的文件(包括全路徑)镇防。通過git cat-file命令可以查看某個文件對應(yīng)的哈希值,這個哈希值就是代表這個文件所在的blob對象潮饱。

[root@localhost .git]# git cat-file -t fa8797f68cd826a3ac7713bdfdb9ddb43b146752
blob
[root@localhost .git]# git cat-file -p fa8797f68cd826a3ac7713bdfdb9ddb43b146752
content1
content2

下面修改file.txt文件来氧,添加提交,其哈希值已經(jīng)發(fā)生變化饼齿。

[root@localhost gitob]# cat file.txt 
content1
content2

stage
[root@localhost gitob]# git add file.txt 
[root@localhost gitob]# git commit -m 'stage update'
[master d540063] stage update
 Committer: root <root@localhost.localdomain>

 1 file changed, 2 insertions(+)

再查看暫存區(qū)index中其對應(yīng)的文件饲漾。

[root@localhost gitob]# git ls-files --stage
100644 7f3886d9cc49b5817001f0fc16c637290e4200b0 0   advance/file.txt
100644 9cce8524a4871530843e41906f1c3e07af4849de 0   advance/test.txt
100644 a458c3d38d26fcac12c94af976c8cc580c5be30a 0   file.txt
100644 27d10cc8d0f10540c1fce1aa6de5e8f3e6b655ba 0   newfile.txt
[root@localhost gitob]# git cat-file -t a458c3d38d26fcac12c94af976c8cc580c5be30a
blob
[root@localhost gitob]# git cat-file -p a458c3d38d26fcac12c94af976c8cc580c5be30a
content1
content2

stage

這個例子我們可以理解之前diff操作會有怎樣的變化。

  • git diff:比較workspace和stage缕溉,add之前有diff輸出考传;add之后沒有diff輸出。
  • git diff HEAD:比較workspace和repo证鸥,add之前之后都有diff輸出僚楞。
  • git diff --cached:比較stage和repo,add之前沒有diff輸出枉层;add之后有diff輸出泉褐。

6.3 git對象存儲

之前提到git所有的對象都會放在.git/objects的目錄中,對象SHA1的哈希值是文件夾名稱鸟蜡,后38位作為對象文件名膜赃。上述所有的對象都可以這么找到。

在git系統(tǒng)中有兩種存儲對象的方式揉忘,松散對象和打包對象存儲跳座。

6.3.1 松散對象(loose object)

松散隨想存儲就是前面提到的每個對象都被寫入一個單獨文件中,對象SHA1哈希值的前兩位是文件夾的名稱泣矛,后38位作為對象文件名疲眷。

6.3.2 打包對象(packed object)

對于松散對象,把每個文件的每個版本都作為一個單獨的對象您朽,它的效率比較低狂丝,而且浪費空間,所有就有了打包文件的存儲方式。

git使用打包文件(packfile)去節(jié)省空間几颜,在這個格式中倍试,git只會保存第二個文件中改變了的部分,然后用一個指針指向相似的那個文件菠剩。

一般的git系統(tǒng)中會自動完成打包的工作易猫,在已經(jīng)發(fā)生打包的git倉庫中,.git/objects/pack目錄下會成對出現(xiàn)跟對‘pack-?.idx’和‘pack-?.pack’文件具壮,再具體這里不做介紹准颓。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市棺妓,隨后出現(xiàn)的幾起案子攘已,更是在濱河造成了極大的恐慌,老刑警劉巖怜跑,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件样勃,死亡現(xiàn)場離奇詭異,居然都是意外死亡性芬,警方通過查閱死者的電腦和手機峡眶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來植锉,“玉大人辫樱,你說我怎么就攤上這事】”樱” “怎么了狮暑?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長辉饱。 經(jīng)常有香客問我搬男,道長,這世上最難降的妖魔是什么彭沼? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任缔逛,我火速辦了婚禮,結(jié)果婚禮上姓惑,老公的妹妹穿的比我還像新娘译株。我一直安慰自己,他們只是感情好挺益,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著乘寒,像睡著了一般望众。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天烂翰,我揣著相機與錄音夯缺,去河邊找鬼。 笑死甘耿,一個胖子當(dāng)著我的面吹牛踊兜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播佳恬,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼捏境,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了毁葱?” 一聲冷哼從身側(cè)響起垫言,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎倾剿,沒想到半個月后筷频,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡前痘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年凛捏,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芹缔。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡坯癣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出乖菱,到底是詐尸還是另有隱情坡锡,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布窒所,位于F島的核電站鹉勒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏吵取。R本人自食惡果不足惜禽额,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望皮官。 院中可真熱鬧脯倒,春花似錦、人聲如沸捺氢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽摄乒。三九已至悠反,卻和暖如春残黑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背斋否。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工梨水, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人茵臭。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓疫诽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親旦委。 傳聞我的和親對象是個殘疾皇子奇徒,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容