Repository: gitpython-developers/GitPython (python)

Issue:
Adding files to repository that is located directly in the root
This is a weird scenario, but if you init git repo in the root directory(e.g. D:\\) and try to add a file using gitpython, it will throw a ValueError:
```
Absolute path `D:\\file` is not in git repository at `D:\\`
```
The reason for this is improper validation in _to_relative_path method located at git/index/base.py:
```
    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 osp.isabs(path):
            return path
        if self.repo.bare:
            raise InvalidGitRepositoryError("require non-bare repository")
        relative_path = path.replace(self.repo.working_tree_dir + os.sep, "")
        if relative_path == path:
            raise ValueError("Absolute path %r is not in git repository at %r" % (path, self.repo.working_tree_dir))
        return relative_path
```
I.e. when path is `/file` and working_tree_dir is `/`, relative_path stays equal to path, because `self.repo.working_tree + os.sep` is equal to `//`. The way to solve this is to simply use os.path.relpath methond. Please see pull-request attached.

Pull request description:
git: index: base: use os.path.relpath
Fixes #743

Signed-off-by: Ruslan Kuprieiev <kupruser@gmail.com>

Patch:
diff --git a/git/index/base.py b/git/index/base.py
index 14a3117a..04a3934d 100644
--- a/git/index/base.py
+++ b/git/index/base.py
@@ -561,10 +561,9 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
             return path
         if self.repo.bare:
             raise InvalidGitRepositoryError("require non-bare repository")
-        relative_path = path.replace(self.repo.working_tree_dir + os.sep, "")
-        if relative_path == path:
+        if not path.startswith(self.repo.working_tree_dir):
             raise ValueError("Absolute path %r is not in git repository at %r" % (path, self.repo.working_tree_dir))
-        return relative_path
+        return os.path.relpath(path, self.repo.working_tree_dir)
 
     def _preprocess_add_items(self, items):
         """ Split the items into two lists of path strings and BaseEntries. """


Test patch:
diff --git a/git/test/test_index.py b/git/test/test_index.py
index 9be4031d..a30d314b 100644
--- a/git/test/test_index.py
+++ b/git/test/test_index.py
@@ -838,6 +838,21 @@ class TestIndex(TestBase):
         r.index.add([fp])
         r.index.commit('Added [.exe')
 
+    def test__to_relative_path_at_root(self):
+        root = osp.abspath(os.sep)
+
+        class Mocked(object):
+            bare = False
+            git_dir = root
+            working_tree_dir = root
+
+        repo = Mocked()
+        path = os.path.join(root, 'file')
+        index = IndexFile(repo)
+
+        rel = index._to_relative_path(path)
+        self.assertEqual(rel, os.path.relpath(path, root))
+
     @with_rw_repo('HEAD', bare=True)
     def test_pre_commit_hook_success(self, rw_repo):
         index = rw_repo.index