コンテンツにスキップ

ワークブックを git で管理する

ワークブックの中身を手元のリポジトリにファイルとして取り出し、git で差分・レビュー・PR にかけ、そのまま書き戻せます。チャットのエージェントが書いた transform も同じ場所に出てくるので、「AI が書いた SQL をレビューしてから確定する」運用がそのまま成立します。

Terminal window
d2b pull --workbook WB # → transforms/ sheets/ charts/ + d2b.json
d2b pull --data 顧客リスト # 小さな base テーブルを data/顧客リスト.csv としても追跡(export = branch)
git add -A && git commit -m "pull from D2B"
# ... transforms/*.sql|py、sheets/*.json、data/*.csv を編集
d2b push --dry-run # 何が送られるか(変更のあったファイルだけ)
d2b push --commit "$(git rev-parse --short HEAD)" # 変更分を反映 → git sha を named version に
git commit -am "d2b push" # push は d2b.json(同期ハッシュ)を更新するので一緒にコミット
ディレクトリ中身pullpush
transforms/SQL / Python transform(agg/monthly.sql のように階層可)✅✅ 変更分だけ POST /transforms で再実行(データ操作として計上)。依存順(上流から)
sheets/表示用シート {"blocks": [...]}✅✅ PUT /sheets/{name}
charts/チャートの config + recipe(生成に使ったツールとパラメータ)✅❌ 読み取り専用 — チャートは recipe から再生成するもので、config を手で直しても再生成できない。履歴・確認用
data/--data で opt-in した base テーブルの CSV(__d2b_row_id 付き)✅ export = branch✅ サーバ側で行 ID キーのセル単位 3-way merge。両側で変わったセルは workbook の conflict キューへ(D2B の値が残る)

--data の対象は base テーブルだけです(行がそのテーブル自身の真実である表)。mode=auto の構造化出力は derived(変換の出力)なので分岐できません — 行を git で往復させたいテーブルは、--mode staged で入れて parse spec を確認し materialize する(= base 化)か、行 API で作成してください。

d2b.json がマニフェストです。transform のエントリは {name, artifact_name, args, layer, hash}(新しい transform を足すときはファイルとこのエントリを書く)。hash は最後の同期時点の digest(= マージベース)で CLI が維持します — push 後の d2b.json はコミットしてください。

新しいエントリを手書きするときは hash を書かないでください(省略。null でも同じ扱い)— 初回 push が採番して書き戻します。

{
"workbook_id": "…",
"transforms": {
"agg/monthly.sql": {
"name": "agg/monthly",
"artifact_name": "商品別売上", "args": {"src": "売上明細"}, "layer": null,
"hash": "…"
}
},
"sheets": {"summary.json": {"name": "summary", "hash": "…"}},
"charts": {"trend.json": {"name": "trend", "readonly": true, "hash": "…"}},
"data": {"顧客リスト.csv": {"table": "顧客リスト", "branch_id": "…", "hash": "…"}}
}

ワークスペース単位で同期する

Section titled “ワークスペース単位で同期する”

数百〜数千のワークブックは、1 リポジトリ = 1 ワークスペースで扱います。ルートの d2b.json(台帳)がワークスペースを固定し、各ワークブックは workbooks/<タイトル>--<ID の先頭 8 桁>/ に、上のレイアウトそのまま(それぞれの d2b.json 付き)で入ります。

Terminal window
d2b pull --workspace WS # 初回: 台帳を作り、ワークスペースの全ワークブックを取り出す(並列、--jobs N)
d2b pull # 2 回目以降: 台帳から。新しいワークブックは自動で現れる
d2b pull --prune # ワークスペースから外れたワークブックのディレクトリを消す(消えたことが diff に出る)
d2b status --strict # 台帳・ディレクトリ・サーバーの食い違いがあれば exit 2(CI の必須チェックに)
d2b push --commit "$(git rev-parse --short HEAD)" # 変更のあるワークブックだけ送る
  • 所属はサーバーの事実です。pull はワークスペースの全ワークブックを列挙し、台帳に無いディレクトリは書きません。別のワークスペースを同じリポジトリに pull することはできません(上書きフラグはありません)。
  • ワークブックのディレクトリは最初の pull で固定され、タイトルを変えても動きません。ID はディレクトリ名と、各 transform ファイルの先頭行 -- d2b ws=… wb=… transform=… にあります(この行はサーバーには送られず、変更としても数えません)。
  • push は、台帳に無いディレクトリ・別のワークブックを名指しするヘッダのファイル・台帳と違う workbook_id のマニフェストがあれば、何も送らずに拒否します。
  • CI の鍵はワークスペースにピン留めした PATにしてください(POST /api/control/account/keys の workspace_id、または POST /api/v1/me/tokens の resource: "workspace:<id>")。設定を間違えても、他のワークスペースはサーバーが 403 にします。d2b login の鍵はアカウント全体に届くので CI には向きません。
  • data/(行データ)は従来どおりワークブックごとの opt-in です(workbooks/<dir>/ の中で d2b pull --data TABLE)。

台帳が無いディレクトリでは、従来の「1 ディレクトリ = 1 ワークブック」の動きのままです。

  • テキスト系(transforms / sheets / charts)は黙って上書きしません(行 API の楽観ロックと同じ契約): 最後の同期以降に両側が変わっていれば pull / push とも拒否し、対象ファイルを JSON で返します。--force の向きはコマンドで異なります: push --force はローカル側で上書き、pull --force はサーバ側を採用(ローカルの編集を破棄)
  • data/ は違います: 同時編集はサーバの 3-way merge がセル単位で裁定するので拒否しません。push 後はマージ結果で CSV を取り直し、新しい branch を切ります(D2B 側の変更もローカルに落ちる)。派生テーブルは branch できません(400)。マージ上限 100,000 行 — マスタや対応表のような小さな表向け
  • ローカルで消したファイルはサーバを消しません(deleted_locally に報告のみ)。--prune で transform の出力テーブルとシートを削除(出力テーブルの削除は workbooks:delete)。data/ は追跡を外すだけで、テーブルは消しません
  • d2b.json のキーは、そのセクションディレクトリ内の正規化された相対パスだけです。絶対パス・..・Windows のドライブ・未正規化のパスは pull / push とも拒否します。同期対象のファイル(transforms/*.sql|py など)がシンボリックリンクのときも拒否します — リンク越しに読み書きはしません(セクションが読まないファイルへのリンクは無視するだけです)

GitHub Actions で往復を自動化する

Section titled “GitHub Actions で往復を自動化する”

GitHub App も D2B 側の連携設定も不要で、CLI だけでリポジトリとワークブックの往復が閉じます。

Terminal window
d2b github-workflow > .github/workflows/d2b.yml
# Secrets: D2B_API_KEY(workbooks:write の PAT)、Variables: D2B_BASE_URL
  • main への merge(同期対象ファイルに変更あり)→ d2b push --commit <sha> → 更新された d2b.json を自動コミット
  • 定時(既定 1 時間ごと)と手動 → d2b pull → 差分があれば PR(d2b/pull ブランチ)。エージェントがワークブック側で変えたものを人がレビューして merge する流れ

SDK では client.transforms.list(wb) / client.sheets.list(wb) / client.charts.list(wb) / client.export.branch(wb, [table]) / client.tables.merge(...) が同じ面です。