Git for QA — Branch / PR review / cherry-pick / bisect 抓 regression 的實戰
「Git 是 dev 的事」是 5 年前的觀念。現在 QA 不會 Git 等於少一半戰力 — 看不懂 PR、找不到 regression commit、救不回手滑的測試。這篇是給 QA 的實戰 Git 指南。
QA 為什麼要會 Git
flowchart LR
QA[QA 工程師] --> A[寫自動化 → push code]
QA --> B[Review PR → 看 dev 改什麼]
QA --> C[找 regression → 哪個 commit 壞的]
QA --> D[救手滑 → 改錯怎麼回去]
QA --> E[分支策略 → 哪個 branch 該測]
QA --> F[Cherry-pick → hotfix 走小路]
style QA fill:#06b6d4,color:#fff
不會 Git 的 QA = 每件事都要等 dev 處理。
第一張地圖:Git 的 4 個區域
flowchart LR
Wkspace[Working Directory<br>你正在改的檔案] --> Stage[Staging Area<br>git add]
Stage --> Repo[Local Repo<br>git commit]
Repo --> Remote[Remote Repo<br>git push]
Remote --> Pull[git fetch / pull]
Pull --> Repo
style Wkspace fill:#f59e0b,color:#fff
style Stage fill:#06b6d4,color:#fff
style Repo fill:#10b981,color:#fff
style Remote fill:#a855f7,color:#fff
| 區域 | 內容 | 怎麼進去 |
|---|---|---|
| Working | 你正在編輯的檔案 | 直接改 |
| Staging | 準備 commit 的內容 | git add |
| Local | 你的 commit | git commit |
| Remote | 雲端版本 | git push / git pull |
核心:每次想做事前先問「我在哪個區域、要去哪個」。
QA 每天用的 20 個指令
看狀態
git status # 我現在在哪、什麼變了
git log --oneline -10 # 最近 10 個 commit
git log --graph --oneline # 視覺化 branch
git diff # 我改了什麼還沒 add
git diff --staged # 我 add 了什麼還沒 commit
git diff main # 跟 main 差什麼
切 branch
git branch # 列所有 branch
git branch -a # 含 remote
git checkout -b feature/x # 建 + 切到新 branch
git checkout main # 切回 main
git switch main # 新版指令(同 checkout)
寫 code
git add tests/test_login.py # stage 單檔
git add tests/ # stage 整個資料夾
git commit -m "test: add login flaky check"
git push origin feature/x # 推到 remote
Pull 別人的 code
git fetch # 抓 remote 更新(不 merge)
git pull origin main # fetch + merge
git pull --rebase # 用 rebase 取代 merge
救手滑
git restore tests/login.py # 丟掉某檔的修改
git restore --staged file # 把 staged 還原回 working
git reset HEAD~1 # 取消最後 1 個 commit(保留改動)
git reset --hard HEAD~1 # 取消 + 丟掉改動(危險)
QA 最強 4 招
招式 1: git log 進階 — 找 regression commit
# 找誰改了 login.py
git log --follow tests/login.py
# 找這禮拜的改動
git log --since="1 week ago" --oneline
# 找 Alice 改的 E2E test
git log --author=alice -- tests/e2e/
# 找改了「login」字串的 commit
git log -S "login" --oneline
# 找改了 LoginPage class 的 commit
git log -G "class LoginPage" --oneline
# 看某 commit 改了什麼
git show abc1234
# 看某 commit 改了哪些檔案
git show --stat abc1234
招式 2: git diff — 對比兩個版本
# 對比 main 跟 staging branch
git diff main..staging
# 對比這個 PR 改了什麼
git diff main...feature/login
# 看哪些檔案改了
git diff --name-only main..staging
# 對比兩個 commit
git diff abc1234..def5678
# 對比兩個 tag
git diff v2.4.0..v2.4.1
QA 發版前一定要看 git diff lastrelease..main 確認 scope。
招式 3: git bisect — 二分查 regression(神技)
flowchart TD
Bad[v2.4.1 壞了] --> Q1{二分查中間<br>哪個 commit 壞的}
Q1 --> S1["git bisect start"]
S1 --> S2["git bisect bad v2.4.1"]
S2 --> S3["git bisect good v2.4.0"]
S3 --> S4[Git checkout 中間 commit]
S4 --> T1{測試<br>好或壞?}
T1 -->|壞| S5[git bisect bad]
T1 -->|好| S6[git bisect good]
S5 --> S4
S6 --> S4
S5 --> Found[找到 commit]
S6 --> Found
Found --> S7["git bisect reset"]
style Bad fill:#ef4444,color:#fff
style Found fill:#10b981,color:#fff
實際操作:
# 1. 知道現在壞、上版好
git bisect start
git bisect bad HEAD
git bisect good v2.4.0
# 2. Git 自動切到中間 commit
# 這時跑你的測試
npm run test:e2e:login
# 3. 結果回報
git bisect bad # 如果還壞
# 或
git bisect good # 如果好
# 4. 重複 2-3 直到找到
# 最後 Git 會說「abc1234 is the first bad commit」
# 5. 結束
git bisect reset
10 個 commit 之中找出壞的、只要測 log2(10) ≈ 4 次。
招式 4: git cherry-pick — Hotfix 走小路
某個 bug 修在 main、要 backport 回 release branch:
# 在 main 上的修復 commit
git log main --oneline
# abc1234 fix: payment race condition
# 切到 release branch
git checkout release/v2.4
# 把那個 commit 「挑」過來
git cherry-pick abc1234
# push 出去
git push origin release/v2.4
Cherry-pick 是 hotfix 工作流的核心。
QA review PR 的 5 個重點
mindmap
root((QA Review PR))
Diff 的範圍
改太大 - 拆 PR
改太小 - 沒抓重點
無關 - 砍掉
測試覆蓋
改了 code 有沒有改 test
Test 真的測到改動嗎
Edge case 補了嗎
破壞性改動
API contract 變嗎
DB schema 變嗎
預設值改嗎
Config 改動
env var 新增
Feature flag
Secret
依賴升級
Package 升版
Breaking change?
Security CVE
看 diff 的順序
- 整體 file 數:改 50 個檔案的 PR = 要拆
- 新檔案 vs 修改檔案:新功能 vs 改舊行為
- Test 檔有沒有跟著改:沒有 = 退回
- API / schema 改動:標 breaking change
- dependency / config:注意 security 與部署影響
Comment 的好習慣
不要只說「LGTM」。
✅ 好的 comment:
「這個 case 沒測 timeout 情境,我來補一個」
「這 schema 改動會 break v1 client,需要 deprecation period」
「flaky test 可能來自這個 race condition」
❌ 沒幫助的 comment:
「LGTM」
「+1」
「ok」
救命招:git reflog
flowchart LR
A[手滑 reset --hard] --> B[Code 不見了?]
B --> C[git reflog]
C --> D[找到要的 commit ID]
D --> E[git reset --hard abc1234]
E --> F[救回來]
style A fill:#ef4444,color:#fff
style F fill:#10b981,color:#fff
# 看你最近做過的所有「動作」
git reflog
# 輸出像這樣:
# abc1234 HEAD@{0}: reset: moving to HEAD~1
# def5678 HEAD@{1}: commit: my important test
# ...
# 救回 commit
git reset --hard def5678
90% 的「Code 不見」都能用 reflog 救。
Branch 策略對 QA 的影響
flowchart LR
F[Feature branch] --> Dev[develop / main]
Dev --> Stage[staging]
Stage --> Prod[production / main]
Bug[Bug found] --> Where{Bug 在哪?}
Where -->|feature| FixF[在 feature branch 修]
Where -->|staging| FixS[在 staging 修 + cherry-pick main]
Where -->|prod| Hot[Hotfix branch + cherry-pick all]
style F fill:#06b6d4,color:#fff
style Stage fill:#a855f7,color:#fff
style Prod fill:#ef4444,color:#fff
QA 要會分辨:
- Bug 在 feature branch → 該 PR 退回 dev 修
- Bug 在 staging → 開 fix PR、merge 回 staging + cherry-pick main
- Bug 在 prod → 開 hotfix branch、修完同時 cherry-pick 給 staging / main
三種常見 workflow
flowchart TD
Models[Branch 模型] --> M1[Git Flow]
Models --> M2[GitHub Flow]
Models --> M3[Trunk-based]
M1 --> M1d[develop / release / hotfix<br>適合大團隊 / 季度發版]
M2 --> M2d[main + feature<br>適合 SaaS 持續部署]
M3 --> M3d[直接到 main<br>用 feature flag<br>適合大規模團隊]
style M1 fill:#06b6d4,color:#fff
style M2 fill:#10b981,color:#fff
style M3 fill:#a855f7,color:#fff
QA 要做的事不同:
| Workflow | QA 重點 |
|---|---|
| Git Flow | Release branch 跑 full regression、長期維運 |
| GitHub Flow | 每 PR 跑 CI、staging 短期測試 |
| Trunk-based | 在 prod 用 feature flag 測、shift-right 取向 |
進階:3 個救命指令
1. git stash — 半途切走
# 改一半要切去看別的 branch
git stash # 暫存
git checkout other # 切走
# 看完...
git checkout original # 切回
git stash pop # 拿回剛剛改的
2. git revert — 安全的撤銷
# 不要用 reset、改用 revert(不改 history)
git revert abc1234 # 產生一個「撤銷 abc1234」的新 commit
git push # 安全推上去
已推到 remote 的 commit 一律用 revert、不用 reset。
3. git blame — 看每行誰寫的
git blame tests/login.py
每行顯示:commit、作者、時間。找到 regression 後找誰一起 debug。
反模式(QA 常踩的雷)
flowchart TD
Anti[QA Git 反模式] --> A1["force push 到 main"]
Anti --> A2["commit 到錯的 branch 才發現"]
Anti --> A3["rebase 已 push 的 branch"]
Anti --> A4["不寫 commit message"]
Anti --> A5["改一堆東西 commit 一次"]
Anti --> A6["不會 conflict resolution"]
Anti --> A7["把 .env / secret commit 進去"]
style A1 fill:#ef4444,color:#fff
style A2 fill:#ef4444,color:#fff
style A3 fill:#ef4444,color:#fff
style A4 fill:#ef4444,color:#fff
style A5 fill:#ef4444,color:#fff
style A6 fill:#ef4444,color:#fff
style A7 fill:#ef4444,color:#fff
1. Force push 到共享 branch
# ❌ NEVER
git push --force origin main
# ✅ 用 --force-with-lease(被別人 push 後會擋住)
git push --force-with-lease origin feature/x
2. Rebase 已 push 的 branch
已 push 的 commit 不要 rebase。會把別人的 history 搞壞。
3. Conflict 不知道怎麼解
<<<<<<< HEAD
我的版本
=======
別人的版本
>>>>>>> branch-x
步驟:
1. 看 <<< 跟 >>> 之間是兩邊版本
2. 決定留哪個、或合併
3. 刪掉 <<< === >>> marker
4. git add 該檔
5. git rebase --continue 或 git merge --continue
Commit message 規範(QA 也要遵守)
type(scope): one-line summary
[optional body]
[optional footer]
常用 type:
feat:新功能fix:bug 修復test:加 / 改測試(QA 最常用)docs:文件refactor:重構chore:雜事
QA 範例:
test(login): add flaky-check for connect timeout
Repro 3 次 100% fail,加 30s timeout retry guard。
Related: #1042
工具
| 工具 | 用途 |
|---|---|
| VS Code GitLens | 看 blame、history、PR |
| GitHub Desktop | 視覺化 GUI、新手友善 |
| Sourcetree | Atlassian 的 GUI |
| lazygit | Terminal UI 神器 |
| git-revise | 安全 rebase |
| gh CLI | GitHub CLI、PR 從 terminal |
給 QA 的 5 句
- Git 不會 = 永遠等 dev
- bisect 救你 80% 的 regression debug 時間
- 手滑都能 reflog 救、別 panic
- conflict 不可怕、看 marker 就好
- 每天用 5 個指令、3 個月就熟
最後
Git 是 QA 最被低估的技能。不會 → 每件事卡 dev;會了 → 你能自己找 regression、Review PR 講重點、救手滑。每天花 10 分鐘練、一個月後你會發現 Git 變成你的第二語言。