diff --git a/dvc/commands/update.py b/dvc/commands/update.py index fcf9243f4..ce5446d41 100644 --- a/dvc/commands/update.py +++ b/dvc/commands/update.py @@ -31,7 +31,8 @@ class CmdUpdate(CmdBase): def add_parser(subparsers, parent_parser): UPDATE_HELP = ( "Update data artifact imported (via dvc import or dvc import-url) " - "from an external DVC repository or URL." + "from an external DVC repository or URL, or update data from a " + "DVC worktree remote." ) update_parser = subparsers.add_parser( "update", diff --git a/dvc/repo/update.py b/dvc/repo/update.py index 9c620a0ca..17e19fbf2 100644 --- a/dvc/repo/update.py +++ b/dvc/repo/update.py @@ -1,7 +1,13 @@ +from typing import TYPE_CHECKING, List + from dvc.exceptions import InvalidArgumentError +from dvc.stage.exceptions import StageUpdateError from . import locked +if TYPE_CHECKING: + from dvc.repo.stage import StageInfo + @locked def update( @@ -15,6 +21,7 @@ def update( jobs=None, ): from ..dvcfile import Dvcfile + from .worktree import update_worktree_stages if not targets: targets = [None] @@ -28,15 +35,21 @@ def update( ) if not to_remote and remote: - raise InvalidArgumentError( - "--remote can't be used without --to-remote" - ) + if not self.cloud.get_remote(name=remote).worktree: + raise InvalidArgumentError( + "--remote can't be used without --to-remote" + ) - stages = set() - for target in targets: - stages.update(self.stage.collect(target, recursive=recursive)) + import_stages = set() + other_stage_infos: List["StageInfo"] = [] - for stage in stages: + for stage_info in self.index.collect_targets(targets, recursive=recursive): + if stage_info.stage.is_import: + import_stages.add(stage_info.stage) + else: + other_stage_infos.append(stage_info) + + for stage in import_stages: stage.update( rev, to_remote=to_remote, @@ -47,4 +60,17 @@ def update( dvcfile = Dvcfile(self, stage.path) dvcfile.dump(stage) + if other_stage_infos: + remote_obj = self.cloud.get_remote(name=remote) + if not remote_obj.worktree: + raise StageUpdateError(other_stage_infos[0].stage.relpath) + update_worktree_stages( + self, + other_stage_infos, + remote_obj, + ) + + stages = import_stages | { + stage_info.stage for stage_info in other_stage_infos + } return list(stages)