大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
基本 Git 操作
这一课你将能做到
- 熟练使用
add / commit / log / diff / restore / switch完成日常 90% 的本地操作 - 看懂
git status和git log的输出,知道每个字段在说什么 - 用
.gitignore排除不该进仓库的文件(编译产物、IDE 配置、密钥)
为什么要学
上一课建立了「三大区域」的图像,这一课把它变成肌肉记忆。你以后每天的工作循环就是:改代码 → git status 看状态 → git add 暂存 → git commit 存档 → 偶尔 git log 回溯。这个循环一天要敲几十遍,必须练到不用想。
同时,这些命令是面试高频题:git restore 和 git reset 区别?怎么撤销已经 commit 的改动?怎么只看某个文件的修改历史?答不上来直接出局。
先建立图像
日常命令地图(背下来):
┌─────────┐ add ┌─────────┐ commit ┌─────────┐
│ 工作区 │ ────> │ 暂存区 │ ────> │ 本地仓库 │
│ │ <──── │ │ <──── │ │
└─────────┘ restore└─────────┘ reset └─────────┘
│ │
│ diff(工作区 vs 暂存) │
│ diff --staged(暂存 vs 仓库)
│ ▼
│ log / show(看历史)
▼
switch / restore(切分支 / 丢弃改动)
跟着做
步骤 1:克隆本站仓库(真实场景)
本站代码托管在 GitHub,用 clone 把它拷到本地:
git clone https://github.com/<your-org>/java-nav.git
cd java-nav
git status
# On branch main
# Your branch is up to date with 'origin/main'.
clone 做的事:下载完整 .git + 检出 main 分支的最新快照到工作区。
步骤 2:改一个文件并查看差异
随便打开一个 markdown 文件改一行,然后:
git status
# modified: content/课程/... ← 红色:已改未暂存
git diff
# - 旧的一行
# + 新的一行 ← 精确显示改了什么
git diff 默认对比「工作区 vs 暂存区」。如果想看「暂存区 vs 仓库」,用 git diff --staged。
步骤 3:暂存 + 提交
git add content/课程/README.md
git status # 变绿:已暂存
git commit -m "docs: 修正课程 README 错别字"
提交信息规范建议用「类型: 描述」,常见类型:feat(新功能)/ fix(修 bug)/ docs(文档)/ refactor(重构)/ chore(杂项)。
步骤 4:查看历史
git log # 完整历史(按 q 退出)
git log --oneline # 一行一条,最常用
git log --oneline -10 # 只看最近 10 条
git log --oneline --graph # 带分支线
git show a1b2c3d # 看某个 commit 的完整改动
git log -- content/课程/README.md # 只看某文件的历史
步骤 5:撤销改动(三大场景)
# 场景 A:改了文件但还没 add,想放弃
git restore content/课程/README.md
# 场景 B:已经 add 了,想从暂存区拿回来(改动保留在工作区)
git restore --staged content/课程/README.md
# 场景 C:已经 commit 了,想修正这次提交(未 push 前)
git commit --amend -m "docs: 修正错别字(补充一处)"
老命令 git checkout -- 文件 也能撤销,但新版 Git 推荐语义更清晰的 restore。
步骤 6:配置 .gitignore
在项目根目录新建 .gitignore:
# Java 编译产物
target/
*.class
# IDE
.idea/
.vscode/
*.iml
# 依赖目录
node_modules/
# 环境与密钥(绝不能进仓库!)
.env
application-local.yml
# 操作系统
.DS_Store
Thumbs.db
.gitignore 只影响「未被跟踪」的文件;如果某文件已经 commit 过,要先用 git rm --cached 文件 移出跟踪。
讲清楚要点
git add是「按文件粒度打包」:不要无脑git add .。养成先看git status再决定 add 哪些的习惯,避免把临时文件、密钥顺手提交。git commit只提交暂存区内容:改完没 add 的文件不会进这次提交。想跳过 add 直接提交所有已跟踪文件:git commit -am "..."(对新增文件无效)。git restorevsgit resetvsgit revert:restore 丢弃工作区/暂存区改动(未入库的消失);reset 移动分支指针改写历史(危险);revert 生成一个「反向 commit」抵消历史(安全,可 push)。团队协作公共分支只用 revert。--oneline --graph是排查利器:能让你一眼看出分支分叉点。- commit 哈希前 7 位就够用:
git show a1b2c3d不用写全 40 位。
你可能会懵的地方
-
git add .和git add *一样吗? 不一样。.是当前目录递归(含删除);*是 shell 通配符,不包含以.开头的隐藏文件,也不处理删除。日常用git add .或明确文件名。 -
commit 信息写错了能改吗? 未 push 前:
git commit --amend -m "新信息"。已 push:改了会造成别人历史错乱,团队内禁止;实在要改得全员协调强推。 -
git log卡死在(END)怎么办? 按q退出。这是因为 log 用了分页器 less。 -
怎么找回刚 reset 掉的 commit?
git reflog会列出 HEAD 的所有移动记录,找到目标哈希再git reset --hard 哈希就能救回来。reflog 是后悔药,但默认只保留 90 天。 -
文件改名 Git 会当成删除+新增吗? 会,但 Git 会自动检测相似度并在 log 里显示
rename old => new。建议用git mv old new明确改名。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
改完直接 git commit | 没 add 进暂存区,提交为空 | 先 git add,或用 commit -am |
| 提交信息写「update」「修改」 | 三个月后看不懂 | 用「类型: 具体描述」 |
把 target/ 提交进仓库 | 仓库膨胀、人人冲突 | .gitignore + git rm -r --cached target/ |
公共分支上 git reset --hard | 队友代码全丢 | 用 git revert 生成反向提交 |
混淆 restore --staged 和 restore | 误把工作区改动也清了 | 记牢:staged 只回退暂存,不带参数才动工作区 |
卡点急救
git restore 文件后改动全没了:这正是它的作用——丢弃未暂存修改。误操作后如果从未 add 过,内容无法找回;养成勤 commit 或至少git stash的习惯。git log显示一大坨看不懂:改用git log --oneline --graph --all,立刻清爽。.gitignore加了规则但文件还在被跟踪:因为该文件已入库,先git rm --cached 文件再 commit。
面试常问
-
git reset --soft / --mixed / --hard区别? 三者都移动 HEAD 到指定 commit。--soft:暂存区、工作区不动(改动还在待提交状态);--mixed(默认):暂存区重置、工作区不动(改动变成未暂存);--hard:暂存区+工作区全重置(改动丢失)。公共分支禁用 reset,改用 revert。 -
git revert和git reset的区别? revert 生成新 commit 来「抵消」历史某次提交,历史不被改写,可安全 push;reset 直接移动分支指针删除历史,已 push 的提交被 reset 会造成队友冲突。共享分支一律 revert。 -
怎么查看某个文件某一行是谁改的?
git blame 文件路径逐行显示最后修改人和 commit;配合git log -p 文件路径看该文件完整演进。
自测三问
- 改了文件后想放弃修改,应该敲什么?已经 add 了呢?
git log --oneline --graph比git log好在哪?- 为什么
.gitignore对已经 commit 过的文件无效?
小结一句话
日常 Git 就是「改—看—暂—提—查」五步循环,配合 .gitignore 和 restore 三板斧,你已经能应付本地开发的全部场景。
延伸
- Pro Git:Git 基础
- 下一课:Git 进阶——分支、合并、stash、标签,理解 HEAD 指针的本质。