From 1d855b7e01b343486c6c3f84ffd57074aaa8cb92 Mon Sep 17 00:00:00 2001 From: jeffro256 Date: Thu, 17 Sep 2026 01:06:07 -0500 Subject: [PATCH] submodule: option to update without fetching --- git/objects/submodule/base.py | 15 ++++++++++++++- git/objects/submodule/root.py | 9 ++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/git/objects/submodule/base.py b/git/objects/submodule/base.py index ba281c499..c544451b8 100644 --- a/git/objects/submodule/base.py +++ b/git/objects/submodule/base.py @@ -733,6 +733,7 @@ def update( clone_multi_options: Union[Sequence[TBD], None] = None, allow_unsafe_options: bool = False, allow_unsafe_protocols: bool = False, + no_fetch: bool = False, ) -> "Submodule": """Update the repository of this submodule to point to the checkout we point at with the binsha of this instance. @@ -795,6 +796,10 @@ def update( :param allow_unsafe_options: Allow unsafe options to be used, like ``--upload-pack``. + :param no_fetch: + If ``True``, submodule updating will be attempted without fetching + new changes from remotes. + :note: Does nothing in bare repositories. @@ -857,7 +862,8 @@ def fetch_remotes(module_repo: "Repo") -> None: ####################################### try: mrepo = self.module() - fetch_remotes(mrepo) + if not no_fetch: + fetch_remotes(mrepo) except InvalidGitRepositoryError: mrepo = None if not init: @@ -884,6 +890,10 @@ def fetch_remotes(module_repo: "Repo") -> None: raise OSError( "Module directory at %r does already exist and is non-empty" % checkout_module_abspath ) + elif no_fetch: + raise ValueError( + "Module directory at %r is empty but fetching is disabled" % checkout_module_abspath + ) os.makedirs(checkout_module_abspath, exist_ok=True) self._write_git_file_and_module_config(checkout_module_abspath, module_abspath) mrepo = git.Repo(checkout_module_abspath) @@ -913,6 +923,8 @@ def fetch_remotes(module_repo: "Repo") -> None: + "Cloning url '%s' to '%s' in submodule %r" % (self.url, checkout_module_abspath, self.name), ) if not dry_run: + if no_fetch: + raise ValueError("Missing module at %r but fetching is disabled" % self.path) from None if self.url.startswith("."): url = urllib.parse.urljoin(self.repo.remotes.origin.url + "/", self.url) else: @@ -1061,6 +1073,7 @@ def fetch_remotes(module_repo: "Repo") -> None: dry_run=dry_run, force=force, keep_going=keep_going, + no_fetch=no_fetch, ) # END handle recursive update # END handle dry run diff --git a/git/objects/submodule/root.py b/git/objects/submodule/root.py index d068049c1..8f31324f5 100644 --- a/git/objects/submodule/root.py +++ b/git/objects/submodule/root.py @@ -87,6 +87,7 @@ def update( # type: ignore[override] dry_run: bool = False, force_reset: bool = False, keep_going: bool = False, + no_fetch: bool = False, ) -> "RootModule": """Update the submodules of this repository to the current HEAD commit. @@ -146,6 +147,10 @@ def update( # type: ignore[override] In conjunction with `dry_run`, this can be useful to anticipate all errors when updating submodules. + :param no_fetch: + If ``True``, submodule updating will be attempted without fetching + new changes from remotes. + :return: self """ @@ -274,7 +279,8 @@ def update( # type: ignore[override] if not dry_run: assert nn not in [r.name for r in rmts] smr = smm.create_remote(nn, sm.url) - smr.fetch(progress=progress) + if not no_fetch: + smr.fetch(progress=progress) # If we have a tracking branch, it should be available # in the new remote as well. @@ -433,6 +439,7 @@ def update( # type: ignore[override] dry_run=dry_run, force=force_reset, keep_going=keep_going, + no_fetch=no_fetch, ) # Update recursively depth first - question is which inconsistent state will