Git 常用命令实战指南:从开发到合并的完整工作流
Git 常用命令实战指南:从开发到合并的完整工作流
引言
很多人学 Git 的方式是:遇到问题 → 搜命令 → 复制粘贴 → 下次继续搜。这当然能干活,但当你面对一个混乱的提交历史、一场惨烈的合并冲突、或是一个"我刚刚到底做了什么"的时刻,零散的命令记忆就捉襟见肘了。
本文不打算罗列 Git 的所有命令,而是沿着一个开发者的真实工作流,把最常用的命令串联起来。读完你会有一个清晰的心智模型——知道每一步在做什么、为什么这样做、踩坑了怎么回退。
一、开始新功能:从仓库到分支
场景
早上领到一个新需求,你需要从团队仓库拉取最新代码,然后创建自己的开发分支。
核心命令
1. 克隆仓库
git clone git@github.com:team/project.git
如果你是第一次接触这个项目,clone 会把整个仓库(含完整历史)拉到本地。如果项目很大,可以只克隆最近一次提交:
git clone --depth 1 git@github.com:team/project.git
2. 拉取最新代码
如果你已经克隆过,先同步远程的最新状态:
git fetch origin
fetch 只下载远程更新,不会动你的工作区。想看看远程有什么新东西?
git log origin/main ^main # 远程比本地多了哪些提交
3. 创建特性分支
永远不要在 main 分支上直接开发,这是团队协作的第一条纪律。
git checkout -b feature/user-login
从 Git 2.23 开始,switch 和 restore 拆分了一部分 checkout 的职责,语义更清晰:
git switch -c feature/user-login # 创建并切换到新分支
分支命名建议遵循团队约定,常见模式:feature/xxx、bugfix/xxx、hotfix/xxx。
常见坑点
git pull=git fetch+git merge,它会在你不知道的时候自动产生一个合并提交。推荐使用git pull --rebase(详见第三节),保持历史线性。- 忘记切分支就开始写代码?用
git stash救回来(详见第三节)。
二、日常开发:写代码与提交
场景
你在特性分支上写代码,时不时需要查看改了什么、暂存文件、提交变更。
核心命令
1. 查看状态
git status # 完整状态
git status -s # 简短模式,适合截图/分享
这是 Git 中使用频率最高的命令。养成习惯:做任何操作前先 git status。
2. 查看差异
git diff # 工作区 vs 暂存区(还没 add 的改动)
git diff --staged # 暂存区 vs 上次提交(已经 add 但还没 commit 的改动)
git diff HEAD # 工作区 + 暂存区 vs 上次提交(全部未提交的改动)
git diff main..feature # 两个分支之间的差异
git diff 的输出有时候不太直观,推荐配合 GUI 工具(VS Code 内置的 diff 就很好用)或者加 --name-only 只看文件名:
git diff --name-only HEAD # 只列出改动的文件
3. 暂存文件
git add filename.py # 暂存单个文件
git add -p filename.py # 交互式暂存,逐块选择(强烈推荐)
git add -A # 暂存所有改动(谨慎使用)
git add -p 是进阶利器——它会逐块展示改动并让你选择是否暂存。这样你可以把一次改动的不同部分分开提交,每个提交只做一件事。
4. 提交
git commit -m "feat: 添加用户登录接口"
提交信息值得认真写。 推荐 Conventional Commits 规范:
| 前缀 | 用途 | 示例 |
|---|---|---|
feat |
新功能 | feat: 添加短信验证码登录 |
fix |
Bug 修复 | fix: 修复 token 过期后不刷新的问题 |
refactor |
重构 | refactor: 提取公共的权限校验逻辑 |
docs |
文档 | docs: 更新 API 接口文档 |
chore |
杂项 | chore: 升级依赖版本 |
如果漏了文件或写错了提交信息:
git add forgotten_file.py
git commit --amend --no-edit # 把漏掉的文件追加到上一次提交,不改信息
git commit --amend -m "新的提交信息" # 修改上一次提交的信息
注意: --amend 会改写历史,只用于还没推送的提交。
5. 查看提交历史
git log # 完整日志
git log --oneline # 每行一条,适合快速浏览
git log --oneline --graph # 带分支图的简洁日志(推荐设为别名)
git log -3 # 只看最近 3 条
git log --since="2026-05-01" --until="2026-05-31" # 按日期范围筛选
建议设一个别名:
git config --global alias.lg "log --oneline --graph --all"
之后 git lg 就能看到漂亮的分支图了。
常见坑点
- 提交完发现
git status还有红色文件?那是因为这些文件从来没被git add过(untracked)。用git add添加它们。 git add -A会把所有改动(包括不想提交的调试代码)都暂存,日常开发用git add -p更安全。
三、同步协作:拉取、冲突与暂存
场景
同事推送了新的提交到远程,你需要同步过来。更糟的是,你可能本地还有一些没写完的代码不想提交。
核心命令
1. 拉取远程更新(推荐 rebase 方式)
git pull --rebase origin main
为什么用 --rebase 而不是默认的 pull?
# 默认 pull(merge 方式):
# A---B---C (main)
# \
# D---E (你的分支)
# 结果会产生一个合并提交 M,历史分叉复杂
# pull --rebase 方式:
# A---B---C---D'---E' (你的分支)
# 把你的提交"接"在远程最新提交后面,历史保持线性
建议设为默认行为:
git config --global pull.rebase true
2. 解决合并冲突
当两个人的改动碰巧在同一个文件的同一区域时,Git 无法自动合并,就会产生冲突。你会在文件里看到:
<<<<<<< HEAD
你的改动
=======
同事的改动
>>>>>>> main
解决步骤:
# 1. 手动编辑文件,删除冲突标记,保留正确的代码
# 2. 标记为已解决
git add conflicted_file.py
# 3. 如果是在 rebase 过程中,继续
git rebase --continue
# 如果想放弃这次合并/变基
git merge --abort # 放弃 merge
git rebase --abort # 放弃 rebase
减少冲突的技巧:
- 经常
pull --rebase,不要攒一周才拉一次 - 多人改同一个文件时,提前沟通分工
3. 暂存临时工作
写到一半需要切分支处理紧急 bug,但又不想提交半成品?
git stash # 暂存所有未提交的改动
git stash list # 查看暂存列表
git stash pop # 恢复最近一次暂存,并从列表中删除
git stash apply # 恢复最近一次暂存,但保留在列表中
git stash drop stash@{0} # 删除指定的暂存
更实用的方式——给 stash 加个描述:
git stash push -m "用户登录写到一半"
常见坑点
git stash pop后有冲突不会自动清理 stash,需要手动git stash drop。- 永远不要 rebase 已经推送到远程的公共分支,这会破坏其他人的工作基础。
四、提交整理:让历史干净如初
场景
你的分支上有 10 个提交,其中 3 个是 "fix typo"、2 个是 "WIP"、还有几个来回调整的。在提 PR 之前,你希望把它们整理成逻辑清晰的几个提交。
核心命令
1. 交互式变基
这是整理提交历史最强大的工具:
git rebase -i HEAD~5 # 整理最近 5 个提交
git rebase -i main # 整理从与 main 分叉以来的所有提交
会打开编辑器,列出你的提交:
pick a1b2c3d feat: 添加登录页面
pick e4f5g6h fix typo
pick i7j8k9l WIP: 接口联调
pick m0n1o2p feat: 完成登录接口
pick q3r4s5t fix: 修正返回值格式
你可以修改每行前面的命令:
| 命令 | 作用 |
|---|---|
pick |
保留这个提交 |
reword |
修改提交信息 |
squash |
合并到上一个提交,保留信息 |
fixup |
合并到上一个提交,丢弃信息(最常用) |
drop |
删除这个提交 |
edit |
暂停在这里,让你手动修改 |
整理后可能是这样:
pick a1b2c3d feat: 添加用户登录功能
fixup e4f5g6h fix typo
fixup i7j8k9l WIP: 接口联调
fixup m0n1o2p feat: 完成登录接口
fixup q3r4s5t fix: 修正返回值格式
最终变成 1 个干净的提交。
2. 软重置
如果还没推送,想要重新组织最近几次提交:
git reset --soft HEAD~3 # 撤销最近 3 次提交,改动保留在暂存区
# 然后重新提交
git commit -m "feat: 完整的功能描述"
三种 reset 模式的区别:
| 模式 | 提交历史 | 暂存区 | 工作区 |
|---|---|---|---|
--soft |
回退 | 保留 | 保留 |
--mixed(默认) |
回退 | 清空 | 保留 |
--hard |
回退 | 清空 | 清空(危险!) |
3. 拣选提交
只想把另一个分支的某个提交拿过来用,而不是合并整个分支:
git cherry-pick a1b2c3d # 拿一个
git cherry-pick a1b2c3d..e4f5g6h # 拿一段(不包含 a1b2c3d)
典型场景:你在 feature/A 修了一个 bug,feature/B 也需要同样的修复。
常见坑点
git reset --hard会永久丢失未提交的改动。执行前确保git status是干净的。- 已经推送过的提交不要用
rebase -i整理,除非你确定只有你一个人在用这个分支(用git push --force-with-lease替代--force,更安全)。 - 如果不小心做错了什么,
git reflog是你的时光机:
git reflog # 查看所有 HEAD 的移动记录
git reset --hard HEAD@{3} # 回到 3 步之前的状态
五、代码合并:提 PR 与推送
场景
代码写好、提交整理完毕,现在推送到远程、发起 Pull Request。
核心命令
1. 推送到远程
git push origin feature/user-login # 首次推送
git push # 如果已经设置了上游跟踪
git push --force-with-lease # 如果本地整理过历史(比 --force 安全)
--force-with-lease 和 --force 的区别:前者在推送前会检查远程分支是否有你不知道的新提交,如果有就拒绝推送,避免覆盖同事的工作。
2. 变基到最新 main
在提 PR 之前,最好先把最新的 main 分支内容合并进来,确保没有冲突:
git fetch origin
git rebase origin/main
git push --force-with-lease
3. 合并到主分支
这部分通常在 GitHub/GitLab 的网页界面上操作,两种策略:
| 策略 | 效果 | 适用场景 |
|---|---|---|
| Merge Commit | 保留完整的分支历史,生成一个合并提交 | 多人协作的大型特性 |
| Squash and Merge | 把一个分支的所有提交压成一个 | 小型修复,保持主分支干净 |
| Rebase and Merge | 线性历史,无合并提交 | 追求整洁历史的团队 |
具体哪种由团队决定,不必纠结——重要的是保持一致。
常见坑点
- 第一次推送新分支需要用
git push -u origin feature/xxx(-u设置上游跟踪),之后才能直接用git push。 - 推送被拒绝(
rejected)通常是因为远程有新的提交,先git pull --rebase再推送。
附录:四道"救命"命令
当你觉得搞砸了的时候,这些命令能救命:
# 1. 时光机:查看 HEAD 移动记录,找回"丢失"的提交
git reflog
# 2. 撤销工作区的所有改动(回到上次提交的状态)
git restore .
# 3. 撤销某个提交(产生一个新的反向提交,不改写历史)
git revert a1b2c3d
# 4. 找出哪次提交引入了一个 bug(二分查找)
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
# Git 会自动 checkout 到中间点让你测试,重复标记 good/bad 直到定位
总结
Git 是一个强大但复杂的工具。记住下面这张心智地图,大部分场景你都能应对:
git fetch → git switch -c xxx → 写代码
→ git add -p → git commit → 循环...
→ git stash(临时切换任务)
→ git pull --rebase(同步远程)
→ git rebase -i(整理历史)
→ git push → 提 PR
→ 搞砸了? git reflog 永远在
最后一条建议:不用记住所有命令,但要知道什么命令能解决什么问题。 当你遇到一个陌生场景时,先停下来想清楚"我现在想做什么",再去找对应的命令,而不是盲目复制粘贴。
本文由 Claude Code + cnblogs MCP Server 协作发布。

浙公网安备 33010602011771号