# Fork Rebase Rename

> 基于已有项目 fork 出新项目：换源子模块远程地址、重命名子模块目录与项目名称、 更新代码中的路径引用。适用于任何语言/构建系统的 git 仓库（含子模块或不含子模块均可）。 当用户说"fork 项目"、"换源"、"基于 X 项目新建 Y 项目"、"子模块改名"时触发。

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

---


# Fork-Rebase-Rename

将一个已有 git 项目（含子模块或不含）原地转换为一个新项目：换远程源、重命名模块目录和项目名称、修改代码中的旧路径引用。全程避免不必要的重新克隆，最大化复用本地已有文件。

## 核心原则

1. **不擅自决定**：遇到不确定、有歧义的内容（如同名资源文件、项目名和资源名重合、多工作区边界等），必须向用户提问并获得明确答复后才行动。
2. **对用户透明**：remote name 等 git 内部概念不暴露给用户；自动检测 remote（若唯一则直接使用，若多个则询问用户用哪个）。
3. **两次提交，不 push**：换源一次 commit，重命名一次 commit，均不自动 push。
4. **commit message 遵循项目惯例**：观察项目已有提交风格（中文/英文、前缀风格），保持一致。若无法判断则询问用户。

## 工作流程

### Phase 0：信息收集

依次向用户收集以下信息（逐步提问，不一次性罗列）：

1. **主模块是否换源？** 新 URL 是什么？
2. **检测子模块情况**：
   - 若 `.gitmodules` 存在且非空 → 列出所有子模块，询问用户"哪些需要换源？各自的新 URL？哪些保持不动？"
   - 若无子模块 → 跳过子模块相关步骤
3. **新库与旧库的关系**（对每个需换源的子模块）：
   - 若新库是旧库的 fork（历史相同/相近）→ 仅换源即可，无需重新克隆
   - 若新库与旧库内容差异大 → 对该子模块执行 deinit + 重新克隆

### Phase 1：换源（commit #1）

#### 1.1 主模块换源

1. 自动检测当前 remote name（`git remote` 输出唯一则用它，多个则问用户）
2. `git remote set-url <remote> <new-url>`
3. 验证：`git remote -v`

#### 1.2 子模块处理（若有）

根据 Phase 0 中对每个子模块确认的关系，走不同路径：

**路径 A：fork 关系（仅换源，不 re-clone）**

1. **检查子模块是否已初始化**：
   - 若 `.git/modules/<name>` 存在且子模块目录内有 `.git` 文件 → 已初始化，进入子模块执行 `git remote set-url`
   - 若未初始化 → 仅更新 `.gitmodules` 中的 url，后续 sync 即可
2. 更新 `.gitmodules` 中对应子模块的 url（`git config -f .gitmodules submodule.<name>.url <new-url>`）
3. `git submodule sync <path>`（同步到 `.git/config`）
4. 若存在嵌套子模块，使用 `git submodule sync --recursive`

**路径 B：内容差异大（deinit + 重新克隆）**

```bash
git submodule deinit -f <path>
git rm -f <path>
rm -rf .git/modules/<path>
git submodule add <new-url> <path>
git submodule update --init <path>
```

#### 1.3 提交

```bash
git add -A
git commit -m "<根据项目惯例生成的换源提交信息>"
```

### Phase 2：信息收集（重命名）

向用户收集：

1. **新项目名称**（影响构建目标名、lib 名等）
2. **子模块目录新名称**（每个需改名的子模块）
3. **构建中间文件/缓存目录**：是否需要清理？（由用户决定）

### Phase 3：自主探索旧名引用

在执行重命名前，自动搜索代码库中所有引用旧名称的位置。

**搜索范围**：仅当前项目目录。若工作区有多个项目目录，询问用户搜索范围。

**排除目录**（搜索时自动跳过）：
- `.git/`
- 构建输出目录（`build/`、`out/`、`dist/`、`target/` 等）
- 依赖缓存（`node_modules/`、`.build/`、`Pods/`、`vendor/` 等）
- 用户指定的其他排除目录

**搜索目标**：
- 构建配置文件（CMakeLists.txt、Makefile、package.json、Cargo.toml、build.gradle 等）
- 资源打包/部署配置（JSON、YAML、CSV 等）
- 源代码中的硬编码路径字符串
- 文档中的引用

将结果汇总为列表，向用户展示并确认：
- 哪些是项目名引用 → 需要改
- 哪些是资源/音频/资产文件名（恰好与项目同名）→ 确认是否改
- 哪些在第三方库/不可控目录中 → 通常不改

**对每一个有歧义的项，单独询问用户。**

### Phase 4：执行重命名（commit #2）

#### 4.1 子模块目录重命名

根据 Phase 1 中各子模块走的路径：

**对路径 A 子模块（已换源、本地文件保留）→ 本地 mv**

```bash
# 1. 移动工作目录
mv <old-path> <new-path>

# 2. 移动 .git/modules 对应目录
mv .git/modules/<old-path> .git/modules/<new-path>

# 3. 修复子模块内 .git 文件的 gitdir 指向
echo "gitdir: <relative-path-to-new-modules-dir>" > <new-path>/.git

# 4. 修复 .git/modules/<new>/config 中的 worktree 指向
#    worktree = <relative-path-to-new-workdir>

# 5. 从 git index 移除旧路径
git update-index --force-remove <old-path>

# 6. 重新注册新路径到 index（利用已有本地仓库，不触发 clone）
git submodule add -f <url> <new-path>

# 7. 确保 .gitmodules 中 submodule name 和 path 正确
git config -f .gitmodules --rename-section "submodule.<old-name>" "submodule.<new-name>"
git config -f .gitmodules submodule.<new-name>.path <new-path>

# 8. 更新 .git/config 中 section 名
git config --local --rename-section "submodule.<old-name>" "submodule.<new-name>"
```

**对路径 B 子模块（已在 Phase 1 重新克隆）→ 仅需改目录名**

路径 B 子模块在 Phase 1 中已通过 `git submodule add <url> <path>` 注册。若目标目录名与 Phase 1 时指定的不同，执行同样的本地 mv 流程。若 Phase 1 时已用新目录名注册，则无需额外操作。

#### 4.2 更新项目名和 lib 名

根据 Phase 3 确认的列表，逐一替换：
- 构建系统中的项目名、目标名、库名
- 源代码中的路径字符串
- 资源配置中的目录引用

#### 4.3 验证

```bash
git submodule status  # 所有子模块正常显示，无 fatal 错误
# 在各子模块内执行 git status / git log --oneline -1 确认正常
```

#### 4.4 提交

若子模块内部有文件改动（如 lib 名变更），先在子模块内提交：
```bash
cd <submodule-path>
git add -A
git commit -m "<子模块内部的改动描述>"
cd <project-root>
```

然后在主模块提交：
```bash
git add -A
git commit -m "<根据项目惯例生成的重命名提交信息>"
```

### Phase 5：收尾提醒

告知用户：
- 两个 commit 已就绪，未 push
- 若子模块内部有提交，push 时需要同时推送子模块和主模块
- 构建缓存/中间文件需要用户自行清理后重新构建
- 可选：工作区根目录重命名（纯本地操作，不影响 git）

## 注意事项

- **不修改不属于当前项目的工作区内容**（如工作区有多个项目目录时）
- **音频、图片等资源文件名**默认不改（除非用户明确要求）
- **remote name 对用户透明**，不要求用户知道或操作 remote name
- **git 操作安全**：不 force push、不 reset --hard、不删除 .git 历史
- **嵌套子模块**：若检测到子模块内还有子模块，提醒用户并确认是否递归处理
- 所有不确定的决策点 → **停下来问用户**

