# repostack snapshot

> 

将当前 stack 的 Git 状态写入 `repostack.lock.yaml`。

```bash
repostack snapshot
```

## 执行流程

<steps level="4">

#### **加载配置**- 读取 `repostack.yaml` 和 `.repostackrc`（如果启用了用户配置）。





#### **读取每个 repo 的 Git 状态**- 对每个 repo 执行：

  - `git rev-parse --abbrev-ref HEAD` → 分支
  - `git rev-parse HEAD` → revision
- 如果 repo 是**空仓库**（无 commit），上述命令失败，会被捕获并记录为 `"(no commits)"`。





#### **构建 lock 对象**- `source` 会优先读取 repo 当前 Git remote URL。
- 如果 repo 没有配置 remote，才回退到 `repostack.yaml` 中的 `source`。
- 结构如下：
```yaml
version: 1
checksum: abc123...
repos:
  foo:
    path: foo
    source: git@github.com:example-org/foo.git
    branch: main
    revision: a79cd2d...
```





#### **计算校验和**- 将 lock 对象去掉 `checksum` 字段后按固定键序序列化为 JSON，计算 SHA-256，取前 16 位作为 `checksum`。
- 该校验和用于 `sync` 时检测 lock 文件是否被意外修改。





#### **写入文件**- 如果某个 repo 能解析出真实 Git remote URL，且 `repostack.yaml` 中的 `source` 仍是旧的占位路径值，会先回写 `repostack.yaml`。
- 如果 `repostack.yaml` 已显式配置了别的 `source`，`snapshot` 不会覆盖它。
- 使用 YAML 格式覆盖写入 `repostack.lock.yaml`。





</steps>

## 涉及文件

| 文件                    | 操作                                  |
| --------------------- | ----------------------------------- |
| `repostack.yaml`      | 读取 / 按需写入（仅修正旧占位 `repos[*].source`） |
| `.repostackrc`        | 读取                                  |
| `repostack.lock.yaml` | 写入（覆盖）                              |

## Git 操作

- `git rev-parse --abbrev-ref HEAD`（每个 repo）
- `git rev-parse HEAD`（每个 repo）
- `git config --get branch.<name>.remote` / `git remote get-url <remote>`（解析 source 时按需执行）

## 错误与边界情况

- 配置加载失败会直接中断命令。
- 文件写入错误会直接抛出。
- 空仓库的分支和 revision 会被记录为字符串 `"(no commits)"`。

## 适用场景

- 完成一组 repo 的版本调整后记录状态
- 在重要变更前创建"检查点"
- 准备提交 stack 状态到版本控制

## 注意

- `use` 和 `remove` 命令在修改配置后会**自动生成 snapshot**。
- `sync` 命令在同步完成后也会自动重新生成 snapshot。
- 因此，通常只有在手动调整 repo 状态后、想立即固化状态时才需要手动运行 `repostack snapshot`。

## 示例

```bash
repostack snapshot
```
