Contents
Updated on 2021-06-23
Git 設定
- 分成三個層級的設定,系統層級優先權最低
- 查看設定參數
git config <level> --list: 查看特定層級的所有設定參數git config <variable-name>: 查看特定參數的值
- 參數設定
git config --system <variable-name> <variable-value>: 系統層級的設定參數,應用到每個使用者git config --global <variable-name> <variable-value>: 使用者層級的設定參數,應用到目前使用者- 常用的是
user.nameuser.email
- 常用的是
git config --local <variable-name> <variable-value>: 儲存區層級git config --local commit.template "<template-file-path>": 設定此儲存區的 commit 樣板
git config <level> --edit: 編輯特定層級的設定檔
檔案狀態

- Working Tree (工作目錄): Git管理的實體資料夾,也就是我們實際操作的資料夾(檔案)
- Index (系統索引): 存放一堆需要被commit的(異動)文件內容集合,把檔案加入索引稱 Stage 或 Cache
- Repository (檔案庫): 是Git存放檔案的位置,許多commit結點(版本)紀錄於此

- 還沒 commit 的狀態,分成四個
- untracked (未追蹤的,代表尚未被加入 Git 儲存庫的檔案狀態)
- unmodified (未修改的,代表檔案第一次被加入,或是檔案內容與 HEAD 內容一致的狀態)
- modified (已修改的,代表檔案已經被編輯過,或是檔案內容與 HEAD 內容不一致的狀態)
- staged (等待被 commit 的,代表下次執行 git commit 會將這些檔案全部送入版本庫)
Git 物件結構

- 所有的物件都會以 zlib 演算法進行壓縮,封裝 (pack) 的時候也可以利用差異壓縮 (delta compression) 演算法來節省空間
- 共有四種物件
- blob: staged 後產生的物件,blob 物件的內容是原始檔經過 zlib 壓縮後的檔案內容,原始檔的 Hash 成為 blob 的檔名
- tree: staged 產生後的物件,tree 物件的內容是 staged 原始檔所在的資料夾下的所有資訊,包含該目錄下的檔名、對應的 blob 物件名稱、檔案連結(symbolic link) 或其他 tree 物件等等
- commit: commit 產生後的物件,commit 物件內容是提交版本的相關資訊,該版本的 tree 物件、版本提交的時間、紀錄訊息和上一層的 commit 物件名稱
- tag: 關聯特定一個 commit 物件 (也可以關聯到特定 blob、tree 物件),並額外儲存一些額外的參考資訊(metadata)
Git 物件的絕對名稱
- 每個物件都有個 hash id,使用 hash id 必須不小於四個字元
git log: 看 commit object 的 hash id--pretty=oneline: 取得較為精簡的歷史紀錄和完整的 hash id--abbrev-commit: 縮減後的 hash id
git cat-file -p <hash>: 看該 hash 對應的 object 內容git cat-file -t <hash>: 看該 hash 對應的 object type
物件的參照 (ref) 和符號參照 (symref)
- 參照指向某個 Git 物件,可以預先定義或自行定義名稱來代表某一個 Git 物件,例如 branch 的名稱就是 ref,指向該 branch 最新的 commit
- 參照檔案的目錄主要有三個
- 本地分支:
.git/refs/heads/ - 遠端分支:
.git/refs/remotes/ - 標籤:
.git/refs/tags/
- 本地分支:
- 符號參照是指向另一個參照的參照,檔案放在
.git/- HEAD: 指向 working dir 的 branch 所在的 commit
- ORG_HEAD: HEAD 的前一版,當在做一些比較「危險」的操作(例如像 merge、rebase 或 reset 之類的),Git 就會把 HEAD 的狀態存放在這裡
- FETCH_HEAD: 紀錄遠端儲存庫每個分支的 HEAD
- MERGE_HEAD: 合併來源的 commit
git update-ref <refname> <hash>: 建立一個 ref 指向特定的 Git object,預設建立在.git/,若要建立較為正式的參照名稱,在<refname>前面加上refs/,建立的目錄在.git/refs/git update-ref -d <refname>: 刪除參照git show-ref: 顯示所有在.git/refs/的參照git rev-parse: 解析參照指向的 object hash
相對名稱表示法
~: 第一個上層 commit 物件^: 擁有多個上層 commit 物件時,要代表第幾個第一代的上層物件
標籤
- Git 標籤 (Tag) 擁有兩種型態,這兩種類型分別是:
- 輕量標籤 (lightweight tag): 是一種物件參照,指向某個 commit
git tag: 列出所有標籤git tag <tagname>: 對 HEAD 建立輕量標籤git tag <tagname> -d: 刪除標籤
- 標示標籤 (annotated tag): 是一種物件,包含關聯的 commit 和版本訊息
git tag -a <tagname> -m <message>: 對 HEAD 建立標示標籤
- 輕量標籤 (lightweight tag): 是一種物件參照,指向某個 commit
查看版本更動紀錄
git reflog <branch>: 查 branch 的 ref (參照內容) 更動紀錄,預設是看 HEADgit log <branch>: 查 commit 紀錄,預設是看 HEADgit log -g <branch>: 查 reflog 並顯示 commit 紀錄,預設是看 HEAD
- 只有 object 會被同步到遠端儲存庫,參照內容不會,所以 reflog 也不會
- reflog 預設會保存 90 天,有 commit 的則保存 30 天
對比檔案和版本差異
- git diff 使用 tree 物件遞迴比較檔案和版本差異,有三種 tree 物件的來源
- commit graph 中的 tree object
- Index 中的 tree object (stage 後就會建立 tree object)
- working dir,雖然還沒產生 tree object,但可以使用
diff
git diff: 比對任意兩個版本- : default, 比對 working dir 和 Index 的差異
<commit>: 比對 working dir 和指定 commit 的差異--cached <commit>aka--staged <commit>: 比對 Index 與指定 commit 的差異<commit> <commit>: 比對兩個 commit 的差異
暫存版本
- 建立暫存版本,預設會將目前已追蹤的檔案建立分支,
stashsymref 指向該分支的 HEADgit stash -m "<message>": 會將所有已列入追蹤(tracked)的檔案建立暫存版git stash -um "<message>": 會包括所有已追蹤或未追蹤的檔案,全部都建立成暫存版
- 查看暫存版本
git stash list
- 取回暫存版本
git stash pop: 取回最近的暫存,把暫存分支合併回目前分支,並刪除分支stash@{1}: 取回特定的暫存
git stash apply: 合併暫存分支後,不刪除分支
- 刪除暫存版本
git stash drop stash@{1}: 刪除特定暫存版本git stash clear: 刪除所有暫存版本
還原檔案內容
git checkout: 不論檔案狀態是 unstaged、modified 或是 deleted 都可以恢復內容,使檔案回到未修改前的樣子 (與 HEAD 內容一致的狀態)-- <file>
還原檔案狀態
git reset: 讓 HEAD 移動到指定的 commit--soft: reset 指定的 commit 到 Repo,只會改變 HEAD,可用來合併 commit--mixed: defualt, reset 指定的 commit 到 Repo、Index,與指定 commit 不同的檔案會變成 unstaged--hard: reset 指定的 commit 到 Repo、Index、Working Tree,reset 所有更變
分支
- 建立一個 ref 到目前的 commit,每個分支會有自己的 HEAD
git checkout <commit>&&git checkout -b <branch>: 工作目錄切換到某個 commit,並建立分支
分支合併
- 合併注意事項
- 合併之前,確認目前的分支
- 合併之前,確認 working dir 沒有 uncommitted change
- 使用
git merge <other branch>來將另一個分支合併進來 - 合併成功後,會建立一個新的 commit
- 合併成功後,刪除不必要的分支
- 合併分支
git merge <other branch>: 將另一個分支合併進來
- 刪除分支
git branch -d <branch>: 刪除有合併過的分支git branch -D <branch>: 刪除沒有合併過的分支
- 救回誤刪分支
git reflog找出分支的最後一個 commitgit branch <branch> <commit>: 重新建立分支
- 合併衝突
<<<<<<< HEAD代表目前分支 HEAD 的內容>>>>>>> hotfixes代表合併進來分支 hotfixes 的內容- 選擇要留下來的內容
- stage 並 commit
修正 commit 歷史紀錄
- 完成小功能就建立 commit,較容易追蹤更變
- 把 commit 修正成有邏輯的內容和順序
- 還沒 push 之前都可以修改,已經 push 就原則上不修改
- 刪除某 commit 之後的 commit,與刪除其之後的內容更變
git reset --hard <commit>來刪除 commit 之後的版本,例如git reset --hard "HEAD^"刪除最近一次版本
- 刪除某 commit 之後的 commit,但不刪除內容更變
git reset --soft <commit>移動 HEAD 到 commit- stage 並 commit,蓋掉原本的 commit
- 更改最後一個 commit 的檔案內容
- 把要更改的檔案內容放入 Index
git commit --amend
- 刪除某 commit 的內容更變,但不刪除此 commit
git revert之前,要確認 working dir 沒有 uncommitted change,如果有更改到一半的,可以用git stash先建立暫存版本git revert <commit>來刪除內容更變,若目前檔案與該 commit 有衝突,則要修改衝突,revert 成功後預設會自動加上新的 commitgit revert -n <commit>不會自動加上 commit,等到完成修改後,git revert --continue建立新的 commitgit revert --abort放棄這次的 revert
Rebase
- 要確認 working dir 沒有 uncommitted change,如果有更改到一半的,可以用
git stash先建立暫存版本 - 如果分支是從遠端庫下載回來的,不要用 rebase 修改歷史紀錄,會無法 push
- rebase 能做的事
- 調換 commit 的順序
- 修改 commit 的訊息
- 插入一個 commit
- 編輯一個 commit
- 拆解一個 commit
- 壓縮一個 commit,且保留訊息紀錄
- 壓縮一個 commit,但丟棄版本紀錄
- 刪除一個 commit
git rebase <branch or commit>: 將目前分支的 HEAD 回到跟 branch 一樣的分支起點 (rewinding head),然後在 branch 的某個 commit (預設是 HEAD) 上重新套用 (replay) 從分支起點到該 commit 的更變,到目前分支在分支起點後的所有 commit-i: 指定 branch 上的 commit,而不是使用預設的 HEAD。會進入到 rebase 編輯介面 (最上方是最舊的 commit,與 git log 相反),可以調整順序、編輯 commit 訊息、新增 commit、編輯 commit 等等
Rebase 後的合併
git merge <rebased branch>: 將 rebase 過的分支合併進目前的分支,會觸發 fast-forward 機制,將目前分支的 HEAD 移到 rebased branch 的 HEAD--no-ff: 取消 fast-forward,正常的合併,目前的分支不會包含 rebased branch 的 commit
從其他分支選想要的 commit
git cherry-pick之前,要確認 working dir 沒有 uncommitted change,如果有更改到一半的,可以用git stash先建立暫存版本git cherry-pick <commit>: 通常會從其他分支選 commit 來加到目前的分支- : 預設自動建立 commit,且版本訊息會和原本的一樣
-x: 會像git revert一樣,版本訊息自動加上(cherry picked from commit ...)。特別注意,若加進來的版本只有在本地,會造成其他人使用遠端庫時查不到-n: 不會自動建立 commit,可以加上自己的修改後再git commit,也就會有自己的 Author、Date 資訊
參考資料
- [Git] Reset - mixed, hard and soft
- Git reset 的三種模式( soft mixed hard )比較
- 30 天精通 Git 版本控管
- git-tutorial - zlargon
Комментарии