GitPython 3.1.59__tar.gz → 3.1.60__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gitpython-3.1.59 → gitpython-3.1.60/GitPython.egg-info}/PKG-INFO +1 -1
- {gitpython-3.1.59/GitPython.egg-info → gitpython-3.1.60}/PKG-INFO +1 -1
- gitpython-3.1.60/VERSION +1 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/doc/source/changes.rst +15 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/__init__.py +1 -1
- {gitpython-3.1.59 → gitpython-3.1.60}/git/config.py +23 -6
- {gitpython-3.1.59 → gitpython-3.1.60}/git/diff.py +31 -12
- {gitpython-3.1.59 → gitpython-3.1.60}/git/repo/base.py +64 -49
- {gitpython-3.1.59 → gitpython-3.1.60}/git/repo/fun.py +71 -39
- {gitpython-3.1.59 → gitpython-3.1.60}/git/util.py +8 -16
- gitpython-3.1.59/VERSION +0 -1
- {gitpython-3.1.59 → gitpython-3.1.60}/AUTHORS +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/CHANGES +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/CONTRIBUTING.md +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/GitPython.egg-info/SOURCES.txt +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/GitPython.egg-info/dependency_links.txt +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/GitPython.egg-info/not-zip-safe +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/GitPython.egg-info/requires.txt +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/GitPython.egg-info/top_level.txt +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/LICENSE +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/MANIFEST.in +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/README.md +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/doc/.gitignore +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/doc/Makefile +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/doc/requirements.txt +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/doc/source/conf.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/doc/source/index.rst +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/doc/source/intro.rst +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/doc/source/quickstart.rst +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/doc/source/reference.rst +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/doc/source/roadmap.rst +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/doc/source/tutorial.rst +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/cmd.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/compat.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/db.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/exc.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/index/__init__.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/index/base.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/index/fun.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/index/typ.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/index/util.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/objects/__init__.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/objects/base.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/objects/blob.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/objects/commit.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/objects/fun.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/objects/submodule/__init__.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/objects/submodule/base.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/objects/submodule/root.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/objects/submodule/util.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/objects/tag.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/objects/tree.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/objects/util.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/py.typed +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/refs/__init__.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/refs/head.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/refs/log.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/refs/reference.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/refs/remote.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/refs/symbolic.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/refs/tag.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/remote.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/repo/__init__.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/git/types.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/pyproject.toml +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/requirements.txt +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/setup.cfg +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/setup.py +0 -0
- {gitpython-3.1.59 → gitpython-3.1.60}/test-requirements.txt +0 -0
gitpython-3.1.60/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.1.60
|
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
Changelog
|
|
3
3
|
=========
|
|
4
4
|
|
|
5
|
+
3.1.60
|
|
6
|
+
======
|
|
7
|
+
|
|
8
|
+
Security fixes for
|
|
9
|
+
|
|
10
|
+
* https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-g5vv-9gxw-82hx
|
|
11
|
+
* https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-whh4-5q6c-9v3x
|
|
12
|
+
* https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-239g-whfq-7xj9
|
|
13
|
+
|
|
14
|
+
If you can, also try and provide feedback on the upcoming v4 branch
|
|
15
|
+
https://github.com/gitpython-developers/GitPython/pull/2177 - patches welcome.
|
|
16
|
+
|
|
17
|
+
See the following for all changes.
|
|
18
|
+
https://github.com/gitpython-developers/GitPython/releases/tag/3.1.60
|
|
19
|
+
|
|
5
20
|
3.1.59
|
|
6
21
|
======
|
|
7
22
|
|
|
@@ -462,7 +462,8 @@ class GitConfigParser(cp.RawConfigParser, metaclass=MetaParserBuilder):
|
|
|
462
462
|
v = v[:-1]
|
|
463
463
|
# END cut trailing escapes to prevent decode error
|
|
464
464
|
|
|
465
|
-
|
|
465
|
+
escapes = {"b": "\b", "n": "\n", "r": "\r", "t": "\t", '"': '"', "\\": "\\"}
|
|
466
|
+
return re.sub(r"\\(.)", lambda match: escapes.get(match.group(1), match.group(0)), v)
|
|
466
467
|
|
|
467
468
|
# END string_decode
|
|
468
469
|
|
|
@@ -517,10 +518,12 @@ class GitConfigParser(cp.RawConfigParser, metaclass=MetaParserBuilder):
|
|
|
517
518
|
# Opens quoting and does not close: appears to start multi-line quoting.
|
|
518
519
|
is_multi_line = True
|
|
519
520
|
optval = string_decode(optval[1:])
|
|
520
|
-
elif
|
|
521
|
-
#
|
|
522
|
-
|
|
523
|
-
|
|
521
|
+
elif re.search(r'(?:^|[^\\])(?:\\\\)*"', optval[1:-1]):
|
|
522
|
+
# Preserve malformed values containing unescaped quotes.
|
|
523
|
+
pass
|
|
524
|
+
else:
|
|
525
|
+
# Opens and closes quoting.
|
|
526
|
+
optval = string_decode(optval[1:-1])
|
|
524
527
|
|
|
525
528
|
# Preserves multiple values for duplicate optnames.
|
|
526
529
|
cursect.add(optname, optval)
|
|
@@ -706,7 +709,7 @@ class GitConfigParser(cp.RawConfigParser, metaclass=MetaParserBuilder):
|
|
|
706
709
|
|
|
707
710
|
for v in values:
|
|
708
711
|
value = self._value_to_string(v)
|
|
709
|
-
if any(char in value for char in '\n\t\b\\"'):
|
|
712
|
+
if any(char in value for char in '\n\t\b\\"#;') or value[:1].isspace() or value[-1:].isspace():
|
|
710
713
|
value = value.replace("\\", "\\\\").replace('"', '\\"')
|
|
711
714
|
value = '"%s\\\n"' % value.replace("\n", "\\n").replace("\t", "\\t").replace("\b", "\\b")
|
|
712
715
|
fp.write(("\t%s = %s\n" % (key, value)).encode(defenc))
|
|
@@ -768,6 +771,20 @@ class GitConfigParser(cp.RawConfigParser, metaclass=MetaParserBuilder):
|
|
|
768
771
|
return
|
|
769
772
|
# END stop if we have include files
|
|
770
773
|
|
|
774
|
+
sections: List[_OMD] = [self._defaults]
|
|
775
|
+
section: _OMD
|
|
776
|
+
stored_section: _OMD
|
|
777
|
+
values: List[Any]
|
|
778
|
+
raw_value: Any
|
|
779
|
+
for _, stored_section in self._sections.items():
|
|
780
|
+
sections.append(stored_section)
|
|
781
|
+
for section in sections:
|
|
782
|
+
for key, values in section.items_all():
|
|
783
|
+
if key != "__name__":
|
|
784
|
+
for raw_value in values:
|
|
785
|
+
if "\r" in self._value_to_string(raw_value) or "\x00" in self._value_to_string(raw_value):
|
|
786
|
+
raise ValueError("Git config values must not contain CR or NUL")
|
|
787
|
+
|
|
771
788
|
fp = self._file_or_files
|
|
772
789
|
|
|
773
790
|
# We have a physical file on disk, so get a lock.
|
|
@@ -95,14 +95,35 @@ This is an alias of :const:`DiffConstants.INDEX`, which may also be accessed as
|
|
|
95
95
|
:const:`git.INDEX` and :const:`Diffable.INDEX`, as well as :const:`Diffable.Index`.
|
|
96
96
|
"""
|
|
97
97
|
|
|
98
|
-
_octal_byte_re = re.compile(rb"\\([0-9]{3})")
|
|
99
98
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
99
|
+
def _unquote_path(path: bytes) -> bytes:
|
|
100
|
+
result = bytearray()
|
|
101
|
+
escapes = {
|
|
102
|
+
ord("a"): 7,
|
|
103
|
+
ord("b"): 8,
|
|
104
|
+
ord("f"): 12,
|
|
105
|
+
ord("n"): 10,
|
|
106
|
+
ord("r"): 13,
|
|
107
|
+
ord("t"): 9,
|
|
108
|
+
ord("v"): 11,
|
|
109
|
+
}
|
|
110
|
+
i = 0
|
|
111
|
+
while i < len(path):
|
|
112
|
+
if path[i] != ord("\\") or i + 1 == len(path):
|
|
113
|
+
result.append(path[i])
|
|
114
|
+
i += 1
|
|
115
|
+
continue
|
|
116
|
+
if path[i + 1] in b"0123" and i + 3 < len(path) and all(c in b"01234567" for c in path[i + 2 : i + 4]):
|
|
117
|
+
result.append(int(path[i + 1 : i + 4], 8))
|
|
118
|
+
i += 4
|
|
119
|
+
continue
|
|
120
|
+
escaped = path[i + 1]
|
|
121
|
+
if escaped in escapes or escaped in b'\\"':
|
|
122
|
+
result.append(escapes.get(escaped, escaped))
|
|
123
|
+
else:
|
|
124
|
+
result.extend(path[i : i + 2])
|
|
125
|
+
i += 2
|
|
126
|
+
return bytes(result)
|
|
106
127
|
|
|
107
128
|
|
|
108
129
|
def decode_path(path: bytes, has_ab_prefix: bool = True) -> Optional[bytes]:
|
|
@@ -110,9 +131,7 @@ def decode_path(path: bytes, has_ab_prefix: bool = True) -> Optional[bytes]:
|
|
|
110
131
|
return None
|
|
111
132
|
|
|
112
133
|
if path.startswith(b'"') and path.endswith(b'"'):
|
|
113
|
-
path = path[1:-1]
|
|
114
|
-
|
|
115
|
-
path = _octal_byte_re.sub(_octal_repl, path)
|
|
134
|
+
path = _unquote_path(path[1:-1])
|
|
116
135
|
|
|
117
136
|
if has_ab_prefix:
|
|
118
137
|
assert path.startswith(b"a/") or path.startswith(b"b/")
|
|
@@ -220,8 +239,8 @@ class Diffable:
|
|
|
220
239
|
to be read and diffed.
|
|
221
240
|
|
|
222
241
|
:param allow_unsafe_options:
|
|
223
|
-
If ``True``, allow options such as ``--output
|
|
224
|
-
or read from arbitrary filesystem paths.
|
|
242
|
+
If ``True``, allow options such as ``--output``, ``--no-index``, and ``-O``
|
|
243
|
+
that can write to or read from arbitrary filesystem paths.
|
|
225
244
|
|
|
226
245
|
:param kwargs:
|
|
227
246
|
Additional arguments passed to :manpage:`git-diff(1)`, such as ``R=True`` to
|
|
@@ -45,7 +45,6 @@ from git.util import (
|
|
|
45
45
|
|
|
46
46
|
from .fun import (
|
|
47
47
|
find_submodule_git_dir,
|
|
48
|
-
find_worktree_git_dir,
|
|
49
48
|
is_git_dir,
|
|
50
49
|
rev_parse,
|
|
51
50
|
touch,
|
|
@@ -209,6 +208,8 @@ class Repo:
|
|
|
209
208
|
]
|
|
210
209
|
|
|
211
210
|
unsafe_git_diff_options = unsafe_git_revision_options + [
|
|
211
|
+
# Treats path operands as arbitrary filesystem paths.
|
|
212
|
+
"--no-index",
|
|
212
213
|
# Reads caller-controlled order patterns from an arbitrary file.
|
|
213
214
|
"-O",
|
|
214
215
|
"--orderfile",
|
|
@@ -232,6 +233,10 @@ class Repo:
|
|
|
232
233
|
) -> None:
|
|
233
234
|
R"""Create a new :class:`Repo` instance.
|
|
234
235
|
|
|
236
|
+
.. note::
|
|
237
|
+
Repositories using reftable may be opened, but GitPython's direct reference
|
|
238
|
+
access does not support reftable.
|
|
239
|
+
|
|
235
240
|
:param path:
|
|
236
241
|
The path to either the worktree directory or the .git directory itself::
|
|
237
242
|
|
|
@@ -266,7 +271,11 @@ class Repo:
|
|
|
266
271
|
:class:`Repo`
|
|
267
272
|
"""
|
|
268
273
|
|
|
269
|
-
|
|
274
|
+
git_dir_env = os.getenv("GIT_DIR")
|
|
275
|
+
object_dir_env = os.getenv("GIT_OBJECT_DIRECTORY")
|
|
276
|
+
if object_dir_env is not None:
|
|
277
|
+
object_dir_env = osp.abspath(object_dir_env)
|
|
278
|
+
epath = path or git_dir_env
|
|
270
279
|
if not epath:
|
|
271
280
|
epath = os.getcwd()
|
|
272
281
|
epath = os.fspath(epath)
|
|
@@ -288,37 +297,48 @@ class Repo:
|
|
|
288
297
|
raise NoSuchPathError(epath)
|
|
289
298
|
|
|
290
299
|
# Walk up the path to find the `.git` dir.
|
|
291
|
-
curpath = epath
|
|
292
|
-
git_dir = None
|
|
300
|
+
curpath = os.fspath(epath) if epath is not None else ""
|
|
301
|
+
git_dir: Optional[str] = None
|
|
302
|
+
explicit_git_dir = not path and bool(git_dir_env)
|
|
293
303
|
while curpath:
|
|
294
304
|
# ABOUT osp.NORMPATH
|
|
295
305
|
# It's important to normalize the paths, as submodules will otherwise
|
|
296
306
|
# initialize their repo instances with paths that depend on path-portions
|
|
297
307
|
# that will not exist after being removed. It's just cleaner.
|
|
298
|
-
if
|
|
299
|
-
osp.
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
308
|
+
if not explicit_git_dir:
|
|
309
|
+
dotgit = osp.join(curpath, ".git")
|
|
310
|
+
try:
|
|
311
|
+
sm_gitpath = find_submodule_git_dir(dotgit)
|
|
312
|
+
except OSError:
|
|
313
|
+
break
|
|
314
|
+
if sm_gitpath is not None:
|
|
315
|
+
# Worktrees can use relative paths as of Git 2.48, so join to curpath.
|
|
316
|
+
git_dir = osp.normpath(osp.join(curpath, os.fspath(sm_gitpath)))
|
|
317
|
+
self._working_tree_dir = curpath
|
|
318
|
+
break
|
|
319
|
+
|
|
320
|
+
# Like Git, do not fall back to a bare repository or parent directory when
|
|
321
|
+
# a non-directory .git entry exists but is not a valid gitfile.
|
|
322
|
+
if osp.exists(dotgit) and not osp.isdir(dotgit):
|
|
323
|
+
break
|
|
312
324
|
|
|
313
|
-
|
|
314
|
-
|
|
325
|
+
if is_git_dir(curpath):
|
|
326
|
+
git_dir = curpath
|
|
327
|
+
if osp.isfile(osp.join(curpath, "gitdir")) and osp.isfile(osp.join(curpath, "commondir")):
|
|
328
|
+
if "GIT_WORK_TREE" in os.environ:
|
|
329
|
+
self._working_tree_dir = os.getenv("GIT_WORK_TREE")
|
|
330
|
+
else:
|
|
331
|
+
# Linked worktree administrative directories store the path to
|
|
332
|
+
# the worktree's .git file in gitdir (without a "gitdir: " prefix).
|
|
333
|
+
with open(osp.join(git_dir, "gitdir")) as fp:
|
|
334
|
+
worktree_gitfile = fp.read().strip()
|
|
315
335
|
|
|
316
|
-
|
|
336
|
+
if not osp.isabs(worktree_gitfile):
|
|
337
|
+
worktree_gitfile = osp.normpath(osp.join(git_dir, worktree_gitfile))
|
|
317
338
|
|
|
318
|
-
|
|
339
|
+
self._working_tree_dir = osp.dirname(worktree_gitfile)
|
|
340
|
+
break
|
|
319
341
|
|
|
320
|
-
if is_git_dir(curpath):
|
|
321
|
-
git_dir = curpath
|
|
322
342
|
# from man git-config : core.worktree
|
|
323
343
|
# Set the path to the root of the working tree. If GIT_COMMON_DIR
|
|
324
344
|
# environment variable is set, core.worktree is ignored and not used for
|
|
@@ -338,22 +358,7 @@ class Repo:
|
|
|
338
358
|
self._working_tree_dir = os.getenv("GIT_WORK_TREE")
|
|
339
359
|
break
|
|
340
360
|
|
|
341
|
-
|
|
342
|
-
sm_gitpath = find_submodule_git_dir(dotgit)
|
|
343
|
-
if sm_gitpath is not None:
|
|
344
|
-
git_dir = osp.normpath(sm_gitpath)
|
|
345
|
-
|
|
346
|
-
sm_gitpath = find_submodule_git_dir(dotgit)
|
|
347
|
-
if sm_gitpath is None:
|
|
348
|
-
sm_gitpath = find_worktree_git_dir(dotgit)
|
|
349
|
-
|
|
350
|
-
if sm_gitpath is not None:
|
|
351
|
-
# worktrees can use relative paths as of Git 2.48, so we join to curpath
|
|
352
|
-
git_dir = osp.normpath(osp.join(curpath, sm_gitpath))
|
|
353
|
-
self._working_tree_dir = curpath
|
|
354
|
-
break
|
|
355
|
-
|
|
356
|
-
if not search_parent_directories:
|
|
361
|
+
if explicit_git_dir or not search_parent_directories:
|
|
357
362
|
break
|
|
358
363
|
curpath, tail = osp.split(curpath)
|
|
359
364
|
if not tail:
|
|
@@ -364,6 +369,16 @@ class Repo:
|
|
|
364
369
|
raise InvalidGitRepositoryError(epath)
|
|
365
370
|
self.git_dir = git_dir
|
|
366
371
|
|
|
372
|
+
common_dir_env = os.getenv("GIT_COMMON_DIR")
|
|
373
|
+
if common_dir_env is not None:
|
|
374
|
+
self._common_dir = osp.abspath(common_dir_env)
|
|
375
|
+
else:
|
|
376
|
+
try:
|
|
377
|
+
common_dir = os.fsdecode((Path(self.git_dir) / "commondir").read_bytes()).rstrip("\r\n")
|
|
378
|
+
self._common_dir = osp.join(self.git_dir, common_dir)
|
|
379
|
+
except OSError:
|
|
380
|
+
self._common_dir = ""
|
|
381
|
+
|
|
367
382
|
self._bare = False
|
|
368
383
|
try:
|
|
369
384
|
self._bare = self.config_reader("repository").getboolean("core", "bare")
|
|
@@ -371,12 +386,6 @@ class Repo:
|
|
|
371
386
|
# Let's not assume the option exists, although it should.
|
|
372
387
|
pass
|
|
373
388
|
|
|
374
|
-
try:
|
|
375
|
-
common_dir = (Path(self.git_dir) / "commondir").read_text().splitlines()[0].strip()
|
|
376
|
-
self._common_dir = osp.join(self.git_dir, common_dir)
|
|
377
|
-
except OSError:
|
|
378
|
-
self._common_dir = ""
|
|
379
|
-
|
|
380
389
|
# Adjust the working directory in case we are actually bare - we didn't know
|
|
381
390
|
# that in the first place.
|
|
382
391
|
if self._bare:
|
|
@@ -385,9 +394,15 @@ class Repo:
|
|
|
385
394
|
|
|
386
395
|
self.working_dir: PathLike = self._working_tree_dir or self.common_dir
|
|
387
396
|
self.git = self.GitCommandWrapperType(self.working_dir)
|
|
397
|
+
if common_dir_env is not None:
|
|
398
|
+
self.git.update_environment(GIT_DIR=os.fspath(self.git_dir), GIT_COMMON_DIR=os.fspath(self.common_dir))
|
|
399
|
+
elif git_dir_env is not None:
|
|
400
|
+
self.git.update_environment(GIT_DIR=os.fspath(self.git_dir))
|
|
401
|
+
if object_dir_env is not None:
|
|
402
|
+
self.git.update_environment(GIT_OBJECT_DIRECTORY=object_dir_env)
|
|
388
403
|
|
|
389
404
|
# Special handling, in special times.
|
|
390
|
-
rootpath = osp.join(self.common_dir, "objects")
|
|
405
|
+
rootpath = object_dir_env if object_dir_env is not None else osp.join(self.common_dir, "objects")
|
|
391
406
|
if issubclass(odbt, GitCmdObjectDB):
|
|
392
407
|
self.odb = odbt(rootpath, self.git)
|
|
393
408
|
else:
|
|
@@ -988,7 +1003,7 @@ class Repo:
|
|
|
988
1003
|
:return:
|
|
989
1004
|
List of strings being pathnames of alternates
|
|
990
1005
|
"""
|
|
991
|
-
alternates_path = osp.join(self.
|
|
1006
|
+
alternates_path = osp.join(self.odb.root_path(), "info", "alternates")
|
|
992
1007
|
|
|
993
1008
|
if osp.exists(alternates_path):
|
|
994
1009
|
with open(alternates_path, "rb") as f:
|
|
@@ -1009,7 +1024,7 @@ class Repo:
|
|
|
1009
1024
|
The method does not check for the existence of the paths in `alts`, as the
|
|
1010
1025
|
caller is responsible.
|
|
1011
1026
|
"""
|
|
1012
|
-
alternates_path = osp.join(self.
|
|
1027
|
+
alternates_path = osp.join(self.odb.root_path(), "info", "alternates")
|
|
1013
1028
|
if not alts:
|
|
1014
1029
|
if osp.isfile(alternates_path):
|
|
1015
1030
|
os.remove(alternates_path)
|
|
@@ -60,22 +60,61 @@ def touch(filename: str) -> str:
|
|
|
60
60
|
def is_git_dir(d: PathLike) -> bool:
|
|
61
61
|
"""This is taken from the git setup.c:is_git_directory function.
|
|
62
62
|
|
|
63
|
+
.. note::
|
|
64
|
+
This function recognizes repositories using reftable through their
|
|
65
|
+
compatibility files, but GitPython's direct reference access does not support
|
|
66
|
+
reftable.
|
|
67
|
+
|
|
63
68
|
:raise git.exc.WorkTreeRepositoryUnsupported:
|
|
64
69
|
If it sees a worktree directory. It's quite hacky to do that here, but at least
|
|
65
70
|
clearly indicates that we don't support it. There is the unlikely danger to
|
|
66
71
|
throw if we see directories which just look like a worktree dir, but are none.
|
|
67
72
|
"""
|
|
68
73
|
if osp.isdir(d):
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
headref = osp.join(d, "HEAD")
|
|
75
|
+
if osp.islink(headref):
|
|
76
|
+
try:
|
|
77
|
+
valid_head = os.readlink(headref).startswith("refs/")
|
|
78
|
+
except OSError:
|
|
79
|
+
valid_head = False
|
|
80
|
+
else:
|
|
81
|
+
try:
|
|
82
|
+
with open(headref, "rb") as fp:
|
|
83
|
+
head = fp.read(256)
|
|
84
|
+
except OSError:
|
|
85
|
+
valid_head = False
|
|
86
|
+
else:
|
|
87
|
+
valid_head = (head.startswith(b"ref:") and head[4:].lstrip().startswith(b"refs/")) or bool(
|
|
88
|
+
re.match(rb"(?:[0-9A-Fa-f]{64}|[0-9A-Fa-f]{40})", head)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
common_dir = os.getenv("GIT_COMMON_DIR")
|
|
92
|
+
if common_dir == "":
|
|
93
|
+
return False
|
|
94
|
+
if common_dir is None:
|
|
95
|
+
common_dir_file = Path(d) / "commondir"
|
|
96
|
+
try:
|
|
97
|
+
common_dir = os.fsdecode(common_dir_file.read_bytes()).rstrip("\r\n")
|
|
98
|
+
except FileNotFoundError:
|
|
99
|
+
if osp.lexists(common_dir_file):
|
|
100
|
+
return False
|
|
101
|
+
common_dir = os.fspath(d)
|
|
102
|
+
except (OSError, UnicodeError):
|
|
103
|
+
return False
|
|
104
|
+
else:
|
|
105
|
+
if not common_dir:
|
|
106
|
+
return False
|
|
107
|
+
try:
|
|
108
|
+
common_dir = osp.realpath(osp.join(d, common_dir))
|
|
109
|
+
except (OSError, ValueError):
|
|
110
|
+
return False
|
|
111
|
+
|
|
112
|
+
object_dir = os.getenv("GIT_OBJECT_DIRECTORY")
|
|
113
|
+
if object_dir is None:
|
|
114
|
+
object_dir = osp.join(common_dir, "objects")
|
|
115
|
+
if valid_head and osp.isdir(object_dir) and osp.isdir(osp.join(common_dir, "refs")):
|
|
116
|
+
return True
|
|
117
|
+
if osp.isfile(osp.join(d, "gitdir")) and osp.isfile(osp.join(d, "commondir")) and osp.isfile(headref):
|
|
79
118
|
raise WorkTreeRepositoryUnsupported(d)
|
|
80
119
|
return False
|
|
81
120
|
|
|
@@ -84,19 +123,20 @@ def find_worktree_git_dir(dotgit: PathLike) -> Optional[str]:
|
|
|
84
123
|
"""Search for a gitdir for this worktree."""
|
|
85
124
|
try:
|
|
86
125
|
statbuf = os.stat(dotgit)
|
|
87
|
-
except
|
|
126
|
+
except (FileNotFoundError, NotADirectoryError):
|
|
88
127
|
return None
|
|
89
|
-
if not stat.S_ISREG(statbuf.st_mode):
|
|
128
|
+
if not stat.S_ISREG(statbuf.st_mode) or statbuf.st_size > (1 << 20):
|
|
90
129
|
return None
|
|
91
130
|
|
|
92
131
|
try:
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
132
|
+
with open(dotgit, "rb") as fp:
|
|
133
|
+
content_bytes = fp.read(statbuf.st_size)
|
|
134
|
+
if len(content_bytes) != statbuf.st_size:
|
|
135
|
+
return None
|
|
136
|
+
content = os.fsdecode(content_bytes).rstrip("\r\n")
|
|
137
|
+
except (OSError, UnicodeError):
|
|
138
|
+
return None
|
|
139
|
+
return content[8:] if len(content) >= 9 and content.startswith("gitdir: ") else None
|
|
100
140
|
|
|
101
141
|
|
|
102
142
|
def find_submodule_git_dir(d: PathLike) -> Optional[PathLike]:
|
|
@@ -104,26 +144,18 @@ def find_submodule_git_dir(d: PathLike) -> Optional[PathLike]:
|
|
|
104
144
|
if is_git_dir(d):
|
|
105
145
|
return d
|
|
106
146
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
# Cygwin git understands Cygwin paths much better than Windows ones.
|
|
120
|
-
# Also the Cygwin tests are assuming Cygwin paths.
|
|
121
|
-
path = cygpath(path)
|
|
122
|
-
if not osp.isabs(path):
|
|
123
|
-
path = osp.normpath(osp.join(osp.dirname(d), path))
|
|
124
|
-
return find_submodule_git_dir(path)
|
|
125
|
-
# END handle exception
|
|
126
|
-
return None
|
|
147
|
+
path = find_worktree_git_dir(d)
|
|
148
|
+
if path is None:
|
|
149
|
+
return None
|
|
150
|
+
|
|
151
|
+
if Git.is_cygwin():
|
|
152
|
+
# Cygwin creates submodules prefixed with `/cygdrive/...`.
|
|
153
|
+
# Cygwin git understands Cygwin paths much better than Windows ones.
|
|
154
|
+
# Also the Cygwin tests are assuming Cygwin paths.
|
|
155
|
+
path = cygpath(path)
|
|
156
|
+
if not osp.isabs(path):
|
|
157
|
+
path = osp.normpath(osp.join(osp.dirname(d), path))
|
|
158
|
+
return path if is_git_dir(path) else None
|
|
127
159
|
|
|
128
160
|
|
|
129
161
|
def short_to_long(odb: "GitCmdObjectDB", hexsha: str) -> Optional[bytes]:
|
|
@@ -858,10 +858,6 @@ class Actor:
|
|
|
858
858
|
committers and authors or anything with a name and an email as mentioned in the git
|
|
859
859
|
log entries."""
|
|
860
860
|
|
|
861
|
-
# PRECOMPILED REGEX
|
|
862
|
-
name_only_regex = re.compile(r"<(.*)>")
|
|
863
|
-
name_email_regex = re.compile(r"(.*) <(.*?)>")
|
|
864
|
-
|
|
865
861
|
# ENVIRONMENT VARIABLES
|
|
866
862
|
# These are read when creating new commits.
|
|
867
863
|
env_author_name = "GIT_AUTHOR_NAME"
|
|
@@ -906,18 +902,14 @@ class Actor:
|
|
|
906
902
|
:return:
|
|
907
903
|
:class:`Actor`
|
|
908
904
|
"""
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
# Assume the best and use the whole string as name.
|
|
918
|
-
return Actor(string, None)
|
|
919
|
-
# END special case name
|
|
920
|
-
# END handle name/email matching
|
|
905
|
+
line = string.partition("\n")[0]
|
|
906
|
+
left_bracket = line.find("<")
|
|
907
|
+
right_bracket = line.find(">", left_bracket + 1)
|
|
908
|
+
if left_bracket >= 0 and right_bracket >= 0:
|
|
909
|
+
return Actor(line[:left_bracket].rstrip(), line[left_bracket + 1 : right_bracket])
|
|
910
|
+
|
|
911
|
+
# Assume the best and use the whole string as name.
|
|
912
|
+
return Actor(string, None)
|
|
921
913
|
|
|
922
914
|
@classmethod
|
|
923
915
|
def _main_actor(
|
gitpython-3.1.59/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3.1.59
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|