Bo2SS

Bo2SS

1 Git基礎

本機測試環境:macOS 11

01 | 課程綜述#

VSC:版本控制系統

  • 集中式 —— 客戶端必須時刻和伺服器相連
    • SVM
  • 分佈式 —— 伺服器和客戶端都有完整的版本庫
    • Git,Linus 開發
    • 基於 Git 的開源社區 —— 背景:DevOps 時代,開發運維
      • GitHub—— 全球最大
      • GitLab—— 公司常用;免費、提供了持續集成 - CI;如阿里雲、點評

02 | 安裝 Git#

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 來認識工作區和暫存區#

image

  • 暫存區❗️——Git 的精髓之一
    • 使用場景:開發兩套方案,第一套方案做好後先暫存,然後做第二套方案,如果第二套方案沒有第一套好,可以再回到第一套
    • PS:
      • 如果要把工作區的某個 file 替換為暫存區,則 git checkout -- file
      • 如果要把工作區變更的所有文件都恢復成和暫存區的一樣,則 git checkout *
  • git add -ugit 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"重命名"
  • 實操展示

image

通過 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 效果圖

image

附加命令

  • 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
  • 界面簡單展示

image

  1. 選擇 View-New View 後,選中 All refs 後,即可展示所有分支、Tag 信息
  2. 右鍵某一個 commit 有很多操作,如 Create tag

PS

  • 為什麼一次 commit 既有作者 Author,又有提交人 Committer
    • 尊重版權
    • 比如 git cherry-pick 命令:將指定的 commit 應用於其他分支
    • 具體使用參考git cherry-pick 教程—— 阮一峰
  • 另推薦一款 Git 圖形界面工具:Sourcetree,其實工具之間大同小異,看個人習慣

09 | 探密.git 目錄#

Git 具有優秀的存儲能力,不需要網絡,本地也能做版本管理

image

  • 🌟4 個關鍵文件:HEAD、config、refs、objects,下面一一剖析
  • ❗️3 個重要對象:commit、tree、blob,PS:tag

image

  1. 關係圖如上,參考GIT 對象模型——Git Community Book 中文版
  2. blob:全稱 Binary Large Object,即二進制大型對象,可理解為文件對象
  3. 下一節還會深入講解,先來看看 4 個關鍵文件~
  • HEAD:指向當前正在工作的分支

image

手動修改 HEAD 裡的分支,效果同 git checkout

  • config:本地倉庫(local)配置信息

image

主要關注 user 信息

手動修改 config 文件,效果同 git config --local

  • refs:包含 heads 和 tags 文件夾

image

  • 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

image

  • 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,加深理解

image

  • 這是它們三者的關係圖,可以關注箭頭的走向,參考GIT 對象模型——Git Community Book 中文版
  • 解析
    • 一個 commit 裡的內容由一棵 tree 來管理,有且只有一棵
      • 存放當前 commit 裡所有文件夾和文件的一個快照
    • 一棵 tree 裡可以有多個子 tree 和多個 blob
    • 一個 blob 裡存儲的就是文件對象的具體信息
      • 文件內容一樣則唯一,與文件名完全無關
  • 示例

image

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

image

  • 添加到暫存區時,就會產生 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 ***

image

  • 可以看出新生成了:1 個 commit、2 個 tree
  • 它們的關係是:
    • commit👉tree(commit 對應一個 tree)👉tree(doc 文件夾)👉blob(readme 文件)

12 | 分離頭指針情況下的注意事項#

detached HEAD

  • 產生:切換 HEAD 到某一個 commit 上(即使是某分支最新的 commit)

image

git checkout <HASH_OF_COMMIT> ,而非某一個分支

此時就會出現 detached HEAD 情況,你可以做一些試驗性操作,並進行 commit

1)如果不想保留這些 commit:可以直接切換回分支,不做其它額外的操作

2)如果想保留這些 commit:則需要在此創建一個新的分支,從而與分支掛鉤

  • 接著對 readme 做一些修改,並進行提交,當切換回某個分支時

image

Git 友好提示:如果想要保留剛才的提交,可以通過 commit 的 hash 值創建一個新的分支

借助 gitk 查看此時分支的情況,可以看到,看不到剛才 commit 的影子

image

執行上述友好提示中的 git branch fix_readme 34976f8

image

前面做的提交已經與 fix_readme 分支聯繫起來了

  • 小結
    • 使用場景:做一些試驗性嘗試
    • ⚠️:當想做保留所做的提交時,要與某個分支掛鉤

13 | 進一步理解 HEAD 和 branch#

  • 帶著 2 個問題學習:
  1. 新建分支的時候,HEAD 會發生什麼變化?(HEAD 指向)
  2. HEAD 相關的使用技巧是什麼?(指代 commit,特殊標記 ^~

下面一一進行探討:

  • 1

HEAD 可以指向具體的分支,也可以指向具體的 commit

通過 git checkout -b <NEW_BRANCH_NAME> <BASE_BRANCH_NAME/HASH_OF_COMMIT> 命令,基於某個分支或提交,創建新的分支,並切換到新分支上

image

可以發現:HEAD 從指向分離頭指針,轉變到,指向 fix_new 分支上

再觀察 HEAD 文件的信息

image

其實,HEAD指向某個分支,而該分支指向某個特定的 commit

  • 2

既然 HEAD 最終指向一個 commit,那也可以用它來指代 commit 的 hash 值啦~

比如在使用 git diff <A> <B> 比較兩個 commit 時

image

上面 3 條命令是等價的,即:

git diff 34976f8 a60a3d5git diff HEAD HEAD~git diff HEAD 'HEAD^'

⚠️:

HEAD 的 ^~ 標記都可以獲取 HEAD 的祖先 commit,它們的區別可參考下圖:

image

這個分支圖的方向和 git log --graph 生成的圖方向相反,即 A 是最小的;且結合了有 merge 分支的情況

參考What's the difference between HEAD^ and HEAD~ in Git?——StackOverflow

PS:在 zsh 下, ^ 有特殊含義,所以需要用引號包起來

學到這裡,是不是更新了自己對 Git 的認識呢~是否期待 Next Part 呢?!

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。