自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Git歷險記(4):索引與提交的那些事

系統(tǒng) Linux
本文是《Git歷險記》的第四篇,前三篇文章從初識、安裝、設置Git談起,并介紹了git add,git commit這兩個命令。但是對這兩個命令幕后還有很多有趣的細節(jié),本文將一一介紹。以下是原文。

編者按:本文是《Git歷險記》的第四篇,前三篇文章從初識、安裝、設置Git談起,并介紹了git add,git commit這兩個命令。但是對這兩個命令幕后還有很多有趣的細節(jié),本文將一一介紹。以下是原文。

 不一樣的索引

我想如果看過《Git歷險記》的前面三篇文章的朋友可能已經知道怎么用git add,git commit這兩個命令了;知道它們一個是把文件暫存到索引中為下一次提交做準備,一個創(chuàng)建新的提交(commit)。但是它們臺前幕后的一些有趣的細節(jié)大家不一定知曉,請允許我一一道來。

Git 索引是一個在你的工作目錄(working tree)和項目倉庫間的暫存區(qū)域(staging area)。有了它, 你可以把許多內容的修改一起提交(commit)。 如果你創(chuàng)建了一個提交(commit),那么提交的一般是暫存區(qū)里的內容, 而不是工作目錄中的內容。

一個Git項目中文件的狀態(tài)大概分成下面的兩大類,而第二大類又分為三小類:

1、未被跟蹤的文件(untracked file)

2、已被跟蹤的文件(tracked file)

             1、被修改但未被暫存的文件(changed but not updated或modified)

             2、已暫存可以被提交的文件(changes to be committed 或staged)

             3、自上次提交以來,未修改的文件(clean 或 unmodified)

看到上面的這么多的規(guī)則,大家早就頭大了吧。老辦法,我們建一個Git測試項目來試驗一下:

我們先來建一個空的項目:

$rm -rf stage_proj
$mkdir stage_proj
$cd stage_proj
$git init
Initialized empty Git repository in /home/test/work/test_stage_proj/.git/

我們還創(chuàng)建一個內容是“hello, world”的文件:

$echo "hello,world" > readme.txt

現(xiàn)在來看一下當前工作目錄的狀態(tài),大家可以看到“readme.txt”處于未被跟蹤的狀態(tài)(untracked file):

$git status
# On branch master
#
# Initial commit
#
# Untracked files:
# (use "git add ..." to include in what will be committed)
#
# readme.txt
nothing added to commit but untracked files present (use "git add" to track)

把“readme.txt"加到暫存區(qū): $git add readme.txt

現(xiàn)在再看一下當前工作目錄的狀態(tài):

$git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
# (use "git rm --cached ..." to unstage)
#
# new file: readme.txt
#

可以看到現(xiàn)在"readme.txt"的狀態(tài)變成了已暫存可以被提交(changes to be committed),這意味著我們下一步可以直接執(zhí)行“git commit“把這個文件提交到本地的倉庫里去了。

暫存區(qū)(staging area)一般存放在“git目錄“下的index文件(.git/index)中,所以我們把暫存區(qū)有時也叫作索引(index)。索引是一個二進制格式的文件,里面存放了與當前暫存內容相關的信息,包括暫存的文件名、文件內容的SHA1哈希串值和文件訪問權限,整個索引文件的內容以暫存的文件名進行排 序保存的。

但是我不想馬上就把文件提交,我想看一下暫存區(qū)(staging area)里的內容,我們執(zhí)行git ls-files命令看一下:

$git ls-files --stage
100644 2d832d9044c698081e59c322d5a2a459da546469 0 readme.txt

我們如果有看過上一篇文章里 的"庖丁解牛", 你會發(fā)現(xiàn)“git目錄“里多出了”.git/objects/2d/832d9044c698081e59c322d5a2a459da546469”這么一個文件,再執(zhí)行“git cat-file -p 2d832d” 的話,就可以看到里面的內容正是“hello,world"。Git在把一個文件添加暫存區(qū)時,不但把它在索引文件(.git/index)里掛了號,而且把它的內容先保存到了“git目錄“里面去了。

如果我們執(zhí)行”git add“命令時不小心把不需要的文件也加入到暫存區(qū)中話,可以執(zhí)行“git rm --cached filename" 來把誤添加的文件從暫存區(qū)中移除。

現(xiàn)在我們先在"readme.txt"文件上做一些修改后:

$echo "hello,world2" >> readme.txt

再來看一下暫存區(qū)的變化:

$git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
# (use "git rm --cached ..." to unstage)
#
# new file: readme.txt
#
# Changed but not updated:
# (use "git add ..." to update what will be committed)
# (use "git checkout -- ..." to discard changes in working directory)
#
# modified: readme.txt
#

大家可以看到命令輸出里多了一塊內容:“changed but not updated ...... modified: readme.txt”。大家可能會覺得很奇怪,我前面不是把"readme.txt"這個文件給添加到暫存區(qū)里去了嗎,這里怎么又提示我未添加到暫存區(qū) (changed but not updated)呢,是不是Git搞錯了呀。

Git 沒有錯,每次執(zhí)行“git add”添加文件到暫存區(qū)時,它都會把文件內容進行SHA1哈希運算,在索引文件中新加一項,再把文件內容存放到本地的“git目錄“里。如果在上次執(zhí)行 “git add”之后再對文件的內容進行了修改,那么在執(zhí)行“git status”命令時,Git會對文件內容進行SHA1哈希運算就會發(fā)現(xiàn)文件又被修改了,這時“readme.txt“就同時呈現(xiàn)了兩個狀態(tài):被修改但未被暫存的文件(changed but not updated),已暫存可以被提交的文件(changes to be committed)。如果我們這時提交的話,就是只會提交***次“git add"所以暫存的文件內容。

我現(xiàn)在對于“hello,world2"的這個修改不是很滿意,想要撤消這個修改,可以執(zhí)行git checkout這個命令:

$git checkout -- readme.txt

現(xiàn)在再來看一下倉庫里工作目錄的狀態(tài):

$git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
# (use "git rm --cached ..." to unstage)
#
# new file: readme.txt
#

好的,現(xiàn)在項目恢復到我想要的狀態(tài)了,下面我就用git commit 命令把這個修改提交了吧:

$git commit -m "project init"
[master (root-commit) 6cdae57] project init 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 readme.txt

現(xiàn)在我們再來看一下工作目錄的狀態(tài):

$git status
# On branch master
nothing to commit (working directory clean)

大家可以看到“nothing to commit (working directory clean)”;如果一個工作樹(working tree)中所有的修改都已提交到了當前分支里(current head),那么就說它是干凈的(clean),反之它就是臟的(dirty)。#p#

SHA1值內容尋址

正如Git is the next Unix 一文中所說的一樣,Git是一種全新的使用數(shù)據(jù)的方式(Git is a totally new way to operate on data)。Git把它所管理的所有對象(blob,tree,commit,tag……),全部根據(jù)它們的內容生成SHA1哈希串值作為對象名;根據(jù)目前的數(shù)學知識,如果兩塊數(shù)據(jù)的SHA1哈希串值相等,那么我們就可以認為這兩塊數(shù)據(jù)是相同 的。這樣會帶來的幾個好處:

Git只要比較對象名,就可以很快的判斷兩個對象的內容是否相同。

因為在每個倉庫(repository)的“對象名”的計算方法都完全一樣,如果同樣的內容存在兩個不同的倉庫中,就會存在相同的“對象名”。

Git還可以通過檢查對象內容的SHA1的哈希值和“對象名”是否匹配,來判斷對象內容是否正確。

我們通過下面的例子,來驗證上面所說的是否屬實?,F(xiàn)在創(chuàng)建一個和“readme.txt“內容完全相同的文件”readme2.txt“,然后再把它提交到本地倉庫中:

$echo "hello,world" > readme2.txt
$git add readme2.txt
$git commit -m "add new file: readme2.txt"
[master 6200c2c] add new file: readme2.txt
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 readme2.txt

下面的這條很復雜的命令是查看當前的提交(HEAD)所包含的blob對象:

$git cat-file -p HEAD | head -n 1 | cut -b6-15 | xargs git cat-file -p
100644 blob 2d832d9044c698081e59c322d5a2a459da546469 readme.txt
100644 blob 2d832d9044c698081e59c322d5a2a459da546469 readme2.txt

我們再來看看上一次提交(HEAD^)所包含的blob對象:

$git cat-file -p HEAD^ | head -n 1 | cut -b6-15 | xargs git cat-file -p
100644 blob 2d832d9044c698081e59c322d5a2a459da546469 readme.txt

很明顯大家看到盡管當前的提交比前一次多了一個文件,但是它們之間卻是在共用同一個blob對象:“2d832d9”。

No delta, just snapshot

Git 與大部分你熟悉的版本控制系統(tǒng),如Subversion、CVS、Perforce 之間的差別是很大的。傳統(tǒng)系統(tǒng)使用的是: “增量文件系統(tǒng)” (Delta Storage systems),它們存儲是每次提交之間的差異。而Git正好與之相反,它是保存的是每次提交的完整內容(snapshot);它會在提交前根據(jù)要提交 的內容求SHA1哈希串值作為對象名,看倉庫內是否有相同的對象,如果沒有就將在“.git/objects"目錄創(chuàng)建對應的對象,如果有就會重用已有的 對象,以節(jié)約空間。

下面我們來試驗一下Git是否真的是以“snapshot”方式保存提交的內容。

先修改一下"readme.txt",給里面加點內容,再把它暫存,***提交到本地倉庫中:

$echo "hello,world2" >> readme.txt
$git add readme.txt
$git commit -m "add new content for readme.txt"
[master c26c2e7] add new content for readme.txt 1 files changed, 1 insertions(+), 0 deletions(-)

我們現(xiàn)在看看當前版本所包含的blob對象有哪些:

$git cat-file -p HEAD | head -n 1 | cut -b6-15 | xargs git cat-file -p
100644 blob 2e4e85a61968db0c9ac294f76de70575a62822e1 readme.txt
100644 blob 2d832d9044c698081e59c322d5a2a459da546469 readme2.txt

從上面的命令輸出,我們可以看到"readme.txt"已經對應了一個新的blob對象:“2e4e85a”,而之前版本的"readme.txt“對應的blob對象是:“2d832d9”。下面我們再來看一看這兩個”blob“里面的內容和我們的預期是否相同:

$git cat-file -p 2e4e85a
hello,world
hello,world2
$git cat-file -p 2d832d9
hello,world

大家可以看到,每一次提交的文件內容還是全部保存的(snapshot)。

小結

Git內在機制和其它傳統(tǒng)的版本控制系統(tǒng)(VCS)間存在本質的差異,所以Git的里"add"操作的含義和其它VCS存在差別也不足為奇,“git add“不但能把未跟蹤的文件(untracked file)添加到版本控制之下,也可以把修改了的文章暫存到索引中。

同時,由于采用“SHA1哈希串值內容尋值“和”快照存儲(snapshot)“,讓Git成為一個速度非常非??斓陌姹究刂葡到y(tǒng)(VCS)。

原文連接:http://www.infoq.com/cn/news/2011/03/git-adventures-index-submit

【編輯推薦】

  1. Git歷險記(3):創(chuàng)建一個自己的本地倉庫
  2. Git歷險記(2):Git的安裝和配置
  3. Git歷險記(1):初識版本控制系統(tǒng)Git
責任編輯:黃丹 來源: InfoQ
相關推薦

2011-03-30 10:50:55

GitLinux 版本控制

2011-01-26 10:05:36

Git安裝配置

2009-10-15 09:21:00

CCNA考試歷險記CCNA

2022-05-26 21:38:02

開源分布式Hadoop

2022-05-05 19:26:17

Druid分布式存儲

2021-02-22 08:20:32

Activity動畫界面

2011-01-26 09:09:06

版本控制系統(tǒng)GitLinux

2011-02-28 14:37:43

GitLinux版本控制

2011-09-16 16:05:10

MySQL

2014-04-01 09:13:23

程序員招聘

2017-06-30 17:54:04

2017-03-08 08:53:44

Git命令 GitHub

2016-10-27 14:28:59

Hadoop系統(tǒng)大數(shù)據(jù)

2021-04-22 05:43:22

索引設計SET

2021-10-19 21:39:51

Unsafe構造器內存

2017-12-08 10:20:45

FedoraLinux

2013-04-12 09:41:52

MySQL 5.6

2019-07-15 15:37:31

頁面緩存內存

2022-06-05 13:51:47

SentinelOpenFeign服務熔斷

2011-09-19 15:40:35

點贊
收藏

51CTO技術棧公眾號