619

IPythonノートブックをバージョン管理下に置くための良い戦略は何ですか?

ノートブック形式は、バージョン管理に非常に適しています。ノートブックと出力をバージョン管理したい場合、これは非常にうまく機能します。特に映画やプロットの場合、大きなバイナリブロブになる可能性があるセル出力(別名「ビルド製品」)を除外して、入力のバージョン管理のみを行いたい場合に煩わしさが生じます。特に、次のような優れたワークフローを見つけようとしています。

  • 出力を含めるか除外するかを選択できます。
  • 必要のない出力を誤ってコミットするのを防ぎます。
  • 出力をローカル バージョンに保持できるようにする
  • バージョン管理システムを使用して、入力にいつ変更があったかを確認できます (つまり、入力のみをバージョン管理し、ローカル ファイルに出力がある場合、入力が変更されたかどうかを確認できるようにしたいと考えています (コミットが必要です) ) バージョン管理ステータス コマンドを使用すると、ローカル ファイルに出力があるため、常に違いが登録されます。)
  • 更新されたクリーンなノートブックから作業中のノートブック (出力を含む) を更新できます。(アップデート)

前述のように、出力を含めることを選択した場合 (たとえば、 nbviewerを使用する場合に望ましい)、すべて問題ありません。問題は、出力をバージョン管理したくない場合です。ノートブックの出力を削除するためのツールとスクリプトがいくつかありますが、次の問題が頻繁に発生します。

  1. 誤ってバージョンを出力でコミットしたため、リポジトリが汚染されました。
  2. バージョン管理を使用するために出力をクリアしますが、実際には出力をローカル コピーに保持したいと考えています (たとえば、再現に時間がかかる場合があります)。
  3. 出力を削除するスクリプトの一部は、Cell/All Output/Clearメニュー オプションと比較して形式をわずかに変更するため、差分に不要なノイズが発生します。これは、いくつかの回答によって解決されます。
  4. 変更をファイルのクリーン バージョンにプルする場合、すべてを再実行することなく、それらの変更を作業ノートブックに組み込む方法を見つける必要があります。 (アップデート)

以下で説明するいくつかのオプションを検討しましたが、まだ優れた包括的な解決策を見つけていません。完全なソリューションでは、IPython にいくつかの変更が必要になるか、いくつかの単純な外部スクリプトに依存する場合があります。私は現在mercurialを使用していますが、 gitでも機能するソリューションが必要です。理想的なソリューションは、バージョン管理に依存しないものです。

この問題は何度も議論されてきましたが、ユーザーの観点から決定的または明確な解決策はありません。この質問に対する答えは、決定的な戦略を提供する必要があります。IPythonの最新の (開発段階であっても) バージョンまたは簡単にインストールできる拡張機能が必要な場合は問題ありません。

更新: Gregory Crosswhite の提案を使用して、保存するたびにオプションでバージョンを保存する変更されたノートブックバージョンで遊んでいます。これは私の制約のほとんどを満たしていますが、次の未解決のままです。.clean

  1. これはまだ標準的な解決策ではありません (ipython ソースの変更が必要です。単純な拡張機能でこの動作を実現する方法はありますか? 何らかの保存時のフックが必要です。
  2. 現在のワークフローで私が抱えている問題は、変更をプルすることです。これらは.cleanファイルに入り、作業中のバージョンに何らかの方法で統合する必要があります。(もちろん、いつでもノートブックを再実行できますが、特に結果の一部が長い計算や並列計算などに依存している場合、これは苦痛になる可能性があります) これを解決する方法についてまだ良い考えがありません. おそらく、ipycacheのような拡張機能を含むワークフローが機能する可能性がありますが、それは少し複雑すぎるようです。

ノート

出力の削除 (ストリッピング)

  • ノートブックが実行されている場合、Cell/All Output/Clearメニュー オプションを使用して出力を削除できます。
  • 出力を削除するスクリプトnbstripout.pyなど、出力を削除するためのスクリプトがいくつかありますが、ノートブック インターフェイスを使用した場合と同じ出力は生成されません。これは最終的に ipython/nbconvert リポジトリに含まれました、変更が現在ipython/ipythonに含まれていることを示してクローズされていますが、対応する機能はまだ含まれていないようです。 (更新)そうは言っても、Gregory Crosswhite のソリューションは、 ipython/nbconvertを呼び出さなくても、これが非常に簡単であることを示しています。であるため、適切にフックできれば、このアプローチはおそらく実行可能です。

ニュースグループ

問題

プルリクエスト

4

23 に答える 23

133

これがgitを使用した私のソリューションです。通常どおり追加とコミット (および差分) を実行できます。これらの操作は作業ツリーを変更せず、同時にノートブックを (再) 実行しても git 履歴は変更されません。

これはおそらく他の VCS に適用できますが、要件 (少なくとも VSC に依存しない) を満たさないことはわかっています。それでも、それは私にとって完璧であり、特に素晴らしいものではなく、おそらくすでに多くの人が使用していますが、グーグルで調べても実装方法に関する明確な指示は見つかりませんでした. したがって、他の人にも役立つ場合があります。

  1. このコンテンツを含むファイルをどこかに保存します(以下では、 と仮定します~/bin/ipynb_output_filter.py)

  2. 実行可能にする ( chmod +x ~/bin/ipynb_output_filter.py)

  3. ~/.gitattributes次の内容でファイルを作成します

    *.ipynb filter=dropoutput_ipynb

  4. 次のコマンドを実行します。

    git config --global core.attributesfile ~/.gitattributes git config --global filter.dropoutput_ipynb.clean ~/bin/ipynb_output_filter.py git config --global filter.dropoutput_ipynb.smudge cat

終わり!

制限:

  • gitでのみ動作します
  • git では、ブランチsomebranchにいるgit checkout otherbranch; git checkout somebranch場合、通常は作業ツリーが変更されていないことを期待します。ここでは代わりに、2 つのブランチ間でソースが異なるノートブックの出力とセルの番号付けが失われます。
  • より一般的には、Gregory のソリューションのように、出力はまったくバージョン管理されません。チェックアウトに関連する何かを行うたびに破棄しないようにするために、別のファイルに保存することでアプローチを変更できます (ただし、上記のコードが実行される時点では、コミット ID がわからないことに注意してください!)。おそらくそれらをバージョン管理します(git commit notebook_file.ipynbただし、少なくともgit diff notebook_file.ipynbbase64ガベージから解放されますが、これには .
  • ちなみに、何らかの出力を含むコードをプルする (つまり、このアプローチを使用していない他の誰かによってコミットされた) 場合、出力は正常にチェックアウトされます。ローカルで生成された出力のみが失われます。

私の解決策は、生成されたものをバージョン管理したくないという事実を反映しています。出力を含むマージを行うと、出力または生産性、またはその両方が無効になることがほぼ保証されていることに注意してください。

編集:

  • 私が提案したソリューションを採用した場合、つまりグローバルに採用した場合、一部の git リポジトリで出力をバージョン管理する場合に問題が発生します。したがって、特定の git リポジトリの出力フィルタリングを無効にする場合は、その中にファイル.git/info/attributesを作成するだけで済みます。

    **.ipynb フィルター =

コンテンツとして。明らかに、同じ方法で反対のことを行うことができます:特定のリポジトリに対してのみフィルタリングを有効にします。

  • コードは独自のgit リポジトリで維持されるようになりました

  • 上記の手順で ImportErrors が発生する場合は、スクリプトのパスの前に「ipython」を追加してみてください。

      git config --global filter.dropoutput_ipynb.clean ipython ~/bin/ipynb_output_filter.py
    

編集: 2016 年 5 月( 2017 年 2 月更新) : 私のスクリプトにはいくつかの代替 手段あります

于 2013-12-30T17:35:23.120 に答える
13

Cyrille Rossant による IPython 3.0 向けの新しいソリューションを次に示します。これは、json ベースの ipymd ファイルではなく、マークダウン ファイルに保持されます。

https://github.com/rossant/ipymd

于 2015-02-21T22:09:36.877 に答える
8

で指摘されているように、--scriptは非推奨です3.x。このアプローチは、post-save-hook を適用することで使用できます。特に、以下を に追加しますipython_notebook_config.py

import os
from subprocess import check_call

def post_save(model, os_path, contents_manager):
    """post-save hook for converting notebooks to .py scripts"""
    if model['type'] != 'notebook':
        return # only do this for notebooks
    d, fname = os.path.split(os_path)
    check_call(['ipython', 'nbconvert', '--to', 'script', fname], cwd=d)

c.FileContentsManager.post_save_hook = post_save

コードは#8009から取得されます。

于 2015-03-11T15:27:32.377 に答える
7

残念ながら、私は Mercurial についてあまり詳しくありませんが、Git で動作する可能性のある解決策を提供できます.

背景として、Git では、addコマンドはファイルに加えられた変更をステージング領域に保存します。これを行うと、ファイルへの以降の変更は、ステージングするように指示しない限り、Git によって無視されます。したがって、次のスクリプトは、指定されたファイルごとに と をすべてoutputs取り除きprompt_number sections、取り除かれたファイルをステージングしてから、元のファイルを復元します。

注:これを実行すると のようなエラー メッセージが表示される場合は、 の代わりに をImportError: No module named IPython.nbformat使用ipythonしてスクリプトを実行しますpython

from IPython.nbformat import current
import io
from os import remove, rename
from shutil import copyfile
from subprocess import Popen
from sys import argv

for filename in argv[1:]:
    # Backup the current file
    backup_filename = filename + ".backup"
    copyfile(filename,backup_filename)

    try:
        # Read in the notebook
        with io.open(filename,'r',encoding='utf-8') as f:
            notebook = current.reads(f.read(),format="ipynb")

        # Strip out all of the output and prompt_number sections
        for worksheet in notebook["worksheets"]:
            for cell in worksheet["cells"]:
               cell.outputs = []
               if "prompt_number" in cell:
                    del cell["prompt_number"]

        # Write the stripped file
        with io.open(filename, 'w', encoding='utf-8') as f:
            current.write(notebook,f,format='ipynb')

        # Run git add to stage the non-output changes
        print("git add",filename)
        Popen(["git","add",filename]).wait()

    finally:
        # Restore the original file;  remove is needed in case
        # we are running in windows.
        remove(filename)
        rename(backup_filename,filename)

変更をコミットしたいファイルに対してスクリプトが実行されたら、実行するだけgit commitです。

于 2013-11-04T04:27:58.513 に答える
6

私は非常に実用的なアプローチを採用しています。いくつかの側面で、いくつかのノートブックに適しています。また、ノートブックを「転送」することもできます。Windows と Unix/MacOS の両方で動作します。
アルは簡単だと思った、上記の問題を解決する...

概念

基本的に、ファイルは追跡せ.ipnyb、対応するファイルのみを追跡し.pyます。オプションでnotebook-server
起動すると、ノートブックを保存するときにそのファイルが自動的に作成/保存されます。--script

これらの.pyファイルにはすべての入力が含まれています。非コードは、セル境界と同様にコメントに保存されます。これらのファイルは、ノートブック サーバーに読み取り/インポート (およびドラッグ) して、ノートブックを (再) 作成できます。出力だけがなくなりました。再実行されるまで。

個人的には、mercurial.pyを使用してファイルのバージョンを追跡しています。通常の(コマンドライン)コマンドを使用して追加し、チェックイン(ect)します。他のほとんどの (D)VCS ではこれが可能です。

履歴を追跡するのは簡単です。これら.pyは小さく、テキストであり、差分が簡単です。ときどき、クローン (分岐するだけ。そこで 2 番目のノートブック サーバーを起動する) や、古いバージョン (チェックアウトしてノートブック サーバーにインポートする) などが必要になります。

ヒントとコツ

  • *.ipynbを ' .hgignore ' に追加して、Mercurial がそれらのファイルを無視できることを認識できるようにします。
  • (bash)スクリプトを作成して(--scriptオプションを使用して)サーバーを起動し、バージョン追跡を行います
  • ノートブックを保存すると、ファイルは保存されますが、チェックインされ .pyません。
    • これは欠点です : それを忘れることができます
    • これも機能です。リポジトリ履歴をクラスタ化せずにノートブックを保存する (そして後で続行する) ことができます。

願い事

  • ノートブック ダッシュボードにチェックイン/追加/その他のボタンがあると便利です
  • (by example) file@date+rev.py) へのチェックアウトが役立つはずです。それを追加するには大変な作業になります。多分私は一度そうするでしょう。今まで、私はそれを手作業で行っていました。
于 2014-07-22T13:35:30.710 に答える
1

Albert & Rich が行ったことを私は行いました - .ipynb ファイルをバージョン管理しないでください (これらには画像が含まれている可能性があり、乱雑になります)。代わりに、ノートブックを保存するときに(バージョン管理可能な) ファイルが常に作成されるように、常に実行するipython notebook --scriptか、構成ファイルに入れます。c.FileNotebookManager.save_script = True.py

ノートブックを再生成するには (リポジトリをチェックアウトした後、またはブランチを切り替えた後)、スクリプトpy_file_to_notebooks.pyをノートブックを保存するディレクトリに配置します。

リポジトリをチェックアウトしたら、実行python py_file_to_notebooks.pyして ipynb ファイルを生成します。ブランチを切り替えた後、実行python py_file_to_notebooks.py -ovして既存の ipynb ファイルを上書きする必要がある場合があります。

安全のために、ファイルにも追加すること *.ipynbをお勧めし.gitignoreます。

編集: (A) ブランチをチェックアウトするたびに py ファイルからノートブックを再生成する必要があり、(B) ノートブックにはマークダウンのような他のものがあるため、これはもう行いません。代わりに、git フィルターを使用してノートブックから出力を取り除きます。これを行う方法についての議論はここにあります。

于 2015-02-18T14:38:34.250 に答える
1

ここでの議論によると、現在の最善の解決策のように見えますが、コミット時に ipynb ファイルから出力を自動的に削除するように git フィルターを作成することです。

これを機能させるために私がしたことは次のとおりです(その議論からコピーされました):

cfriedline の nbstripout ファイルを少し変更して、最新の IPython をインポートできない場合に有益なエラーが発生するように ました。で言う./relative/path/to/strip_notebook_output

また、以下を含むファイル .gitattributes ファイルをリポジトリのルートに追加しました。

*.ipynb filter=stripoutput

そして、setup_git_filters.sh含むを作成しました

git config filter.stripoutput.clean "$(git rev-parse --show-toplevel)/relative/path/to/strip_notebook_output" 
git config filter.stripoutput.smudge cat
git config filter.stripoutput.required true

そして走っsource setup_git_filters.shた。派手な $(git rev-parse...) のことは、任意の (Unix) マシンでレポのローカル パスを見つけることです。

于 2015-03-16T14:05:33.797 に答える