summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--README.md1
-rw-r--r--git/cmd.py2
-rw-r--r--git/config.py41
-rw-r--r--git/diff.py3
-rw-r--r--git/remote.py4
-rw-r--r--git/test/test_remote.py4
-rw-r--r--git/test/test_repo.py14
8 files changed, 61 insertions, 9 deletions
diff --git a/AUTHORS b/AUTHORS
index c8604bfc..a6212c2f 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -36,5 +36,6 @@ Contributors are:
-Arthur Milchior <arthur _at_ milchior.fr>
-Anil Khatri <anil.soccer.khatri _at_ gmail.com>
-JJ Graham <thetwoj _at_ gmail.com>
+-Ben Thayer <ben _at_ benthayer.com>
Portions derived from other open source works and are clearly marked.
diff --git a/README.md b/README.md
index 46867a4c..a2b53c8d 100644
--- a/README.md
+++ b/README.md
@@ -180,6 +180,7 @@ gpg --edit-key 88710E60
* [Loki](https://github.com/Neo23x0/Loki)
* [Omniwallet](https://github.com/OmniLayer/omniwallet)
* [GitViper](https://github.com/BeayemX/GitViper)
+* [Git Gud](https://github.com/bthayer2365/git-gud)
### LICENSE
diff --git a/git/cmd.py b/git/cmd.py
index a13556aa..08e25af5 100644
--- a/git/cmd.py
+++ b/git/cmd.py
@@ -401,7 +401,7 @@ class Git(LazyMixin):
:raise GitCommandError: if the return status is not 0"""
if stderr is None:
stderr = b''
- stderr = force_bytes(stderr)
+ stderr = force_bytes(data=stderr, encoding='utf-8')
status = self.proc.wait()
diff --git a/git/config.py b/git/config.py
index edd5750b..762069c7 100644
--- a/git/config.py
+++ b/git/config.py
@@ -20,7 +20,8 @@ from git.compat import (
defenc,
force_text,
with_metaclass,
- PY3
+ PY3,
+ is_win,
)
from git.util import LockFile
@@ -40,6 +41,10 @@ __all__ = ('GitConfigParser', 'SectionConstraint')
log = logging.getLogger('git.config')
log.addHandler(logging.NullHandler())
+# invariants
+# represents the configuration level of a configuration file
+CONFIG_LEVELS = ("system", "user", "global", "repository")
+
class MetaParserBuilder(abc.ABCMeta):
@@ -191,6 +196,26 @@ class _OMD(OrderedDict):
return [(k, self.getall(k)) for k in self]
+def get_config_path(config_level):
+
+ # we do not support an absolute path of the gitconfig on windows ,
+ # use the global config instead
+ if is_win and config_level == "system":
+ config_level = "global"
+
+ if config_level == "system":
+ return "/etc/gitconfig"
+ elif config_level == "user":
+ config_home = os.environ.get("XDG_CONFIG_HOME") or osp.join(os.environ.get("HOME", '~'), ".config")
+ return osp.normpath(osp.expanduser(osp.join(config_home, "git", "config")))
+ elif config_level == "global":
+ return osp.normpath(osp.expanduser("~/.gitconfig"))
+ elif config_level == "repository":
+ raise ValueError("No repo to get repository configuration from. Use Repo._get_config_path")
+
+ raise ValueError("Invalid configuration level: %r" % config_level)
+
+
class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, object)):
"""Implements specifics required to read git style configuration files.
@@ -229,7 +254,7 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje
# list of RawConfigParser methods able to change the instance
_mutating_methods_ = ("add_section", "remove_section", "remove_option", "set")
- def __init__(self, file_or_files, read_only=True, merge_includes=True):
+ def __init__(self, file_or_files=None, read_only=True, merge_includes=True, config_level=None):
"""Initialize a configuration reader to read the given file_or_files and to
possibly allow changes to it by setting read_only False
@@ -251,7 +276,17 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje
if not hasattr(self, '_proxies'):
self._proxies = self._dict()
- self._file_or_files = file_or_files
+ if file_or_files is not None:
+ self._file_or_files = file_or_files
+ else:
+ if config_level is None:
+ if read_only:
+ self._file_or_files = [get_config_path(f) for f in CONFIG_LEVELS if f != 'repository']
+ else:
+ raise ValueError("No configuration level or configuration files specified")
+ else:
+ self._file_or_files = [get_config_path(config_level)]
+
self._read_only = read_only
self._dirty = False
self._is_initialized = False
diff --git a/git/diff.py b/git/diff.py
index 897228a7..7a06f3a1 100644
--- a/git/diff.py
+++ b/git/diff.py
@@ -283,7 +283,8 @@ class Diff(object):
if repo and a_rawpath:
for submodule in repo.submodules:
if submodule.path == a_rawpath.decode("utf-8"):
- repo = submodule.module()
+ if submodule.module_exists():
+ repo = submodule.module()
break
if a_blob_id is None or a_blob_id == self.NULL_HEX_SHA:
diff --git a/git/remote.py b/git/remote.py
index 23337a9c..05d7d0db 100644
--- a/git/remote.py
+++ b/git/remote.py
@@ -717,7 +717,7 @@ class Remote(LazyMixin, Iterable):
# read the lines manually as it will use carriage returns between the messages
# to override the previous one. This is why we read the bytes manually
progress_handler = progress.new_message_handler()
- output = IterableList('name')
+ output = []
def stdout_handler(line):
try:
@@ -833,7 +833,7 @@ class Remote(LazyMixin, Iterable):
:note: No further progress information is returned after push returns.
:param kwargs: Additional arguments to be passed to git-push
:return:
- IterableList(PushInfo, ...) iterable list of PushInfo instances, each
+ list(PushInfo, ...) list of PushInfo instances, each
one informing about an individual head which had been updated on the remote
side.
If the push contains rejected heads, these will have the PushInfo.ERROR bit set
diff --git a/git/test/test_remote.py b/git/test/test_remote.py
index 95898f12..3ef47472 100644
--- a/git/test/test_remote.py
+++ b/git/test/test_remote.py
@@ -31,7 +31,7 @@ from git.test.lib import (
GIT_DAEMON_PORT,
assert_raises
)
-from git.util import IterableList, rmtree, HIDE_WINDOWS_FREEZE_ERRORS
+from git.util import rmtree, HIDE_WINDOWS_FREEZE_ERRORS
import os.path as osp
@@ -325,7 +325,7 @@ class TestRemote(TestBase):
self._commit_random_file(rw_repo)
progress = TestRemoteProgress()
res = remote.push(lhead.reference, progress)
- self.assertIsInstance(res, IterableList)
+ self.assertIsInstance(res, list)
self._do_test_push_result(res, remote)
progress.make_assertion()
diff --git a/git/test/test_repo.py b/git/test/test_repo.py
index de1e951a..c59203ed 100644
--- a/git/test/test_repo.py
+++ b/git/test/test_repo.py
@@ -245,6 +245,20 @@ class TestRepo(TestBase):
assert_equal(cloned.config_reader().get_value('core', 'filemode'), False)
assert_equal(cloned.config_reader().get_value('submodule "repo"', 'update'), 'checkout')
+ def test_clone_from_with_path_contains_unicode(self):
+ with tempfile.TemporaryDirectory() as tmpdir:
+ unicode_dir_name = '\u0394'
+ path_with_unicode = os.path.join(tmpdir, unicode_dir_name)
+ os.makedirs(path_with_unicode)
+
+ try:
+ Repo.clone_from(
+ url=self._small_repo_url(),
+ to_path=path_with_unicode,
+ )
+ except UnicodeEncodeError:
+ self.fail('Raised UnicodeEncodeError')
+
@with_rw_repo('HEAD')
def test_max_chunk_size(self, repo):
class TestOutputStream(object):