jelmer / dulwich

Pure-Python Git implementation
https://www.dulwich.io/
Other
2.04k stars 390 forks source link

porcelain.add() should not resolve symlinks #789

Open mjpieters opened 4 years ago

mjpieters commented 4 years ago

porcelain.add() resolves paths to be relative to the repository root:

https://github.com/dulwich/dulwich/blob/06bfbd92a0ab05d61656aa50f1e6e1b19a342e34/dulwich/porcelain.py#L445

This follows symlinks to produce a canonical path. So the following code tries to add a non-existing path to the repository:

>>> with TemporaryDirectory() as root:
...     repo = porcelain.init(root)
...     link = os.path.join(root, "bar")
...     target = "/foo"  # outside the root
...     os.symlink(target, link)
...     added, _ = porcelain.add(repo, link)
...
Traceback (most recent call last):
  File "<stdin>", line 6, in <module>
  File "/.../site-packages/dulwich/porcelain.py", line 445, in add
    relpath = str(Path(p).resolve().relative_to(repo_path))
  File "/.../pathlib.py", line 874, in relative_to
    .format(str(self), str(formatted)))
ValueError: '/foo' does not start with '/.../T/tmp1askonz_'

Adding a symlink should not resolve the symlink; it should, at most, resolve and check parent of the path being added. I'm not sure what the git C layer does here, but adding symlinks that point nowhere is supported by the command-line git command.

Kryan90 commented 1 year ago

I am having a similar issue. git cli will show a new symlink as an untracked file, but in dulwich it doesn't get included in porcelain.get_untracked_paths()

Since the relative path of the symlinked file ends up getting resolved, the check here to see if the file is already in the index ends up being true: https://github.com/jelmer/dulwich/blob/master/dulwich/porcelain.py#L1424