Search code examples
gitgit-diffmingw-w64winmergemsys2

What is the rule of MSYS/MinGW path translation?


I have been following this post on how to use Winmerge as a diff tool in git. Initially it doesn't work (ok now, therefore irrelevant to my question here). One key difference is I'm using git provided inside MSYS2, not the msysgit under native Windows environment. The relevant git config fragment is:

[diff]
        guitool = winmerge

[difftool "winmerge"]
        cmd = \"????/WinMergeU.exe\" /e /s /u /r /wl \"$LOCAL\" \"$REMOTE\"

To my shock, some of the command line options of winmerge have been converted to drive letters upon execution, causing failure. The real command executed after git difftool -g is:

"????\WinMergeU.exe" /e S:/ U:/ R:/ D:/msys64/wl <file1> <file2>

Where D:/msys64 is my MSYS2 installation prefix. Note the inconsistency in errors — /e unconverted, /wl converted to path component, and all others to drive letters. A solution is found later by using - instead of / as prefix of all options:

[difftool "winmerge"]
        cmd = \"????/WinMergeU.exe\" -e -s -u -r -wl \"$LOCAL\" \"$REMOTE\"

My question is:

  1. Why the inconsistent behavior? Is there any reference on how cygpath performs the path translation?
  2. Luckily WinMerge accepts using - as option indicator. For those GUI tools where only / is accepted, is there any workaround?

Solution

  • I believe MSYS2 tried to follow the same behavior in MSYS to translate the unix path arguments to Windows path for executable not depending on the msys2 dll.

    In this case, you can escape the arguments starting with single slash with double slash, i.e.

    \"????/WinMergeU.exe\" //e //s //u //r //wl \"$LOCAL\" \"$REMOTE\"

    The rules (extracted from the linked page):

    • Arguments starting with a drive specifier (eg C:) are considered to be Windows paths and are not converted.
    • Arguments containing a ; are considered to be Windows path lists and are not converted.
    • An argument starting with 2 or more / is considered an escaped Windows style switch and will be passed with the leading / removed and all \ changed to /.
      • Except that if there is a / following the leading block of /, the argument is considered to be a UNC path and the leading / is not removed.
    • If an argument has a leading / followed by a drive specfier, the / is removed and all \ are changed to /.
    • If an argument has a = it is considered a variable assignment. The right hand side is converted according to these rules and the left hand side has all \ converted to /, unless the right hand side starts with a drive specifier.
    • An argument that doesn't start with -, ", ', or @ and contains a : followed by /, :, or .; and a / is considered a POSIX path list. Every :-separated element is converted according to these rules, and the : are replaced with ;. Any / are converted to \.
      • Unless the : is followed by //: then it is considered a URL and not converted.
    • An argument with a leading / is converted up to the first /...
    • If an argument has a leading - and a ,, the part after the , is converted according to these rules and the whole argument has \ converted to / unless the path starts with a drive specifier.
    • If an argument has a leading - and the second character is a /, the part from the / onward is converted according to these rules.
    • An argument with a leading @ is considered a response file argument and the text following the @ is converted according to these rules.
    • An argument inside ' or " is processed according to these rules with the quotes ignored.