この記事の目次
研究を半年も続けると、フォルダにanalysis.py、analysis_new.py、analysis_final.py、analysis_final2.pyが並び始めます。ファイル名から新旧は何となく分かっても、「学位論文の図を作ったのはどれか」「品質フィルターを直したときに何が変わったか」「修正前の計算へ戻せるか」には答えられません。
こうした混乱を防ぐために使うのがGitとGitHubです。Gitは、指定したファイルの状態を時点ごとに自分のパソコンへ記録します。GitHubは、そのGitリポジトリをオンラインに保管し、共有、議論、レビューを行えるようにします。二つを組み合わせれば、曖昧なファイル名や記憶に頼らず、研究結果と、それを作った時点のコードを結び付けられます。
この記事は、解析スクリプトとデータフォルダはあるものの、バージョン管理を使ったことがない研究者を対象としています。大容量データと生成結果を除外した研究用リポジトリを作り、変更を確認しやすい単位で記録して、結果に使ったコードを特定できるようにする手順を説明します。
問題はファイルを失うことだけではない
通常のバックアップは、パソコンが故障したときにファイルを守ります。ただし、バックアップだけでは研究結果を再現できるとは限りません。ある結果を作ったコード、入力データ、パラメーター、実行環境を特定できるでしょうか。
プロジェクトフォルダを時々コピーしても、どの行をなぜ変えたのかは分かりません。クラウド同期されたフォルダに最新版が残っていても、似た名前の複数ファイルがそれぞれ何のために作られたのかまでは分かりません。Gitを使えば、ファイル一式を時点ごとに記録し、前後の差を比較できます。
ただし、Gitは変更の科学的な意味を理解しません。しきい値が0.2から0.3へ変わったことは示せますが、なぜ変更したのか、どの結果が変わったのかは研究者が記録する必要があります。
GitとGitHubは別の役割を持つ
二つの名前は一緒に登場しますが、担当する仕事は異なります。
| 用語 | 日常語での意味 | 研究で得られるもの |
|---|---|---|
| Git | パソコン上で動くバージョン管理システム | 各時点のファイルを記録し、変更を比較して、以前のコードへ戻せる |
| リポジトリ | Gitで管理するプロジェクトフォルダ | コード、手法、テスト、環境定義をまとめて履歴に残せる |
| コミット | ある時点のファイル一式を、短い説明とともに記録したもの | 結果を作った時点のコードを示す目印になる |
| ブランチ | 本流から分けた作業場所 | 確認済みの処理をすぐ置き換えずに、別の手法を試せる |
| GitHub | Gitリポジトリを置くオンラインサービス | 履歴の共有とIssue、Pull Request、レビュー |
GitはGitHubがなくても使え、オフラインでもコミットできます。GitHubはGitそのものではなく、パソコン上のあらゆるファイルを保管する汎用バックアップでもありません。
リポジトリに何を残すか決める
研究用リポジトリには、別の人が解析手順をたどれるように、必要なファイルと説明を残します。
- ソースコードと小さな補助スクリプト
- 解析方法の説明とパラメーターファイル
- テストと小さな合成テストデータ
Dockerfile、compose.yaml、依存関係の定義- 入力、実行コマンド、出力を説明するREADME
- 入手元、製品名、取得日、チェックサムなど、使用したデータを特定する情報
通常は次のものを含めません。
- 大容量の元データやダウンロードしたデータセット
- 多数のNetCDFファイル
- 再生成できる中間データ
- キャッシュ、仮想環境、Notebookのチェックポイント
- 生成したすべての図とレポート
- パスワード、APIキー、トークン、秘密鍵
レビューやテストに必要なら、小さな参照結果や合成データをGitで管理することもあります。「コードかどうか」ではなく、「このファイルの変更履歴を残すと解析内容の理解や検証に役立つか」で判断します。
研究向けのディレクトリ構成から始める
コード、データ、結果の役割を分けます。
research-project/
├── .gitignore
├── README.md
├── requirements.txt
├── method/
│ └── analysis-contract.yaml
├── src/
│ └── analyze.py
├── tests/
│ ├── test_analysis.py
│ └── fixtures/
├── data/
│ ├── README.md
│ └── raw/ # ローカルには置くがGitでは管理しない
└── output/
└── README.md # 生成内容はGitでは管理しない
Gitでは、解析コードや手順書など、解析内容を説明して再実行するためのファイルを管理します。data/raw/の大容量データと、再生成できるoutput/の内容は、研究者のパソコンまたは別のストレージへ置きます。
いま使っているプロジェクトでコード、データ、結果が一つのフォルダに混ざっているなら、最初のコミットより前に分けてください。後からデータを誤って追加する危険を減らせます。
リポジトリを作る
使用中のOSに対応する公式手順でGitを導入し、コマンドが使えることを確認します。
git --version
今後作るコミットに記録される作成者情報を設定します。
git config --global user.name "Your Name"
git config --global user.email "[email protected]"
コミットの作成者情報として公開してよいメールアドレスを選んでください。個人のアドレスを公開したくない場合は、GitHubが提供する非公開用のnoreplyアドレスも利用できます。
続いて、ターミナルでプロジェクトのディレクトリへ移動し、次のコマンドを実行します。
git init
git branch -M main
git status
git initはローカルのリポジトリを作ります。この時点では何もアップロードされません。git statusは、未追跡、変更済み、ステージ済みのファイルを、状態を変えずに表示します。何度実行しても問題はないので、こまめに確認してください。
ファイルを追加する前に、管理対象から外す規則を用意します。
.gitignoreでデータと生成ファイルを除外する
リポジトリ直下に.gitignoreを作ります。
# Raw and downloaded data
data/*
!data/README.md
!data/sample/
!data/sample/**
# Generated analysis output
output/*
!output/README.md
# Local configuration and credentials
.env
.env.*
!.env.example
secrets/
# Python and notebook caches
__pycache__/
*.py[cod]
.pytest_cache/
.ipynb_checkpoints/
# Local environments and editor files
.venv/
.DS_Store
先頭に!を付けた例外規則によって、大容量のファイルを除外したまま、説明用のREADMEと、必要なら小さなサンプルだけを管理対象に残せます。
.gitignoreが作用するのは、Gitがまだ追跡していないファイルです。コミット済みのファイル名を後から追加しても、以前の履歴からは消えません。
データをアップロードする代わりに説明する
データセットをGitから除外しても、説明はリポジトリに残します。data/README.mdを作ります。
# Input data
## Dataset
- Provider: [official provider and URL]
- Product or collection: [identifier]
- Retrieval or snapshot date: YYYY-MM-DD
- Spatial and temporal subset: [selection]
- License or access terms: [reference]
## Local layout
- `raw/`: files obtained from the provider; do not edit in place
- `derived/`: recreated with the preprocessing command below
## Obtain the data
Run:
`bash scripts/download-data.sh`
Expected SHA-256:
`filename.nc expected-digest`
データセットに固定の識別子、バージョン、DOI、オブジェクトバージョン、チェックサムがあるなら、ダウンロードURLと一緒に記録します。同じURLから、後日更新された別のデータが配布されることもあるためです。
利用制限があるデータについては、権限のある研究者が取得する方法を記録します。認証情報や、再配布を許可されていないデータ本体をリポジトリに入れてはいけません。
最初のコミットを慎重に作る
パスを指定してステージし、履歴に入る内容を確認します。
git add .gitignore README.md requirements.txt
git add method src tests data/README.md output/README.md
git status
git diff --cached
git commit -m "Initialize reproducible analysis project"
ステージング領域は、次のコミットに含める内容を確認する場所です。git diff --cachedを使うと、記録する前の差分を読めます。
コミットメッセージは、何を変更したかが一目で分かる文にします。
Add adjusted-temperature quality filterCorrect pressure-unit validationRecord parameters for North Pacific comparison
科学的手法の変更と、無関係なファイル名変更や整形を混ぜないでください。小さなコミットに分けると、計算が変わった時点を探しやすくなります。
GitHubへリポジトリを置く
使用するGitHubアカウントまたはOrganizationに、空のリポジトリを作ります。ライセンス、共同研究の規則、未発表の内容、研究機関の方針を踏まえて、publicまたはprivateを選びます。
GitHubに表示されるリモートURLを追加し、確認済みの履歴をpushします。
git remote add origin https://github.com/ACCOUNT/REPOSITORY.git
git remote -v
git push -u origin main
例のアカウント名とリポジトリ名は、自分のものに置き換えてください。認証には、ブラウザーでの認可、認証情報マネージャー、SSH鍵、GitHub CLIなどを使います。Personal Access TokenをリモートURL、スクリプト、READMEに埋め込んではいけません。
privateリポジトリは閲覧者を制限しますが、秘密情報や、再配布できないデータを不必要に置いてよい理由にはなりません。
毎日の作業は簡単な手順でよい
最初の研究用リポジトリに、高度なブランチ戦略は必要ありません。次の流れから始めます。
git status
git diff
git add src/analyze.py tests/test_analysis.py method/analysis-contract.yaml
git diff --cached
git commit -m "Apply reviewed salinity filter"
git push
大事な習慣は次の五つです。
- ステージ前の変更を見る
- 一つの判断に関係するファイルだけをステージする
- ステージ済みの変更を見る
- 判断内容が分かるメッセージでコミットする
- 確認済みの履歴を共有リポジトリへpushする
Gitは何が変わったかを記録します。なぜ変えたかは、解析方法を記したファイルとコミットメッセージで説明します。
科学的な変更はブランチで確認する
結果に影響しそうな変更では、ブランチを作ります。
git switch -c revise-qc-filter
解析方法を記したファイル、コード、テストを一緒に変更します。READMEやDockerfileで定めた環境で解析を実行し、途中の計算値と出力を確認してから、ブランチをpushします。
GitHubのPull Requestには、次の情報を記載します。
- どの研究上の課題や不具合を扱うか
- 変数、単位、品質管理、式を変更したか
- どのテストと解析コマンドを実行したか
- どの出力が、なぜ変わったか
- 専門家による確認がまだ必要な点は何か
Pull Requestにすれば、共同研究者が変更内容を確認できます。ただし、承認ボタンを押しただけでは、計算が科学的に正しいという根拠にはなりません。
結果と使用したコードを結び付ける
確認済みの結果を学位論文、報告書、論文原稿に使うときは、コミットIDを記録します。
git rev-parse HEAD
git show --stat HEAD
分かりやすいタグを付けることもできます。
git tag -a analysis-v1 -m "Code used for the reviewed analysis"
git show analysis-v1
git push origin analysis-v1
コミットまたはタグと一緒に、次の情報を記録します。
- 入力データのスナップショットまたはチェックサム
- パラメーターファイル
- ソフトウェア環境
- 結果を作ったコマンド
コミットIDやタグだけで特定できるのはコードです。別に保管したデータや、コミットしていないパラメーターまでは特定できません。
大容量の研究ファイルを置く場所
ファイルの役割に合わせて保存先を選びます。
| ファイルの種類 | 適した保存先 |
|---|---|
| コード、テキスト設定、解析方法の説明 | 通常のGit |
| 小さな合成テストデータ | 通常のGit |
| Gitの履歴と一緒に管理する必要がある少数の大容量ファイル | Git LFSを検討 |
| 大容量の元データ、頻繁に再生成するバイナリ | データリポジトリまたはオブジェクトストレージ |
| 引用対象として公開するデータセット | 安定した識別子やDOIを提供するリポジトリ |
| 認証情報 | パスワードマネージャーまたは秘密情報管理システム |
Git LFSは、Gitにポインターファイルだけを置き、大きなファイル本体は別のストレージに保存します。数の限られたバイナリには役立ちますが、容量、通信量、ファイルサイズの制限は残ります。更新が続く数TB規模のデータ置き場が、そのままGit LFS向きになるわけではありません。
大きなファイルをステージしただけなら、ステージから外して除外規則を追加します。パソコンには残し、Gitの追跡だけを止めるには次を使います。
git rm --cached data/raw/filename.nc
このコマンドでは、以前のコミットからファイルは消えません。大容量ファイルや機密ファイルをすでにpushした場合は、GitHubが案内する手順を確認し、共同研究者と調整してから共有履歴を書き換えます。
秘密情報は削除しただけでは対処できない
コミット前にgit statusとgit diff --cachedを確認します。.env、APIキー、アクセストークン、クラウド認証情報、秘密鍵、パスワードはGitの外で管理してください。
認証情報がコミットに入ってしまった場合は、まず漏えいしたものとして扱い、失効させて再発行します。作業フォルダのファイルを消したり、.gitignoreに書き足したりしても、リポジトリの履歴からは消えません。
Gitだけでは研究結果を再現できない
GitとGitHubが保存するのは、コードの履歴とレビューです。Python本体、システムライブラリ、インストール済みパッケージまでは保存しません。研究の解析環境を再現可能にする方法:Docker入門 では、その実行環境を記録する方法を説明します。
また、Gitは計算の正しさを検証するものでもありません。エージェントに解析コードを変更させる場合は、Codex・Claude Codeで「動くけれど間違った」研究コードを防ぐ方法 の確認手順も参考になります。
Argoを扱う研究では、スクリプトを書き始める前に、OceanGraphで解析対象にするプロファイルを絞り込めます。解析用にダウンロードしたファイルはGitの管理外に置き、WMO ID、サイクル、取得日、選んだ理由を記録します。操作方法は Search and Bookmark(英語) と Analysis Lab: Vertical Profiles(英語) を参照してください。
研究用リポジトリの完成目安
研究用リポジトリでは、同じデータを利用できる別の研究者が次のことを確認できる状態を目標にします。
- 報告した結果を、どのコードで作ったか
- 二つの時点の間で何が変わったか
- 入力データをどこから取得したか
- 同じ入力をどう入手または特定するか
- どのコマンドと環境を使うか
- どのテストと科学的確認を行ったか
Gitは履歴を残し、GitHubはその履歴とレビューを共有する場所になります。解析手法、データの入手元や処理条件、検証結果、解釈は、研究チームが自分で残す必要があります。
このリポジトリ運用やレビューの仕組みを自組織だけで整えるのが難しい場合は、下の問い合わせ導線から、環境構築・実装支援についてもご相談いただけます。
お問い合わせ
構築・実装支援とアノテーション業務
環境構築や設計・実装の支援、アノテーション業務の委託について、ご相談いただけます。
関連記事と公式資料
次に読む記事:
公式資料:
