Git 工作流与高级技巧:分支管理、Rebase 与团队协作

Git 分支模型

分支是 Git 最强大的特性之一。合理的分支策略能让团队协作更加高效。以下是两种主流的分支工作流。

Git Flow

适合有固定发版周期的项目:

main          ─── 生产环境代码,每次发布打 tag
  └── develop   ─── 开发主线,集成所有功能
        ├── feature/xxx  ─── 功能分支,从 develop 创建
        ├── release/x.x  ─── 发布准备分支
        └── hotfix/xxx   ─── 紧急修复,从 main 创建
# Git Flow 典型操作
git checkout develop
git checkout -b feature/user-auth

# 开发完成后合并回 develop
git checkout develop
git merge --no-ff feature/user-auth
git branch -d feature/user-auth

# 发布新版本
git checkout -b release/1.2.0 develop
# 修复小 bug、更新版本号...
git checkout main
git merge --no-ff release/1.2.0
git tag -a v1.2.0 -m "Release 1.2.0"
git checkout develop
git merge --no-ff release/1.2.0

Trunk-Based Development

适合持续部署的项目(Google、Facebook 均采用):

main ──────────────────────────────────── 持续集成
  ├── feature/small-change-1  (短命分支,1-2天)
  ├── feature/small-change-2
  └── feature/small-change-3

核心原则:频繁集成、短命分支、功能开关(Feature Flags)控制未完成功能的可见性。

Rebase —— 重写提交历史

Rebase 是 Git 中最强大也最容易误用的功能。它能将一系列提交"移植"到新的基点上。

基本 Rebase

# 场景:feature 分支落后于 main
# merge 方式:产生一个合并提交
git checkout feature
git merge main
# 结果: A-B-C-D-E-F-G-M  (M 是合并提交)

# rebase 方式:将 feature 的提交"移到" main 最新提交之后
git checkout feature
git rebase main
# 结果: A-B-C-D-E-F-G-H-I  (线性历史,更清晰)

交互式 Rebase —— 整理提交历史

# 整理最近 5 个提交
git rebase -i HEAD~5

# 编辑器会打开:
pick a1b2c3d 添加用户模型
pick e4f5g6h 修复 typo
pick i7j8k9l 添加用户路由
pick m0n1o2p WIP: 还没写完
pick q3r4s5t 添加测试

# 常用操作:
# pick   = 保留提交
# reword = 修改提交信息
# squash = 合并到上一个提交,保留信息
# fixup  = 合并到上一个提交,丢弃信息
# drop   = 删除提交
# edit   = 暂停,允许修改内容

# 修改为:
pick a1b2c3d 添加用户模型
fixup e4f5g6h 修复 typo           # 合并到上一个
pick i7j8k9l 添加用户路由
drop m0n1o2p WIP: 还没写完        # 删除
pick q3r4s5t 添加测试

Rebase 的黄金规则

永远不要 rebase 已经推送到远程的、其他人正在使用的分支。

Rebase 会改写提交历史(改变 commit hash),如果其他人已经基于旧历史开发,会导致冲突和混乱。只在本地分支或个人分支上使用 rebase。

Cherry-Pick —— 精确移植提交

# 将某个提交应用到当前分支
git cherry-pick abc1234

# 一次性 cherry-pick 多个提交
git cherry-pick abc1234 def5678 ghi9012

# cherry-pick 一个范围(不含起始提交)
git cherry-pick abc1234..ghi9012

# cherry-pick 但不自动提交(可以继续修改)
git cherry-pick --no-commit abc1234

# 实际场景:修复 bug 在 develop 上,需要同步到 release 分支
git checkout release/1.2.0
git cherry-pick <bug-fix-commit-hash>

Bisect —— 用二分法定位 Bug

当发现某个 bug 但不知道是哪个提交引入时,git bisect 能帮你用二分法快速定位。

# 开始 bisect
git bisect start

# 标记当前版本有 bug
git bisect bad

# 标记某个旧版本没有 bug
git bisect good v1.0.0

# Git 会自动 checkout 到中间的提交,你测试后告诉它结果:
# 测试这个版本
git bisect bad   # 有 bug
# 或
git bisect good  # 没有 bug

# Git 继续二分,直到找到引入 bug 的那个提交
# 最终输出:abc1234 is the first bad commit

# 结束 bisect,回到原来的分支
git bisect reset

# 自动化 bisect(用脚本测试)
git bisect start HEAD v1.0.0
git bisect run npm test
# Git 会自动运行 npm test,根据返回码判断 good/bad

Stash —— 临时保存工作区

# 保存当前工作区(包括已暂存的修改)
git stash push -m "正在开发的功能"

# 查看所有 stash
git stash list
# stash@{0}: On feature: 正在开发的功能
# stash@{1}: On feature: 另一个修改

# 恢复最近的 stash(保留 stash 记录)
git stash apply

# 恢复并删除 stash 记录
git stash pop

# 恢复指定的 stash
git stash apply stash@{1}

# 只 stash 指定文件
git stash push -m "只保存这个文件" -- src/app.js

# 包含未追踪的文件
git stash push -u -m "包含新文件"

# 从 stash 创建新分支
git stash branch new-feature-branch stash@{0}

# 删除所有 stash
git stash clear

实用技巧合集

修改最近的提交

# 修改最后一次提交的信息
git commit --amend -m "新的提交信息"

# 追加文件到上一次提交(不改信息)
git add forgotten-file.js
git commit --amend --no-edit

查看精美日志

# 一行式日志,显示分支图
git log --oneline --graph --all --decorate

# 设置别名
git config --global alias.lg "log --oneline --graph --all --decorate --date=short --format='%C(yellow)%h%C(reset) %C(green)%ad%C(reset) %s %C(blue)%an%C(reset) %C(red)%d%C(reset)'"

# 使用
git lg

找回误删的分支或提交

# 查看所有操作记录(包括已删除的分支)
git reflog

# 输出示例:
# abc1234 HEAD@{0}: checkout: moving from main to feature
# def5678 HEAD@{1}: commit: 添加新功能
# ghi9012 HEAD@{2}: branch: Created branch feature

# 恢复被删除的分支
git checkout -b feature-restored def5678

# 恢复被 reset 丢失的提交
git reset --hard HEAD@{2}

对比和调试

# 比较工作区和暂存区
git diff

# 比较暂存区和最后一次提交
git diff --staged

# 比较两个分支
git diff main..feature --stat  # 只看文件统计
git diff main..feature -- src/ # 只看 src 目录

# 查看某个文件的每一行是谁在什么时候修改的
git blame src/app.js

# 搜索提交历史中的代码变更
git log -S "functionName" --oneline  # 搜索代码内容变化
git log --grep="fix" --oneline       # 搜索提交信息

.gitconfig 推荐配置

# ~/.gitconfig
[user]
    name = 陈博豪
    email = bohao@example.com

[alias]
    co = checkout
    br = branch
    ci = commit
    st = status
    lg = log --oneline --graph --all --decorate
    unstage = reset HEAD --
    last = log -1 HEAD --stat
    amend = commit --amend --no-edit

[core]
    autocrlf = input    # Linux/Mac
    editor = code --wait # VS Code 作为默认编辑器

[pull]
    rebase = true        # git pull 时默认使用 rebase

[push]
    default = current    # push 当前分支到同名远程分支

[diff]
    tool = vscode
[difftool]
    prompt = false

[merge]
    tool = vscode
    conflictstyle = diff3  # 显示三方合并冲突

团队协作最佳实践

总结

Git 的学习曲线虽然陡峭,但掌握这些高级技巧后,你的开发效率会有质的飞跃。建议在日常开发中逐步实践:先熟悉 rebase -i 和 stash,再学习 bisect 和 cherry-pick。记住,reflog 是你的安全网——大胆尝试,错了总能找回来。