---
title: 書く
description: チェックアウト、コミット、push。作業カタログ、書き込みの順番、push が断られるとき。
---

## 作業カタログ

書き手は作業カタログに書きます。リポジトリの外にある、SQLite の DuckLake カタログです。手元のパソコンでもホストのコンテナでも、作業カタログは 1 種類です。

- `DATA_INLINING_ROW_LIMIT 0` で ATTACH し、すべての行をデータファイルに書かなければならない
- データパスはリポジトリのデータフォルダ（`<root><data_dir>`）。新しいデータファイルはリポジトリに書かれる。HTTP 越しのリポジトリだけは例外で、新しいデータファイルは書き手のマシンのフォルダに書き、push がそれを上げる（[HTTP での push](/ja/spec/http#書き方)）
- `ducklake_expire_snapshots` と `ducklake_cleanup_old_files` を流してはいけない

## 段階

| 段階 | すること |
| --- | --- |
| チェックアウト | ブランチのバージョンのカタログから作業カタログを作り、そのバージョンを覚える。最初のバージョンの前は空のものを作る |
| コミット | 作業カタログの最後のスナップショットを新しいバージョンに固める。親は覚えておいたバージョン。中身を `dataset.json` で説明する |
| push | データファイルを確かめ、カタログ、`dataset.json` と `files.json`、`version.json` の順にアップロードし、条件付きで ref を動かす |

チェックアウトでは、DuckLake の管理用の表を、固めたカタログから SQLite へそのまま写します。固めるときはその逆で、最後のスナップショットまでの行を残します。どちらもデータファイルは書き換えません。

固めるとき、書き手は次のことをしなければなりません。

- 行をカタログの中に持つ作業カタログを断る
- 固めたカタログの `data_path` を `<root><data_dir>` の絶対 URL にする
- 絶対パスで記録されたデータファイルや、`data_dir` の外のデータファイルがあれば断る

## 変更がないとき

書き手は、親と同じ中身のバージョンを作らないようにするべきです。Git が親と同じ tree のコミットを作らないのと同じです。次のどちらかなら、親と同じ中身です。

- 最後のスナップショットが親のもの（`ducklake.snapshot_id`）と同じ
- 同じ表とビューがあり、どの表も列の名前と型が同じで、行が同じ（重複を数え、順番は問わない）。さらに `dataset.json` の sha256 が親と同じ

同じ入力から作り直した表は新しいデータファイルに書かれるので、ファイルやカタログのバイトを比べても判定できません。書き手はまずファイルを比べ、ファイルが違う表だけ行を読みます。行を読めないときはバージョンを作ります。頼まれたときは、`git commit --allow-empty` と同じく、変更がなくても作ってかまいません。

## 書き込みの順番

1. データファイル
2. `versions/<ID>/ducklake.duckdb`（と `catalogs/`）
3. `versions/<ID>/dataset.json` と `versions/<ID>/files.json`
4. `versions/<ID>/version.json`
5. ref（条件付き）

途中で止まった書き手は、読み手に見えるものを何も変えていません。残ったファイルはどの ref からも参照されず、その中のデータファイルは猶予期間のあとに消されます。

バージョンのファイルは一度だけ書きます。既に同じ中身のファイルがあれば先へ進み、違う中身なら止まります。

## push が断られるとき

古い作業カタログからの push は、次の 2 つの確認で断られます。

1. いまブランチが指すバージョンが、新しいバージョンの `parents` に無い。ほかの人が先に push した
2. カタログが参照するデータファイルがリポジトリに無い。書いたまま猶予期間より長く参照されなかったファイルは、消されていることがある

どちらの場合も、書き手はチェックアウトし直し、作業をやり直して、もう一度 push します。リポジトリを片付ける必要はありません。断られたバージョンはどの ref からも参照されていません。
