summaryrefslogtreecommitdiff
path: root/git/index/base.py
diff options
context:
space:
mode:
Diffstat (limited to 'git/index/base.py')
-rw-r--r--git/index/base.py479
1 files changed, 310 insertions, 169 deletions
diff --git a/git/index/base.py b/git/index/base.py
index 00e51bf5..48894833 100644
--- a/git/index/base.py
+++ b/git/index/base.py
@@ -15,12 +15,7 @@ from git.compat import (
force_bytes,
defenc,
)
-from git.exc import (
- GitCommandError,
- CheckoutError,
- GitError,
- InvalidGitRepositoryError
-)
+from git.exc import GitCommandError, CheckoutError, GitError, InvalidGitRepositoryError
from git.objects import (
Blob,
Submodule,
@@ -36,7 +31,7 @@ from git.util import (
file_contents_ro,
to_native_path_linux,
unbare_repo,
- to_bin_sha
+ to_bin_sha,
)
from gitdb.base import IStream
from gitdb.db import MemoryDB
@@ -52,23 +47,32 @@ from .fun import (
write_tree_from_cache,
stat_mode_to_index_mode,
S_IFGITLINK,
- run_commit_hook
+ run_commit_hook,
)
from .typ import (
BaseIndexEntry,
IndexEntry,
)
-from .util import (
- TemporaryFileSwap,
- post_clear_cache,
- default_index,
- git_working_dir
-)
+from .util import TemporaryFileSwap, post_clear_cache, default_index, git_working_dir
# typing -----------------------------------------------------------------------------
-from typing import (Any, BinaryIO, Callable, Dict, IO, Iterable, Iterator, List, NoReturn,
- Sequence, TYPE_CHECKING, Tuple, Type, Union)
+from typing import (
+ Any,
+ BinaryIO,
+ Callable,
+ Dict,
+ IO,
+ Iterable,
+ Iterator,
+ List,
+ NoReturn,
+ Sequence,
+ TYPE_CHECKING,
+ Tuple,
+ Type,
+ Union,
+)
from git.types import Commit_ish, PathLike
@@ -85,7 +89,7 @@ Treeish = Union[Tree, Commit, str, bytes]
# ------------------------------------------------------------------------------------
-__all__ = ('IndexFile', 'CheckoutError')
+__all__ = ("IndexFile", "CheckoutError")
class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
@@ -110,11 +114,12 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
Make sure you use index.write() once you are done manipulating the index directly
before operating on it using the git command"""
+
__slots__ = ("repo", "version", "entries", "_extension_data", "_file_path")
- _VERSION = 2 # latest version we support
+ _VERSION = 2 # latest version we support
S_IFGITLINK = S_IFGITLINK # a submodule
- def __init__(self, repo: 'Repo', file_path: Union[PathLike, None] = None) -> None:
+ def __init__(self, repo: "Repo", file_path: Union[PathLike, None] = None) -> None:
"""Initialize this Index instance, optionally from the given ``file_path``.
If no file_path is given, we will be created from the current index file.
@@ -122,7 +127,7 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
repository's index on demand."""
self.repo = repo
self.version = self._VERSION
- self._extension_data = b''
+ self._extension_data = b""
self._file_path: PathLike = file_path or self._index_path()
def _set_cache_(self, attr: str) -> None:
@@ -152,40 +157,48 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
@property
def path(self) -> PathLike:
- """ :return: Path to the index file we are representing """
+ """:return: Path to the index file we are representing"""
return self._file_path
def _delete_entries_cache(self) -> None:
"""Safely clear the entries cache so it can be recreated"""
try:
- del(self.entries)
+ del self.entries
except AttributeError:
# fails in python 2.6.5 with this exception
pass
# END exception handling
- #{ Serializable Interface
+ # { Serializable Interface
- def _deserialize(self, stream: IO) -> 'IndexFile':
+ def _deserialize(self, stream: IO) -> "IndexFile":
"""Initialize this instance with index values read from the given stream"""
- self.version, self.entries, self._extension_data, _conten_sha = read_cache(stream)
+ self.version, self.entries, self._extension_data, _conten_sha = read_cache(
+ stream
+ )
return self
def _entries_sorted(self) -> List[IndexEntry]:
""":return: list of entries, in a sorted fashion, first by path, then by stage"""
return sorted(self.entries.values(), key=lambda e: (e.path, e.stage))
- def _serialize(self, stream: IO, ignore_extension_data: bool = False) -> 'IndexFile':
+ def _serialize(
+ self, stream: IO, ignore_extension_data: bool = False
+ ) -> "IndexFile":
entries = self._entries_sorted()
- extension_data = self._extension_data # type: Union[None, bytes]
+ extension_data = self._extension_data # type: Union[None, bytes]
if ignore_extension_data:
extension_data = None
write_cache(entries, stream, extension_data)
return self
- #} END serializable interface
+ # } END serializable interface
- def write(self, file_path: Union[None, PathLike] = None, ignore_extension_data: bool = False) -> None:
+ def write(
+ self,
+ file_path: Union[None, PathLike] = None,
+ ignore_extension_data: bool = False,
+ ) -> None:
"""Write the current state to our file path or to the given one
:param file_path:
@@ -229,7 +242,9 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
@post_clear_cache
@default_index
- def merge_tree(self, rhs: Treeish, base: Union[None, Treeish] = None) -> 'IndexFile':
+ def merge_tree(
+ self, rhs: Treeish, base: Union[None, Treeish] = None
+ ) -> "IndexFile":
"""Merge the given rhs treeish into the current index, possibly taking
a common base treeish into account.
@@ -252,7 +267,7 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
be raised at the first conflicting path. If you want to have proper
merge resolution to be done by yourself, you have to commit the changed
index ( or make a valid tree from it ) and retry with a three-way
- index.from_tree call. """
+ index.from_tree call."""
# -i : ignore working tree status
# --aggressive : handle more merge cases
# -m : do an actual merge
@@ -265,8 +280,8 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
return self
@classmethod
- def new(cls, repo: 'Repo', *tree_sha: Union[str, Tree]) -> 'IndexFile':
- """ Merge the given treeish revisions into a new index which is returned.
+ def new(cls, repo: "Repo", *tree_sha: Union[str, Tree]) -> "IndexFile":
+ """Merge the given treeish revisions into a new index which is returned.
This method behaves like git-read-tree --aggressive when doing the merge.
:param repo: The repository treeish are located in.
@@ -283,15 +298,18 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
inst = cls(repo)
# convert to entries dict
- entries: Dict[Tuple[PathLike, int], IndexEntry] = dict(zip(
- ((e.path, e.stage) for e in base_entries),
- (IndexEntry.from_base(e) for e in base_entries)))
+ entries: Dict[Tuple[PathLike, int], IndexEntry] = dict(
+ zip(
+ ((e.path, e.stage) for e in base_entries),
+ (IndexEntry.from_base(e) for e in base_entries),
+ )
+ )
inst.entries = entries
return inst
@classmethod
- def from_tree(cls, repo: 'Repo', *treeish: Treeish, **kwargs: Any) -> 'IndexFile':
+ def from_tree(cls, repo: "Repo", *treeish: Treeish, **kwargs: Any) -> "IndexFile":
"""Merge the given treeish revisions into a new index which is returned.
The original index will remain unaltered
@@ -326,7 +344,9 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
it will be temporarily moved out of the way to assure there are no unsuspected
interferences."""
if len(treeish) == 0 or len(treeish) > 3:
- raise ValueError("Please specify between 1 and 3 treeish, got %i" % len(treeish))
+ raise ValueError(
+ "Please specify between 1 and 3 treeish, got %i" % len(treeish)
+ )
arg_list: List[Union[Treeish, str]] = []
# ignore that working tree and index possibly are out of date
@@ -339,7 +359,7 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# tmp file created in git home directory to be sure renaming
# works - /tmp/ dirs could be on another device
- tmp_index = tempfile.mktemp('', '', repo.git_dir)
+ tmp_index = tempfile.mktemp("", "", repo.git_dir)
arg_list.append("--index-output=%s" % tmp_index)
arg_list.extend(treeish)
@@ -348,12 +368,12 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# Unfortunately there is no 'soft' way to do it.
# The TemporaryFileSwap assure the original file get put back
if repo.git_dir:
- index_handler = TemporaryFileSwap(join_path_native(repo.git_dir, 'index'))
+ index_handler = TemporaryFileSwap(join_path_native(repo.git_dir, "index"))
try:
repo.git.read_tree(*arg_list, **kwargs)
index = cls(repo, tmp_index)
- index.entries # force it to read the file as we will delete the temp-file
- del(index_handler) # release as soon as possible
+ index.entries # force it to read the file as we will delete the temp-file
+ del index_handler # release as soon as possible
finally:
if osp.exists(tmp_index):
os.remove(tmp_index)
@@ -363,14 +383,18 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# UTILITIES
@unbare_repo
- def _iter_expand_paths(self: 'IndexFile', paths: Sequence[PathLike]) -> Iterator[PathLike]:
+ def _iter_expand_paths(
+ self: "IndexFile", paths: Sequence[PathLike]
+ ) -> Iterator[PathLike]:
"""Expand the directories in list of paths to the corresponding paths accordingly,
Note: git will add items multiple times even if a glob overlapped
with manually specified paths or if paths where specified multiple
times - we respect that and do not prune"""
+
def raise_exc(e: Exception) -> NoReturn:
raise e
+
r = str(self.repo.working_tree_dir)
rs = r + os.sep
for path in paths:
@@ -380,18 +404,20 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# END make absolute path
try:
- st = os.lstat(abs_path) # handles non-symlinks as well
+ st = os.lstat(abs_path) # handles non-symlinks as well
except OSError:
# the lstat call may fail as the path may contain globs as well
pass
else:
if S_ISLNK(st.st_mode):
- yield abs_path.replace(rs, '')
+ yield abs_path.replace(rs, "")
continue
# end check symlink
# if the path is not already pointing to an existing file, resolve globs if possible
- if not os.path.exists(abs_path) and ('?' in abs_path or '*' in abs_path or '[' in abs_path):
+ if not os.path.exists(abs_path) and (
+ "?" in abs_path or "*" in abs_path or "[" in abs_path
+ ):
resolved_paths = glob.glob(abs_path)
# not abs_path in resolved_paths:
# a glob() resolving to the same path we are feeding it with
@@ -401,25 +427,31 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# whose name contains wildcard characters.
if abs_path not in resolved_paths:
for f in self._iter_expand_paths(glob.glob(abs_path)):
- yield str(f).replace(rs, '')
+ yield str(f).replace(rs, "")
continue
# END glob handling
try:
for root, _dirs, files in os.walk(abs_path, onerror=raise_exc):
for rela_file in files:
# add relative paths only
- yield osp.join(root.replace(rs, ''), rela_file)
+ yield osp.join(root.replace(rs, ""), rela_file)
# END for each file in subdir
# END for each subdirectory
except OSError:
# was a file or something that could not be iterated
- yield abs_path.replace(rs, '')
+ yield abs_path.replace(rs, "")
# END path exception handling
# END for each path
- def _write_path_to_stdin(self, proc: 'Popen', filepath: PathLike, item: PathLike, fmakeexc: Callable[..., GitError],
- fprogress: Callable[[PathLike, bool, PathLike], None],
- read_from_stdout: bool = True) -> Union[None, str]:
+ def _write_path_to_stdin(
+ self,
+ proc: "Popen",
+ filepath: PathLike,
+ item: PathLike,
+ fmakeexc: Callable[..., GitError],
+ fprogress: Callable[[PathLike, bool, PathLike], None],
+ read_from_stdout: bool = True,
+ ) -> Union[None, str]:
"""Write path to proc.stdin and make sure it processes the item, including progress.
:return: stdout string
@@ -451,15 +483,16 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
fprogress(filepath, True, item)
return rval
- def iter_blobs(self, predicate: Callable[[Tuple[StageType, Blob]], bool] = lambda t: True
- ) -> Iterator[Tuple[StageType, Blob]]:
+ def iter_blobs(
+ self, predicate: Callable[[Tuple[StageType, Blob]], bool] = lambda t: True
+ ) -> Iterator[Tuple[StageType, Blob]]:
"""
:return: Iterator yielding tuples of Blob objects and stages, tuple(stage, Blob)
:param predicate:
Function(t) returning True if tuple(stage, Blob) should be yielded by the
iterator. A default filter, the BlobFilter, allows you to yield blobs
- only if they match a given list of paths. """
+ only if they match a given list of paths."""
for entry in self.entries.values():
blob = entry.to_blob(self.repo)
blob.size = entry.size
@@ -491,11 +524,13 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
return path_map
- @ classmethod
- def entry_key(cls, *entry: Union[BaseIndexEntry, PathLike, StageType]) -> Tuple[PathLike, StageType]:
+ @classmethod
+ def entry_key(
+ cls, *entry: Union[BaseIndexEntry, PathLike, StageType]
+ ) -> Tuple[PathLike, StageType]:
return entry_key(*entry)
- def resolve_blobs(self, iter_blobs: Iterator[Blob]) -> 'IndexFile':
+ def resolve_blobs(self, iter_blobs: Iterator[Blob]) -> "IndexFile":
"""Resolve the blobs given in blob iterator. This will effectively remove the
index entries of the respective path at all non-null stages and add the given
blob as new stage null blob.
@@ -519,7 +554,7 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# delete all possible stages
for stage in (1, 2, 3):
try:
- del(self.entries[(blob.path, stage)])
+ del self.entries[(blob.path, stage)]
except KeyError:
pass
# END ignore key errors
@@ -530,7 +565,7 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
return self
- def update(self) -> 'IndexFile':
+ def update(self) -> "IndexFile":
"""Reread the contents of our index file, discarding all cached information
we might have.
@@ -550,7 +585,7 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
does not yet exist in the object database. This could happen if you added
Entries to the index directly.
:raise ValueError: if there are no entries in the cache
- :raise UnmergedEntriesError: """
+ :raise UnmergedEntriesError:"""
# we obtain no lock as we just flush our contents to disk as tree
# If we are a new index, the entries access will load our data accordingly
mdb = MemoryDB()
@@ -562,13 +597,14 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# note: additional deserialization could be saved if write_tree_from_cache
# would return sorted tree entries
- root_tree = Tree(self.repo, binsha, path='')
+ root_tree = Tree(self.repo, binsha, path="")
root_tree._cache = tree_items
return root_tree
- def _process_diff_args(self, # type: ignore[override]
- args: List[Union[str, 'git_diff.Diffable', Type['git_diff.Diffable.Index']]]
- ) -> List[Union[str, 'git_diff.Diffable', Type['git_diff.Diffable.Index']]]:
+ def _process_diff_args(
+ self, # type: ignore[override]
+ args: List[Union[str, "git_diff.Diffable", Type["git_diff.Diffable.Index"]]],
+ ) -> List[Union[str, "git_diff.Diffable", Type["git_diff.Diffable.Index"]]]:
try:
args.pop(args.index(self))
except IndexError:
@@ -585,12 +621,16 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
if self.repo.bare:
raise InvalidGitRepositoryError("require non-bare repository")
if not str(path).startswith(str(self.repo.working_tree_dir)):
- raise ValueError("Absolute path %r is not in git repository at %r" % (path, self.repo.working_tree_dir))
+ raise ValueError(
+ "Absolute path %r is not in git repository at %r"
+ % (path, self.repo.working_tree_dir)
+ )
return os.path.relpath(path, self.repo.working_tree_dir)
- def _preprocess_add_items(self, items: Sequence[Union[PathLike, Blob, BaseIndexEntry, 'Submodule']]
- ) -> Tuple[List[PathLike], List[BaseIndexEntry]]:
- """ Split the items into two lists of path strings and BaseEntries. """
+ def _preprocess_add_items(
+ self, items: Sequence[Union[PathLike, Blob, BaseIndexEntry, "Submodule"]]
+ ) -> Tuple[List[PathLike], List[BaseIndexEntry]]:
+ """Split the items into two lists of path strings and BaseEntries."""
paths = []
entries = []
# if it is a string put in list
@@ -612,43 +652,58 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
def _store_path(self, filepath: PathLike, fprogress: Callable) -> BaseIndexEntry:
"""Store file at filepath in the database and return the base index entry
Needs the git_working_dir decorator active ! This must be assured in the calling code"""
- st = os.lstat(filepath) # handles non-symlinks as well
+ st = os.lstat(filepath) # handles non-symlinks as well
if S_ISLNK(st.st_mode):
# in PY3, readlink is string, but we need bytes. In PY2, it's just OS encoded bytes, we assume UTF-8
- open_stream: Callable[[], BinaryIO] = lambda: BytesIO(force_bytes(os.readlink(filepath),
- encoding=defenc))
+ open_stream: Callable[[], BinaryIO] = lambda: BytesIO(
+ force_bytes(os.readlink(filepath), encoding=defenc)
+ )
else:
- open_stream = lambda: open(filepath, 'rb')
+ open_stream = lambda: open(filepath, "rb")
with open_stream() as stream:
fprogress(filepath, False, filepath)
istream = self.repo.odb.store(IStream(Blob.type, st.st_size, stream))
fprogress(filepath, True, filepath)
- return BaseIndexEntry((stat_mode_to_index_mode(st.st_mode),
- istream.binsha, 0, to_native_path_linux(filepath)))
+ return BaseIndexEntry(
+ (
+ stat_mode_to_index_mode(st.st_mode),
+ istream.binsha,
+ 0,
+ to_native_path_linux(filepath),
+ )
+ )
- @ unbare_repo
- @ git_working_dir
- def _entries_for_paths(self, paths: List[str], path_rewriter: Callable, fprogress: Callable,
- entries: List[BaseIndexEntry]) -> List[BaseIndexEntry]:
+ @unbare_repo
+ @git_working_dir
+ def _entries_for_paths(
+ self,
+ paths: List[str],
+ path_rewriter: Callable,
+ fprogress: Callable,
+ entries: List[BaseIndexEntry],
+ ) -> List[BaseIndexEntry]:
entries_added: List[BaseIndexEntry] = []
if path_rewriter:
for path in paths:
if osp.isabs(path):
abspath = path
- gitrelative_path = path[len(str(self.repo.working_tree_dir)) + 1:]
+ gitrelative_path = path[len(str(self.repo.working_tree_dir)) + 1 :]
else:
gitrelative_path = path
if self.repo.working_tree_dir:
abspath = osp.join(self.repo.working_tree_dir, gitrelative_path)
# end obtain relative and absolute paths
- blob = Blob(self.repo, Blob.NULL_BIN_SHA,
- stat_mode_to_index_mode(os.stat(abspath).st_mode),
- to_native_path_linux(gitrelative_path))
+ blob = Blob(
+ self.repo,
+ Blob.NULL_BIN_SHA,
+ stat_mode_to_index_mode(os.stat(abspath).st_mode),
+ to_native_path_linux(gitrelative_path),
+ )
# TODO: variable undefined
entries.append(BaseIndexEntry.from_blob(blob))
# END for each path
- del(paths[:])
+ del paths[:]
# END rewrite paths
# HANDLE PATHS
@@ -659,9 +714,15 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# END path handling
return entries_added
- def add(self, items: Sequence[Union[PathLike, Blob, BaseIndexEntry, 'Submodule']], force: bool = True,
- fprogress: Callable = lambda *args: None, path_rewriter: Union[Callable[..., PathLike], None] = None,
- write: bool = True, write_extension_data: bool = False) -> List[BaseIndexEntry]:
+ def add(
+ self,
+ items: Sequence[Union[PathLike, Blob, BaseIndexEntry, "Submodule"]],
+ force: bool = True,
+ fprogress: Callable = lambda *args: None,
+ path_rewriter: Union[Callable[..., PathLike], None] = None,
+ write: bool = True,
+ write_extension_data: bool = False,
+ ) -> List[BaseIndexEntry]:
"""Add files from the working tree, specific blobs or BaseIndexEntries
to the index.
@@ -769,30 +830,43 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# That way, we are OK on a bare repository as well.
# If there are no paths, the rewriter has nothing to do either
if paths:
- entries_added.extend(self._entries_for_paths(paths, path_rewriter, fprogress, entries))
+ entries_added.extend(
+ self._entries_for_paths(paths, path_rewriter, fprogress, entries)
+ )
# HANDLE ENTRIES
if entries:
null_mode_entries = [e for e in entries if e.mode == 0]
if null_mode_entries:
raise ValueError(
- "At least one Entry has a null-mode - please use index.remove to remove files for clarity")
+ "At least one Entry has a null-mode - please use index.remove to remove files for clarity"
+ )
# END null mode should be remove
# HANDLE ENTRY OBJECT CREATION
# create objects if required, otherwise go with the existing shas
- null_entries_indices = [i for i, e in enumerate(entries) if e.binsha == Object.NULL_BIN_SHA]
+ null_entries_indices = [
+ i for i, e in enumerate(entries) if e.binsha == Object.NULL_BIN_SHA
+ ]
if null_entries_indices:
- @ git_working_dir
- def handle_null_entries(self: 'IndexFile') -> None:
+
+ @git_working_dir
+ def handle_null_entries(self: "IndexFile") -> None:
for ei in null_entries_indices:
null_entry = entries[ei]
new_entry = self._store_path(null_entry.path, fprogress)
# update null entry
entries[ei] = BaseIndexEntry(
- (null_entry.mode, new_entry.binsha, null_entry.stage, null_entry.path))
+ (
+ null_entry.mode,
+ new_entry.binsha,
+ null_entry.stage,
+ null_entry.path,
+ )
+ )
# END for each entry index
+
# end closure
handle_null_entries(self)
# END null_entry handling
@@ -802,7 +876,9 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# all object sha's
if path_rewriter:
for i, e in enumerate(entries):
- entries[i] = BaseIndexEntry((e.mode, e.binsha, e.stage, path_rewriter(e)))
+ entries[i] = BaseIndexEntry(
+ (e.mode, e.binsha, e.stage, path_rewriter(e))
+ )
# END for each entry
# END handle path rewriting
@@ -828,8 +904,12 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
return entries_added
- def _items_to_rela_paths(self, items: Union[PathLike, Sequence[Union[PathLike, BaseIndexEntry, Blob, Submodule]]]
- ) -> List[PathLike]:
+ def _items_to_rela_paths(
+ self,
+ items: Union[
+ PathLike, Sequence[Union[PathLike, BaseIndexEntry, Blob, Submodule]]
+ ],
+ ) -> List[PathLike]:
"""Returns a list of repo-relative paths from the given items which
may be absolute or relative paths, entries or blobs"""
paths = []
@@ -847,10 +927,14 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# END for each item
return paths
- @ post_clear_cache
- @ default_index
- def remove(self, items: Sequence[Union[PathLike, Blob, BaseIndexEntry, 'Submodule']], working_tree: bool = False,
- **kwargs: Any) -> List[str]:
+ @post_clear_cache
+ @default_index
+ def remove(
+ self,
+ items: Sequence[Union[PathLike, Blob, BaseIndexEntry, "Submodule"]],
+ working_tree: bool = False,
+ **kwargs: Any
+ ) -> List[str]:
"""Remove the given items from the index and optionally from
the working tree as well.
@@ -885,7 +969,7 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
List(path_string, ...) list of repository relative paths that have
been removed effectively.
This is interesting to know in case you have provided a directory or
- globs. Paths are relative to the repository. """
+ globs. Paths are relative to the repository."""
args = []
if not working_tree:
args.append("--cached")
@@ -899,10 +983,14 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# rm 'path'
return [p[4:-1] for p in removed_paths]
- @ post_clear_cache
- @ default_index
- def move(self, items: Sequence[Union[PathLike, Blob, BaseIndexEntry, 'Submodule']], skip_errors: bool = False,
- **kwargs: Any) -> List[Tuple[str, str]]:
+ @post_clear_cache
+ @default_index
+ def move(
+ self,
+ items: Sequence[Union[PathLike, Blob, BaseIndexEntry, "Submodule"]],
+ skip_errors: bool = False,
+ **kwargs: Any
+ ) -> List[Tuple[str, str]]:
"""Rename/move the items, whereas the last item is considered the destination of
the move operation. If the destination is a file, the first item ( of two )
must be a file as well. If the destination is a directory, it may be preceded
@@ -928,14 +1016,16 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
GitCommandError: If git could not handle your request"""
args = []
if skip_errors:
- args.append('-k')
+ args.append("-k")
paths = self._items_to_rela_paths(items)
if len(paths) < 2:
- raise ValueError("Please provide at least one source and one destination of the move operation")
+ raise ValueError(
+ "Please provide at least one source and one destination of the move operation"
+ )
- was_dry_run = kwargs.pop('dry_run', kwargs.pop('n', None))
- kwargs['dry_run'] = True
+ was_dry_run = kwargs.pop("dry_run", kwargs.pop("n", None))
+ kwargs["dry_run"] = True
# first execute rename in dryrun so the command tells us what it actually does
# ( for later output )
@@ -945,7 +1035,7 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# parse result - first 0:n/2 lines are 'checking ', the remaining ones
# are the 'renaming' ones which we parse
for ln in range(int(len(mvlines) / 2), len(mvlines)):
- tokens = mvlines[ln].split(' to ')
+ tokens = mvlines[ln].split(" to ")
assert len(tokens) == 2, "Too many tokens in %s" % mvlines[ln]
# [0] = Renaming x
@@ -959,20 +1049,22 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# END handle dryrun
# now apply the actual operation
- kwargs.pop('dry_run')
+ kwargs.pop("dry_run")
self.repo.git.mv(args, paths, **kwargs)
return out
- def commit(self,
- message: str,
- parent_commits: Union[Commit_ish, None] = None,
- head: bool = True,
- author: Union[None, 'Actor'] = None,
- committer: Union[None, 'Actor'] = None,
- author_date: Union[str, None] = None,
- commit_date: Union[str, None] = None,
- skip_hooks: bool = False) -> Commit:
+ def commit(
+ self,
+ message: str,
+ parent_commits: Union[Commit_ish, None] = None,
+ head: bool = True,
+ author: Union[None, "Actor"] = None,
+ committer: Union[None, "Actor"] = None,
+ author_date: Union[str, None] = None,
+ commit_date: Union[str, None] = None,
+ skip_hooks: bool = False,
+ ) -> Commit:
"""Commit the current default index file, creating a commit object.
For more information on the arguments, see Commit.create_from_tree().
@@ -982,18 +1074,26 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
or `--no-verify` on the command line.
:return: Commit object representing the new commit"""
if not skip_hooks:
- run_commit_hook('pre-commit', self)
+ run_commit_hook("pre-commit", self)
self._write_commit_editmsg(message)
- run_commit_hook('commit-msg', self, self._commit_editmsg_filepath())
+ run_commit_hook("commit-msg", self, self._commit_editmsg_filepath())
message = self._read_commit_editmsg()
self._remove_commit_editmsg()
tree = self.write_tree()
- rval = Commit.create_from_tree(self.repo, tree, message, parent_commits,
- head, author=author, committer=committer,
- author_date=author_date, commit_date=commit_date)
+ rval = Commit.create_from_tree(
+ self.repo,
+ tree,
+ message,
+ parent_commits,
+ head,
+ author=author,
+ committer=committer,
+ author_date=author_date,
+ commit_date=commit_date,
+ )
if not skip_hooks:
- run_commit_hook('post-commit', self)
+ run_commit_hook("post-commit", self)
return rval
def _write_commit_editmsg(self, message: str) -> None:
@@ -1010,13 +1110,15 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
def _commit_editmsg_filepath(self) -> str:
return osp.join(self.repo.common_dir, "COMMIT_EDITMSG")
- def _flush_stdin_and_wait(cls, proc: 'Popen[bytes]', ignore_stdout: bool = False) -> bytes:
+ def _flush_stdin_and_wait(
+ cls, proc: "Popen[bytes]", ignore_stdout: bool = False
+ ) -> bytes:
stdin_IO = proc.stdin
if stdin_IO:
stdin_IO.flush()
stdin_IO.close()
- stdout = b''
+ stdout = b""
if not ignore_stdout and proc.stdout:
stdout = proc.stdout.read()
@@ -1025,10 +1127,14 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
proc.wait()
return stdout
- @ default_index
- def checkout(self, paths: Union[None, Iterable[PathLike]] = None, force: bool = False,
- fprogress: Callable = lambda *args: None, **kwargs: Any
- ) -> Union[None, Iterator[PathLike], Sequence[PathLike]]:
+ @default_index
+ def checkout(
+ self,
+ paths: Union[None, Iterable[PathLike]] = None,
+ force: bool = False,
+ fprogress: Callable = lambda *args: None,
+ **kwargs: Any
+ ) -> Union[None, Iterator[PathLike], Sequence[PathLike]]:
"""Checkout the given paths or all files from the version known to the index into
the working tree.
@@ -1070,7 +1176,7 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
the working tree will not be deleted. This behaviour is fundamentally
different to *head.checkout*, i.e. if you want git-checkout like behaviour,
use head.checkout instead of index.checkout.
- """
+ """
args = ["--index"]
if force:
args.append("--force")
@@ -1079,7 +1185,9 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
failed_reasons = []
unknown_lines = []
- def handle_stderr(proc: 'Popen[bytes]', iter_checked_out_files: Iterable[PathLike]) -> None:
+ def handle_stderr(
+ proc: "Popen[bytes]", iter_checked_out_files: Iterable[PathLike]
+ ) -> None:
stderr_IO = proc.stderr
if not stderr_IO:
@@ -1089,20 +1197,27 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# line contents:
stderr = stderr_bytes.decode(defenc)
# git-checkout-index: this already exists
- endings = (' already exists', ' is not in the cache', ' does not exist at stage', ' is unmerged')
+ endings = (
+ " already exists",
+ " is not in the cache",
+ " does not exist at stage",
+ " is unmerged",
+ )
for line in stderr.splitlines():
- if not line.startswith("git checkout-index: ") and not line.startswith("git-checkout-index: "):
+ if not line.startswith("git checkout-index: ") and not line.startswith(
+ "git-checkout-index: "
+ ):
is_a_dir = " is a directory"
unlink_issue = "unable to unlink old '"
- already_exists_issue = ' already exists, no checkout' # created by entry.c:checkout_entry(...)
+ already_exists_issue = " already exists, no checkout" # created by entry.c:checkout_entry(...)
if line.endswith(is_a_dir):
- failed_files.append(line[:-len(is_a_dir)])
+ failed_files.append(line[: -len(is_a_dir)])
failed_reasons.append(is_a_dir)
elif line.startswith(unlink_issue):
- failed_files.append(line[len(unlink_issue):line.rfind("'")])
+ failed_files.append(line[len(unlink_issue) : line.rfind("'")])
failed_reasons.append(unlink_issue)
elif line.endswith(already_exists_issue):
- failed_files.append(line[:-len(already_exists_issue)])
+ failed_files.append(line[: -len(already_exists_issue)])
failed_reasons.append(already_exists_issue)
else:
unknown_lines.append(line)
@@ -1111,7 +1226,7 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
for e in endings:
if line.endswith(e):
- failed_files.append(line[20:-len(e)])
+ failed_files.append(line[20 : -len(e)])
failed_reasons.append(e)
break
# END if ending matches
@@ -1123,12 +1238,16 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
valid_files = list(set(iter_checked_out_files) - set(failed_files))
raise CheckoutError(
"Some files could not be checked out from the index due to local modifications",
- failed_files, valid_files, failed_reasons)
+ failed_files,
+ valid_files,
+ failed_reasons,
+ )
+
# END stderr handler
if paths is None:
args.append("--all")
- kwargs['as_process'] = 1
+ kwargs["as_process"] = 1
fprogress(None, False, None)
proc = self.repo.git.checkout_index(*args, **kwargs)
proc.wait()
@@ -1146,11 +1265,13 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
self.entries
args.append("--stdin")
- kwargs['as_process'] = True
- kwargs['istream'] = subprocess.PIPE
+ kwargs["as_process"] = True
+ kwargs["istream"] = subprocess.PIPE
proc = self.repo.git.checkout_index(args, **kwargs)
# FIXME: Reading from GIL!
- make_exc = lambda: GitCommandError(("git-checkout-index",) + tuple(args), 128, proc.stderr.read())
+ make_exc = lambda: GitCommandError(
+ ("git-checkout-index",) + tuple(args), 128, proc.stderr.read()
+ )
checked_out_files: List[PathLike] = []
for path in paths:
@@ -1162,13 +1283,14 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
self.entries[(co_path, 0)]
except KeyError:
folder = str(co_path)
- if not folder.endswith('/'):
- folder += '/'
+ if not folder.endswith("/"):
+ folder += "/"
for entry in self.entries.values():
if str(entry.path).startswith(folder):
p = entry.path
- self._write_path_to_stdin(proc, p, p, make_exc,
- fprogress, read_from_stdout=False)
+ self._write_path_to_stdin(
+ proc, p, p, make_exc, fprogress, read_from_stdout=False
+ )
checked_out_files.append(p)
path_is_directory = True
# END if entry is in directory
@@ -1176,8 +1298,9 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# END path exception handlnig
if not path_is_directory:
- self._write_path_to_stdin(proc, co_path, path, make_exc,
- fprogress, read_from_stdout=False)
+ self._write_path_to_stdin(
+ proc, co_path, path, make_exc, fprogress, read_from_stdout=False
+ )
checked_out_files.append(co_path)
# END path is a file
# END for each path
@@ -1187,16 +1310,24 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# Without parsing stdout we don't know what failed.
raise CheckoutError(
"Some files could not be checked out from the index, probably because they didn't exist.",
- failed_files, [], failed_reasons)
+ failed_files,
+ [],
+ failed_reasons,
+ )
handle_stderr(proc, checked_out_files)
return checked_out_files
# END paths handling
- @ default_index
- def reset(self, commit: Union[Commit, 'Reference', str] = 'HEAD', working_tree: bool = False,
- paths: Union[None, Iterable[PathLike]] = None,
- head: bool = False, **kwargs: Any) -> 'IndexFile':
+ @default_index
+ def reset(
+ self,
+ commit: Union[Commit, "Reference", str] = "HEAD",
+ working_tree: bool = False,
+ paths: Union[None, Iterable[PathLike]] = None,
+ head: bool = False,
+ **kwargs: Any
+ ) -> "IndexFile":
"""Reset the index to reflect the tree at the given commit. This will not
adjust our HEAD reference as opposed to HEAD.reset by default.
@@ -1228,7 +1359,7 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
checkout the files according to their state in the index.
If you want git-reset like behaviour, use *HEAD.reset* instead.
- :return: self """
+ :return: self"""
# what we actually want to do is to merge the tree into our existing
# index, which is what git-read-tree does
new_inst = type(self).from_tree(self.repo, commit)
@@ -1244,7 +1375,7 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
except KeyError:
# if key is not in theirs, it musn't be in ours
try:
- del(self.entries[key])
+ del self.entries[key]
except KeyError:
pass
# END handle deletion keyerror
@@ -1258,17 +1389,23 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# END handle working tree
if head:
- self.repo.head.set_commit(self.repo.commit(commit), logmsg="%s: Updating HEAD" % commit)
+ self.repo.head.set_commit(
+ self.repo.commit(commit), logmsg="%s: Updating HEAD" % commit
+ )
# END handle head change
return self
# @ default_index, breaks typing for some reason, copied into function
- def diff(self, # type: ignore[override]
- other: Union[Type['git_diff.Diffable.Index'], 'Tree', 'Commit', str, None] = git_diff.Diffable.Index,
- paths: Union[PathLike, List[PathLike], Tuple[PathLike, ...], None] = None,
- create_patch: bool = False, **kwargs: Any
- ) -> git_diff.DiffIndex:
+ def diff(
+ self, # type: ignore[override]
+ other: Union[
+ Type["git_diff.Diffable.Index"], "Tree", "Commit", str, None
+ ] = git_diff.Diffable.Index,
+ paths: Union[PathLike, List[PathLike], Tuple[PathLike, ...], None] = None,
+ create_patch: bool = False,
+ **kwargs: Any
+ ) -> git_diff.DiffIndex:
"""Diff this index against the working copy or a Tree or Commit object
For a documentation of the parameters and return values, see,
@@ -1282,7 +1419,9 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
# only run if we are the default repository index
if self._file_path != self._index_path():
raise AssertionError(
- "Cannot call %r on indices that do not represent the default git index" % self.diff())
+ "Cannot call %r on indices that do not represent the default git index"
+ % self.diff()
+ )
# index against index is always empty
if other is self.Index:
return git_diff.DiffIndex()
@@ -1296,14 +1435,16 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
if isinstance(other, Object): # for Tree or Commit
# invert the existing R flag
- cur_val = kwargs.get('R', False)
- kwargs['R'] = not cur_val
+ cur_val = kwargs.get("R", False)
+ kwargs["R"] = not cur_val
return other.diff(self.Index, paths, create_patch, **kwargs)
# END diff against other item handling
# if other is not None here, something is wrong
if other is not None:
- raise ValueError("other must be None, Diffable.Index, a Tree or Commit, was %r" % other)
+ raise ValueError(
+ "other must be None, Diffable.Index, a Tree or Commit, was %r" % other
+ )
# diff against working copy - can be handled by superclass natively
return super(IndexFile, self).diff(other, paths, create_patch, **kwargs)