5.1 修改不能直接提交git
首先修改welcome.txt文件,在這個文件後面追加一行:svn
echo "Nice to meet you." >> welcome.txt
使用git diff命令查看修改後的文件與暫存區(並非版本庫,後面會有相關討論)中的文件的差別:3d
diff --git a/welcome.txt b/welcome.txt index a8f9fd8..b0e5c6e 100644 --- a/welcome.txt +++ b/welcome.txt @@ -1 +1,2 @@ Hello +Nice to meet you.
差別的輸出格式:指針
此時使用git commit命令並不會提交修改,反而會報錯:code
git commit -m "Append a nice line." On branch master Changes not staged for commit: modified: welcome.txt no changes added to commit
使用git status查看文件狀態,加上-s參數顯示精簡格式的狀態輸出:對象
git status On branch master 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: welcome.txt no changes added to commit (use "git add" and/or "git commit -a"
git status -s M welcome.txt
welcome.txt文件處於修改狀態。遞歸
根據git status輸出的提示,須要對修改的文件執行git add命令,將修改的文件添加到「提交任務」中,而後才能提交。此處與svn差異很大,在svn中執行add操做是向版本庫中添加新文件,修改的文件在下次提交時會直接提交。索引
按照提示將修改的文件添加到提交任務中:it
git add welcome.txt
在執行完添加操做,而沒有執行提交操做時,查看一下Git工做區發生了什麼變化:io
一、執行git diff沒有輸出,說明是本地文件與暫存區的比較;
二、執行git diff HEAD(當前版本庫的頭指針),會有差別輸出,說明此時比較的是本地文件和版本庫的最新版本;
三、執行git status,輸出與添加前不同了:
On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: welcome.txt
四、執行git status -s,以簡潔方式顯示狀態:
git status -s M welcome.txt
乍一看貌似與添加前的輸出同樣,其實它們有細微的差異:
爲了加深理解,暫不提交以前的添加任務,而繼續修改文件:
echo "Bye-Bye." >> welcome.txt
查看一下狀態:
git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: welcome.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: welcome.txt
這裏同時出現了前文討論的兩種狀態。再查看精簡的狀態:
git status -s MM welcome.txt
同時出現了兩個M:不但版本庫中最新提交的文件與處於暫存區中的文件相比有改動,並且工做區與暫存區中的文件相比也有改動。
即如今有三個不一樣版本的welcome.txt:一個在工做區,一個在暫存區,一個是版本庫中最新版本的welcome.txt。
使用不一樣參數調用git diff命令能夠看到不一樣狀態下welcome.txt文件的差別:
git diff diff --git a/welcome.txt b/welcome.txt index b0e5c6e..45cf837 100644 --- a/welcome.txt +++ b/welcome.txt @@ -1,2 +1,3 @@ Hello Nice to meet you. +Bye-Bye.
git diff HEAD diff --git a/welcome.txt b/welcome.txt index a8f9fd8..45cf837 100644 --- a/welcome.txt +++ b/welcome.txt @@ -1 +1,3 @@ Hello +Nice to meet you. +Bye-Bye.
git diff --staged diff --git a/welcome.txt b/welcome.txt index a8f9fd8..b0e5c6e 100644 --- a/welcome.txt +++ b/welcome.txt @@ -1 +1,2 @@ Hello +Nice to meet you.
執行提交操做:
git commit -m "which version checked in?" [master 326f237] which version checked in? 1 file changed, 1 insertion(+)
提交成功,使用git status -s查看狀態:
git status -s M welcome.txt
文件名前少了第一個M,只剩下第二個M,說明暫存區的任務被提交到了版本庫,如今只剩下工做區和暫存區的差別。
5.2 理解Git暫存區
在版本庫.git目錄下有一個index文件,看一下這個文件:
一、撤銷工做區中welcome.txt文件還沒有提交的修改(5.1中添加的Bye-Bye那一行)並查看工做區狀態:
git checkout -- welcome.txt git status -s
git status -s無輸出,說明未提交的修改已經被撤銷了。
二、查看.git/index的時間戳:
ls --full-time .git/index -rw-r--r-- 1 x250 197121 145 2016-07-16 07:52:20.640437700 +0800 .git/index
時間戳是剛剛運行git status -s的時間。
三、再次查看工做區狀態並查看.git/index的時間戳:
git status -s ls --full-time .git/index -rw-r--r-- 1 x250 197121 145 2016-07-16 07:52:20.640437700 +0800 .git/index
時間戳沒有變化。
四、更改welcome.txt文件的時間戳,但並不改變它的內容(可使用touch命令,它用來修改文件時間戳,或者新建一個不存在的文件)。而後查看工做區狀態並查看.git/index的時間戳:
touch welcome.txt git status -s ls --full-time .git/index -rw-r--r-- 1 x250 197121 145 2016-07-16 07:58:10.512449200 +0800 .git/index
發現git status -s依然無輸出,說明工做區沒有新的修改;可是.git/index時間戳改變了。
以上的實驗說明當執行git status命令(或者git diff命令)掃描工做區改動的時候,先依據.git/index文件中記錄的時間戳、長度等信息判斷工做區文件是否改變。若是工做區文件的時間戳改變了,說明文件的內容可能被改變了,須要打開文件、讀取文件內容,與更改前的原始文件相比較,判斷文件內容是否被更改。若是文件內容沒有改變,則將該文件新的時間戳記錄到.git/index文件中。由於若是要判斷文件是否更改,使用時間戳、文件長度等信息進行比較要比經過文件北榮比較快得多,因此Git這樣的實現方式可讓工做區狀態掃描更快速的執行。
文件.git/index是包含文件索引的目錄樹,記錄了文件名和文件的狀態信息,文件的內容沒有存儲在其中,而是保存在Git對象庫.git/objects目錄中,文件索引創建了文件和對象庫的對應關係。
下圖展現了工做區、版本庫中的暫存區和版本庫之間的關係:
5.3 瀏覽暫存區和版本庫的目錄樹、git diff
一、瀏覽暫存區和版本庫的目錄樹
對於HEAD指向的目錄樹,可使用git ls-tree來查看,-l參數可現實文件的大小:
git ls-tree -l HEAD 100644 blob b0e5c6e24bc84d489773b2fda5accf005bc912f1 25 welcome.txt
輸出中的信息從左到右:
下面的命令清除當前工做區中沒有加入版本庫的文件和目錄:
git clean -fd
下面的命令用暫存區內容刷新工做區:
git checkout .
對工做區作一些修改:
$ echo "Bye-Bye." >> welcome.txt $ mkdir -p a/b/c $ echo "Hello." > a/b/c/hello.txt $ git add . x250@x250-PC MINGW64 ~/demo (master) $ echo "Bye-Bye." >> a/b/c/hello.txt $ git status -s AM a/b/c/hello.txt M welcome.txt
查看工做區文件的大小:
$ find . -path ./.git -prune -o -type f -printf "%-20p\t%s\n" ./a/b/c/hello.txt 16 ./welcome.txt 36
顯示暫存區的目錄樹:
git ls-files -s 100644 18832d35117ef2f013c4009f5b2128dfaeff354f 0 a/b/c/hello.txt 100644 45cf8376b221e28cb9c5afb382cfe15ceb3dc520 0 welcome.txt
-s命令要去顯示暫存區中Object的對象名。輸出中的0不是文件大小而是暫存區編號。若是想針對暫存區的目錄樹使用git ls-tree命令,須要先將暫存區的目錄樹寫入Git對象庫(git write-tree):
$ git write-tree 1343285bb5205fe9eed661efebcc9d65bf0cea7e $ git ls-tree -l 1343285 040000 tree 53583ee687fbb2e913d18d508aefd512465b2092 - a 100644 blob 45cf8376b221e28cb9c5afb382cfe15ceb3dc520 34 welcome.txt
git write-tree的輸出是寫入Git對象庫中的TreeID,這個ID將做爲下一條命令的參數。
在git ls-tree命令中,沒有把40位的ID寫全,而是使用了前幾位,實際上只要不與其餘對象的ID衝突,就可使用縮寫ID。
git ls-tree輸出的第一條顯示目錄a是一個tree對象。
若是想要遞歸顯示目錄內容,則使用-r參數。使用參數-t能夠把遞歸中遇到的每棵樹都顯示出來,而不是隻顯示最終文件。
二、git diff
經過調用git diff並添加不一樣參數,能夠對工做區、暫存區和HEAD中的內容進行兩兩比較。以下圖所致(1)工做區和暫存區的比較:
$ git diff diff --git a/a/b/c/hello.txt b/a/b/c/hello.txt index 18832d3..e8577ea 100644 --- a/a/b/c/hello.txt +++ b/a/b/c/hello.txt @@ -1 +1,2 @@ Hello. +Bye-Bye.
(2)暫存區和HEAD比較
git diff --cached diff --git a/a/b/c/hello.txt b/a/b/c/hello.txt new file mode 100644 index 0000000..18832d3 --- /dev/null +++ b/a/b/c/hello.txt @@ -0,0 +1 @@ +Hello. diff --git a/welcome.txt b/welcome.txt index b0e5c6e..45cf837 100644 --- a/welcome.txt +++ b/welcome.txt @@ -1,2 +1,3 @@ Hello Nice to meet you. +Bye-Bye.
(3)工做區和HEAD比較
git diff HEAD diff --git a/a/b/c/hello.txt b/a/b/c/hello.txt new file mode 100644 index 0000000..e8577ea --- /dev/null +++ b/a/b/c/hello.txt @@ -0,0 +1,2 @@ +Hello. +Bye-Bye. diff --git a/welcome.txt b/welcome.txt index b0e5c6e..45cf837 100644 --- a/welcome.txt +++ b/welcome.txt @@ -1,2 +1,3 @@ Hello Nice to meet you. +Bye-Bye.
5.4 不要使用git commit -a
Git的提交命令(git commit)能夠帶上-a參數,對本地全部變動的文件執行提交操做,包括對本地修改的文件和刪除的文件,但不包括未被版本庫跟蹤的文件。
這個命令的確能夠簡化一些操做,減小用git add命令表示變動文件的步驟,可是若是習慣了使用這種偷懶的提交命令,機會丟掉Git暫存區最大的好處:對提交內容進行控制的能力。做者推薦不要使用git commit -a。
5.5 保存當前的工做進度
git stash Saved working directory and index state WIP on master: 326f237 which version checked in? HEAD is now at 326f237 which version checked in? $ git status On branch master nothing to commit, working directory clean
git stash命令備份當前的工做區的內容,從最近的一次提交中讀取相關內容,讓工做區保證和上次提交的內容一致。同時,將當前的工做區內容保存到Git棧中。
運行完git stash後使用git status命令,發現工做區中還沒有提交的改動都不見了。