diff --git a/src/scmrepo/base.py b/src/scmrepo/base.py index a40fd8b..53447aa 100644 --- a/src/scmrepo/base.py +++ b/src/scmrepo/base.py @@ -103,3 +103,7 @@ def close(self): def _reset(self) -> None: pass + + def list_submodules(self) -> list[str]: + """Returns a list of submodules in the repo.""" + return [] diff --git a/src/scmrepo/git/__init__.py b/src/scmrepo/git/__init__.py index e9ae19a..16649ee 100644 --- a/src/scmrepo/git/__init__.py +++ b/src/scmrepo/git/__init__.py @@ -412,6 +412,7 @@ def fetch_refspecs( check_attr = partialmethod(_backend_func, "check_attr") get_tree_obj = partialmethod(_backend_func, "get_tree_obj") + list_submodules = partialmethod(_backend_func, "list_submodules") def branch_revs(self, branch: str, end_rev: Optional[str] = None) -> Iterable[str]: """Iterate over revisions in a given branch (from newest to oldest). diff --git a/src/scmrepo/git/backend/dulwich/__init__.py b/src/scmrepo/git/backend/dulwich/__init__.py index f75d27a..6b64c34 100644 --- a/src/scmrepo/git/backend/dulwich/__init__.py +++ b/src/scmrepo/git/backend/dulwich/__init__.py @@ -199,6 +199,9 @@ def __init__( # pylint:disable=W0231 self._submodules: dict[str, str] = self._find_submodules() self._stashes: dict = {} + def list_submodules(self) -> list[str]: + raise NotImplementedError + def _find_submodules(self) -> dict[str, str]: """Return dict mapping submodule names to submodule paths. @@ -349,21 +352,6 @@ def add( def _expand_paths(self, paths: list[str], force: bool = False) -> Iterator[str]: for path in paths: - if not os.path.isabs(path) and self._submodules: - # NOTE: If path is inside a submodule, Dulwich expects the - # staged paths to be relative to the submodule root (not the - # parent git repo root). We append path to root_dir here so - # that the result of relpath(path, root_dir) is actually the - # path relative to the submodule root. - fs_path = relpath(path, self.root_dir) - for sm_path in self._submodules.values(): - assert self.root_dir - if fs_path.startswith(sm_path): - path = os.path.join( - self.root_dir, - relpath(fs_path, sm_path), - ) - break if os.path.isdir(path): for root, _, fs in os.walk(path): for fpath in fs: diff --git a/src/scmrepo/git/backend/gitpython.py b/src/scmrepo/git/backend/gitpython.py index 5498324..d887675 100644 --- a/src/scmrepo/git/backend/gitpython.py +++ b/src/scmrepo/git/backend/gitpython.py @@ -789,3 +789,6 @@ def check_attr( if info == "unset": return False return info + + def list_submodules(self) -> list[str]: + raise NotImplementedError diff --git a/src/scmrepo/git/backend/pygit2/__init__.py b/src/scmrepo/git/backend/pygit2/__init__.py index 07d311e..4646094 100644 --- a/src/scmrepo/git/backend/pygit2/__init__.py +++ b/src/scmrepo/git/backend/pygit2/__init__.py @@ -269,6 +269,9 @@ def release_odb_handles(self): # can be reacquired later as needed. self.repo.free() + def list_submodules(self) -> list[str]: + return self.repo.listall_submodules() + @classmethod def clone( cls, @@ -865,6 +868,11 @@ def reset(self, hard: bool = False, paths: Optional[Iterable[str]] = None): from pygit2 import IndexEntry from pygit2.enums import ResetMode + if self.list_submodules(): + raise NotImplementedError( + "pygit2 seems to remove files from submodules on reset" + ) + self.repo.index.read(False) # type: ignore[attr-defined] if paths is not None: tree = self.repo.revparse_single("HEAD").tree # type: ignore[attr-defined]