GitPython 3.1.58__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.58 → gitpython-3.1.60/GitPython.egg-info}/PKG-INFO +1 -1
- {gitpython-3.1.58/GitPython.egg-info → gitpython-3.1.60}/PKG-INFO +1 -1
- gitpython-3.1.60/VERSION +1 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/doc/source/changes.rst +32 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/__init__.py +1 -1
- {gitpython-3.1.58 → gitpython-3.1.60}/git/cmd.py +7 -4
- {gitpython-3.1.58 → gitpython-3.1.60}/git/config.py +27 -6
- {gitpython-3.1.58 → gitpython-3.1.60}/git/db.py +24 -1
- {gitpython-3.1.58 → gitpython-3.1.60}/git/diff.py +33 -13
- {gitpython-3.1.58 → gitpython-3.1.60}/git/index/base.py +2 -1
- {gitpython-3.1.58 → gitpython-3.1.60}/git/objects/submodule/base.py +11 -1
- {gitpython-3.1.58 → gitpython-3.1.60}/git/refs/tag.py +6 -4
- {gitpython-3.1.58 → gitpython-3.1.60}/git/repo/base.py +86 -53
- {gitpython-3.1.58 → gitpython-3.1.60}/git/repo/fun.py +71 -39
- {gitpython-3.1.58 → gitpython-3.1.60}/git/util.py +8 -16
- gitpython-3.1.58/VERSION +0 -1
- {gitpython-3.1.58 → gitpython-3.1.60}/AUTHORS +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/CHANGES +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/CONTRIBUTING.md +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/GitPython.egg-info/SOURCES.txt +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/GitPython.egg-info/dependency_links.txt +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/GitPython.egg-info/not-zip-safe +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/GitPython.egg-info/requires.txt +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/GitPython.egg-info/top_level.txt +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/LICENSE +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/MANIFEST.in +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/README.md +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/doc/.gitignore +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/doc/Makefile +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/doc/requirements.txt +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/doc/source/conf.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/doc/source/index.rst +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/doc/source/intro.rst +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/doc/source/quickstart.rst +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/doc/source/reference.rst +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/doc/source/roadmap.rst +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/doc/source/tutorial.rst +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/compat.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/exc.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/index/__init__.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/index/fun.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/index/typ.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/index/util.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/objects/__init__.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/objects/base.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/objects/blob.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/objects/commit.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/objects/fun.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/objects/submodule/__init__.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/objects/submodule/root.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/objects/submodule/util.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/objects/tag.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/objects/tree.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/objects/util.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/py.typed +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/refs/__init__.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/refs/head.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/refs/log.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/refs/reference.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/refs/remote.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/refs/symbolic.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/remote.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/repo/__init__.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/git/types.py +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/pyproject.toml +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/requirements.txt +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/setup.cfg +0 -0
- {gitpython-3.1.58 → gitpython-3.1.60}/setup.py +0 -0
- {gitpython-3.1.58 → 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,38 @@
|
|
|
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
|
+
|
|
20
|
+
3.1.59
|
|
21
|
+
======
|
|
22
|
+
|
|
23
|
+
Security fixes for
|
|
24
|
+
|
|
25
|
+
* https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-5xxx-qhh7-9287
|
|
26
|
+
* https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-3wxw-xv34-2frg
|
|
27
|
+
* https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-8mcc-hrx5-hvxc
|
|
28
|
+
* https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-284h-m62q-gf8w
|
|
29
|
+
* https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-7833-fr7j-v32q
|
|
30
|
+
|
|
31
|
+
If you can, also try and provide feedback on the upcoming v4 branch
|
|
32
|
+
https://github.com/gitpython-developers/GitPython/pull/2177 - patches welcome.
|
|
33
|
+
|
|
34
|
+
See the following for all changes.
|
|
35
|
+
https://github.com/gitpython-developers/GitPython/releases/tag/3.1.59
|
|
36
|
+
|
|
5
37
|
3.1.58
|
|
6
38
|
======
|
|
7
39
|
|
|
@@ -652,6 +652,7 @@ class Git(metaclass=_GitMeta):
|
|
|
652
652
|
unsafe_git_ls_remote_options = [
|
|
653
653
|
# This option allows arbitrary command execution in git-ls-remote.
|
|
654
654
|
"--upload-pack",
|
|
655
|
+
"--exec",
|
|
655
656
|
]
|
|
656
657
|
|
|
657
658
|
unsafe_git_pathspec_from_file_options = [
|
|
@@ -976,7 +977,9 @@ class Git(metaclass=_GitMeta):
|
|
|
976
977
|
return dashify(option_tokens[0])
|
|
977
978
|
|
|
978
979
|
@classmethod
|
|
979
|
-
def check_unsafe_options(
|
|
980
|
+
def check_unsafe_options(
|
|
981
|
+
cls, options: List[str], unsafe_options: List[str], clusterable_short_options: str = "46flnqsv"
|
|
982
|
+
) -> None:
|
|
980
983
|
"""Raise :class:`~git.exc.UnsafeOptionError` for blocked option spellings.
|
|
981
984
|
|
|
982
985
|
In addition to exact matches, this rejects abbreviated long options accepted
|
|
@@ -1011,7 +1014,7 @@ class Git(metaclass=_GitMeta):
|
|
|
1011
1014
|
# These value-less Git flags can be clustered before another short option
|
|
1012
1015
|
# (for example, ``-fuVALUE``). Stop at any other character because it may
|
|
1013
1016
|
# begin an attached value, as ``o`` does in the safe option ``-oupstream``.
|
|
1014
|
-
|
|
1017
|
+
clusterable_short_options_set = frozenset(clusterable_short_options)
|
|
1015
1018
|
options_are_kwargs = all(not option.startswith("-") for option in options)
|
|
1016
1019
|
for option in options:
|
|
1017
1020
|
candidate = cls._canonicalize_option_name(option)
|
|
@@ -1028,7 +1031,7 @@ class Git(metaclass=_GitMeta):
|
|
|
1028
1031
|
raise UnsafeOptionError(
|
|
1029
1032
|
f"{unsafe_option} is not allowed, use `allow_unsafe_options=True` to allow it."
|
|
1030
1033
|
)
|
|
1031
|
-
if option_char not in
|
|
1034
|
+
if option_char not in clusterable_short_options_set:
|
|
1032
1035
|
break
|
|
1033
1036
|
if not (option.startswith("--") or (options_are_kwargs and len(candidate) > 1)):
|
|
1034
1037
|
continue
|
|
@@ -1133,7 +1136,7 @@ class Git(metaclass=_GitMeta):
|
|
|
1133
1136
|
"""List references in a remote repository.
|
|
1134
1137
|
|
|
1135
1138
|
:param allow_unsafe_options:
|
|
1136
|
-
Allow unsafe options, like ``--upload-pack``.
|
|
1139
|
+
Allow unsafe options, like ``--upload-pack`` or ``--exec``.
|
|
1137
1140
|
"""
|
|
1138
1141
|
if not allow_unsafe_options:
|
|
1139
1142
|
candidate_options = self._option_candidates(args, kwargs)
|
|
@@ -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)
|
|
@@ -705,7 +708,11 @@ class GitConfigParser(cp.RawConfigParser, metaclass=MetaParserBuilder):
|
|
|
705
708
|
continue
|
|
706
709
|
|
|
707
710
|
for v in values:
|
|
708
|
-
|
|
711
|
+
value = self._value_to_string(v)
|
|
712
|
+
if any(char in value for char in '\n\t\b\\"#;') or value[:1].isspace() or value[-1:].isspace():
|
|
713
|
+
value = value.replace("\\", "\\\\").replace('"', '\\"')
|
|
714
|
+
value = '"%s\\\n"' % value.replace("\n", "\\n").replace("\t", "\\t").replace("\b", "\\b")
|
|
715
|
+
fp.write(("\t%s = %s\n" % (key, value)).encode(defenc))
|
|
709
716
|
# END if key is not __name__
|
|
710
717
|
|
|
711
718
|
# END section writing
|
|
@@ -764,6 +771,20 @@ class GitConfigParser(cp.RawConfigParser, metaclass=MetaParserBuilder):
|
|
|
764
771
|
return
|
|
765
772
|
# END stop if we have include files
|
|
766
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
|
+
|
|
767
788
|
fp = self._file_or_files
|
|
768
789
|
|
|
769
790
|
# We have a physical file on disk, so get a lock.
|
|
@@ -5,10 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
__all__ = ["GitCmdObjectDB", "GitDB"]
|
|
7
7
|
|
|
8
|
-
from
|
|
8
|
+
from subprocess import PIPE
|
|
9
|
+
|
|
10
|
+
from gitdb.base import IStream, OInfo, OStream
|
|
9
11
|
from gitdb.db import GitDB, LooseObjectDB
|
|
10
12
|
from gitdb.exc import BadObject
|
|
13
|
+
from gitdb.fun import stream_copy
|
|
11
14
|
|
|
15
|
+
from git.compat import force_text
|
|
12
16
|
from git.util import bin_to_hex, hex_to_bin
|
|
13
17
|
from git.exc import GitCommandError
|
|
14
18
|
|
|
@@ -46,6 +50,25 @@ class GitCmdObjectDB(LooseObjectDB):
|
|
|
46
50
|
hexsha, typename, size, stream = self._git.stream_object_data(bin_to_hex(binsha))
|
|
47
51
|
return OStream(hex_to_bin(hexsha), typename, size, stream)
|
|
48
52
|
|
|
53
|
+
def store(self, istream: IStream) -> IStream:
|
|
54
|
+
"""Store an object using git itself."""
|
|
55
|
+
if istream.binsha is not None or self.ostream() is not None:
|
|
56
|
+
return super().store(istream)
|
|
57
|
+
|
|
58
|
+
proc = self._git.hash_object(
|
|
59
|
+
"-t", force_text(istream.type), "-w", "--stdin", "--literally", as_process=True, istream=PIPE
|
|
60
|
+
)
|
|
61
|
+
assert proc.stdin is not None
|
|
62
|
+
try:
|
|
63
|
+
stream_copy(istream.read, proc.stdin.write, istream.size, self.stream_chunk_size)
|
|
64
|
+
finally:
|
|
65
|
+
proc.stdin.close()
|
|
66
|
+
assert proc.stdout is not None
|
|
67
|
+
hexsha = proc.stdout.read().strip()
|
|
68
|
+
proc.wait()
|
|
69
|
+
istream.binsha = hex_to_bin(hexsha)
|
|
70
|
+
return istream
|
|
71
|
+
|
|
49
72
|
# { Interface
|
|
50
73
|
|
|
51
74
|
def partial_to_complete_sha_hex(self, partial_hexsha: str) -> bytes:
|
|
@@ -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
|
-
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
|
|
@@ -238,7 +257,8 @@ class Diffable:
|
|
|
238
257
|
if not allow_unsafe_options:
|
|
239
258
|
Git.check_unsafe_options(
|
|
240
259
|
options=Git._option_candidates([other], kwargs),
|
|
241
|
-
unsafe_options=self.repo.
|
|
260
|
+
unsafe_options=self.repo.unsafe_git_diff_options,
|
|
261
|
+
clusterable_short_options="46abceflmnpqrstuvwzBCDMNRW",
|
|
242
262
|
)
|
|
243
263
|
|
|
244
264
|
args: List[Union[PathLike, Diffable]] = []
|
|
@@ -1567,7 +1567,8 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
|
|
|
1567
1567
|
if not allow_unsafe_options:
|
|
1568
1568
|
Git.check_unsafe_options(
|
|
1569
1569
|
options=Git._option_candidates([other], kwargs),
|
|
1570
|
-
unsafe_options=self.repo.
|
|
1570
|
+
unsafe_options=self.repo.unsafe_git_diff_options,
|
|
1571
|
+
clusterable_short_options="46abceflmnpqrstuvwzBCDMNRW",
|
|
1571
1572
|
)
|
|
1572
1573
|
|
|
1573
1574
|
# Only run if we are the default repository index.
|
|
@@ -9,6 +9,7 @@ import logging
|
|
|
9
9
|
import ntpath
|
|
10
10
|
import os
|
|
11
11
|
import os.path as osp
|
|
12
|
+
import shlex
|
|
12
13
|
import stat
|
|
13
14
|
import sys
|
|
14
15
|
import uuid
|
|
@@ -270,7 +271,7 @@ class Submodule(IndexObject, TraversableIterableObj):
|
|
|
270
271
|
raise ValueError("Cannot write blobs of 'historical' submodule configurations")
|
|
271
272
|
# END handle writes of historical submodules
|
|
272
273
|
|
|
273
|
-
return SubmoduleConfigParser(fp_module, read_only=read_only)
|
|
274
|
+
return SubmoduleConfigParser(fp_module, read_only=read_only, merge_includes=False)
|
|
274
275
|
|
|
275
276
|
def _clear_cache(self) -> None:
|
|
276
277
|
"""Clear the possibly changed values."""
|
|
@@ -363,6 +364,15 @@ class Submodule(IndexObject, TraversableIterableObj):
|
|
|
363
364
|
module_abspath = cls._module_abspath(repo, path, name)
|
|
364
365
|
module_checkout_path = module_abspath
|
|
365
366
|
if cls._need_gitfile_submodules(repo.git):
|
|
367
|
+
if not allow_unsafe_options:
|
|
368
|
+
Git.check_unsafe_options(Git._option_candidates([], kwargs), repo.unsafe_git_clone_options)
|
|
369
|
+
multi_options = kwargs.get("multi_options")
|
|
370
|
+
if multi_options:
|
|
371
|
+
Git.check_unsafe_options(
|
|
372
|
+
shlex.split(" ".join(cast("Sequence[str]", multi_options))),
|
|
373
|
+
repo.unsafe_git_clone_options,
|
|
374
|
+
)
|
|
375
|
+
allow_unsafe_options = True
|
|
366
376
|
kwargs["separate_git_dir"] = module_abspath
|
|
367
377
|
module_abspath_dir = osp.dirname(module_abspath)
|
|
368
378
|
if not osp.isdir(module_abspath_dir):
|
|
@@ -134,15 +134,17 @@ class TagReference(Reference):
|
|
|
134
134
|
:return:
|
|
135
135
|
A new :class:`TagReference`.
|
|
136
136
|
"""
|
|
137
|
+
legacy_ref = kwargs.pop("ref", None)
|
|
138
|
+
if legacy_ref:
|
|
139
|
+
reference = legacy_ref
|
|
140
|
+
|
|
137
141
|
if not allow_unsafe_options:
|
|
138
142
|
Git.check_unsafe_options(
|
|
139
|
-
options=Git._option_candidates([], kwargs),
|
|
143
|
+
options=Git._option_candidates([path, reference], kwargs),
|
|
140
144
|
unsafe_options=cls.unsafe_git_tag_options,
|
|
145
|
+
clusterable_short_options="46adefilnqsv",
|
|
141
146
|
)
|
|
142
147
|
|
|
143
|
-
if "ref" in kwargs and kwargs["ref"]:
|
|
144
|
-
reference = kwargs["ref"]
|
|
145
|
-
|
|
146
148
|
if "message" in kwargs and kwargs["message"]:
|
|
147
149
|
kwargs["m"] = kwargs["message"]
|
|
148
150
|
del kwargs["message"]
|
|
@@ -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,
|
|
@@ -159,6 +158,8 @@ class Repo:
|
|
|
159
158
|
"-c",
|
|
160
159
|
# Can install hooks that execute during clone:
|
|
161
160
|
"--template",
|
|
161
|
+
# Redirects the repository metadata to a caller-controlled path:
|
|
162
|
+
"--separate-git-dir",
|
|
162
163
|
# Fetches from an additional caller-controlled URI:
|
|
163
164
|
"--bundle-uri",
|
|
164
165
|
]
|
|
@@ -199,6 +200,21 @@ class Repo:
|
|
|
199
200
|
"-o",
|
|
200
201
|
]
|
|
201
202
|
|
|
203
|
+
unsafe_git_blame_options = unsafe_git_revision_options + [
|
|
204
|
+
# These options read from arbitrary files and expose their contents through blame output.
|
|
205
|
+
"--contents",
|
|
206
|
+
"-S",
|
|
207
|
+
"--ignore-revs-file",
|
|
208
|
+
]
|
|
209
|
+
|
|
210
|
+
unsafe_git_diff_options = unsafe_git_revision_options + [
|
|
211
|
+
# Treats path operands as arbitrary filesystem paths.
|
|
212
|
+
"--no-index",
|
|
213
|
+
# Reads caller-controlled order patterns from an arbitrary file.
|
|
214
|
+
"-O",
|
|
215
|
+
"--orderfile",
|
|
216
|
+
]
|
|
217
|
+
|
|
202
218
|
# Invariants
|
|
203
219
|
config_level: ConfigLevels_Tup = ("system", "user", "global", "repository")
|
|
204
220
|
"""Represents the configuration level of a configuration file."""
|
|
@@ -217,6 +233,10 @@ class Repo:
|
|
|
217
233
|
) -> None:
|
|
218
234
|
R"""Create a new :class:`Repo` instance.
|
|
219
235
|
|
|
236
|
+
.. note::
|
|
237
|
+
Repositories using reftable may be opened, but GitPython's direct reference
|
|
238
|
+
access does not support reftable.
|
|
239
|
+
|
|
220
240
|
:param path:
|
|
221
241
|
The path to either the worktree directory or the .git directory itself::
|
|
222
242
|
|
|
@@ -251,7 +271,11 @@ class Repo:
|
|
|
251
271
|
:class:`Repo`
|
|
252
272
|
"""
|
|
253
273
|
|
|
254
|
-
|
|
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
|
|
255
279
|
if not epath:
|
|
256
280
|
epath = os.getcwd()
|
|
257
281
|
epath = os.fspath(epath)
|
|
@@ -273,37 +297,48 @@ class Repo:
|
|
|
273
297
|
raise NoSuchPathError(epath)
|
|
274
298
|
|
|
275
299
|
# Walk up the path to find the `.git` dir.
|
|
276
|
-
curpath = epath
|
|
277
|
-
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)
|
|
278
303
|
while curpath:
|
|
279
304
|
# ABOUT osp.NORMPATH
|
|
280
305
|
# It's important to normalize the paths, as submodules will otherwise
|
|
281
306
|
# initialize their repo instances with paths that depend on path-portions
|
|
282
307
|
# that will not exist after being removed. It's just cleaner.
|
|
283
|
-
if
|
|
284
|
-
osp.
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
|
289
324
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
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()
|
|
297
335
|
|
|
298
|
-
|
|
299
|
-
|
|
336
|
+
if not osp.isabs(worktree_gitfile):
|
|
337
|
+
worktree_gitfile = osp.normpath(osp.join(git_dir, worktree_gitfile))
|
|
300
338
|
|
|
301
|
-
|
|
339
|
+
self._working_tree_dir = osp.dirname(worktree_gitfile)
|
|
340
|
+
break
|
|
302
341
|
|
|
303
|
-
break
|
|
304
|
-
|
|
305
|
-
if is_git_dir(curpath):
|
|
306
|
-
git_dir = curpath
|
|
307
342
|
# from man git-config : core.worktree
|
|
308
343
|
# Set the path to the root of the working tree. If GIT_COMMON_DIR
|
|
309
344
|
# environment variable is set, core.worktree is ignored and not used for
|
|
@@ -323,22 +358,7 @@ class Repo:
|
|
|
323
358
|
self._working_tree_dir = os.getenv("GIT_WORK_TREE")
|
|
324
359
|
break
|
|
325
360
|
|
|
326
|
-
|
|
327
|
-
sm_gitpath = find_submodule_git_dir(dotgit)
|
|
328
|
-
if sm_gitpath is not None:
|
|
329
|
-
git_dir = osp.normpath(sm_gitpath)
|
|
330
|
-
|
|
331
|
-
sm_gitpath = find_submodule_git_dir(dotgit)
|
|
332
|
-
if sm_gitpath is None:
|
|
333
|
-
sm_gitpath = find_worktree_git_dir(dotgit)
|
|
334
|
-
|
|
335
|
-
if sm_gitpath is not None:
|
|
336
|
-
# worktrees can use relative paths as of Git 2.48, so we join to curpath
|
|
337
|
-
git_dir = osp.normpath(osp.join(curpath, sm_gitpath))
|
|
338
|
-
self._working_tree_dir = curpath
|
|
339
|
-
break
|
|
340
|
-
|
|
341
|
-
if not search_parent_directories:
|
|
361
|
+
if explicit_git_dir or not search_parent_directories:
|
|
342
362
|
break
|
|
343
363
|
curpath, tail = osp.split(curpath)
|
|
344
364
|
if not tail:
|
|
@@ -349,6 +369,16 @@ class Repo:
|
|
|
349
369
|
raise InvalidGitRepositoryError(epath)
|
|
350
370
|
self.git_dir = git_dir
|
|
351
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
|
+
|
|
352
382
|
self._bare = False
|
|
353
383
|
try:
|
|
354
384
|
self._bare = self.config_reader("repository").getboolean("core", "bare")
|
|
@@ -356,12 +386,6 @@ class Repo:
|
|
|
356
386
|
# Let's not assume the option exists, although it should.
|
|
357
387
|
pass
|
|
358
388
|
|
|
359
|
-
try:
|
|
360
|
-
common_dir = (Path(self.git_dir) / "commondir").read_text().splitlines()[0].strip()
|
|
361
|
-
self._common_dir = osp.join(self.git_dir, common_dir)
|
|
362
|
-
except OSError:
|
|
363
|
-
self._common_dir = ""
|
|
364
|
-
|
|
365
389
|
# Adjust the working directory in case we are actually bare - we didn't know
|
|
366
390
|
# that in the first place.
|
|
367
391
|
if self._bare:
|
|
@@ -370,9 +394,15 @@ class Repo:
|
|
|
370
394
|
|
|
371
395
|
self.working_dir: PathLike = self._working_tree_dir or self.common_dir
|
|
372
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)
|
|
373
403
|
|
|
374
404
|
# Special handling, in special times.
|
|
375
|
-
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")
|
|
376
406
|
if issubclass(odbt, GitCmdObjectDB):
|
|
377
407
|
self.odb = odbt(rootpath, self.git)
|
|
378
408
|
else:
|
|
@@ -973,7 +1003,7 @@ class Repo:
|
|
|
973
1003
|
:return:
|
|
974
1004
|
List of strings being pathnames of alternates
|
|
975
1005
|
"""
|
|
976
|
-
alternates_path = osp.join(self.
|
|
1006
|
+
alternates_path = osp.join(self.odb.root_path(), "info", "alternates")
|
|
977
1007
|
|
|
978
1008
|
if osp.exists(alternates_path):
|
|
979
1009
|
with open(alternates_path, "rb") as f:
|
|
@@ -994,7 +1024,7 @@ class Repo:
|
|
|
994
1024
|
The method does not check for the existence of the paths in `alts`, as the
|
|
995
1025
|
caller is responsible.
|
|
996
1026
|
"""
|
|
997
|
-
alternates_path = osp.join(self.
|
|
1027
|
+
alternates_path = osp.join(self.odb.root_path(), "info", "alternates")
|
|
998
1028
|
if not alts:
|
|
999
1029
|
if osp.isfile(alternates_path):
|
|
1000
1030
|
os.remove(alternates_path)
|
|
@@ -1149,7 +1179,7 @@ class Repo:
|
|
|
1149
1179
|
:manpage:`git-rev-parse(1)` is a valid option.
|
|
1150
1180
|
|
|
1151
1181
|
:param allow_unsafe_options:
|
|
1152
|
-
Allow unsafe options in revision argument, like ``--output``.
|
|
1182
|
+
Allow unsafe options in revision argument, like ``--output`` or ``--contents``.
|
|
1153
1183
|
|
|
1154
1184
|
:return:
|
|
1155
1185
|
Lazy iterator of :class:`BlameEntry` tuples, where the commit indicates the
|
|
@@ -1161,7 +1191,9 @@ class Repo:
|
|
|
1161
1191
|
"""
|
|
1162
1192
|
if not allow_unsafe_options:
|
|
1163
1193
|
Git.check_unsafe_options(
|
|
1164
|
-
options=Git._option_candidates([rev], kwargs),
|
|
1194
|
+
options=Git._option_candidates([rev], kwargs),
|
|
1195
|
+
unsafe_options=self.unsafe_git_blame_options,
|
|
1196
|
+
clusterable_short_options="46bceflnpqstvw",
|
|
1165
1197
|
)
|
|
1166
1198
|
|
|
1167
1199
|
data: bytes = self.git.blame(rev, "--", file, p=True, incremental=True, stdout_as_string=False, **kwargs)
|
|
@@ -1253,7 +1285,7 @@ class Repo:
|
|
|
1253
1285
|
:manpage:`git-rev-parse(1)` is a valid option.
|
|
1254
1286
|
|
|
1255
1287
|
:param allow_unsafe_options:
|
|
1256
|
-
Allow unsafe options in revision argument, like ``--output``.
|
|
1288
|
+
Allow unsafe options in revision argument, like ``--output`` or ``--contents``.
|
|
1257
1289
|
|
|
1258
1290
|
:return:
|
|
1259
1291
|
list: [git.Commit, list: [<line>]]
|
|
@@ -1269,7 +1301,8 @@ class Repo:
|
|
|
1269
1301
|
if not allow_unsafe_options:
|
|
1270
1302
|
Git.check_unsafe_options(
|
|
1271
1303
|
options=Git._option_candidates([rev, rev_opts_list], kwargs),
|
|
1272
|
-
unsafe_options=self.
|
|
1304
|
+
unsafe_options=self.unsafe_git_blame_options,
|
|
1305
|
+
clusterable_short_options="46bceflnpqstvw",
|
|
1273
1306
|
)
|
|
1274
1307
|
data: bytes = self.git.blame(rev, *rev_opts_list, "--", file, p=True, stdout_as_string=False, **kwargs)
|
|
1275
1308
|
commits: Dict[str, Commit] = {}
|
|
@@ -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.58/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3.1.58
|
|
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
|