mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-06 23:09:55 +01:00
git: add support for working with refspecs and stashes (#4952)
* 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
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import logging
|
||||
from typing import Callable, Iterable, Optional, Tuple
|
||||
|
||||
from .base import BaseGitBackend
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GitPythonBackend(BaseGitBackend): # pylint:disable=abstract-method
|
||||
"""git-python Git backend."""
|
||||
|
||||
@property
|
||||
def git(self):
|
||||
return self.scm.repo.git
|
||||
|
||||
def is_ignored(self, path):
|
||||
raise NotImplementedError
|
||||
|
||||
def set_ref(
|
||||
self,
|
||||
name: str,
|
||||
new_ref: str,
|
||||
old_ref: Optional[str] = None,
|
||||
message: Optional[str] = None,
|
||||
symbolic: Optional[bool] = False,
|
||||
):
|
||||
raise NotImplementedError
|
||||
|
||||
def get_ref(self, name, follow: Optional[bool] = True) -> Optional[str]:
|
||||
raise NotImplementedError
|
||||
|
||||
def remove_ref(self, name: str, old_ref: Optional[str] = None):
|
||||
raise NotImplementedError
|
||||
|
||||
def get_refs_containing(self, rev: str, pattern: Optional[str] = None):
|
||||
from git.exc import GitCommandError
|
||||
|
||||
try:
|
||||
if pattern:
|
||||
args = [pattern]
|
||||
else:
|
||||
args = []
|
||||
for line in self.git.for_each_ref(
|
||||
*args, contains=rev, format=r"%(refname)"
|
||||
).splitlines():
|
||||
line = line.strip()
|
||||
if line:
|
||||
yield line
|
||||
except GitCommandError:
|
||||
pass
|
||||
|
||||
def push_refspec(self, url: str, src: Optional[str], dest: str):
|
||||
raise NotImplementedError
|
||||
|
||||
def fetch_refspecs(
|
||||
self,
|
||||
url: str,
|
||||
refspecs: Iterable[str],
|
||||
force: Optional[bool] = False,
|
||||
on_diverged: Optional[Callable[[bytes, bytes], bool]] = None,
|
||||
):
|
||||
raise NotImplementedError
|
||||
|
||||
def _stash_iter(self, ref: str):
|
||||
raise NotImplementedError
|
||||
|
||||
def _stash_push(
|
||||
self,
|
||||
ref: str,
|
||||
message: Optional[str] = None,
|
||||
include_untracked: Optional[bool] = False,
|
||||
) -> Tuple[Optional[str], bool]:
|
||||
from dvc.scm.git import Stash
|
||||
|
||||
args = ["push"]
|
||||
if message:
|
||||
args.extend(["-m", message])
|
||||
if include_untracked:
|
||||
args.append("--include-untracked")
|
||||
self.git.stash(*args)
|
||||
commit = self.scm.resolve_commit("stash@{0}")
|
||||
if ref != Stash.DEFAULT_STASH:
|
||||
# `git stash` CLI doesn't support using custom refspecs,
|
||||
# so we push a commit onto refs/stash, make our refspec
|
||||
# point to the new commit, then pop it from refs/stash
|
||||
# `git stash create` is intended to be used for this kind of
|
||||
# behavior but it doesn't support --include-untracked so we need to
|
||||
# use push
|
||||
self.scm.set_ref(ref, commit.hexsha, message=commit.message)
|
||||
self.git.stash("drop")
|
||||
return commit.hexsha, False
|
||||
|
||||
def _stash_apply(self, rev: str):
|
||||
self.git.stash("apply", rev)
|
||||
|
||||
def reflog_delete(self, ref: str, updateref: bool = False):
|
||||
args = ["delete"]
|
||||
if updateref:
|
||||
args.append("--updateref")
|
||||
args.append(ref)
|
||||
self.git.reflog(*args)
|
||||
Reference in New Issue
Block a user