Git 最佳实践

Git 最佳实践

概述

本文档规定了项目的 Git 提交信息规范,采用 Conventional Commits 格式,确保提交历史清晰易读、便于追溯。

Commit Message 格式

基本结构

xml 复制代码
<type>(<scope>): <subject>

[可选 body]

[可选 footer]

示例:

bash 复制代码
feat(router): 新增虚拟路由插件支持动态路由

实现了基于 Vue Router 的虚拟路由插件,支持:
- 动态路由注册
- 路由守卫自动绑定
- 路由缓存管理

Closes #123

必填字段

Type 类型
Type 说明 使用场景
feat 新功能 添加新特性、新模块
fix Bug 修复 修复缺陷、错误
docs 文档 更新文档、注释
style 代码格式 格式化代码、调整缩进、优化导入等(不影响功能)
refactor 重构 重构代码逻辑(不改变功能)
perf 性能优化 提升性能、优化算法
test 测试 添加/修改测试
chore 构建/工具 修改配置、构建脚本、依赖管理
revert 回滚 回滚之前的提交
Scope 范围

范围应该是受影响的业务模块或功能,使用 kebab-case

业务模块示例:

复制代码
purchase, supplier, contract, requisition, approval, inventory

功能模块示例:

复制代码
login, dashboard, settings, report, notification, workflow

其他:

arduino 复制代码
config, build, ci, docs, deps

💡 Scope 应根据实际业务场景命名,上述仅为示例。建议团队内部统一约定常用的 scope 列表。

Subject 主题
  • ✅ 使用中文描述
  • ✅ 使用动词开头,现在时态(如:新增、修复、优化)
  • 首字母小写
  • 不超过 50 个字符
  • 结尾不加句号

可选字段

Body 正文

对于复杂的提交,使用多行 body 详细说明:

  • 说明修改的原因和背景
  • 描述具体实现的功能点
  • 列出重要的技术细节

格式: 与 subject 之间空一行

bash 复制代码
feat(wormhole): 新增 Swagger API 自动生成功能

实现了从 Swagger 文档自动生成 API 代码的功能,包括:
- 自动解析 Swagger/OpenAPI 文档
- 生成 TypeScript 类型定义
- 生成 API 函数代码
- 自动生成 Mock 数据
- 支持 Alova 实例自动检测

该功能可大幅提高 API 接口对接效率,减少手写重复代码。

用于关联 Issue 或标记破坏性变更:

关联 Issue:

bash 复制代码
fix(router): 修复路由缓存失效问题

修复了在特定场景下路由缓存失效的问题。

Closes #123
Fixes #456

破坏性变更 (Breaking Changes):

bash 复制代码
feat(api): 重构 API 请求接口

重构了整个 API 请求模块,采用新的 Alova 实例创建方式。

BREAKING CHANGE: createAppAlova 方法签名已更改。
旧版本: createAppAlova(baseURL, timeout)
新版本: createAppAlova({ baseURL, timeout, ...options })

迁移指南:将所有 createAppAlova 调用更新为对象参数形式。

提交示例

✅ 正例

bash 复制代码
# 新功能
feat(purchase): 新增采购申请单批量审批功能
feat(supplier): 实现供应商信息批量导入功能
feat(contract): 新增合同电子签章功能
feat(requisition): 新增请购单高级搜索筛选条件

# Bug 修复
fix(login): 修复登录失败后跳转错误
fix(approval): 修复审批流程状态更新失败的问题
fix(inventory): 修复库存数量显示不正确的问题
fix(notification): 修复消息通知未实时更新的问题

# 文档更新
docs(readme): 更新项目安装说明
docs(api): 补充采购单接口调用文档
docs(workflow): 完善审批流程配置说明

# 代码格式
style(supplier): 格式化供应商模块代码
style(dashboard): 调整仪表盘组件导入顺序

# 重构
refactor(approval): 重构审批流程逻辑
refactor(purchase): 优化采购单查询流程

# 性能优化
perf(dashboard): 优化仪表盘数据加载性能
perf(requisition): 减少请购单列表查询时间

# 测试
test(contract): 添加合同创建流程单元测试
test(approval): 补充审批功能测试用例

# 构建/工具
chore(vite): 更新 Vite 构建配置
chore(deps): 升级 Vue 到 3.4.0
chore(eslint): 调整 ESLint 规则配置

# 回滚
revert(approval): 回滚审批流程优化提交

回滚提交 a1b2c3d,该优化导致某些场景下审批失败。

❌ 反例

bash 复制代码
# 缺少 type
(purchase): 新增采购申请单
purchase: 新增采购申请单

# 缺少 scope
feat: 新增采购申请单
fix: 修复问题

# scope 使用大写或驼峰
feat(Purchase): 新增采购申请单
feat(purchaseOrder): 新增采购申请单

# 使用英文主题(应使用中文)
feat(purchase): add purchase order
fix(supplier): fix supplier bug

# 主题过长(超过 50 字符)
feat(purchase): 新增采购管理功能包括采购申请、采购审批、采购执行、采购统计等完整功能

# 结尾加句号
feat(purchase): 新增采购申请单。

# 主题不清晰
feat(purchase): 更新代码
fix(supplier): 修复问题
chore: 更新

Git 常用操作

1. 查看状态和历史

bash 复制代码
# 查看当前状态
git status

# 查看提交历史(推荐)
git log --oneline --graph --decorate

# 查看某个文件的提交历史
git log --follow -- src/views/purchase/index.vue

# 按作者过滤
git log --author="张三"

# 按模块过滤
git log --grep="purchase"

2. 提交代码

bash 复制代码
# 添加所有修改的文件
git add .

# 添加指定文件
git add src/views/purchase/index.vue

# 提交代码
git commit -m "feat(purchase): 新增采购申请单列表"

# 查看提交结果
git log -1

3. 分支操作

bash 复制代码
# 查看所有分支
git branch -a

# 创建并切换到新分支
git checkout -b feature/purchase-list

# 切换分支
git checkout develop

# 删除本地分支
git branch -d feature/purchase-list

4. 同步代码

bash 复制代码
# 拉取远程最新代码
git pull origin develop

# 推送到远程
git push origin feature/purchase-list

# 第一次推送(关联远程分支)
git push -u origin feature/purchase-list

5. 暂存修改

使用场景: 临时切换分支但不想提交当前修改

bash 复制代码
# 暂存当前修改
git stash save "采购单开发进行中"

# 查看暂存列表
git stash list

# 恢复暂存(保留暂存记录)
git stash apply

# 恢复暂存(删除暂存记录)
git stash pop

6. 查看差异

bash 复制代码
# 查看工作区修改
git diff

# 查看已暂存的修改
git diff --cached

# 查看两个分支的差异
git diff develop feature/purchase-list

7. 撤销和回退(本地未推送)

使用场景: 本地修改错了或提交错了,想要撤销

bash 复制代码
# 撤销工作区的修改
git checkout -- src/views/purchase/index.vue

# 撤销暂存区的修改(保留工作区修改)
git reset HEAD src/views/purchase/index.vue

# 回退到上一个提交(保留修改)
git reset --soft HEAD^

# 回退到上一个提交(丢弃修改)
git reset --hard HEAD^

# 回退到指定提交
git reset --hard a1b2c3d

⚠️ 注意: reset 会改变提交历史,只能在本地未推送时使用

8. 恢复误删(reflog)

使用场景: 误删了分支或回退过头了

bash 复制代码
# 第1步:查看所有操作记录
git reflog

# 第2步:找到想要恢复的提交,比如 d4e5f6g

# 第3步:恢复到那个提交
git reset --hard d4e5f6g

# 或者创建新分支指向那个提交
git checkout -b recovered-branch d4e5f6g

9. 合并分支(merge)

使用场景: 将一个分支的修改合并到当前分支

bash 复制代码
# 合并指定分支到当前分支
git merge feature/purchase-list

# 合并但不自动提交(可以先检查)
git merge feature/purchase-list --no-commit

# 放弃合并
git merge --abort

示例: 功能开发完成后,将 feature 分支合并到 develop 分支

10. 解决冲突

使用场景: 合并或拉取代码时出现冲突

bash 复制代码
# 第1步:查看冲突文件
git status

# 第2步:手动编辑冲突文件,解决冲突标记
# <<<<<<< HEAD
# 当前分支的内容
# =======
# 要合并进来的内容
# >>>>>>> feature/purchase-list

# 第3步:标记冲突已解决
git add src/views/purchase/index.vue

# 第4步:完成合并
git commit  # 如果是 merge
git rebase --continue  # 如果是 rebase
git cherry-pick --continue  # 如果是 cherry-pick

提示: 使用 VSCode 等编辑器可以更方便地解决冲突

11. 挑选提交(cherry-pick)

使用场景: 需要把某个分支的特定提交应用到当前分支

bash 复制代码
# 将某个提交应用到当前分支
git cherry-pick a1b2c3d

# 挑选多个提交
git cherry-pick a1b2c3d e4f5g6h

# 挑选提交范围(不包含 start)
git cherry-pick start..end

# 挑选时发生冲突,解决后继续
git cherry-pick --continue

# 放弃挑选
git cherry-pick --abort

示例: 在 feature 分支修复了一个 bug,现在需要把这个修复应用到 master 分支

12. 反向提交(revert)

使用场景: 已经推送到远程的提交需要撤销

bash 复制代码
# 创建一个反向提交来撤销某次提交(推荐,不改变历史)
git revert a1b2c3d

# 反向提交但不自动提交(可以修改提交信息)
git revert a1b2c3d --no-commit

# 撤销合并提交
git revert -m 1 a1b2c3d  # -m 1 表示保留第一个父节点

示例: 某个功能提交后发现有问题,但已经推送到远程,使用 revert 创建一个新提交来撤销

13. 标签管理

使用场景: 版本发布时打标签,方便版本管理

bash 复制代码
# 查看所有标签
git tag

# 创建标签
git tag v1.0.0

# 创建带说明的标签
git tag -a v1.0.0 -m "发布 1.0.0 版本"

# 给指定提交打标签
git tag v1.0.0 a1b2c3d

# 推送标签到远程
git push origin v1.0.0

# 推送所有标签
git push origin --tags

# 删除本地标签
git tag -d v1.0.0

# 删除远程标签
git push origin --delete v1.0.0

14. 文件修改追溯(blame)

使用场景: 追溯某行代码是谁写的,什么时候写的

bash 复制代码
# 查看文件每行的最后修改记录
git blame src/views/purchase/index.vue

# 查看指定行范围
git blame -L 10,20 src/views/purchase/index.vue

# 查看详细信息(显示邮箱)
git blame -e src/views/purchase/index.vue

# 配合 show 查看完整提交
git show a1b2c3d

技巧: 在 VSCode 中安装 GitLens 插件,鼠标悬停在代码行上即可看到提交信息

15. 清理操作

使用场景: 清理本地无用的分支和文件

bash 复制代码
# 查看远程已删除但本地还存在的分支
git remote prune origin --dry-run

# 删除远程已删除的本地分支
git remote prune origin

# 删除已合并的本地分支
git branch --merged | grep -v "master\|develop" | xargs git branch -d

# 清理未跟踪的文件(谨慎使用)
git clean -fd

# 查看会删除哪些文件(不实际删除)
git clean -fd --dry-run

示例: 远程分支已经删除,但本地还有很多旧分支,用 prune 清理

常见问题

Q1: 如何选择合适的 type?

原则: 根据修改的主要内容选择:

  • 新增功能 → feat
  • 修复 Bug → fix
  • 更新文档 → docs
  • 调整格式 → style
  • 重构代码 → refactor
  • 性能优化 → perf
  • 测试相关 → test
  • 构建/配置 → chore

判断技巧:

  • 如果用户能感知到变化 → feat 或 fix
  • 如果只是内部优化 → refactor 或 perf
  • 如果只改格式不改逻辑 → style
  • 如果改配置/依赖 → chore

Q2: scope 应该写多详细?

建议: 使用顶层模块名即可,不要过于详细:

bash 复制代码
# ✅ 推荐
feat(purchase): 新增采购申请单审批

# ❌ 过于详细
feat(purchase/approval): 新增采购申请单审批
feat(src/views/purchase/approval): 新增采购申请单审批

特殊情况: 如果修改影响多个模块,可以选择:

bash 复制代码
# 方案 1: 使用多个 scope
feat(purchase,approval): 新增采购申请和审批功能

# 方案 2: 使用更通用的 scope
feat(system): 新增系统核心功能

# 方案 3: 省略 scope(不推荐)
feat: 新增核心功能

Q3: 什么时候需要写 body?

需要 body 的情况:

  • 复杂功能,需要说明实现细节
  • 破坏性变更,需要说明迁移方法
  • 重大重构,需要说明原因和影响

不需要 body 的情况:

  • 简单的功能新增
  • 明显的 Bug 修复
  • 文档更新
  • 代码格式调整

Q4: 代码冲突了怎么办?

场景: 合并代码或拉取代码时出现冲突

bash 复制代码
# 第1步:查看冲突的文件
git status

# 第2步:手动编辑冲突文件,解决冲突标记
# <<<<<<< HEAD
# 你的修改
# =======
# 别人的修改
# >>>>>>> feature/purchase-list

# 第3步:标记冲突已解决
git add src/views/purchase/index.vue

# 第4步:继续合并
git commit  # 如果是 merge
git rebase --continue  # 如果是 rebase
git cherry-pick --continue  # 如果是 cherry-pick

技巧:

  • 使用 VSCode,可以点击"接受当前更改"/"接受传入更改"快速解决
  • 不确定时可以先 git merge --abort 取消合并,询问同事后再操作

Q5: 如何撤销已合并的分支?

场景: master 由 feat-a 和 feat-b 合并而成,现在不想要 feat-a 的功能

方法一:使用 revert(推荐,适合已推送到远程)

bash 复制代码
# 第1步:查看合并历史
git log --oneline --graph

# 输出类似:
# d4e5f6 (HEAD -> master) Merge branch 'feat-b'
# a1b2c3 Merge branch 'feat-a'  ← 要撤销这个合并

# 第2步:撤销 feat-a 的合并提交
git revert -m 1 a1b2c3

# -m 1 的含义:
# 合并提交有两个父节点,1 是 master,2 是 feat-a
# -m 1 表示保留 master 的内容,撤销 feat-a 的内容

# 第3步:推送到远程
git push origin master

方法二:使用 reset(只适合本地未推送)

bash 复制代码
# 第1步:找到合并 feat-a 之前的提交
git log --oneline
# 找到 feat-a 合并之前的 commit hash,比如 xyz789

# 第2步:回退到那个提交
git reset --hard xyz789

# 第3步:重新合并 feat-b
git merge feat-b

选择建议:

  • master 已推送到远程,团队成员在使用 → 用 revert
  • 只在本地操作,还没推送 → 用 reset

Q6: 误删了分支/提交怎么恢复?

场景: 不小心删除了分支或回退过头了

bash 复制代码
# 第1步:查看所有操作记录
git reflog

# 输出类似:
# a1b2c3d HEAD@{0}: reset: moving to HEAD^
# d4e5f6g HEAD@{1}: commit: feat(purchase): 新增采购单
# h7i8j9k HEAD@{2}: commit: fix(supplier): 修复供应商

# 第2步:找到想要恢复的提交,比如 d4e5f6g

# 第3步:恢复到那个提交
git reset --hard d4e5f6g

# 或者创建新分支指向那个提交
git checkout -b recovered-branch d4e5f6g

Q7: 如何临时切换分支但不想提交当前修改?

场景: 正在开发功能,突然需要切换到别的分支修 bug,但当前代码还不想提交

使用 stash(推荐)

bash 复制代码
# 第1步:暂存当前修改
git stash save "采购单开发进行中"

# 第2步:切换到其他分支
git checkout hotfix/urgent-bug

# 第3步:修完 bug 后,切回原分支
git checkout feature/purchase-list

# 第4步:恢复之前的修改
git stash pop

Q8: 如何挑选特定的多个提交?

场景: master 分支有 10 次提交,想把其中的第 1、3、5、7、9 次提交抽出来

bash 复制代码
# 第1步:查看提交历史,找到对应的 commit hash
git log --oneline master

# 假设输出:
# j10 第10次提交
# i9  第9次提交  ← 要
# h8  第8次提交
# g7  第7次提交  ← 要
# f6  第6次提交
# e5  第5次提交  ← 要
# d4  第4次提交
# c3  第3次提交  ← 要
# b2  第2次提交
# a1  第1次提交  ← 要

# 第2步:创建新分支(或切换到目标分支)
git checkout -b selected-commits

# 第3步:挑选这些提交
git cherry-pick a1 c3 e5 g7 i9

Q9: merge 和 rebase 的区别?

merge(合并):

bash 复制代码
git checkout develop
git merge feature/purchase-list

# 结果:保留所有提交历史,产生一个合并提交
# develop: A - B - C - M (merge commit)
#                    /
# feature:      D - E

rebase(变基):

bash 复制代码
git checkout feature/purchase-list
git rebase develop

# 结果:将 feature 的提交"移动"到 develop 最新提交之后
# develop: A - B - C - D' - E'

选择建议:

  • 公共分支(develop、master)→ 用 merge(保留完整历史)
  • 个人分支整理提交 → 用 rebase(保持线性历史)
  • 已经推送到远程的分支 → 不要用 rebase(会造成冲突)

Q10: pull 和 fetch 的区别?

区别:

bash 复制代码
# fetch: 只下载远程代码,不合并
git fetch origin develop

# 此时可以先查看差异
git diff develop origin/develop

# 确认没问题后再手动合并
git merge origin/develop

# pull: 下载并自动合并(相当于 fetch + merge)
git pull origin develop

推荐用法:

  • 不确定远程有什么改动 → 先用 git fetch,查看后再合并
  • 确定可以直接合并 → 用 git pull

Q11: 如何修改历史提交信息?

场景: 最近几次提交的信息写错了,想批量修改

bash 复制代码
# 修改最近 3 次提交
git rebase -i HEAD~3

# 会打开编辑器,显示:
# pick a1b2c3d feat(purchase): 新增采购单
# pick d4e5f6g fix(supplier): 修复供应商
# pick h7i8j9k docs(readme): 更新文档

# 将要修改的提交的 pick 改为 reword:
# reword a1b2c3d feat(purchase): 新增采购单
# pick d4e5f6g fix(supplier): 修复供应商
# pick h7i8j9k docs(readme): 更新文档

# 保存后,会依次让你修改每个标记为 reword 的提交信息

⚠️ 注意: 只能修改未推送到远程的提交,否则会造成历史冲突

相关文档

相关推荐
星秀日7 小时前
JavaWeb--Ajax
前端·javascript·ajax
4_0_47 小时前
全栈视角:从零构建一个现代化的 Todo 应用
前端·node.js
BumBle8 小时前
uniapp 用css实现圆形进度条组件
前端·vue.js·uni-app
杏花春雨江南8 小时前
npm error Could not resolve dependency:
前端·npm·node.js
嫂子的姐夫8 小时前
10-七麦js扣代码
前端·javascript·爬虫·python·node.js·网络爬虫
Komorebi_99998 小时前
Vue3 + TypeScript provide/inject 小白学习笔记
前端·javascript·vue.js
少吃一口都不行8 小时前
脚手架学习
前端·javascript·学习
地方地方8 小时前
手写JavaScript 深拷贝
前端·javascript
yeyuningzi8 小时前
npm升级提示error engine not compatible with your version of node/npm: npm@11.6.2
前端·npm·node.js