# Nop Git Master

> Nop项目Git专家 - 智能提交、Rebase、历史搜索（基于项目风格固化）

- Skill: `entropy-cloud/nop-git-master-3` (Agent Skill)
- Install (CLI): `npx skillmds@latest add entropy-cloud/nop-git-master-3`
- Raw SKILL.md: https://api.skillmd.com/api/skills/entropy-cloud/nop-git-master-3/raw
- Safety review: pending (external: skill-scanner PASS, skillspector CAUTION)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: entropy-cloud (https://skillmd.com/u/entropy-cloud)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/entropy-cloud/nop-git-master-3

---


## 我会做什么

基于Nop项目实际提交历史调研的**全功能Git专家**：

- **智能提交**：自动拆分commits，符合项目风格
- **Rebase管理**：历史清理、squash、conflict解决
- **历史搜索**：查找代码变更、作者、引入时间
- **提交验证**：构建测试、代码检查

## 什么时候用我

- `更新` / `同步` / `pull` - 同步远程最新代码
- `提交修改` / `commit` - 智能提交（自动拆分）
- `rebase` / `squash` / `清理历史` - 历史管理
- `查找` / `谁写的` / `什么时候引入` - 历史搜索

---

# MODE DETECTION

| 用户请求 | 模式 |
|---------|------|
| "更新"、"同步"、"pull"、"最新" | SYNC |
| "合并远程"、"merge"、"同步冲突"、"bundle合并" | MERGE_SYNC |
| "提交"、"commit"、"改动" | COMMIT |
| "rebase"、"squash"、"清理历史" | REBASE |
| "查找"、"谁"、"什么时候"、"blame" | HISTORY_SEARCH |

---

# ENVIRONMENT DETECTION

**每个模式开始前，必须先检测仓库类型和默认分支：**

```bash
# 检测当前是否在 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

## 核心原则

1. **永不使用 `reset --hard` 做同步** — 它会丢弃未推送的提交，无论仓库类型
2. **先用 `git ls-remote` 无缓存检查远程状态**
3. **用强制 refspec fetch 更新 `origin/$BRANCH`**
4. **用 `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` 可能过期，用它检查会误报。**

```bash
# 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？

```bash
# ❌ 不可靠：可能只更新 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` | ❌ 否（直接查询远程） | ✅ 可靠 |

## 特殊情况

### 有未提交的工作目录修改

```bash
# 选项1：stash 暂存
git stash
# 执行同步...
git stash pop

# 选项2：commit 提交
git add -A && git commit -m "WIP"

# 选项3：放弃修改（确认后）
git checkout -- .
git clean -fd
```

### 有未推送的提交

SYNC **拒绝执行**，提示用户选择：

```bash
# 选项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"
```

---

# MERGE_SYNC MODE

**⚠️ 与 SYNC MODE 的区别**：SYNC 用于 `pull --ff-only` 安全快进；MERGE_SYNC 用于需要 `reset --hard` 到远程并解决冲突的场景（如 worktree 间同步、离线 bundle 合并后）。

## 什么时候用

- `合并远程` / `merge remote` / `同步冲突` — 需要解决冲突的同步
- `bundle合并` — 从 bundle 恢复后合并
- `worktree同步` — 跨 worktree 同步

## 标准流程

```bash
# 0. 检查状态
git status
CURRENT_BRANCH=$(git branch --show-current)

# 1. 获取远程真实 SHA（无缓存）
REMOTE_SHA=$(git ls-remote origin "$CURRENT_BRANCH" | awk '{print $1}')
LOCAL_SHA=$(git rev-parse HEAD)

echo "Remote: $REMOTE_SHA"
echo "Local:  $LOCAL_SHA"

if [ "$REMOTE_SHA" = "$LOCAL_SHA" ]; then
  echo "✅ 已是最新"
  exit 0
fi

# 2. 暂存本地修改
git stash push -m "Stashing before merge sync"

# 3. 强制更新到远程
git fetch origin "$REMOTE_SHA" --force
git checkout "$CURRENT_BRANCH"
git reset --hard "$REMOTE_SHA"

# 4. 恢复本地修改
git stash pop

# 5. 解决冲突（如果有）
git status  # 查看冲突文件
# 手动解决冲突后：
# git add <resolved-files>

# 6. 提交
git commit -m "chore: 合并远程主分支并解决冲突"
```

## 冲突解决模式

```bash
# 查找冲突标记
grep -rn "<<<<<<" .

# 解决每个冲突文件后：
git add <file>

# 确认所有冲突已解决
git status | grep "both modified"

# 如果冲突太复杂，可以中止：
git merge --abort  # 或 git reset --hard HEAD
git stash pop
```

## 特殊情况

### 有未推送的提交

MERGE_SYNC 会**丢失未推送的提交**，必须先警告用户：

```bash
UNPUSHED=$(git log --oneline "origin/$CURRENT_BRANCH..HEAD" 2>/dev/null)
if [ -n "$UNPUSHED" ]; then
  echo "⚠️ 以下未推送提交将被丢弃："
  echo "$UNPUSHED"
  echo "请先 push 或确认丢弃"
  exit 1
fi
```

### 多文件冲突

```bash
# 批量查看冲突
git diff --name-only --diff-filter=U

# 逐个解决后 add
for f in $(git diff --name-only --diff-filter=U); do
  echo "解决: $f"
  # 编辑文件...
  git add "$f"
done
```

---

# 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: 文档独立提交
```

## 提交流程（零冗余）

```bash
# 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的情况：**

1. **用户可见的新功能**
   - 新增API接口
   - 新增配置项
   - 新增命令行参数
   - 新增UI功能

2. **破坏性变更**
   - API签名变更
   - 配置项重命名/删除
   - 数据库表结构变更
   - 依赖版本升级（major）

3. **重要的Bug修复**
   - 安全漏洞修复
   - 数据丢失风险修复
   - 性能问题修复

### CHANGELOG.md格式

基于项目现有的CHANGELOG.md格式：

```markdown
# 更新日志

## 特性 YYYY-MM-DD
* 新增XXX功能 (commit: abc1234)
* 增强YYY机制 (commit: def5678)

## 变更 YYYY-MM-DD
* **破坏性变更**: ZZZ接口重构，需要迁移 (commit: ghi9012)
* 重构AAA模块，提升性能 (commit: jkl3456)

## 修复 YYYY-MM-DD
* 修复BBB场景下的数据丢失问题 (commit: mno7890)
```

### 更新流程

```bash
# 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条目模板

**新功能：**
```markdown
## 特性 2024-03-04
* 新增nop.cluster.name配置项，支持物理机房隔离 (commit: abc1234)
* 增强服务注册功能，支持groupName和clusterName (commit: def5678)
```

**破坏性变更：**
```markdown
## 变更 2024-03-04
* **破坏性变更**: 重构认证接口，旧版token参数不再支持，需使用AuthRequest对象 (commit: ghi9012)
  - 迁移指南: 将 `authenticate(token)` 改为 `authenticate(new AuthRequest(token))`
```

**重要修复：**
```markdown
## 修复 2024-03-04
* 修复分布式事务在超时场景下的数据不一致问题 (commit: jkl3456)
```

## 不兼容变更检测清单

在提交前检查以下项，如果命中任意一条，**必须**更新CHANGELOG.md并添加BREAKING CHANGE说明：

### API层
- [ ] 修改了public/protected方法签名
- [ ] 删除了public/protected方法
- [ ] 修改了返回值类型
- [ ] 修改了参数类型或顺序
- [ ] 新增了必填参数

### 配置层
- [ ] 删除了配置项
- [ ] 重命名了配置项
- [ ] 修改了配置项的默认值
- [ ] 修改了配置项的格式

### 数据层
- [ ] 删除了数据库表
- [ ] 删除了表字段
- [ ] 修改了字段类型（不兼容）
- [ ] 删除了索引
- [ ] 修改了主键

### 依赖层
- [ ] 升级了major版本的依赖
- [ ] 删除了依赖（可能导致编译失败）
- [ ] 修改了依赖的scope

### 行为层
- [ ] 修改了默认行为
- [ ] 修改了错误处理方式
- [ ] 修改了日志级别或格式
- [ ] 修改了性能特性（可能影响现有系统）

**如果以上任意一项命中：**
1. ✅ 在commit message中添加 `**BREAKING CHANGE:**` 说明
2. ✅ 更新CHANGELOG.md，添加迁移指南
3. ✅ 如果可能，提供兼容层或迁移脚本

**示例输出：**
```
⚠️  检测到破坏性变更：
  - API签名变更: authenticate(String) → authenticate(AuthRequest)
  
✅ 已执行：
  1. Commit message包含BREAKING CHANGE说明
  2. CHANGELOG.md已更新（包含迁移指南）
  3. 提供了迁移示例代码
```

---

# REBASE MODE

## 安全评估

```bash
# 并行收集信息
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）**
```bash
# 合并所有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）**
```bash
MERGE_BASE=$(git merge-base HEAD "$DEFAULT_BRANCH" 2>/dev/null)
GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash $MERGE_BASE
```

**3. Rebase Onto（更新分支）**
```bash
# 强制更新远程跟踪分支（不用 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（查找字符串添加/删除）**
```bash
# 基础：查找字符串何时添加/删除
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（正则匹配）**
```bash
# 查找匹配模式的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（逐行归属）**
```bash
# 基础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）**
```bash
# 开始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. 文件历史追踪**
```bash
# 文件完整历史
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
```

---

# 提交后验证

## 自动验证流程

```bash
# 提交后立即运行（如果修改了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: 性能优化
```

## 同步速查

```bash
# 标准同步流程（安全：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速查

```bash
# 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"
```

## 搜索速查

```bash
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）

1. **从不做单一大commit** - 3+文件必须拆分
2. **从不使用`--force`** - 必须用`--force-with-lease`
3. **从不rebase main/master** - 永远禁止
4. **从不分离实现和单元测试** - 必须同一commit
5. **从不跳过COMMIT PLAN输出** - 必须验证拆分计划
6. **从不使用模糊的分组理由** - "相关"不是理由
7. **SYNC时从不直接 pull/fetch** - 必须先用 `git ls-remote` 无缓存检查，再决定是否更新
8. **从不信任本地 refs 缓存** - `origin/$BRANCH` 可能过期，检查未推送前必须先 `git fetch origin +refs/heads/$BRANCH:refs/remotes/origin/$BRANCH` 更新，否则会误报
9. **SYNC时从不使用 `reset --hard`** - 会丢弃未推送的提交，用 `pull --ff-only` 代替
10. **从不使用 `git fetch origin $SHA`** - 不更新 refs/remotes，用 `git fetch origin +refs/heads/$BRANCH:refs/remotes/origin/$BRANCH` 代替
11. **MERGE_SYNC时从不跳过冲突检查** - 必须 `git status` 确认所有冲突已解决
12. **MERGE_SYNC时从不跳过 stash pop** - 恢复本地修改前必须确认冲突已解决

---

# 最终检查清单

**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已更新（如有破坏性变更/新功能/数据库变更）？

