Lesson 0003:Git 进阶——不只是 commit & push

你已经在用 git addgit commitgit pushgit pull。这是开发者的 Git。DevOps 工程师用的是另一套 Git——用于自动化、排查、救火和代码考古。

这节课讲 6 个你面试会被问到、工作中会救命的高级操作。

1. git log —— 代码考古学

默认的 git log 输出太啰嗦。DevOps 的标准配方:

# 一行一个 commit,带图形化分支
git log --oneline --graph --all

# 只看最近 10 条
git log --oneline -10

# 找特定人的 commit
git log --oneline --author="bram35mm"

# 找特定时间段的
git log --oneline --since="2026-07-01" --until="2026-07-15"

# 找改过某个字符串的 commit(比如找谁动了 API_URL)
git log -S "API_URL" --oneline

# 看某个文件的变更历史
git log --oneline -- package.json
~/.gitconfig 里加个 alias:git lg = log --oneline --graph --all,以后打 git lg 就行。

2. git stash —— 临时保存现场

场景:你在 feature 分支改了一半,突然线上出 bug 需要切回 main 修。但你不想 commit 半成品。

git stash                    # 把当前改动「藏起来」,工作区恢复干净
git stash list               # 查看所有 stash
git stash pop                # 恢复最近一次 stash 并删除它
git stash apply stash@{1}    # 恢复指定 stash,不删除
git stash drop stash@{1}     # 删除指定 stash
git stash save "WIP: login"  # 带备注 stash

DevOps 场景:你在改 CI 配置,突然需要切回去修 pipeline。stash → 切分支 → 修完 → stash pop。

3. git rebase —— 重写历史

这是面试最爱问的。rebase 和 merge 都能合并分支,但结果不同:

# merge:产生一个额外的 merge commit,历史是「网状的」
# rebase:把你的 commit 「搬到」目标分支最新 commit 之后,历史是「线性的」

交互式 rebase(最强大):

git rebase -i HEAD~4    # 对最近 4 个 commit 进行交互式操作

会打开编辑器,列出最近 4 个 commit,每行前面有一个命令:

命令效果什么时候用
pick保留这个 commit默认
squash合并到上一个 commit,保留 commit message把「fix typo」合并进主 commit
fixup合并到上一个 commit,丢弃 commit message同上但不需要保留 message
reword只改 commit messagemessage 写错了
drop删除这个 commit不小心提交了敏感信息
⚠️ 黄金法则:不要 rebase 已经 push 到共享分支的 commit。 rebase 会改变 commit hash,别人的本地分支会炸。只 rebase 你自己的、还没 push 的 commit。

4. git cherry-pick —— 摘樱桃

把某个 commit 的改动「复制」到当前分支。不合并整个分支,只要一个 commit。

git cherry-pick abc1234    # 把 commit abc1234 的改动应用到当前分支

DevOps 场景:你在 release 分支上,只需要 hotfix 分支里的一个 commit,不需要整个 hotfix 分支。

5. git bisect —— 二分法找 bug

场景:3 天前的版本没问题,现在的版本有问题。中间有 50 个 commit。谁引入的?

git bisect start              # 开始二分搜索
git bisect bad HEAD           # 标记当前版本是坏的
git bisect good abc1234       # 标记 3 天前的版本是好的

# Git 会自动 checkout 到中间一个 commit
# 你测试一下 → 如果是好的就 git bisect good
#             → 如果是坏的就 git bisect bad
# 重复几次后 Git 找到第一个坏的 commit

git bisect reset              # 结束搜索,回到原地

50 个 commit 只需要大约 log₂(50) ≈ 6 次测试就能定位。这是 DevOps 排查线上问题的神器。

6. git reflog —— 后悔药

你做了 git reset --hard,删掉了 3 天的代码。panic?不用。

git reflog            # 显示 HEAD 的所有移动历史(包括「丢失」的 commit)
git reset --hard HEAD@{3}   # 回到 3 步之前的状态

reflog 是本地 Git 的「操作日志」,记录了每一次 HEAD 变动。只要 commit 过,就永远能找到(默认保留 90 天)。

7. Git Hooks —— CI/CD 的入口

Git Hook 是在特定 Git 事件发生时自动执行的脚本。它们存在 .git/hooks/ 下(每个 repo 一份)。

Hook触发时机DevOps 用途
pre-commitcommit 之前跑 lint、格式化、检查密码泄漏
commit-msg编辑完 commit message 后检查 message 格式(如 Conventional Commits)
pre-pushpush 之前跑测试,不通过则阻止 push
post-receive服务端收到 push 后触发 CI/CD 流水线!
# 快速试一下 pre-commit hook
cd /tmp && mkdir hook-demo && cd hook-demo && git init
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
echo "🔍 Running pre-commit checks..."
# 检查是否有 console.log 残留
if git diff --cached | grep -q "console\.log"; then
  echo "❌ Found console.log! Remove it before committing."
  exit 1
fi
echo "✅ All checks passed!"
EOF
chmod +x .git/hooks/pre-commit

# 测试
echo "console.log('test')" > app.js
git add app.js
git commit -m "test"    # 会被 hook 拦截!
实际项目中不会手写 hook 脚本,而是用工具管理:pre-commit(Python 生态)或 husky(Node 生态,你可能已经在用了)。

动手练习

在你的终端里建一个临时仓库来练习(不会影响任何项目):

cd /tmp && rm -rf git-practice && mkdir git-practice && cd git-practice
git init

# 创建 5 个 commit 来模拟真实开发
echo "v1" > file.txt && git add . && git commit -m "init"
echo "v2" >> file.txt && git add . && git commit -m "feat: add v2"
echo "v3" >> file.txt && git add . && git commit -m "fix: typo"
echo "v4" >> file.txt && git add . && git commit -m "wip"
echo "v5" >> file.txt && git add . && git commit -m "feat: add v5"

# 1. 用 git log --oneline 看历史
# 2. 用 git rebase -i HEAD~4 把后 4 个 commit 压缩成 1 个
#    → 保留第一个 "init",其余改成 squash 或 fixup
# 3. 用 git log --oneline 确认只有 2 个 commit 了
# 4. 用 git reflog 看被你「压缩掉」的原始 commit 还在

小测验

Q1:你做了 git reset --hard 误删了代码。哪个命令能救回来?
Q2:在交互式 rebase 中,要把「fix typo」合并到上一个 commit 且丢弃 message,用哪个命令?
Q3:rebase 的黄金法则是什么?
Q4:服务端收到 push 后自动触发 CI/CD,用什么 hook?

推荐资源

下一步

下一课我们进入 Shell 脚本编程——把命令行操作变成可重复执行的自动化脚本。这是所有 CI/CD 流水线和自动化运维的基础。

Git 操作卡住了?把报错发给我。如果你用 rebase 把自己搞晕了,记住 git rebase --abort 可以安全退出。
← Lesson 0002 · 术语表 · Mission