diff --git a/dvc/repo/move.py b/dvc/repo/move.py index 11a92861e..49d2361f5 100644 --- a/dvc/repo/move.py +++ b/dvc/repo/move.py @@ -1,7 +1,6 @@ import os from typing import TYPE_CHECKING -from dvc.exceptions import MoveNotDataSourceError from dvc.repo.scm_context import scm_context from . import locked @@ -38,7 +37,9 @@ def move(self: "Repo", from_path, to_path): """ from dvc import dependency, output from dvc.dvcfile import DVC_FILE_SUFFIX + from dvc.exceptions import MoveNotDataSourceError from dvc.stage import Stage + from dvc.stage.exceptions import StageFileAlreadyExistsError from dvc_objects.fs.local import LocalFileSystem from_out = output.loads_from(Stage(self), [from_path])[0] @@ -64,16 +65,20 @@ def move(self: "Repo", from_path, to_path): ) new_wdir = os.path.abspath(os.path.join(os.curdir, os.path.dirname(to_path))) to_path = os.path.relpath(to_path, new_wdir) - new_stage = self.stage.create( - single_stage=True, - fname=new_fname, - wdir=new_wdir, - outs=[to_path], - meta=stage.meta, - frozen=stage.frozen, - always_changed=stage.always_changed, - desc=stage.desc, - ) + try: + new_stage = self.stage.create( + single_stage=True, + fname=new_fname, + wdir=new_wdir, + outs=[to_path], + meta=stage.meta, + frozen=stage.frozen, + always_changed=stage.always_changed, + desc=stage.desc, + ) + except StageFileAlreadyExistsError: + # reraise to remove `--force` hint + raise StageFileAlreadyExistsError(f"{new_fname!r} already exists") from None else: new_stage = stage to_path = os.path.relpath(to_path, stage.wdir) diff --git a/tests/func/test_move.py b/tests/func/test_move.py index 5c0ca15c6..d1702d503 100644 --- a/tests/func/test_move.py +++ b/tests/func/test_move.py @@ -6,6 +6,7 @@ import pytest from dvc.cli import main from dvc.exceptions import MoveNotDataSourceError, OutputNotFoundError +from dvc.stage.exceptions import StageFileAlreadyExistsError def test_move(tmp_dir, dvc, scm): @@ -382,3 +383,12 @@ def test_all_metadata_are_preserved(tmp_dir, dvc, make_tmp_dir, path_func): contents["deps"][0] |= {"path": expected_path} contents |= {"md5": stage.md5} assert new_dvcfile.parse() == contents + + +def test_move_dst_stage_file_already_exists(tmp_dir, dvc): + tmp_dir.dvc_gen({"foo": "foo", "bar": "bar"}) + + with pytest.raises(StageFileAlreadyExistsError) as exc_info: + dvc.move("foo", "bar") + assert str(exc_info.value) == "'bar.dvc' already exists" + assert exc_info.value.__cause__ is None