Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

git.Repo.clone_from() not working correctly in WSL #1902

Open
paolzpk opened this issue Apr 15, 2024 · 3 comments
Open

git.Repo.clone_from() not working correctly in WSL #1902

paolzpk opened this issue Apr 15, 2024 · 3 comments

Comments

@paolzpk
Copy link

paolzpk commented Apr 15, 2024

I am using GitPython both in windows and WSL and I noticed that paths are not handled coherently between the two (i.e. C:/ vs /mnt/c). It is possible to go around it most of the time using wslpath and converting from Windows to WSL and vice versa but it looks that the clone_from() ends up raising an exception regardless if the to_path is in WSL format or Windows format.

Steps to reproduce:

from pathlib import Path
import git
import traceback
import subprocess

def to_windows_path(wsl_path: Path) -> Path:
    """ Converts a WSL path to windows path - works only if the WSL path actually exists """
    wslpath_process = subprocess.run(['wslpath', '-w', wsl_path], text=True, capture_output=True)
    return Path(wslpath_process.stdout.strip())

try:
  git.Repo.clone_from('git@github.com:gitpython-developers/GitPython.git', Path.cwd() / 'gitpython')
except git.GitCommandError:
  print(traceback.format_exc())

try:
  git.Repo.clone_from('git@github.com:gitpython-developers/GitPython.git', to_windows_path(Path.cwd()) / 'gitpython')
except git.NoSuchPathError:
  print(traceback.format_exc())

Expected behaviour:
When the script is launched from a python instance running on WSL the repo is cloned in $PWD/gitpython.

Actual behaviour:

[if (Path.cwd() / 'gitpython').exists() == False before running the script]
[git.version == '3.1.40']
python the_script.py

File ~/anaconda3/lib/python3.11/site-packages/git/repo/base.py:1328, in Repo.clone_from(cls, url, to_path, progress, env, multi_options, allow_unsafe_protocols, allow_unsafe_options, **kwargs)
1326 if env is not None:
1327 git.update_environment(**env)
-> 1328 return cls._clone(
1329 git,
1330 url,
1331 to_path,
1332 GitCmdObjectDB,
1333 progress,
1334 multi_options,
1335 allow_unsafe_protocols=allow_unsafe_protocols,
1336 allow_unsafe_options=allow_unsafe_options,
1337 **kwargs,
1338 )

File ~/anaconda3/lib/python3.11/site-packages/git/repo/base.py:1244, in Repo._clone(cls, git, url, path, odb_default_type, progress, multi_options, allow_unsafe_protocols, allow_unsafe_options, **kwargs)
1241 if not osp.isabs(path):
1242 path = osp.join(git._working_dir, path) if git._working_dir is not None else path
-> 1244 repo = cls(path, odbt=odbt)
1246 # retain env values that were passed to _clone()
1247 repo.git.update_environment(**git.environment())

File ~/anaconda3/lib/python3.11/site-packages/git/repo/base.py:215, in Repo.init(self, path, odbt, search_parent_directories, expand_vars)
213 if epath is not None:
214 if not os.path.exists(epath):
--> 215 raise NoSuchPathError(epath)
217 ## Walk up the path to find the .git dir.
218 #
219 curpath = epath
NoSuchPathError: /mnt/c/Users/user.name/Documents/C:\Users\user.name\Documents/gitpython

@Byron
Copy link
Member

Byron commented Apr 15, 2024

Thanks for reporting.

Even though I couldn't reproduce it, I wouldn't be surprised if something is going wrong here. It might be that it doesn't recognise the path as absolute, and makes it absolute by pre-pending the CWD all by itself (which it shouldn't have to do at all).

@paolzpk
Copy link
Author

paolzpk commented Apr 16, 2024

Indeed with relative paths it looks like it is working correctly, but still it would be nice if it worked correctly with absolute paths as well. In my project I think I will be able to get around this issue, but if I have time I will look into your repo and propose some changes!
Thanks!

@EliahKagan
Copy link
Contributor

EliahKagan commented Jun 1, 2024

I don't know if a bug is involved here or not, but this does not look like a bug in GitPython's handling of WSL paths, though even that I cannot be sure of. This may relate to problems using the git executable in the WSL system to perform operations in the mounted Windows volumes for which the WSL systems's git may not be configured properly, or it may be a bug in GitPython, or something else. I cannot tell.

I have tried running your script, as well as several manual variations, in WSL 2 (Ubuntu 22.04 LTS) in Windows 10, using Python 3.11 and GitPython 3.1.40 as in your description. I am not able to produce anything like this. When I run it, as well as when I perform the clones and variations on them manually in the Python REPL, both clones succeed. No exception is raised, and no traceback is printed for either.

Although not stipulated in the description here, I did make sure to run it in a subdirectory of my Windows home (user profile) directory accessed through /mnt/c, so that Path.cwd() would evaluate to such a path. I tried this with the Documents subdirectory of my Windows home directory, as appears to have been done in your example, as well as another directory. (I also tried it in other directories not in a mounted Windows volume, just in case.)

For me, the first clone succeeds and creates the intended cloned gitpython directory.

The second clone, which uses wslpath -w, can never do what you want, or at least it can never be equivalent to the first one. This is because POSIX path semantics in a Unix-like environment including WSL require that a path such as C:\Users\user.name\Documents--which is the sort of thing wslpath -w outputs--be interpreted as a simple filename that happens to contain : and \ characters. Such paths are usable as if Windows were not involved, even when they are resolved under a mount point like /mnt/c in WSL. This is because the disallowed : and \ characters are mapped to other Unicode code points. Literal : and \ appear within WSL, while the substituted code points appear only from the Windows side. (The code-point substitution is WSL-specific behavior, independent of Python or GitPython. The rest is straightforward POSIX path handling and I believe it would be a bug to attempt to change it in any way.) But the clone still succeeds for me, creating a subdirectory of that strange name, which itself contains a gitpython directory, and this behavior is what I would expect.

Due to a combination of how the demonstration code concatenates both tracebacks if present, and how spacing and other formatting information is lost when formatting the output as a blockquote rather than a code block, I find it hard to be confident that I understand the output. So it could be that I am missing something, but based on that output, it looks like it might only be one traceback rather than two, in which case one of the tries may not have raised an exception even if it did not behave as intended. I don't think there is enough information here to determine whether or not there is a bug or, if there is, to work toward a fix.

I would be curious what is shown under the conditions where the script you showed produces output like you showed, if instead you open a Python REPL, import the necessary modules, and run the one-line expression statement:

git.Repo.clone_from('git@github.com:gitpython-developers/GitPython.git', Path.cwd() / 'gitpython')

This is what that looks like for me:

(.venv) ek@Glub:/mnt/c/Users/ek/Documents$ python3.11
Python 3.11.9 (main, Apr  6 2024, 17:59:24) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pathlib import Path
>>> import git
>>> git.Repo.clone_from('git@github.com:gitpython-developers/GitPython.git', Path.cwd() / 'gitpython')
<git.repo.base.Repo '/mnt/c/Users/ek/Documents/gitpython/.git'>

As shown, that successfully clones the repo in $PWD/gitpython.

Edit: Fixed the first occurrence of the git.Repo.clone_from expression, for which I had wrongly pasted in the subprocess expression.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

3 participants