mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-11 07:18:28 +01:00
pygit2, gitpython: handle relpaths in reset/checkout_index backends (#5414)
* Make minor change that fixes things for some reason While working on vscode-dvc, both mattseddon and I found that this change allows us to run `dvc exp run`, and we cannot otherwise. I don't exactly know what this change does, and I'm hoping someone more knowledgable does- after which we can give this PR a better name. * test relpaths in git backend funcs which take path lists * gitpython: handle relpaths in reset and checkout_index * use / for git relpaths on windows Co-authored-by: Peter Rowlands <[email protected]>
This commit is contained in:
@@ -3,13 +3,13 @@ import locale
|
||||
import logging
|
||||
import os
|
||||
from functools import partial
|
||||
from typing import Callable, Iterable, Mapping, Optional, Tuple
|
||||
from typing import Callable, Iterable, List, Mapping, Optional, Tuple
|
||||
|
||||
from funcy import first, ignore
|
||||
|
||||
from dvc.progress import Tqdm
|
||||
from dvc.scm.base import CloneError, MergeConflictError, RevError, SCMError
|
||||
from dvc.utils import fix_env, is_binary
|
||||
from dvc.utils import fix_env, is_binary, relpath
|
||||
|
||||
from ..objects import GitObject
|
||||
from .base import BaseGitBackend
|
||||
@@ -526,7 +526,18 @@ class GitPythonBackend(BaseGitBackend): # pylint:disable=abstract-method
|
||||
raise NotImplementedError
|
||||
|
||||
def reset(self, hard: bool = False, paths: Iterable[str] = None):
|
||||
self.repo.head.reset(index=True, working_tree=hard, paths=paths)
|
||||
if paths:
|
||||
paths_list: Optional[List[str]] = [
|
||||
relpath(path, self.root_dir) for path in paths
|
||||
]
|
||||
if os.name == "nt":
|
||||
paths_list = [
|
||||
path.replace("\\", "/")
|
||||
for path in paths_list # type: ignore[union-attr]
|
||||
]
|
||||
else:
|
||||
paths_list = None
|
||||
self.repo.head.reset(index=True, working_tree=hard, paths=paths_list)
|
||||
|
||||
def checkout_index(
|
||||
self,
|
||||
@@ -548,7 +559,18 @@ class GitPythonBackend(BaseGitBackend): # pylint:disable=abstract-method
|
||||
args.append(".")
|
||||
self.repo.git.checkout(*args)
|
||||
else:
|
||||
self.repo.index.checkout(paths=paths, force=force)
|
||||
if paths:
|
||||
paths_list: Optional[List[str]] = [
|
||||
relpath(path, self.root_dir) for path in paths
|
||||
]
|
||||
if os.name == "nt":
|
||||
paths_list = [
|
||||
path.replace("\\", "/")
|
||||
for path in paths_list # type: ignore[union-attr]
|
||||
]
|
||||
else:
|
||||
paths_list = None
|
||||
self.repo.index.checkout(paths=paths_list, force=force)
|
||||
|
||||
def status(
|
||||
self, ignored: bool = False
|
||||
|
||||
@@ -183,7 +183,10 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
||||
raise NotImplementedError
|
||||
|
||||
def is_ignored(self, path: str) -> bool:
|
||||
return self.repo.path_is_ignored(relpath(path, self.root_dir))
|
||||
rel = relpath(path, self.root_dir)
|
||||
if os.name == "nt":
|
||||
rel.replace("\\", "/")
|
||||
return self.repo.path_is_ignored(rel)
|
||||
|
||||
def set_ref(
|
||||
self,
|
||||
@@ -287,7 +290,9 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
||||
tree = self.repo.revparse_single("HEAD").tree
|
||||
for path in paths:
|
||||
rel = relpath(path, self.root_dir)
|
||||
obj = tree[relpath(rel, self.root_dir)]
|
||||
if os.name == "nt":
|
||||
rel = rel.replace("\\", "/")
|
||||
obj = tree[rel]
|
||||
self.repo.index.add(IndexEntry(rel, obj.oid, obj.filemode))
|
||||
self.repo.index.write()
|
||||
elif hard:
|
||||
@@ -324,6 +329,11 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
||||
path_list: Optional[List[str]] = [
|
||||
relpath(path, self.root_dir) for path in paths
|
||||
]
|
||||
if os.name == "nt":
|
||||
path_list = [
|
||||
path.replace("\\", "/")
|
||||
for path in path_list # type: ignore[union-attr]
|
||||
]
|
||||
else:
|
||||
path_list = None
|
||||
self.repo.checkout_index(
|
||||
|
||||
+24
-13
@@ -363,16 +363,21 @@ def test_checkout_index(tmp_dir, scm, git):
|
||||
if git.test_backend == "dulwich":
|
||||
pytest.skip()
|
||||
|
||||
tmp_dir.scm_gen({"foo": "foo", "bar": "bar"}, commit="init")
|
||||
tmp_dir.gen("foo", "baz")
|
||||
tmp_dir.scm_gen(
|
||||
{"foo": "foo", "bar": "bar", "dir": {"baz": "baz"}}, commit="init"
|
||||
)
|
||||
tmp_dir.gen({"foo": "baz", "dir": {"baz": "foo"}})
|
||||
|
||||
git.checkout_index(["foo"], force=True)
|
||||
with (tmp_dir / "dir").chdir():
|
||||
git.checkout_index([os.path.join("..", "foo"), "baz"], force=True)
|
||||
assert (tmp_dir / "foo").read_text() == "foo"
|
||||
assert (tmp_dir / "dir" / "baz").read_text() == "baz"
|
||||
|
||||
tmp_dir.gen({"foo": "baz", "bar": "baz"})
|
||||
tmp_dir.gen({"foo": "baz", "bar": "baz", "dir": {"baz": "foo"}})
|
||||
git.checkout_index(force=True)
|
||||
assert (tmp_dir / "foo").read_text() == "foo"
|
||||
assert (tmp_dir / "bar").read_text() == "bar"
|
||||
assert (tmp_dir / "dir" / "baz").read_text() == "baz"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -471,31 +476,37 @@ def test_reset(tmp_dir, scm, git):
|
||||
if git.test_backend == "dulwich":
|
||||
pytest.skip()
|
||||
|
||||
tmp_dir.scm_gen({"foo": "foo"}, commit="init")
|
||||
tmp_dir.scm_gen(
|
||||
{"foo": "foo", "dir": {"baz": "baz"}}, commit="init",
|
||||
)
|
||||
|
||||
tmp_dir.gen("foo", "bar")
|
||||
scm.add(["foo"])
|
||||
tmp_dir.gen({"foo": "bar", "dir": {"baz": "bar"}})
|
||||
scm.add(["foo", os.path.join("dir", "baz")])
|
||||
git.reset()
|
||||
assert (tmp_dir / "foo").read_text() == "bar"
|
||||
assert (tmp_dir / "dir" / "baz").read_text() == "bar"
|
||||
staged, unstaged, _ = scm.status()
|
||||
assert len(staged) == 0
|
||||
assert list(unstaged) == ["foo"]
|
||||
assert set(unstaged) == {"foo", "dir/baz"}
|
||||
|
||||
scm.add(["foo"])
|
||||
scm.add(["foo", os.path.join("dir", "baz")])
|
||||
git.reset(hard=True)
|
||||
assert (tmp_dir / "foo").read_text() == "foo"
|
||||
assert (tmp_dir / "dir" / "baz").read_text() == "baz"
|
||||
staged, unstaged, _ = scm.status()
|
||||
assert len(staged) == 0
|
||||
assert len(unstaged) == 0
|
||||
|
||||
tmp_dir.gen({"foo": "bar", "bar": "bar"})
|
||||
scm.add(["foo", "bar"])
|
||||
git.reset(paths=["foo"])
|
||||
tmp_dir.gen({"foo": "bar", "bar": "bar", "dir": {"baz": "bar"}})
|
||||
scm.add(["foo", "bar", os.path.join("dir", "baz")])
|
||||
with (tmp_dir / "dir").chdir():
|
||||
git.reset(paths=[os.path.join("..", "foo"), os.path.join("baz")])
|
||||
assert (tmp_dir / "foo").read_text() == "bar"
|
||||
assert (tmp_dir / "bar").read_text() == "bar"
|
||||
assert (tmp_dir / "dir" / "baz").read_text() == "bar"
|
||||
staged, unstaged, _ = scm.status()
|
||||
assert len(staged) == 1
|
||||
assert len(unstaged) == 1
|
||||
assert len(unstaged) == 2
|
||||
|
||||
|
||||
def test_remind_to_track(scm, caplog):
|
||||
|
||||
Reference in New Issue
Block a user