加深理解 commit 提交
執(zhí)行完成了 git commit 命令,究竟做了什么呢?
當(dāng)我們?cè)俅螌?duì) file2.txt 文件的內(nèi)容進(jìn)行變更、添加以及提交之后,發(fā)現(xiàn)在提交的時(shí)候,查看的 commit 對(duì)象的內(nèi)容時(shí),其包含有父節(jié)點(diǎn)的 commit 信息。而對(duì)于理解的話,可以看看下面的這個(gè)提交流程圖。
# 左邊執(zhí)行
$ echo "file2.txt" > file2.txt
$ git status
$ git add file2.txt
$ git ls-files -s
$ git cat-file -p 0ac9638
$ git commit -m "2nd commit"
$ git cat-file -p bab53ff
$ git cat-file -p 2f07720
# 右邊執(zhí)行
$ watch -n 1 -d tree .git
在 Git 中空文件夾是不算在追蹤范圍內(nèi)的,而且添加文件夾并不會(huì)增加 object 對(duì)象。當(dāng)我們查看 index 內(nèi)容的時(shí)候,會(huì)發(fā)現(xiàn)文件名稱是包含相對(duì)路徑的。
而當(dāng)我們通過(guò) commit 命令提交之后,會(huì)發(fā)現(xiàn)生成了三個(gè) object 對(duì)象,因?yàn)?commit 操作不會(huì)生成 blob 對(duì)象,所以分別是一個(gè) commit 對(duì)象和兩個(gè) tree 對(duì)象??梢园l(fā)現(xiàn),tree 對(duì)象里面有包含了一個(gè)目錄的 tree,其里面包含對(duì)象文件內(nèi)容。
下圖所示的文件狀態(tài),可以體會(huì)到 Git 中版本的概念。即 commit 對(duì)象指向一個(gè)該版本中的文件目錄樹(shù)的根(tree),然后 tree 在指向 blob 對(duì)象(文件)和 tree 對(duì)象(目錄),這樣就可以無(wú)限的往復(fù)下去形成一個(gè)完整的版本。
# 左邊執(zhí)行
$ mkdir floder1
$ echo "file3" > floder1/file3.txt
$ git add floder1
$ git ls-files -s
$ git commit -m "3rd commit"
$ git cat-file -p 1711e01
$ git cat-file -p 9ab67f8
# 右邊執(zhí)行
$ watch -n 1 -d tree .git
文件的生命周期狀態(tài)
總結(jié)一下,Git 里面的文件狀態(tài)和如何切換。
現(xiàn)在,我們已經(jīng)基本理解了文件如何在工作區(qū)、暫存區(qū)以及代碼倉(cāng)庫(kù)之間進(jìn)行狀態(tài)的跟蹤和同步。在 Git 的操作中,文件的可能狀態(tài)有哪些,以及如何進(jìn)行狀態(tài)切換的,我們這里一起總結(jié)一下!
Branch 和 HEAD 的意義
執(zhí)行完成了 git branch 命令,究竟做了什么呢?
到底什么是分支?分支切換又是怎么一回事?我們通過(guò)查看 Git 的官方文檔,就可以得到,分支就是一個(gè)有名字的(master/dev)指向 commit 對(duì)象的一個(gè)指針。
我們?cè)诔跏蓟瘋}(cāng)庫(kù)的時(shí)候,提供會(huì)默認(rèn)給我們分配一個(gè)叫做 master 的分支(在最新的版本默認(rèn)倉(cāng)庫(kù)已經(jīng)變更為 main 了),而 master 分支就是指向最新的一次提交。為什么需要給分支起名字呢?就是為了方便我們使用和記憶,可以簡(jiǎn)單理解為 alias 命令的意義一致。
有了上述基礎(chǔ),我們就需要考慮下,分支到底是如何實(shí)現(xiàn)和工作的。要實(shí)現(xiàn)一個(gè)分支,我們最基本需要解決兩個(gè)問(wèn)題,第一個(gè)就是需要存儲(chǔ)每一個(gè)分支指向的 commit,第二個(gè)問(wèn)題就是在切換分支的時(shí)候幫助我們標(biāo)識(shí)當(dāng)前分支。
在 Git 中,它有一個(gè)非常特殊的 HEAD 文件。而 HEAD 文件是一個(gè)指針,其有一個(gè)特性就是總會(huì)指向當(dāng)前分支的最新的一個(gè) commit 對(duì)象。而這個(gè) HEAD 文件正好,解決了我們上面提出的兩個(gè)問(wèn)題。
當(dāng)我們從 master 切換分支到 dev 的時(shí)候,HEAD 文件也會(huì)隨即切換,即指向 dev 這個(gè)指針。設(shè)計(jì)就是這么美麗,不愧是鬼才,好腦袋。
# 左邊執(zhí)行
$ cat .git/HEAD
$ cat .git/refs/heads/master
$ git cat-file -t 1711e01
# 右邊執(zhí)行
$ glo = git log
分支操作的背后邏輯
執(zhí)行完成了 git branch 命令,究竟做了什么呢?
這里我們可以看到分支切換之后,HEAD 指向發(fā)生變動(dòng)了。
# 左邊執(zhí)行
$ git branch
$ git branch dev
$ ll .git/refs/heads
$ cat .git/refs/heads/master
$ cat .git/refs/heads/dev
$ cat .git/HEAD
$ git checkout dev
$ cat .git/HEAD
# 右邊執(zhí)行
$ glo = git log
這里需要注意的是,即使我們刪除了分支,但是該分支上一些特有的對(duì)象并不會(huì)被刪除的。這些對(duì)象其實(shí)就是我們俗稱的垃圾對(duì)象,還有我們多次使用 add 命令所產(chǎn)生的也有垃圾對(duì)象,而這些垃圾對(duì)象怎么清除和回收呢?后續(xù),我們會(huì)涉及到的。
# 左邊執(zhí)行
$ echo "dev" > dev.txt
$ git add dev.txt
$ git commit -m "1st commit from dev branch"
$ git checkout master
$ git branch -d dev
$ git branch -D dev
$ git cat-file -t 861832c
$ git cat-file -p 861832c
$ git cat-file -p 680f6e9
$ git cat-file -p 38f8e88
# 右邊執(zhí)行
$ glo = git log
checkout 和 commit 操作
我們一起聊一聊,checkout 和 commit 的操作!
我們執(zhí)行 checkout 命令的時(shí)候,其不光可以切換分支,而且可以切換到指定的 commit 上面,即 HEAD 文件會(huì)指向某個(gè) commit 對(duì)象。在 Git 里面,將 HEAD 文件沒(méi)有指向 master 的這個(gè)現(xiàn)象稱之為 detached HEAD。
這里不管 HEAD 文件指向的是分支名稱也好,是 commit 對(duì)象也罷,其實(shí)本質(zhì)都是一樣的,因?yàn)榉种Q也是指向某個(gè) commit 對(duì)象的。
# 左邊執(zhí)行
$ git checkout 6e4a700
$ git log
# 右邊執(zhí)行
$ glo = git log
當(dāng)我們切換到指定的 commit 的時(shí)候,如果需要在對(duì)應(yīng)的 commit 上繼續(xù)修改代碼提交的話,可以使用上述圖片中提及的 swtich 命令創(chuàng)建新分支,再進(jìn)行提交。但是,通常我們都不會(huì)著玩,都會(huì)使用 checkout 命令來(lái)創(chuàng)建新分支的。
$ git checkout -b tmp
$ git log
即使可以這樣操作,我們也很少使用。還記得我們上一章節(jié)創(chuàng)建的 dev 分支嗎?我們創(chuàng)建了該分支并有了一個(gè)新的提交,但是沒(méi)有合并到 master 分支就直接刪除了?,F(xiàn)在再使用 log 命令查看的話,是看不到了。
實(shí)際,真的看不到了嗎?大家要記住,在 Git 里面任何的操作,比如分支的刪除。它只是刪除了指向某個(gè)特定 commit 的指針引用而已,而那個(gè) commit 本身并不會(huì)被刪除,即 dev 分支的那個(gè) commit 提交還是在的。
那我們?cè)趺凑业竭@個(gè) commit 呢?找到之后,我們就可以在上面繼續(xù)工作,或者找到之前的文件數(shù)據(jù)等。
第一種方法:
- [費(fèi)勁不太好,下下策]
- 在 objects 目錄下面,自己一個(gè)一個(gè)看,然后切換過(guò)去。
第二種方法:
- [推薦的操作方式]
- 使用 Git 提供的 git reflog 專用命令來(lái)查找。
- 該命令的作用就是用于將我們之前的所有操作都記錄下來(lái)。
# 左邊執(zhí)行
$ git reflog
$ git checkout 9fb7a14
$ git checkout -b dev
# 右邊執(zhí)行
$ glo = git log
聊聊 diff 的執(zhí)行邏輯
當(dāng)我們執(zhí)行 diff 命令之后,Git 的邏輯它們是怎么對(duì)比出來(lái)的呢?
就在本節(jié)中中,我們使用上節(jié)的倉(cāng)庫(kù),修改文件內(nèi)容之后,看看 diff 命令都輸出了哪些內(nèi)容呢?我們這里一起來(lái)看看,研究研究!
$ echo "hello" > file1.txt
$ git diff
$ git cat-file -p 42d9955
$ git cat-file -p ce01362
# 下述命令原理也是一樣的
$ git diff --cached
$ git diff HEAD
Git 如何添加遠(yuǎn)程倉(cāng)庫(kù)
如何將我們本地的倉(cāng)庫(kù)和遠(yuǎn)程服務(wù)器上面的倉(cāng)庫(kù)關(guān)聯(lián)起來(lái)呢?
初始化倉(cāng)庫(kù)
$ git init
$ git add README.md
$ git commit -m "first commit"
關(guān)聯(lián)遠(yuǎn)程倉(cāng)庫(kù)
當(dāng)我們使用上述命令來(lái)關(guān)聯(lián)遠(yuǎn)程服務(wù)器倉(cāng)庫(kù)的時(shí)候,我們本地 .git 目錄也是會(huì)發(fā)生改變的。通過(guò)命令查看 .git/config 文件的話,可以看到配置文件中出現(xiàn)了 [remote] 字段。
# 關(guān)聯(lián)遠(yuǎn)程倉(cāng)庫(kù)
$ git remote add origin git@github.com:escapelife/git-demo.git
? cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote "origin"]
url = git@github.com:escapelife/git-demo.git
fetch = +refs/heads/*:refs/remotes/origin/*
推送本地分支
當(dāng)我們執(zhí)行如下命令,將本地 master 分支推送到遠(yuǎn)程 origin 倉(cāng)庫(kù)的 master 分支。之后,我們登陸 GitHub 就可以看到推送的文件及目錄內(nèi)容了。
推送分支內(nèi)容的時(shí)候,會(huì)列舉推送的 objects 數(shù)量,并將其內(nèi)容進(jìn)行壓縮,之后推送到我們遠(yuǎn)程的 GitHub 倉(cāng)庫(kù),并且創(chuàng)建了一個(gè)遠(yuǎn)程的 master 分支(origin 倉(cāng)庫(kù))。
# 推送本地分支
$ git push -u origin master
推送之后,我們可以發(fā)現(xiàn),本地的 .git 生成了一些文件和目錄,它們都是什么呢?如下所示,會(huì)新增四個(gè)目錄和兩個(gè)文件,皆為遠(yuǎn)程倉(cāng)庫(kù)的信息。當(dāng)我們通過(guò)命令查看 master 這個(gè)文件的內(nèi)容時(shí),會(huì)發(fā)現(xiàn)其也是一個(gè) commit 對(duì)象。此時(shí)與我們本地 master 分支所指向的一致。而其用于表示遠(yuǎn)程倉(cāng)庫(kù)的當(dāng)前版本,用于和本地進(jìn)行區(qū)別和校對(duì)的。
? tree .git
├── logs
│ ├── HEAD
│ └── refs
│ ├── heads
│ │ ├── dev
│ │ ├── master
│ │ └── tmp
│ └── remotes # 新增目錄
│ └── origin # 新增目錄
│ └── master # 新增文件
└── refs
├── heads
│ ├── dev
│ ├── master
│ └── tmp
├── remotes # 新增目錄
│ └── origin # 新增目錄
│ └── master # 新增文件
└── tags
遠(yuǎn)程倉(cāng)庫(kù)存儲(chǔ)代碼
使用 GitLab 來(lái)了解遠(yuǎn)程倉(cāng)庫(kù)的服務(wù)器到底是如何存儲(chǔ),我們的代碼的!
當(dāng)我們編寫(xiě)完代碼之后,將其提交到對(duì)應(yīng)的遠(yuǎn)程服務(wù)器上面,其存儲(chǔ)結(jié)構(gòu)和我們地址是一模一樣的。如果我們仔細(xì)想想的話,不一樣的話才見(jiàn)怪了。
Git 本來(lái)就是代碼的分發(fā)平臺(tái),無(wú)中心節(jié)點(diǎn),即每個(gè)節(jié)點(diǎn)都是主節(jié)點(diǎn),所以其存儲(chǔ)的目錄結(jié)構(gòu)都是一直的。這樣,不管哪一個(gè)節(jié)點(diǎn)的內(nèi)容發(fā)生丟失或缺失的話,我們都可以通過(guò)其他節(jié)點(diǎn)來(lái)找到。而 Git 服務(wù)器就是一個(gè)可以幫助我們,實(shí)時(shí)都可以找到的節(jié)點(diǎn)而已。
-
CVS
+關(guān)注
關(guān)注
0文章
14瀏覽量
10984 -
Git
+關(guān)注
關(guān)注
0文章
198瀏覽量
15755 -
版本管理
+關(guān)注
關(guān)注
0文章
7瀏覽量
160
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論