datalad 是做什麼的?
概觀
DataLad 是一個基於 Git 和 git-annex 的資料管理層。Git 負責追蹤資料集結構、小型文字檔案以及歷史記錄。git-annex 則負責追蹤大型檔案的內容,將每個檔案儲存為一個金鑰,並將位元組資料存放在不一定在本機儲存庫中的地方。
這個分離架構是最需要理解的核心概念,因為它意味著新複製的資料集包含完整的歷史記錄和完整的檔案清單,但幾乎不包含任何資料。一個 100 TB 的資料集在數秒內完成複製,僅佔用數 MB 空間。資料只有在被要求時才會逐個檔案透過 datalad get 指令送達。
DataLad 提供的第二個功能是溯源。datalad run 執行一個命令,並將結果與命令、輸入和輸出的機器可讀記錄一起提交。datalad rerun 讀取該記錄並重新執行。這將「這個圖表是如何產生的」從考古問題轉變為一個指令。
何時使用 DataLad 而非純 Git
當以下任一情況成立時,請使用 DataLad:
- 檔案太大,Git 難以處理,或總量超過所有協作者願意儲存在本機的容量。
- 資料存放在多個位置(實驗室伺服器、叢集暫存區、S3、超級電腦),且需要知道哪些副本存在。
- 分析必須可重新執行,且單純的提交訊息不足以作為證據。
- 正在使用來自 OpenNeuro、DANDI 或
datasets.datalad.org的已發布資料集,這些資料集以 DataLad 資料集形式發布。 - 專案中包含巢狀的其他資料集,且希望每個資料集保留其獨立的歷史記錄。
當儲存庫僅包含程式碼和純文字、所有內容都能輕鬆容納在 Git 中,且無人需要部分檢出時,請使用純 Git。在小型純程式碼儲存庫上疊加 DataLad 只會增加間接性,而沒有任何好處。
安裝
# git-annex 並非用 Python 編寫,但如果已安裝 Git 本身,可從 PyPI 取得:
uv pip install git-annex
# 也可以先從系統安裝
# (Debian/Ubuntu: apt install git-annex; macOS: brew install git-annex;
# conda-forge: conda install -c conda-forge git-annex)
uv pip install datalad
uv pip install datalad-container # 僅用於 containers-run
datalad wtf --section dependencies # 確認 git-annex 版本可見
PyPI 上的 git-annex 套件會以 wheel 形式為 Linux、macOS 和 Windows 提供預建二進位檔,而不是編譯 Haskell 原始碼,因此它像任何其他 Python 依賴項一樣安裝,並且可以與 DataLad 固定在相同的環境中。它不附帶 Git。
datalad wtf 會列印已解析的環境,是當行為看似不可能時第一個要執行的指令。老舊或遺失的 git-annex 是許多令人困惑的錯誤背後的原因。
DataLad 本身採用 MIT 授權。git-annex 是另一個採用 AGPL 的工具,這僅在您重新發布修改過的 git-annex 而非單純呼叫它時才重要。
最常遇到的失敗:指標不是資料
執行 datalad clone 後,被 annex 管理的檔案會以指向 .git/annex/objects/ 的符號連結存在(或在無法使用符號連結的系統上,如 Windows 或功能受限的檔案系統,則為小型指標檔)。尚未下載任何內容。
datalad clone https://github.com/OpenNeuroDatasets/ds000001.git
cd ds000001
ls sub-01/anat/ # 檔案已列出
python -c "import nibabel; nibabel.load('sub-01/anat/sub-01_T1w.nii.gz')" # 失敗
datalad get sub-01/anat/sub-01_T1w.nii.gz # 現在可以了
需要辨識的失敗模式:工具報告檔案為空、截斷、損毀、「不是 gzip 檔案」或損毀的符號連結,且磁碟上的檔案大小僅幾百位元組。這是指標,而非損毀的下載。在讀取資料之前執行 datalad get,並將「檔案存在」視為其內容已存在的證據不足。
在分析觸及目錄之前,明確擷取它:
datalad get sub-01/ # 路徑下的所有內容
datalad get -r . # 所有內容,包括子資料集
datalad get -n -r . # 僅子資料集結構,不包含檔案內容
datalad status --annex 會報告本機已存在多少內容,而 git annex whereis <path> 會報告哪些儲存庫包含特定檔案。whereis 讀取已記錄的狀態,不會聯繫遠端,因此它告訴您的是 git-annex 上次學到的資訊,而非當前的實際狀況。
請參閱 data-access.md 以了解如何尋找資料集、子資料集行為、安全地丟棄內容以及修復資料集。
使用 datalad run 記錄溯源
在方法學情境中,datalad run 是使用 DataLad 的原因。它將命令及其效果保存在同一個提交中:
datalad run -m "extract brain mask" \
--input "sub-01/anat/sub-01_T1w.nii.gz" \
--output "derivatives/sub-01_brain.nii.gz" \
"bet {inputs} {outputs} -m"
每個部分的作用,以及為何省略會造成問題:
--input在執行前擷取內容,因此命令不會因指標檔而失敗。它同時記錄依賴關係,這讓rerun能夠在不同的機器上擷取相同的輸入。--output會先解鎖或移除目標,以避免 git-annex 拒絕寫入它正在保護的內容。沒有這個選項,第二次執行相同命令通常會因附加檔案看起來是唯讀而導致權限錯誤。{inputs}和{outputs}會展開為對應值。{pwd}、{dspath}和{tmpdir}也可使用,而{inputs[0]}可索引單個項目。- 提交訊息在
=== Do not change lines below ===和^^^ Do not change lines above ^^^之間攜帶 JSON 執行記錄。請勿手動編輯該區塊;rerun會解析它。
datalad run 在資料集存在未儲存的修改時會拒絕啟動,因為不乾淨的起始狀態會使記錄不可靠。請先儲存或捨棄修改,或傳遞 --explicit 宣告所列的輸入和輸出即為完整故事。使用 --dry-run basic 或 --dry-run command 在提交前檢查命令。
未產生任何變更的執行不會產生提交,與 datalad save 的行為完全相同。
重新執行
datalad rerun # 重做 HEAD 記錄的執行
datalad rerun --report # 顯示將執行的操作,不執行任何變更
datalad rerun --script recompute.sh # 提取命令而非執行它們
datalad rerun --since <commit> -b check <revision> # 將一系列執行重播到新分支
將執行重播到分支 (-b) 是測試可重現性的安全方式:重播會落地到其他地方,而與原始分支的比較可以回答輸出是否完全相同。
容器
使用 datalad-container 擴充套件,註冊映像檔一次,之後每次執行都會記錄是哪個映像檔產生了輸出:
datalad containers-add fsl --url docker://brainlife/fsl:6.0.4
datalad containers-run -n fsl -m "brain mask in container" \
--input "sub-01/anat/sub-01_T1w.nii.gz" \
--output "derivatives/sub-01_brain.nii.gz" \
"bet {inputs} {outputs} -m"
映像檔本身會記錄在資料集中,因此軟體環境會隨資料和溯源記錄一起移動,而不是存在於某人的 shell 歷史中。當只設定了一個容器時,可以省略 -n。
請參閱 provenance.md 以了解 STAMPED 原則和 YODA 專案佈局、執行記錄格式、--explicit 和 --assume-ready 語意,以及將溯源匯出至 W3C PROV。
儲存與檢查變更
datalad status # 哪些變更了,包括子資料集狀態
datalad save -m "add QC report" path/to/file
datalad save -m "checkpoint" -r # 遞迴進入子資料集
datalad save -m "small text file" --to-git notes.md
datalad save 會根據資料集的 .gitattributes 決定每個檔案要加入 Git 還是 git-annex。使用 --to-git 強制將檔案加入 Git,這對於應該保持直接可讀的程式碼和小型文字檔案是正確的做法。yoda 程序(datalad create -c yoda)會自動為 code/、README.md 和 CHANGELOG.md 設定此項。
建立資料集
datalad create my_dataset # 純資料集
datalad create -c yoda my_analysis # 分析佈局(code/ 由 Git 追蹤,
# 預先設定 README.md 和 CHANGELOG.md)
datalad create -d . inputs/raw # 在現有資料集下註冊新的子資料集
-c yoda 會套用 provenance.md 中描述的分析專案佈局。-d . 用於將新資料集註冊為父資料集的子資料集,而不是在內部留下一個不相關的儲存庫。
發布
DataLad 資料集通常同時發布到兩個地方:一個 Git 託管服務用於歷史記錄,一個儲存遠端用於被 annex 管理的內容。
datalad create-sibling-github myaccount/mydataset
git annex initremote store type=S3 bucket=my-bucket encryption=none autoenable=true
datalad siblings configure -s github --publish-depends store
datalad push --to github
Git 兄弟站點和儲存兄弟站點是透過不同的工具建立,這是刻意的。Git 兄弟站點是一個 Git 遠端,datalad create-sibling-* 負責處理託管服務的這部分。S3 儲存桶(或 WebDAV、SSH 目錄)是一個 git-annex 特殊遠端,而不是 Git 遠端,因此需要使用 git annex initremote 建立。datalad siblings 之後會自動偵測特殊遠端並像對待其他遠端一樣處理。在此處使用 datalad siblings add --url s3://... 是此章節旨在避免的錯誤:--url 是 Git 遠端 URL,S3 不是,而下面的 push --to github 在 --publish-depends 跳躍時會失敗。
--publish-depends 用於防止常見的發布中斷問題:Git 儲存庫的歷史記錄引用了從未上傳的內容,導致協作者成功複製,但每次 datalad get 都失敗。宣告依賴關係可確保儲存兄弟站點每次都優先發布。
datalad push 會同時發送 Git 歷史記錄,以及(預設情況下,--data auto-if-wanted)目標設定為需要的被 annex 管理的內容。傳遞 --data anything 可推送所有內容,無論目標的偏好設定為何。
請參閱 publishing.md 以了解 RIA 儲存、特殊遠端、憑證處理以及設定哪個兄弟站點儲存哪些內容。
釋放磁碟空間
git annex whereis sub-01/ # 先確認存在另一個副本
datalad drop sub-01/ # 移除本機內容,保留指標
datalad drop --what all --reckless kill <path> # 最後手段,會銷毀資料
當 datalad drop 無法驗證內容的另一個副本存在時,預設會拒絕執行,這是一種安全檢查而非障礙。--nocheck 和 --if-dirty 已被棄用;目前的寫法是 --reckless availability,其意義如其所述。--what 用於選擇 filecontent(預設值)、allkeys、datasets 和 all。
值得了解的失敗模式
| 症狀 | 原因 | 修正方法 |
|---|---|---|
| 檔案讀取為空、截斷或損毀的符號連結 | 內容未被擷取;僅存在指標 | datalad get <path> |
| 寫入現有輸出時出現「權限被拒絕」 | git-annex 對被 annex 管理的內容進行寫入保護 | 使用 --output 宣告,或執行 datalad unlock <path> |
datalad run 拒絕啟動 | 資料集存在未儲存的變更 | 先執行 datalad save,或傳遞 --explicit |
datalad drop 拒絕 | 無法驗證內容的第二個副本 | 先推送到兄弟站點,或接受 --reckless availability |
協作者複製成功,但每次 get 都失敗 | 歷史記錄已發布,但內容未發布 | 發布儲存兄弟站點,並設定 --publish-depends |
| 複製成功,但子資料集目錄為空 | 子資料集預設不會被安裝 | datalad get -n -r .,然後 get 需要的路徑 |
| 指令行為看似不可能 | git-annex 遺失或太舊 | datalad wtf --section dependencies |
詳細參考資料
- data-access.md:尋找已發布的資料集(
registry.datalad.org、OpenNeuro、DANDI、datasets.datalad.org和///捷徑)、複製和 get 選項、子資料集處理、被 annex 管理的內容狀態、丟棄和移除,以及fsck修復。 - provenance.md:STAMPED 原則和 YODA 佈局、執行記錄格式、
run和rerun選項的完整說明、containers-run,以及將 DataLad 溯源匯出至 W3C PROV 的當前狀態。 - publishing.md:兄弟站點及其動作、
create-sibling-*變體、RIA 儲存、特殊遠端、push語意以及憑證處理。
相關技能
bids 技能涵蓋了大多數透過 DataLad 發布的神經影像資料集所遵循的腦影像資料結構。一個典型的工作流程是使用 DataLad 複製一個 BIDS 資料集,使用 BIDS 工具進行驗證,然後在 datalad containers-run 下執行一個 BIDS-App,使衍生資料攜帶溯源記錄。
主要來源
- DataLad 文件:https://docs.datalad.org/en/stable/
- DataLad 手冊:https://handbook.datalad.org/en/latest/
datalad run章節:https://handbook.datalad.org/en/latest/basics/101-108-run.html- YODA 原則:https://handbook.datalad.org/en/latest/basics/101-127-yoda.html
- STAMPED 原則(從 YODA 實作):https://stamped-principles.org
- datalad-container:https://docs.datalad.org/projects/container/en/stable/
- git-annex:https://git-annex.branchable.com/
- 資料集註冊表:https://registry.datalad.org
致謝
此技能的主題範圍部分參考了 @bcmcpher 的 MIT 授權 datalad-cli。