| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4,17 +4,32 @@ | |||
| 4 | 4 | __all__ = ["Submodule", "UpdateProgress"] | |
| 5 | 5 | ||
| 6 | 6 | import gc | |
| 7 | - from io import BytesIO | ||
| 8 | 7 | import logging | |
| 9 | 8 | import ntpath | |
| 10 | 9 | import os | |
| 11 | 10 | import os.path as osp | |
| 12 | - from pathlib import Path | ||
| 13 | 11 | import shlex | |
| 14 | 12 | import stat | |
| 15 | 13 | import sys | |
| 16 | - import uuid | ||
| 17 | 14 | import urllib.parse | |
| 15 | + import uuid | ||
| 16 | + from io import BytesIO | ||
| 17 | + from pathlib import Path | ||
| 18 | + | ||
| 19 | + # typing ---------------------------------------------------------------------- | ||
| 20 | + from typing import ( | ||
| 21 | + TYPE_CHECKING, | ||
| 22 | + Any, | ||
| 23 | + Callable, | ||
| 24 | + Dict, | ||
| 25 | + Iterator, | ||
| 26 | + List, | ||
| 27 | + Literal, | ||
| 28 | + Mapping, | ||
| 29 | + Sequence, | ||
| 30 | + Union, | ||
| 31 | + cast, | ||
| 32 | + ) | ||
| 18 | 33 | ||
| 19 | 34 | import git | |
| 20 | 35 | from git.cmd import Git | |
@@ -46,23 +61,7 @@ | |||
| 46 | 61 | sm_section, | |
| 47 | 62 | ) | |
| 48 | 63 | ||
| 49 | - # typing ---------------------------------------------------------------------- | ||
| 50 | - | ||
| 51 | - from typing import ( | ||
| 52 | - Any, | ||
| 53 | - Callable, | ||
| 54 | - Dict, | ||
| 55 | - Iterator, | ||
| 56 | - List, | ||
| 57 | - Literal, | ||
| 58 | - Mapping, | ||
| 59 | - Sequence, | ||
| 60 | - TYPE_CHECKING, | ||
| 61 | - Union, | ||
| 62 | - cast, | ||
| 63 | - ) | ||
| 64 | - | ||
| 65 | - from git.types import Commit_ish, PathLike, TBD | ||
| 64 | + from git.types import TBD, Commit_ish, PathLike | ||
| 66 | 65 | ||
| 67 | 66 | if TYPE_CHECKING: | |
| 68 | 67 | from git.index import IndexFile | |
@@ -729,6 +728,7 @@ def update( | |||
| 729 | 728 | clone_multi_options: Union[Sequence[TBD], None] = None, | |
| 730 | 729 | allow_unsafe_options: bool = False, | |
| 731 | 730 | allow_unsafe_protocols: bool = False, | |
| 731 | + no_fetch: bool = False, | ||
| 732 | 732 | ) -> "Submodule": | |
| 733 | 733 | """Update the repository of this submodule to point to the checkout we point at | |
| 734 | 734 | with the binsha of this instance. | |
@@ -791,6 +791,11 @@ def update( | |||
| 791 | 791 | :param allow_unsafe_options: | |
| 792 | 792 | Allow unsafe options to be used, like ``--upload-pack``. | |
| 793 | 793 | ||
| 794 | + :param no_fetch: | ||
| 795 | + If ``True``, update using locally available objects and remote-tracking | ||
| 796 | + refs without fetching or cloning. Repositories retained after | ||
| 797 | + :meth:`deinit` can be restored without fetching. | ||
| 798 | + | ||
| 794 | 799 | :note: | |
| 795 | 800 | Does nothing in bare repositories. | |
| 796 | 801 | ||
@@ -853,7 +858,8 @@ def fetch_remotes(module_repo: "Repo") -> None: | |||
| 853 | 858 | ####################################### | |
| 854 | 859 | try: | |
| 855 | 860 | mrepo = self.module() | |
| 856 | - fetch_remotes(mrepo) | ||
| 861 | + if not no_fetch: | ||
| 862 | + fetch_remotes(mrepo) | ||
| 857 | 863 | except InvalidGitRepositoryError: | |
| 858 | 864 | mrepo = None | |
| 859 | 865 | if not init: | |
@@ -884,7 +890,8 @@ def fetch_remotes(module_repo: "Repo") -> None: | |||
| 884 | 890 | self._write_git_file_and_module_config(checkout_module_abspath, module_abspath) | |
| 885 | 891 | mrepo = git.Repo(checkout_module_abspath) | |
| 886 | 892 | mrepo.head.reset(mrepo.head.commit, index=True, working_tree=True) | |
| 887 | - fetch_remotes(mrepo) | ||
| 893 | + if not no_fetch: | ||
| 894 | + fetch_remotes(mrepo) | ||
| 888 | 895 | with self.repo.config_writer() as writer: | |
| 889 | 896 | writer.set_value(sm_section(self.name), "url", self.url) | |
| 890 | 897 | ||
@@ -909,6 +916,8 @@ def fetch_remotes(module_repo: "Repo") -> None: | |||
| 909 | 916 | + "Cloning url '%s' to '%s' in submodule %r" % (self.url, checkout_module_abspath, self.name), | |
| 910 | 917 | ) | |
| 911 | 918 | if not dry_run: | |
| 919 | + if no_fetch: | ||
| 920 | + raise ValueError("Missing module at %r but fetching is disabled" % self.path) from None | ||
| 912 | 921 | if self.url.startswith("."): | |
| 913 | 922 | url = urllib.parse.urljoin(self.repo.remotes.origin.url + "/", self.url) | |
| 914 | 923 | else: | |
@@ -1057,6 +1066,7 @@ def fetch_remotes(module_repo: "Repo") -> None: | |||
| 1057 | 1066 | dry_run=dry_run, | |
| 1058 | 1067 | force=force, | |
| 1059 | 1068 | keep_going=keep_going, | |
| 1069 | + no_fetch=no_fetch, | ||
| 1060 | 1070 | ) | |
| 1061 | 1071 | # END handle recursive update | |
| 1062 | 1072 | # END handle dry run | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,19 +5,17 @@ | |||
| 5 | 5 | ||
| 6 | 6 | import logging | |
| 7 | 7 | ||
| 8 | + # typing ------------------------------------------------------------------- | ||
| 9 | + from typing import TYPE_CHECKING, Union | ||
| 10 | + | ||
| 8 | 11 | import git | |
| 9 | 12 | from git.exc import InvalidGitRepositoryError | |
| 13 | + from git.types import Commit_ish | ||
| 10 | 14 | from git.util import IterableList | |
| 11 | 15 | ||
| 12 | 16 | from .base import Submodule, UpdateProgress | |
| 13 | 17 | from .util import find_first_remote_branch | |
| 14 | 18 | ||
| 15 | - # typing ------------------------------------------------------------------- | ||
| 16 | - | ||
| 17 | - from typing import TYPE_CHECKING, Union | ||
| 18 | - | ||
| 19 | - from git.types import Commit_ish | ||
| 20 | - | ||
| 21 | 19 | if TYPE_CHECKING: | |
| 22 | 20 | from git.repo import Repo | |
| 23 | 21 | ||
@@ -87,6 +85,7 @@ def update( # type: ignore[override] | |||
| 87 | 85 | dry_run: bool = False, | |
| 88 | 86 | force_reset: bool = False, | |
| 89 | 87 | keep_going: bool = False, | |
| 88 | + no_fetch: bool = False, | ||
| 90 | 89 | ) -> "RootModule": | |
| 91 | 90 | """Update the submodules of this repository to the current HEAD commit. | |
| 92 | 91 | ||
@@ -146,6 +145,11 @@ def update( # type: ignore[override] | |||
| 146 | 145 | In conjunction with `dry_run`, this can be useful to anticipate all errors | |
| 147 | 146 | when updating submodules. | |
| 148 | 147 | ||
| 148 | + :param no_fetch: | ||
| 149 | + If ``True``, update using locally available objects and remote-tracking | ||
| 150 | + refs without fetching or cloning. Cached refs are preserved and used even | ||
| 151 | + when a submodule's URL changes. | ||
| 152 | + | ||
| 149 | 153 | :return: | |
| 150 | 154 | self | |
| 151 | 155 | """ | |
@@ -254,7 +258,7 @@ def update( # type: ignore[override] | |||
| 254 | 258 | # HANDLE URL CHANGE | |
| 255 | 259 | ################### | |
| 256 | 260 | if sm.url != psm.url: | |
| 257 | - # Add the new remote, remove the old one. | ||
| 261 | + # When fetching, add the new remote and remove the old one. | ||
| 258 | 262 | # This way, if the url just changes, the commits will not have | |
| 259 | 263 | # to be re-retrieved. | |
| 260 | 264 | nn = "__new_origin__" | |
@@ -272,33 +276,19 @@ def update( # type: ignore[override] | |||
| 272 | 276 | ) | |
| 273 | 277 | ||
| 274 | 278 | if not dry_run: | |
| 275 | - assert nn not in [r.name for r in rmts] | ||
| 276 | - smr = smm.create_remote(nn, sm.url) | ||
| 277 | - smr.fetch(progress=progress) | ||
| 278 | - | ||
| 279 | - # If we have a tracking branch, it should be available | ||
| 280 | - # in the new remote as well. | ||
| 281 | - if len([r for r in smr.refs if r.remote_head == sm.branch_name]) == 0: | ||
| 282 | - raise ValueError( | ||
| 283 | - "Submodule branch named %r was not available in new submodule remote at %r" | ||
| 284 | - % (sm.branch_name, sm.url) | ||
| 285 | - ) | ||
| 286 | - # END head is not detached | ||
| 287 | - | ||
| 288 | - # Now delete the changed one. | ||
| 289 | - rmt_for_deletion = None | ||
| 279 | + previous_remote = None | ||
| 290 | 280 | for remote in rmts: | |
| 291 | 281 | if remote.url == psm.url: | |
| 292 | - rmt_for_deletion = remote | ||
| 282 | + previous_remote = remote | ||
| 293 | 283 | break | |
| 294 | 284 | # END if urls match | |
| 295 | 285 | # END for each remote | |
| 296 | 286 | ||
| 297 | 287 | # If we didn't find a matching remote, but have exactly | |
| 298 | 288 | # one, we can safely use this one. | |
| 299 | - if rmt_for_deletion is None: | ||
| 289 | + if previous_remote is None: | ||
| 300 | 290 | if len(rmts) == 1: | |
| 301 | - rmt_for_deletion = rmts[0] | ||
| 291 | + previous_remote = rmts[0] | ||
| 302 | 292 | else: | |
| 303 | 293 | # If we have not found any remote with the | |
| 304 | 294 | # original URL we may not have a name. This is a | |
@@ -311,45 +301,64 @@ def update( # type: ignore[override] | |||
| 311 | 301 | # END handle one single remote | |
| 312 | 302 | # END handle check we found a remote | |
| 313 | 303 | ||
| 314 | - orig_name = rmt_for_deletion.name | ||
| 315 | - smm.delete_remote(rmt_for_deletion) | ||
| 316 | - # NOTE: Currently we leave tags from the deleted remotes | ||
| 317 | - # as well as separate tracking branches in the possibly | ||
| 318 | - # totally changed repository (someone could have changed | ||
| 319 | - # the url to another project). At some point, one might | ||
| 320 | - # want to clean it up, but the danger is high to remove | ||
| 321 | - # stuff the user has added explicitly. | ||
| 322 | - | ||
| 323 | - # Rename the new remote back to what it was. | ||
| 324 | - smr.rename(orig_name) | ||
| 325 | - | ||
| 326 | - # Early on, we verified that the our current tracking | ||
| 327 | - # branch exists in the remote. Now we have to ensure | ||
| 328 | - # that the sha we point to is still contained in the new | ||
| 329 | - # remote tracking branch. | ||
| 330 | - smsha = sm.binsha | ||
| 331 | - found = False | ||
| 332 | - rref = smr.refs[self.branch_name] | ||
| 333 | - for c in rref.commit.traverse(): | ||
| 334 | - if c.binsha == smsha: | ||
| 335 | - found = True | ||
| 336 | - break | ||
| 337 | - # END traverse all commits in search for sha | ||
| 338 | - # END for each commit | ||
| 339 | - | ||
| 340 | - if not found: | ||
| 341 | - # Adjust our internal binsha to use the one of the | ||
| 342 | - # remote this way, it will be checked out in the | ||
| 343 | - # next step. This will change the submodule relative | ||
| 344 | - # to us, so the user will be able to commit the | ||
| 345 | - # change easily. | ||
| 346 | - _logger.warning( | ||
| 347 | - "Current sha %s was not contained in the tracking\ | ||
| 304 | + if no_fetch: | ||
| 305 | + # A new remote would have no cached refs. Preserve | ||
| 306 | + # the existing refs and tracking configuration for | ||
| 307 | + # offline updates instead of replacing the remote. | ||
| 308 | + previous_remote.set_url(git.Git.polish_url(sm.url, expand_vars=False)) | ||
| 309 | + else: | ||
| 310 | + assert nn not in [r.name for r in rmts] | ||
| 311 | + smr = smm.create_remote(nn, sm.url) | ||
| 312 | + smr.fetch(progress=progress) | ||
| 313 | + | ||
| 314 | + # If we have a tracking branch, it should be available | ||
| 315 | + # in the new remote as well. | ||
| 316 | + if len([r for r in smr.refs if r.remote_head == sm.branch_name]) == 0: | ||
| 317 | + raise ValueError( | ||
| 318 | + "Submodule branch named %r was not available in new submodule remote at %r" | ||
| 319 | + % (sm.branch_name, sm.url) | ||
| 320 | + ) | ||
| 321 | + # END head is not detached | ||
| 322 | + | ||
| 323 | + orig_name = previous_remote.name | ||
| 324 | + smm.delete_remote(previous_remote) | ||
| 325 | + # NOTE: Currently we leave tags from the deleted remotes | ||
| 326 | + # as well as separate tracking branches in the possibly | ||
| 327 | + # totally changed repository (someone could have changed | ||
| 328 | + # the url to another project). At some point, one might | ||
| 329 | + # want to clean it up, but the danger is high to remove | ||
| 330 | + # stuff the user has added explicitly. | ||
| 331 | + | ||
| 332 | + # Rename the new remote back to what it was. | ||
| 333 | + smr.rename(orig_name) | ||
| 334 | + | ||
| 335 | + # Early on, we verified that the our current tracking | ||
| 336 | + # branch exists in the remote. Now we have to ensure | ||
| 337 | + # that the sha we point to is still contained in the new | ||
| 338 | + # remote tracking branch. | ||
| 339 | + smsha = sm.binsha | ||
| 340 | + found = False | ||
| 341 | + rref = smr.refs[self.branch_name] | ||
| 342 | + for c in rref.commit.traverse(): | ||
| 343 | + if c.binsha == smsha: | ||
| 344 | + found = True | ||
| 345 | + break | ||
| 346 | + # END traverse all commits in search for sha | ||
| 347 | + # END for each commit | ||
| 348 | + | ||
| 349 | + if not found: | ||
| 350 | + # Adjust our internal binsha to use the one of the | ||
| 351 | + # remote this way, it will be checked out in the | ||
| 352 | + # next step. This will change the submodule relative | ||
| 353 | + # to us, so the user will be able to commit the | ||
| 354 | + # change easily. | ||
| 355 | + _logger.warning( | ||
| 356 | + "Current sha %s was not contained in the tracking\ | ||
| 348 | 357 | branch at the new remote, setting it the the remote's tracking branch", | |
| 349 | - sm.hexsha, | ||
| 350 | - ) | ||
| 351 | - sm.binsha = rref.commit.binsha | ||
| 352 | - # END reset binsha | ||
| 358 | + sm.hexsha, | ||
| 359 | + ) | ||
| 360 | + sm.binsha = rref.commit.binsha | ||
| 361 | + # END reset binsha | ||
| 353 | 362 | ||
| 354 | 363 | # NOTE: All checkout is performed by the base | |
| 355 | 364 | # implementation of update. | |
@@ -379,11 +388,12 @@ def update( # type: ignore[override] | |||
| 379 | 388 | if not dry_run: | |
| 380 | 389 | smm = sm.module() | |
| 381 | 390 | smmr = smm.remotes | |
| 382 | - # As the branch might not exist yet, we will have to fetch | ||
| 383 | - # all remotes to be sure... | ||
| 384 | - for remote in smmr: | ||
| 385 | - remote.fetch(progress=progress) | ||
| 386 | - # END for each remote | ||
| 391 | + # As the branch might not exist yet, fetch all remotes | ||
| 392 | + # unless restricted to locally cached refs. | ||
| 393 | + if not no_fetch: | ||
| 394 | + for remote in smmr: | ||
| 395 | + remote.fetch(progress=progress) | ||
| 396 | + # END for each remote | ||
| 387 | 397 | ||
| 388 | 398 | try: | |
| 389 | 399 | tbr = git.Head.create( | |
@@ -433,6 +443,7 @@ def update( # type: ignore[override] | |||
| 433 | 443 | dry_run=dry_run, | |
| 434 | 444 | force=force_reset, | |
| 435 | 445 | keep_going=keep_going, | |
| 446 | + no_fetch=no_fetch, | ||
| 436 | 447 | ) | |
| 437 | 448 | ||
| 438 | 449 | # Update recursively depth first - question is which inconsistent state will | |
@@ -451,6 +462,7 @@ def update( # type: ignore[override] | |||
| 451 | 462 | dry_run=dry_run, | |
| 452 | 463 | force_reset=force_reset, | |
| 453 | 464 | keep_going=keep_going, | |
| 465 | + no_fetch=no_fetch, | ||
| 454 | 466 | ) | |
| 455 | 467 | # END handle dry_run | |
| 456 | 468 | # END handle recursive | |
| Back | FazBrowse Home | New Git URL |
0 commit comments