Git 工作流实战
本章目标:掌握企业日常开发中最高频的 Git 操作,做到"闭眼操作不出错"。
一、企业日常开发的标准流程
1.1 每天早上到公司
bash
# 第一件事:同步远程代码
git checkout main
git pull origin main
# 同步 develop(如果用 Git Flow)
git checkout develop
git pull origin develop
# 如果你昨天的功能分支还没合并,也同步一下
git checkout feature/user-login
git rebase origin/develop # 把 develop 的最新改动变基到你的分支
1.2 开发过程中的提交
bash
# 提交信息必须规范(下一节详细讲)
git add <具体文件> # 不要用 git add .
git commit -m "feat(auth): add login form validation"
1.3 下班前
bash
# 推送到远程(备份 + 让同事能看到你的进度)
git push -u origin feature/user-login
# 如果用了 rebase
git push --force-with-lease
1.4 功能开发完成
bash
# 同步最新代码
git fetch origin
git rebase origin/develop
# 解决冲突(如果有)
# ...
# 推送
git push --force-with-lease
# 在 GitLab 上创建 Merge Request
# 等待 Code Review → 合并 → 删除分支
二、Git Commit Message 规范(Conventional Commits)
这是企业中最重要的规范之一,不遵守会被 leader 打回来。
2.1 格式
<type>(<scope>): <subject>
<body>
<footer>
2.2 Type 类型
| Type | 说明 | 示例 |
|---|---|---|
feat |
新功能 | feat(auth): add login page |
fix |
修复 Bug | fix(payment): fix amount calculation |
docs |
文档更新 | docs(readme): update installation guide |
style |
代码格式(不影响逻辑) | style: fix indentation |
refactor |
重构(非新功能非修复) | refactor(user): extract validation logic |
perf |
性能优化 | perf(query): add database index |
test |
测试 | test(auth): add login unit tests |
chore |
构建/工具/依赖 | chore: update dependencies |
ci |
CI/CD 配置 | ci: add GitHub Actions workflow |
revert |
回滚 | revert: revert "feat(auth): add login" |
2.3 Scope 范围
表示影响范围(模块/组件),可选:
auth- 认证模块payment- 支付模块user- 用户模块api- API 层db- 数据库
2.4 实际示例
bash
# 简单的
git commit -m "feat(auth): add user login"
# 带 body 的
git commit -m "fix(payment): fix discount calculation
The discount was not applied when using coupon codes.
This was caused by missing null check in applyDiscount().
Fixes #123"
2.5 用 Git Hooks 自动检查(推荐)
bash
# 安装 commitlint
npm install --save-dev @commitlint/cli @commitlint/config-conventional
# 创建配置文件
cat > commitlint.config.js << 'EOF'
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [2, 'always', [
'feat', 'fix', 'docs', 'style', 'refactor',
'perf', 'test', 'chore', 'ci', 'revert'
]],
'subject-max-length': [2, 'always', 100],
},
};
EOF
三、git add 的正确姿势
3.1 交互式暂存(企业推荐)
bash
# 选择性暂存(最推荐)
git add -p <file>
# 会逐个显示代码块(hunk),选择:
# y - 暂存这个 hunk
# n - 跳过
# s - 拆分这个 hunk
# q - 退出
# 这样你可以把一个文件的改动分成多次提交
3.2 常见场景
bash
# ✅ 推荐:只添加需要的文件
git add src/login.js src/login.css
# ❌ 不推荐:添加所有改动
git add .
# ⚠️ 谨慎:添加所有改动(跳过交互确认)
git add -A
# 查看将要提交的内容
git diff --staged
3.3 撤误操作
bash
# 撤销 git add(取消暂存)
git reset HEAD <file>
# 或者用新语法
git restore --staged <file>
# 丢弃工作区的修改(危险!不可恢复)
git restore <file>
# 丢弃暂存区的修改
git restore --staged <file>
四、git commit 深入
4.1 好的 commit 原则
一个 commit = 一个逻辑单元
✅ 好的:
commit 1: feat(auth): add login form
commit 2: feat(auth): add login API call
commit 3: feat(auth): add login error handling
❌ 不好的:
commit 1: feat(auth): add login (包含了 form + API + error + style)
4.2 修改最近一次 commit
bash
# 修改 commit message
git commit --amend -m "feat(auth): add login validation"
# 修改内容(忘记 add 某个文件)
git add forgotten-file.js
git commit --amend --no-edit
4.3 修改更早的 commit(交互式 rebase)
bash
# 修改最近 3 次 commit
git rebase -i HEAD~3
# 编辑器会显示:
pick abc1234 feat(auth): add login form
pick def5678 feat(auth): add login API
pick ghi9012 fix(auth): fix typo
# 把你想修改的那行的 pick 改成 edit 或 reword
# edit = 修改内容
# reword = 只修改 message
# squash = 合并到上一个 commit
# drop = 删除这个 commit
# 例如修改第一个 commit:
edit abc1234 feat(auth): add login form
pick def5678 feat(auth): add login API
pick ghi9012 fix(auth): fix typo
五、git stash --- 临时存储工作
场景:你正在开发功能 A,突然要修紧急 Bug。
bash
# ===== 1. 保存当前工作 =====
git stash push -m "WIP: feature A"
# 或者更简洁
git stash
# ===== 2. 切到 main 修 Bug =====
git checkout main
git pull origin main
git checkout -b hotfix/fix-bug
# ... 修 Bug ...
git commit -m "fix: critical bug"
git push origin hotfix/fix-bug
# ===== 3. 回到功能 A 继续开发 =====
git checkout feature/user-login
# 恢复之前的工作
git stash pop
# ===== 4. stash 操作 =====
git stash list # 查看所有 stash
git stash pop # 恢复并删除
git stash apply stash@{1} # 恢复但不删除
git stash drop stash@{0} # 删除指定 stash
git stash clear # 清空所有 stash
六、git cherry-pick --- 精确移植提交
场景:你在 feature 分支修了一个 Bug,需要把这个修复也同步到 release 分支。
bash
# 先找到要移植的 commit hash
git log --oneline feature/user-login
# 输出:abc1234 fix(auth): fix login timeout
# 切到目标分支
git checkout release/v1.2.0
# 精确移植这个 commit
git cherry-pick abc1234
# 如果有冲突,解决后
git cherry-pick --continue
# 取消本次 cherry-pick
git cherry-pick --abort
七、git bisect --- 二分查找 Bug
场景:你知道某个 commit 引入了 Bug,但不知道是哪个。
bash
# 启动二分查找
git bisect start
# 标记当前版本是有 Bug 的
git bisect bad
# 标记某个已知好的版本
git bisect good v1.0.0
# Git 会自动 checkout 中间的 commit
# 你测试一下,然后告诉 Git:
git bisect good # 这个版本没问题
# 或
git bisect bad # 这个版本有问题
# 重复几次,Git 会找到引入 Bug 的第一个 commit
# 结束后
git bisect reset
八、git log 进阶
bash
# 简洁一行显示
git log --oneline
# 带分支图
git log --oneline --graph --all --decorate
# 按时间范围
git log --since="2 weeks ago"
git log --since="2024-01-01" --until="2024-01-31"
# 按作者
git log --author="张三"
# 按文件
git log -- src/login.js
# 按内容搜索
git log --grep="fix login"
# 查看每次提交的改动
git log -p
# 查看统计信息
git log --stat
# 自定义格式
git log --pretty=format:"%h - %an, %ar : %s"
九、git diff 进阶
bash
# 工作区 vs 暂存区
git diff
# 暂存区 vs 最新提交
git diff --staged
# 两个 commit 之间的差异
git diff abc1234 def5678
# 两个分支之间的差异
git diff main..feature/user-login
# 只看文件名
git diff --stat main..feature/user-login
# 按单词比较(更精确)
git diff --word-diff
十、配置企业 Git Hooks
pre-commit:提交前检查
bash
# .husky/pre-commit(如果用 husky)
#!/bin/sh
npx lint-staged
# lint-staged 配置(package.json)
{
"lint-staged": {
"*.{js,ts}": ["eslint --fix", "prettier --write"],
"*.{css,scss}": ["prettier --write"],
"*.{json,md}": ["prettier --write"]
}
}
commit-msg:检查 commit 信息
bash
# .husky/commit-msg
#!/bin/sh
npx commitlint --edit $1
pre-push:推送前检查
bash
# .husky/pre-push
#!/bin/sh
npm run test
十一、练习清单
学完本章,请完成以下操作:
- 用
git add -p把一个文件的改动分多次提交 - 用
git stash暂存工作,切换分支修 Bug,再恢复 - 用
git cherry-pick移植一个 commit 到另一个分支 - 用
git rebase -i修改/合并/删除最近 3 次 commit - 用
git log --graph --all查看完整的分支图 - 配置 commitlint,提交一个不规范的 commit 试试
上一章 :02-企业分支管理策略
下一章:04-团队协作与Code Review(04-团队协作与Code Review.md)