git-mediate icon indicating copy to clipboard operation
git-mediate copied to clipboard

incorrect handling of filenames containing spaces or line endings

Open pabs3 opened this issue 2 years ago • 2 comments

When dealing with file names containing a space, according to strace, git-mediate instead tries to access the filename with double quotes at the start and end of the filename.

When dealing with file names containing an LF characer, according to strace, git-mediate instead tries to access the filename with LF converted to a literal \n and also double quotes at the start and end of the filename.

This is because the machine-readable git status output format does filename mangling in order to escape characters not representable in that format.

$ git status --porcelain 
UU "a b"
UU "foo\nbar"

To avoid having to unescape characters, I suggest using the NUL-separated git status output format instead.

$ git status --porcelain -z | hd
00000000  55 55 20 61 20 62 00 3f  3f 20 2e 67 69 74 63 6f  |UU a b.?? .gitco|
00000010  6e 66 69 67 00 3f 3f 20  66 6f 6f 0a 62 61 72 00  |nfig.?? foo.bar.|
00000020  3f 3f 20 66 6f 6f 5c 6e  62 61 72 00 3f 3f 20 74  |?? foo\nbar.?? t|
00000030  65 73 74 00                                       |est.|
00000034

This NUL-separated format has some other differences too, a quote from the docs:

There is also an alternate -z format recommended for machine parsing. In that format, the status field is the same, but some other things change. First, the -> is omitted from rename entries and the field order is reversed (e.g from -> to becomes to from). Second, a NUL (ASCII 0) follows each filename, replacing space as a field separator and the terminating newline (but a space still separates the status field from the first filename). Third, filenames containing special characters are not specially formatted; no quoting or backslash-escaping is performed.

pabs3 avatar Jul 25 '23 13:07 pabs3

Made a work-in-progress implementation for this in https://github.com/Peaker/git-mediate/compare/statusz It's working for me so far but the git status -z docs isn't too clear on which status types have a second parameter so I'm not sure it's solid.

yairchu avatar Oct 02 '23 11:10 yairchu

Thanks! I'm not a Haskell person so I can't review that sorry.

Looking at the git code it seems that only the status types for rename and (when enabled) copy have the second parameter.

That said, maybe it would be worth using version 2 of the porcelain format by default anyway, it is much more detailed and better documented and the -z version of it is exactly the same as the standard version except for quoting and the record ending is NUL. For older versions of git you could fall back to version 1 instead.

-- bye, pabs

https://bonedaddy.net/pabs3/

pabs3 avatar Oct 03 '23 05:10 pabs3

After a period of time using the change it seems like it works. We'll see if any unsupported cases are reported but felt merging it in is suitable :) Sorry for the delay

yairchu avatar Jul 29 '24 07:07 yairchu