From f2254af5d3fd183ec150740d517bd0f8070fc67d Mon Sep 17 00:00:00 2001
From: Andrej730 <azhilenkov@gmail.com>
Date: Sat, 14 Sep 2024 10:45:53 +0500
Subject: [PATCH 1/4] _to_relative_path to support mixing slashes and
 backslashes

Working on Windows you sometime end up having some paths with backslashes (windows native) and some with slashes - this PR will resolve the issue using gitpython for those kind of cases (see example below). It will also fix the issues if paths contain redundant separators or "..".

```
import git

repo = git.Repo(r"C:\gittest")
repo.index.add(r"C:\gittest\1.txt")
# Traceback (most recent call last):
#   File "c:\second_test.py", line 5, in <module>
#     repo.index.add(r"C:/gittest/2.txt")
#   File "Python311\Lib\site-packages\git\index\base.py", line 879, in add
#     paths, entries = self._preprocess_add_items(items)
#                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#   File "Python311\Lib\site-packages\git\index\base.py", line 672, in _preprocess_add_items
#     paths.append(self._to_relative_path(item))
#                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#   File "Python311\Lib\site-packages\git\index\base.py", line 657, in _to_relative_path
#     raise ValueError("Absolute path %r is not in git repository at %r" % (path, self.repo.working_tree_dir))
# ValueError: Absolute path 'C:/gittest/2.txt' is not in git repository at 'C:\\gittest'

repo.index.add(r"C:/gittest/2.txt")

repo.index.commit("test")
```
---
 git/index/base.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git/index/base.py b/git/index/base.py
index 47925ad1c..7f53e614a 100644
--- a/git/index/base.py
+++ b/git/index/base.py
@@ -653,7 +653,7 @@ def _to_relative_path(self, path: PathLike) -> PathLike:
             return path
         if self.repo.bare:
             raise InvalidGitRepositoryError("require non-bare repository")
-        if not str(path).startswith(str(self.repo.working_tree_dir)):
+        if not osp.normpath(str(path)).startswith(osp.normpath(str(self.repo.working_tree_dir))):
             raise ValueError("Absolute path %r is not in git repository at %r" % (path, self.repo.working_tree_dir))
         return os.path.relpath(path, self.repo.working_tree_dir)
 

From ca06b11efde845080354dac71e9062ea6d63ab84 Mon Sep 17 00:00:00 2001
From: Andrej730 <azhilenkov@gmail.com>
Date: Sat, 14 Sep 2024 16:51:41 +0500
Subject: [PATCH 2/4] test adding a file using non-normalized path

---
 test/test_index.py | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/test/test_index.py b/test/test_index.py
index 2684cfd81..efd5b83a6 100644
--- a/test/test_index.py
+++ b/test/test_index.py
@@ -1181,6 +1181,18 @@ def test_index_add_pathlike(self, rw_repo):
 
         rw_repo.index.add(file)
 
+    @with_rw_repo("HEAD")
+    def test_index_add_non_normalized_path(self, rw_repo):
+        git_dir = Path(rw_repo.git_dir)
+
+        file = git_dir / "file.txt"
+        file.touch()
+        non_normalized_path = file.as_posix()
+        if os.name != "nt":
+            non_normalized_path = non_normalized_path.replace("/", "\\")
+
+        rw_repo.index.add(non_normalized_path)
+
 
 class TestIndexUtils:
     @pytest.mark.parametrize("file_path_type", [str, Path])

From 46740590f7918fd5b789c95db7e41fbda06fb46f Mon Sep 17 00:00:00 2001
From: Andrej730 <azhilenkov@gmail.com>
Date: Sat, 14 Sep 2024 16:52:56 +0500
Subject: [PATCH 3/4] Remove redundant path normalization for working_tree_dir

---
 git/index/base.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git/index/base.py b/git/index/base.py
index 7f53e614a..39cc9143c 100644
--- a/git/index/base.py
+++ b/git/index/base.py
@@ -653,7 +653,7 @@ def _to_relative_path(self, path: PathLike) -> PathLike:
             return path
         if self.repo.bare:
             raise InvalidGitRepositoryError("require non-bare repository")
-        if not osp.normpath(str(path)).startswith(osp.normpath(str(self.repo.working_tree_dir))):
+        if not osp.normpath(str(path)).startswith(str(self.repo.working_tree_dir)):
             raise ValueError("Absolute path %r is not in git repository at %r" % (path, self.repo.working_tree_dir))
         return os.path.relpath(path, self.repo.working_tree_dir)
 

From 8327b82a1079f667006f649cb3f1bbdcc8792955 Mon Sep 17 00:00:00 2001
From: Andrej730 <azhilenkov@gmail.com>
Date: Sat, 14 Sep 2024 21:18:18 +0500
Subject: [PATCH 4/4] Fix test failing on unix

---
 test/test_index.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/test_index.py b/test/test_index.py
index efd5b83a6..c586a0b5a 100644
--- a/test/test_index.py
+++ b/test/test_index.py
@@ -1189,7 +1189,7 @@ def test_index_add_non_normalized_path(self, rw_repo):
         file.touch()
         non_normalized_path = file.as_posix()
         if os.name != "nt":
-            non_normalized_path = non_normalized_path.replace("/", "\\")
+            non_normalized_path = "/" + non_normalized_path[1:].replace("/", "//")
 
         rw_repo.index.add(non_normalized_path)