團隊協作與 GitHub
遠端儲存庫(Remote Repository)
💡 比喻:雲端硬碟 本地的 Git 儲存庫就像你電腦上的檔案, 遠端儲存庫(如 GitHub)就像 Google Drive 或 OneDrive, 把程式碼備份到雲端,讓團隊成員都能存取。
Remote 基本操作
# 查看目前設定的遠端儲存庫
git remote -v # 列出所有遠端儲存庫的名稱和網址
# 新增遠端儲存庫(通常叫 origin)
git remote add origin https://github.com/username/repo.git # 新增名為 origin 的遠端連結
# 修改遠端網址
git remote set-url origin https://github.com/username/new-repo.git # 更改 origin 的網址
# 移除遠端連結
git remote remove origin # 移除名為 origin 的遠端連結
# 查看遠端詳細資訊
git remote show origin # 顯示 origin 的詳細分支追蹤資訊
Push、Pull、Fetch
# === Push(推送)===
# 把本地的 commit 上傳到遠端
git push origin main # 把本地 main 分支推送到遠端 origin
# 第一次推送時設定追蹤關係(之後只需 git push)
git push -u origin main # -u 設定 upstream,之後可以簡寫 git push
# 推送所有分支
git push --all origin # 把所有本地分支都推送到遠端
# 推送標籤
git push origin --tags # 把所有標籤推送到遠端
# === Pull(拉取 + 合併)===
# 從遠端下載最新的變更並合併到目前分支
git pull origin main # 從 origin 拉取 main 的變更並合併
# 使用 rebase 方式拉取(保持歷史乾淨)
git pull --rebase origin main # 拉取後用 rebase 而非 merge 整合
# === Fetch(只下載,不合併)===
# 只下載遠端的變更,但不自動合併
git fetch origin # 下載 origin 所有分支的最新狀態
# 查看遠端有什麼新變更
git fetch origin # 先下載遠端最新狀態
git log main..origin/main --oneline # 比較本地和遠端 main 的差異
# Fetch vs Pull 的差別
# fetch = 只下載,你可以檢查後再決定要不要合併
# pull = fetch + merge,自動下載並合併
從 GitHub 複製(Clone)專案
# 複製遠端儲存庫到本地(HTTPS 方式)
git clone https://github.com/username/repo.git # 複製整個儲存庫到本地
# 複製到指定資料夾
git clone https://github.com/username/repo.git my-folder # 複製到 my-folder 資料夾
# 複製遠端儲存庫到本地(SSH 方式,推薦)
git clone git@github.com:username/repo.git # 用 SSH 複製(不需每次輸入密碼)
# 只複製最新的一次 commit(淺複製,適合大型專案)
git clone --depth 1 https://github.com/username/repo.git # 淺複製,只下載最新版本
Pull Request 工作流程
💡 比喻:審稿流程 你寫了一篇文章(程式碼變更), 不是直接發表,而是先交給編輯(審查者)審核, 編輯提出修改意見,你修改後再正式發表(合併到 main)。
完整 PR 流程
# 步驟 1:從 main 建立功能分支
git switch main # 先確認在 main 上
git pull origin main # 拉取最新的 main
git switch -c feature/user-profile # 建立並切換到功能分支
# 步驟 2:開發功能,多次 commit
git add . # 暫存變更
git commit -m "新增用戶個人資料頁面" # 提交第一步
# ... 繼續開發 ...
git add . # 暫存更多變更
git commit -m "新增頭像上傳功能" # 提交第二步
# 步驟 3:推送到遠端
git push -u origin feature/user-profile # 推送功能分支到遠端
# 步驟 4:在 GitHub 上建立 Pull Request
# 前往 GitHub 網站,點擊 "Compare & pull request"
# 填寫 PR 標題和說明
# 步驟 5:Code Review 後可能需要修改
git add . # 暫存修改
git commit -m "根據 review 意見修改驗證邏輯" # 提交修改
git push # 推送到遠端,PR 會自動更新
# 步驟 6:合併後清理
git switch main # 切回 main
git pull origin main # 拉取包含 PR 合併後的最新 main
git branch -d feature/user-profile # 刪除本地功能分支
PR 說明模板
## 變更說明
簡要描述這個 PR 做了什麼
## 變更類型
- [ ] 新功能(New Feature)
- [ ] Bug 修復(Bug Fix)
- [ ] 重構(Refactoring)
- [ ] 文件更新(Documentation)
## 測試方式
描述如何測試這些變更
## 截圖(如果有 UI 變更)
貼上前後對比截圖
## 相關 Issue
Closes #123
Code Review 最佳實踐
給予 Review 的原則
Code Review 檢查清單:
┌────────────────────────────────────────────────────────┐
│ ✅ 程式邏輯正確嗎?有沒有邊界條件沒處理? │
│ ✅ 命名清楚嗎?其他人看得懂變數和函式的用途? │
│ ✅ 有重複的程式碼嗎?能不能抽取共用方法? │
│ ✅ 有寫測試嗎?測試有覆蓋主要情境嗎? │
│ ✅ 安全性:有 SQL Injection、XSS 等風險嗎? │
│ ✅ 效能:有不必要的迴圈或資料庫查詢嗎? │
│ ✅ 是否遵循團隊的 coding style? │
│ ✅ commit 訊息清楚嗎?PR 說明完整嗎? │
└────────────────────────────────────────────────────────┘
Review 留言語氣
❌ 不好的留言:
"這段程式碼很爛"
"你不懂怎麼寫嗎?"
✅ 好的留言:
"建議這裡可以用 Dictionary 取代 List,查找效率會從 O(n) 提升到 O(1)"
"這個方法超過 50 行了,考慮拆成幾個小方法提升可讀性?"
"nit: 這個變數名稱 d 建議改成 dayCount,更好理解"
GitHub Actions CI/CD 基礎
💡 比喻:自動化工廠流水線 每次你把程式碼推送到 GitHub, GitHub Actions 就像一條自動化流水線, 幫你自動編譯、測試、部署,不需要人工介入。
基本 .NET 專案的 CI 設定
# .github/workflows/dotnet-ci.yml
# 工作流程名稱
name: .NET CI
# 觸發條件:push 到 main 或建立 PR 時
on:
push:
branches: [ main ] # 推送到 main 時觸發
pull_request:
branches: [ main ] # 對 main 建立 PR 時觸發
# 定義工作
jobs:
build-and-test: # 工作名稱
runs-on: ubuntu-latest # 執行環境:最新版 Ubuntu
steps:
# 步驟 1:取出程式碼
- uses: actions/checkout@v4 # 從儲存庫取出程式碼
# 步驟 2:設定 .NET SDK
- name: Setup .NET # 步驟顯示名稱
uses: actions/setup-dotnet@v4 # 安裝 .NET SDK
with:
dotnet-version: '8.0.x' # 指定 .NET 8 版本
# 步驟 3:還原套件
- name: Restore # 步驟顯示名稱
run: dotnet restore # 執行 NuGet 套件還原
# 步驟 4:編譯
- name: Build # 步驟顯示名稱
run: dotnet build --no-restore # 編譯專案(不重複還原)
# 步驟 5:執行測試
- name: Test # 步驟顯示名稱
run: dotnet test --no-build --verbosity normal # 執行單元測試
常用 CI/CD 工作流程
CI/CD 流水線常見階段:
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Restore │ → │ Build │ → │ Test │ → │ Deploy │
│ 還原套件│ │ 編譯 │ │ 測試 │ │ 部署 │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
│ │ │ │
自動下載 自動編譯 自動跑測試 自動部署到
NuGet 套件 程式碼 確認沒有 Bug 正式環境
Issue、Milestone、Project Board
Issue(議題)
GitHub Issue 的用途:
┌────────────────────────────────────────────────┐
│ 🐛 Bug Report │ 回報程式中發現的錯誤 │
│ ✨ Feature Request│ 提出新功能的需求 │
│ 📝 Task │ 一般工作任務 │
│ ❓ Question │ 提出技術問題 │
│ 📖 Documentation │ 文件改善需求 │
└────────────────────────────────────────────────┘
Label(標籤)分類:
- bug:程式錯誤
- enhancement:功能改善
- good first issue:適合新手的任務
- help wanted:需要幫助
- priority: high/medium/low:優先度
Milestone 與 Project Board
Milestone(里程碑):
┌────────────────────────────────────────┐
│ v1.0 Release(截止日:2024-06-30) │
│ ├── #12 使用者登入 ✅ │
│ ├── #13 使用者註冊 ✅ │
│ ├── #14 個人資料頁 🔄 │
│ └── #15 忘記密碼 📋 │
│ 進度:50% ████░░░░ │
└────────────────────────────────────────┘
Project Board(看板):
┌──────────┬──────────┬──────────┬──────────┐
│ 待辦 │ 進行中 │ 審查中 │ 完成 │
│ (To Do) │(In Progress)│(In Review)│(Done) │
├──────────┼──────────┼──────────┼──────────┤
│ #15 │ #14 │ │ #12 │
│ 忘記密碼 │ 個人資料 │ │ 登入 │
│ │ │ │ #13 │
│ │ │ │ 註冊 │
└──────────┴──────────┴──────────┴──────────┘
SSH Key 設定
💡 比喻:門禁卡 SSH Key 就像你公司的門禁卡, 你只要設定一次,之後進出(push/pull)都不用再輸入密碼。 私鑰(Private Key)= 你的門禁卡(絕對不能給別人) 公鑰(Public Key)= 門禁系統的紀錄(給 GitHub 保管)
產生 SSH Key
# 步驟 1:產生 SSH Key(使用 Ed25519 演算法,較安全)
ssh-keygen -t ed25519 -C "you@example.com" # 產生新的 SSH 金鑰對
# 按 Enter 使用預設路徑(~/.ssh/id_ed25519)
# 設定密碼短語(passphrase)或直接 Enter 跳過
# 步驟 2:啟動 SSH Agent
eval "$(ssh-agent -s)" # 啟動 SSH Agent 背景服務
# 步驟 3:新增私鑰到 SSH Agent
ssh-add ~/.ssh/id_ed25519 # 把私鑰加入 SSH Agent
# 步驟 4:複製公鑰(要貼到 GitHub)
# Windows(Git Bash)
cat ~/.ssh/id_ed25519.pub # 顯示公鑰內容,手動複製
# macOS
pbcopy < ~/.ssh/id_ed25519.pub # 自動複製公鑰到剪貼簿
# Linux
xclip -sel clip < ~/.ssh/id_ed25519.pub # 自動複製公鑰到剪貼簿
在 GitHub 上設定
設定步驟:
1. 登入 GitHub
2. 點擊右上角頭像 → Settings(設定)
3. 左側選單 → SSH and GPG keys
4. 點擊 "New SSH key"
5. Title 填入識別名稱(如 "我的筆電")
6. Key type 選 "Authentication Key"
7. 貼上剛才複製的公鑰
8. 點擊 "Add SSH key"
# 測試 SSH 連線
ssh -T git@github.com # 測試是否能成功連線到 GitHub
# 成功會顯示:Hi username! You've successfully authenticated...
# 把現有的 HTTPS 遠端改為 SSH
git remote set-url origin git@github.com:username/repo.git # 改用 SSH 連線
🤔 我這樣寫為什麼會錯?
❌ 錯誤 1:pull 之前先 push 導致被拒絕
# 錯誤:直接 push,但遠端已經有別人的新 commit
git push origin main # 被拒絕! rejected(non-fast-forward)
# ✅ 正確:先 pull 再 push
git pull origin main # 先拉取遠端的最新變更
# 如果有衝突就解決衝突
git push origin main # 再推送自己的變更
為什麼錯? 遠端有你沒有的 commit,Git 不讓你直接覆蓋。必須先把遠端的變更整合到本地,確認沒有衝突後再推送。
❌ 錯誤 2:直接推送到 main 分支
# 錯誤:跳過 PR 直接推 main
git switch main # 切到 main
git commit -m "新增購物車功能" # 在 main 上提交
git push origin main # 直接推到遠端 main
# ✅ 正確:用 PR 流程
git switch -c feature/cart # 建立功能分支
git commit -m "新增購物車功能" # 在功能分支上提交
git push -u origin feature/cart # 推送功能分支
# 然後在 GitHub 上建立 Pull Request
為什麼錯? 直接推到 main 跳過了 Code Review,可能引入 Bug 或破壞性變更。團隊協作應該透過 PR 流程,讓其他人有機會審查程式碼。
❌ 錯誤 3:把 SSH 私鑰分享給別人
# 錯誤:把私鑰檔案傳給同事
# "你拿去用我的 SSH Key 就可以 push 了"
# ✅ 正確:每個人產生自己的 SSH Key
ssh-keygen -t ed25519 -C "colleague@example.com" # 每人自己產生金鑰
# 把自己的公鑰加到 GitHub
為什麼錯? 私鑰就像你的密碼,給了別人等於讓別人能用你的身份操作所有 GitHub 儲存庫。每個人都應該有自己的 SSH Key。
📝 本章重點整理
| 概念 | 用途 | 比喻 |
|---|---|---|
git remote |
管理遠端連結 | 設定雲端硬碟 |
git push |
推送到遠端 | 上傳到雲端 |
git pull |
拉取並合併 | 從雲端下載 |
git fetch |
只下載不合併 | 先看看雲端有什麼新的 |
| Pull Request | 程式碼審查流程 | 投稿審稿流程 |
| GitHub Actions | 自動化流水線 | 自動化工廠 |
| SSH Key | 免密碼認證 | 門禁卡 |