commit
记录由 DVC 跟踪的文件或目录的更改。
概要
usage: dvc commit [-h] [-q | -v] [-f] [-d] [-R]
[--no-relink] [targets [targets ...]]
positional arguments:
targets Limit command scope to these stages or .dvc files.
Using -R, directories to search for stages or .dvc
files can also be given.
描述
将 DVC 跟踪的文件和目录当前的内容存储到 缓存 中,并在需要时更新 dvc.lock
或 .dvc
文件。这会强制 DVC 接受工作区(workspace)中当前被跟踪数据的所有变更内容。
💡 为方便起见,DVC 提供了一个 pre-commit Git 钩子,用于提醒你在必要时执行 dvc commit
。更多信息请参见 dvc install
。
dvc commit
提供了一种方式来完成那些使用了 --no-commit
或 --no-exec
选项的数据跟踪命令(如 dvc add
、dvc repro
、dvc import
等)。这些选项会导致命令在处理每个文件或目录时跳过以下步骤:
通常跳过这些步骤是为了避免缓存尚未完成的数据,例如在探索不同数据集时。
dvc commit
的一些使用场景包括:
-
作为已跟踪数据的
dvc add
替代方案:dvc commit
可以将所有更改添加到已被 DVC 跟踪的文件或目录中,而无需逐一指定目标。 -
我们经常修改源代码、配置文件或其他在
dvc.yaml
中定义为依赖项(deps
字段)的文件,但这些修改并不会导致输出发生变化,例如:重新格式化输入数据、添加代码注释等。然而,DVC 会检测到所有依赖项的变化,并提示你重新运行相应管道(dvc repro
)。此时你可以改用dvc commit
来强制接受这些新版本,而无需执行阶段命令。 -
有时在执行某个阶段后,我们才发现其部分依赖项或输出未在
dvc.yaml
中正确定义。此时可以添加缺失的 deps/outs,而无需重新执行该阶段,但需要使用dvc commit
来完成操作(详见链接)。 -
也可以手动执行阶段命令(不使用
dvc repro
),或手动修改其输出文件或目录。完成后,使用dvc commit
将更改注册到 DVC 中。请注意,在重写由 DVC 跟踪的文件/目录之前,通常需要先执行
dvc unprotect
(或删除输出文件)。
请注意,应尽量避免这些强制更新缓存、dvc.lock
和 .dvc
文件的情况。在这种情况下,DVC 无法保证结果的可复现性。
选项
-
-d
,--with-deps
- 仅在指定targets
时有意义。此选项通过解析目标阶段或.dvc
文件的所有依赖关系来确定要提交的文件:DVC 会从相应管道中的目标节点向后搜索。该操作不会提交在目标阶段之后的阶段中引用的文件。 -
-R
,--recursive
- 通过搜索每个目标目录及其子目录中的阶段(位于dvc.yaml
中)或.dvc
文件来确定要提交的文件。如果targets
中没有目录,则此选项无效。 -
-f
,--force
- 即使依赖项或输出的哈希值未发生变化,也会提交数据。 -
--no-relink
- 不从缓存重新创建文件链接类型到工作区。在处理大量文件时可节省时间,但即使配置了其他链接类型,文件仍可能从缓存中重新建立硬链接或被复制。 -
-h
,--help
- 打印使用说明/帮助信息,然后退出。 -
-q
,--quiet
- 不向标准输出写入任何内容。如果没有问题则以 0 退出,否则以 1 退出。 -
-v
,--verbose
- 显示执行dvc add
命令时的详细跟踪信息。
示例
让我们使用一个包含一些数据、代码、机器学习模型和流水线阶段的简单工作区,例如为快速入门创建的DVC 项目。然后我们可以观察在不同情况下使用 git commit
和dvc commit
会发生什么。
如果你还没有该项目,请先克隆我们的示例仓库:
$ git clone https://github.com/iterative/example-get-started
$ cd example-get-started
现在让我们安装依赖项。但在执行此操作之前,我们强烈建议创建一个 虚拟环境:
$ python3 -m venv .env
$ source .env/bin/activate
$ pip install -r src/requirements.txt
使用以下命令下载预计算的数据:
$ dvc pull -aT
示例:快速迭代
有时我们希望对配置、代码或数据进行多次修改,尝试不同的方法来改进某个阶段的输出结果。为了避免将不需要的中间结果填满缓存,可以使用dvc repro
命令的--no-commit
选项。当进展达到满意程度后,再使用dvc commit
将数据文件保存到缓存中。
在featurize
阶段中,会执行src/featurization.py
。一个有用的修改是调整该脚本的参数。这些参数定义在params.yaml
文件中。将max_features
参数的值更新为 6000,会改变最终生成的模型:
featurize:
max_features: 6000
ngrams: 2
这一修改会导致如果我们运行dvc repro
,则featurize
、train
和evaluate
阶段都会被执行。但如果我们想尝试多个max_features
的取值,并仅将最佳结果保存到缓存中,可以这样运行:
$ dvc repro --no-commit
我们可以随意多次运行此命令,以任意方式编辑params.yaml
,只要使用--no-commit
,数据就不会被保存到缓存中。让我们验证这一点:
第一次验证(通过dvc status
):
$ dvc status
featurize:
changed outs:
not in cache: data/features
train:
changed outs:
not in cache: model.pkl
现在我们可以查看缓存目录,确认新的model.pkl
版本确实不在缓存中。首先查看dvc.lock
中train
阶段的最新状态:
train:
cmd: python src/train.py data/features model.pkl
deps:
- path: data/features
md5: de03a7e34e003e54dde0d40582c6acf4.dir
- path: src/train.py
md5: ad8e71b2cca4334a7d3bb6495645068c
params:
params.yaml:
train.n_estimators: 100
train.seed: 20170428
outs:
- path: model.pkl
md5: 9aba000ba83b341a423a81eed8ff9238
为了验证这个model.pkl
实例是否在缓存中不存在,我们必须知道缓存文件的路径。在缓存目录中,哈希值的前两个字符用作子目录名,其余字符作为文件名。因此,如果该文件已被提交到缓存,它应出现在.dvc/cache/files/md5/9a
目录下。让我们检查一下:
$ ls .dvc/cache/files/md5/9a
ls: .dvc/cache/files/md5/9a: No such file or directory
如果我们确认对params.yaml
的更改已成功,就可以执行以下命令集:
$ dvc commit
$ dvc status
Data and pipelines are up to date.
$ ls .dvc/cache/files/md5/9a
ba000ba83b341a423a81eed8ff9238
我们已验证 dvc commit
已将更改保存到缓存中,并且新的 model.pkl
实例也已存在。
示例:不使用 DVC 执行阶段命令
有时你可能希望手动执行阶段命令(而不是使用 dvc repro
)。虽然你将无法获得 DVC 的帮助,但你可以自由运行任何命令,包括那些未在 dvc.yaml
中定义的命令。例如:
$ python src/featurization.py data/prepared data/features
$ python src/train.py data/features model.pkl
$ python src/evaluate.py model.pkl data/features auc.metric
和之前一样,dvc status
将显示哪些被跟踪的文件/目录发生了变化,当你的工作完成后,dvc commit
会将输出保存到 缓存 中。
示例:更新依赖项
有时我们希望以一种不会改变其结果的方式清理代码或配置文件。例如添加注释形式的内联文档、调整缩进、删除调试用的打印语句,或其他任何不会导致流水线阶段输出不同的修改。
$ git status -s
M src/train.py
$ dvc status
train:
changed deps:
modified: src/train.py
让我们编辑其中一个源代码文件。具体是哪一个并不重要。你会看到 Git 和 DVC 都识别到了变更。
如果此时运行 dvc repro
,该流水线将会被重新执行。但由于此次更改并无实际影响,这将浪费时间和 CPU 资源。特别是当相关阶段执行需要消耗大量资源时,这一点尤为关键。
$ git add src/train.py
$ git commit -m "CHANGED"
[master 72327bd] CHANGED
1 file changed, 2 insertions(+)
$ dvc commit
dependencies ['src/train.py'] of 'train.dvc' changed.
Are you sure you commit it? [y/n] y
$ dvc status
Data and pipelines are up to date.
对于不会产生不同结果的更改,无需重新运行整个流水线,只需在 Git 和 DVC 中都执行 commit
即可。