300 lines
8.7 KiB
Python
300 lines
8.7 KiB
Python
# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors
|
|
#
|
|
# This module is part of GitPython and is released under the
|
|
# 3-Clause BSD License: https://opensource.org/license/bsd-3-clause/
|
|
|
|
# @PydevCodeAnalysisIgnore
|
|
|
|
__all__ = [
|
|
"Actor",
|
|
"AmbiguousObjectName",
|
|
"BadName",
|
|
"BadObject",
|
|
"BadObjectType",
|
|
"BaseIndexEntry",
|
|
"Blob",
|
|
"BlobFilter",
|
|
"BlockingLockFile",
|
|
"CacheError",
|
|
"CheckoutError",
|
|
"CommandError",
|
|
"Commit",
|
|
"Diff",
|
|
"DiffConstants",
|
|
"DiffIndex",
|
|
"Diffable",
|
|
"FetchInfo",
|
|
"Git",
|
|
"GitCmdObjectDB",
|
|
"GitCommandError",
|
|
"GitCommandNotFound",
|
|
"GitConfigParser",
|
|
"GitDB",
|
|
"GitError",
|
|
"HEAD",
|
|
"Head",
|
|
"HookExecutionError",
|
|
"INDEX",
|
|
"IndexEntry",
|
|
"IndexFile",
|
|
"IndexObject",
|
|
"InvalidDBRoot",
|
|
"InvalidGitRepositoryError",
|
|
"List", # Deprecated - import this from `typing` instead.
|
|
"LockFile",
|
|
"NULL_TREE",
|
|
"NoSuchPathError",
|
|
"ODBError",
|
|
"Object",
|
|
"Optional", # Deprecated - import this from `typing` instead.
|
|
"ParseError",
|
|
"PathLike",
|
|
"PushInfo",
|
|
"RefLog",
|
|
"RefLogEntry",
|
|
"Reference",
|
|
"Remote",
|
|
"RemoteProgress",
|
|
"RemoteReference",
|
|
"Repo",
|
|
"RepositoryDirtyError",
|
|
"RootModule",
|
|
"RootUpdateProgress",
|
|
"Sequence", # Deprecated - import from `typing`, or `collections.abc` in 3.9+.
|
|
"StageType",
|
|
"Stats",
|
|
"Submodule",
|
|
"SymbolicReference",
|
|
"TYPE_CHECKING", # Deprecated - import this from `typing` instead.
|
|
"Tag",
|
|
"TagObject",
|
|
"TagReference",
|
|
"Tree",
|
|
"TreeModifier",
|
|
"Tuple", # Deprecated - import this from `typing` instead.
|
|
"Union", # Deprecated - import this from `typing` instead.
|
|
"UnmergedEntriesError",
|
|
"UnsafeOptionError",
|
|
"UnsafeProtocolError",
|
|
"UnsupportedOperation",
|
|
"UpdateProgress",
|
|
"WorkTreeRepositoryUnsupported",
|
|
"refresh",
|
|
"remove_password_if_present",
|
|
"rmtree",
|
|
"safe_decode",
|
|
"to_hex_sha",
|
|
]
|
|
|
|
__version__ = '3.1.45'
|
|
|
|
from typing import Any, List, Optional, Sequence, TYPE_CHECKING, Tuple, Union
|
|
|
|
if TYPE_CHECKING:
|
|
from types import ModuleType
|
|
|
|
import warnings
|
|
|
|
from gitdb.util import to_hex_sha
|
|
|
|
from git.exc import (
|
|
AmbiguousObjectName,
|
|
BadName,
|
|
BadObject,
|
|
BadObjectType,
|
|
CacheError,
|
|
CheckoutError,
|
|
CommandError,
|
|
GitCommandError,
|
|
GitCommandNotFound,
|
|
GitError,
|
|
HookExecutionError,
|
|
InvalidDBRoot,
|
|
InvalidGitRepositoryError,
|
|
NoSuchPathError,
|
|
ODBError,
|
|
ParseError,
|
|
RepositoryDirtyError,
|
|
UnmergedEntriesError,
|
|
UnsafeOptionError,
|
|
UnsafeProtocolError,
|
|
UnsupportedOperation,
|
|
WorkTreeRepositoryUnsupported,
|
|
)
|
|
from git.types import PathLike
|
|
|
|
try:
|
|
from git.compat import safe_decode # @NoMove
|
|
from git.config import GitConfigParser # @NoMove
|
|
from git.objects import ( # @NoMove
|
|
Blob,
|
|
Commit,
|
|
IndexObject,
|
|
Object,
|
|
RootModule,
|
|
RootUpdateProgress,
|
|
Submodule,
|
|
TagObject,
|
|
Tree,
|
|
TreeModifier,
|
|
UpdateProgress,
|
|
)
|
|
from git.refs import ( # @NoMove
|
|
HEAD,
|
|
Head,
|
|
RefLog,
|
|
RefLogEntry,
|
|
Reference,
|
|
RemoteReference,
|
|
SymbolicReference,
|
|
Tag,
|
|
TagReference,
|
|
)
|
|
from git.diff import ( # @NoMove
|
|
INDEX,
|
|
NULL_TREE,
|
|
Diff,
|
|
DiffConstants,
|
|
DiffIndex,
|
|
Diffable,
|
|
)
|
|
from git.db import GitCmdObjectDB, GitDB # @NoMove
|
|
from git.cmd import Git # @NoMove
|
|
from git.repo import Repo # @NoMove
|
|
from git.remote import FetchInfo, PushInfo, Remote, RemoteProgress # @NoMove
|
|
from git.index import ( # @NoMove
|
|
BaseIndexEntry,
|
|
BlobFilter,
|
|
CheckoutError,
|
|
IndexEntry,
|
|
IndexFile,
|
|
StageType,
|
|
# NOTE: This tells type checkers what util resolves to. We delete it, and it is
|
|
# really resolved by __getattr__, which warns. See below on what to use instead.
|
|
util,
|
|
)
|
|
from git.util import ( # @NoMove
|
|
Actor,
|
|
BlockingLockFile,
|
|
LockFile,
|
|
Stats,
|
|
remove_password_if_present,
|
|
rmtree,
|
|
)
|
|
except GitError as _exc:
|
|
raise ImportError("%s: %s" % (_exc.__class__.__name__, _exc)) from _exc
|
|
|
|
|
|
def _warned_import(message: str, fullname: str) -> "ModuleType":
|
|
import importlib
|
|
|
|
warnings.warn(message, DeprecationWarning, stacklevel=3)
|
|
return importlib.import_module(fullname)
|
|
|
|
|
|
def _getattr(name: str) -> Any:
|
|
# TODO: If __version__ is made dynamic and lazily fetched, put that case right here.
|
|
|
|
if name == "util":
|
|
return _warned_import(
|
|
"The expression `git.util` and the import `from git import util` actually "
|
|
"reference git.index.util, and not the git.util module accessed in "
|
|
'`from git.util import XYZ` or `sys.modules["git.util"]`. This potentially '
|
|
"confusing behavior is currently preserved for compatibility, but may be "
|
|
"changed in the future and should not be relied on.",
|
|
fullname="git.index.util",
|
|
)
|
|
|
|
for names, prefix in (
|
|
({"head", "log", "reference", "symbolic", "tag"}, "git.refs"),
|
|
({"base", "fun", "typ"}, "git.index"),
|
|
):
|
|
if name not in names:
|
|
continue
|
|
|
|
fullname = f"{prefix}.{name}"
|
|
|
|
return _warned_import(
|
|
f"{__name__}.{name} is a private alias of {fullname} and subject to "
|
|
f"immediate removal. Use {fullname} instead.",
|
|
fullname=fullname,
|
|
)
|
|
|
|
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
|
|
|
|
if not TYPE_CHECKING:
|
|
# NOTE: The expression `git.util` gives git.index.util and `from git import util`
|
|
# imports git.index.util, NOT git.util. It may not be feasible to change this until
|
|
# the next major version, to avoid breaking code inadvertently relying on it.
|
|
#
|
|
# - If git.index.util *is* what you want, use (or import from) that, to avoid
|
|
# confusion.
|
|
#
|
|
# - To use the "real" git.util module, write `from git.util import ...`, or if
|
|
# necessary access it as `sys.modules["git.util"]`.
|
|
#
|
|
# Note also that `import git.util` technically imports the "real" git.util... but
|
|
# the *expression* `git.util` after doing so is still git.index.util!
|
|
#
|
|
# (This situation differs from that of other indirect-submodule imports that are
|
|
# unambiguously non-public and subject to immediate removal. Here, the public
|
|
# git.util module, though different, makes less discoverable that the expression
|
|
# `git.util` refers to a non-public attribute of the git module.)
|
|
#
|
|
# This had originally come about by a wildcard import. Now that all intended imports
|
|
# are explicit, the intuitive but potentially incompatible binding occurs due to the
|
|
# usual rules for Python submodule bindings. So for now we replace that binding with
|
|
# git.index.util, delete that, and let __getattr__ handle it and issue a warning.
|
|
#
|
|
# For the same runtime behavior, it would be enough to forgo importing util, and
|
|
# delete util as created naturally; __getattr__ would behave the same. But type
|
|
# checkers would not know what util refers to when accessed as an attribute of git.
|
|
del util
|
|
|
|
# This is "hidden" to preserve static checking for undefined/misspelled attributes.
|
|
__getattr__ = _getattr
|
|
|
|
# { Initialize git executable path
|
|
|
|
GIT_OK = None
|
|
|
|
|
|
def refresh(path: Optional[PathLike] = None) -> None:
|
|
"""Convenience method for setting the git executable path.
|
|
|
|
:param path:
|
|
Optional path to the Git executable. If not absolute, it is resolved
|
|
immediately, relative to the current directory.
|
|
|
|
:note:
|
|
The `path` parameter is usually omitted and cannot be used to specify a custom
|
|
command whose location is looked up in a path search on each call. See
|
|
:meth:`Git.refresh <git.cmd.Git.refresh>` for details on how to achieve this.
|
|
|
|
:note:
|
|
This calls :meth:`Git.refresh <git.cmd.Git.refresh>` and sets other global
|
|
configuration according to the effect of doing so. As such, this function should
|
|
usually be used instead of using :meth:`Git.refresh <git.cmd.Git.refresh>` or
|
|
:meth:`FetchInfo.refresh <git.remote.FetchInfo.refresh>` directly.
|
|
|
|
:note:
|
|
This function is called automatically, with no arguments, at import time.
|
|
"""
|
|
global GIT_OK
|
|
GIT_OK = False
|
|
|
|
if not Git.refresh(path=path):
|
|
return
|
|
if not FetchInfo.refresh(): # noqa: F405
|
|
return # type: ignore[unreachable]
|
|
|
|
GIT_OK = True
|
|
|
|
|
|
try:
|
|
refresh()
|
|
except Exception as _exc:
|
|
raise ImportError("Failed to initialize: {0}".format(_exc)) from _exc
|
|
|
|
# } END initialize git executable path
|