mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-10 15:28:34 +01:00
* git: add support for dulwich Stash * git: start adding support for custom refs * git: add Stash and helper context managers for preserving workspace state * scm: cleanup refs/stash and add push_refspec * tests: add tests for git refs and stash * fix push_refspec * tests: add tests for git push_refspec * scm: add git fetch-refspecs * add test for fetch refspecs * scm: add test for git refs containing * remove extraneous log msgs * fix typing issues * stash: only try to push if workspace is dirty * update dulwich to 0.20.14 * scm: move dulwich into scm.backend * move stash internals to backends * scm: move git code into dvc/scm/git/... module * git: use ABC for BaseGitBackend * fix rebase issue * git: fix refspec tests on windows - git file:// URLs need posix style paths * git: move get_refs_containing to backend * scm: add callback for handling diverged refs during fetch
124 lines
3.9 KiB
Python
124 lines
3.9 KiB
Python
import os
|
|
from abc import ABC, abstractmethod
|
|
from typing import TYPE_CHECKING, Callable, Iterable, Optional, Tuple
|
|
|
|
from dvc.scm.base import SCMError
|
|
|
|
if TYPE_CHECKING:
|
|
from dvc.scm.git import Git
|
|
|
|
|
|
class NoGitBackendError(SCMError):
|
|
def __init__(self, func):
|
|
super().__init__(f"No valid Git backend for '{func}'")
|
|
|
|
|
|
class BaseGitBackend(ABC):
|
|
"""Base Git backend class."""
|
|
|
|
def __init__(self, scm: "Git", **kwargs):
|
|
self.scm = scm
|
|
self.root_dir = os.fspath(scm.root_dir)
|
|
|
|
def close(self):
|
|
pass
|
|
|
|
@abstractmethod
|
|
def is_ignored(self, path):
|
|
"""Return True if the specified path is gitignored."""
|
|
|
|
@abstractmethod
|
|
def set_ref(
|
|
self,
|
|
name: str,
|
|
new_ref: str,
|
|
old_ref: Optional[str] = None,
|
|
message: Optional[str] = None,
|
|
symbolic: Optional[bool] = False,
|
|
):
|
|
"""Set the specified git ref.
|
|
|
|
Optional kwargs:
|
|
old_ref: If specified, ref will only be set if it currently equals
|
|
old_ref. Has no effect is symbolic is True.
|
|
message: Optional reflog message.
|
|
symbolic: If True, ref will be set as a symbolic ref to new_ref
|
|
rather than the dereferenced object.
|
|
"""
|
|
|
|
@abstractmethod
|
|
def get_ref(self, name, follow: Optional[bool] = True) -> Optional[str]:
|
|
"""Return the value of specified ref.
|
|
|
|
If follow is false, symbolic refs will not be dereferenced.
|
|
Returns None if the ref does not exist.
|
|
"""
|
|
|
|
@abstractmethod
|
|
def remove_ref(self, name: str, old_ref: Optional[str] = None):
|
|
"""Remove the specified git ref.
|
|
|
|
If old_ref is specified, ref will only be removed if it currently
|
|
equals old_ref.
|
|
"""
|
|
|
|
@abstractmethod
|
|
def get_refs_containing(self, rev: str, pattern: Optional[str] = None):
|
|
"""Iterate over all git refs containing the specfied revision."""
|
|
|
|
@abstractmethod
|
|
def push_refspec(self, url: str, src: Optional[str], dest: str):
|
|
"""Push refspec to a remote Git repo.
|
|
|
|
Args:
|
|
url: Remote repo Git URL (Note this must be a Git URL and not
|
|
a remote name).
|
|
src: Local refspec. If src ends with "/" it will be treated as a
|
|
prefix, and all refs inside src will be pushed using dest
|
|
as destination refspec prefix. If src is None, dest will be
|
|
deleted from the remote.
|
|
dest: Remote refspec.
|
|
"""
|
|
|
|
@abstractmethod
|
|
def fetch_refspecs(
|
|
self,
|
|
url: str,
|
|
refspecs: Iterable[str],
|
|
force: Optional[bool] = False,
|
|
on_diverged: Optional[Callable[[bytes, bytes], bool]] = None,
|
|
):
|
|
"""Fetch refspecs from a remote Git repo.
|
|
|
|
Args:
|
|
url: Remote repo Git URL (Note this must be a Git URL and not
|
|
a remote name).
|
|
refspecs: Iterable containing refspecs to fetch.
|
|
Note that this will not match subkeys.
|
|
force: If True, local refs will be overwritten.
|
|
on_diverged: Callback function which will be called if local ref
|
|
and remote have diverged and force is False. If the callback
|
|
returns True the local ref will be overwritten.
|
|
"""
|
|
|
|
@abstractmethod
|
|
def _stash_iter(self, ref: str):
|
|
"""Iterate over stash commits in the specified ref."""
|
|
|
|
@abstractmethod
|
|
def _stash_push(
|
|
self,
|
|
ref: str,
|
|
message: Optional[str] = None,
|
|
include_untracked: Optional[bool] = False,
|
|
) -> Tuple[Optional[str], bool]:
|
|
"""Push a commit onto the specified stash."""
|
|
|
|
@abstractmethod
|
|
def _stash_apply(self, rev: str):
|
|
"""Apply the specified stash revision."""
|
|
|
|
@abstractmethod
|
|
def reflog_delete(self, ref: str, updateref: bool = False):
|
|
"""Delete the specified reflog entry."""
|