diff --git a/git_config.py b/git_config.py index 84d347b1a..4facccda6 100644 --- a/git_config.py +++ b/git_config.py @@ -266,6 +266,13 @@ class GitConfig: except KeyError: old = [] + if self.file != self._SYSTEM_CONFIG: + # `git config --file` does not create missing parent directories + # (e.g. ~/.repoconfig/ on first use). + parent_dir = os.path.dirname(self.file) + if parent_dir: + os.makedirs(parent_dir, exist_ok=True) + if value is None: if old: del self._cache[key] @@ -444,6 +451,11 @@ class GitConfig: class RepoConfig(GitConfig): """User settings for repo itself.""" + # Keep separate caches from GitConfig, otherwise ForUser()/ForSystem() + # would return the already-cached ~/.gitconfig instance of the parent. + _ForUser = None + _ForSystem = None + @staticmethod def _getUserConfig(): repo_config_dir = os.getenv("REPO_CONFIG_DIR", os.path.expanduser("~")) diff --git a/tests/test_git_config.py b/tests/test_git_config.py index 4b4e4cabb..33b0466fa 100644 --- a/tests/test_git_config.py +++ b/tests/test_git_config.py @@ -268,3 +268,23 @@ def test_remote_save_with_push_url_without_projectname( def test_is_id(rev: str, expected: bool) -> None: """Test IsId identifies both SHA-1 and SHA-256 hashes.""" assert git_config.IsId(rev) == expected + + +def test_repo_config_for_user_is_not_shared_with_git_config( + monkeypatch: pytest.MonkeyPatch, tmp_home_dir: Path +) -> None: + """RepoConfig.ForUser() must not reuse GitConfig.ForUser()'s cache.""" + monkeypatch.setattr(git_config.GitConfig, "_ForUser", None) + monkeypatch.setattr(git_config.RepoConfig, "_ForUser", None) + monkeypatch.delenv("REPO_CONFIG_DIR", raising=False) + + # Populate the GitConfig cache first, as manifest loading does. + git_cfg = git_config.GitConfig.ForUser() + repo_cfg = git_config.RepoConfig.ForUser() + + assert repo_cfg is not git_cfg + assert git_cfg.file == str(tmp_home_dir / ".gitconfig") + assert repo_cfg.file == str(tmp_home_dir / ".repoconfig" / "config") + # And the RepoConfig instance is cached on its own class. + assert git_config.RepoConfig.ForUser() is repo_cfg + assert git_config.GitConfig.ForUser() is git_cfg