Contents

Git Cheatsheet

Git 基本觀念和重要指令

Updated on 2021-06-23
  • 分成三個層級的設定,系統層級優先權最低
  • 查看設定參數
    • 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: 編輯特定層級的設定檔

/git-cheatsheet/git_state.png

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

/git-cheatsheet/file_state.png

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

/git-cheatsheet/object_relationship.png

  • 所有的物件都會以 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)
  • 每個物件都有個 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
  • 參照指向某個 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-cheatsheet/relative_name.png
  • 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 建立標示標籤
  • git reflog <branch>: 查 branch 的 ref (參照內容) 更動紀錄,預設是看 HEAD
  • git log <branch>: 查 commit 紀錄,預設是看 HEAD
    • git 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 指向該分支的 HEAD
    • git 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 找出分支的最後一個 commit
    • git branch <branch> <commit>: 重新建立分支
  • 合併衝突
    • <<<<<<< HEAD 代表目前分支 HEAD 的內容
    • >>>>>>> hotfixes 代表合併進來分支 hotfixes 的內容
    • 選擇要留下來的內容
    • stage 並 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 成功後預設會自動加上新的 commit
    • git revert -n <commit> 不會自動加上 commit,等到完成修改後,git revert --continue 建立新的 commit
    • git revert --abort 放棄這次的 revert
  • 要確認 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 等等
  • git merge <rebased branch>: 將 rebase 過的分支合併進目前的分支,會觸發 fast-forward 機制,將目前分支的 HEAD 移到 rebased branch 的 HEAD
    • --no-ff: 取消 fast-forward,正常的合併,目前的分支不會包含 rebased branch 的 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 資訊





Комментарии