# Snapshot 与 Sync

> 

`snapshot` 和 `sync` 是 `repostack` 实现"时间旅行"的核心机制。

## 两个配置文件的关系

| 文件                    | 作用                   | 是否应提交到 Git |
| --------------------- | -------------------- | ---------- |
| `repostack.yaml`      | 声明 stack 包含哪些 repo   | ✅ 是        |
| `repostack.lock.yaml` | 记录每个 repo 的精确 Git 状态 | ✅ 是        |

**简单记忆**：

- `repostack.yaml` = "我想要什么"
- `repostack.lock.yaml` = "实际是什么"

关于 lock 文件的详细说明，参见 [Lock 文件](./lock-file)。

## `snapshot` 做了什么

```bash
repostack snapshot
```

执行步骤：

<steps level="4">

#### 读取当前 stack 中每个 repo 的：- `path` - 本地路径
- `source` - 远程地址
- 当前 branch
- 当前 `HEAD` revision





#### 构建 lock 对象并计算 checksum（SHA-256）



#### 将数据写入 `repostack.lock.yaml`



</steps>

**生成示例**：

```yaml
version: 1
checksum: a1b2c3d4e5f67890
repos:
  foo:
    path: foo
    source: git@github.com:example-org/foo.git
    branch: main
    revision: a79cd2d8f1b2c3d4e5f678901234567890abcdef
```

## 自动 Snapshot

以下命令会自动更新 lock 文件，通常不需要手动运行 `snapshot`：

- `repostack use` - 添加 repo 后自动 snapshot
- `repostack remove` - 移除 repo 后自动 snapshot
- `repostack sync` - 同步完成后自动 snapshot

## `sync` 做了什么

```bash
repostack sync
```

执行步骤：

<steps level="4">

#### **下载** - clone 本地缺失的 repo



#### **读取 lock** - 解析 `repostack.lock.yaml`



#### **拉取** - 对每个 repo 执行 `git fetch --all --tags`



#### **检出** - 如果 lock 有指定 revision，checkout 到该版本



#### **记录** - 重新生成 lock 文件



</steps>

## Checksum 校验机制

lock 文件包含 SHA-256 校验和，用于检测文件是否被意外修改：

```yaml
checksum: a1b2c3d4e5f67890
```

**作用**：

- 生成时计算 lock 内容（不含 checksum 本身）的 SHA-256 哈希，取前 16 位
- `sync` 命令读取时重新计算比对
- 不匹配时报错，防止文件被意外修改

详细计算方式参见 [Lock 文件](./lock-file)。

**如何处理错误**：

<steps level="4">

#### 如果确实需要修改，删除 `checksum` 字段后重新运行 `snapshot`



#### 如果是意外损坏，从 Git 历史恢复 lock 文件



</steps>

## 时间旅行工作流

推荐将 stack root 本身作为 Git 仓库：

```bash
# 1. 当前状态
cd ~/my-stack
repostack list
# foo @ main a79cd2d
# bar @ main 1234567

# 2. 记录状态
repostack snapshot
git add repostack.lock.yaml
git commit -m "checkpoint: before big refactor"

# 3. 继续开发...
# （在 foo 和 bar 中做各种修改、提交）

# 4. 需要回到之前的状态
git log --oneline
git checkout abc123  # 回到之前的 stack 状态
repostack sync       # 各 repo 也回到当时的 revision
```

## 当前边界

- `snapshot` 只记录 commit，不记录**未提交的修改**（dirty 状态只会在 `list` 中显示）
- 如果 repo checkout 到具体 revision，branch 会显示为 `HEAD`
- lock 文件记录的是 Git revision 快照，不是完整环境锁定（不包含 node_modules 等）

## 常见问题

**Q: 为什么 use/remove 会自动 snapshot？**  

A: 为了保持 `repostack.yaml` 和 `repostack.lock.yaml` 始终同步。添加/移除 repo 后，lock 文件的内容定义已经变化，需要更新。

**Q: lock 文件冲突了怎么办？**  

A: 解决方式和普通代码冲突一样：

<steps level="4">

#### 选择一方的版本



#### 运行 `repostack sync` 确保本地状态匹配



#### 如果需要，重新 `snapshot` 生成新的 lock



</steps>

**Q: 空仓库（无 commit）会怎样？**  

A: 会显示 `(no commits)`，sync 时不会尝试 checkout。
