Git 全景課 / 第一部分 建立心智模型 · M2
M2 基本循環
日常用 Git,九成時間都在重複同一個循環:改、看、暫存、提交、查歷史。本單元把這個循環練熟,並學會兩件讓歷史「有用」的事:忽略不該提交的檔案,以及寫好 commit 說明。
學完本單元,你能夠:
- 用
git init建立倉庫,並完成「改 → 看 → 暫存 → 提交 → 查歷史」的循環; - 用
.gitignore排除系統雜物、個人設定和密鑰; - 寫出清楚的 commit 說明;
- 判斷甚麼時候該把改動拆成幾個 commit。
1循環一覽 The everyday loop
②「看」是最常被跳過的一步,也是最值得養成的習慣:每次 add 之前用 git status 和 git diff 看一眼,就能避免把不該提交的東西封進歷史。
2建立倉庫:git init Creating a repository
在一個資料夾裏執行 git init,Git 會在裏面建立一個隱藏的 .git 資料夾。倉庫就是這個 .git 資料夾:所有 commit、暫存區、設定都在裏面。你的檔案本身不會被改動,也還沒有任何檔案被追蹤,要等你 add 和 commit。
另一種開始方式
如果專案已經在 GitHub 等地方,就不用
init,而是用 git clone 把整個倉庫複製下來。這在 M9 介紹。
3.gitignore:不該提交的檔案 Ignoring files
每個資料夾裏都有一些檔案不應該進入歷史:
| 類別 | 知識線例子 | 軟件線例子 |
|---|---|---|
| 作業系統雜物 | .DS_Store(macOS)、Thumbs.db | 同左 |
| 個人設定 | .obsidian/workspace.json(你的視窗佈局) | .vscode/、.idea/ |
| 可以重新產生的檔案 | 匯出的 PDF | __pycache__/、node_modules/、build/ |
| 密鑰與私人資料 | 含個人資料的名單 | .env(API key、密碼) |
在倉庫根目錄建立一個叫 .gitignore 的純文字檔,每行寫一條規則,Git 就會當這些檔案不存在:git status 不再列出它們,git add . 也會跳過它們。
| 寫法 | 意思 |
|---|---|
.DS_Store | 任何位置叫這個名字的檔案 |
*.pdf | 所有 .pdf 檔 |
build/ | 整個 build 資料夾 |
!keep.pdf | 例外:前面的規則排除了它,這一行再把它納回來 |
# 說明 | 註解 |
.gitignore 本身要提交,這樣團隊每個人都套用同一套規則。
兩個陷阱
- 已追蹤的檔案不受
.gitignore影響。如果某個檔案早已提交,事後才寫進.gitignore是沒有用的。要先用git rm --cached <檔名>讓 Git 停止追蹤(檔案本身保留),再提交。 - 密鑰一旦提交,就永遠留在歷史裏。即使下一個 commit 把它刪掉,舊 commit 仍然有它,任何拿到倉庫的人都看得到。補救方法是立即作廢那條密鑰、換一條新的。最好的做法是在第一次 commit 之前就寫好
.gitignore。
4沙盒:從零開始的五次提交 Sandbox: five commits
5寫好 commit 說明 Writing commit messages
commit 說明是寫給將來的人看的,包括半年後的你。他們看歷史時,只有這一句話可以判斷「這次改了甚麼、要不要細看」。好的說明有幾個共通點:
- 第一行是標題,簡短概括做了甚麼。習慣上不超過 50 個字元(中文字大約 25 個字),因為很多工具只顯示這一行。
- 用動詞開頭,寫具體的事。「修正第三節的樣本數」勝過「修改」;「加入 CSV 匯出」勝過「update」。
- 需要解釋「為甚麼」時,空一行再寫正文。改了甚麼,
git show會告訴讀者;為甚麼要改,只有你知道。 - 一個 commit 只做一件事。如果標題需要用「和」連接兩件事,通常代表應該拆成兩個 commit。
6一個大 commit,還是幾個小 commit? One big commit or several?
一天下來你可能改了五件事。全部放進一個 commit 最省事,但代價會在之後出現。試試看:
| 一個大 commit | 幾個小 commit | |
|---|---|---|
| 提交時 | 省事 | 要逐件 add、分開寫說明 |
| 說明 | 只能寫得含糊(「更新報告」) | 每個都具體 |
| 撤銷其中一件 | 會連帶撤銷其他改動 | 只撤銷那一件 |
| 找出問題何時出現 | 難,要在大 commit 裏逐行找 | 容易(M14 的 bisect) |
| 審查(PR) | 審查者要一次看懂所有改動 | 可以逐件理解 |
準則不是「越小越好」,而是一個 commit 一件完整的事:它本身說得清楚,撤銷它也不會留下半件事。
7查看歷史 Viewing history
| 命令 | 用途 |
|---|---|
git log | 完整列出 commit:編號、作者、時間、說明 |
git log --oneline | 每個 commit 一行,最常用 |
git log -n 3 | 只看最近 3 個 |
git log --stat | 同時列出每個 commit 改了哪些檔案 |
git log -p notes.md | 只看和 notes.md 有關的 commit,並顯示改動內容 |
git show | 最新一個 commit 的說明和改動 |
git show a1b2c3d | 指定某個 commit(編號寫頭幾位就夠) |
git commit -a:方便,但要知道它跳過了甚麼
git commit -a -m "說明"(可合寫成 -am)會先把所有已追蹤檔案的修改自動 add,再提交。它省了一步,但有兩點要記住:
- 它不會加入未追蹤的新檔案,新檔案仍要先
git add。 - 它跳過了「挑選放甚麼進紙箱」這一步。改動混雜時,先
git status看清楚再決定用不用。
8小測 Quiz
本單元重點 Summary
- 基本循環:改 → 看(
status、diff)→ 暫存(add)→ 提交(commit)→ 查(log、show)。 git init建立.git資料夾,那就是倉庫本身。.gitignore要在第一次提交前寫好,並且本身要提交;它管不到已追蹤的檔案。- 密鑰一旦提交就留在歷史裏,唯一可靠的補救是作廢它。
- commit 說明:簡短標題、動詞開頭、寫具體的事、需要時補「為甚麼」。
- 一個 commit 一件完整的事,日後撤銷、追查、審查都容易。
延伸閱讀
- Pro Git 2.1 Getting a Git Repository
- Pro Git 2.2 Recording Changes to the Repository(含 Ignoring Files 一節)
- Pro Git 2.3 Viewing the Commit History
- github/gitignore:各種語言和工具常用的
.gitignore範本 - 有問題?記下來,它很可能也是其他同學的問題 → 學生問題庫