全文约2200字,预计阅读8分钟。
刚用 Git 的人,命令背了一堆,真到团队协作还是心里没底:提交写错了怎么改?分支该怎么命名?rebase 和 merge 到底用哪个?冲突了不敢动怎么办?这篇不堆概念,只把日常开发天天会用到的命令和一套能跑通的协作流程捋一遍,每段配命令和踩坑记录。照着这个流程走,提交、分支、合并、处理冲突都能稳稳落地。
01 前言:先把工作区这几个状态分清
Git 里文件有几个状态,搞混了命令就用不对:
- 工作区:你正在编辑的目录;
- 暂存区 :
git add之后、等着被提交的内容; - 本地仓库 :
git commit之后真正记下来的版本; - 远程仓库 :
git push之后别人能看到的版本。
一条命令一个目的地。很多混乱都来自"以为 add 了就提交了",其实 add 只是放进暂存区,commit 才真正落库。
02 提交前:init、add、commit 与忽略规则
新项目或拉下来的项目,先看状态,别凭感觉:
bash
git status # 看现在改了什么、哪些已暂存
git diff # 看工作区还没暂存的具体改动
git diff --staged # 看已经暂存、准备提交的改动
提交本身:
bash
git add . # 把改动放进暂存区
git commit -m "修复列表为空时的样式错位" # 落一次提交
提交信息要写清楚"做了什么",而不是"改了改"。过两周回头看,一份好的提交信息能帮你秒懂当时在干嘛。
.gitignore 是提交前的必修课,常见要忽略的:
gitignore
# 依赖与构建产物
node_modules/
dist/
# 本地环境与日志
.env
*.log
# 编辑器与系统临时文件
.DS_Store
.idea/
要点:.gitignore 一定要在文件还没被跟踪之前写好。已经提交过的文件,再写进 .gitignore 也不会自动消失,得先从版本库里删掉。
03 分支:日常开发的主战场
分支是 Git 最有用的功能,日常开发几乎都在分支上进行:
bash
git branch # 看本地有哪些分支
git switch -c feature/login # 新建并切到功能分支(旧写法是 checkout -b)
git switch main # 切回主分支
git branch -d feature/login # 删掉已合并的分支
分支命名建议带上目的,比如 feature/登录优化、fix/列表闪退、hotfix/支付回滚。看到名字就知道这分支在干嘛,比一串随机 hash 好协作得多。
04 同步远程:fetch、pull、push 的区别
这三个新手最容易混:
bash
git fetch # 只把远程的更新拉下来,不动你当前的工作区
git pull # 拉远程更新并立刻合并到当前分支
git push # 把本地提交推到远程
- fetch 是安全的,它只更新远程跟踪分支,不碰你手里的活,不确定的时候先 fetch 看看。
- pull 等于 fetch + merge,如果本地有没提交的改动,可能直接拉出冲突。
- push 第一次推新分支要带上上游:
bash
git push -u origin feature/login
之后在这个分支上直接 git push 就行。
05 合并:rebase 和 merge 怎么选
这是协作里争论最多的点,其实按场景分就好。
merge:把目标分支合并进来,保留完整的提交历史,会产生一个合并节点。
bash
git switch feature/login
git merge main # 把最新的 main 合进当前功能分支
rebase:把你这几个提交"搬到"目标分支最新位置上,历史更线性、干净。
bash
git switch feature/login
git rebase main
判断原则:
- 公共分支上的提交,别 rebase。已经 push 到远程、别人还在基于它开发的分支,rebase 会改写历史,把协作的人坑得很惨。
- 自己本地、还没分享出去的提交,可以放心 rebase,把提交整理得清爽一点再推。
- 团队定好统一习惯:有人偏好线性历史用 rebase,有人偏好保留合并节点用 merge,跟着团队约定走,别自己一套。
06 冲突:别慌,一步步解
合并或 rebase 时提示冲突,是再正常不过的事。冲突时文件里会长这样:
markdown
<<<<<<< HEAD
这是当前分支的写法
=======
这是要合进来的写法
>>>>>>> feature/login
解法流程:
- 打开冲突文件 ,找到所有
<<<<<<<标记,想清楚两边到底该留哪段、或者怎么合并; - 手动删掉标记行,保留最终正确的内容;
- 标记已解决 :
git add 冲突文件; - 继续流程 :merge 的话直接
git commit;rebase 的话git rebase --continue。
实在解乱了想放弃这一步,退路是有的:merge 进行中可以 git merge --abort,rebase 进行中可以 git rebase --abort,都能回到操作前的状态。知道有退路,就不会怕冲突。
07 一套能跑通的协作流程
日常协作最省心的是主干加功能分支的模式,流程如下:
- 从最新的主干切出功能分支:
git switch -c feature/xxx; - 在功能分支上小步提交,别攒几十个改动一次提交;
- 隔段时间同步一次主干,把主干的更新合进来,提前解决冲突,别等到最后一刻;
- 开发完推到远程,发起合并请求到主干;
- 评审通过后合并,删掉已经合掉的功能分支。
这个模式的好处是主干始终保持可用,每个人在自己的分支上折腾,互不打扰。
08 踩坑记录
踩坑一:提交信息写错了,想改最近一次。 还没 push 的话,git commit --amend -m "新的提交信息" 可以改最近一次提交。已经 push 到公共分支的,别用 amend,会改写历史。
踩坑二:误 push 了不该推的东西,想撤回。 还没被别人拉下的话,可以本地撤掉提交再强推;但强推公共分支风险很大,确认没人基于它开发再操作。自己的功能分支强推无所谓。
踩坑三:.gitignore 没提前写,把依赖文件夹提交上去了。 修复:git rm -r --cached node_modules 先从版本库移除(本地文件保留),再写进 .gitignore,重新提交。光写 .gitignore 不删已跟踪文件是没用的。
踩坑四:切分支时提示有未提交改动。 别硬切。要么先 commit,要么 git stash 把改动临时存起来,切完再 git stash pop 取回来。带着没提交的改动切分支,很容易把两个分支的改动搅在一起。
踩坑五:进了 detached HEAD 状态不知道怎么回去。 checkout 到某个具体提交而不是分支名时会进入这个状态。修复:基于当前状态新建分支 git switch -c 临时分支,再正常切回去,别在 detached 状态下直接开发,容易丢提交。
踩坑六:rebase 改了已经推送的分支,队友拉代码时炸了。 这就是前面说的铁律:公共分支上的提交绝不 rebase。rebase 只用于整理自己本地还没分享的提交。
09 总结
Git 日常用到的命令其实不多,记住这套骨架就够:
- 改之前
git status看状态,改完add再commit; - 永远在功能分支上开发,别直接在主干上改;
- 同步远程先
fetch看一眼,合并用merge,整理本地提交用rebase; - 冲突别怕,找到标记、手动合并、
add、继续流程,解错了随时--abort退回; - 公共分支不改写历史,这是协作的底线。
Git 没有那么神秘,日常高频命令就那十几个。真正容易出错的不是命令本身,而是不了解每个命令改了工作区的哪一层。把状态流转想清楚,提交、分支、合并这几件事就稳了。剩下的冷门命令,用到的时候再查文档也完全来得及。