ツチノコの夢を見ていたツチノコの夢を見ていた

gitのfilterについて

概要

jupyter notebookをgitで管理する状況で、コミット時に出力セルを削除しつつgitの内部データとして保存するために、gitのclean filter機能というものを利用したところ便利だった。

このgit clean filterについて簡単に整理する。

詳細

git clean filterについて端的に説明すると、ステージングエリアにファイルを移動する際に、任意コマンドを対象ファイルに対して実行して変換する機能である。詳細は以下の通り。

  1. リポジトリの内部状態

    • Gitは.gitディレクトリ内に全てのデータを特殊な形式(主にオブジェクトデータベース)で保存している

    • これが「リポジトリの内部状態」で、通常は直接編集することはない

    • コミットされたファイルやその履歴はすべてここに圧縮・最適化された形で格納されている

  2. ワーキングディレクトリ

    • これは実際に見えて操作できるディレクトリで、コードを編集する場所

    • .gitディレクトリ以外のプロジェクトディレクトリ全体がこれに当たる

  3. データフローとフィルター適用

    • コミット時 (ワーキングディレクトリ → リポジトリ): clean filterが適用される

      • git addgit commitの流れで、ファイルがステージングエリアを経由してリポジトリに格納される

      • この過程でclean filterが適用され、Jupyter Notebookの出力などが削除される

    • チェックアウト時 (リポジトリ → ワーキングディレクトリ): smudge filterが適用される

      • git checkoutgit cloneでファイルを取り出す際に適用される

      • この例ではcat (何もしない) が指定されているため、クリーンアップされた状態のままファイルが展開される

  4. ステージングエリア (インデックス)

    • 実際には、ワーキングディレクトリとリポジトリの間にはステージングエリアという中間層がある

    • git addでファイルをステージングすると、この時点でclean filterが適用される

この流れを図式化すると

plain
ワーキングディレクトリ → [clean filter] → ステージングエリア → リポジトリ内部
リポジトリ内部 → [smudge filter] → ワーキングディレクトリ

このgit clean filterにjupyter notebookの出力セルを削除するコマンドを設定することで、コミット時に出力セルを削除しつつgitの内部データとして保存することができる。具体的には以下のように設定すれば良い。

bash
git config filter.clean-notebook.clean "jq '.cells |= map(if .cell_type == \"code\" then (.outputs |= [] | .execution_count |= null) else . end | .metadata |= if has(\"tags\") then {tags: .tags} else {} end) | .metadata |= {kernelspec: .kernelspec}'"
git config filter.clean-notebook.smudge "cat"
git config filter.clean-notebook.required true
echo "*.ipynb filter=clean-notebook" >> .gitattributes