版本控制
我們知道 git
是分散式版本控制系統,所以稱被控制物件是版本本身沒錯,但是從git
命令中發現,並沒有版本這個名詞,有的只是commit
,所以前幾節我一直稱其為提交.
為了避免後續教程引發歧義,特意說明,無論是版本也好,提交也罷,都是中文翻譯而已,不必太過較真,直接原汁原味稱commit
也可以啊!
假設你已掌握暫存區的相關概念,簡單來說,暫存區就是更改檔案的快取集合,等待一次性全部提交到版本庫,正因如此,方便我們批量操作相關性檔案,打包提交到版本庫,這正是暫存區的獨特魅力.
我們反覆在說 git
是分散式版本控制系統,分散式的概念已經粗略講過多次了,下面我們講一下版本控制,談談 git
的版本控制和其他系統的版本控制有什麼不同,為什麼 git
這麼優秀,如此流行?
git
跟蹤並管理的是更改,而非檔案本身.正如linux 一切皆檔案
,java 一切皆物件
一樣,git 一切皆更改
.新增檔案是一個更改,新增檔案內容是一個更改,修改檔案內容是一個更改,刪除檔案內容也是一個更改,換言之,git
管理的正是這一個個的更改,並不是檔案本身.
下面我們用事實說話,證明 git
管理的是更改而不是檔案本身:
第一步,追加 git tracks changes
到 test.txt
檔案
# 檢視 test.txt 檔案內容
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
# 追加 git tracks changes 檔案內容到 test.txt 檔案
$ echo "git tracks changes" >> test.txt
# 再次檢視 test.txt 檔案內容
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes
$
複製程式碼
第二步,新增test.txt
檔案到暫存區並檢視檔案狀態
$ git add test.txt
sunpodeMacBook-Pro:demo sunpo$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: test.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
.DS_Store
$
複製程式碼
對於上述內容應該不必再解釋了吧,無外乎說test.txt
檔案已修改(modified),即將被提交(to be committed).
但是,此時偏偏不提交,繼續修改 test.txt
檔案:(這種情況實際工作中也有可能出現,比如你正在研發某功能,本以為已經開發完畢,滿心歡喜新增到暫存區,然後意外發現一個小bug,分分鐘就修復了,時間間隔很短以至於你根本不記得還需要再次新增到暫存區.)
第三步,繼續修改檔案內容,忘記再次新增到暫存區
# 編輯 test.txt 檔案,將 git tracks changes 更改為 git tracks changes of files
vim test.txt
# 檢視 test.txt 檔案內容
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
$
複製程式碼
第四步,正常提交暫存區的全部更改到版本庫
$ git commit -m "git tracks changes"
[master 2daa74a] git tracks changes
1 file changed, 1 insertion(+)
複製程式碼
此次提交後,我們再看一下檔案狀態:
$ 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: test.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
.DS_Store
no changes added to commit (use "git add" and/or "git commit -a")
$
複製程式碼
發現有什麼不同嗎?以往提交後再次檢視檔案狀態,工作區都是乾淨的,這次居然提示我們 test.txt
檔案已經修改但未新增到暫存區?!
等一下,我們先回憶一下我們的操作流程:
第一次修改(git tracks changes) -> git add
-> 第二次修改(git tracks changes of files) -> git commit
這樣就很好理解了,git
管理的是更改而不是檔案本身,如果是檔案本身的話,應該將檔案的內容全部提交才對,所以管理的是更改.
第一次修改過後使用 git add
命令將工作區的第一次修改內容放到暫存區準備提交,但是此時工作區發生了第二次修改,注意,這次修改並沒有放到暫存區,所以下一步的git commit
命令提交的暫存區內容中自然也就沒有第二次修改的內容了!所以git commit
完畢後執行git status
命令才會發現此時工作區和暫存區還存在版本差異,即此時工作區不是乾淨的!
這一次的實驗很好理解,工作區的修改需要主動告訴暫存區,暫存區的全部更改再提交到版本庫.所以版本庫的提交取決於暫存區,而暫存區又取決工作區是否主動將更改新增進去了嗎!
理論再多不如親身體驗,讓我們直接比較一下工作區和版本庫的差異吧!
# 比較 test.txt 檔案在工作區和版本庫的差異
$ git diff HEAD -- test.txt
diff --git a/test.txt b/test.txt
index d31bdd2..56c76b7 100644
--- a/test.txt
+++ b/test.txt
@@ -3,4 +3,4 @@ git init
git diff
understand how git control version
how git work
-git tracks changes
+git tracks changes of files
$
複製程式碼
由此可見,工作區比版本庫多了git tracks changes of files
,少了git tracks changes
,所以說第二次修改內容 git tracks changes of files
並沒有被提交.
現在我們再解釋一下-git tracks changes
和 +git tracks changes of files
的問題:
首先檢視工作區 test.txt
檔案內容
$ cat test.txt
git test
git init
git diff
understand how git control version
how git work
git tracks changes of files
$
複製程式碼
根據上述分析,我們知道第一次的修改git tracks changes
已被提交到版本庫,第二次的修改git tracks changes of files
沒有被提交而是繼續留在工作區.
因此,可以推斷出目前版本庫的檔案應該是這樣的:
git test
git init
git diff
understand how git control version
how git work
git tracks changes
複製程式碼
既然如何,工作區和版本庫相比豈不剛好是少了一個git tracks changes
,多了git tracks changes of files
,其餘檔案內容完全相同!
透過現象看本質,已經分析了現象也解釋了產生現象的原因,是時候分析一下本質了.
丟擲問題:因為git tracks changes of fiels
和 git tracks changes
被視為不同的更改,所以才會造成上述現象.如果git tracks changes of fiels
被認為是git tracks changes
+ of fiels
兩者疊加產生的更改,還會產生上述現象嗎?
答案是否定的,如果兩個更改可以疊加的話,按照版本控制的思路,第二次的修改即便沒有提交也只是 of fiels
沒有加入到版本庫而已,如此一來,工作區和版本庫的差異將不再是少了一個git tracks changes
,多了git tracks changes of files
,而僅僅是多了of files
!
由此可見,git
版本控制系統其實是全量更新的思維模式,並不是差量更新模式.
小結
- 工作區的更改需要
git add
新增到暫存區,git commit
將暫存區的全部更改提交到版本庫. - 工作區,暫存區,版本庫三者既相關獨立又密切關聯,三者是傳遞性依賴的關係.
git
版本控制的是檔案的更改,而不是檔案本身,是全量更新模式,而不是差量更新模式.