書接上文,咱們對Git有了一個基本的認知,而且基礎工做也作好了。接下來,筆者就用一個實例,對照執行命令先後文件的變化,探索如下命令的運行過程。若是,看官對命令底層原理不感興趣,只是想知道命令怎麼用,就直接看翻到文章最後。git
git init
git add
git status
git commit
git log
行文時,系統環境爲 macOS Mojave v10.14.5,Git版本爲 2.20.1 ,開發工具爲 vscode 1.45.1 。
shell
git init
首先,咱們須要有一個工做目錄(Working Directory)。工做目錄能夠是剛新建無文件的文件夾,也能夠是一個已經有文件的文件夾。bash
mkdir git-kael-project
cd git-kael-project
複製代碼
而後,我須要使用 git init
對工做目錄進行初始化。 git init
命令以後能夠帶上文件夾名稱,若是文件夾不存在,則在當前路徑下新建文件夾,並將其初始化。若是存在就直接對文件夾初始化。app
git init
git init folderName
複製代碼
接下來,讓咱們看一下執行 git init
先後,工做目錄的區別。工具
# 未初始化
ls -al
total 0
drwxr-xr-x 2 apple staff 64 5 29 22:31 .
drwxr-xr-x+ 45 apple staff 1440 5 29 22:31 ..
# 初始化
git init
ls -al
total 0
drwxr-xr-x 3 apple staff 96 5 29 22:32 .
drwxr-xr-x+ 45 apple staff 1440 5 29 22:31 ..
drwxr-xr-x 9 apple staff 288 5 29 22:32 .git # 多了一個 .git 文件夾,這就是咱們說的倉庫!
複製代碼
對比,咱們能夠知道, git init
命令就是在工做目錄的根目錄下,生成一個 .git 文件夾,這個文件就是咱們這個項目的 Git 倉庫。它包含了幾乎全部 Git 存儲和操做的東西。 要想備份或複製一個版本庫,只需把這個目錄拷貝至另外一處便可。
咱們查看一下, .git 文件夾裏到底有什麼開發工具
ls -al .git/
total 24
drwxr-xr-x 9 apple staff 288 5 29 21:41 .
drwxr-xr-x 3 apple staff 96 5 29 21:41 ..
-rw-r--r-- 1 apple staff 23 5 29 21:41 HEAD # HEAD指針,後文再講
-rw-r--r-- 1 apple staff 137 5 29 21:41 config # 項目配置,使用 git config --loacl 時,配置的內容就存放在這裏
-rw-r--r-- 1 apple staff 73 5 29 21:41 description # 項目描述文件,給GitWeb使用,咱們不用關心
drwxr-xr-x 13 apple staff 416 5 29 21:41 hooks # 鉤子,存放的是一些 shell 腳本
drwxr-xr-x 3 apple staff 96 5 29 21:41 info # 目錄下面的 exclude 文件,是用來存放不想放置在 .gitignore 文件裏的忽略模式
drwxr-xr-x 4 apple staff 128 5 29 21:41 objects # 項目全部的 git 對象都被存放在這裏,tree 對象、parent 對象、blob 對象
drwxr-xr-x 4 apple staff 128 5 29 21:41 refs # 存放指針的位置,branch 、remote 、tag
# -rw-r--r-- 1 apple staff xx x xx xx:xx index # 暫存區,還未生成
複製代碼
你們能夠先對上面的目錄結構稍微記憶一下。強調一下,由於尚未執行任何操做,因此如今暫存區還沒被建立,也就是 index 文件!
ui
git add
接下來,咱們新建一個 hello-git.txt 文件。編碼
touch hello-git.txt
複製代碼
再加入到暫存區以前,咱們先查看一下spa
# 當前狀態下,是沒有index文件的,也就是無暫存區
ls -al .git/
total 24
drwxr-xr-x 11 apple staff 352 5 29 22:47 .
drwxr-xr-x 5 apple staff 160 5 29 22:47 ..
-rw-r--r--@ 1 apple staff 23 5 29 21:41 HEAD
-rw-r--r-- 1 apple staff 137 5 29 21:41 config
-rw-r--r-- 1 apple staff 73 5 29 21:41 description
drwxr-xr-x 13 apple staff 416 5 29 21:41 hooks
drwxr-xr-x 3 apple staff 96 5 29 21:41 info
drwxr-xr-x 5 apple staff 160 5 29 22:37 objects
drwxr-xr-x 4 apple staff 128 5 29 21:41 refs
# 同時.git/objects下,也是沒有git對象的
ls -al .git/objects/
total 0
drwxr-xr-x 5 apple staff 160 5 29 22:37 .
drwxr-xr-x 11 apple staff 352 5 29 22:47 ..
drwxr-xr-x 2 apple staff 64 5 29 21:41 info
drwxr-xr-x 2 apple staff 64 5 29 21:41 pack
複製代碼
而後,咱們用 git add
命令,把 hello-git.txt 加入到暫存區。以後咱們再查看一下3d
固然,我這裏查看的就是執行命令後,會有變化的位置。其它位置是沒有變化的,各位看官可自行驗證。
# git add 命令,後面能夠帶文件名(這裏能夠是一個或多個),也能夠帶符號點 . ,符號點與 --all 全等。
# git add . 與 git add --all 效果同樣
git add hello-git.txt
# 查看 .git/
ls -al .git/
total 48
drwxr-xr-x 11 apple staff 352 5 29 22:47 .
drwxr-xr-x 5 apple staff 160 5 29 22:47 ..
-rw-r--r--@ 1 apple staff 6148 5 29 22:47 .DS_Store
-rw-r--r--@ 1 apple staff 23 5 29 21:41 HEAD
-rw-r--r-- 1 apple staff 137 5 29 21:41 config
-rw-r--r-- 1 apple staff 73 5 29 21:41 description
drwxr-xr-x 13 apple staff 416 5 29 21:41 hooks
-rw-r--r--@ 1 apple staff 32 5 29 22:46 index # 這個暫存區終於出來!
drwxr-xr-x 3 apple staff 96 5 29 21:41 info
drwxr-xr-x 5 apple staff 160 5 29 22:37 objects
drwxr-xr-x 4 apple staff 128 5 29 21:41 refs
# 查看 .git/objects/
ls -al .git/objects/
total 0
drwxr-xr-x 5 apple staff 160 5 29 22:37 .
drwxr-xr-x 11 apple staff 352 5 29 22:47 ..
drwxr-xr-x 3 apple staff 96 5 29 22:37 e6
drwxr-xr-x 2 apple staff 64 5 29 21:41 info
drwxr-xr-x 2 apple staff 64 5 29 21:41 pack
# 繼續查看 .git/objects/e6/
ls -al .git/objects/e6/
total 8
drwxr-xr-x 3 apple staff 96 5 29 22:37 .
drwxr-xr-x 5 apple staff 160 5 29 22:37 ..
-r--r--r-- 1 apple staff 15 5 29 22:37 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
複製代碼
到這裏,咱們能夠清楚的看到,當咱們執行了 git add hello-git.txt
以後,倉庫發生的變化。
git ls-files --stage
查看暫存區的內容
對於 git add
這個命令,其實它是 git hash-object
和 git update-index
這兩個底層命令組合實現的。也就是說,若是你願意,你是可使用這兩個底層命令來 裝逼 操做的。 git add
只是爲了簡化操做而實現的上層命令。這兩個底層命令後續有機會再講!
git status
好了,在看官平時工做當中,可能會出現,離開工位一段時間,回來時就不記得以前在工做目錄作了什麼(嗯,應該只有筆者纔會這樣zz)。這個時候,你能夠努力回想使用 git status
查看工做目錄的狀態。
git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: hello-git.txt
# 打印的信息告訴咱們,在 master 分支上,有一個尚未提交的新文件: hello-git.txt。
# 括號裏還告訴咱們,可使用 git rm --cached filename 來把文件從暫存區移走。
複製代碼
若是你想,你也可使用 git ls-files --stage
來 裝逼 操做。
git ls-files --stage
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 hello-git.txt
複製代碼
git commit
把修改加入到暫存區以後,使用 git commit
命令,生成整個項目的‘全貌快照’,也就是 commitObject 。項目版本歷史就是由一個個 commitObject 組成的,Git 能夠將項目還原到任意一個 commitObject 。生成一個 commitObject 又叫 完成一次提交。
# 在使用 git add 時,咱們能夠有選擇的把文件加放到暫存區
# 可是在使用 git commit 時,必定是把暫存區裏包含的 blob 對象所有一塊兒,生成一個 commitObject。
# git commit --amend 後面會在應用場景裏講,能夠先理解爲修改前一個 commitObject。
# 雖然表面上來看是這樣。可是實際上是不對的。commitObject 在大部分狀況下,是沒法修改的。
git commit -m 'create hello-git.txt'
[master (root-commit) 9eb3d5f] create hello-git.txt
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 hello-git.txt
# 提示信息裏,有 分支、commitObject 的校驗和、commitMessage、修改的內容統計。
複製代碼
老規則,咱們來對比看一下, 輸入 git commit
命令先後, .git 裏的文件變化。
# 下面信息是在 git commit 命令以前查看的。
ls -al .git/
total 32
drwxr-xr-x 10 apple staff 320 5 30 17:27 .
drwxr-xr-x 5 apple staff 160 5 30 17:27 ..
-rw-r--r-- 1 apple staff 23 5 30 17:26 HEAD
-rw-r--r-- 1 apple staff 137 5 30 17:26 config
-rw-r--r-- 1 apple staff 73 5 30 17:26 description
drwxr-xr-x 13 apple staff 416 5 30 17:26 hooks
-rw-r--r-- 1 apple staff 112 5 30 17:26 index
drwxr-xr-x 3 apple staff 96 5 30 17:26 info
drwxr-xr-x 5 apple staff 160 5 30 17:26 objects
drwxr-xr-x 4 apple staff 128 5 30 17:26 refs
# 下面信息是在 git commit 命令以後查看的。
ls -al .git/
total 56
drwxr-xr-x 13 apple staff 416 5 30 17:22 .
drwxr-xr-x 4 apple staff 128 5 30 17:22 ..
-rw-r--r-- 1 apple staff 21 5 30 17:10 COMMIT_EDITMSG
-rw-r--r--@ 1 apple staff 23 5 29 21:41 HEAD
-rw-r--r-- 1 apple staff 137 5 29 21:41 config
-rw-r--r-- 1 apple staff 73 5 29 21:41 description
drwxr-xr-x 13 apple staff 416 5 29 21:41 hooks
-rw-r--r-- 1 apple staff 145 5 30 17:10 index
drwxr-xr-x 3 apple staff 96 5 29 21:41 info
drwxr-xr-x 5 apple staff 160 5 30 17:22 logs
drwxr-xr-x 8 apple staff 256 5 30 17:10 objects
drwxr-xr-x 4 apple staff 128 5 29 21:41 refs
# 查看logs
ls -al .git/logs/
total 24
drwxr-xr-x 5 apple staff 160 5 30 17:22 .
drwxr-xr-x 13 apple staff 416 5 30 17:22 ..
-rw-r--r--@ 1 apple staff 165 5 30 17:10 HEAD
drwxr-xr-x 4 apple staff 128 5 30 17:22 refs
ls -al .git/logs/refs/heads/
total 8
drwxr-xr-x 3 apple staff 96 5 30 17:10 .
drwxr-xr-x 4 apple staff 128 5 30 17:22 ..
-rw-r--r--@ 1 apple staff 165 5 30 17:10 master
# 查看objects
ls -al .git/objects/
total 16
drwxr-xr-x 8 apple staff 256 5 30 17:10 .
drwxr-xr-x 13 apple staff 416 5 30 17:22 ..
drwxr-xr-x 3 apple staff 96 5 30 17:10 62
drwxr-xr-x 3 apple staff 96 5 30 17:10 9e
drwxr-xr-x 3 apple staff 96 5 29 22:37 e6
drwxr-xr-x 2 apple staff 64 5 29 21:41 info
drwxr-xr-x 2 apple staff 64 5 29 21:41 pack
ls -al .git/objects/9e/
total 8
drwxr-xr-x 3 apple staff 96 5 30 17:10 .
drwxr-xr-x 8 apple staff 256 5 30 17:10 ..
-r--r--r-- 1 apple staff 131 5 30 17:10 b3d5fe6014cf11a120a26b3f8b3af2f20964bd
ls -al .git/objects/62/
total 8
drwxr-xr-x 3 apple staff 96 5 30 17:10 .
drwxr-xr-x 8 apple staff 256 5 30 17:10 ..
-r--r--r-- 1 apple staff 58 5 30 17:10 01f623b63c5736c92895712c6038835be6a7f2
複製代碼
對比能夠發現, git commit
以後,多瞭如下文件
經過對比,筆者理解的 git commit
命令執行以後,Git 作了以下事情:
-m
參數以後的 commitMessage 寫入到這個文件。git log
命令獲得的內容。
這裏,筆者再詳細的描述一下 commitObject。爲了更好的演示,咱們在當前的提交基礎上,繼續做一些操做。
mkdir lib
touch lib/lib.js
echo 'Git 真好用!' > lib/git.txt
git add .
git commit -m 'create lib/git.txt'
[master 75f75b1] create lib/git.txt
2 files changed, 1 insertion(+)
create mode 100644 lib/git.txt
create mode 100644 lib/lib.js
複製代碼
咱們新建了一個 lib/ 文件夾,而後在這個文件夾裏,新建了一個 lib.js 文件,和一個 git.txt 文件,並在git.txt 文件裏寫入了 'Git 真好用!'。接着就是 git add .
把剛的這些修改添加到暫存區,最後使用 git commit -m 'create lib/git.txt'
生成一個提交。
咱們如今獲得了一個 75f75b1
的 commitObject。咱們來查看一下這個對象的信息。
# 查看 75f75b1 的類型和詳情
git cat-file -t 75f75b1
commit # 這是一個 commit 類型的對象
git cat-file -p 75f75b1
tree d1d138a1890c432ef996b8713b69453a8baa339e # 75f75b1 對象的 tree 對象,對應的項目目錄
parent 9eb3d5fe6014cf11a120a26b3f8b3af2f20964bd # 75f75b1 對象的 parent 對象,對應着父提交對象
author kael <kael_yp@foxmail.com> 1590841110 +0800 # 75f75b1 對象的做者
committer kael <kael_yp@foxmail.com> 1590841110 +0800 # 75f75b1 對象的提交者
create lib/git.txt # 75f75b1 對象的提交說明 commitMessage
複製代碼
咱們繼續查看 d1d138a
這個 tree 對象。
# 查看 d1d138a 的類型和詳情
git cat-file -t d1d138a
tree # 這是一個 tree 類型的對象
git cat-file -p 1d138a
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 hello-git.txt # blob 類型的對象,hello-git.txt文件
040000 tree 8bc5165a0972ca341226552000d29888be651bc9 lib # tree 類型的對象,lib 文件夾
# 查看 hello-git.txt 文件
git cat-file -p e69de2
# 爲空,由於這個文件就是一個空文件。我忘記加內容了。。。哈哈
# 查看 lib 文件夾
git cat-file -p 8bc516
100644 blob cdb8667b7f629f26cae0ea24993bfd2c6411e33c git.txt # blob 類型的對象,git.txt 文件
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 lib.js # blob 類型的對象,lib.js 文件
# 查看 git.txt 文件
git cat-file -p cdb8667
Git 真好用! # 這就是咱們以前寫入的內容。這就是 Git 哲學裏的,經過文件快照記錄版本,而不是使用 diff 。
複製代碼
咱們繼續查看 9eb3d5f
這個 parent 對象。
# 查看 9eb3d5f 的類型和詳情
git cat-file -t 9eb3d5f
commit # 這是一個 commit 類型的對象
# 這是一個 parent 類型的對象
git cat-file -p 9eb3d5f
tree 6201f623b63c5736c92895712c6038835be6a7f2 # 9eb3d5f 對象的 tree 對象,對應的項目目錄
author kael <kael_yp@foxmail.com> 1590829805 +0800 # 9eb3d5f 對象的做者
committer kael <kael_yp@foxmail.com> 1590829805 +0800 # 9eb3d5f 對象的提交者
create hello-git.txt # 9eb3d5f 對象的提交說明 commitMessage
複製代碼
再看看 6201f62
這個 tree 對象。
git cat-file -p 6201f62
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 hello-git.txt
git cat-file -p e69de29
# hello-git.txt 內容爲空
複製代碼
咱們簡單描述上面查看到的信息。 75f75b1
這個對象裏有 tree 和 parent。tree 裏有 blob 和 tree。而後就是 parent 裏有 tree,沒有 parent。
若是你不想使用git commit
這個命令,那就使用 git write-tree
和 git commit-tree
來 裝逼 實現。 git write-tree
命令用來將當前的目錄結構,生成一個 treeObject。 git commit-tree
命令用於將目錄樹對象寫入版本歷史。有機會,後續再講這兩個命令。
git log
git log
這個命令是最經常使用命令之一,能夠查看指定的 指針 的提交歷史。
git log
# 第一行是 類型 校驗和 指針集,指針集裏可能會有 HEAD、branch、tag,使用逗號分開
commit 9eb3d5fe6014cf11a120a26b3f8b3af2f20964bd (HEAD -> master)
# 第二行是 做者信息
Author: kael <kael_yp@foxmail.com>
# 第三行是 時間
Date: Sat May 30 17:10:05 2020 +0800
# 往下就是 commitMessage
create hello-git.txt
複製代碼
使用 git log
命令是不會對 .git 倉庫操做的,也就是你不會有 何時什麼方式使用了 git log
命令 的記錄,由於記錄這個操做,沒有任何意義。
git log
是一個超級厲害的命令。看一我的 Git 用得好很差,看Ta使用 git log
的姿式怎麼樣就能看出來。下面我就列舉一些經常使用的 git log
使用場景和其它參數。如下選項能夠組合使用
# 正常查看歷史記錄
git log
# 查看簡潔的歷史記錄
git log --oneline
# 查看帶每一次提交時修改的歷史記錄
git log -p # -p 是 --patch 的簡寫
# 查看必定數量的歷史記錄
git log -4 # 這裏就是顯示倒數的4條
# 查看有簡略統計信息的歷史記錄
git log --stat
# 控制歷史記錄的顯示格式。
git log --pretty=format:"%h - %an, %s" # %h 簡短校驗和;%an 做者;%s 提交說明;
git log --pretty=online # 差很少等於 git log --oneline
# 查看帶結合路徑的歷史記錄,大概就是會給 commitObject 間邊上線條
git log --graph
# 查看指定時限內的歷史記錄
git log --since=1.weeks # 一週內的歷史記錄
git log --since=2020-05-01 # 查看2020年05月01號以後的提交,--since 能夠寫做 --after
# 查看指定時間以前的提交
git log --until=2020-05-01 # 查看2020年05月01號以前的提交,--until 能夠寫做 --before
# 查看包含了指定字符的message所在的歷史記錄
git log --grep=create # 查看包含了 ‘create’ 的提交說明的歷史記錄
# 這個就牛逼了,查看包含了指定字符修改的歷史記錄
git log -Svar # 查看修改裏包含了 ‘var’ 的歷史記錄
# 查看指定做者的歷史記錄
git log --author=kael # 查看 kael 寫的歷史記錄
# 查看指定提交者的歷史記錄
git log --committer=kael # 查看 kael 提交的歷史記錄
複製代碼
這個提交歷史記錄實際是經過 commitObject 的 parent 屬性連起來的,直到找到一個沒有 parent 屬性的 commitObject。能夠跟鏈表對應理解。
補充一下,.git/HEAD 文件的相關知識點。這個文件在 git init
時,裏面的內容是 ref: refs/heads/master
,是否是很眼熟?沒錯,這是一個路徑【 .git/refs/heads/master 】。當咱們提交時,HEAD 會帶着移動的分支指針。若是是第一次提交,Git 會用這個文件的內容生成對應的 分支。這也就是爲何,咱們的倉庫通常都會有一個 master 分支。若是你在 git init
以後(固然,你其實能夠在任意時候對這個文件進行修改),把這個文件的內容改爲 refs/heads/test
,那在提交時,默認就會生成 test 分支。筆者強烈建議不要改!會被同事打的! 後續會講的 git checkout
簽出命令,改的就是這個文件的內容。
補充一下,.git/logs/裏文件的相關知識點。這個文件夾下的文件,它的內容是長這樣的:
cat .git/logs/HEAD
# 首先是40個0,原本是這個記錄的 parent 的校驗和,可是由於這條記錄是第一個,沒有父對象,因此就用0佔位
# 而後是正常的40位的校驗和,這是這個記錄自身的校驗和
# 而後再是提交者,郵箱,時間
# 最後就是操做類型和 message
0000000000000000000000000000000000000000 9eb3d5fe6014cf11a120a26b3f8b3af2f20964bd kael <kael_yp@foxmail.com> 1590829805 +0800 commit (initial): create hello-git.txt
複製代碼
當咱們使用 git reflog
命令時,就是把對應的指針的 logs 文件的內容稍微處理一下顯示出來。
最後,筆者就 大概的說一下 Git 基本使用流程 祝你們六一快樂。
git ini
初始化。git add
把修改的內容添加到暫存區。git commit
把暫存區的內容生成快照提交。git status
查看當前的狀態。git log
查看歷史記錄。
世界上只有兩種人,一種懂二進制,一種不懂二進制。