name: nop-git-master description: Nop项目Git专家 - 智能提交、Rebase、历史搜索(基于项目风格固化)
我会做什么
基于Nop项目实际提交历史调研的全功能Git专家:
- 智能提交:自动拆分commits,符合项目风格
- Rebase管理:历史清理、squash、conflict解决
- 历史搜索:查找代码变更、作者、引入时间
- 提交验证:构建测试、代码检查
什么时候用我
更新/同步/pull- 同步远程最新代码提交修改/commit- 智能提交(自动拆分)rebase/squash/清理历史- 历史管理查找/谁写的/什么时候引入- 历史搜索
MODE DETECTION
| 用户请求 | 模式 |
|---|---|
| "更新"、"同步"、"pull"、"最新" | SYNC |
| "提交"、"commit"、"改动" | COMMIT |
| "rebase"、"squash"、"清理历史" | REBASE |
| "查找"、"谁"、"什么时候"、"blame" | HISTORY_SEARCH |
ENVIRONMENT DETECTION
每个模式开始前,必须先检测仓库类型和默认分支:
# 检测当前是否在 worktree 中
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
if echo "$GIT_DIR" | grep -q "worktrees/"; then
REPO_TYPE="worktree"
else
REPO_TYPE="regular"
fi
# 获取当前分支名
CURRENT_BRANCH=$(git branch --show-current)
# 检测默认分支名(main 或 master)
DEFAULT_BRANCH=$(git remote show origin 2>/dev/null | grep 'HEAD branch' | awk '{print $NF}')
if [ -z "$DEFAULT_BRANCH" ]; then
DEFAULT_BRANCH=$(git rev-parse --verify main 2>/dev/null && echo main || echo master)
fi
| REPO_TYPE | 含义 | SYNC 行为 | REBASE 行为 |
|---|---|---|---|
worktree |
bare + worktree 架构 | refspec fetch + pull --ff-only |
在 worktree 内 rebase |
regular |
普通仓库 | refspec fetch + pull --ff-only |
直接 rebase |
注意:下文中所有 master 均应替换为 $DEFAULT_BRANCH 变量。
SYNC MODE
核心原则
- 永不使用
reset --hard做同步 — 它会丢弃未推送的提交,无论仓库类型 - 先用
git ls-remote无缓存检查远程状态 - 用强制 refspec fetch 更新
origin/$BRANCH - 用
pull --ff-only安全同步 — 如果有未推送的提交会拒绝,不会丢弃
为什么 reset --hard 禁止用于 SYNC?
场景:本地有 3 个未推送的 commit,远程也有 2 个新 commit
❌ reset --hard $REMOTE_SHA → 本地 3 个 commit 被丢弃!
✅ pull --ff-only → 拒绝,提示需要先 push 或 rebase
即使本地没有未推送的提交,reset --hard 也是危险的:如果 ls-remote 和 fetch 之间远程有新提交,可能 reset 到非最新状态。
标准流程(强制)
⚠️ 关键顺序:必须先 fetch 更新 origin/$BRANCH,再检查未推送提交。origin/$BRANCH 可能过期,用它检查会误报。
# 0. 环境检测
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
CURRENT_BRANCH=$(git branch --show-current)
echo "Branch: $CURRENT_BRANCH, Repo: $(echo $GIT_DIR | grep -q 'worktrees/' && echo 'worktree' || echo 'regular')"
# 1. 获取远程真实 SHA(无缓存)
REMOTE_SHA=$(git ls-remote origin "$CURRENT_BRANCH" | awk '{print $1}')
if [ -z "$REMOTE_SHA" ]; then
echo "❌ 远程分支 $CURRENT_BRANCH 不存在"
exit 1
fi
# 2. 获取本地 SHA
LOCAL_SHA=$(git rev-parse HEAD)
echo "Remote: $REMOTE_SHA"
echo "Local: $LOCAL_SHA"
# 3. 对比
if [ "$REMOTE_SHA" = "$LOCAL_SHA" ]; then
echo "✅ 已是最新: $(git log --oneline -1)"
else
# 4. 先强制更新远程跟踪分支(必须在检查未推送之前!)
# 原因:origin/$BRANCH 可能过期,用它检查未推送会误报
git fetch origin "+refs/heads/$CURRENT_BRANCH:refs/remotes/origin/$CURRENT_BRANCH"
# 5. 用更新后的 origin/$BRANCH 检查本地是否有未推送的提交
UNPUSHED=$(git log --oneline "origin/$CURRENT_BRANCH..HEAD" 2>/dev/null)
if [ -n "$UNPUSHED" ]; then
echo "⚠️ 本地有未推送的提交:"
echo "$UNPUSHED"
echo ""
echo "请先 push 或 rebase,不要用 SYNC 强制覆盖。"
exit 1
fi
# 6. 安全同步
git pull --ff-only origin "$CURRENT_BRANCH"
git log --oneline -3
fi
为什么必须用强制 refspec fetch?
# ❌ 不可靠:可能只更新 FETCH_HEAD,不更新 refs/remotes/origin/$BRANCH
git fetch origin
git fetch origin $REMOTE_SHA
# ✅ 可靠:显式映射远程分支到本地 remote ref
git fetch origin "+refs/heads/$CURRENT_BRANCH:refs/remotes/origin/$CURRENT_BRANCH"
| 命令 | 更新 FETCH_HEAD | 更新 refs/remotes | 可靠性 |
|---|---|---|---|
git fetch origin |
✅ | ⚠️ 可能不更新 | ❌ |
git fetch origin $SHA |
✅ | ❌ 不更新 | ❌ |
git fetch origin +refs/heads/X:refs/remotes/origin/X |
✅ | ✅ 强制更新 | ✅ |
为什么必须用 git ls-remote 先检查?
| 命令 | 是否使用缓存 | 可靠性 |
|---|---|---|
git fetch |
✅ 是(refs 可能过期) | ❌ 不可靠 |
git pull |
✅ 是(依赖 fetch) | ❌ 不可靠 |
git ls-remote |
❌ 否(直接查询远程) | ✅ 可靠 |
特殊情况
有未提交的工作目录修改
# 选项1:stash 暂存
git stash
# 执行同步...
git stash pop
# 选项2:commit 提交
git add -A && git commit -m "WIP"
# 选项3:放弃修改(确认后)
git checkout -- .
git clean -fd
有未推送的提交
SYNC 拒绝执行,提示用户选择:
# 选项1:先 push 再 sync
git push origin $CURRENT_BRANCH
# 选项2:用 rebase 合并远程变更
git fetch origin "+refs/heads/$CURRENT_BRANCH:refs/remotes/origin/$CURRENT_BRANCH"
git rebase "origin/$CURRENT_BRANCH"
# 选项3:确认丢弃(必须向用户确认)
# ⚠️ 仅在用户明确确认后执行
git reset --hard "origin/$CURRENT_BRANCH"
COMMIT MODE
固定的提交风格(基于项目调研)
语言: 中文为主(87%),技术术语用英文
格式: 语义化提交 type(scope): 描述
类型分布:
feat(40%) - 新功能docs(15%) - 文档refactor(15%) - 重构test(10%) - 测试fix(10%) - Bug修复chore(8%) - 构建/工具perf(2%) - 性能
作用域规则:
- 小写模块名:
sys,cluster,orm,gateway,graphql,config,ai - 多作用域逗号分隔(无空格):
feat(sys,cluster): - 可选:单文件或全局改动可省略scope
正文格式:
type(scope): 简短描述(20字以内)
- 具体变更1(动词+对象)
- 具体变更2
- 具体变更3(典型3-6项)
[可选] Co-authored-by: Name <email>
智能提交拆分规则
拆分原则(简化版)
核心原则:按逻辑分组,一个commit只做一件事
1. 不同模块 → 不同commit(最高优先级)
- nop-sys的变更不和nop-cluster混在一起
- nop-orm的变更不和nop-gateway混在一起
2. 同一模块内按功能分组
- 数据库schema变更单独commit
- API接口变更单独commit
- 配置变更单独commit
- 文档变更单独commit
3. 测试和实现在同一commit
拆分维度(优先级从高到低)
1. 按模块拆分(Primary)
Nop项目模块结构:
nop-sys/ # 系统模块
├─ api/ # API接口定义
├─ dao/ # 数据访问层
├─ service/ # 业务逻辑层
├─ web/ # Web控制器
├─ meta/ # 元数据定义
└─ codegen/ # 代码生成
nop-cluster/ # 集群模块
nop-orm/ # ORM模块
nop-gateway/ # 网关模块
...
规则:不同模块 → 不同commit
示例:8个文件修改
- nop-sys/api/IService.java
- nop-sys/dao/ServiceDao.java
- nop-cluster/api/INaming.java
- nop-cluster/service/NamingService.java
- docs/guide.md
- README.md
❌ 错误:1个commit "更新系统"
❌ 错误:2个commit(太少)
✅ 正确:4个commit
1. feat(sys): 增强服务接口
- nop-sys/api/IService.java
- nop-sys/dao/ServiceDao.java
2. feat(cluster): 增强命名服务
- nop-cluster/api/INaming.java
- nop-cluster/service/NamingService.java
3. docs: 更新开发指南
- docs/guide.md
4. docs: 更新README
- README.md
2. 按层级拆分(Secondary)
同一模块内,按层级拆分:
优先级:api → dao → service → web → meta
示例:nop-auth模块有5个文件
1. feat(auth): 添加认证API接口
- api/AuthApi.java
2. feat(auth): 实现认证数据访问
- dao/AuthDao.java
3. feat(auth): 实现认证业务逻辑
- service/AuthService.java
4. feat(auth): 添加认证Web接口
- web/AuthController.java
3. 按关注点拆分(Tertiary)
- 实现代码 vs 测试代码(通常同一commit)
- 功能代码 vs 配置文件(不同commit)
- 源代码 vs 文档(不同commit)
必须合并的情况
测试+实现必须在同一commit:
✅ 正确:
feat(orm): 添加CRUD业务接口
- 新增 ICrudBizModel 接口定义
- 实现 CrudBizModel 基础功能
- 添加单元测试覆盖
包含:
- orm/src/main/java/CrudBizModel.java
- orm/src/test/java/TestCrudBizModel.java
拆分验证(简化版)
执行commits前输出计划即可:
COMMIT PLAN
===========
Files changed: 8 | Planned commits: 4
COMMIT 1: feat(sys): 增强服务注册功能
- nop-sys/api/IServiceInstance.java
- nop-sys/dao/ServiceInstanceDao.java
Justification: 同一功能
COMMIT 2: feat(cluster): 增强集群发现机制
- nop-cluster/service/DiscoveryService.java
Justification: 不同模块
COMMIT 3: docs: 更新文档
- docs/cluster-setup.md
Justification: 文档独立提交
提交流程(零冗余)
# 1. 并行收集信息(一次性)
git status && git diff --staged --stat && git diff --stat
# 2. 生成commit plan(必须输出)
# 3. 执行commits(按依赖顺序)
for each commit:
git add <files>
git commit -m "type(scope): 描述" -m "- 变更1" -m "- 变更2"
# 4. 最终验证(一次)
git status
Commit消息增强规则
正文详细程度要求
单行commit(仅限1-2个文件):
fix(typo): 修正拼写错误
标准commit(3-5个文件,必须3+项):
feat(sys): 增强服务注册功能
- 新增groupName和clusterName配置项
- AutoRegistration支持自动注册到指定分组
- SysDaoNamingService实现按组过滤服务实例
- 服务发现增加clusterName匹配逻辑
大型commit(5+文件或重要变更,必须5+项):
feat(sys,cluster): 升级版本字段类型并增强集群功能
- 将所有nop-sys表的VERSION字段从INTEGER升级为BIGINT以支持更大范围
- ZoneServiceInstanceFilter增加clusterName匹配逻辑
- 服务注册配置增加clusterName属性支持
- nop_sys_service_instance表的tags_text字段改为可空
- ORM代码生成配置从xlsx改为xml格式
- 更新相关文档说明
必须详细说明的场景
1. 破坏性变更(BREAKING CHANGE)
feat(api): 重构用户认证接口
**BREAKING CHANGE:** 认证接口签名变更
- 旧版: AuthResult authenticate(String token)
- 新版: AuthResult authenticate(AuthRequest req)
- 迁移指南: 将token包装为AuthRequest对象
- 重构authenticate方法签名
- 增加AuthRequest请求对象
- 支持多种认证方式
- 添加迁移示例代码
2. 数据库变更
feat(orm): 修改用户表结构
**数据库变更:**
- 新增字段: user_phone VARCHAR(20)
- 修改字段: user_name VARCHAR(50) → VARCHAR(100)
- 索引优化: 添加idx_user_phone索引
- 迁移脚本: V2024.03.04__user_table_update.sql
- User实体新增phone属性
- 加长name字段长度
- 添加phone索引定义
3. 配置变更
feat(config): 重构数据库配置项
**配置变更:**
- 废弃: nop.db.url (使用nop.datasource.url替代)
- 新增: nop.datasource.* 系列配置
- 兼容性: 旧配置仍可用但会警告
- 新增DataSourceProperties配置类
- 支持多数据源配置
- 添加配置迁移提示
CHANGELOG.md更新规则
自动检测条件
必须更新CHANGELOG.md的情况:
用户可见的新功能
- 新增API接口
- 新增配置项
- 新增命令行参数
- 新增UI功能
破坏性变更
- API签名变更
- 配置项重命名/删除
- 数据库表结构变更
- 依赖版本升级(major)
重要的Bug修复
- 安全漏洞修复
- 数据丢失风险修复
- 性能问题修复
CHANGELOG.md格式
基于项目现有的CHANGELOG.md格式:
# 更新日志
## 特性 YYYY-MM-DD
* 新增XXX功能 (commit: abc1234)
* 增强YYY机制 (commit: def5678)
## 变更 YYYY-MM-DD
* **破坏性变更**: ZZZ接口重构,需要迁移 (commit: ghi9012)
* 重构AAA模块,提升性能 (commit: jkl3456)
## 修复 YYYY-MM-DD
* 修复BBB场景下的数据丢失问题 (commit: mno7890)
更新流程
# 1. 提交代码变更
git add <files>
git commit -m "feat(xxx): 描述"
# 2. 检查是否需要更新CHANGELOG
# 如果是用户可见变更,添加CHANGELOG条目
# 3. 更新CHANGELOG.md(如果需要)
# 在当前日期下添加条目
# 4. 提交CHANGELOG更新
git add CHANGELOG.md
git commit -m "docs: 更新CHANGELOG"
CHANGELOG条目模板
新功能:
## 特性 2024-03-04
* 新增nop.cluster.name配置项,支持物理机房隔离 (commit: abc1234)
* 增强服务注册功能,支持groupName和clusterName (commit: def5678)
破坏性变更:
## 变更 2024-03-04
* **破坏性变更**: 重构认证接口,旧版token参数不再支持,需使用AuthRequest对象 (commit: ghi9012)
- 迁移指南: 将 `authenticate(token)` 改为 `authenticate(new AuthRequest(token))`
重要修复:
## 修复 2024-03-04
* 修复分布式事务在超时场景下的数据不一致问题 (commit: jkl3456)
不兼容变更检测清单
在提交前检查以下项,如果命中任意一条,必须更新CHANGELOG.md并添加BREAKING CHANGE说明:
API层
- 修改了public/protected方法签名
- 删除了public/protected方法
- 修改了返回值类型
- 修改了参数类型或顺序
- 新增了必填参数
配置层
- 删除了配置项
- 重命名了配置项
- 修改了配置项的默认值
- 修改了配置项的格式
数据层
- 删除了数据库表
- 删除了表字段
- 修改了字段类型(不兼容)
- 删除了索引
- 修改了主键
依赖层
- 升级了major版本的依赖
- 删除了依赖(可能导致编译失败)
- 修改了依赖的scope
行为层
- 修改了默认行为
- 修改了错误处理方式
- 修改了日志级别或格式
- 修改了性能特性(可能影响现有系统)
如果以上任意一项命中:
- ✅ 在commit message中添加
**BREAKING CHANGE:**说明 - ✅ 更新CHANGELOG.md,添加迁移指南
- ✅ 如果可能,提供兼容层或迁移脚本
示例输出:
⚠️ 检测到破坏性变更:
- API签名变更: authenticate(String) → authenticate(AuthRequest)
✅ 已执行:
1. Commit message包含BREAKING CHANGE说明
2. CHANGELOG.md已更新(包含迁移指南)
3. 提供了迁移示例代码
REBASE MODE
安全评估
# 并行收集信息
git branch --show-current
git log --oneline -20
MERGE_BASE=$(git merge-base HEAD "$DEFAULT_BRANCH" 2>/dev/null || git merge-base HEAD master)
git rev-parse --abbrev-ref @{upstream} 2>/dev/null || echo "NO_UPSTREAM"
git status --porcelain
风险评估:
| 条件 | 风险 | 动作 |
|---|---|---|
| 在main/master上 | 🔴 CRITICAL | 禁止rebase |
| 工作目录脏 | 🟡 WARNING | 先stash |
| 已push的commits | 🟡 WARNING | 需要force-push |
| 全部commits本地 | 🟢 SAFE | 自由操作 |
Rebase策略
1. Interactive Squash(合并commits)
# 合并所有commits为一个
MERGE_BASE=$(git merge-base HEAD "$DEFAULT_BRANCH" 2>/dev/null)
git reset --soft $MERGE_BASE
git commit -m "feat(module): 合并描述"
2. Autosquash(应用fixups)
MERGE_BASE=$(git merge-base HEAD "$DEFAULT_BRANCH" 2>/dev/null)
GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash $MERGE_BASE
3. Rebase Onto(更新分支)
# 强制更新远程跟踪分支(不用 git fetch origin,它可能不更新 refs/remotes)
git fetch origin "+refs/heads/$DEFAULT_BRANCH:refs/remotes/origin/$DEFAULT_BRANCH"
git rebase "origin/$DEFAULT_BRANCH"
冲突解决
CONFLICT → 工作流:
1. 识别冲突文件:
git status | grep "both modified"
2. 解决每个冲突:
- 阅读文件内容
- 理解两个版本(HEAD vs incoming)
- 编辑文件解决冲突
- 移除冲突标记(<<<<, ====, >>>>)
3. 暂存解决后的文件:
git add <resolved-file>
4. 继续rebase:
git rebase --continue
5. 如果卡住:
git rebase --abort # 安全回滚
Push策略
IF 从未push过:
-> git push -u origin <branch>
IF 已经push过:
-> git push --force-with-lease origin <branch>
-> ⚠️ 必须用 --force-with-lease(不是--force)
HISTORY SEARCH MODE
搜索类型识别
| 用户请求 | 搜索类型 | 工具 |
|---|---|---|
| "什么时候添加X" | PICKAXE | git log -S |
| "查找改变X模式的commits" | REGEX | git log -G |
| "谁写了这行" | BLAME | git blame |
| "bug什么时候开始" | BISECT | git bisect |
| "文件历史" | FILE_LOG | git log -- path |
搜索命令
1. Pickaxe Search(查找字符串添加/删除)
# 基础:查找字符串何时添加/删除
git log -S "searchString" --oneline
# 带上下文(查看实际变更):
git log -S "searchString" -p
# 在特定文件中:
git log -S "searchString" -- path/to/file.java
# 跨所有分支(查找已删除代码):
git log -S "searchString" --all --oneline
# 示例:
git log -S "def calculate_discount" --oneline
git log -S "MAX_RETRY_COUNT" --all --oneline
2. Regex Search(正则匹配)
# 查找匹配模式的commits
git log -G "pattern.*regex" --oneline
# 查找函数定义变更
git log -G "def\s+my_function" --oneline -p
# -S vs -G区别:
# -S "foo": 查找"foo"数量改变的commits
# -G "foo": 查找diff中包含"foo"的commits
3. Git Blame(逐行归属)
# 基础blame
git blame path/to/file.java
# 特定行范围
git blame -L 10,20 path/to/file.java
# 显示原始commit(忽略移动/复制)
git blame -C path/to/file.java
# 输出格式:
# ^abc1234 (Author 2024-01-15 10:30 +0900 42) code_line
4. Git Bisect(二分查找bug)
# 开始bisect会话
git bisect start
git bisect bad # 当前(坏)状态
git bisect good v1.0.0 # 已知好状态
# Git会checkout中间commit,测试后:
git bisect good # 如果这个commit正常
git bisect bad # 如果这个commit有问题
# 重复直到找到culprit commit
# Git会输出:"abc1234 is the first bad commit"
# 完成后返回原状态
git bisect reset
5. 文件历史追踪
# 文件完整历史
git log --oneline -- path/to/file.java
# 跟踪文件重命名
git log --follow --oneline -- path/to/file.java
# 显示实际变更
git log -p -- path/to/file.java
结果展示
SEARCH QUERY: "什么时候添加calculate_discount函数"
SEARCH TYPE: PICKAXE
COMMAND: git log -S "calculate_discount" --oneline
RESULTS:
Commit Date Message
--------- -------- --------------------------------
abc1234 2024-06-15 feat(order): 添加折扣计算功能
def5678 2024-05-20 refactor: 提取定价逻辑
MOST RELEVANT: abc1234
DETAILS:
Author: John Doe <john@example.com>
Date: 2024-06-15
Files changed: 3
DIFF:
+ def calculate_discount(price, rate):
+ return price * (1 - rate)
ACTIONS:
- 查看完整commit: git show abc1234
- 回退此commit: git revert abc1234
- Cherry-pick到其他分支: git cherry-pick abc1234
提交后验证
自动验证流程
# 提交后立即运行(如果修改了Java代码)
git status # 确认工作目录干净
git log --oneline -5 # 查看最新提交
# 如果修改了pom.xml或Java代码:
mvn clean install -DskipTests -T 1C
# 如果只修改了文档/配置:跳过构建
验证清单:
- 工作目录干净(
git status无未提交文件) - Commit历史正确(
git log --oneline -10) - 每个commit可独立回退
- 构建成功(如果修改了代码)
- 测试通过(如果存在测试)
快速参考
Commit消息速查
feat(sys): 添加新功能
fix(cluster): 修复bug
docs: 更新文档
refactor(orm): 重构代码
test(gateway): 添加测试
chore: 构建配置
perf: 性能优化
同步速查
# 标准同步流程(安全:ls-remote → fetch → 检查未推送 → pull)
BRANCH=$(git branch --show-current) && \
REMOTE_SHA=$(git ls-remote origin "$BRANCH" | awk '{print $1}') && \
LOCAL_SHA=$(git rev-parse HEAD) && \
if [ "$REMOTE_SHA" = "$LOCAL_SHA" ]; then \
echo "✅ 已是最新: $(git log --oneline -1)"; \
else \
echo "⚠️ 更新中: $LOCAL_SHA → $REMOTE_SHA" && \
git fetch origin "+refs/heads/$BRANCH:refs/remotes/origin/$BRANCH" && \
UNPUSHED=$(git log --oneline "origin/$BRANCH..HEAD" 2>/dev/null) && \
if [ -n "$UNPUSHED" ]; then echo "⚠️ 本地有未推送提交,先 push 或 rebase"; exit 1; fi && \
git pull --ff-only origin "$BRANCH" && \
git log --oneline -3; \
fi
Rebase速查
# Squash所有commits
git reset --soft $(git merge-base HEAD "$DEFAULT_BRANCH") && git commit -m "..."
# Autosquash fixups
GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash $(git merge-base HEAD "$DEFAULT_BRANCH")
# 更新分支(强制 refspec fetch)
git fetch origin "+refs/heads/$DEFAULT_BRANCH:refs/remotes/origin/$DEFAULT_BRANCH" && git rebase "origin/$DEFAULT_BRANCH"
搜索速查
git log -S "string" --oneline # 何时添加/删除
git log -G "pattern" --oneline # 正则匹配
git blame -L 10,20 file.java # 谁写了这行
git log --follow -- path/file.java # 文件历史
反模式(AUTOMATIC FAILURE)
- 从不做单一大commit - 3+文件必须拆分
- 从不使用
--force- 必须用--force-with-lease - 从不rebase main/master - 永远禁止
- 从不分离实现和单元测试 - 必须同一commit
- 从不跳过COMMIT PLAN输出 - 必须验证拆分计划
- 从不使用模糊的分组理由 - "相关"不是理由
- SYNC时从不直接 pull/fetch - 必须先用
git ls-remote无缓存检查,再决定是否更新 - 从不信任本地 refs 缓存 -
origin/$BRANCH可能过期,检查未推送前必须先git fetch origin +refs/heads/$BRANCH:refs/remotes/origin/$BRANCH更新,否则会误报 - SYNC时从不使用
reset --hard- 会丢弃未推送的提交,用pull --ff-only代替 - 从不使用
git fetch origin $SHA- 不更新 refs/remotes,用git fetch origin +refs/heads/$BRANCH:refs/remotes/origin/$BRANCH代替
最终检查清单
COMMIT前:
- 文件数 → commit数:N files >= ceil(N/3) commits?
- 拆分计划:每个commit有justification?
- 模块拆分:不同模块 → 不同commits?
- 测试配对:单元测试和实现在同一commit?
- 依赖顺序:api → dao → service → web?
REBASE前:
- 不在main/master上?
- 工作目录干净(或已stash)?
- 了解force-push影响(如果已push)?
SYNC前:
- 用
git ls-remote获取远程真实 SHA? - 用强制 refspec fetch 更新了
origin/$BRANCH(在检查未推送之前)? - 用更新后的
origin/$BRANCH检查了是否有未推送的提交(git log origin/$BRANCH..HEAD)? - 使用
pull --ff-only而不是reset --hard? - 工作目录干净(或已处理未提交修改)?
提交后:
- 工作目录干净?
- 构建成功(如果修改了代码)?
- Commit消息符合风格?
- CHANGELOG已更新(如有破坏性变更/新功能/数据库变更)?