Git 常用指令跟設定
基礎概念
-
Working directory: 工作目錄
-
Staging area: 暫存區
-
remote and origin: remote 指的是遠端的 repo,概念,origin 是真的一個指標指向一個 url
$ git remote -v origin https://github.com/example/repo.git (fetch) origin https://github.com/example/repo.git (push) -
HEAD: 指向現在整個工作環境所在的 commit
-
Branch: 只是指標,所以切換 branch 就是把 HEAD 指標移動到 MASTER 指標上
Config
[user]
email = bses30074@gmail.com
name = Yan-Hao-Wang
[core]
editor = vim
autocrlf = input
[color]
ui = true
[diff]
algorithm = histogram
indentHeuristic = true
[branch]
sort = -committerdate
[pull]
rebase = true
[alias]
st = status
rst = restore
ck = checkout
lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commitautocrlf = input: 在送出(Commit)時自動將 CRLF 轉為 LF,但在拉取(Checkout)時不做變動ui = true: 強制在終端機顯示顏色,讓 status 或 diff 的結果一眼就能看出哪些是新增或刪除algorithm = histogram: 比起預設的 myers,histogram 能更聰明地處理程式碼塊的搬移,產生的 diff 邏輯更貼近人類閱讀程式碼的方式indentHeuristic = true: 當你移動函數或修改巢狀縮排時,Git 會試著讓 diff 的起點和終點對齊縮排,讓修改看起來更整潔sort = -committerdate: 當你執行 git branch 時,它會把最近操作過的分支排在最上面rebase = true執行 git pull 時預設用 rebase 而不是 mergelg = ...: 它會用漂亮的顏色與線條畫出分支拓撲圖,並顯示相對時間(如 2 hours ago)與作者
常用指令速查表
| 分類 | 指令 | 功能說明 | 備註 |
|---|---|---|---|
| 暫存與提交 (Add/Commit) | git add -p |
互動式暫存已追蹤檔案的部分區塊 | 適合將一個檔案拆成多個 commit |
git add *xxx* |
可以用正則表達式來加入檔案,會比較快 | 避免打太長的路徑 | |
git commit --amend |
將目前的修改併入上一次 commit | 常用於修正 commit 訊息或補檔 | |
| 還原 (Restore) | git restore <file> |
將工作目錄檔案還原至 HEAD 狀態 | 取代舊版 git checkout <file> |
git restore --staged <file> |
將檔案從暫存區移回工作目錄 | 讓檔案變成「已修改但未暫存」 | |
git restore --source HEAD~2 <f> |
將特定檔案還原至前兩個版本的狀態 | 只針對單一檔案進行時光倒流 | |
| 重置 (Reset) | git reset --soft HEAD~1 |
退回版本,保留暫存區與工作目錄修改 | 適合重新組合多個 commit |
git reset --mixed HEAD~1 |
退回版本,重置暫存區,保留工作目錄 | Git 的預設重置模式 | |
git reset --hard HEAD~1 |
退回版本,刪除所有未提交的修改 | 危險:所有更動都會消失 | |
| 日誌與差異 (Log/Diff) | git log --oneline <file> |
以單行模式顯示特定檔案的 commit 紀錄 | 快速追蹤該檔案的歷史 |
git log --name-only |
若要在 git log 中僅顯示被變更的檔案名稱 | ||
git log --name-status |
若需要同時顯示操作類型(新增、修改、刪除) | ||
git diff --staged |
比較「暫存區」與「最後一次提交」差異 | 確認準備要 commit 的內容 | |
git diff --color-words |
顯示單字級差異,不顯示 +/- 符號 |
適合需要複製乾淨程式碼時使用 | |
git diff -U1000 |
顯示前後各 1000 行的上下文 | 適合 Review 較長的函數邏輯 | |
git diff > a.patch |
產生成純文字格式的補丁檔,之後使用 git apply 套用 |
純文字專案專用。適合透過 Email 傳送輕量化的程式碼變更 | |
git diff --binary > a.patch |
產生成包含二進位資料的完整補丁檔 | 含有編譯產物或圖檔時必用 | |
| 分支 (Branch/Checkout) | git checkout -b <name> |
建立新分支並立即切換過去 | 常用於開發新 Feature |
git branch -m <new_name> |
修改當前分支的名稱 | ||
git branch -vv |
查看本地分支與遠端分支的追蹤關係 | 確認 Upstream 設定是否正確 | |
git branch -D <branch> |
強制刪除分支(不論是否已合併) | ||
| 合併與重底 (Merge/Rebase) | git merge <branch> --no-ff |
合併時強制產生一個 Merge Commit | 保留完整的分支開發軌跡 |
git rebase <new_base> |
將當前分支的基準點移動到 new_base |
維持線性歷史,線圖更整潔 | |
git rebase -i HEAD~n |
互動式 Rebase,編輯最近 n 個 commit | 可進行 squash (合併) 或 edit | |
| 遠端 (Remote/Push) | git push <rem> <b1>:<b2> |
本地 b1 推送到遠端並命名為 b2 |
手動指定遠端分支名稱 |
git push <rem> :<branch> |
刪除指定的遠端分支 | 冒號前留白代表「推入空內容」 | |
git branch --set-upstream-to=<u> |
設定本地分支追蹤特定的遠端分支 | 例如:origin/main |
|
| 暫存 (Stash) | git stash pop |
取出最新的暫存進度並從清單中移除 | 處理臨時需要切換分支的情況 |
git stash list |
列出目前所有暫存的進度 | ||
git stash push -m "Messages..." |
存入時加上訊息 (Message) | ||
git stash --keep-index |
只把 unstage 的東西 stash | ||
git stash apply stash@{x} |
套用某個暫存,但不刪除 | ||
git stash show stash@{x} |
查看特定 Index 的檔案清單 | ||
git stash show -p stash@{x} |
查看特定 Index 的程式碼差異 | ||
git stash drop stash@{x} |
刪除特定 Index 的暫存 | ||
| 特殊 | git mv |
可被 Git 識別的移動檔案 |
Patch Add
可以特別談談 git add -p,他應該常常被使用:
| 指令 | 意義 | 說明 |
|---|---|---|
| y | Yes | 將這個區塊加入暫存區。 |
| n | No | 不將這個區塊加入暫存區。 |
| q | Quit | 退出,不處理剩下的區塊。 |
| s | Split | 將目前的區塊拆分成更小的塊(如果改動分得很開)。 |
| e | Edit | 手動編輯這個區塊(最強大但也最進階的功能)。 |
| d | Don’t add | 跳過這個檔案中剩下的所有區塊。 |
| ? | Help | 顯示所有指令的詳細說明。 |
其中 edit 比較複雜,你假如不想要這行 +,就直接把他刪除。假如不想要這行 -,就把他的 - 變成空白,然後 # 好像是把這一行註解。
Edit 超級難用,他非常在乎每一行,我有遇到因為我的 vimrc 有 autocmd BufWritePre * :%s/\s\+$//e Automatically remove trailing whitespace on save,但因為 Edit 很嚴格,他要每個空白都在,導致我一直不能成功。
最後要使用 :noautocmd wq 才能成功,找超級久。
Rebase
特別談談 rebase 的詳細用法,基礎用法像是,假設你想修改最近 3 次的提交 ,可以用 git rebase -i HEAD~3,然後你會有不同的選項可以選,像是:
- pick: 保留該提交
- reword: 修改提交訊息
- edit: 停下來讓你修改代碼內容
- squash: 將該提交合併到前一個提交中(保留訊息)
- fixup: 類似 squash,但會捨棄該提交的訊息(常用於修正小錯誤)
- drop: 刪除該提交
Edit 修改特定的 Commit
如果你發現某個舊的 commit 少改了一個檔案,或是程式碼有 bug,可以使用 edit。
更改標記:在互動視窗中,將目標 commit 前方的 pick 改成 edit(或簡寫 e),儲存並退出。
進入編輯狀態:Git 會停在那個 commit。此時你可以修改程式碼。
加入修改:
git add <檔案名稱>
git commit --amend --no-edit
git rebase --continueFixup and Auto Squash
除了以上方法,還有一個快速 fixup commit 的方式。
# Git 會自動幫你產生一個 commit,標題叫 fixup! <原本 commit 的標題>。這個 fixup! 字眼就是給 Git 看的「自動合體雷達」
git commit --fixup <你想要 merge 進去的 commit>
# 執行 rebase 時加上 --autosquash 參數
git rebase -i --autosquash <你想要 merge 進去的 commit 的上一個 commit>- 自動排隊:Git 會自動把那個 fixup! 開頭的 commit,從最後面搬到目標 commit a1b2c3d 的正下方
- 自動選模式:Git 會自動把該行的指令從 pick 改成 fixup
- 直接儲存即可:你不需要在那邊手動剪下貼上、改 f。你只要看一眼,確認 Git 沒排錯,直接輸入 :wq 離開
Stash
Stash 本質上就是一個「隱形的 Commit」
通常一個 Stash 包含:
- Index Commit:保存你當時 git add 過的暫存區內容
- Working Tree Commit:保存你當時在工作區改動但還沒 add 的內容
- (有時還有)Untracked Commit:如果你用了 -u,它會再開一個 Commit 存新檔案
Git 沒有直接修改 Stash message 的方式,所以我們只能。
hash=$(git rev-parse stash@{1}) # 取得該 stash 的 Commit Hash
git stash store -m "你的新訊息內容" $hash # 存入一個帶有新訊息的 stash
git stash drop stash@{2} # 刪除原本舊的 stash其他情況
我們可能會想說,最新的幾個 commit 有沒有特定不小心加進去的特定關鍵字,像是可能是 log 相關的。
# 最快掃描法:檢查「從 master 分叉後」的所有改動
# -E: 正則表示法
# -i: 無視大小寫
git diff master..HEAD | grep -Ei "info|debug|log"
# 精確追蹤法:找出「是哪一筆 commit」帶進來的
git log -p master..HEAD -G"StoreManager: Unlink callback"Github
Sync
我們假如有自己的 branch,想要 sync,所以要 merge master,可以直接打
git rebase master這樣可以讓我們的 commit 還是在最新的地方,不會 sync 之後,修改的 commit 在新 merge 進來的 commit 前面。