?
このドキュメントでは、 php中國語ネットマニュアル リリース
gittutorial-2 - Git 的教程介紹:第二部分
git *
閱讀本教程之前,您應(yīng)該通過 gittutorial [7] 。
本教程的目標(biāo)是介紹 Git 體系結(jié)構(gòu)的兩個(gè)基本部分 - 對(duì)象數(shù)據(jù)庫和索引文件,并向讀者提供理解其余 Git 文檔所需的一切。
讓我們開始一個(gè)新項(xiàng)目并創(chuàng)建少量歷史記錄:
$ mkdir test-project $ cd test-project $ git init Initialized empty Git repository in .git/$ echo 'hello world' > file.txt $ git add .$ git commit -a -m "initial commit"[master (root-commit) 54196cc] initial commit 1 file changed, 1 insertion(+) create mode 100644 file.txt $ echo 'hello world!' >file.txt $ git commit -a -m "add emphasis"[master c4d59f3] add emphasis 1 file changed, 1 insertion(+), 1 deletion(-)
Git 響應(yīng)提交的十六進(jìn)制數(shù)字是什么?
我們在教程的第一部分看到了提交這樣的名字。事實(shí)證明,Git 歷史記錄中的每個(gè)對(duì)象都以40位十六進(jìn)制名稱存儲(chǔ)。該名稱是對(duì)象內(nèi)容的 SHA-1 散列; 除此之外,這確保了 Git 永遠(yuǎn)不會(huì)存儲(chǔ)兩次相同的數(shù)據(jù)(因?yàn)橄嗤臄?shù)據(jù)具有相同的 SHA-1 名稱),并且 Git 對(duì)象的內(nèi)容永遠(yuǎn)不會(huì)改變(因?yàn)檫@也會(huì)改變對(duì)象的名稱)。這里的7個(gè)字符的十六進(jìn)制字符串就是這樣的40個(gè)字符長的字符串的縮寫??s寫可以用于任何可以使用40個(gè)字符串的地方,只要它們是明確的即可。
預(yù)計(jì)在上面的例子中創(chuàng)建的提交對(duì)象的內(nèi)容會(huì)生成與上面顯示的不同的 SHA-1 哈希值,因?yàn)樘峤粚?duì)象會(huì)記錄創(chuàng)建時(shí)間和執(zhí)行提交人員的姓名。
我們可以用cat-file
命令向 Git 詢問這個(gè)特定的對(duì)象。不要復(fù)制這個(gè)例子中的40個(gè)十六進(jìn)制數(shù)字,而是使用你自己版本的數(shù)字。請(qǐng)注意,您可以將其縮短為只有幾個(gè)字符,以免鍵入所有40個(gè)十六進(jìn)制數(shù)字:
$ git cat-file -t 54196cc2 commit $ git cat-file commit 54196cc2 tree 92b8b694ffb1675e5975148e1121810081dbdffe author J. Bruce Fields <bfields@puzzle.fieldses.org> 1143414668 -0500committer J. Bruce Fields <bfields@puzzle.fieldses.org> 1143414668 -0500initial commit
樹可以引用一個(gè)或多個(gè) “blob” 對(duì)象,每個(gè)對(duì)象都對(duì)應(yīng)一個(gè)文件。另外,樹還可以引用其他樹對(duì)象,從而創(chuàng)建目錄層次結(jié)構(gòu)。您可以使用 ls-tree 檢查任何樹的內(nèi)容(請(qǐng)記住,SHA-1 的足夠長的初始部分也可以工作):
$ git ls-tree 92b8b694100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad file.txt
因此我們看到這棵樹里有一個(gè)文件。SHA-1 散列是對(duì)該文件數(shù)據(jù)的引用:
$ git cat-file -t 3b18e512 blob
“blob” 只是文件數(shù)據(jù),我們也可以用 cat-file 來檢查:
$ git cat-file blob 3b18e512 hello world
請(qǐng)注意,這是舊的文件數(shù)據(jù); 所以 Git 在對(duì)初始樹的響應(yīng)中命名的對(duì)象是一棵樹,其中包含第一次提交記錄的目錄狀態(tài)的快照。
所有這些對(duì)象都存儲(chǔ)在 Git 目錄下的 SHA-1 名稱下:
$ find .git/objects/.git/objects/.git/objects/pack.git/objects/info.git/objects/3b.git/objects/3b/18e512dba79e4c8300dd08aeb37f8e728b8dad.git/objects/92.git/objects/92/b8b694ffb1675e5975148e1121810081dbdffe.git/objects/54.git/objects/54/196cc2703dc165cbd373a65a4dcf22d50ae7f7.git/objects/a0.git/objects/a0/423896973644771497bdc03eb99d5281615b51.git/objects/d0.git/objects/d0/492b368b66bdabf2ac1fd8c92b39d3db916e59.git/objects/c4.git/objects/c4/d59f390b9cfd4318117afde11d601c1085f241
而這些文件的內(nèi)容只是壓縮數(shù)據(jù)加上一個(gè)標(biāo)識(shí)它們的長度和類型的頭文件。該類型是 blob ,樹,提交或標(biāo)記。
最簡單的提交是 HEAD 提交,我們可以從 .git / HEAD 找到:
$ cat .git/HEAD ref: refs/heads/master
正如你所看到的,這告訴我們我們當(dāng)前正在使用哪個(gè)分支,并且它通過命名 .git 目錄下的一個(gè)文件告訴我們這個(gè)文件,它本身包含引用一個(gè)提交對(duì)象的 SHA-1 名稱,我們可以用它來檢查貓文件:
$ cat .git/refs/heads/master c4d59f390b9cfd4318117afde11d601c1085f241 $ git cat-file -t c4d59f39 commit $ git cat-file commit c4d59f39 tree d0492b368b66bdabf2ac1fd8c92b39d3db916e59 parent 54196cc2703dc165cbd373a65a4dcf22d50ae7f7 author J. Bruce Fields <bfields@puzzle.fieldses.org> 1143418702 -0500committer J. Bruce Fields <bfields@puzzle.fieldses.org> 1143418702 -0500add emphasis
這里的“樹”對(duì)象指的是樹的新狀態(tài):
$ git ls-tree d0492b36100644 blob a0423896973644771497bdc03eb99d5281615b51 file.txt $ git cat-file blob a0423896 hello world!
而“父”對(duì)象引用了之前的提交:
$ git cat-file commit 54196cc2 tree 92b8b694ffb1675e5975148e1121810081dbdffe author J. Bruce Fields <bfields@puzzle.fieldses.org> 1143414668 -0500committer J. Bruce Fields <bfields@puzzle.fieldses.org> 1143414668 -0500initial commit
樹對(duì)象是我們首先檢查的樹,而這個(gè)提交是不尋常的,因?yàn)樗鄙偃魏胃笇?duì)象。
大多數(shù)提交只有一個(gè)父,但是承諾有多個(gè)父也很常見。在這種情況下,提交表示合并,并且父引用指向合并分支的 HEAD 。
除了斑點(diǎn),樹和提交之外,唯一剩下的對(duì)象就是一個(gè)“tag”,我們不在這里討論; 有關(guān)詳細(xì)信息,請(qǐng)參閱 git-tag [1] 。
所以現(xiàn)在我們知道 Git 如何使用對(duì)象數(shù)據(jù)庫來表示一個(gè)項(xiàng)目的歷史記錄:
“commit”對(duì)象指的是表示歷史中特定點(diǎn)上的目錄樹快照的“樹”對(duì)象,并參考“父”提交來顯示它們?nèi)绾芜B接到項(xiàng)目歷史中。
“樹”對(duì)象表示單個(gè)目錄的狀態(tài),將目錄名稱與包含文件數(shù)據(jù)的 “blob” 對(duì)象以及包含子目錄信息的“樹”對(duì)象相關(guān)聯(lián)。
“blob”對(duì)象包含沒有任何其他結(jié)構(gòu)的文件數(shù)據(jù)。
在每個(gè)分支頭部提交對(duì)象的引用存儲(chǔ)在 .git / refs / heads / 下的文件中。
當(dāng)前分支的名稱存儲(chǔ)在 .git / HEAD 中。
請(qǐng)注意,順便提一下,很多命令都以樹為參數(shù)。但是,正如我們上面所看到的,樹可以以許多不同的方式引用 - 通過樹的 SHA-1 名稱,引用樹的提交的名稱,引用其頭部的分支的名稱到那棵樹等等 - 而且大多數(shù)這樣的命令可以接受任何這些名字。
在命令提要中,有時(shí)用 “tree-ish” 這個(gè)詞來表示這樣一個(gè)參數(shù)。
我們用來創(chuàng)建提交的主要工具是git-commit -a
創(chuàng)建一個(gè)提交,包括您對(duì)工作樹所做的每個(gè)更改。但是,如果您只想對(duì)某些文件進(jìn)行更改,該怎么辦?或者只對(duì)某些文件進(jìn)行某些更改?
如果我們看一下在封面下創(chuàng)建提交的方式,我們會(huì)看到創(chuàng)建提交的方式更加靈活。
繼續(xù)我們的測試項(xiàng)目,讓我們再次修改 file.txt :
$ echo "hello world, again" >>file.txt
但是這次不是立即做出提交,而是讓我們采取中間步驟,并沿途詢問差異來跟蹤發(fā)生的事情:
$ git diff--- a/file.txt+++ b/file.txt @@ -1 +1,2 @@ hello world!+hello world, again $ git add file.txt $ git diff
最后的差異是空的,但沒有新的提交已經(jīng)完成,并且 head 仍然不包含新行:
$ git diff HEAD diff --git a/file.txt b/file.txt index a042389..513feba 100644--- a/file.txt+++ b/file.txt @@ -1 +1,2 @@ hello world!+hello world, again
所以git diff
比較頭部以外的東西。它比較的東西實(shí)際上是索引文件,它以二進(jìn)制格式存儲(chǔ)在 .git / index 中,但其內(nèi)容可以用 ls-files 檢查:
$ git ls-files --stage100644 513feba2e53ebbd2532419ded848ba19de88ba00 0 file.txt $ git cat-file -t 513feba2 blob $ git cat-file blob 513feba2 hello world!hello world, again
所以我們git add
做的是存儲(chǔ)一個(gè)新的 blob ,然后在索引文件中加入一個(gè)引用。如果我們再次修改文件,我們會(huì)看到新的修改反映在git diff
輸出中:
$ echo 'again?' >>file.txt $ git diff index 513feba..ba3da7b 100644--- a/file.txt+++ b/file.txt @@ -1,2 +1,3 @@ hello world! hello world, again+again?
使用正確的參數(shù),git diff
還可以顯示工作目錄和上次提交之間或索引和上次提交之間的區(qū)別:
$ git diff HEAD diff --git a/file.txt b/file.txt index a042389..ba3da7b 100644--- a/file.txt+++ b/file.txt @@ -1 +1,3 @@ hello world!+hello world, again+again?$ git diff --cached diff --git a/file.txt b/file.txt index a042389..513feba 100644--- a/file.txt+++ b/file.txt @@ -1 +1,2 @@ hello world!+hello world, again
在任何時(shí)候,我們都可以使用git commit
(不帶 “-a” 選項(xiàng))創(chuàng)建一個(gè)新的提交,并驗(yàn)證提交的狀態(tài)只包含索引文件中存儲(chǔ)的更改,而不是僅存在于工作樹中的更改。
$ git commit -m "repeat"$ git diff HEAD diff --git a/file.txt b/file.txt index 513feba..ba3da7b 100644--- a/file.txt+++ b/file.txt @@ -1,2 +1,3 @@ hello world! hello world, again+again?
所以默認(rèn)情況下git commit
使用索引來創(chuàng)建提交,而不是工作樹; 提交的 “-a” 選項(xiàng)告訴它首先用工作樹中的所有更改更新索引。
最后,值得關(guān)注git add
索引文件的效果:
$ echo "goodbye, world" >closing.txt $ git add closing.txt
該功能的作用git add
是將一個(gè)條目添加到索引文件中:
$ git ls-files --stage100644 8b9743b20d4b15be3955fc8d5cd2b09cd2336138 0 closing.txt100644 513feba2e53ebbd2532419ded848ba19de88ba00 0 file.txt
而且,正如您可以用 cat-file 看到的那樣,這個(gè)新條目引用了該文件的當(dāng)前內(nèi)容:
$ git cat-file blob 8b9743b2 goodbye, world
"status" 命令是快速總結(jié)情況的有用方法:
$ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: closing.txt Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: file.txt
由于 closing.txt 的當(dāng)前狀態(tài)被緩存在索引文件中,因此它被列為“要提交的更改”。由于 file.txt 在工作目錄中的變化未反映在索引中,因此它被標(biāo)記為“已更改但未更新”。此時(shí),運(yùn)行 “git commit” 會(huì)創(chuàng)建一個(gè)提交 clos.txt(及其新內(nèi)容)的提交,但不會(huì)修改 file.txt 。
此外,請(qǐng)注意,bare 會(huì)git diff
顯示對(duì) file.txt 的更改,但不會(huì)增加 closing.txt ,因?yàn)樗饕募?closing.txt 的版本與工作目錄中的版本相同。
除了作為新提交的暫存區(qū)域之外,還在檢出分支時(shí)從對(duì)象數(shù)據(jù)庫填充索引文件,并且該文件用于保存涉及合并操作的樹。有關(guān)詳細(xì)信息,請(qǐng)參閱 gitcore-tutorial [7] 和相關(guān)手冊頁。
此時(shí),您應(yīng)該知道讀取任何 git 命令的手冊頁所需的一切; 在 giteveryday [7] 中提到的命令是一個(gè)很好的開始。你應(yīng)該能夠在 gitglossary 中找到任何未知的術(shù)語[7]。
Git 用戶手冊提供了更全面的 Git 介紹。
gitcvs-migration [7] 解釋了如何將 CVS 存儲(chǔ)庫導(dǎo)入到 Git 中,并展示了如何以類似 CVS 的方式使用 Git 。
有關(guān) Git 使用的一些有趣示例,請(qǐng)參閱 howtos。
對(duì)于 Git 開發(fā)人員,gitcore-tutorial [7] 詳細(xì)介紹了涉及創(chuàng)建新提交的較低級(jí) Git 機(jī)制。