Repository: gitpython-developers/GitPython
Pull request #894 (2019-07-16 09:45:33)

use git rev-parse to look for config file
It fixes config file finding when in a separate worktree.

If fixes the issue with worktree reported in https://github.com/gitpython-developers/GitPython/issues/719#issuecomment-362232645

Byron: Thanks a lot for the contribution - I would love to merge, but can't as long as there is test breakage. Maybe it's an easy fix.
bdauvergne: I tried a work-around but i'm not sure of it, there is some circular dependency between the search got the .git directory in Repo and the initialization of the self.git command wrapper (the git command should be able to find the .git itself, but the late initialization has maybe some use).
bdauvergne: And it works (I don't know the problem with appveyor, I do not think it's related to my patch).
codecov-io: # [Codecov](https://codecov.io/gh/gitpython-developers/GitPython/pull/894?src=pr&el=h1) Report
> Merging [#894](https://codecov.io/gh/gitpython-developers/GitPython/pull/894?src=pr&el=desc) into [master](https://codecov.io/gh/gitpython-developers/GitPython/commit/ce7e1507fa5f6faf049794d4d47b14157d1f2e50?src=pr&el=desc) will **decrease** coverage by `0.02%`.
> The diff coverage is `95.45%`.

[![Impacted file tree graph](https://codecov.io/gh/gitpython-developers/GitPython/pull/894/graphs/tree.svg?width=650&token=mTmKwYbezP&height=150&src=pr)](https://codecov.io/gh/gitpython-developers/GitPython/pull/894?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #894      +/-   ##
==========================================
- Coverage    93.6%   93.57%   -0.03%     
==========================================
  Files          59       59              
  Lines        9769     9787      +18     
==========================================
+ Hits         9144     9158      +14     
- Misses        625      629       +4
```


| [Impacted Files](https://codecov.io/gh/gitpython-developers/GitPython/pull/894?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [git/repo/base.py](https://codecov.io/gh/gitpython-developers/GitPython/pull/894/diff?src=pr&el=tree#diff-Z2l0L3JlcG8vYmFzZS5weQ==) | `93.57% <95.45%> (-0.6%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/gitpython-developers/GitPython/pull/894?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/gitpython-developers/GitPython/pull/894?src=pr&el=footer). Last update [ce7e150...7f12bd4](https://codecov.io/gh/gitpython-developers/GitPython/pull/894?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/.appveyor.yml b/.appveyor.yml
index 017cf120..2658d96e 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -5,9 +5,6 @@ environment:
     CYGWIN64_GIT_PATH: "C:\\cygwin64\\bin;%GIT_DAEMON_PATH%"
 
     matrix:
-      - PYTHON: "C:\\Python27"
-        PYTHON_VERSION: "2.7"
-        GIT_PATH: "%GIT_DAEMON_PATH%"
       - PYTHON: "C:\\Python34-x64"
         PYTHON_VERSION: "3.4"
         GIT_PATH: "%GIT_DAEMON_PATH%"
@@ -26,12 +23,6 @@ environment:
         MAYFAIL: "yes"
         GIT_PATH: "%GIT_DAEMON_PATH%"
         ## Cygwin
-      - PYTHON: "C:\\Miniconda-x64"
-        PYTHON_VERSION: "2.7"
-        IS_CONDA: "yes"
-        IS_CYGWIN: "yes"
-        MAYFAIL: "yes"
-        GIT_PATH: "%CYGWIN_GIT_PATH%"
       - PYTHON: "C:\\Python35-x64"
         PYTHON_VERSION: "3.5"
         IS_CYGWIN: "yes"
diff --git a/.travis.yml b/.travis.yml
index 206c133e..56c86d1b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,6 @@
 language: python
 python:
+  - "2.7"
   - "3.4"
   - "3.5"
   - "3.6"
diff --git a/README.md b/README.md
index 3734019e..e252c34c 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ If it is not in your `PATH`, you can help GitPython find it by setting
 the `GIT_PYTHON_GIT_EXECUTABLE=<path/to/git>` environment variable.
 
 * Git (1.7.x or newer)
-* Python 3 to 3.7.
+* Python 2.7 to 3.7.
 
 The list of dependencies are listed in `./requirements.txt` and `./test-requirements.txt`.
 The installer takes care of installing them for you.
diff --git a/VERSION b/VERSION
index 348fc11e..ea4bd0fb 100644
--- a/VERSION
+++ b/VERSION
@@ -1,1 +1,1 @@
-2.1.12
+2.1.13
diff --git a/doc/source/changes.rst b/doc/source/changes.rst
index 92c28b69..b9f28638 100644
--- a/doc/source/changes.rst
+++ b/doc/source/changes.rst
@@ -2,6 +2,12 @@
 Changelog
 =========
 
+2.1.13 - Bring back Python 2.7 support
+======================================
+
+My apologies for any inconvenience this may have caused. Following semver, backward incompatible changes
+will be introduced in a minor version.
+
 2.1.12 - Bugfixes and Features
 ==============================
 
diff --git a/doc/source/intro.rst b/doc/source/intro.rst
index e2cd196b..d68e5eb2 100644
--- a/doc/source/intro.rst
+++ b/doc/source/intro.rst
@@ -13,7 +13,7 @@ The object database implementation is optimized for handling large quantities of
 Requirements
 ============
 
-* `Python`_ 3.0 or newer
+* `Python`_ 2.7 or newer
 * `Git`_ 1.7.0 or newer
     It should also work with older versions, but it may be that some operations
     involving remotes will not work as expected.
diff --git a/git/cmd.py b/git/cmd.py
index 64c3d480..50b1e321 100644
--- a/git/cmd.py
+++ b/git/cmd.py
@@ -893,7 +893,7 @@ class Git(LazyMixin):
         else:
             if value is True:
                 return ["--%s" % dashify(name)]
-            elif value not in (False, None):
+            elif value is not False and value is not None:
                 return ["--%s=%s" % (dashify(name), value)]
         return []
 
diff --git a/git/compat.py b/git/compat.py
index 02dc69de..b63768f3 100644
--- a/git/compat.py
+++ b/git/compat.py
@@ -30,10 +30,7 @@ PY3 = sys.version_info[0] >= 3
 is_win = (os.name == 'nt')
 is_posix = (os.name == 'posix')
 is_darwin = (os.name == 'darwin')
-if hasattr(sys, 'getfilesystemencoding'):
-    defenc = sys.getfilesystemencoding()
-if defenc is None:
-    defenc = sys.getdefaultencoding()
+defenc = sys.getdefaultencoding()
 
 if PY3:
     import io
diff --git a/git/repo/base.py b/git/repo/base.py
index 911494ad..af8e0c74 100644
--- a/git/repo/base.py
+++ b/git/repo/base.py
@@ -4,7 +4,6 @@
 # This module is part of GitPython and is released under
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 
-from builtins import str
 from collections import namedtuple
 import logging
 import os
@@ -67,7 +66,7 @@ class Repo(object):
     'git_dir' is the .git repository directory, which is always set."""
     DAEMON_EXPORT_FILE = 'git-daemon-export-ok'
 
-    git = None  # Must exist, or  __del__  will fail in case we raise on `__init__()`
+    _git = None  # Must exist, or  __del__  will fail in case we raise on `__init__()`
     working_dir = None
     _working_tree_dir = None
     git_dir = None
@@ -203,7 +202,6 @@ class Repo(object):
         # END working dir handling
 
         self.working_dir = self._working_tree_dir or self.common_dir
-        self.git = self.GitCommandWrapperType(self.working_dir)
 
         # special handling, in special times
         args = [osp.join(self.common_dir, 'objects')]
@@ -211,6 +209,35 @@ class Repo(object):
             args.append(self.git)
         self.odb = odbt(*args)
 
+    def _get_git(self):
+        working_dir = self._working_tree_dir or self.common_dir
+        if self._git:
+            if self._git._working_dir != expand_path(working_dir):
+                self.close()
+                self._git = None
+
+        if not self._git:
+            self._git = self.GitCommandWrapperType(working_dir)
+        return self._git
+
+    def _del_git(self):
+        if self._git:
+            self._git.clear_cache()
+            self._git = None
+            # Tempfiles objects on Windows are holding references to
+            # open files until they are collected by the garbage
+            # collector, thus preventing deletion.
+            # TODO: Find these references and ensure they are closed
+            # and deleted synchronously rather than forcing a gc
+            # collection.
+            if is_win:
+                gc.collect()
+            gitdb.util.mman.collect()
+            if is_win:
+                gc.collect()
+
+    git = property(fget=_get_git, fdel=_del_git)
+
     def __enter__(self):
         return self
 
@@ -224,19 +251,7 @@ class Repo(object):
             pass
 
     def close(self):
-        if self.git:
-            self.git.clear_cache()
-            # Tempfiles objects on Windows are holding references to
-            # open files until they are collected by the garbage
-            # collector, thus preventing deletion.
-            # TODO: Find these references and ensure they are closed
-            # and deleted synchronously rather than forcing a gc
-            # collection.
-            if is_win:
-                gc.collect()
-            gitdb.util.mman.collect()
-            if is_win:
-                gc.collect()
+        del self.git
 
     def __eq__(self, rhs):
         if isinstance(rhs, Repo):
@@ -432,7 +447,15 @@ class Repo(object):
         elif config_level == "global":
             return osp.normpath(osp.expanduser("~/.gitconfig"))
         elif config_level == "repository":
-            return osp.normpath(osp.join(self._common_dir or self.git_dir, "config"))
+            try:
+                config_path = self.git.rev_parse("config", git_path=True)
+            except GitCommandError:
+                return osp.normpath(osp.join(self._common_dir or self.git_dir, "config"))
+            else:
+                if self.git._working_dir:
+                    return osp.normpath(osp.join(self.git._working_dir, config_path))
+                else:
+                    return config_path
 
         raise ValueError("Invalid configuration level: %r" % config_level)
 
diff --git a/requirements.txt b/requirements.txt
index c0cca9f4..63d5ddfe 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,1 @@
 gitdb2 (>=2.0.0)
-gitdb>=0.6.4
-ddt>=1.1.1
diff --git a/setup.py b/setup.py
index 65656d55..49288f69 100755
--- a/setup.py
+++ b/setup.py
@@ -79,7 +79,7 @@ setup(
     package_data={'git.test': ['fixtures/*']},
     package_dir={'git': 'git'},
     license="BSD License",
-    python_requires='>=3.0, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
+    python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
     install_requires=requirements,
     tests_require=requirements + test_requirements,
     zip_safe=False,
@@ -102,6 +102,8 @@ setup(
         "Operating System :: Microsoft :: Windows",
         "Operating System :: MacOS :: MacOS X",
         "Programming Language :: Python",
+        "Programming Language :: Python :: 2",
+        "Programming Language :: Python :: 2.7",
         "Programming Language :: Python :: 3",
         "Programming Language :: Python :: 3.4",
         "Programming Language :: Python :: 3.5",
diff --git a/tox.ini b/tox.ini
index e46136d6..36048fbc 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = py27,py34,py35,py36,py37,flake8
+envlist = py34,py35,py36,py37,flake8
 
 [testenv]
 commands = nosetests {posargs}


Test patch:
diff --git a/git/test/lib/helper.py b/git/test/lib/helper.py
index 1c06010f..687db990 100644
--- a/git/test/lib/helper.py
+++ b/git/test/lib/helper.py
@@ -366,8 +366,7 @@ class TestBase(TestCase):
 
     @classmethod
     def tearDownClass(cls):
-        cls.rorepo.git.clear_cache()
-        cls.rorepo.git = None
+        del cls.rorepo.git
 
     def _make_file(self, rela_path, data, repo=None):
         """
diff --git a/git/test/test_git.py b/git/test/test_git.py
index 30a6a335..4a189267 100644
--- a/git/test/test_git.py
+++ b/git/test/test_git.py
@@ -86,6 +86,7 @@ class TestGit(TestBase):
 
         assert_equal(["--max-count"], self.git.transform_kwargs(**{'max_count': True}))
         assert_equal(["--max-count=5"], self.git.transform_kwargs(**{'max_count': 5}))
+        assert_equal(["--max-count=0"], self.git.transform_kwargs(**{'max_count': 0}))
         assert_equal([], self.git.transform_kwargs(**{'max_count': None}))
 
         # Multiple args are supported by using lists/tuples
diff --git a/test-requirements.txt b/test-requirements.txt
index ec0e4c56..ec2912ba 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -3,4 +3,3 @@ coverage
 flake8
 nose
 tox
-mock; python_version=='2.7'