Pull Request(在 GitLab 中稱為 Merge Request)是現代軟體開發中最重要的協作機制之一。作為一位資深工程師,我可以說 Pull Request 不僅僅是合併程式碼的工具,更是知識分享、品質把關、和團隊學習的平台。今天我們要深入了解如何有效地使用這個強大的協作工具。
什麼是 Pull Request?
Pull Request 就像是向專案維護者「請求拉取」你的變更。想像你是一位作家,想要為一本書貢獻新的章節。你不能直接修改原書,而是要將你的章節提交給編輯審查,編輯同意後才會將你的內容加入到正式版本中。
Pull Request 的核心價值:
- 程式碼審查:讓其他開發者檢視你的程式碼
- 討論平台:針對具體的程式碼進行討論
- 品質控制:確保進入主分支的程式碼符合標準
- 知識分享:團隊成員互相學習的機會
- 歷史記錄:保留決策過程和討論內容
Pull Request 的完整生命週期
graph LR
A[建立功能分支] --> B[開發功能]
B --> C[推送分支]
C --> D[建立 PR]
D --> E[Code Review]
E --> F{需要修改?}
F -->|是| G[修改程式碼]
G --> H[推送更新]
H --> E
F -->|否| I[核准合併]
I --> J[合併到主分支]
J --> K[清理分支]
建立 Pull Request 的標準流程
步驟 1:準備工作環境
# 1. 確保主分支是最新的
git switch main
git pull origin main
# 2. 建立功能分支
git switch -c feature/user-profile-enhancement
# 3. 確認分支狀態
git status
git branch
步驟 2:開發和提交
# 進行開發工作
echo "實作使用者個人資料頁面" > profile.js
echo "個人資料頁面樣式" > profile.css
echo "個人資料 API 端點" > profile-api.js
# 分階段提交(推薦)
git add profile.js
git commit -m "新增使用者個人資料頁面組件"
git add profile.css
git commit -m "新增個人資料頁面樣式設計"
git add profile-api.js
git commit -m "實作個人資料 API 端點"
步驟 3:推送分支並建立 PR
# 推送功能分支
git push -u origin feature/user-profile-enhancement
# 輸出會包含建立 PR 的連結
# remote: Create a pull request for 'feature/user-profile-enhancement' on GitHub by visiting:
# remote: https://github.com/username/repo/pull/new/feature/user-profile-enhancement
步驟 4:在平台上建立 Pull Request
在 GitHub 上建立 PR 時需要填寫:
標題範例:
新增使用者個人資料管理功能
描述範例:
## 功能說明
實作使用者個人資料管理功能,包括:
- 個人資料顯示頁面
- 編輯個人資料功能
- 頭像上傳功能
- 響應式設計
## 變更內容
- 新增 `ProfileComponent` 組件
- 實作個人資料 API 端點
- 新增個人資料頁面樣式
- 加入單元測試
## 測試
- [ ] 單元測試通過
- [ ] 整合測試通過
- [ ] 手動測試完成
- [ ] 響應式設計測試完成
## 截圖

## 相關議題
Closes #123
Related to #456
## 檢查清單
- [x] 程式碼遵循專案風格指南
- [x] 新增適當的註解
- [x] 更新相關文件
- [x] 加入或更新測試
- [x] 所有測試通過
Fork 工作流程詳解
Fork 工作流程是參與開源專案的標準方式,特別適合不熟悉的專案或大型開源社群。
完整的 Fork 流程
# 1. 在 GitHub 上 Fork 目標專案
# 點選專案頁面的 "Fork" 按鈕
# 2. 複製你 Fork 的版本
git clone git@github.com:yourusername/awesome-project.git
cd awesome-project
# 3. 新增原始專案為 upstream
git remote add upstream git@github.com:original-owner/awesome-project.git
# 4. 確認遠端設定
git remote -v
# origin git@github.com:yourusername/awesome-project.git (fetch)
# origin git@github.com:yourusername/awesome-project.git (push)
# upstream git@github.com:original-owner/awesome-project.git (fetch)
# upstream git@github.com:original-owner/awesome-project.git (push)
保持 Fork 同步
# 定期同步上游變更(建議每天或每週)
git fetch upstream
git switch main
git merge upstream/main
git push origin main
# 或使用 rebase 保持線性歷史
git fetch upstream
git switch main
git rebase upstream/main
git push origin main
Fork 貢獻流程
# 1. 同步上游
git fetch upstream
git switch main
git merge upstream/main
# 2. 建立功能分支
git switch -c fix/documentation-typo
# 3. 進行修改
echo "修正文件中的拼寫錯誤" > docs/README.md
git add docs/README.md
git commit -m "修正 README 中的拼寫錯誤"
# 4. 推送到你的 Fork
git push -u origin fix/documentation-typo
# 5. 在原始專案建立 Pull Request
# 從 yourusername:fix/documentation-typo
# 到 original-owner:main
Code Review 最佳實踐
Code Review 是 Pull Request 流程中最重要的環節,它不僅能提高程式碼品質,還能促進團隊學習。
作為 PR 作者的準則
1. 撰寫清楚的 PR 描述
## 問題描述
使用者無法在行動裝置上正確查看個人資料頁面
## 解決方案
- 修正 CSS 媒體查詢
- 調整響應式斷點
- 優化觸控互動
## 測試方式
在以下裝置測試:
- iPhone 12 (Safari)
- Samsung Galaxy S21 (Chrome)
- iPad Air (Safari)
## 影響範圍
只影響前端顯示,不涉及後端 API 變更
2. 保持 PR 規模適中
# 好的做法:單一目的的小 PR
git log --oneline
# a1b2c3d 修正行動裝置個人資料頁面佈局
# e4f5g6h 調整響應式斷點設定
# h7i8j9k 優化觸控按鈕大小
# 避免:包含多個不相關變更的大 PR
git log --oneline
# a1b2c3d 修正個人資料頁面 + 新增支付功能 + 重構認證系統
3. 自我審查
在建立 PR 前進行自我審查:
# 查看即將提交的所有變更
git diff main..feature/my-branch
# 查看每個檔案的變更
git diff main..feature/my-branch --name-only | xargs -I {} git diff main..feature/my-branch {}
# 確保沒有調試程式碼
grep -r "console.log\|debugger\|TODO" src/
作為 Reviewer 的準則
1. 審查的重點領域
功能正確性
// 審查:這個函數是否正確處理邊界情況?
function calculateDiscount(price, discountPercent) {
// ✅ 好:有輸入驗證
if (price <= 0 || discountPercent < 0 || discountPercent > 100) {
throw new Error('Invalid input parameters');
}
return price * (1 - discountPercent / 100);
}
程式碼風格和一致性
// ❌ 不一致的命名風格
const user_name = getUserName();
const userAge = getUserAge();
// ✅ 一致的命名風格
const userName = getUserName();
const userAge = getUserAge();
效能和安全性
// ❌ 潛在的安全問題
app.get('/api/user/:id', (req, res) => {
const query = `SELECT * FROM users WHERE id = ${req.params.id}`;
// SQL 注入風險
});
// ✅ 使用參數化查詢
app.get('/api/user/:id', (req, res) => {
const query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [req.params.id], (err, result) => {
// 安全的查詢方式
});
});
2. 提供建設性的回饋
好的回饋範例:
## 建議改善
在 `calculateTax` 函數中,建議加入輸入驗證:
```javascript
function calculateTax(amount) {
if (typeof amount !== 'number' || amount < 0) {
throw new Error('Amount must be a positive number');
}
return amount * 0.1;
}
</code></pre>
<!-- /wp:code -->
<!-- wp:paragraph -->
<p>這樣可以避免在傳入無效值時產生意外結果。</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2 class="wp-block-heading">優點</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>使用 async/await 讓非同步程式碼更易讀,很棒的改善!</p>
<!-- /wp:paragraph -->
<!-- wp:code -->
<pre class="wp-block-code"><code>
**避免的回饋方式:**
```markdown
❌ "這個程式碼有問題"
❌ "不對"
❌ "重寫"
3. 使用 GitHub 的審查功能
# 在程式碼行上留言
// 點選行號左邊的 "+" 號
# 建議具體的程式碼變更
```suggestion
const isValid = validateInput(userInput);
if (!isValid) {
return { error: 'Invalid input' };
}
總結性的審查意見
Overall, this is a solid implementation. Just a few minor suggestions above. LGTM! (Looks Good To Me)
## Pull Request 範本
建立 `.github/pull_request_template.md` 檔案:
```markdown
## 變更類型
- [ ] 新功能 (feature)
- [ ] 錯誤修復 (bug fix)
- [ ] 文件更新 (documentation)
- [ ] 樣式修改 (formatting, missing semi colons, etc)
- [ ] 重構 (refactoring)
- [ ] 測試 (adding missing tests, refactoring tests)
- [ ] 其他 (請說明):
## 變更描述
簡要描述這個 PR 的目的和變更內容
## 相關議題
- Closes #(issue number)
- Related to #(issue number)
## 測試
說明如何測試這些變更:
- [ ] 單元測試
- [ ] 整合測試
- [ ] 手動測試
- [ ] 其他測試 (請說明):
## 檢查清單
- [ ] 我的程式碼遵循專案的風格指南
- [ ] 我已進行自我審查
- [ ] 我已為程式碼加入註解,特別是複雜的邏輯
- [ ] 我已更新相關文件
- [ ] 我的變更不會產生新的警告
- [ ] 我已加入測試,且新舊測試都通過
- [ ] 相關的測試都已在本地通過
## 螢幕截圖 (如適用)
請加入螢幕截圖或 GIF 來說明變更
## 其他資訊
任何其他相關資訊
自動化檢查設定
GitHub Actions 工作流程
建立 .github/workflows/pr-checks.yml
:
name: Pull Request Checks
on:
pull_request:
branches: [ main, develop ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm run test:coverage
- name: Check code coverage
run: |
coverage=$(npm run test:coverage:json | grep -o '"total":{"lines":{"pct":[0-9.]*' | grep -o '[0-9.]*$')
if (( $(echo "$coverage < 80" | bc -l) )); then
echo "Code coverage is below 80%: $coverage%"
exit 1
fi
- name: Build project
run: npm run build
- name: Check bundle size
run: npm run bundlesize
分支保護規則
在 GitHub 專案設定中啟用:
# Branch protection rules for 'main'
- Require pull request reviews before merging
- Required approving reviews: 2
- Dismiss stale reviews when new commits are pushed
- Require review from code owners
- Restrict who can dismiss reviews
- Require status checks to pass before merging
- Require branches to be up to date before merging
- Required status checks:
- test
- lint
- build
- Require conversation resolution before merging
- Require signed commits
- Require linear history
- Include administrators in restrictions
處理 PR 回饋的流程
回應審查意見
# 1. 拉取最新的變更(如果有其他協作者)
git pull origin feature/my-branch
# 2. 根據回饋進行修改
echo "根據審查意見修改的內容" > updated-file.js
# 3. 提交修改
git add updated-file.js
git commit -m "根據 Code Review 意見修正驗證邏輯"
# 4. 推送更新
git push origin feature/my-branch
# PR 會自動更新,觸發新的檢查
處理衝突
# 當 PR 與主分支產生衝突時
git fetch origin
git switch feature/my-branch
git merge origin/main
# 解決衝突後
git add .
git commit -m "解決與 main 分支的合併衝突"
git push origin feature/my-branch
壓縮提交(如果需要)
# 使用互動式 rebase 整理提交歷史
git rebase -i origin/main
# 在編輯器中:
# pick a1b2c3d 第一個提交
# squash e4f5g6h 第二個提交
# squash h7i8j9k 第三個提交
# 強制推送(因為改寫了歷史)
git push --force-with-lease origin feature/my-branch
大型團隊的 PR 策略
程式碼擁有者 (CODEOWNERS)
建立 .github/CODEOWNERS
檔案:
# 全域規則
* @team-leads
# 前端程式碼
/frontend/ @frontend-team @ui-team
*.css @ui-team
*.scss @ui-team
# 後端程式碼
/backend/ @backend-team
/api/ @api-team
# 資料庫相關
/migrations/ @database-team @senior-devs
/models/ @backend-team @database-team
# 基礎設施
/docker/ @devops-team
/k8s/ @devops-team
*.yml @devops-team
*.yaml @devops-team
# 文件
/docs/ @tech-writers @team-leads
README.md @team-leads
# 安全相關(需要額外審查)
/auth/ @security-team @senior-devs
/payment/ @security-team @backend-team
多階段審查流程
# .github/workflows/staged-review.yml
name: Staged Review Process
on:
pull_request:
types: [opened, synchronize]
jobs:
initial-checks:
runs-on: ubuntu-latest
steps:
- name: Automated Tests
run: npm test
- name: Code Quality
run: npm run lint && npm run type-check
security-scan:
needs: initial-checks
if: contains(github.event.pull_request.changed_files, 'auth/') || contains(github.event.pull_request.changed_files, 'payment/')
runs-on: ubuntu-latest
steps:
- name: Security Scan
run: npm audit && npm run security-scan
performance-check:
needs: initial-checks
if: contains(github.event.pull_request.changed_files, 'frontend/')
runs-on: ubuntu-latest
steps:
- name: Bundle Size Check
run: npm run bundlesize
- name: Lighthouse CI
run: npm run lighthouse-ci
PR 標籤和里程碑管理
自動標籤分配
建立 .github/workflows/auto-label.yml
:
name: Auto Label PR
on:
pull_request:
types: [opened, synchronize]
jobs:
label:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v4
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
configuration-path: .github/labeler.yml
建立 .github/labeler.yml
:
# 根據檔案路徑自動加標籤
frontend:
- frontend/**/*
- '**/*.css'
- '**/*.scss'
- '**/*.js'
- '**/*.jsx'
- '**/*.ts'
- '**/*.tsx'
backend:
- backend/**/*
- api/**/*
- '**/*.py'
- '**/*.java'
- '**/*.go'
documentation:
- docs/**/*
- '**/*.md'
- '**/*.rst'
tests:
- '**/*test*'
- '**/*spec*'
- tests/**/*
security:
- auth/**/*
- security/**/*
- '**/*auth*'
- '**/*security*'
PR 性能優化
減少 PR 大小
# 使用 git 查看 PR 的統計資訊
git diff --stat origin/main..feature/my-branch
# 輸出範例:
# src/components/UserProfile.js | 145 ++++++++++++++++++++++++++++++++++++
# src/styles/profile.css | 89 +++++++++++++++++++++++
# tests/UserProfile.test.js | 67 ++++++++++++++++++
# 3 files changed, 301 insertions(+)
# 如果變更過多,考慮拆分:
git switch -c feature/user-profile-component
git cherry-pick commit1 commit2
git push -u origin feature/user-profile-component
git switch -c feature/user-profile-styles
git cherry-pick commit3 commit4
git push -u origin feature/user-profile-styles
並行審查策略
# 對於大型功能,建立多個相關的 PR
# PR 1: 基礎組件
feature/user-profile-base
# PR 2: 樣式設計 (依賴 PR 1)
feature/user-profile-styles
# PR 3: 互動功能 (依賴 PR 1)
feature/user-profile-interactions
# PR 4: 單元測試 (依賴 PR 1-3)
feature/user-profile-tests
常見 PR 問題和解決方案
問題 1:PR 過大難以審查
解決方案:
# 將大型 PR 拆分成多個小 PR
git log --oneline feature/large-feature
# 建立多個針對性的分支
git switch -c feature/part1
git cherry-pick commit1 commit2
git switch -c feature/part2
git cherry-pick commit3 commit4
問題 2:審查意見太多難以追蹤
解決方案:
## 審查意見處理清單
### 已處理
- [x] 修正輸入驗證邏輯 (John的建議)
- [x] 更新測試案例 (Sarah的建議)
- [x] 改善錯誤處理 (Mike的建議)
### 處理中
- [ ] 重構 API 介面 (預計明天完成)
- [ ] 優化資料庫查詢 (需要與 DBA 討論)
### 待討論
- [ ] 是否需要快取機制?(性能 vs 複雜度的權衡)
問題 3:CI/CD 檢查失敗
解決方案:
# 本地重現 CI 環境
docker run -it --rm -v $(pwd):/app node:18-alpine sh
cd /app
npm ci
npm run test
npm run lint
npm run build
# 修復問題後重新推送
git add .
git commit -m "修復 CI 檢查失敗問題"
git push origin feature/my-branch
PR 合併策略
Merge Commit
# 保留完整的分支歷史
git switch main
git merge --no-ff feature/user-profile
# 建立明確的合併提交
Squash and Merge
# 將功能分支的所有提交壓縮成一個
git switch main
git merge --squash feature/user-profile
git commit -m "新增使用者個人資料功能
- 實作個人資料顯示頁面
- 新增編輯個人資料功能
- 加入頭像上傳功能
- 完整的單元測試覆蓋
Closes #123"
Rebase and Merge
# 保持線性歷史,但保留個別提交
git switch feature/user-profile
git rebase main
git switch main
git merge --ff-only feature/user-profile
開源專案的 PR 特殊考慮
貢獻者協議 (CLA)
# .github/CONTRIBUTING.md
## 貢獻協議
在提交 Pull Request 前,請確保:
1. 您已閱讀並同意我們的貢獻者許可協議
2. 您的程式碼遵循專案的授權條款
3. 您有權限貢獻所提交的程式碼
## 首次貢獻者
歡迎首次貢獻者!請查看標有 `good first issue` 的議題。
## 程式碼風格
請執行 `npm run lint` 確保程式碼符合我們的風格指南。
社群互動範本
# .github/workflows/welcome.yml
name: Welcome New Contributors
on:
pull_request_target:
types: [opened]
jobs:
welcome:
if: github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
runs-on: ubuntu-latest
steps:
- uses: actions/first-interaction@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
pr-message: |
感謝您的第一個 Pull Request!🎉
請確保:
- 您已閱讀我們的貢獻指南
- 所有測試都通過
- 程式碼遵循專案風格
我們會盡快審查您的 PR。歡迎加入我們的社群!
小結
Pull Request 是現代軟體開發協作的核心,掌握 PR 工作流程讓你能夠:
核心技能回顧:
- PR 建立:清楚的描述、適當的規模、完整的測試
- Code Review:建設性的回饋、關注重點領域、促進學習
- Fork 流程:參與開源專案的標準方式
- 自動化檢查:CI/CD 整合、品質把關、效率提升
- 團隊協作:程式碼擁有者、多階段審查、衝突解決
重要原則:
- 小而頻繁:保持 PR 規模適中
- 清楚溝通:詳細的描述和建設性的回饋
- 品質第一:程式碼審查不僅是找錯誤,更是知識分享
- 自動化助力:善用工具提高效率和品質
- 持續改進:根據團隊需求調整流程
最佳實踐檢查清單:
## PR 作者檢查清單
- [ ] PR 規模適中(<400 行變更)
- [ ] 清楚的標題和描述
- [ ] 相關測試已加入和通過
- [ ] 自我審查完成
- [ ] 文件已更新
- [ ] CI 檢查通過
## Reviewer 檢查清單
- [ ] 功能符合需求
- [ ] 程式碼品質良好
- [ ] 安全性考慮
- [ ] 效能影響評估
- [ ] 測試覆蓋充足
- [ ] 文件準確完整
在下一篇文章中,我們將探討多人協作的分支策略與規範,學習如何在大型團隊中建立有效的 Git 工作流程,包括 Conventional Commits 規範和進階的分支管理策略。
記住,優秀的 Pull Request 不僅能提高程式碼品質,更是建立團隊知識共享文化的重要工具。投入時間學習和實踐 PR 最佳實踐,將大大提升你和團隊的開發效率。