Git 分支与 rebase 日常工作流笔记

这篇是我自己用了一段时间后整理的工作流笔记。不追求标准答案,只记录在多人协作里行之有效的几个习惯:怎么开 feature 分支、提交搞乱了怎么用交互式 rebase 收拾干净、rebase 撞上冲突时按什么顺序想问题,以及几个用顺手的 alias。

为什么坚持用 feature 分支

主分支(我这里叫 main)我尽量保持随时可发布。任何一个新功能、一个修复,都先切出一条独立分支:

git switch -c feat/user-pagination
# 旧版本 Git 可以用 git checkout -b feat/user-pagination

分支名我习惯加个前缀,比如 feat/、fix/、chore/,一眼就能看出意图。这样做的好处很直接:main 上的历史是一条干净的主线,每个功能的探索过程都关在自己的分支里,没合并之前怎么折腾都不影响别人。

开发途中我会频繁提交,哪怕是半成品。提交信息此时随便写,反正后面要整理。先把进度存下来,比纠结提交粒度更重要。

用交互式 rebase 整理提交

功能写到一半,本地往往攒了一堆零碎提交:“先这样”、“改个拼写”、“再调一下”。这种历史合进 main 会很难读。提交前我会用交互式 rebase 把它们捏成几个有意义的提交。

git rebase -i main

Git 会打开一个待办列表,每一行一个提交,前面是动作。常用的几个:

一个典型的整理,把三个零碎提交压成一个完整功能提交:

pick   a1b2c3d 加分页骨架
fixup  d4e5f6a 改个拼写
fixup  b7c8d9e 补默认页大小

存盘退出后,这三个就合成一条,提交信息以第一条为准。我还会顺手把它 reword 成一句说清楚做了什么的话,例如“为用户列表接口加入分页支持”。

这里有个我吃过亏的点:交互式 rebase 会改写提交历史。所以只对还没推送、或者只有自己在用的分支这么做。已经推上去、别人可能基于它工作的提交,不要随便重写。

解决 rebase 冲突的思路

把分支 rebase 到最新的 main 上,是我合并前的固定动作,这样能让我的提交叠在最新代码之上,历史是直的:

git switch feat/user-pagination
git fetch origin
git rebase origin/main

撞上冲突时,我不会慌着改。先搞清楚当前在重放哪一个提交,Git 会告诉你停在哪。心里有个顺序:

如果中途发现方向不对,或者冲突多到想重来,随时可以 git rebase --abort 退回到 rebase 之前的状态,什么都不会丢。这个后路让我做 rebase 时心里很踏实。

还有个习惯能少踩坑:rebase 之前先确认工作区是干净的,没有未提交的改动。要么先提交,要么 git stash 存起来。

merge 还是 rebase

这两个不是对立的。我的分工大概是:本地整理自己的提交、把功能分支更到最新 main 上,用 rebase,图的是历史干净;真正把功能并回 main 时,用 merge,保留一个合并点,能看出这一组提交是一个完整功能进来的。

原则就一条前面提过:别 rebase 已经共享出去的历史。自己分支上随便整理,共享分支上只做 merge,基本不会出乱子。

几个用顺手的 alias

这些配在全局 ~/.gitconfig[alias] 段里,日常省了不少键:

[alias]
    co = checkout
    sw = switch
    st = status -sb
    cm = commit -m
    lg = log --oneline --graph --decorate -20
    last = log -1 HEAD
    unstage = reset HEAD --
    amend = commit --amend --no-edit

几个我用得最多的:

小结

核心就几句话:功能各走各的分支;本地用交互式 rebase 把提交整理成能读的样子;rebase 撞冲突时一次只想一个提交,留好 abort 后路;共享出去的历史不要重写。把这些变成肌肉记忆之后,日常协作里的提交历史会干净很多,回头查问题也轻松。