Skip to content

Commit 0c5170a

Browse files
author
wangweichen
committed
merge master branch, resolve conflicts
2 parents 27fcca1 + f237620 commit 0c5170a

File tree

16 files changed

+377
-124
lines changed

16 files changed

+377
-124
lines changed

AUTHORS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,9 @@ Contributors are:
1919
-Timothy B. Hartman <tbhartman _at_ gmail.com>
2020
-Konstantin Popov <konstantin.popov.89 _at_ yandex.ru>
2121
-Peter Jones <pjones _at_ redhat.com>
22+
-Anson Mansfield <anson.mansfield _at_ gmail.com>
23+
-Ken Odegard <ken.odegard _at_ gmail.com>
24+
-Alexis Horgix Chotard
25+
-Piotr Babij <piotr.babij _at_ gmail.com>
2226

2327
Portions derived from other open source works and are clearly marked.

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ release: clean
1414

1515
force_release: clean
1616
git push --tags
17-
python setup.py sdist bdist_wheel
17+
python3 setup.py sdist bdist_wheel
1818
twine upload -s -i byronimo@gmail.com dist/*

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.1.5
1+
2.1.6

git/__init__.py

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,49 @@ def _init_externals():
3535

3636
#{ Imports
3737

38-
from git.config import GitConfigParser # @NoMove @IgnorePep8
39-
from git.objects import * # @NoMove @IgnorePep8
40-
from git.refs import * # @NoMove @IgnorePep8
41-
from git.diff import * # @NoMove @IgnorePep8
42-
from git.exc import * # @NoMove @IgnorePep8
43-
from git.db import * # @NoMove @IgnorePep8
44-
from git.cmd import Git # @NoMove @IgnorePep8
45-
from git.repo import Repo # @NoMove @IgnorePep8
46-
from git.remote import * # @NoMove @IgnorePep8
47-
from git.index import * # @NoMove @IgnorePep8
48-
from git.util import ( # @NoMove @IgnorePep8
49-
LockFile,
50-
BlockingLockFile,
51-
Stats,
52-
Actor,
53-
rmtree,
54-
)
38+
from git.exc import * # @NoMove @IgnorePep8
39+
try:
40+
from git.config import GitConfigParser # @NoMove @IgnorePep8
41+
from git.objects import * # @NoMove @IgnorePep8
42+
from git.refs import * # @NoMove @IgnorePep8
43+
from git.diff import * # @NoMove @IgnorePep8
44+
from git.db import * # @NoMove @IgnorePep8
45+
from git.cmd import Git # @NoMove @IgnorePep8
46+
from git.repo import Repo # @NoMove @IgnorePep8
47+
from git.remote import * # @NoMove @IgnorePep8
48+
from git.index import * # @NoMove @IgnorePep8
49+
from git.util import ( # @NoMove @IgnorePep8
50+
LockFile,
51+
BlockingLockFile,
52+
Stats,
53+
Actor,
54+
rmtree,
55+
)
56+
except GitError as exc:
57+
raise ImportError('%s: %s' % (exc.__class__.__name__, exc))
5558

5659
#} END imports
5760

5861
__all__ = [name for name, obj in locals().items()
5962
if not (name.startswith('_') or inspect.ismodule(obj))]
63+
64+
65+
#{ Initialize git executable path
66+
GIT_OK = None
67+
68+
def refresh(path=None):
69+
"""Convenience method for setting the git executable path."""
70+
global GIT_OK
71+
GIT_OK = False
72+
73+
if not Git.refresh(path=path):
74+
return
75+
if not FetchInfo.refresh():
76+
return
77+
78+
GIT_OK = True
79+
#} END initialize git executable path
80+
81+
#################
82+
refresh()
83+
#################

git/cmd.py

Lines changed: 146 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import subprocess
1818
import sys
1919
import threading
20+
from textwrap import dedent
2021

2122
from git.compat import (
2223
string_types,
@@ -31,7 +32,7 @@
3132
)
3233
from git.exc import CommandError
3334
from git.odict import OrderedDict
34-
from git.util import is_cygwin_git, cygpath
35+
from git.util import is_cygwin_git, cygpath, expand_path
3536

3637
from .exc import (
3738
GitCommandError,
@@ -46,7 +47,7 @@
4647
execute_kwargs = set(('istream', 'with_extended_output',
4748
'with_exceptions', 'as_process', 'stdout_as_string',
4849
'output_stream', 'with_stdout', 'kill_after_timeout',
49-
'universal_newlines', 'shell'))
50+
'universal_newlines', 'shell', 'env'))
5051

5152
log = logging.getLogger(__name__)
5253
log.addHandler(logging.NullHandler())
@@ -182,16 +183,141 @@ def __setstate__(self, d):
182183
# Enables debugging of GitPython's git commands
183184
GIT_PYTHON_TRACE = os.environ.get("GIT_PYTHON_TRACE", False)
184185

185-
# Provide the full path to the git executable. Otherwise it assumes git is in the path
186-
_git_exec_env_var = "GIT_PYTHON_GIT_EXECUTABLE"
187-
GIT_PYTHON_GIT_EXECUTABLE = os.environ.get(_git_exec_env_var, git_exec_name)
188-
189186
# If True, a shell will be used when executing git commands.
190187
# This should only be desirable on Windows, see https://github.com/gitpython-developers/GitPython/pull/126
191188
# and check `git/test_repo.py:TestRepo.test_untracked_files()` TC for an example where it is required.
192189
# Override this value using `Git.USE_SHELL = True`
193190
USE_SHELL = False
194191

192+
# Provide the full path to the git executable. Otherwise it assumes git is in the path
193+
_git_exec_env_var = "GIT_PYTHON_GIT_EXECUTABLE"
194+
_refresh_env_var = "GIT_PYTHON_REFRESH"
195+
GIT_PYTHON_GIT_EXECUTABLE = None
196+
# note that the git executable is actually found during the refresh step in
197+
# the top level __init__
198+
199+
@classmethod
200+
def refresh(cls, path=None):
201+
"""This gets called by the refresh function (see the top level
202+
__init__).
203+
"""
204+
# discern which path to refresh with
205+
if path is not None:
206+
new_git = os.path.expanduser(path)
207+
new_git = os.path.abspath(new_git)
208+
else:
209+
new_git = os.environ.get(cls._git_exec_env_var, cls.git_exec_name)
210+
211+
# keep track of the old and new git executable path
212+
old_git = cls.GIT_PYTHON_GIT_EXECUTABLE
213+
cls.GIT_PYTHON_GIT_EXECUTABLE = new_git
214+
215+
# test if the new git executable path is valid
216+
217+
if sys.version_info < (3,):
218+
# - a GitCommandNotFound error is spawned by ourselves
219+
# - a OSError is spawned if the git executable provided
220+
# cannot be executed for whatever reason
221+
exceptions = (GitCommandNotFound, OSError)
222+
else:
223+
# - a GitCommandNotFound error is spawned by ourselves
224+
# - a PermissionError is spawned if the git executable provided
225+
# cannot be executed for whatever reason
226+
exceptions = (GitCommandNotFound, PermissionError)
227+
228+
has_git = False
229+
try:
230+
cls().version()
231+
has_git = True
232+
except exceptions:
233+
pass
234+
235+
# warn or raise exception if test failed
236+
if not has_git:
237+
err = dedent("""\
238+
Bad git executable.
239+
The git executable must be specified in one of the following ways:
240+
- be included in your $PATH
241+
- be set via $%s
242+
- explicitly set via git.refresh()
243+
""") % cls._git_exec_env_var
244+
245+
# revert to whatever the old_git was
246+
cls.GIT_PYTHON_GIT_EXECUTABLE = old_git
247+
248+
if old_git is None:
249+
# on the first refresh (when GIT_PYTHON_GIT_EXECUTABLE is
250+
# None) we only are quiet, warn, or error depending on the
251+
# GIT_PYTHON_REFRESH value
252+
253+
# determine what the user wants to happen during the initial
254+
# refresh we expect GIT_PYTHON_REFRESH to either be unset or
255+
# be one of the following values:
256+
# 0|q|quiet|s|silence
257+
# 1|w|warn|warning
258+
# 2|r|raise|e|error
259+
260+
mode = os.environ.get(cls._refresh_env_var, "raise").lower()
261+
262+
quiet = ["quiet", "q", "silence", "s", "none", "n", "0"]
263+
warn = ["warn", "w", "warning", "1"]
264+
error = ["error", "e", "raise", "r", "2"]
265+
266+
if mode in quiet:
267+
pass
268+
elif mode in warn or mode in error:
269+
err = dedent("""\
270+
%s
271+
All git commands will error until this is rectified.
272+
273+
This initial warning can be silenced or aggravated in the future by setting the
274+
$%s environment variable. Use one of the following values:
275+
- %s: for no warning or exception
276+
- %s: for a printed warning
277+
- %s: for a raised exception
278+
279+
Example:
280+
export %s=%s
281+
""") % (
282+
err,
283+
cls._refresh_env_var,
284+
"|".join(quiet),
285+
"|".join(warn),
286+
"|".join(error),
287+
cls._refresh_env_var,
288+
quiet[0])
289+
290+
if mode in warn:
291+
print("WARNING: %s" % err)
292+
else:
293+
raise ImportError(err)
294+
else:
295+
err = dedent("""\
296+
%s environment variable has been set but it has been set with an invalid value.
297+
298+
Use only the following values:
299+
- %s: for no warning or exception
300+
- %s: for a printed warning
301+
- %s: for a raised exception
302+
""") % (
303+
cls._refresh_env_var,
304+
"|".join(quiet),
305+
"|".join(warn),
306+
"|".join(error))
307+
raise ImportError(err)
308+
309+
# we get here if this was the init refresh and the refresh mode
310+
# was not error, go ahead and set the GIT_PYTHON_GIT_EXECUTABLE
311+
# such that we discern the difference between a first import
312+
# and a second import
313+
cls.GIT_PYTHON_GIT_EXECUTABLE = cls.git_exec_name
314+
else:
315+
# after the first refresh (when GIT_PYTHON_GIT_EXECUTABLE
316+
# is no longer None) we raise an exception
317+
raise GitCommandNotFound("git", err)
318+
319+
return has_git
320+
195321
@classmethod
196322
def is_cygwin(cls):
197323
return is_cygwin_git(cls.GIT_PYTHON_GIT_EXECUTABLE)
@@ -405,7 +531,7 @@ def __init__(self, working_dir=None):
405531
It is meant to be the working tree directory if available, or the
406532
.git directory in case of bare repositories."""
407533
super(Git, self).__init__()
408-
self._working_dir = working_dir
534+
self._working_dir = expand_path(working_dir)
409535
self._git_options = ()
410536
self._persistent_git_options = []
411537

@@ -471,6 +597,7 @@ def execute(self, command,
471597
with_stdout=True,
472598
universal_newlines=False,
473599
shell=None,
600+
env=None,
474601
**subprocess_kwargs
475602
):
476603
"""Handles executing the command on the shell and consumes and returns
@@ -514,6 +641,9 @@ def execute(self, command,
514641
decoded into a string using the default encoding (usually utf-8).
515642
The latter can fail, if the output contains binary data.
516643
644+
:param env:
645+
A dictionary of environment variables to be passed to `subprocess.Popen`.
646+
517647
:param subprocess_kwargs:
518648
Keyword arguments to be passed to subprocess.Popen. Please note that
519649
some of the valid kwargs are already set by this method, the ones you
@@ -559,6 +689,7 @@ def execute(self, command,
559689
cwd = self._working_dir or os.getcwd()
560690

561691
# Start the process
692+
inline_env = env
562693
env = os.environ.copy()
563694
# Attempt to force all output to plain ascii english, which is what some parsing code
564695
# may expect.
@@ -567,6 +698,8 @@ def execute(self, command,
567698
env["LANGUAGE"] = "C"
568699
env["LC_ALL"] = "C"
569700
env.update(self._environment)
701+
if inline_env is not None:
702+
env.update(inline_env)
570703

571704
if is_win:
572705
cmd_not_found_exception = OSError
@@ -647,8 +780,8 @@ def _kill_process(pid):
647780
if kill_after_timeout:
648781
watchdog.cancel()
649782
if kill_check.isSet():
650-
stderr_value = 'Timeout: the command "%s" did not complete in %d ' \
651-
'secs.' % (" ".join(command), kill_after_timeout)
783+
stderr_value = ('Timeout: the command "%s" did not complete in %d '
784+
'secs.' % (" ".join(command), kill_after_timeout)).encode(defenc)
652785
# strip trailing "\n"
653786
if stdout_value.endswith(b"\n"):
654787
stdout_value = stdout_value[:-1]
@@ -828,13 +961,13 @@ def _call_process(self, method, *args, **kwargs):
828961
- "command options" to be converted by :meth:`transform_kwargs()`;
829962
- the `'insert_kwargs_after'` key which its value must match one of ``*args``,
830963
and any cmd-options will be appended after the matched arg.
831-
964+
832965
Examples::
833-
966+
834967
git.rev_list('master', max_count=10, header=True)
835-
968+
836969
turns into::
837-
970+
838971
git rev-list max-count 10 --header master
839972
840973
:return: Same as ``execute``"""

git/objects/submodule/base.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,12 @@ def _set_cache_(self, attr):
123123
reader = self.config_reader()
124124
# default submodule values
125125
try:
126-
self.path = reader.get_value('path')
126+
self.path = reader.get('path')
127127
except cp.NoSectionError:
128128
raise ValueError("This submodule instance does not exist anymore in '%s' file"
129129
% osp.join(self.repo.working_tree_dir, '.gitmodules'))
130130
# end
131-
self._url = reader.get_value('url')
131+
self._url = reader.get('url')
132132
# git-python extension values - optional
133133
self._branch_path = reader.get_value(self.k_head_option, git.Head.to_full_path(self.k_head_default))
134134
elif attr == '_name':
@@ -358,7 +358,9 @@ def add(cls, repo, name, path, url=None, branch=None, no_checkout=False):
358358
if sm.exists():
359359
# reretrieve submodule from tree
360360
try:
361-
return repo.head.commit.tree[path]
361+
sm = repo.head.commit.tree[path]
362+
sm._name = name
363+
return sm
362364
except KeyError:
363365
# could only be in index
364366
index = repo.index
@@ -1168,11 +1170,11 @@ def iter_items(cls, repo, parent_commit='HEAD'):
11681170

11691171
for sms in parser.sections():
11701172
n = sm_name(sms)
1171-
p = parser.get_value(sms, 'path')
1172-
u = parser.get_value(sms, 'url')
1173+
p = parser.get(sms, 'path')
1174+
u = parser.get(sms, 'url')
11731175
b = cls.k_head_default
11741176
if parser.has_option(sms, cls.k_head_option):
1175-
b = str(parser.get_value(sms, cls.k_head_option))
1177+
b = str(parser.get(sms, cls.k_head_option))
11761178
# END handle optional information
11771179

11781180
# get the binsha

git/refs/remote.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ def delete(cls, repo, *refs, **kwargs):
3636
# are generally ignored in the refs/ folder. We don't though
3737
# and delete remainders manually
3838
for ref in refs:
39+
try:
40+
os.remove(osp.join(repo.common_dir, ref.path))
41+
except OSError:
42+
pass
3943
try:
4044
os.remove(osp.join(repo.git_dir, ref.path))
4145
except OSError:

0 commit comments

Comments
 (0)