GeezerVison is showing github.com — index: write blobs via git hash-object, not gitdb's odb.store · gitpython-developers/GitPython@4dbefc1
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: git/index/base.py +23-14Lines changed: 23 additions & 14 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 11 | 11 | import contextlib | 12 | 12 | import datetime | 13 | 13 | import glob | 14 | | -from io import BytesIO | 15 | 14 | import os | 16 | 15 | import os.path as osp | 17 | 16 | from stat import S_ISLNK | 18 | 17 | import subprocess | 19 | 18 | import sys | 20 | 19 | import tempfile | 21 | 20 |
| 22 | | -from gitdb.base import IStream | 23 | 21 | from gitdb.db import MemoryDB | 24 | 22 |
| 25 | 23 | from git.compat import defenc, force_bytes | | 34 | 32 | LockedFD, | 35 | 33 | join_path_native, | 36 | 34 | file_contents_ro, | | 35 | + hex_to_bin, | 37 | 36 | _is_path_rooted, | 38 | 37 | _to_relative_path, | 39 | 38 | to_native_path_linux, | | 58 | 57 |
| 59 | 58 | from typing import ( | 60 | 59 | Any, | 61 | | - BinaryIO, | 62 | 60 | Callable, | 63 | 61 | cast, | 64 | 62 | Dict, | @@ -726,24 +724,35 @@ def _store_path(self, filepath: PathLike, fprogress: Callable) -> BaseIndexEntry | 726 | 724 | """ | 727 | 725 | st = os.lstat(filepath) # Handles non-symlinks as well. | 728 | 726 |
| | 727 | + fprogress(filepath, False, filepath) | 729 | 728 | if S_ISLNK(st.st_mode): | 730 | 729 | # In PY3, readlink is a string, but we need bytes. | 731 | 730 | # In PY2, it was just OS encoded bytes, we assumed UTF-8. | 732 | | - def open_stream() -> BinaryIO: | 733 | | - return BytesIO(force_bytes(os.readlink(filepath), encoding=defenc)) | | 731 | + # | | 732 | + # `git hash-object` on a symlink path follows the link and hashes the | | 733 | + # target file's content, whereas Git stores the link's target string as | | 734 | + # the blob content. So the target string is written to a regular | | 735 | + # temporary file and hashed from there instead of passing the symlink | | 736 | + # path directly. | | 737 | + target = force_bytes(os.readlink(filepath), encoding=defenc) | | 738 | + fd, tmp_path = tempfile.mkstemp() | | 739 | + try: | | 740 | + os.write(fd, target) | | 741 | + os.close(fd) | | 742 | + hexsha = self.repo.git.hash_object(tmp_path, w=True, no_filters=True) | | 743 | + finally: | | 744 | + os.remove(tmp_path) | 734 | 745 | else: | 735 | | - | 736 | | - def open_stream() -> BinaryIO: | 737 | | - return open(filepath, "rb") | 738 | | - | 739 | | - with open_stream() as stream: | 740 | | - fprogress(filepath, False, filepath) | 741 | | - istream = self.repo.odb.store(IStream(Blob.type, st.st_size, stream)) | 742 | | - fprogress(filepath, True, filepath) | | 746 | + # Let the `git` binary write the object. This matches `git add`'s | | 747 | + # behavior exactly, including applying any clean filters configured via | | 748 | + # `.gitattributes`, and avoids reimplementing object creation (and its | | 749 | + # object-file permission handling) in Python. | | 750 | + hexsha = self.repo.git.hash_object(filepath, w=True) | | 751 | + fprogress(filepath, True, filepath) | 743 | 752 | return BaseIndexEntry( | 744 | 753 | ( | 745 | 754 | stat_mode_to_index_mode(st.st_mode), | 746 | | - istream.binsha, | | 755 | + hex_to_bin(hexsha), | 747 | 756 | 0, | 748 | 757 | to_native_path_linux(filepath), | 749 | 758 | ) | |
|