Repository: gitpython-developers/GitPython
Pull request #533 (2016-10-14 15:57:45)

Support Cygwin's Git on Windows
+ Add 2 more Appveyor matrix-combinations for *Cygwin*, and *hide* 2+2 (see below) TCs failing - *you have to check from time to time if they hve been fixed*.
+ Add `git.util.cygpath()` & `git.util.decygpath()` based on material from these 2 resources:
  +https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
  +https://www.cygwin.com/cygwin-ug-net/using.html#unc-paths
+ Fix launching of *MINGW's `git-daemon`* also for Cygwin - reqork it as resource-managed (`with` statement.
+ "Polish" some urls sent to `git` commands to inlude `'/cygdrive/...'` prefix.
+ *de-cygpathize* repo-paths when creating `git.Repo()` instances to accept also `'/cygdrive/...'` paths.

### Appveyor Cygwin TC failures
Reporting changes in the Appvayor cygwin-combination *bottom-line* for significant commits, in reverse chronological order:
- 5962373: cygwin, appveyor, #533: Enable actual failures, hide certain 2+2 cases
  - PY2: skip: 12
  - PY3: skip: 16
- b2efa1b1: cygwin, #533: FIX submodules detection (~10TCs fixed)
  - PY2: err: 2, fail: 1
  - PY3: err: 2, fail: 1
- 9afebf67: cygwin, #533: FIX submodules detection (~10TCs fixed)
  - PY2: err: 2, fail: 2
  - PY3: err: 2, fail: 2
- a2d248bb: cygwin, #533: polish abs-paths in `git add` commands
  - PY2: err: 12, fail: 2
  - PY3: err: 11, fail: 2
- 3b1cfcc6: cygwin, #525: Allow '/cygdrive/c/' paths on repo init
  - PY2: err: 13, fail: 2
  - PY3: err: 12, fail: 2
- 57d05379: cygwin, #525: Polish also --git-separate-dir
  - PY2: err: 13, fail: 3
  - PY3: err: 12, fail: 3
- 0bce7cc4: cygwin, #525: FIX daemon launching
  - PY2: err: 13, fail: 3
  - PY3: err: 12, fail: 3
- e6e23ed2: cygwin, #525: Try to make it work with Cygwin's Git.
  - PY2: err: 14, fail: 3
  - PY3: err: 13, fail: 3
- ba7c2a0f: appveyor, #525: enable CYGWIN TCs without failing (START: no Cygwin specific code)
  - PY2: err: 44, fail: 0
  - PY3: err: 13, fail: 0



Patch:
diff --git a/.appveyor.yml b/.appveyor.yml
index 0e9a9473..701fc4ac 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -21,18 +21,17 @@ environment:
         IS_CONDA: "yes"
         GIT_PATH: "%GIT_DAEMON_PATH%"
 
-      #   ## Cygwin
-      #   #
-      # - PYTHON: "C:\\Miniconda-x64"
-      #   PYTHON_VERSION: "2.7"
-      #   IS_CONDA: "yes"
-      #   GIT_PATH: "%CYGWIN_GIT_PATH%"
-      # - PYTHON: "C:\\Python34-x64"
-      #   PYTHON_VERSION: "3.4"
-      #   GIT_PATH: "%CYGWIN_GIT_PATH%"
-      # - PYTHON: "C:\\Python35-x64"
-      #   PYTHON_VERSION: "3.5"
-      #   GIT_PATH: "%CYGWIN64_GIT_PATH%"
+        ## Cygwin
+        #
+      - PYTHON: "C:\\Miniconda-x64"
+        PYTHON_VERSION: "2.7"
+        IS_CONDA: "yes"
+        IS_CYGWIN: "yes"
+        GIT_PATH: "%CYGWIN_GIT_PATH%"
+      - PYTHON: "C:\\Python35-x64"
+        PYTHON_VERSION: "3.5"
+        GIT_PATH: "%CYGWIN64_GIT_PATH%"
+        IS_CYGWIN: "yes"
 
 
 install:
@@ -48,14 +47,12 @@ install:
         python --version
         python -c "import struct; print(struct.calcsize('P') * 8)"
 
-    - IF "%IS_CONDA%"=="yes" (
+    - IF "%IS_CONDA%" == "yes" (
         conda info -a &
         conda install --yes --quiet  pip
       )
-    - pip install  nose ddt wheel codecov
-    -   IF "%PYTHON_VERSION%"=="2.7" (
-            pip install mock
-        )
+    - pip install -r test-requirements.txt
+    - pip install codecov
 
     ## Copied from `init-tests-after-clone.sh`.
     #
@@ -79,7 +76,15 @@ install:
 build: false
 
 test_script:
-    - IF "%PYTHON_VERSION%"=="3.5" (nosetests -v --with-coverage) ELSE (nosetests -v)
+    -   IF "%IS_CYGWIN%" == "yes" (
+            nosetests -v
+        ) ELSE (
+            IF "%PYTHON_VERSION%" == "3.5" (
+                nosetests -v --with-coverage
+            ) ELSE (
+                nosetests -v
+            )
+        )
 
 on_success:
-    - IF "%PYTHON_VERSION%"=="3.5" (codecov)
+    - IF "%PYTHON_VERSION%" == "3.5" IF NOT "%IS_CYGWIN%" == "yes" (codecov)
diff --git a/.travis.yml b/.travis.yml
index 4c191db2..f7dd247b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,14 +1,10 @@
 language: python
 python:
-  - "2.6"
   - "2.7"
   - "3.3"
   - "3.4"
   - "3.5"
   # - "pypy" - won't work as smmap doesn't work (see gitdb/.travis.yml for details)
-matrix:
-  allow_failures:
-    - python: "2.6"
 git:
   # a higher depth is needed for most of the tests - must be high enough to not actually be shallow
   # as we clone our own repository in the process
@@ -17,7 +13,8 @@ install:
   - python --version; git --version
   - git submodule update --init --recursive
   - git fetch --tags
-  - pip install codecov flake8 ddt sphinx
+  - pip install -r test-requirements.txt
+  - pip install codecov sphinx
 
   # generate some reflog as git-python tests need it (in master)
   - ./init-tests-after-clone.sh
diff --git a/git/__init__.py b/git/__init__.py
index 58e4e7b6..0514d545 100644
--- a/git/__init__.py
+++ b/git/__init__.py
@@ -5,9 +5,12 @@
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 # flake8: noqa
 #@PydevCodeAnalysisIgnore
+import inspect
 import os
 import sys
-import inspect
+
+import os.path as osp
+
 
 __version__ = 'git'
 
@@ -16,7 +19,7 @@ __version__ = 'git'
 def _init_externals():
     """Initialize external projects by putting them into the path"""
     if __version__ == 'git':
-        sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'ext', 'gitdb'))
+        sys.path.insert(0, osp.join(osp.dirname(__file__), 'ext', 'gitdb'))
 
     try:
         import gitdb
diff --git a/git/cmd.py b/git/cmd.py
index f0757301..c43fac56 100644
--- a/git/cmd.py
+++ b/git/cmd.py
@@ -31,6 +31,7 @@ from git.compat import (
 )
 from git.exc import CommandError
 from git.odict import OrderedDict
+from git.util import is_cygwin_git, cygpath
 
 from .exc import (
     GitCommandError,
@@ -191,8 +192,26 @@ class Git(LazyMixin):
     USE_SHELL = False
 
     @classmethod
-    def polish_url(cls, url):
-        return url.replace("\\\\", "\\").replace("\\", "/")
+    def is_cygwin(cls):
+        return is_cygwin_git(cls.GIT_PYTHON_GIT_EXECUTABLE)
+
+    @classmethod
+    def polish_url(cls, url, is_cygwin=None):
+        if is_cygwin is None:
+            is_cygwin = cls.is_cygwin()
+
+        if is_cygwin:
+            url = cygpath(url)
+        else:
+            """Remove any backslahes from urls to be written in config files.
+
+            Windows might create config-files containing paths with backslashed,
+            but git stops liking them as it will escape the backslashes.
+            Hence we undo the escaping just to be sure.
+            """
+            url = url.replace("\\\\", "\\").replace("\\", "/")
+
+        return url
 
     class AutoInterrupt(object):
         """Kill/Interrupt the stored process instance once this instance goes out of scope. It is
diff --git a/git/config.py b/git/config.py
index eddfac15..a0b25822 100644
--- a/git/config.py
+++ b/git/config.py
@@ -6,21 +6,13 @@
 """Module containing module parser implementation able to properly read and write
 configuration files"""
 
-import re
-try:
-    import ConfigParser as cp
-except ImportError:
-    # PY3
-    import configparser as cp
+import abc
+from functools import wraps
 import inspect
 import logging
-import abc
 import os
+import re
 
-from functools import wraps
-
-from git.odict import OrderedDict
-from git.util import LockFile
 from git.compat import (
     string_types,
     FileType,
@@ -29,6 +21,18 @@ from git.compat import (
     with_metaclass,
     PY3
 )
+from git.odict import OrderedDict
+from git.util import LockFile
+
+import os.path as osp
+
+
+try:
+    import ConfigParser as cp
+except ImportError:
+    # PY3
+    import configparser as cp
+
 
 __all__ = ('GitConfigParser', 'SectionConstraint')
 
@@ -408,15 +412,15 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje
             if self._has_includes():
                 for _, include_path in self.items('include'):
                     if include_path.startswith('~'):
-                        include_path = os.path.expanduser(include_path)
-                    if not os.path.isabs(include_path):
+                        include_path = osp.expanduser(include_path)
+                    if not osp.isabs(include_path):
                         if not file_ok:
                             continue
                         # end ignore relative paths if we don't know the configuration file path
-                        assert os.path.isabs(file_path), "Need absolute paths to be sure our cycle checks will work"
-                        include_path = os.path.join(os.path.dirname(file_path), include_path)
+                        assert osp.isabs(file_path), "Need absolute paths to be sure our cycle checks will work"
+                        include_path = osp.join(osp.dirname(file_path), include_path)
                     # end make include path absolute
-                    include_path = os.path.normpath(include_path)
+                    include_path = osp.normpath(include_path)
                     if include_path in seen or not os.access(include_path, os.R_OK):
                         continue
                     seen.add(include_path)
diff --git a/git/db.py b/git/db.py
index 39b9872a..653fa7da 100644
--- a/git/db.py
+++ b/git/db.py
@@ -1,12 +1,9 @@
 """Module with our own gitdb implementation - it uses the git command"""
+from git.util import bin_to_hex, hex_to_bin
 from gitdb.base import (
     OInfo,
     OStream
 )
-from gitdb.util import (
-    bin_to_hex,
-    hex_to_bin
-)
 from gitdb.db import GitDB  # @UnusedImport
 from gitdb.db import LooseObjectDB
 
diff --git a/git/diff.py b/git/diff.py
index 35c7ff86..52dbf3a7 100644
--- a/git/diff.py
+++ b/git/diff.py
@@ -5,18 +5,17 @@
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 import re
 
-from gitdb.util import hex_to_bin
+from git.cmd import handle_process_output
+from git.compat import (
+    defenc,
+    PY3
+)
+from git.util import finalize_process, hex_to_bin
 
 from .compat import binary_type
 from .objects.blob import Blob
 from .objects.util import mode_str_to_int
 
-from git.compat import (
-    defenc,
-    PY3
-)
-from git.cmd import handle_process_output
-from git.util import finalize_process
 
 __all__ = ('Diffable', 'DiffIndex', 'Diff', 'NULL_TREE')
 
diff --git a/git/ext/gitdb b/git/ext/gitdb
index 38866bc7..97035c64 160000
--- a/git/ext/gitdb
+++ b/git/ext/gitdb
@@ -1,1 +1,1 @@
-Subproject commit 38866bc7c4956170c681a62c4508f934ac826469
+Subproject commit 97035c64f429c229629c25becc54ae44dd95e49d
diff --git a/git/index/base.py b/git/index/base.py
index ac2d3019..95ad8b05 100644
--- a/git/index/base.py
+++ b/git/index/base.py
@@ -3,34 +3,28 @@
 #
 # This module is part of GitPython and is released under
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
-import tempfile
-import os
-import sys
-import subprocess
 import glob
 from io import BytesIO
-
+import os
 from stat import S_ISLNK
+import subprocess
+import sys
+import tempfile
 
-from .typ import (
-    BaseIndexEntry,
-    IndexEntry,
-)
-
-from .util import (
-    TemporaryFileSwap,
-    post_clear_cache,
-    default_index,
-    git_working_dir
+from git.compat import (
+    izip,
+    xrange,
+    string_types,
+    force_bytes,
+    defenc,
+    mviter,
+    is_win
 )
-
-import git.diff as diff
 from git.exc import (
     GitCommandError,
     CheckoutError,
     InvalidGitRepositoryError
 )
-
 from git.objects import (
     Blob,
     Submodule,
@@ -38,26 +32,21 @@ from git.objects import (
     Object,
     Commit,
 )
-
 from git.objects.util import Serializable
-from git.compat import (
-    izip,
-    xrange,
-    string_types,
-    force_bytes,
-    defenc,
-    mviter,
-    is_win
-)
-
 from git.util import (
     LazyMixin,
     LockedFD,
     join_path_native,
     file_contents_ro,
     to_native_path_linux,
-    unbare_repo
+    unbare_repo,
+    to_bin_sha
 )
+from gitdb.base import IStream
+from gitdb.db import MemoryDB
+
+import git.diff as diff
+import os.path as osp
 
 from .fun import (
     entry_key,
@@ -69,10 +58,17 @@ from .fun import (
     S_IFGITLINK,
     run_commit_hook
 )
+from .typ import (
+    BaseIndexEntry,
+    IndexEntry,
+)
+from .util import (
+    TemporaryFileSwap,
+    post_clear_cache,
+    default_index,
+    git_working_dir
+)
 
-from gitdb.base import IStream
-from gitdb.db import MemoryDB
-from gitdb.util import to_bin_sha
 
 __all__ = ('IndexFile', 'CheckoutError')
 
@@ -354,7 +350,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
             index.entries       # force it to read the file as we will delete the temp-file
             del(index_handler)  # release as soon as possible
         finally:
-            if os.path.exists(tmp_index):
+            if osp.exists(tmp_index):
                 os.remove(tmp_index)
         # END index merge handling
 
@@ -374,8 +370,8 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
         rs = r + os.sep
         for path in paths:
             abs_path = path
-            if not os.path.isabs(abs_path):
-                abs_path = os.path.join(r, path)
+            if not osp.isabs(abs_path):
+                abs_path = osp.join(r, path)
             # END make absolute path
 
             try:
@@ -407,7 +403,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
                 for root, dirs, files in os.walk(abs_path, onerror=raise_exc):  # @UnusedVariable
                     for rela_file in files:
                         # add relative paths only
-                        yield os.path.join(root.replace(rs, ''), rela_file)
+                        yield osp.join(root.replace(rs, ''), rela_file)
                     # END for each file in subdir
                 # END for each subdirectory
             except OSError:
@@ -569,7 +565,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
     def _to_relative_path(self, path):
         """:return: Version of path relative to our git directory or raise ValueError
         if it is not within our git direcotory"""
-        if not os.path.isabs(path):
+        if not osp.isabs(path):
             return path
         if self.repo.bare:
             raise InvalidGitRepositoryError("require non-bare repository")
@@ -617,12 +613,12 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
         entries_added = list()
         if path_rewriter:
             for path in paths:
-                if os.path.isabs(path):
+                if osp.isabs(path):
                     abspath = path
                     gitrelative_path = path[len(self.repo.working_tree_dir) + 1:]
                 else:
                     gitrelative_path = path
-                    abspath = os.path.join(self.repo.working_tree_dir, gitrelative_path)
+                    abspath = osp.join(self.repo.working_tree_dir, gitrelative_path)
                 # end obtain relative and absolute paths
 
                 blob = Blob(self.repo, Blob.NULL_BIN_SHA,
diff --git a/git/index/fun.py b/git/index/fun.py
index 7a7593fe..d9c0f215 100644
--- a/git/index/fun.py
+++ b/git/index/fun.py
@@ -1,6 +1,8 @@
 # Contains standalone functions to accompany the index implementation and make it
 # more versatile
 # NOTE: Autodoc hates it if this is a docstring
+from io import BytesIO
+import os
 from stat import (
     S_IFDIR,
     S_IFLNK,
@@ -9,13 +11,18 @@ from stat import (
     S_IFMT,
     S_IFREG,
 )
-
-from io import BytesIO
-import os
 import subprocess
 
-from git.util import IndexFileSHA1Writer, finalize_process
 from git.cmd import PROC_CREATIONFLAGS, handle_process_output
+from git.compat import (
+    PY3,
+    defenc,
+    force_text,
+    force_bytes,
+    is_posix,
+    safe_encode,
+    safe_decode,
+)
 from git.exc import (
     UnmergedEntriesError,
     HookExecutionError
@@ -25,6 +32,11 @@ from git.objects.fun import (
     traverse_tree_recursive,
     traverse_trees_recursive
 )
+from git.util import IndexFileSHA1Writer, finalize_process
+from gitdb.base import IStream
+from gitdb.typ import str_tree_type
+
+import os.path as osp
 
 from .typ import (
     BaseIndexEntry,
@@ -32,23 +44,11 @@ from .typ import (
     CE_NAMEMASK,
     CE_STAGESHIFT
 )
-
 from .util import (
     pack,
     unpack
 )
 
-from gitdb.base import IStream
-from gitdb.typ import str_tree_type
-from git.compat import (
-    PY3,
-    defenc,
-    force_text,
-    force_bytes,
-    is_posix,
-    safe_encode,
-    safe_decode,
-)
 
 S_IFGITLINK = S_IFLNK | S_IFDIR     # a submodule
 CE_NAMEMASK_INV = ~CE_NAMEMASK
@@ -59,7 +59,7 @@ __all__ = ('write_cache', 'read_cache', 'write_tree_from_cache', 'entry_key',
 
 def hook_path(name, git_dir):
     """:return: path to the given named hook in the given git repository directory"""
-    return os.path.join(git_dir, 'hooks', name)
+    return osp.join(git_dir, 'hooks', name)
 
 
 def run_commit_hook(name, index):
diff --git a/git/index/util.py b/git/index/util.py
index ce798851..3c59b1d8 100644
--- a/git/index/util.py
+++ b/git/index/util.py
@@ -1,12 +1,14 @@
 """Module containing index utilities"""
+from functools import wraps
+import os
 import struct
 import tempfile
-import os
-
-from functools import wraps
 
 from git.compat import is_win
 
+import os.path as osp
+
+
 __all__ = ('TemporaryFileSwap', 'post_clear_cache', 'default_index', 'git_working_dir')
 
 #{ Aliases
@@ -32,8 +34,8 @@ class TemporaryFileSwap(object):
             pass
 
     def __del__(self):
-        if os.path.isfile(self.tmp_file_path):
-            if is_win and os.path.exists(self.file_path):
+        if osp.isfile(self.tmp_file_path):
+            if is_win and osp.exists(self.file_path):
                 os.remove(self.file_path)
             os.rename(self.tmp_file_path, self.file_path)
         # END temp file exists
diff --git a/git/objects/base.py b/git/objects/base.py
index 0b849960..d6080779 100644
--- a/git/objects/base.py
+++ b/git/objects/base.py
@@ -3,14 +3,13 @@
 #
 # This module is part of GitPython and is released under
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
-from .util import get_object_type_by_name
-from git.util import LazyMixin, join_path_native, stream_copy
-from gitdb.util import (
-    bin_to_hex,
-    basename
-)
+from git.util import LazyMixin, join_path_native, stream_copy, bin_to_hex
 
 import gitdb.typ as dbtyp
+import os.path as osp
+
+from .util import get_object_type_by_name
+
 
 _assertion_msg_format = "Created object %r whose python type %r disagrees with the acutal git object type %r"
 
@@ -170,7 +169,7 @@ class IndexObject(Object):
     @property
     def name(self):
         """:return: Name portion of the path, effectively being the basename"""
-        return basename(self.path)
+        return osp.basename(self.path)
 
     @property
     def abspath(self):
diff --git a/git/objects/commit.py b/git/objects/commit.py
index 1534c552..85955806 100644
--- a/git/objects/commit.py
+++ b/git/objects/commit.py
@@ -5,8 +5,8 @@
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 
 from gitdb import IStream
-from gitdb.util import hex_to_bin
 from git.util import (
+    hex_to_bin,
     Actor,
     Iterable,
     Stats,
diff --git a/git/objects/submodule/base.py b/git/objects/submodule/base.py
index 9bb563d7..d2c6e020 100644
--- a/git/objects/submodule/base.py
+++ b/git/objects/submodule/base.py
@@ -1,21 +1,18 @@
-from .util import (
-    mkhead,
-    sm_name,
-    sm_section,
-    SubmoduleConfigParser,
-    find_first_remote_branch
-)
-from git.objects.util import Traversable
-from io import BytesIO                   # need a dict to set bloody .name field
-from git.util import (
-    Iterable,
-    join_path_native,
-    to_native_path_linux,
-    RemoteProgress,
-    rmtree,
-    unbare_repo
-)
+# need a dict to set bloody .name field
+from io import BytesIO
+import logging
+import os
+import stat
+from unittest.case import SkipTest
+import uuid
 
+import git
+from git.cmd import Git
+from git.compat import (
+    string_types,
+    defenc,
+    is_win,
+)
 from git.config import (
     SectionConstraint,
     GitConfigParser,
@@ -26,22 +23,28 @@ from git.exc import (
     NoSuchPathError,
     RepositoryDirtyError
 )
-from git.compat import (
-    string_types,
-    defenc,
-    is_win,
+from git.objects.base import IndexObject, Object
+from git.objects.util import Traversable
+from git.util import (
+    Iterable,
+    join_path_native,
+    to_native_path_linux,
+    RemoteProgress,
+    rmtree,
+    unbare_repo
 )
+from git.util import HIDE_WINDOWS_KNOWN_ERRORS
 
-import stat
-import git
+import os.path as osp
+
+from .util import (
+    mkhead,
+    sm_name,
+    sm_section,
+    SubmoduleConfigParser,
+    find_first_remote_branch
+)
 
-import os
-import logging
-import uuid
-from unittest.case import SkipTest
-from git.util import HIDE_WINDOWS_KNOWN_ERRORS
-from git.objects.base import IndexObject, Object
-from git.cmd import Git
 
 __all__ = ["Submodule", "UpdateProgress"]
 
@@ -120,7 +123,7 @@ class Submodule(IndexObject, Iterable, Traversable):
                 self.path = reader.get_value('path')
             except cp.NoSectionError:
                 raise ValueError("This submodule instance does not exist anymore in '%s' file"
-                                 % os.path.join(self.repo.working_tree_dir, '.gitmodules'))
+                                 % osp.join(self.repo.working_tree_dir, '.gitmodules'))
             # end
             self._url = reader.get_value('url')
             # git-python extension values - optional
@@ -181,7 +184,7 @@ class Submodule(IndexObject, Iterable, Traversable):
         # end hanlde parent_commit
 
         if not repo.bare and parent_matches_head:
-            fp_module = os.path.join(repo.working_tree_dir, cls.k_modules_file)
+            fp_module = osp.join(repo.working_tree_dir, cls.k_modules_file)
         else:
             assert parent_commit is not None, "need valid parent_commit in bare repositories"
             try:
@@ -229,9 +232,9 @@ class Submodule(IndexObject, Iterable, Traversable):
     @classmethod
     def _module_abspath(cls, parent_repo, path, name):
         if cls._need_gitfile_submodules(parent_repo.git):
-            return os.path.join(parent_repo.git_dir, 'modules', name)
+            return osp.join(parent_repo.git_dir, 'modules', name)
         else:
-            return os.path.join(parent_repo.working_tree_dir, path)
+            return osp.join(parent_repo.working_tree_dir, path)
         # end
 
     @classmethod
@@ -246,10 +249,10 @@ class Submodule(IndexObject, Iterable, Traversable):
         module_checkout_path = module_abspath
         if cls._need_gitfile_submodules(repo.git):
             kwargs['separate_git_dir'] = module_abspath
-            module_abspath_dir = os.path.dirname(module_abspath)
-            if not os.path.isdir(module_abspath_dir):
+            module_abspath_dir = osp.dirname(module_abspath)
+            if not osp.isdir(module_abspath_dir):
                 os.makedirs(module_abspath_dir)
-            module_checkout_path = os.path.join(repo.working_tree_dir, path)
+            module_checkout_path = osp.join(repo.working_tree_dir, path)
         # end
 
         clone = git.Repo.clone_from(url, module_checkout_path, **kwargs)
@@ -267,7 +270,7 @@ class Submodule(IndexObject, Iterable, Traversable):
             path = path[:-1]
         # END handle trailing slash
 
-        if os.path.isabs(path):
+        if osp.isabs(path):
             working_tree_linux = to_native_path_linux(parent_repo.working_tree_dir)
             if not path.startswith(working_tree_linux):
                 raise ValueError("Submodule checkout path '%s' needs to be within the parents repository at '%s'"
@@ -291,18 +294,18 @@ class Submodule(IndexObject, Iterable, Traversable):
         :param working_tree_dir: directory to write the .git file into
         :param module_abspath: absolute path to the bare repository
         """
-        git_file = os.path.join(working_tree_dir, '.git')
-        rela_path = os.path.relpath(module_abspath, start=working_tree_dir)
+        git_file = osp.join(working_tree_dir, '.git')
+        rela_path = osp.relpath(module_abspath, start=working_tree_dir)
         if is_win:
-            if os.path.isfile(git_file):
+            if osp.isfile(git_file):
                 os.remove(git_file)
         with open(git_file, 'wb') as fp:
             fp.write(("gitdir: %s" % rela_path).encode(defenc))
 
-        with GitConfigParser(os.path.join(module_abspath, 'config'),
+        with GitConfigParser(osp.join(module_abspath, 'config'),
                              read_only=False, merge_includes=False) as writer:
             writer.set_value('core', 'worktree',
-                             to_native_path_linux(os.path.relpath(working_tree_dir, start=module_abspath)))
+                             to_native_path_linux(osp.relpath(working_tree_dir, start=module_abspath)))
 
     #{ Edit Interface
 
@@ -501,7 +504,7 @@ class Submodule(IndexObject, Iterable, Traversable):
 
                 # there is no git-repository yet - but delete empty paths
                 checkout_module_abspath = self.abspath
-                if not dry_run and os.path.isdir(checkout_module_abspath):
+                if not dry_run and osp.isdir(checkout_module_abspath):
                     try:
                         os.rmdir(checkout_module_abspath)
                     except OSError:
@@ -671,7 +674,7 @@ class Submodule(IndexObject, Iterable, Traversable):
         # END handle no change
 
         module_checkout_abspath = join_path_native(self.repo.working_tree_dir, module_checkout_path)
-        if os.path.isfile(module_checkout_abspath):
+        if osp.isfile(module_checkout_abspath):
             raise ValueError("Cannot move repository onto a file: %s" % module_checkout_abspath)
         # END handle target files
 
@@ -684,12 +687,12 @@ class Submodule(IndexObject, Iterable, Traversable):
 
         # remove existing destination
         if module:
-            if os.path.exists(module_checkout_abspath):
+            if osp.exists(module_checkout_abspath):
                 if len(os.listdir(module_checkout_abspath)):
                     raise ValueError("Destination module directory was not empty")
                 # END handle non-emptiness
 
-                if os.path.islink(module_checkout_abspath):
+                if osp.islink(module_checkout_abspath):
                     os.remove(module_checkout_abspath)
                 else:
                     os.rmdir(module_checkout_abspath)
@@ -704,11 +707,11 @@ class Submodule(IndexObject, Iterable, Traversable):
         # move the module into place if possible
         cur_path = self.abspath
         renamed_module = False
-        if module and os.path.exists(cur_path):
+        if module and osp.exists(cur_path):
             os.renames(cur_path, module_checkout_abspath)
             renamed_module = True
 
-            if os.path.isfile(os.path.join(module_checkout_abspath, '.git')):
+            if osp.isfile(osp.join(module_checkout_abspath, '.git')):
                 module_abspath = self._module_abspath(self.repo, self.path, self.name)
                 self._write_git_file_and_module_config(module_checkout_abspath, module_abspath)
             # end handle git file rewrite
@@ -804,11 +807,11 @@ class Submodule(IndexObject, Iterable, Traversable):
                 # state. Delete the .git folders last, start with the submodules first
                 mp = self.abspath
                 method = None
-                if os.path.islink(mp):
+                if osp.islink(mp):
                     method = os.remove
-                elif os.path.isdir(mp):
+                elif osp.isdir(mp):
                     method = rmtree
-                elif os.path.exists(mp):
+                elif osp.exists(mp):
                     raise AssertionError("Cannot forcibly delete repository as it was neither a link, nor a directory")
                 # END handle brutal deletion
                 if not dry_run:
@@ -865,7 +868,7 @@ class Submodule(IndexObject, Iterable, Traversable):
                 # END delete tree if possible
             # END handle force
 
-            if not dry_run and os.path.isdir(git_dir):
+            if not dry_run and osp.isdir(git_dir):
                 self._clear_cache()
                 try:
                     rmtree(git_dir)
diff --git a/git/objects/tag.py b/git/objects/tag.py
index cefff083..19cb04bf 100644
--- a/git/objects/tag.py
+++ b/git/objects/tag.py
@@ -5,12 +5,9 @@
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 """ Module containing all object based types. """
 from . import base
-from .util import (
-    get_object_type_by_name,
-    parse_actor_and_date
-)
-from gitdb.util import hex_to_bin
-from git.compat import defenc
+from .util import get_object_type_by_name, parse_actor_and_date
+from ..util import hex_to_bin
+from ..compat import defenc
 
 __all__ = ("TagObject", )
 
diff --git a/git/objects/tree.py b/git/objects/tree.py
index 4f853f92..46fe63e7 100644
--- a/git/objects/tree.py
+++ b/git/objects/tree.py
@@ -5,7 +5,7 @@
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 from git.util import join_path
 import git.diff as diff
-from gitdb.util import to_bin_sha
+from git.util import to_bin_sha
 
 from . import util
 from .base import IndexObject
@@ -18,7 +18,7 @@ from .fun import (
     tree_to_stream
 )
 
-from gitdb.utils.compat import PY3
+from git.compat import PY3
 
 if PY3:
     cmp = lambda a, b: (a > b) - (a < b)
diff --git a/git/refs/log.py b/git/refs/log.py
index 3078355d..bab6ae04 100644
--- a/git/refs/log.py
+++ b/git/refs/log.py
@@ -1,31 +1,29 @@
+import re
+import time
+
+from git.compat import (
+    PY3,
+    xrange,
+    string_types,
+    defenc
+)
+from git.objects.util import (
+    parse_date,
+    Serializable,
+    altz_to_utctz_str,
+)
 from git.util import (
     Actor,
     LockedFD,
     LockFile,
     assure_directory_exists,
     to_native_path,
-)
-
-from gitdb.util import (
     bin_to_hex,
-    join,
-    file_contents_ro_filepath,
+    file_contents_ro_filepath
 )
 
-from git.objects.util import (
-    parse_date,
-    Serializable,
-    altz_to_utctz_str,
-)
-from git.compat import (
-    PY3,
-    xrange,
-    string_types,
-    defenc
-)
+import os.path as osp
 
-import time
-import re
 
 __all__ = ["RefLog", "RefLogEntry"]
 
@@ -185,7 +183,7 @@ class RefLog(list, Serializable):
             instance would be found. The path is not guaranteed to point to a valid
             file though.
         :param ref: SymbolicReference instance"""
-        return join(ref.repo.git_dir, "logs", to_native_path(ref.path))
+        return osp.join(ref.repo.git_dir, "logs", to_native_path(ref.path))
 
     @classmethod
     def iter_entries(cls, stream):
diff --git a/git/refs/remote.py b/git/refs/remote.py
index 1f256b75..4fc784d1 100644
--- a/git/refs/remote.py
+++ b/git/refs/remote.py
@@ -1,9 +1,10 @@
+import os
+
 from git.util import join_path
-from gitdb.util import join
 
-from .head import Head
+import os.path as osp
 
-import os
+from .head import Head
 
 
 __all__ = ["RemoteReference"]
@@ -36,7 +37,7 @@ class RemoteReference(Head):
         # and delete remainders manually
         for ref in refs:
             try:
-                os.remove(join(repo.git_dir, ref.path))
+                os.remove(osp.join(repo.git_dir, ref.path))
             except OSError:
                 pass
         # END for each ref
diff --git a/git/refs/symbolic.py b/git/refs/symbolic.py
index ebaff8ca..3a93d81c 100644
--- a/git/refs/symbolic.py
+++ b/git/refs/symbolic.py
@@ -1,34 +1,28 @@
 import os
 
+from git.compat import (
+    string_types,
+    defenc
+)
 from git.objects import Object, Commit
 from git.util import (
     join_path,
     join_path_native,
     to_native_path_linux,
-    assure_directory_exists
+    assure_directory_exists,
+    hex_to_bin,
+    LockedFD
 )
-
 from gitdb.exc import (
     BadObject,
     BadName
 )
-from gitdb.util import (
-    join,
-    dirname,
-    isdir,
-    exists,
-    isfile,
-    rename,
-    hex_to_bin,
-    LockedFD
-)
-from git.compat import (
-    string_types,
-    defenc
-)
+
+import os.path as osp
 
 from .log import RefLog
 
+
 __all__ = ["SymbolicReference"]
 
 
@@ -81,7 +75,7 @@ class SymbolicReference(object):
 
     @classmethod
     def _get_packed_refs_path(cls, repo):
-        return join(repo.git_dir, 'packed-refs')
+        return osp.join(repo.git_dir, 'packed-refs')
 
     @classmethod
     def _iter_packed_refs(cls, repo):
@@ -134,7 +128,7 @@ class SymbolicReference(object):
         point to, or None"""
         tokens = None
         try:
-            with open(join(repo.git_dir, ref_path), 'rt') as fp:
+            with open(osp.join(repo.git_dir, ref_path), 'rt') as fp:
                 value = fp.read().rstrip()
             # Don't only split on spaces, but on whitespace, which allows to parse lines like
             # 60b64ef992065e2600bfef6187a97f92398a9144                branch 'master' of git-server:/path/to/repo
@@ -418,8 +412,8 @@ class SymbolicReference(object):
             or just "myreference", hence 'refs/' is implied.
             Alternatively the symbolic reference to be deleted"""
         full_ref_path = cls.to_full_path(path)
-        abs_path = join(repo.git_dir, full_ref_path)
-        if exists(abs_path):
+        abs_path = osp.join(repo.git_dir, full_ref_path)
+        if osp.exists(abs_path):
             os.remove(abs_path)
         else:
             # check packed refs
@@ -458,7 +452,7 @@ class SymbolicReference(object):
 
         # delete the reflog
         reflog_path = RefLog.path(cls(repo, full_ref_path))
-        if os.path.isfile(reflog_path):
+        if osp.isfile(reflog_path):
             os.remove(reflog_path)
         # END remove reflog
 
@@ -470,14 +464,14 @@ class SymbolicReference(object):
         corresponding object and a detached symbolic reference will be created
         instead"""
         full_ref_path = cls.to_full_path(path)
-        abs_ref_path = join(repo.git_dir, full_ref_path)
+        abs_ref_path = osp.join(repo.git_dir, full_ref_path)
 
         # figure out target data
         target = reference
         if resolve:
             target = repo.rev_parse(str(reference))
 
-        if not force and isfile(abs_ref_path):
+        if not force and osp.isfile(abs_ref_path):
             target_data = str(target)
             if isinstance(target, SymbolicReference):
                 target_data = target.path
@@ -544,9 +538,9 @@ class SymbolicReference(object):
         if self.path == new_path:
             return self
 
-        new_abs_path = join(self.repo.git_dir, new_path)
-        cur_abs_path = join(self.repo.git_dir, self.path)
-        if isfile(new_abs_path):
+        new_abs_path = osp.join(self.repo.git_dir, new_path)
+        cur_abs_path = osp.join(self.repo.git_dir, self.path)
+        if osp.isfile(new_abs_path):
             if not force:
                 # if they point to the same file, its not an error
                 with open(new_abs_path, 'rb') as fd1:
@@ -561,12 +555,12 @@ class SymbolicReference(object):
             os.remove(new_abs_path)
         # END handle existing target file
 
-        dname = dirname(new_abs_path)
-        if not isdir(dname):
+        dname = osp.dirname(new_abs_path)
+        if not osp.isdir(dname):
             os.makedirs(dname)
         # END create directory
 
-        rename(cur_abs_path, new_abs_path)
+        os.rename(cur_abs_path, new_abs_path)
         self.path = new_path
 
         return self
diff --git a/git/remote.py b/git/remote.py
index 71585a41..b920079d 100644
--- a/git/remote.py
+++ b/git/remote.py
@@ -5,8 +5,25 @@
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 
 # Module implementing a remote object allowing easy access to git remotes
+import logging
 import re
 
+from git.cmd import handle_process_output, Git
+from git.compat import (defenc, force_text, is_win)
+from git.exc import GitCommandError
+from git.util import (
+    LazyMixin,
+    Iterable,
+    IterableList,
+    RemoteProgress,
+    CallableRemoteProgress
+)
+from git.util import (
+    join_path,
+)
+
+import os.path as osp
+
 from .config import (
     SectionConstraint,
     cp,
@@ -18,21 +35,7 @@ from .refs import (
     SymbolicReference,
     TagReference
 )
-from git.util import (
-    LazyMixin,
-    Iterable,
-    IterableList,
-    RemoteProgress,
-    CallableRemoteProgress
-)
-from git.util import (
-    join_path,
-)
-from git.cmd import handle_process_output, Git
-from gitdb.util import join
-from git.compat import (defenc, force_text, is_win)
-import logging
-from git.exc import GitCommandError
+
 
 log = logging.getLogger('git.remote')
 
@@ -644,7 +647,7 @@ class Remote(LazyMixin, Iterable):
                     continue
 
         # read head information
-        with open(join(self.repo.git_dir, 'FETCH_HEAD'), 'rb') as fp:
+        with open(osp.join(self.repo.git_dir, 'FETCH_HEAD'), 'rb') as fp:
             fetch_head_info = [l.decode(defenc) for l in fp.readlines()]
 
         l_fil = len(fetch_info_lines)
diff --git a/git/repo/base.py b/git/repo/base.py
index c5cdce7c..21d129e9 100644
--- a/git/repo/base.py
+++ b/git/repo/base.py
@@ -4,52 +4,16 @@
 # This module is part of GitPython and is released under
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 
-from git.exc import (
-    InvalidGitRepositoryError,
-    NoSuchPathError,
-    GitCommandError
-)
+from collections import namedtuple
+import logging
+import os
+import re
+import sys
+
 from git.cmd import (
     Git,
     handle_process_output
 )
-from git.refs import (
-    HEAD,
-    Head,
-    Reference,
-    TagReference,
-)
-from git.objects import (
-    Submodule,
-    RootModule,
-    Commit
-)
-from git.util import (
-    Actor,
-    finalize_process
-)
-from git.index import IndexFile
-from git.config import GitConfigParser
-from git.remote import (
-    Remote,
-    add_progress,
-    to_progress_instance
-)
-
-from git.db import GitCmdObjectDB
-
-from gitdb.util import (
-    join,
-    isfile,
-    hex_to_bin
-)
-
-from .fun import (
-    rev_parse,
-    is_git_dir,
-    find_git_dir,
-    touch,
-)
 from git.compat import (
     text_type,
     defenc,
@@ -58,12 +22,19 @@ from git.compat import (
     range,
     is_win,
 )
+from git.config import GitConfigParser
+from git.db import GitCmdObjectDB
+from git.exc import InvalidGitRepositoryError, NoSuchPathError, GitCommandError
+from git.index import IndexFile
+from git.objects import Submodule, RootModule, Commit
+from git.refs import HEAD, Head, Reference, TagReference
+from git.remote import Remote, add_progress, to_progress_instance
+from git.util import Actor, finalize_process, decygpath, hex_to_bin
+
+import os.path as osp
+
+from .fun import rev_parse, is_git_dir, find_git_dir, touch
 
-import os
-import sys
-import re
-import logging
-from collections import namedtuple
 
 log = logging.getLogger(__name__)
 
@@ -79,7 +50,7 @@ __all__ = ('Repo',)
 
 
 def _expand_path(p):
-    return os.path.abspath(os.path.expandvars(os.path.expanduser(p)))
+    return osp.abspath(osp.expandvars(osp.expanduser(p)))
 
 
 class Repo(object):
@@ -124,6 +95,8 @@ class Repo(object):
                 repo = Repo("~/Development/git-python.git")
                 repo = Repo("$REPOSITORIES/Development/git-python.git")
 
+            In *Cygwin*, path may be a `'cygdrive/...'` prefixed path.
+
         :param odbt:
             Object DataBase type - a type which is constructed by providing
             the directory containing the database objects, i.e. .git/objects. It will
@@ -136,9 +109,12 @@ class Repo(object):
         :raise InvalidGitRepositoryError:
         :raise NoSuchPathError:
         :return: git.Repo """
+        if Git.is_cygwin():
+            path = decygpath(path)
+
         epath = _expand_path(path or os.getcwd())
         self.git = None  # should be set for __del__ not to fail in case we raise
-        if not os.path.exists(epath):
+        if not osp.exists(epath):
             raise NoSuchPathError(epath)
 
         self.working_dir = None
@@ -148,24 +124,24 @@ class Repo(object):
 
         # walk up the path to find the .git dir
         while curpath:
-            # ABOUT os.path.NORMPATH
+            # ABOUT osp.NORMPATH
             # It's important to normalize the paths, as submodules will otherwise initialize their
             # repo instances with paths that depend on path-portions that will not exist after being
             # removed. It's just cleaner.
             if is_git_dir(curpath):
-                self.git_dir = os.path.normpath(curpath)
-                self._working_tree_dir = os.path.dirname(self.git_dir)
+                self.git_dir = osp.normpath(curpath)
+                self._working_tree_dir = osp.dirname(self.git_dir)
                 break
 
-            gitpath = find_git_dir(join(curpath, '.git'))
+            gitpath = find_git_dir(osp.join(curpath, '.git'))
             if gitpath is not None:
-                self.git_dir = os.path.normpath(gitpath)
+                self.git_dir = osp.normpath(gitpath)
                 self._working_tree_dir = curpath
                 break
 
             if not search_parent_directories:
                 break
-            curpath, dummy = os.path.split(curpath)
+            curpath, dummy = osp.split(curpath)
             if not dummy:
                 break
         # END while curpath
@@ -190,7 +166,7 @@ class Repo(object):
         self.git = self.GitCommandWrapperType(self.working_dir)
 
         # special handling, in special times
-        args = [join(self.git_dir, 'objects')]
+        args = [osp.join(self.git_dir, 'objects')]
         if issubclass(odbt, GitCmdObjectDB):
             args.append(self.git)
         self.odb = odbt(*args)
@@ -212,12 +188,12 @@ class Repo(object):
 
     # Description property
     def _get_description(self):
-        filename = join(self.git_dir, 'description')
+        filename = osp.join(self.git_dir, 'description')
         with open(filename, 'rb') as fp:
             return fp.read().rstrip().decode(defenc)
 
     def _set_description(self, descr):
-        filename = join(self.git_dir, 'description')
+        filename = osp.join(self.git_dir, 'description')
         with open(filename, 'wb') as fp:
             fp.write((descr + '\n').encode(defenc))
 
@@ -381,12 +357,12 @@ class Repo(object):
         if config_level == "system":
             return "/etc/gitconfig"
         elif config_level == "user":
-            config_home = os.environ.get("XDG_CONFIG_HOME") or os.path.join(os.environ.get("HOME", '~'), ".config")
-            return os.path.normpath(os.path.expanduser(join(config_home, "git", "config")))
+            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 os.path.normpath(os.path.expanduser("~/.gitconfig"))
+            return osp.normpath(osp.expanduser("~/.gitconfig"))
         elif config_level == "repository":
-            return os.path.normpath(join(self.git_dir, "config"))
+            return osp.normpath(osp.join(self.git_dir, "config"))
 
         raise ValueError("Invalid configuration level: %r" % config_level)
 
@@ -530,12 +506,12 @@ class Repo(object):
         return True
 
     def _get_daemon_export(self):
-        filename = join(self.git_dir, self.DAEMON_EXPORT_FILE)
-        return os.path.exists(filename)
+        filename = osp.join(self.git_dir, self.DAEMON_EXPORT_FILE)
+        return osp.exists(filename)
 
     def _set_daemon_export(self, value):
-        filename = join(self.git_dir, self.DAEMON_EXPORT_FILE)
-        fileexists = os.path.exists(filename)
+        filename = osp.join(self.git_dir, self.DAEMON_EXPORT_FILE)
+        fileexists = osp.exists(filename)
         if value and not fileexists:
             touch(filename)
         elif not value and fileexists:
@@ -550,9 +526,9 @@ class Repo(object):
         """The list of alternates for this repo from which objects can be retrieved
 
         :return: list of strings being pathnames of alternates"""
-        alternates_path = join(self.git_dir, 'objects', 'info', 'alternates')
+        alternates_path = osp.join(self.git_dir, 'objects', 'info', 'alternates')
 
-        if os.path.exists(alternates_path):
+        if osp.exists(alternates_path):
             with open(alternates_path, 'rb') as f:
                 alts = f.read().decode(defenc)
             return alts.strip().splitlines()
@@ -570,9 +546,9 @@ class Repo(object):
         :note:
             The method does not check for the existance of the paths in alts
             as the caller is responsible."""
-        alternates_path = join(self.git_dir, 'objects', 'info', 'alternates')
+        alternates_path = osp.join(self.git_dir, 'objects', 'info', 'alternates')
         if not alts:
-            if isfile(alternates_path):
+            if osp.isfile(alternates_path):
                 os.remove(alternates_path)
         else:
             with open(alternates_path, 'wb') as f:
@@ -601,7 +577,7 @@ class Repo(object):
             default_args.append(path)
         if index:
             # diff index against HEAD
-            if isfile(self.index.path) and \
+            if osp.isfile(self.index.path) and \
                     len(self.git.diff('--cached', *default_args)):
                 return True
         # END index handling
@@ -861,7 +837,7 @@ class Repo(object):
         :return: ``git.Repo`` (the newly created repo)"""
         if path:
             path = _expand_path(path)
-        if mkdir and path and not os.path.exists(path):
+        if mkdir and path and not osp.exists(path):
             os.makedirs(path, 0o755)
 
         # git command automatically chdir into the directory
@@ -875,19 +851,32 @@ class Repo(object):
             progress = to_progress_instance(progress)
 
         odbt = kwargs.pop('odbt', odb_default_type)
-        proc = git.clone(url, path, with_extended_output=True, as_process=True,
+
+        ## A bug win cygwin's Git, when `--bare` or `--separate-git-dir`
+        #  it prepends the cwd or(?) the `url` into the `path, so::
+        #        git clone --bare  /cygwin/d/foo.git  C:\\Work
+        #  becomes::
+        #        git clone --bare  /cygwin/d/foo.git  /cygwin/d/C:\\Work
+        #
+        clone_path = (Git.polish_url(path)
+                      if Git.is_cygwin() and 'bare'in kwargs
+                      else path)
+        sep_dir = kwargs.get('separate_git_dir')
+        if sep_dir:
+            kwargs['separate_git_dir'] = Git.polish_url(sep_dir)
+        proc = git.clone(Git.polish_url(url), clone_path, with_extended_output=True, as_process=True,
                          v=True, **add_progress(kwargs, git, progress))
         if progress:
             handle_process_output(proc, None, progress.new_message_handler(), finalize_process)
         else:
-            (stdout, stderr) = proc.communicate()  # FIXME: Will block of outputs are big!
+            (stdout, stderr) = proc.communicate()  # FIXME: Will block if outputs are big!
             log.debug("Cmd(%s)'s unused stdout: %s", getattr(proc, 'args', ''), stdout)
             finalize_process(proc, stderr=stderr)
 
         # our git command could have a different working dir than our actual
         # environment, hence we prepend its working dir if required
-        if not os.path.isabs(path) and git.working_dir:
-            path = join(git._working_dir, path)
+        if not osp.isabs(path) and git.working_dir:
+            path = osp.join(git._working_dir, path)
 
         # adjust remotes - there may be operating systems which use backslashes,
         # These might be given as initial paths, but when handling the config file
@@ -965,7 +954,7 @@ class Repo(object):
         """
         if self.bare:
             return False
-        return os.path.isfile(os.path.join(self.working_tree_dir, '.git'))
+        return osp.isfile(osp.join(self.working_tree_dir, '.git'))
 
     rev_parse = rev_parse
 
diff --git a/git/repo/fun.py b/git/repo/fun.py
index 320eb1c8..7ea45e6b 100644
--- a/git/repo/fun.py
+++ b/git/repo/fun.py
@@ -2,22 +2,18 @@
 import os
 from string import digits
 
+from git.compat import xrange
+from git.exc import WorkTreeRepositoryUnsupported
+from git.objects import Object
+from git.refs import SymbolicReference
+from git.util import hex_to_bin, bin_to_hex, decygpath
 from gitdb.exc import (
     BadObject,
     BadName,
 )
-from git.refs import SymbolicReference
-from git.objects import Object
-from gitdb.util import (
-    join,
-    isdir,
-    isfile,
-    dirname,
-    hex_to_bin,
-    bin_to_hex
-)
-from git.exc import WorkTreeRepositoryUnsupported
-from git.compat import xrange
+
+import os.path as osp
+from git.cmd import Git
 
 
 __all__ = ('rev_parse', 'is_git_dir', 'touch', 'find_git_dir', 'name_to_object', 'short_to_long', 'deref_tag',
@@ -38,13 +34,15 @@ def is_git_dir(d):
             but at least clearly indicates that we don't support it.
             There is the unlikely danger to throw if we see directories which just look like a worktree dir,
             but are none."""
-    if isdir(d):
-        if isdir(join(d, 'objects')) and isdir(join(d, 'refs')):
-            headref = join(d, 'HEAD')
-            return isfile(headref) or \
-                (os.path.islink(headref) and
+    if osp.isdir(d):
+        if osp.isdir(osp.join(d, 'objects')) and osp.isdir(osp.join(d, 'refs')):
+            headref = osp.join(d, 'HEAD')
+            return osp.isfile(headref) or \
+                (osp.islink(headref) and
                  os.readlink(headref).startswith('refs'))
-        elif isfile(join(d, 'gitdir')) and isfile(join(d, 'commondir')) and isfile(join(d, 'gitfile')):
+        elif (osp.isfile(osp.join(d, 'gitdir')) and
+              osp.isfile(osp.join(d, 'commondir')) and
+              osp.isfile(osp.join(d, 'gitfile'))):
             raise WorkTreeRepositoryUnsupported(d)
     return False
 
@@ -62,8 +60,11 @@ def find_git_dir(d):
     else:
         if content.startswith('gitdir: '):
             path = content[8:]
-            if not os.path.isabs(path):
-                path = join(dirname(d), path)
+            if Git.is_cygwin():
+                ## Cygwin creates submodules prefixed with `/cygdrive/...` suffixes.
+                path = decygpath(path)
+            if not osp.isabs(path):
+                path = osp.join(osp.dirname(d), path)
             return find_git_dir(path)
     # end handle exception
     return None
diff --git a/git/util.py b/git/util.py
index d00de1e4..c3c8e562 100644
--- a/git/util.py
+++ b/git/util.py
@@ -5,6 +5,8 @@
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 from __future__ import unicode_literals
 
+import contextlib
+from functools import wraps
 import getpass
 import logging
 import os
@@ -13,19 +15,21 @@ import re
 import shutil
 import stat
 import time
+from unittest.case import SkipTest
 
-from functools import wraps
-
-from git.compat import is_win
 from gitdb.util import (# NOQA @IgnorePep8
     make_sha,
     LockedFD,               # @UnusedImport
     file_contents_ro,       # @UnusedImport
+    file_contents_ro_filepath,       # @UnusedImport
     LazyMixin,              # @UnusedImport
     to_hex_sha,             # @UnusedImport
-    to_bin_sha              # @UnusedImport
+    to_bin_sha,             # @UnusedImport
+    bin_to_hex,             # @UnusedImport
+    hex_to_bin,             # @UnusedImport
 )
 
+from git.compat import is_win
 import os.path as osp
 
 from .compat import (
@@ -34,7 +38,6 @@ from .compat import (
     PY3
 )
 from .exc import InvalidGitRepositoryError
-from unittest.case import SkipTest
 
 
 # NOTE:  Some of the unused imports might be used/imported by others.
@@ -47,11 +50,13 @@ __all__ = ("stream_copy", "join_path", "to_native_path_windows", "to_native_path
            'RemoteProgress', 'CallableRemoteProgress', 'rmtree', 'unbare_repo',
            'HIDE_WINDOWS_KNOWN_ERRORS')
 
+log = logging.getLogger(__name__)
+
 #: We need an easy way to see if Appveyor TCs start failing,
 #: so the errors marked with this var are considered "acknowledged" ones, awaiting remedy,
 #: till then, we wish to hide them.
 HIDE_WINDOWS_KNOWN_ERRORS = is_win and os.environ.get('HIDE_WINDOWS_KNOWN_ERRORS', True)
-HIDE_WINDOWS_FREEZE_ERRORS = is_win and os.environ.get('HIDE_WINDOWS_FREEZE_ERRORS', HIDE_WINDOWS_KNOWN_ERRORS)
+HIDE_WINDOWS_FREEZE_ERRORS = is_win and os.environ.get('HIDE_WINDOWS_FREEZE_ERRORS', True)
 
 #{ Utility Methods
 
@@ -70,6 +75,16 @@ def unbare_repo(func):
     return wrapper
 
 
+@contextlib.contextmanager
+def cwd(new_dir):
+    old_dir = os.getcwd()
+    os.chdir(new_dir)
+    try:
+        yield new_dir
+    finally:
+        os.chdir(old_dir)
+
+
 def rmtree(path):
     """Remove the given recursively.
 
@@ -116,7 +131,7 @@ def stream_copy(source, destination, chunk_size=512 * 1024):
 
 
 def join_path(a, *p):
-    """Join path tokens together similar to os.path.join, but always use
+    """Join path tokens together similar to osp.join, but always use
     '/' instead of possibly '\' on windows."""
     path = a
     for b in p:
@@ -162,14 +177,154 @@ def assure_directory_exists(path, is_file=False):
         Otherwise it must be a directory
     :return: True if the directory was created, False if it already existed"""
     if is_file:
-        path = os.path.dirname(path)
+        path = osp.dirname(path)
     # END handle file
-    if not os.path.isdir(path):
+    if not osp.isdir(path):
         os.makedirs(path)
         return True
     return False
 
 
+def _get_exe_extensions():
+    try:
+        winprog_exts = tuple(p.upper() for p in os.environ['PATHEXT'].split(os.pathsep))
+    except:
+        winprog_exts = ('.BAT', 'COM', '.EXE')
+
+    return winprog_exts
+
+
+def py_where(program, path=None):
+    # From: http://stackoverflow.com/a/377028/548792
+    try:
+        winprog_exts = tuple(p.upper() for p in os.environ['PATHEXT'].split(os.pathsep))
+    except:
+        winprog_exts = is_win and ('.BAT', 'COM', '.EXE') or ()
+
+    def is_exec(fpath):
+        return osp.isfile(fpath) and os.access(fpath, os.X_OK) and (
+            os.name != 'nt' or not winprog_exts or any(fpath.upper().endswith(ext)
+                                                       for ext in winprog_exts))
+
+    progs = []
+    if not path:
+        path = os.environ["PATH"]
+    for folder in path.split(os.pathsep):
+        folder = folder.strip('"')
+        if folder:
+            exe_path = osp.join(folder, program)
+            for f in [exe_path] + ['%s%s' % (exe_path, e) for e in winprog_exts]:
+                if is_exec(f):
+                    progs.append(f)
+    return progs
+
+
+def _cygexpath(drive, path):
+    if osp.isabs(path) and not drive:
+        ## Invoked from `cygpath()` directly with `D:Apps\123`?
+        #  It's an error, leave it alone just slashes)
+        p = path
+    else:
+        p = path and osp.normpath(osp.expandvars(osp.expanduser(path)))
+        if osp.isabs(p):
+            if drive:
+                # Confusing, maybe a remote system should expand vars.
+                p = path
+            else:
+                p = cygpath(p)
+        elif drive:
+            p = '/cygdrive/%s/%s' % (drive.lower(), p)
+
+    return p.replace('\\', '/')
+
+
+_cygpath_parsers = (
+    ## See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
+    ## and: https://www.cygwin.com/cygwin-ug-net/using.html#unc-paths
+    (re.compile(r"\\\\\?\\UNC\\([^\\]+)\\([^\\]+)(?:\\(.*))?"),
+     (lambda server, share, rest_path: '//%s/%s/%s' % (server, share, rest_path.replace('\\', '/'))),
+     False
+     ),
+
+    (re.compile(r"\\\\\?\\(\w):[/\\](.*)"),
+     _cygexpath,
+     False
+     ),
+
+    (re.compile(r"(\w):[/\\](.*)"),
+     _cygexpath,
+     False
+     ),
+
+    (re.compile(r"file:(.*)", re.I),
+     (lambda rest_path: rest_path),
+     True),
+
+    (re.compile(r"(\w{2,}:.*)"),  # remote URL, do nothing
+     (lambda url: url),
+     False),
+)
+
+
+def cygpath(path):
+    """Use :meth:`git.cmd.Git.polish_url()` instead, that works on any environment."""
+    if not path.startswith(('/cygdrive', '//')):
+        for regex, parser, recurse in _cygpath_parsers:
+            match = regex.match(path)
+            if match:
+                path = parser(*match.groups())
+                if recurse:
+                    path = cygpath(path)
+                break
+        else:
+            path = _cygexpath(None, path)
+
+    return path
+
+
+_decygpath_regex = re.compile(r"/cygdrive/(\w)(/.*)?")
+
+
+def decygpath(path):
+    m = _decygpath_regex.match(path)
+    if m:
+        drive, rest_path = m.groups()
+        path = '%s:%s' % (drive.upper(), rest_path or '')
+
+    return path.replace('/', '\\')
+
+
+#: Store boolean flags denoting if a specific Git executable
+#: is from a Cygwin installation (since `cache_lru()` unsupported on PY2).
+_is_cygwin_cache = {}
+
+
+def is_cygwin_git(git_executable):
+    if not is_win:
+        return False
+
+    from subprocess import check_output
+
+    is_cygwin = _is_cygwin_cache.get(git_executable)
+    if is_cygwin is None:
+        is_cygwin = False
+        try:
+            git_dir = osp.dirname(git_executable)
+            if not git_dir:
+                res = py_where(git_executable)
+                git_dir = osp.dirname(res[0]) if res else None
+
+            ## Just a name given, not a real path.
+            uname_cmd = osp.join(git_dir, 'uname')
+            uname = check_output(uname_cmd, universal_newlines=True)
+            is_cygwin = 'CYGWIN' in uname
+        except Exception as ex:
+            log.debug('Failed checking if running in CYGWIN due to: %r', ex)
+        _is_cygwin_cache[git_executable] = is_cygwin
+
+    return is_cygwin
+
+
 def get_user_id():
     """:return: string identifying the currently active system user as name@node"""
     return "%s@%s" % (getpass.getuser(), platform.node())
@@ -589,7 +744,7 @@ class LockFile(object):
         if self._has_lock():
             return
         lock_file = self._lock_file_path()
-        if os.path.isfile(lock_file):
+        if osp.isfile(lock_file):
             raise IOError("Lock for file %r did already exist, delete %r in case the lock is illegal" %
                           (self._file_path, lock_file))
 
@@ -659,7 +814,7 @@ class BlockingLockFile(LockFile):
                 # synity check: if the directory leading to the lockfile is not
                 # readable anymore, raise an execption
                 curtime = time.time()
-                if not os.path.isdir(os.path.dirname(self._lock_file_path())):
+                if not osp.isdir(osp.dirname(self._lock_file_path())):
                     msg = "Directory containing the lockfile %r was not readable anymore after waiting %g seconds" % (
                         self._lock_file_path(), curtime - starttime)
                     raise IOError(msg)
diff --git a/requirements.txt b/requirements.txt
index 85d25511..39644606 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,2 @@
 gitdb>=0.6.4
-ddt
-mock
\ No newline at end of file
+ddt>=1.1.1
diff --git a/setup.py b/setup.py
index 737e52a6..cbf5cf57 100755
--- a/setup.py
+++ b/setup.py
@@ -68,7 +68,7 @@ install_requires = ['gitdb2 >= 2.0.0']
 extras_require = {
     ':python_version == "2.6"': ['ordereddict'],
 }
-test_requires = ['ddt']
+test_requires = ['ddt>=1.1.1']
 if sys.version_info[:2] < (2, 7):
     test_requires.append('mock')
 


Test patch:
diff --git a/git/test/lib/helper.py b/git/test/lib/helper.py
index c5a003ea..871cbe93 100644
--- a/git/test/lib/helper.py
+++ b/git/test/lib/helper.py
@@ -5,6 +5,7 @@
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 from __future__ import print_function
 
+import contextlib
 from functools import wraps
 import io
 import logging
@@ -16,7 +17,7 @@ from unittest import TestCase
 import unittest
 
 from git.compat import string_types, is_win, PY3
-from git.util import rmtree
+from git.util import rmtree, cwd
 
 import os.path as osp
 
@@ -32,7 +33,7 @@ __all__ = (
     'GIT_REPO', 'GIT_DAEMON_PORT'
 )
 
-log = logging.getLogger('git.util')
+log = logging.getLogger(__name__)
 
 #{ Routines
 
@@ -118,7 +119,7 @@ def with_rw_repo(working_tree_ref, bare=False):
             if bare:
                 prefix = ''
             # END handle prefix
-            repo_dir = tempfile.mktemp("%sbare_%s" % (prefix, func.__name__))
+            repo_dir = tempfile.mktemp(prefix="%sbare_%s" % (prefix, func.__name__))
             rw_repo = self.rorepo.clone(repo_dir, shared=True, bare=bare, n=True)
 
             rw_repo.head.commit = rw_repo.commit(working_tree_ref)
@@ -151,32 +152,66 @@ def with_rw_repo(working_tree_ref, bare=False):
     return argument_passer
 
 
-def launch_git_daemon(base_path, ip, port):
-    from git import Git
-    if is_win:
-        ## On MINGW-git, daemon exists in .\Git\mingw64\libexec\git-core\,
-        #  but if invoked as 'git daemon', it detaches from parent `git` cmd,
-        #  and then CANNOT DIE!
-        #  So, invoke it as a single command.
-        ## Cygwin-git has no daemon.  But it can use MINGW's.
-        #
-        daemon_cmd = ['git-daemon',
-                      '--enable=receive-pack',
-                      '--listen=%s' % ip,
-                      '--port=%s' % port,
-                      '--base-path=%s' % base_path,
-                      base_path]
-        gd = Git().execute(daemon_cmd, as_process=True)
+@contextlib.contextmanager
+def git_daemon_launched(base_path, ip, port):
+    from git import Git  # Avoid circular deps.
+
+    gd = None
+    try:
+        if is_win:
+            ## On MINGW-git, daemon exists in .\Git\mingw64\libexec\git-core\,
+            #  but if invoked as 'git daemon', it detaches from parent `git` cmd,
+            #  and then CANNOT DIE!
+            #  So, invoke it as a single command.
+            ## Cygwin-git has no daemon.  But it can use MINGW's.
+            #
+            daemon_cmd = ['git-daemon',
+                          '--enable=receive-pack',
+                          '--listen=%s' % ip,
+                          '--port=%s' % port,
+                          '--base-path=%s' % base_path,
+                          base_path]
+            gd = Git().execute(daemon_cmd, as_process=True)
+        else:
+            gd = Git().daemon(base_path,
+                              enable='receive-pack',
+                              listen=ip,
+                              port=port,
+                              base_path=base_path,
+                              as_process=True)
+        # yes, I know ... fortunately, this is always going to work if sleep time is just large enough
+        time.sleep(0.5 * (1 + is_win))
+    except Exception as ex:
+        msg = textwrap.dedent("""
+        Launching git-daemon failed due to: %s
+          Probably test will fail subsequently.
+
+          BUT you may start *git-daemon* manually with this command:"
+                git daemon --enable=receive-pack  --listen=%s --port=%s --base-path=%s  %s
+          You may also run the daemon on a different port by passing --port=<port>"
+          and setting the environment variable GIT_PYTHON_TEST_GIT_DAEMON_PORT to <port>
+        """)
+        if is_win:
+            msg += textwrap.dedent("""
+
+            On Windows,
+              the `git-daemon.exe` must be in PATH.
+              For MINGW, look into .\Git\mingw64\libexec\git-core\), but problems with paths might appear.
+              CYGWIN has no daemon, but if one exists, it gets along fine (but has also paths problems).""")
+        log.warning(msg, ex, ip, port, base_path, base_path, exc_info=1)
+
+        yield  # OK, assume daemon started manually.
+
     else:
-        gd = Git().daemon(base_path,
-                          enable='receive-pack',
-                          listen=ip,
-                          port=port,
-                          base_path=base_path,
-                          as_process=True)
-    # yes, I know ... fortunately, this is always going to work if sleep time is just large enough
-    time.sleep(0.5)
-    return gd
+        yield  # Yield outside try, to avoid catching
+    finally:
+        if gd:
+            try:
+                log.debug("Killing git-daemon...")
+                gd.proc.kill()
+            except Exception as ex:
+                ## Either it has died (and we're here), or it won't die, again here...
+                log.debug("Hidden error while Killing git-daemon: %s", ex, exc_info=1)
 
 
 def with_rw_and_rw_remote_repo(working_tree_ref):
@@ -193,10 +228,10 @@ def with_rw_and_rw_remote_repo(working_tree_ref):
     directories in it.
 
     The following scetch demonstrates this::
-     rorepo ---<bare clone>---> rw_remote_repo ---<clone>---> rw_repo
+     rorepo ---<bare clone>---> rw_daemon_repo ---<clone>---> rw_repo
 
     The test case needs to support the following signature::
-        def case(self, rw_repo, rw_remote_repo)
+        def case(self, rw_repo, rw_daemon_repo)
 
     This setup allows you to test push and pull scenarios and hooks nicely.
 
@@ -211,94 +246,65 @@ def with_rw_and_rw_remote_repo(working_tree_ref):
 
         @wraps(func)
         def remote_repo_creator(self):
-            remote_repo_dir = tempfile.mktemp("remote_repo_%s" % func.__name__)
-            repo_dir = tempfile.mktemp("remote_clone_non_bare_repo")
+            rw_daemon_repo_dir = tempfile.mktemp(prefix="daemon_repo-%s-" % func.__name__)
+            rw_repo_dir = tempfile.mktemp(prefix="daemon_cloned_repo-%s-" % func.__name__)
 
-            rw_remote_repo = self.rorepo.clone(remote_repo_dir, shared=True, bare=True)
+            rw_daemon_repo = self.rorepo.clone(rw_daemon_repo_dir, shared=True, bare=True)
             # recursive alternates info ?
-            rw_repo = rw_remote_repo.clone(repo_dir, shared=True, bare=False, n=True)
-            rw_repo.head.commit = working_tree_ref
-            rw_repo.head.reference.checkout()
-
-            # prepare for git-daemon
-            rw_remote_repo.daemon_export = True
-
-            # this thing is just annoying !
-            with rw_remote_repo.config_writer() as crw:
-                section = "daemon"
-                try:
-                    crw.add_section(section)
-                except Exception:
-                    pass
-                crw.set(section, "receivepack", True)
-
-            # Initialize the remote - first do it as local remote and pull, then
-            # we change the url to point to the daemon.
-            d_remote = Remote.create(rw_repo, "daemon_origin", remote_repo_dir)
-            d_remote.fetch()
-
-            base_path, rel_repo_dir = osp.split(remote_repo_dir)
-
-            remote_repo_url = Git.polish_url("git://localhost:%s/%s" % (GIT_DAEMON_PORT, rel_repo_dir))
-            with d_remote.config_writer as cw:
-                cw.set('url', remote_repo_url)
-
+            rw_repo = rw_daemon_repo.clone(rw_repo_dir, shared=True, bare=False, n=True)
             try:
-                gd = launch_git_daemon(Git.polish_url(base_path), '127.0.0.1', GIT_DAEMON_PORT)
-            except Exception as ex:
-                if is_win:
-                    msg = textwrap.dedent("""
-                    The `git-daemon.exe` must be in PATH.
-                    For MINGW, look into .\Git\mingw64\libexec\git-core\), but problems with paths might appear.
-                    CYGWIN has no daemon, but if one exists, it gets along fine (has also paths problems)
-                    Anyhow, alternatively try starting `git-daemon` manually:""")
-                else:
-                    msg = "Please try starting `git-daemon` manually:"
-                msg += textwrap.dedent("""
-                    git daemon --enable=receive-pack  --base-path=%s  %s
-                You can also run the daemon on a different port by passing --port=<port>"
-                and setting the environment variable GIT_PYTHON_TEST_GIT_DAEMON_PORT to <port>
-                """ % (base_path, base_path))
-                raise AssertionError(ex, msg)
-                # END make assertion
-            else:
-                # Try listing remotes, to diagnose whether the daemon is up.
-                rw_repo.git.ls_remote(d_remote)
-
-                # adjust working dir
-                prev_cwd = os.getcwd()
-                os.chdir(rw_repo.working_dir)
+                rw_repo.head.commit = working_tree_ref
+                rw_repo.head.reference.checkout()
 
-                try:
-                    return func(self, rw_repo, rw_remote_repo)
-                except:
-                    log.info("Keeping repos after failure: repo_dir = %s, remote_repo_dir = %s",
-                             repo_dir, remote_repo_dir)
-                    repo_dir = remote_repo_dir = None
-                    raise
-                finally:
-                    os.chdir(prev_cwd)
+                # prepare for git-daemon
+                rw_daemon_repo.daemon_export = True
+
+                # this thing is just annoying !
+                with rw_daemon_repo.config_writer() as crw:
+                    section = "daemon"
+                    try:
+                        crw.add_section(section)
+                    except Exception:
+                        pass
+                    crw.set(section, "receivepack", True)
+
+                # Initialize the remote - first do it as local remote and pull, then
+                # we change the url to point to the daemon.
+                d_remote = Remote.create(rw_repo, "daemon_origin", rw_daemon_repo_dir)
+                d_remote.fetch()
+
+                base_daemon_path, rel_repo_dir = osp.split(rw_daemon_repo_dir)
+
+                remote_repo_url = Git.polish_url("git://localhost:%s/%s" % (GIT_DAEMON_PORT, rel_repo_dir))
+                with d_remote.config_writer as cw:
+                    cw.set('url', remote_repo_url)
+
+                with git_daemon_launched(Git.polish_url(base_daemon_path, is_cygwin=False),  # No daemon in Cygwin.
+                                         '127.0.0.1',
+                                         GIT_DAEMON_PORT):
+                    # Try listing remotes, to diagnose whether the daemon is up.
+                    rw_repo.git.ls_remote(d_remote)
+
+                    with cwd(rw_repo.working_dir):
+                        try:
+                            return func(self, rw_repo, rw_daemon_repo)
+                        except:
+                            log.info("Keeping repos after failure: \n  rw_repo_dir: %s \n  rw_daemon_repo_dir: %s",
+                                     rw_repo_dir, rw_daemon_repo_dir)
+                            rw_repo_dir = rw_daemon_repo_dir = None
+                            raise
 
             finally:
-                try:
-                    log.debug("Killing git-daemon...")
-                    gd.proc.kill()
-                except:
-                    ## Either it has died (and we're here), or it won't die, again here...
-                    pass
-
                 rw_repo.git.clear_cache()
-                rw_remote_repo.git.clear_cache()
-                rw_repo = rw_remote_repo = None
+                rw_daemon_repo.git.clear_cache()
+                del rw_repo
+                del rw_daemon_repo
                 import gc
                 gc.collect()
-                if repo_dir:
-                    rmtree(repo_dir)
-                if remote_repo_dir:
-                    rmtree(remote_repo_dir)
-
-                if gd is not None:
-                    gd.proc.wait()
+                if rw_repo_dir:
+                    rmtree(rw_repo_dir)
+                if rw_daemon_repo_dir:
+                    rmtree(rw_daemon_repo_dir)
             # END cleanup
         # END bare repo creator
         return remote_repo_creator
diff --git a/git/test/performance/lib.py b/git/test/performance/lib.py
index b57b9b71..700fee98 100644
--- a/git/test/performance/lib.py
+++ b/git/test/performance/lib.py
@@ -1,21 +1,23 @@
 """Contains library functions"""
+import logging
 import os
-from git.test.lib import (
-    TestBase
-)
 import tempfile
-import logging
 
+from git import (
+    Repo
+)
 from git.db import (
     GitCmdObjectDB,
     GitDB
 )
-
-from git import (
-    Repo
+from git.test.lib import (
+    TestBase
 )
 from git.util import rmtree
 
+import os.path as osp
+
+
 #{ Invvariants
 k_env_git_repo = "GIT_PYTHON_TEST_GIT_REPO_BASE"
 
@@ -52,7 +54,7 @@ class TestBigRepoR(TestBase):
             logging.info(
                 ("You can set the %s environment variable to a .git repository of" % k_env_git_repo) +
                 "your choice - defaulting to the gitpython repository")
-            repo_path = os.path.dirname(__file__)
+            repo_path = osp.dirname(__file__)
         # end set some repo path
         self.gitrorepo = Repo(repo_path, odbt=GitCmdObjectDB, search_parent_directories=True)
         self.puregitrorepo = Repo(repo_path, odbt=GitDB, search_parent_directories=True)
diff --git a/git/test/performance/test_streams.py b/git/test/performance/test_streams.py
index 42cbade5..3909d8ff 100644
--- a/git/test/performance/test_streams.py
+++ b/git/test/performance/test_streams.py
@@ -1,26 +1,27 @@
 """Performance data streaming performance"""
 from __future__ import print_function
 
-from time import time
 import os
-import sys
 import subprocess
+import sys
+from time import time
 
 from git.test.lib import (
     with_rw_repo
 )
-from gitdb.util import bin_to_hex
+from git.util import bin_to_hex
+from gitdb import (
+    LooseObjectDB,
+    IStream
+)
 from gitdb.test.lib import make_memory_file
 
+import os.path as osp
+
 from .lib import (
     TestBigRepoR
 )
 
-from gitdb import (
-    LooseObjectDB,
-    IStream
-)
-
 
 class TestObjDBPerformance(TestBigRepoR):
 
@@ -31,7 +32,7 @@ class TestObjDBPerformance(TestBigRepoR):
     def test_large_data_streaming(self, rwrepo):
         # TODO: This part overlaps with the same file in gitdb.test.performance.test_stream
         # It should be shared if possible
-        ldb = LooseObjectDB(os.path.join(rwrepo.git_dir, 'objects'))
+        ldb = LooseObjectDB(osp.join(rwrepo.git_dir, 'objects'))
 
         for randomize in range(2):
             desc = (randomize and 'random ') or ''
@@ -47,7 +48,7 @@ class TestObjDBPerformance(TestBigRepoR):
             elapsed_add = time() - st
             assert ldb.has_object(binsha)
             db_file = ldb.readable_db_object_path(bin_to_hex(binsha))
-            fsize_kib = os.path.getsize(db_file) / 1000
+            fsize_kib = osp.getsize(db_file) / 1000
 
             size_kib = size / 1000
             msg = "Added %i KiB (filesize = %i KiB) of %s data to loose odb in %f s ( %f Write KiB / s)"
@@ -109,7 +110,7 @@ class TestObjDBPerformance(TestBigRepoR):
             assert gitsha == bin_to_hex(binsha)     # we do it the same way, right ?
 
             #  as its the same sha, we reuse our path
-            fsize_kib = os.path.getsize(db_file) / 1000
+            fsize_kib = osp.getsize(db_file) / 1000
             msg = "Added %i KiB (filesize = %i KiB) of %s data to using git-hash-object in %f s ( %f Write KiB / s)"
             msg %= (size_kib, fsize_kib, desc, gelapsed_add, size_kib / gelapsed_add)
             print(msg, file=sys.stderr)
diff --git a/git/test/test_base.py b/git/test/test_base.py
index 7fc3096f..cec40de8 100644
--- a/git/test/test_base.py
+++ b/git/test/test_base.py
@@ -9,22 +9,24 @@ import sys
 import tempfile
 from unittest import skipIf
 
-import git.objects.base as base
-from git.test.lib import (
-    TestBase,
-    assert_raises,
-    with_rw_repo,
-    with_rw_and_rw_remote_repo
-)
 from git import (
     Blob,
     Tree,
     Commit,
     TagObject
 )
-from git.objects.util import get_object_type_by_name
-from gitdb.util import hex_to_bin
 from git.compat import is_win
+from git.objects.util import get_object_type_by_name
+from git.test.lib import (
+    TestBase,
+    assert_raises,
+    with_rw_repo,
+    with_rw_and_rw_remote_repo
+)
+from git.util import hex_to_bin
+
+import git.objects.base as base
+import os.path as osp
 
 
 class TestBase(TestBase):
@@ -103,19 +105,19 @@ class TestBase(TestBase):
     @with_rw_repo('HEAD', bare=True)
     def test_with_bare_rw_repo(self, bare_rw_repo):
         assert bare_rw_repo.config_reader("repository").getboolean("core", "bare")
-        assert os.path.isfile(os.path.join(bare_rw_repo.git_dir, 'HEAD'))
+        assert osp.isfile(osp.join(bare_rw_repo.git_dir, 'HEAD'))
 
     @with_rw_repo('0.1.6')
     def test_with_rw_repo(self, rw_repo):
         assert not rw_repo.config_reader("repository").getboolean("core", "bare")
-        assert os.path.isdir(os.path.join(rw_repo.working_tree_dir, 'lib'))
+        assert osp.isdir(osp.join(rw_repo.working_tree_dir, 'lib'))
 
     #@skipIf(HIDE_WINDOWS_FREEZE_ERRORS, "FIXME: Freezes!  sometimes...")
     @with_rw_and_rw_remote_repo('0.1.6')
     def test_with_rw_remote_and_rw_repo(self, rw_repo, rw_remote_repo):
         assert not rw_repo.config_reader("repository").getboolean("core", "bare")
         assert rw_remote_repo.config_reader("repository").getboolean("core", "bare")
-        assert os.path.isdir(os.path.join(rw_repo.working_tree_dir, 'lib'))
+        assert osp.isdir(osp.join(rw_repo.working_tree_dir, 'lib'))
 
     @skipIf(sys.version_info < (3,) and is_win,
             "Unicode woes, see https://github.com/gitpython-developers/GitPython/pull/519")
@@ -123,7 +125,7 @@ class TestBase(TestBase):
     def test_add_unicode(self, rw_repo):
         filename = u"שלום.txt"
 
-        file_path = os.path.join(rw_repo.working_dir, filename)
+        file_path = osp.join(rw_repo.working_dir, filename)
 
         # verify first that we could encode file name in this environment
         try:
diff --git a/git/test/test_commit.py b/git/test/test_commit.py
index fd9777fb..fbb1c244 100644
--- a/git/test/test_commit.py
+++ b/git/test/test_commit.py
@@ -6,34 +6,36 @@
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 from __future__ import print_function
 
-from git.test.lib import (
-    TestBase,
-    assert_equal,
-    assert_not_equal,
-    with_rw_repo,
-    fixture_path,
-    StringProcessAdapter
-)
+from datetime import datetime
+from io import BytesIO
+import re
+import sys
+import time
+
 from git import (
     Commit,
     Actor,
 )
-from gitdb import IStream
-from git.test.lib import with_rw_directory
+from git import Repo
 from git.compat import (
     string_types,
     text_type
 )
-from git import Repo
+from git.objects.util import tzoffset, utc
 from git.repo.fun import touch
+from git.test.lib import (
+    TestBase,
+    assert_equal,
+    assert_not_equal,
+    with_rw_repo,
+    fixture_path,
+    StringProcessAdapter
+)
+from git.test.lib import with_rw_directory
+from gitdb import IStream
+
+import os.path as osp
 
-from io import BytesIO
-import time
-import sys
-import re
-import os
-from datetime import datetime
-from git.objects.util import tzoffset, utc
 
 try:
     from unittest.mock import Mock
@@ -232,8 +234,8 @@ class TestCommit(TestBase):
 
     @with_rw_directory
     def test_ambiguous_arg_iteration(self, rw_dir):
-        rw_repo = Repo.init(os.path.join(rw_dir, 'test_ambiguous_arg'))
-        path = os.path.join(rw_repo.working_tree_dir, 'master')
+        rw_repo = Repo.init(osp.join(rw_dir, 'test_ambiguous_arg'))
+        path = osp.join(rw_repo.working_tree_dir, 'master')
         touch(path)
         rw_repo.index.add([path])
         rw_repo.index.commit('initial commit')
diff --git a/git/test/test_config.py b/git/test/test_config.py
index 32873f24..0dfadda6 100644
--- a/git/test/test_config.py
+++ b/git/test/test_config.py
@@ -6,7 +6,6 @@
 
 import glob
 import io
-import os
 
 from git import (
     GitConfigParser
@@ -91,7 +90,7 @@ class TestBase(TestCase):
 
     @with_rw_directory
     def test_lock_reentry(self, rw_dir):
-        fpl = os.path.join(rw_dir, 'l')
+        fpl = osp.join(rw_dir, 'l')
         gcp = GitConfigParser(fpl, read_only=False)
         with gcp as cw:
             cw.set_value('include', 'some_value', 'a')
@@ -103,7 +102,7 @@ class TestBase(TestCase):
                 GitConfigParser(fpl, read_only=False)
         # but work when the lock is removed
         with GitConfigParser(fpl, read_only=False):
-            assert os.path.exists(fpl)
+            assert osp.exists(fpl)
             # reentering with an existing lock must fail due to exclusive access
             with self.assertRaises(IOError):
                 gcp.__enter__()
@@ -178,17 +177,17 @@ class TestBase(TestCase):
         # end
 
         # PREPARE CONFIG FILE A
-        fpa = os.path.join(rw_dir, 'a')
+        fpa = osp.join(rw_dir, 'a')
         with GitConfigParser(fpa, read_only=False) as cw:
             write_test_value(cw, 'a')
 
-            fpb = os.path.join(rw_dir, 'b')
-            fpc = os.path.join(rw_dir, 'c')
+            fpb = osp.join(rw_dir, 'b')
+            fpc = osp.join(rw_dir, 'c')
             cw.set_value('include', 'relative_path_b', 'b')
             cw.set_value('include', 'doesntexist', 'foobar')
             cw.set_value('include', 'relative_cycle_a_a', 'a')
             cw.set_value('include', 'absolute_cycle_a_a', fpa)
-        assert os.path.exists(fpa)
+        assert osp.exists(fpa)
 
         # PREPARE CONFIG FILE B
         with GitConfigParser(fpb, read_only=False) as cw:
diff --git a/git/test/test_db.py b/git/test/test_db.py
index 5dcf592a..8f67dd48 100644
--- a/git/test/test_db.py
+++ b/git/test/test_db.py
@@ -3,17 +3,18 @@
 #
 # This module is part of GitPython and is released under
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
-from git.test.lib import TestBase
 from git.db import GitCmdObjectDB
-from gitdb.util import bin_to_hex
 from git.exc import BadObject
-import os
+from git.test.lib import TestBase
+from git.util import bin_to_hex
+
+import os.path as osp
 
 
 class TestDB(TestBase):
 
     def test_base(self):
-        gdb = GitCmdObjectDB(os.path.join(self.rorepo.git_dir, 'objects'), self.rorepo.git)
+        gdb = GitCmdObjectDB(osp.join(self.rorepo.git_dir, 'objects'), self.rorepo.git)
 
         # partial to complete - works with everything
         hexsha = bin_to_hex(gdb.partial_to_complete_sha_hex("0.1.6"))
diff --git a/git/test/test_diff.py b/git/test/test_diff.py
index d34d84e3..48a5a641 100644
--- a/git/test/test_diff.py
+++ b/git/test/test_diff.py
@@ -4,8 +4,15 @@
 #
 # This module is part of GitPython and is released under
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
-import os
-
+import ddt
+from git import (
+    Repo,
+    GitCommandError,
+    Diff,
+    DiffIndex,
+    NULL_TREE,
+)
+from git.cmd import Git
 from git.test.lib import (
     TestBase,
     StringProcessAdapter,
@@ -14,17 +21,9 @@ from git.test.lib import (
     assert_true,
 
 )
-
 from git.test.lib import with_rw_directory
 
-from git import (
-    Repo,
-    GitCommandError,
-    Diff,
-    DiffIndex,
-    NULL_TREE,
-)
-import ddt
+import os.path as osp
 
 
 @ddt.ddt
@@ -53,10 +52,10 @@ class TestDiff(TestBase):
     def test_diff_with_staged_file(self, rw_dir):
         # SETUP INDEX WITH MULTIPLE STAGES
         r = Repo.init(rw_dir)
-        fp = os.path.join(rw_dir, 'hello.txt')
+        fp = osp.join(rw_dir, 'hello.txt')
         with open(fp, 'w') as fs:
             fs.write("hello world")
-        r.git.add(fp)
+        r.git.add(Git.polish_url(fp))
         r.git.commit(message="init")
 
         with open(fp, 'w') as fs:
diff --git a/git/test/test_docs.py b/git/test/test_docs.py
index f3c75f79..bb937d93 100644
--- a/git/test/test_docs.py
+++ b/git/test/test_docs.py
@@ -9,6 +9,8 @@ import os
 from git.test.lib import TestBase
 from git.test.lib.helper import with_rw_directory
 
+import os.path as osp
+
 
 class Tutorials(TestBase):
 
@@ -23,7 +25,7 @@ class Tutorials(TestBase):
     def test_init_repo_object(self, rw_dir):
         # [1-test_init_repo_object]
         from git import Repo
-        join = os.path.join
+        join = osp.join
 
         # rorepo is a Repo instance pointing to the git-python repository.
         # For all you know, the first argument to Repo is a path to the repository
@@ -62,7 +64,7 @@ class Tutorials(TestBase):
 
         # repository paths
         # [7-test_init_repo_object]
-        assert os.path.isdir(cloned_repo.working_tree_dir)                   # directory with your work files
+        assert osp.isdir(cloned_repo.working_tree_dir)                   # directory with your work files
         assert cloned_repo.git_dir.startswith(cloned_repo.working_tree_dir)  # directory containing the git repository
         assert bare_repo.working_tree_dir is None                            # bare repositories have no working tree
         # ![7-test_init_repo_object]
@@ -146,7 +148,7 @@ class Tutorials(TestBase):
         self.assertEqual(new_branch.checkout(), cloned_repo.active_branch)     # checking out branch adjusts the wtree
         self.assertEqual(new_branch.commit, past.commit)                       # Now the past is checked out
 
-        new_file_path = os.path.join(cloned_repo.working_tree_dir, 'my-new-file')
+        new_file_path = osp.join(cloned_repo.working_tree_dir, 'my-new-file')
         open(new_file_path, 'wb').close()                             # create new file in working tree
         cloned_repo.index.add([new_file_path])                        # add it to the index
         # Commit the changes to deviate masters history
@@ -162,7 +164,7 @@ class Tutorials(TestBase):
         # now new_branch is ahead of master, which probably should be checked out and reset softly.
         # note that all these operations didn't touch the working tree, as we managed it ourselves.
         # This definitely requires you to know what you are doing :) !
-        assert os.path.basename(new_file_path) in new_branch.commit.tree  # new file is now in tree
+        assert osp.basename(new_file_path) in new_branch.commit.tree  # new file is now in tree
         master.commit = new_branch.commit            # let master point to most recent commit
         cloned_repo.head.reference = master          # we adjusted just the reference, not the working tree or index
         # ![13-test_init_repo_object]
@@ -192,7 +194,7 @@ class Tutorials(TestBase):
     def test_references_and_objects(self, rw_dir):
         # [1-test_references_and_objects]
         import git
-        repo = git.Repo.clone_from(self._small_repo_url(), os.path.join(rw_dir, 'repo'), branch='master')
+        repo = git.Repo.clone_from(self._small_repo_url(), osp.join(rw_dir, 'repo'), branch='master')
 
         heads = repo.heads
         master = heads.master       # lists can be accessed by name for convenience
@@ -264,7 +266,7 @@ class Tutorials(TestBase):
 
         # [11-test_references_and_objects]
         hct.blobs[0].data_stream.read()        # stream object to read data from
-        hct.blobs[0].stream_data(open(os.path.join(rw_dir, 'blob_data'), 'wb'))  # write data to given stream
+        hct.blobs[0].stream_data(open(osp.join(rw_dir, 'blob_data'), 'wb'))  # write data to given stream
         # ![11-test_references_and_objects]
 
         # [12-test_references_and_objects]
@@ -350,11 +352,11 @@ class Tutorials(TestBase):
         # Access blob objects
         for (path, stage), entry in index.entries.items():  # @UnusedVariable
             pass
-        new_file_path = os.path.join(repo.working_tree_dir, 'new-file-name')
+        new_file_path = osp.join(repo.working_tree_dir, 'new-file-name')
         open(new_file_path, 'w').close()
         index.add([new_file_path])                                             # add a new file to the index
         index.remove(['LICENSE'])                                              # remove an existing one
-        assert os.path.isfile(os.path.join(repo.working_tree_dir, 'LICENSE'))  # working tree is untouched
+        assert osp.isfile(osp.join(repo.working_tree_dir, 'LICENSE'))  # working tree is untouched
 
         self.assertEqual(index.commit("my commit message").type, 'commit')              # commit changed index
         repo.active_branch.commit = repo.commit('HEAD~1')                      # forget last commit
@@ -373,11 +375,11 @@ class Tutorials(TestBase):
         # merge two trees three-way into memory
         merge_index = IndexFile.from_tree(repo, 'HEAD~10', 'HEAD', repo.merge_base('HEAD~10', 'HEAD'))
         # and persist it
-        merge_index.write(os.path.join(rw_dir, 'merged_index'))
+        merge_index.write(osp.join(rw_dir, 'merged_index'))
         # ![24-test_references_and_objects]
 
         # [25-test_references_and_objects]
-        empty_repo = git.Repo.init(os.path.join(rw_dir, 'empty'))
+        empty_repo = git.Repo.init(osp.join(rw_dir, 'empty'))
         origin = empty_repo.create_remote('origin', repo.remotes.origin.url)
         assert origin.exists()
         assert origin == empty_repo.remotes.origin == empty_repo.remotes['origin']
@@ -480,8 +482,8 @@ class Tutorials(TestBase):
     def test_add_file_and_commit(self, rw_dir):
         import git
 
-        repo_dir = os.path.join(rw_dir, 'my-new-repo')
-        file_name = os.path.join(repo_dir, 'new-file')
+        repo_dir = osp.join(rw_dir, 'my-new-repo')
+        file_name = osp.join(repo_dir, 'new-file')
 
         r = git.Repo.init(repo_dir)
         # This function just creates an empty file ...
diff --git a/git/test/test_fun.py b/git/test/test_fun.py
index 02f338dd..9d436653 100644
--- a/git/test/test_fun.py
+++ b/git/test/test_fun.py
@@ -1,6 +1,11 @@
-from git.test.lib import (
-    TestBase,
-    with_rw_repo
+from io import BytesIO
+from stat import S_IFDIR, S_IFREG, S_IFLNK
+from unittest.case import skipIf
+
+from git.compat import PY3
+from git.index import IndexFile
+from git.index.fun import (
+    aggressive_tree_merge
 )
 from git.objects.fun import (
     traverse_tree_recursive,
@@ -8,25 +13,13 @@ from git.objects.fun import (
     tree_to_stream,
     tree_entries_from_data
 )
-
-from git.index.fun import (
-    aggressive_tree_merge
+from git.test.lib import (
+    TestBase,
+    with_rw_repo
 )
-
-from gitdb.util import bin_to_hex
+from git.util import bin_to_hex
 from gitdb.base import IStream
 from gitdb.typ import str_tree_type
-from git.compat import PY3
-
-from unittest.case import skipIf
-from stat import (
-    S_IFDIR,
-    S_IFREG,
-    S_IFLNK
-)
-
-from git.index import IndexFile
-from io import BytesIO
 
 
 class TestFun(TestBase):
@@ -262,7 +255,7 @@ class TestFun(TestBase):
     def test_tree_entries_from_data_with_failing_name_decode_py2(self):
         r = tree_entries_from_data(b'100644 \x9f\0aaa')
         assert r == [('aaa', 33188, u'\udc9f')], r
-        
+
     @skipIf(not PY3, 'odd types returned ... maybe figure it out one day')
     def test_tree_entries_from_data_with_failing_name_decode_py3(self):
         r = tree_entries_from_data(b'100644 \x9f\0aaa')
diff --git a/git/test/test_git.py b/git/test/test_git.py
index bd8ebee2..7d713022 100644
--- a/git/test/test_git.py
+++ b/git/test/test_git.py
@@ -5,9 +5,17 @@
 # This module is part of GitPython and is released under
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 import os
-import sys
 import subprocess
+import sys
 
+from git import (
+    Git,
+    GitCommandError,
+    GitCommandNotFound,
+    Repo,
+    cmd
+)
+from git.compat import PY3, is_darwin
 from git.test.lib import (
     TestBase,
     patch,
@@ -17,18 +25,12 @@ from git.test.lib import (
     assert_match,
     fixture_path
 )
-from git import (
-    Git,
-    GitCommandError,
-    GitCommandNotFound,
-    Repo,
-    cmd
-)
 from git.test.lib import with_rw_directory
-
-from git.compat import PY3, is_darwin
 from git.util import finalize_process
 
+import os.path as osp
+
+
 try:
     from unittest import mock
 except ImportError:
@@ -147,7 +149,7 @@ class TestGit(TestBase):
         exc = GitCommandNotFound
         try:
             # set it to something that doens't exist, assure it raises
-            type(self.git).GIT_PYTHON_GIT_EXECUTABLE = os.path.join(
+            type(self.git).GIT_PYTHON_GIT_EXECUTABLE = osp.join(
                 "some", "path", "which", "doesn't", "exist", "gitbinary")
             self.failUnlessRaises(exc, self.git.version)
         finally:
@@ -198,13 +200,13 @@ class TestGit(TestBase):
         self.assertEqual(new_env, {'VARKEY': 'VARVALUE'})
         self.assertEqual(self.git.environment(), {})
 
-        path = os.path.join(rw_dir, 'failing-script.sh')
+        path = osp.join(rw_dir, 'failing-script.sh')
         with open(path, 'wt') as stream:
             stream.write("#!/usr/bin/env sh\n"
                          "echo FOO\n")
         os.chmod(path, 0o777)
 
-        rw_repo = Repo.init(os.path.join(rw_dir, 'repo'))
+        rw_repo = Repo.init(osp.join(rw_dir, 'repo'))
         remote = rw_repo.create_remote('ssh-origin', "ssh://git@server/foo")
 
         with rw_repo.git.custom_environment(GIT_SSH=path):
diff --git a/git/test/test_index.py b/git/test/test_index.py
index d851743e..1abe22f4 100644
--- a/git/test/test_index.py
+++ b/git/test/test_index.py
@@ -26,7 +26,7 @@ from git import (
     GitCommandError,
     CheckoutError,
 )
-from git.compat import string_types, is_win
+from git.compat import string_types, is_win, PY3
 from git.exc import (
     HookExecutionError,
     InvalidGitRepositoryError
@@ -43,11 +43,13 @@ from git.test.lib import (
     fixture,
     with_rw_repo
 )
-from git.util import HIDE_WINDOWS_KNOWN_ERRORS
 from git.test.lib import with_rw_directory
 from git.util import Actor, rmtree
+from git.util import HIDE_WINDOWS_KNOWN_ERRORS, hex_to_bin
 from gitdb.base import IStream
-from gitdb.util import hex_to_bin
+
+import os.path as osp
+from git.cmd import Git
 
 
 class TestIndex(TestBase):
@@ -85,7 +87,7 @@ class TestIndex(TestBase):
     def _assert_entries(self, entries):
         for entry in entries:
             assert isinstance(entry, BaseIndexEntry)
-            assert not os.path.isabs(entry.path)
+            assert not osp.isabs(entry.path)
             assert "\\" not in entry.path
         # END for each entry
 
@@ -329,7 +331,7 @@ class TestIndex(TestBase):
 
         # reset the working copy as well to current head,to pull 'back' as well
         new_data = b"will be reverted"
-        file_path = os.path.join(rw_repo.working_tree_dir, "CHANGES")
+        file_path = osp.join(rw_repo.working_tree_dir, "CHANGES")
         with open(file_path, "wb") as fp:
             fp.write(new_data)
         index.reset(rev_head_parent, working_tree=True)
@@ -340,26 +342,26 @@ class TestIndex(TestBase):
             assert fp.read() != new_data
 
         # test full checkout
-        test_file = os.path.join(rw_repo.working_tree_dir, "CHANGES")
+        test_file = osp.join(rw_repo.working_tree_dir, "CHANGES")
         with open(test_file, 'ab') as fd:
             fd.write(b"some data")
         rval = index.checkout(None, force=True, fprogress=self._fprogress)
         assert 'CHANGES' in list(rval)
         self._assert_fprogress([None])
-        assert os.path.isfile(test_file)
+        assert osp.isfile(test_file)
 
         os.remove(test_file)
         rval = index.checkout(None, force=False, fprogress=self._fprogress)
         assert 'CHANGES' in list(rval)
         self._assert_fprogress([None])
-        assert os.path.isfile(test_file)
+        assert osp.isfile(test_file)
 
         # individual file
         os.remove(test_file)
         rval = index.checkout(test_file, fprogress=self._fprogress)
         self.assertEqual(list(rval)[0], 'CHANGES')
         self._assert_fprogress([test_file])
-        assert os.path.exists(test_file)
+        assert osp.exists(test_file)
 
         # checking out non-existing file throws
         self.failUnlessRaises(CheckoutError, index.checkout, "doesnt_exist_ever.txt.that")
@@ -373,7 +375,7 @@ class TestIndex(TestBase):
             index.checkout(test_file)
         except CheckoutError as e:
             self.assertEqual(len(e.failed_files), 1)
-            self.assertEqual(e.failed_files[0], os.path.basename(test_file))
+            self.assertEqual(e.failed_files[0], osp.basename(test_file))
             self.assertEqual(len(e.failed_files), len(e.failed_reasons))
             self.assertIsInstance(e.failed_reasons[0], string_types)
             self.assertEqual(len(e.valid_files), 0)
@@ -388,7 +390,7 @@ class TestIndex(TestBase):
         assert not open(test_file, 'rb').read().endswith(append_data)
 
         # checkout directory
-        rmtree(os.path.join(rw_repo.working_tree_dir, "lib"))
+        rmtree(osp.join(rw_repo.working_tree_dir, "lib"))
         rval = index.checkout('lib')
         assert len(list(rval)) > 1
 
@@ -399,11 +401,17 @@ class TestIndex(TestBase):
         existing = 0
         basedir = repo.working_tree_dir
         for f in files:
-            existing += os.path.isfile(os.path.join(basedir, f))
+            existing += osp.isfile(osp.join(basedir, f))
         # END for each deleted file
         return existing
     # END num existing helper
 
+    @skipIf(HIDE_WINDOWS_KNOWN_ERRORS and Git.is_cygwin(),
+            """FIXME: File "C:\projects\gitpython\git\test\test_index.py", line 642, in test_index_mutation
+                self.assertEqual(fd.read(), link_target)
+                AssertionError: '!<symlink>\xff\xfe/\x00e\x00t\x00c\x00/\x00t\x00h\x00a\x00t\x00\x00\x00'
+                != '/etc/that'
+                """)
     @with_rw_repo('0.1.6')
     def test_index_mutation(self, rw_repo):
         index = rw_repo.index
@@ -458,7 +466,7 @@ class TestIndex(TestBase):
         self.failUnlessRaises(TypeError, index.remove, [1])
 
         # absolute path
-        deleted_files = index.remove([os.path.join(rw_repo.working_tree_dir, "lib")], r=True)
+        deleted_files = index.remove([osp.join(rw_repo.working_tree_dir, "lib")], r=True)
         assert len(deleted_files) > 1
         self.failUnlessRaises(ValueError, index.remove, ["/doesnt/exists"])
 
@@ -525,9 +533,9 @@ class TestIndex(TestBase):
         # re-add all files in lib
         # get the lib folder back on disk, but get an index without it
         index.reset(new_commit.parents[0], working_tree=True).reset(new_commit, working_tree=False)
-        lib_file_path = os.path.join("lib", "git", "__init__.py")
+        lib_file_path = osp.join("lib", "git", "__init__.py")
         assert (lib_file_path, 0) not in index.entries
-        assert os.path.isfile(os.path.join(rw_repo.working_tree_dir, lib_file_path))
+        assert osp.isfile(osp.join(rw_repo.working_tree_dir, lib_file_path))
 
         # directory
         entries = index.add(['lib'], fprogress=self._fprogress_add)
@@ -536,14 +544,14 @@ class TestIndex(TestBase):
         assert len(entries) > 1
 
         # glob
-        entries = index.reset(new_commit).add([os.path.join('lib', 'git', '*.py')], fprogress=self._fprogress_add)
+        entries = index.reset(new_commit).add([osp.join('lib', 'git', '*.py')], fprogress=self._fprogress_add)
         self._assert_entries(entries)
         self._assert_fprogress(entries)
         self.assertEqual(len(entries), 14)
 
         # same file
         entries = index.reset(new_commit).add(
-            [os.path.join(rw_repo.working_tree_dir, 'lib', 'git', 'head.py')] * 2, fprogress=self._fprogress_add)
+            [osp.join(rw_repo.working_tree_dir, 'lib', 'git', 'head.py')] * 2, fprogress=self._fprogress_add)
         self._assert_entries(entries)
         self.assertEqual(entries[0].mode & 0o644, 0o644)
         # would fail, test is too primitive to handle this case
@@ -583,7 +591,7 @@ class TestIndex(TestBase):
             for target in ('/etc/nonexisting', '/etc/passwd', '/etc'):
                 basename = "my_real_symlink"
 
-                link_file = os.path.join(rw_repo.working_tree_dir, basename)
+                link_file = osp.join(rw_repo.working_tree_dir, basename)
                 os.symlink(target, link_file)
                 entries = index.reset(new_commit).add([link_file], fprogress=self._fprogress_add)
                 self._assert_entries(entries)
@@ -645,7 +653,7 @@ class TestIndex(TestBase):
         # TEST RENAMING
         def assert_mv_rval(rval):
             for source, dest in rval:
-                assert not os.path.exists(source) and os.path.exists(dest)
+                assert not osp.exists(source) and osp.exists(dest)
             # END for each renamed item
         # END move assertion utility
 
@@ -661,7 +669,7 @@ class TestIndex(TestBase):
         paths = ['LICENSE', 'VERSION', 'doc']
         rval = index.move(paths, dry_run=True)
         self.assertEqual(len(rval), 2)
-        assert os.path.exists(paths[0])
+        assert osp.exists(paths[0])
 
         # again, no dry run
         rval = index.move(paths)
@@ -719,8 +727,8 @@ class TestIndex(TestBase):
         index.add(files, write=True)
         if is_win:
             hp = hook_path('pre-commit', index.repo.git_dir)
-            hpd = os.path.dirname(hp)
-            if not os.path.isdir(hpd):
+            hpd = osp.dirname(hp)
+            if not osp.isdir(hpd):
                 os.mkdir(hpd)
             with open(hp, "wt") as fp:
                 fp.write("#!/usr/bin/env sh\necho stdout; echo stderr 1>&2; exit 1")
@@ -766,7 +774,7 @@ class TestIndex(TestBase):
         for fkey in keys:
             assert fkey in index.entries
         for absfile in absfiles:
-            assert os.path.isfile(absfile)
+            assert osp.isfile(absfile)
 
     @with_rw_repo('HEAD')
     def test_compare_write_tree(self, rw_repo):
@@ -815,21 +823,21 @@ class TestIndex(TestBase):
 
         # Adding using a path should still require a non-bare repository.
         asserted = False
-        path = os.path.join('git', 'test', 'test_index.py')
+        path = osp.join('git', 'test', 'test_index.py')
         try:
             rw_bare_repo.index.add([path])
         except InvalidGitRepositoryError:
             asserted = True
         assert asserted, "Adding using a filename is not correctly asserted."
 
-    @skipIf(HIDE_WINDOWS_KNOWN_ERRORS and sys.version_info[:2] == (2, 7), r"""
+    @skipIf(HIDE_WINDOWS_KNOWN_ERRORS and not PY3, r"""
         FIXME:  File "C:\projects\gitpython\git\util.py", line 125, in to_native_path_linux
         return path.replace('\\', '/')
         UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)""")
     @with_rw_directory
     def test_add_utf8P_path(self, rw_dir):
         # NOTE: fp is not a Unicode object in python 2 (which is the source of the problem)
-        fp = os.path.join(rw_dir, 'ø.txt')
+        fp = osp.join(rw_dir, 'ø.txt')
         with open(fp, 'wb') as fs:
             fs.write(u'content of ø'.encode('utf-8'))
 
@@ -840,7 +848,7 @@ class TestIndex(TestBase):
     @with_rw_directory
     def test_add_a_file_with_wildcard_chars(self, rw_dir):
         # see issue #407
-        fp = os.path.join(rw_dir, '[.exe')
+        fp = osp.join(rw_dir, '[.exe')
         with open(fp, "wb") as f:
             f.write(b'something')
 
diff --git a/git/test/test_reflog.py b/git/test/test_reflog.py
index dffedf3b..20495be1 100644
--- a/git/test/test_reflog.py
+++ b/git/test/test_reflog.py
@@ -1,17 +1,18 @@
-from git.test.lib import (
-    TestBase,
-    fixture_path
-)
+import os
+import tempfile
+
 from git.objects import IndexObject
 from git.refs import (
     RefLogEntry,
     RefLog
 )
-from git.util import Actor, rmtree
-from gitdb.util import hex_to_bin
+from git.test.lib import (
+    TestBase,
+    fixture_path
+)
+from git.util import Actor, rmtree, hex_to_bin
 
-import tempfile
-import os
+import os.path as osp
 
 
 class TestRefLog(TestBase):
@@ -42,7 +43,7 @@ class TestRefLog(TestBase):
         os.mkdir(tdir)
 
         rlp_master_ro = RefLog.path(self.rorepo.head)
-        assert os.path.isfile(rlp_master_ro)
+        assert osp.isfile(rlp_master_ro)
 
         # simple read
         reflog = RefLog.from_file(rlp_master_ro)
@@ -70,7 +71,7 @@ class TestRefLog(TestBase):
         cr = self.rorepo.config_reader()
         for rlp in (rlp_head, rlp_master):
             reflog = RefLog.from_file(rlp)
-            tfile = os.path.join(tdir, os.path.basename(rlp))
+            tfile = osp.join(tdir, osp.basename(rlp))
             reflog.to_file(tfile)
             assert reflog.write() is reflog
 
diff --git a/git/test/test_refs.py b/git/test/test_refs.py
index 43f1dcc7..fd0be108 100644
--- a/git/test/test_refs.py
+++ b/git/test/test_refs.py
@@ -4,10 +4,8 @@
 # This module is part of GitPython and is released under
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 
-from git.test.lib import (
-    TestBase,
-    with_rw_repo
-)
+from itertools import chain
+
 from git import (
     Reference,
     Head,
@@ -18,11 +16,15 @@ from git import (
     GitCommandError,
     RefLog
 )
-import git.refs as refs
-from git.util import Actor
 from git.objects.tag import TagObject
-from itertools import chain
-import os
+from git.test.lib import (
+    TestBase,
+    with_rw_repo
+)
+from git.util import Actor
+
+import git.refs as refs
+import os.path as osp
 
 
 class TestRefs(TestBase):
@@ -268,10 +270,10 @@ class TestRefs(TestBase):
             assert tmp_head == new_head and tmp_head.object == new_head.object
 
             logfile = RefLog.path(tmp_head)
-            assert os.path.isfile(logfile)
+            assert osp.isfile(logfile)
             Head.delete(rw_repo, tmp_head)
             # deletion removes the log as well
-            assert not os.path.isfile(logfile)
+            assert not osp.isfile(logfile)
             heads = rw_repo.heads
             assert tmp_head not in heads and new_head not in heads
             # force on deletion testing would be missing here, code looks okay though ;)
@@ -450,12 +452,12 @@ class TestRefs(TestBase):
         symbol_ref_path = "refs/symbol_ref"
         symref = SymbolicReference(rw_repo, symbol_ref_path)
         assert symref.path == symbol_ref_path
-        symbol_ref_abspath = os.path.join(rw_repo.git_dir, symref.path)
+        symbol_ref_abspath = osp.join(rw_repo.git_dir, symref.path)
 
         # set it
         symref.reference = new_head
         assert symref.reference == new_head
-        assert os.path.isfile(symbol_ref_abspath)
+        assert osp.isfile(symbol_ref_abspath)
         assert symref.commit == new_head.commit
 
         for name in ('absname', 'folder/rela_name'):
@@ -507,7 +509,7 @@ class TestRefs(TestBase):
         rw_repo.head.reference = Head.create(rw_repo, "master")
 
         # At least the head should still exist
-        assert os.path.isfile(os.path.join(rw_repo.git_dir, 'HEAD'))
+        assert osp.isfile(osp.join(rw_repo.git_dir, 'HEAD'))
         refs = list(SymbolicReference.iter_items(rw_repo))
         assert len(refs) == 1
 
diff --git a/git/test/test_repo.py b/git/test/test_repo.py
index a0a6a5b0..8b644f7f 100644
--- a/git/test/test_repo.py
+++ b/git/test/test_repo.py
@@ -50,10 +50,9 @@ from git.test.lib import (
     assert_true,
     raises
 )
-from git.util import HIDE_WINDOWS_KNOWN_ERRORS
+from git.util import HIDE_WINDOWS_KNOWN_ERRORS, cygpath
 from git.test.lib import with_rw_directory
-from git.util import join_path_native, rmtree, rmfile
-from gitdb.util import bin_to_hex
+from git.util import join_path_native, rmtree, rmfile, bin_to_hex
 from unittest import SkipTest
 
 import functools as fnt
@@ -203,8 +202,8 @@ class TestRepo(TestBase):
         prev_cwd = os.getcwd()
         os.chdir(tempfile.gettempdir())
         git_dir_rela = "repos/foo/bar.git"
-        del_dir_abs = os.path.abspath("repos")
-        git_dir_abs = os.path.abspath(git_dir_rela)
+        del_dir_abs = osp.abspath("repos")
+        git_dir_abs = osp.abspath(git_dir_rela)
         try:
             # with specific path
             for path in (git_dir_rela, git_dir_abs):
@@ -212,7 +211,7 @@ class TestRepo(TestBase):
                 self.assertIsInstance(r, Repo)
                 assert r.bare is True
                 assert not r.has_separate_working_tree()
-                assert os.path.isdir(r.git_dir)
+                assert osp.isdir(r.git_dir)
 
                 self._assert_empty_repo(r)
 
@@ -306,16 +305,16 @@ class TestRepo(TestBase):
     def test_is_dirty_with_path(self, rwrepo):
         assert rwrepo.is_dirty(path="git") is False
 
-        with open(os.path.join(rwrepo.working_dir, "git", "util.py"), "at") as f:
+        with open(osp.join(rwrepo.working_dir, "git", "util.py"), "at") as f:
             f.write("junk")
         assert rwrepo.is_dirty(path="git") is True
         assert rwrepo.is_dirty(path="doc") is False
 
-        rwrepo.git.add(os.path.join("git", "util.py"))
+        rwrepo.git.add(Git.polish_url(osp.join("git", "util.py")))
         assert rwrepo.is_dirty(index=False, path="git") is False
         assert rwrepo.is_dirty(path="git") is True
 
-        with open(os.path.join(rwrepo.working_dir, "doc", "no-such-file.txt"), "wt") as f:
+        with open(osp.join(rwrepo.working_dir, "doc", "no-such-file.txt"), "wt") as f:
             f.write("junk")
         assert rwrepo.is_dirty(path="doc") is False
         assert rwrepo.is_dirty(untracked_files=True, path="doc") is True
@@ -412,6 +411,14 @@ class TestRepo(TestBase):
         self.assertEqual(len(res), 1)
         self.assertEqual(len(res[0][1]), 83, "Unexpected amount of parsed blame lines")
 
+    @skipIf(HIDE_WINDOWS_KNOWN_ERRORS and Git.is_cygwin(),
+            """FIXME: File "C:\projects\gitpython\git\cmd.py", line 671, in execute
+                    raise GitCommandError(command, status, stderr_value, stdout_value)
+                GitCommandError: Cmd('git') failed due to: exit code(128)
+                  cmdline: git add 1__��ava verb��ten 1_test _myfile 1_test_other_file
+                          1_��ava-----verb��ten
+                  stderr: 'fatal: pathspec '"1__çava verböten"' did not match any files'
+                """)
     @with_rw_repo('HEAD', bare=False)
     def test_untracked_files(self, rwrepo):
         for run, (repo_add, is_invoking_git) in enumerate((
@@ -494,10 +501,10 @@ class TestRepo(TestBase):
         ph = os.environ.get('HOME')
         try:
             os.environ['HOME'] = rw_dir
-            Repo.init(os.path.join('~', 'test.git'), bare=True)
+            Repo.init(osp.join('~', 'test.git'), bare=True)
 
             os.environ['FOO'] = rw_dir
-            Repo.init(os.path.join('$FOO', 'test.git'), bare=True)
+            Repo.init(osp.join('$FOO', 'test.git'), bare=True)
         finally:
             if ph:
                 os.environ['HOME'] = ph
@@ -785,7 +792,7 @@ class TestRepo(TestBase):
     @with_rw_repo('HEAD')
     def test_git_file(self, rwrepo):
         # Move the .git directory to another location and create the .git file.
-        real_path_abs = os.path.abspath(join_path_native(rwrepo.working_tree_dir, '.real'))
+        real_path_abs = osp.abspath(join_path_native(rwrepo.working_tree_dir, '.real'))
         os.rename(rwrepo.git_dir, real_path_abs)
         git_file_path = join_path_native(rwrepo.working_tree_dir, '.git')
         with open(git_file_path, 'wb') as fp:
@@ -793,13 +800,13 @@ class TestRepo(TestBase):
 
         # Create a repo and make sure it's pointing to the relocated .git directory.
         git_file_repo = Repo(rwrepo.working_tree_dir)
-        self.assertEqual(os.path.abspath(git_file_repo.git_dir), real_path_abs)
+        self.assertEqual(osp.abspath(git_file_repo.git_dir), real_path_abs)
 
         # Test using an absolute gitdir path in the .git file.
         with open(git_file_path, 'wb') as fp:
             fp.write(('gitdir: %s\n' % real_path_abs).encode('ascii'))
         git_file_repo = Repo(rwrepo.working_tree_dir)
-        self.assertEqual(os.path.abspath(git_file_repo.git_dir), real_path_abs)
+        self.assertEqual(osp.abspath(git_file_repo.git_dir), real_path_abs)
 
     @skipIf(HIDE_WINDOWS_KNOWN_ERRORS and PY3,
             "FIXME: smmp fails with: TypeError: Can't convert 'bytes' object to str implicitly")
@@ -840,7 +847,7 @@ class TestRepo(TestBase):
         # It's expected to not be able to access a tree
         self.failUnlessRaises(ValueError, r.tree)
 
-        new_file_path = os.path.join(rw_dir, "new_file.ext")
+        new_file_path = osp.join(rw_dir, "new_file.ext")
         touch(new_file_path)
         r.index.add([new_file_path])
         r.index.commit("initial commit\nBAD MESSAGE 1\n")
@@ -901,9 +908,6 @@ class TestRepo(TestBase):
         for i, j in itertools.permutations([c1, 'ffffff', ''], r=2):
             self.assertRaises(GitCommandError, repo.is_ancestor, i, j)
 
-    # @skipIf(HIDE_WINDOWS_KNOWN_ERRORS,
-    #         "FIXME: helper.wrapper fails with: PermissionError: [WinError 5] Access is denied: "
-    #         "'C:\\Users\\appveyor\\AppData\\Local\\Temp\\1\\test_work_tree_unsupportedryfa60di\\master_repo\\.git\\objects\\pack\\pack-bc9e0787aef9f69e1591ef38ea0a6f566ec66fe3.idx")  # noqa E501
     @with_rw_directory
     def test_work_tree_unsupported(self, rw_dir):
         git = Git(rw_dir)
@@ -913,6 +917,8 @@ class TestRepo(TestBase):
         rw_master = self.rorepo.clone(join_path_native(rw_dir, 'master_repo'))
         rw_master.git.checkout('HEAD~10')
         worktree_path = join_path_native(rw_dir, 'worktree_repo')
+        if Git.is_cygwin():
+            worktree_path = cygpath(worktree_path)
         try:
             rw_master.git.worktree('add', worktree_path, 'master')
         except Exception as ex:
diff --git a/git/test/test_submodule.py b/git/test/test_submodule.py
index 9db4f9c9..fcaad04b 100644
--- a/git/test/test_submodule.py
+++ b/git/test/test_submodule.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # This module is part of GitPython and is released under
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 import os
@@ -6,24 +7,34 @@ from unittest.case import skipIf
 
 import git
 from git.cmd import Git
-from git.compat import string_types, is_win
+from git.compat import (
+    string_types,
+    is_win,
+)
 from git.exc import (
     InvalidGitRepositoryError,
     RepositoryDirtyError
 )
 from git.objects.submodule.base import Submodule
-from git.objects.submodule.root import RootModule, RootUpdateProgress
+from git.objects.submodule.root import (
+    RootModule,
+    RootUpdateProgress,
+)
 from git.repo.fun import (
     find_git_dir,
-    touch
+    touch,
 )
 from git.test.lib import (
     TestBase,
-    with_rw_repo
+    with_rw_repo,
 )
 from git.test.lib import with_rw_directory
-from git.util import HIDE_WINDOWS_KNOWN_ERRORS
-from git.util import to_native_path_linux, join_path_native
+from git.util import (
+    to_native_path_linux,
+    join_path_native,
+    HIDE_WINDOWS_KNOWN_ERRORS,
+)
+
 import os.path as osp
 
 
@@ -673,6 +684,13 @@ class TestSubmodule(TestBase):
                                   url=empty_repo_dir, no_checkout=checkout_mode and True or False)
         # end for each checkout mode
 
+    @skipIf(HIDE_WINDOWS_KNOWN_ERRORS and Git.is_cygwin(),
+            """FIXME: ile "C:\projects\gitpython\git\cmd.py", line 671, in execute
+                raise GitCommandError(command, status, stderr_value, stdout_value)
+            GitCommandError: Cmd('git') failed due to: exit code(128)
+              cmdline: git add 1__Xava verbXXten 1_test _myfile 1_test_other_file 1_XXava-----verbXXten
+              stderr: 'fatal: pathspec '"1__çava verböten"' did not match any files'
+                """)
     @with_rw_directory
     def test_git_submodules_and_add_sm_with_new_commit(self, rwdir):
         parent = git.Repo.init(osp.join(rwdir, 'parent'))
@@ -705,7 +723,7 @@ class TestSubmodule(TestBase):
         fp = osp.join(smm.working_tree_dir, 'empty-file')
         with open(fp, 'w'):
             pass
-        smm.git.add(fp)
+        smm.git.add(Git.polish_url(fp))
         smm.git.commit(m="new file added")
 
         # submodules are retrieved from the current commit's tree, therefore we can't really get a new submodule
@@ -730,7 +748,7 @@ class TestSubmodule(TestBase):
         assert commit_sm.binsha == sm_too.binsha
         assert sm_too.binsha != sm.binsha
 
-    # @skipIf(HIDE_WINDOWS_KNOWN_ERRORS,
+    # @skipIf(HIDE_WINDOWS_KNOWN_ERRORS,  ## ACTUALLY skipped by `git.submodule.base#L869`.
     #         "FIXME: helper.wrapper fails with: PermissionError: [WinError 5] Access is denied: "
     #         "'C:\\Users\\appveyor\\AppData\\Local\\Temp\\1\\test_work_tree_unsupportedryfa60di\\master_repo\\.git\\objects\\pack\\pack-bc9e0787aef9f69e1591ef38ea0a6f566ec66fe3.idx")  # noqa E501
     @with_rw_directory
diff --git a/git/test/test_tree.py b/git/test/test_tree.py
index f36c4337..f9259874 100644
--- a/git/test/test_tree.py
+++ b/git/test/test_tree.py
@@ -5,7 +5,6 @@
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 
 from io import BytesIO
-import os
 import sys
 from unittest.case import skipIf
 
@@ -13,8 +12,10 @@ from git import (
     Tree,
     Blob
 )
-from git.util import HIDE_WINDOWS_KNOWN_ERRORS
 from git.test.lib import TestBase
+from git.util import HIDE_WINDOWS_KNOWN_ERRORS
+
+import os.path as osp
 
 
 class TestTree(TestBase):
@@ -90,12 +91,12 @@ class TestTree(TestBase):
         assert len(set(b for b in root if isinstance(b, Blob)) | set(root.blobs)) == len(root.blobs)
         subitem = trees[0][0]
         assert "/" in subitem.path
-        assert subitem.name == os.path.basename(subitem.path)
+        assert subitem.name == osp.basename(subitem.path)
 
         # assure that at some point the traversed paths have a slash in them
         found_slash = False
         for item in root.traverse():
-            assert os.path.isabs(item.abspath)
+            assert osp.isabs(item.abspath)
             if '/' in item.path:
                 found_slash = True
             # END check for slash
diff --git a/git/test/test_util.py b/git/test/test_util.py
index e07417b4..8f8d2272 100644
--- a/git/test/test_util.py
+++ b/git/test/test_util.py
@@ -5,7 +5,19 @@
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 
 import tempfile
+import time
+from unittest.case import skipIf
+
+import ddt
 
+from git.cmd import dashify
+from git.compat import string_types, is_win
+from git.objects.util import (
+    altz_to_utctz_str,
+    utctz_to_altz,
+    verify_utctz,
+    parse_date,
+)
 from git.test.lib import (
     TestBase,
     assert_equal
@@ -15,19 +27,37 @@ from git.util import (
     BlockingLockFile,
     get_user_id,
     Actor,
-    IterableList
+    IterableList,
+    cygpath,
+    decygpath
 )
-from git.objects.util import (
-    altz_to_utctz_str,
-    utctz_to_altz,
-    verify_utctz,
-    parse_date,
+
+
+_norm_cygpath_pairs = (
+    (r'foo\bar', 'foo/bar'),
+    (r'foo/bar', 'foo/bar'),
+
+    (r'C:\Users', '/cygdrive/c/Users'),
+    (r'C:\d/e', '/cygdrive/c/d/e'),
+
+    ('C:\\', '/cygdrive/c/'),
+
+    (r'\\server\C$\Users', '//server/C$/Users'),
+    (r'\\server\C$', '//server/C$'),
+    ('\\\\server\\c$\\', '//server/c$/'),
+    (r'\\server\BAR/', '//server/BAR/'),
+
+    (r'D:/Apps', '/cygdrive/d/Apps'),
+    (r'D:/Apps\fOO', '/cygdrive/d/Apps/fOO'),
+    (r'D:\Apps/123', '/cygdrive/d/Apps/123'),
 )
-from git.cmd import dashify
-from git.compat import string_types, is_win
 
-import time
-import ddt
+_unc_cygpath_pairs = (
+    (r'\\?\a:\com', '/cygdrive/a/com'),
+    (r'\\?\a:/com', '/cygdrive/a/com'),
+
+    (r'\\?\UNC\server\D$\Apps', '//server/D$/Apps'),
+)
 
 
 class TestIterableMember(object):
@@ -52,6 +82,46 @@ class TestUtils(TestBase):
             "array": [42],
         }
 
+    @skipIf(not is_win, "Paths specifically for Windows.")
+    @ddt.idata(_norm_cygpath_pairs + _unc_cygpath_pairs)
+    def test_cygpath_ok(self, case):
+        wpath, cpath = case
+        cwpath = cygpath(wpath)
+        self.assertEqual(cwpath, cpath, wpath)
+
+    @skipIf(not is_win, "Paths specifically for Windows.")
+    @ddt.data(
+        (r'./bar', 'bar'),
+        (r'.\bar', 'bar'),
+        (r'../bar', '../bar'),
+        (r'..\bar', '../bar'),
+        (r'../bar/.\foo/../chu', '../bar/chu'),
+    )
+    def test_cygpath_norm_ok(self, case):
+        wpath, cpath = case
+        cwpath = cygpath(wpath)
+        self.assertEqual(cwpath, cpath or wpath, wpath)
+
+    @skipIf(not is_win, "Paths specifically for Windows.")
+    @ddt.data(
+        r'C:',
+        r'C:Relative',
+        r'D:Apps\123',
+        r'D:Apps/123',
+        r'\\?\a:rel',
+        r'\\share\a:rel',
+    )
+    def test_cygpath_invalids(self, wpath):
+        cwpath = cygpath(wpath)
+        self.assertEqual(cwpath, wpath.replace('\\', '/'), wpath)
+
+    @skipIf(not is_win, "Paths specifically for Windows.")
+    @ddt.idata(_norm_cygpath_pairs)
+    def test_decygpath(self, case):
+        wpath, cpath = case
+        wcpath = decygpath(cpath)
+        self.assertEqual(wcpath, wpath.replace('/', '\\'), cpath)
+
     def test_it_should_dashify(self):
         assert_equal('this-is-my-argument', dashify('this_is_my_argument'))
         assert_equal('foo', dashify('foo'))
diff --git a/test-requirements.txt b/test-requirements.txt
index 4d08a501..8f13395d 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -3,4 +3,4 @@
 coverage
 flake8
 nose
-mock
+mock; python_version<='2.7'