| |
| |
|
|
| __all__ = ["Reference"] |
|
|
| from git.util import IterableObj, LazyMixin |
|
|
| from .symbolic import SymbolicReference, T_References |
|
|
| |
|
|
| from typing import Any, Callable, Iterator, TYPE_CHECKING, Type, Union |
|
|
| from git.types import AnyGitObject, PathLike, _T |
|
|
| if TYPE_CHECKING: |
| from git.repo import Repo |
|
|
| |
|
|
| |
|
|
|
|
| def require_remote_ref_path(func: Callable[..., _T]) -> Callable[..., _T]: |
| """A decorator raising :exc:`ValueError` if we are not a valid remote, based on the |
| path.""" |
|
|
| def wrapper(self: T_References, *args: Any) -> _T: |
| if not self.is_remote(): |
| raise ValueError("ref path does not point to a remote reference: %s" % self.path) |
| return func(self, *args) |
|
|
| |
| wrapper.__name__ = func.__name__ |
| return wrapper |
|
|
|
|
| |
|
|
|
|
| class Reference(SymbolicReference, LazyMixin, IterableObj): |
| """A named reference to any object. |
| |
| Subclasses may apply restrictions though, e.g., a :class:`~git.refs.head.Head` can |
| only point to commits. |
| """ |
|
|
| __slots__ = () |
|
|
| _points_to_commits_only = False |
| _resolve_ref_on_create = True |
| _common_path_default = "refs" |
|
|
| def __init__(self, repo: "Repo", path: PathLike, check_path: bool = True) -> None: |
| """Initialize this instance. |
| |
| :param repo: |
| Our parent repository. |
| |
| :param path: |
| Path relative to the ``.git/`` directory pointing to the ref in question, |
| e.g. ``refs/heads/master``. |
| |
| :param check_path: |
| If ``False``, you can provide any path. |
| Otherwise the path must start with the default path prefix of this type. |
| """ |
| if check_path and not str(path).startswith(self._common_path_default + "/"): |
| raise ValueError(f"Cannot instantiate {self.__class__.__name__!r} from path {path}") |
| self.path: str |
| super().__init__(repo, path) |
|
|
| def __str__(self) -> str: |
| return self.name |
|
|
| |
|
|
| |
| def set_object( |
| self, |
| object: Union[AnyGitObject, "SymbolicReference", str], |
| logmsg: Union[str, None] = None, |
| ) -> "Reference": |
| """Special version which checks if the head-log needs an update as well. |
| |
| :return: |
| self |
| """ |
| oldbinsha = None |
| if logmsg is not None: |
| head = self.repo.head |
| if not head.is_detached and head.ref == self: |
| oldbinsha = self.commit.binsha |
| |
| |
|
|
| super().set_object(object, logmsg) |
|
|
| if oldbinsha is not None: |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| self.repo.head.log_append(oldbinsha, logmsg) |
| |
|
|
| return self |
|
|
| |
|
|
| @property |
| def name(self) -> str: |
| """ |
| :return: |
| (shortest) Name of this reference - it may contain path components |
| """ |
| |
| |
| tokens = self.path.split("/") |
| if len(tokens) < 3: |
| return self.path |
| return "/".join(tokens[2:]) |
|
|
| @classmethod |
| def iter_items( |
| cls: Type[T_References], |
| repo: "Repo", |
| common_path: Union[PathLike, None] = None, |
| *args: Any, |
| **kwargs: Any, |
| ) -> Iterator[T_References]: |
| """Equivalent to |
| :meth:`SymbolicReference.iter_items <git.refs.symbolic.SymbolicReference.iter_items>`, |
| but will return non-detached references as well.""" |
| return cls._iter_items(repo, common_path) |
|
|
| |
|
|
| |
|
|
| @property |
| @require_remote_ref_path |
| def remote_name(self) -> str: |
| """ |
| :return: |
| Name of the remote we are a reference of, such as ``origin`` for a reference |
| named ``origin/master``. |
| """ |
| tokens = self.path.split("/") |
| |
| return tokens[2] |
|
|
| @property |
| @require_remote_ref_path |
| def remote_head(self) -> str: |
| """ |
| :return: |
| Name of the remote head itself, e.g. ``master``. |
| |
| :note: |
| The returned name is usually not qualified enough to uniquely identify a |
| branch. |
| """ |
| tokens = self.path.split("/") |
| return "/".join(tokens[3:]) |
|
|
| |
|
|