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.name
user.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 的差異
暫存版本
- 建立暫存版本,預設會將目前已追蹤的檔案建立分支,
stash
symref 指向該分支的 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
Комментарии