| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent b3a4ba8 commit 30013e9
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -38,6 +38,9 @@ Git executable and safety | |||
| 38 | 38 | suppresses configured signing by default; signing, verification, and editor | |
| 39 | 39 | options require the same opt-in. | |
| 40 | 40 | * The raw ``repo.git`` interface remains available for direct Git commands. | |
| 41 | + Global ``-C`` options select the requested checkout without the repository | ||
| 42 | + locations automatically supplied by ``Repo`` overriding it. Explicit | ||
| 43 | + environment overrides retain Git's precedence over ``-C``. | ||
| 41 | 44 | Existing explicit unsafe-option and unsafe-protocol opt-ins remain independent. | |
| 42 | 45 | They do not permit argument or stdin-record injection, or reordering command | |
| 43 | 46 | options past the library's safety flags. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -616,6 +616,7 @@ class Git: | |||
| 616 | 616 | "_git_options", | |
| 617 | 617 | "_persistent_git_options", | |
| 618 | 618 | "_environment", | |
| 619 | + "_repository_environment", | ||
| 619 | 620 | "_repo", | |
| 620 | 621 | ) | |
| 621 | 622 | ||
@@ -1164,6 +1165,7 @@ def __init__(self, working_dir: Union[None, PathLike] = None) -> None: | |||
| 1164 | 1165 | ||
| 1165 | 1166 | # Extra environment variables to pass to git commands | |
| 1166 | 1167 | self._environment: Dict[str, Optional[str]] = {} | |
| 1168 | + self._repository_environment: Dict[str, Optional[str]] = {} | ||
| 1167 | 1169 | self._repo: Any = None # Weak reference; the Repo owns native resources. | |
| 1168 | 1170 | ||
| 1169 | 1171 | # Cached version slots | |
@@ -1535,7 +1537,11 @@ def execute( | |||
| 1535 | 1537 | # just to be sure. | |
| 1536 | 1538 | environment["LANGUAGE"] = "C" | |
| 1537 | 1539 | environment["LC_ALL"] = "C" | |
| 1538 | - environment.update(self._environment) | ||
| 1540 | + redirected = subprocess_kwargs.pop("_repository_redirected", False) | ||
| 1541 | + automatic = self._repository_environment if redirected else {} | ||
| 1542 | + environment.update( | ||
| 1543 | + {key: value for key, value in self._environment.items() if key not in automatic or value != automatic[key]} | ||
| 1544 | + ) | ||
| 1539 | 1545 | if inline_env is not None: | |
| 1540 | 1546 | environment.update(inline_env) | |
| 1541 | 1547 | # Internal or per-call None overrides remove inherited variables. | |
@@ -1725,6 +1731,7 @@ def update_environment(self, **kwargs: Any) -> Dict[str, Union[str, None]]: | |||
| 1725 | 1731 | """ | |
| 1726 | 1732 | old_env = {} | |
| 1727 | 1733 | for key, value in kwargs.items(): | |
| 1734 | + self._repository_environment.pop(key, None) | ||
| 1728 | 1735 | # Set value if it is None. | |
| 1729 | 1736 | if value is not None: | |
| 1730 | 1737 | old_env[key] = self._environment.get(key) | |
@@ -1748,11 +1755,13 @@ def custom_environment(self, **kwargs: Any) -> Iterator[None]: | |||
| 1748 | 1755 | :param kwargs: | |
| 1749 | 1756 | See :meth:`update_environment`. | |
| 1750 | 1757 | """ | |
| 1758 | + automatic = {key: self._repository_environment[key] for key in kwargs if key in self._repository_environment} | ||
| 1751 | 1759 | old_env = self.update_environment(**kwargs) | |
| 1752 | 1760 | try: | |
| 1753 | 1761 | yield | |
| 1754 | 1762 | finally: | |
| 1755 | 1763 | self.update_environment(**old_env) | |
| 1764 | + self._repository_environment.update(automatic) | ||
| 1756 | 1765 | ||
| 1757 | 1766 | def transform_kwarg(self, name: str, value: Any, split_single_char_options: bool) -> List[str]: | |
| 1758 | 1767 | if len(name) == 1: | |
@@ -1907,6 +1916,11 @@ def _call_process( | |||
| 1907 | 1916 | call.extend(self._git_options) | |
| 1908 | 1917 | self._git_options = () | |
| 1909 | 1918 | ||
| 1919 | + # Only global options redirect discovery. A subcommand operand named | ||
| 1920 | + # -C must not drop the repository locations supplied by Repo. | ||
| 1921 | + if any(option == "-C" for option in call[1:]): | ||
| 1922 | + exec_kwargs["_repository_redirected"] = True | ||
| 1923 | + | ||
| 1910 | 1924 | call.extend(safe_git_options) | |
| 1911 | 1925 | ||
| 1912 | 1926 | call.append(dashify(method)) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -447,8 +447,12 @@ def __init__( | |||
| 447 | 447 | self.git = self.GitCommandWrapperType(self.working_dir) | |
| 448 | 448 | self.git._repo = weakref.ref(self) | |
| 449 | 449 | self.git._environment.update(GIT_DIR=git_dir, **environment) | |
| 450 | + if git_dir_env is None: | ||
| 451 | + self.git._repository_environment["GIT_DIR"] = git_dir | ||
| 450 | 452 | if self._working_tree_dir is not None: | |
| 451 | 453 | self.git.update_environment(GIT_WORK_TREE=os.fspath(self._working_tree_dir)) | |
| 454 | + if "GIT_WORK_TREE" not in environment: | ||
| 455 | + self.git._repository_environment["GIT_WORK_TREE"] = os.fspath(self._working_tree_dir) | ||
| 452 | 456 | if native is not NotImplemented: | |
| 453 | 457 | self._gix_repository = native | |
| 454 | 458 | self._empty_tree_hexsha = str(native.empty_tree().id) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -31,3 +31,35 @@ def test_index_entries_readers_retain_pending_and_published_snapshots(object_for | |||
| 31 | 31 | index.write() | |
| 32 | 32 | assert repo.index.entries == pending | |
| 33 | 33 | assert entries[("tracked", 0)].binsha == repo.head.commit.tree["tracked"].binsha | |
| 34 | + | ||
| 35 | + | ||
| 36 | + @pytest.mark.parametrize("object_format", ["sha1", "sha256"]) | ||
| 37 | + @pytest.mark.parametrize("ref_format", ["files", "reftable"]) | ||
| 38 | + def test_git_directory_option_selects_the_requested_worktree(object_format, ref_format): | ||
| 39 | + with fixture_repo("downstream-worktree.sh", object_format, ref_format, write=True) as repo: | ||
| 40 | + root = Path(repo.working_tree_dir).parent | ||
| 41 | + linked = root / "linked" | ||
| 42 | + original_index = Path(repo.index.path).read_bytes() | ||
| 43 | + assert not (linked / "tracked").exists() | ||
| 44 | + process = repo.git(C=str(linked)).checkout("--force", as_process=True) | ||
| 45 | + process.wait() | ||
| 46 | + assert (linked / "tracked").read_text() == "original" | ||
| 47 | + assert Path(repo.working_tree_dir, "tracked").read_text() == "unchanged" | ||
| 48 | + assert Path(repo.index.path).read_bytes() == original_index | ||
| 49 | + assert repo.git(C=str(linked)).rev_parse("--show-toplevel") == str(linked) | ||
| 50 | + assert repo.git(C=str(root / "other")).show("HEAD:tracked") == "other" | ||
| 51 | + repo.git.set_persistent_git_options(C=str(linked)) | ||
| 52 | + assert repo.git.rev_parse("--show-toplevel") == str(linked) | ||
| 53 | + repo.git.set_persistent_git_options() | ||
| 54 | + assert repo.git.rev_parse("--show-toplevel") == repo.working_tree_dir | ||
| 55 | + | ||
| 56 | + | ||
| 57 | + def test_git_directory_option_retains_explicit_environment(): | ||
| 58 | + with fixture_repo("downstream-worktree.sh", "sha1", "files", write=True) as repo: | ||
| 59 | + root = Path(repo.working_tree_dir).parent | ||
| 60 | + other = root / "other" | ||
| 61 | + with repo.git.custom_environment(GIT_DIR=repo.git_dir, GIT_WORK_TREE=repo.working_tree_dir): | ||
| 62 | + assert repo.git(C=str(other)).show("HEAD:tracked") == "original" | ||
| 63 | + assert repo.git(C=str(other)).show("HEAD:tracked") == "other" | ||
| 64 | + assert repo.git(C=str(other)).show("HEAD:tracked", env={"GIT_DIR": repo.git_dir}) == "original" | ||
| 65 | + | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,14 @@ | |||
| 1 | + #!/usr/bin/env bash | ||
| 2 | + set -eu | ||
| 3 | + git init -q --object-format="$1" --ref-format="$2" repo | ||
| 4 | + cd repo | ||
| 5 | + printf original > tracked | ||
| 6 | + git add tracked | ||
| 7 | + git commit -qm initial | ||
| 8 | + git worktree add -q --no-checkout -b linked ../linked HEAD | ||
| 9 | + printf unchanged > tracked | ||
| 10 | + git init -q ../other | ||
| 11 | + cd ../other | ||
| 12 | + printf other > tracked | ||
| 13 | + git add tracked | ||
| 14 | + git commit -qm other | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments