# Lock 文件

> 

`repostack.lock.yaml` 是自动生成的锁定文件，记录每个 repo 的精确 Git 状态。

## 作用

与 `repostack.yaml` 的关系：

| 文件                    | 作用                   | 类比                  |
| --------------------- | -------------------- | ------------------- |
| `repostack.yaml`      | 声明 stack 包含哪些 repo   | `package.json`      |
| `repostack.lock.yaml` | 记录 repo 的精确 revision | `package-lock.json` |

简单说：

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

## 结构示例

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

## 字段说明

| 字段                      | 说明                                  |
| ----------------------- | ----------------------------------- |
| `version`               | 锁定文件格式版本                            |
| `checksum`              | 内容校验和（SHA-256 前 16 位），用于检测文件是否被意外修改 |
| `repos`                 | 每个 repo 的锁定状态                       |
| `repos.<name>.path`     | 本地路径（冗余，用于校验）                       |
| `repos.<name>.source`   | 远程地址（冗余，用于校验）                       |
| `repos.<name>.branch`   | 分支名称                                |
| `repos.<name>.revision` | 精确的 Git commit SHA                  |

## 工作原理

### 生成时机

以下命令会自动更新 lock 文件：

- `repostack snapshot` - 显式记录当前状态
- `repostack use` - 添加 repo 后自动记录
- `repostack remove` - 移除 repo 后自动记录
- `repostack sync` - 同步完成后重新记录

### 校验机制

Lock 文件包含 SHA-256 校验和：

```yaml
checksum: a1b2c3d4e5f67890
```

**计算方式**：

<steps level="4">

#### 取 lock 文件内容，**排除 `checksum` 字段本身**



#### 将剩余字段（`version` + `repos`）按字母顺序排序



#### 将排序后的对象转为 JSON 字符串



#### 计算 SHA-256 哈希值



#### 取前 16 位作为 checksum



</steps>

**验证时机**：

- `sync` 命令读取 lock 文件时会重新计算并比对
- 不匹配则报错，防止文件被意外修改

**示例**：

假设 lock 文件内容（不含 checksum）为：

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

计算过程：

```text
JSON: {"repos":{"foo":{"branch":"main","path":"foo","revision":"a79cd2d","source":"git@github.com:example-org/foo.git"}},"version":1}
SHA-256: a1b2c3d4e5f67890...
checksum: a1b2c3d4e5f67890  (前16位)
```

**校验失败报错**：

```text
Lock file checksum mismatch: expected a1b2c3d4..., got xxxxxxxxxxxxxxxx.
The lock file may have been corrupted or manually edited.
```

**处理方法**：

<steps level="4">

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



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



</steps>

### 与 Git 的配合

推荐将 lock 文件提交到版本控制：

```bash
# 记录当前状态
repostack snapshot

# 提交到 Git
git add repostack.yaml repostack.lock.yaml
git commit -m "update stack"
```

这样可以通过 stack root 的 commit 历史来"时间旅行"：

```bash
# 回到之前的 stack 状态
git checkout <commit>
repostack sync  # 各 repo 也回到当时的 revision
```

## 最佳实践

### ✅ 应该做

- **提交到 Git**：将 `repostack.lock.yaml` 加入版本控制
- **定期 snapshot**：重要变更前记录状态
- **配合 `sync` 使用**：切换分支或协作后运行 `sync`

### ❌ 不应该做

- **不要手动编辑**：如需修改，使用 `use`/`remove` 命令
- **不要忽略**：不要将 lock 文件加入 `.gitignore`
- **不要依赖它做备份**：lock 文件只记录 revision，不记录代码内容

## 常见问题

**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: Revision 会显示 `(no commits)`，`sync` 时不会尝试 checkout。

**Q: 可以删除 lock 文件吗？**

A: 可以，但会丢失精确的版本锁定。下次 `sync` 时 repo 会停留在当前 HEAD，而不是某个特定的历史版本。
