本機測試環境:macOS 11
01 | 課程綜述#
VSC:版本控制系統
- 集中式 —— 客戶端必須時刻和伺服器相連
- SVM
- 分佈式 —— 伺服器和客戶端都有完整的版本庫
- Git,Linus 開發
- 基於 Git 的開源社區 —— 背景:DevOps 時代,開發運維
- GitHub—— 全球最大
- GitLab—— 公司常用;免費、提供了持續集成 - CI;如阿里雲、點評
02 | 安裝 Git#
- 起步 - 安裝 Git—— 官網:Linux、macOS、Windows、源碼
03 | 使用 Git 之前需要做的最小配置#
## 添加name和email配置
git config [--local | --global | --system] user.name '你的名字'
git config [--local | --global | --system] user.email '你的郵箱'
## 查看現有配置
git config --list [--local | --global | --system]
## 區別
## --local:本倉庫
## --global: 當前用戶的所有倉庫
## --system: 本系統的所有用戶
- 作用:記錄人員信息,CR(Code Review,代碼審查)時也可以對應發郵件提醒
04 | 創建第一個倉庫並配置 local 用戶信息#
- 創建倉庫的兩種方式,均會生成.git 文件夾
## 在已有項目文件夾裡創建git倉庫
git init
## 新建一個名為[Project Name]的git倉庫
git init [Project Name]
- 如果需要單獨配置 local 用戶信息,使用 --local 配置即可,該種配置優先級最高,見上一節
- 進行一次簡單的 commit❗️
## 添加文件到該git項目中,略
## 添加要commit的文件到
git add [File Name]
### PS:添加當前路徑下的所有文件—— git add .
## 附帶信息進行commit操作
git commit -m'一些信息'
### 查看git狀態,如:哪些文件待commit,哪些未被跟蹤
git status
### 查看git記錄,如:commit的記錄
git log
05 | 通過幾次 commit 來認識工作區和暫存區#
- 暫存區❗️——Git 的精髓之一
- 使用場景:開發兩套方案,第一套方案做好後先暫存,然後做第二套方案,如果第二套方案沒有第一套好,可以再回到第一套
- PS:
- 如果要把工作區的某個 file 替換為暫存區,則
git checkout -- file
- 如果要把工作區變更的所有文件都恢復成和暫存區的一樣,則
git checkout *
- 如果要把工作區的某個 file 替換為暫存區,則
git add -u
與git add .
- 前者:只操作已經被跟蹤的文件,即將文件的修改和刪除,添加到暫存區
- 後者:還會操作文件的新建,即將文件的創建、修改和刪除,添加到暫存區
- PS:
git add all/-A
針對整個倉庫,不只是當前路徑
- 具體操作類似上一節 —— 一次簡單的 commit
06 | 給文件重命名的簡便方法#
- 細化步驟
## 重命名
mv readme readme.md
## 添加新文件readme.md
git add readme.md
## 刪除被跟蹤的舊文件readme
git rm readme
## 提交
git commit -m"重命名"
- 使用
git reset --hard
回退到最新的一次提交,即清空暫存區 - 再展示精簡步驟
## 一條命令頂上面三條
git mv readme readme.md
## 提交
git commit -m"重命名"
- 實操展示
通過 git status 實時觀察暫存區狀態。
PS:第一種方式 git status 也能檢測出是 renamed
07 | 通過 git log 查看版本演變歷史#
## 查看簡潔的單行歷史
git log --oneline
## 查看最近的4條歷史
git log -n4
git log -4
## 查看所有分支的歷史
git log --all
## 查看指定分支(名為BRANCH_NAME)的歷史
git log BRANCH_NAME
## 查看圖形化的版本歷史
git log --graph
## 組合使用:查看所有分支最近4條圖形化的單行歷史
git log --all -n4 --graph --oneline
## 跳轉到网页版的git log幫助文檔
git help --web log
git log --all -n4 --graph --oneline
效果圖
附加命令
git branch
查看本地有哪些分支,-a
會同時查看本地和遠程的分支git checkout -b
<new_branch> []- 創建名為 new_brach(以 commit hash 值為 start point 的 commit 為基)的新分支
- 為了簡便,start point 可以選取 hash 值的一個片段,只要能夠唯一標識 commit 即可
git commit -am'msg'
- 直接將工作區和暫存區中的文件添加到版本庫中,相當於使用了 add
- ⚠️:只能提交已經被跟蹤的文件,新建的文件還是要先通過
git add .
添加到暫存區
PS
- 可以在~/.zshrc 裡,通過別名設置更友好的 log 顯示方式,設置好後使用
lg ...
即可
alias lg="git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
- 一般地,單字母的選項對應
-
,非單字母的選項是--
08 | gitk:通過圖形界面工具來查看版本歷史#
- Mac 下安裝:
brew install git-gui
- 使用:
gitk
- 界面簡單展示
- 選擇 View-New View 後,選中 All refs 後,即可展示所有分支、Tag 信息
- 右鍵某一個 commit 有很多操作,如 Create tag
PS
- 為什麼一次 commit 既有作者 Author,又有提交人 Committer
- 尊重版權
- 比如
git cherry-pick
命令:將指定的 commit 應用於其他分支 - 具體使用參考git cherry-pick 教程—— 阮一峰
- 另推薦一款 Git 圖形界面工具:Sourcetree,其實工具之間大同小異,看個人習慣
09 | 探密.git 目錄#
Git 具有優秀的存儲能力,不需要網絡,本地也能做版本管理
- 🌟4 個關鍵文件:HEAD、config、refs、objects,下面一一剖析
- ❗️3 個重要對象:commit、tree、blob,PS:tag
- 關係圖如上,參考GIT 對象模型——Git Community Book 中文版
- blob:全稱 Binary Large Object,即二進制大型對象,可理解為文件對象
- 下一節還會深入講解,先來看看 4 個關鍵文件~
- HEAD:指向當前正在工作的分支
手動修改 HEAD 裡的分支,效果同 git checkout
- config:本地倉庫(local)配置信息
主要關注 user 信息
手動修改 config 文件,效果同 git config --local
- refs:包含 heads 和 tags 文件夾
- heads 裡每個分支存放的是一個 commit 的 hash 值
- tags 裡每個里程碑存放的也是一個 commit 的 hash 值
- 也可能是一個 tag 的 hash 值,其又指向 commit
git cat-file
:顯示版本庫對象的信息-t
:類型-p
:內容(直接用 cat 命令可能會顯示亂碼,因為這些對象需要解析)- 後者接唯一的 hash 值或文件名即可
PS:細心的你會發現一個 commit 裡存儲了一個 tree 的 hash 值,是不是和一開始的關係圖串起來了,再試試查看 tree 的內容
- objects:存放所有對象,包括 tree /blob/commit
- 1)大部分文件夾📁都是以 hash 值的前 2 位字符命名,裡面存放 38 位字符命名的文件
- 由這 40 位字符組成唯一的 hash 值,指向一個對象
- 2)tree 對象裡存儲了 blob 對象信息,blob 對象的內容就是某個文件的內容,如 css.x
- tree 對象裡還可以存儲另一個 tree 對象信息
- 只要文件的內容相同,在 Git 眼裡它就是唯一的一个 blob
- 3)blob 對象內容與其指向的文件內容一致
- 一定會一致嗎?不一定,和版本有關
- PS:還有 pack 文件夾和 info 文件夾
- 前者用於存放打包的鬆散的文件夾,後者與前者相配合
10 | commit、tree 和 blob 三個對象之間的關係#
上一節提到了它們仨,這一節再具體看一個 commit,加深理解
- 這是它們三者的關係圖,可以關注箭頭的走向,參考GIT 對象模型——Git Community Book 中文版
- 解析
- 一個 commit 裡的內容由一棵 tree 來管理,有且只有一棵
- 存放當前 commit 裡所有文件夾和文件的一個快照
- 一棵 tree 裡可以有多個子 tree 和多個 blob
- 一個 blob 裡存儲的就是文件對象的具體信息
- 文件內容一樣則唯一,與文件名完全無關
- 一個 commit 裡的內容由一棵 tree 來管理,有且只有一棵
- 示例
commit👉tree👉blob + tree
PS: lg
是在第 7 節配置的 git log
友好顯示版命令
11 | 小練習:數一數 tree 的個數#
新建的 Git 倉庫,有且僅有 1 個 commit,僅僅包含 /doc/readme
請問內含多少個 tree、多少個 blob?
下面開始試驗🧪
## 首先新建Git倉庫
git init watch_git_object
## 進入倉庫,創建doc文件夾,並添加readme
cd watch_git_object
mkdir doc
echo "hello, world" > doc/readme
## 此時觀察.git/objects裡有沒有文件類型的文件:空
find .git/objects -type f
## 把doc添加到暫存區
git add doc/
## 再次觀察:Git生成了一個blob對象,裡面記錄了readme的內容
find .git/objects -type f
- 添加到暫存區時,就會產生 blob 對象
- ❗️此時還沒有 commit、tree 對象,下面進行 commit
## 進行commit
git commit -m'添加readme'
## 觀察.git/objects裡的文件:已經有4個了
find .git/objects -type f
## 逐個檢查它們的類型和內容,如下圖所示
git cat-file -t ***
git cat-file -p ***
- 可以看出新生成了:1 個 commit、2 個 tree
- 它們的關係是:
- commit👉tree(commit 對應一個 tree)👉tree(doc 文件夾)👉blob(readme 文件)
12 | 分離頭指針情況下的注意事項#
detached HEAD
- 產生:切換 HEAD 到某一個 commit 上(即使是某分支最新的 commit)
git checkout <HASH_OF_COMMIT>
,而非某一個分支
此時就會出現 detached HEAD 情況,你可以做一些試驗性操作,並進行 commit
1)如果不想保留這些 commit:可以直接切換回分支,不做其它額外的操作
2)如果想保留這些 commit:則需要在此創建一個新的分支,從而與分支掛鉤
- 接著對 readme 做一些修改,並進行提交,當切換回某個分支時
Git 友好提示:如果想要保留剛才的提交,可以通過 commit 的 hash 值創建一個新的分支
借助 gitk 查看此時分支的情況,可以看到,看不到剛才 commit 的影子
執行上述友好提示中的 git branch fix_readme 34976f8
前面做的提交已經與 fix_readme 分支聯繫起來了
- 小結
- 使用場景:做一些試驗性嘗試
- ⚠️:當想做保留所做的提交時,要與某個分支掛鉤
13 | 進一步理解 HEAD 和 branch#
- 帶著 2 個問題學習:
- 新建分支的時候,HEAD 會發生什麼變化?(HEAD 指向)
- HEAD 相關的使用技巧是什麼?(指代 commit,特殊標記
^
、~
)
下面一一進行探討:
- 1
HEAD 可以指向具體的分支,也可以指向具體的 commit
通過 git checkout -b <NEW_BRANCH_NAME> <BASE_BRANCH_NAME/HASH_OF_COMMIT>
命令,基於某個分支或提交,創建新的分支,並切換到新分支上
可以發現:HEAD 從指向分離頭指針,轉變到,指向 fix_new 分支上
再觀察 HEAD 文件的信息
其實,HEAD指向某個分支,而該分支指向某個特定的 commit
- 2
既然 HEAD 最終指向一個 commit,那也可以用它來指代 commit 的 hash 值啦~
比如在使用 git diff <A> <B>
比較兩個 commit 時
上面 3 條命令是等價的,即:
git diff 34976f8 a60a3d5
、 git diff HEAD HEAD~
、 git diff HEAD 'HEAD^'
⚠️:
HEAD 的 ^
和 ~
標記都可以獲取 HEAD 的祖先 commit,它們的區別可參考下圖:
這個分支圖的方向和 git log --graph
生成的圖方向相反,即 A 是最小的;且結合了有 merge 分支的情況
參考What's the difference between HEAD^ and HEAD~ in Git?——StackOverflow
PS:在 zsh 下, ^
有特殊含義,所以需要用引號包起來
學到這裡,是不是更新了自己對 Git 的認識呢~是否期待 Next Part 呢?!