Skip to content

Commit ec3c02e

Browse files
committed
Merge branch 'unc-path-w-backslashes'
This topic branch addresses a problem identified in git-for-windows#439: while cloning/fetching/pushing from "POSIX-ified UNC paths" (i.e. UNC paths whose backslashes have been converted to forward slashes) works for some time now, true UNC paths (with backslashes left intact) were handled incorrectly. Example: git clone //myserver/folder/repo.git works, but git clone \\myserver\folder\repo.git (in CMD; in Git Bash, the backslashes would need to be doubled) used to fail. The reason was an unexpected difference in command-line handling between Win32 executables and MSYS2 ones (such as the shell that is used by git-clone.exe to spawn git-upload-pack.exe). This topic branch features a workaround *just* for the case where Git passes stuff through sh.exe (which covers quite a few use cases, though). Signed-off-by: Johannes Schindelin <[email protected]>
2 parents 42a9d17 + afb7686 commit ec3c02e

File tree

3 files changed

+78
-2
lines changed

3 files changed

+78
-2
lines changed

compat/mingw.c

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1112,7 +1112,7 @@ char *mingw_getcwd(char *pointer, int len)
11121112
* See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
11131113
* (Parsing C++ Command-Line Arguments)
11141114
*/
1115-
static const char *quote_arg(const char *arg)
1115+
static const char *quote_arg_msvc(const char *arg)
11161116
{
11171117
/* count chars to quote */
11181118
int len = 0, n = 0;
@@ -1167,6 +1167,37 @@ static const char *quote_arg(const char *arg)
11671167
return q;
11681168
}
11691169

1170+
#include "quote.h"
1171+
1172+
static const char *quote_arg_msys2(const char *arg)
1173+
{
1174+
struct strbuf buf = STRBUF_INIT;
1175+
const char *p2 = arg, *p;
1176+
1177+
for (p = arg; *p; p++) {
1178+
int ws = isspace(*p);
1179+
if (!ws && *p != '\\' && *p != '"' && *p != '{')
1180+
continue;
1181+
if (!buf.len)
1182+
strbuf_addch(&buf, '"');
1183+
if (p != p2)
1184+
strbuf_add(&buf, p2, p - p2);
1185+
if (!ws && *p != '{')
1186+
strbuf_addch(&buf, '\\');
1187+
p2 = p;
1188+
}
1189+
1190+
if (p == arg)
1191+
strbuf_addch(&buf, '"');
1192+
else if (!buf.len)
1193+
return arg;
1194+
else
1195+
strbuf_add(&buf, p2, p - p2),
1196+
1197+
strbuf_addch(&buf, '"');
1198+
return strbuf_detach(&buf, 0);
1199+
}
1200+
11701201
static const char *parse_interpreter(const char *cmd)
11711202
{
11721203
static char buf[100];
@@ -1477,6 +1508,34 @@ struct pinfo_t {
14771508
static struct pinfo_t *pinfo = NULL;
14781509
CRITICAL_SECTION pinfo_cs;
14791510

1511+
static int is_msys2_sh(const char *cmd)
1512+
{
1513+
if (cmd && !strcmp(cmd, "sh")) {
1514+
static int ret = -1;
1515+
char *p;
1516+
1517+
if (ret >= 0)
1518+
return ret;
1519+
1520+
p = path_lookup(cmd, 0);
1521+
if (!p)
1522+
ret = 0;
1523+
else {
1524+
size_t len = strlen(p);
1525+
ret = len > 15 &&
1526+
is_dir_sep(p[len - 15]) &&
1527+
!strncasecmp(p + len - 14, "usr", 3) &&
1528+
is_dir_sep(p[len - 11]) &&
1529+
!strncasecmp(p + len - 10, "bin", 3) &&
1530+
is_dir_sep(p[len - 7]) &&
1531+
!strcasecmp(p + len - 6, "sh.exe");
1532+
free(p);
1533+
}
1534+
return ret;
1535+
}
1536+
return 0;
1537+
}
1538+
14801539
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
14811540
const char *dir,
14821541
int prepend_cmd, int fhin, int fhout, int fherr)
@@ -1489,6 +1548,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
14891548
BOOL ret;
14901549
HANDLE cons;
14911550
const char *strace_env;
1551+
const char *(*quote_arg)(const char *arg) =
1552+
is_msys2_sh(*argv) ? quote_arg_msys2 : quote_arg_msvc;
14921553

14931554
do_unset_environment_variables();
14941555

t/t0061-run-command.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,4 +178,14 @@ test_expect_success 'GIT_TRACE with environment variables' '
178178
)
179179
'
180180

181+
test_expect_success MINGW 'verify curlies are quoted properly' '
182+
: force the rev-parse through the MSYS2 Bash &&
183+
git -c alias.r="!git rev-parse" r -- a{b}c >actual &&
184+
cat >expect <<-\EOF &&
185+
--
186+
a{b}c
187+
EOF
188+
test_cmp expect actual
189+
'
190+
181191
test_done

t/t5580-clone-push-unc.sh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ esac
3131

3232
test_expect_success 'clone into absolute path lacking a drive prefix' '
3333
USINGBACKSLASHES="$(echo "$WITHOUTDRIVE"/without-drive-prefix |
34-
tr / \\)" &&
34+
tr / \\\\)" &&
3535
git clone . "$USINGBACKSLASHES" &&
3636
test -f without-drive-prefix/.git/HEAD
3737
'
@@ -49,6 +49,11 @@ test_expect_success clone '
4949
git clone "file://$UNCPATH" clone
5050
'
5151

52+
test_expect_success 'clone with backslashed path' '
53+
BACKSLASHED="$(echo "$UNCPATH" | tr / \\\\)" &&
54+
git clone "$BACKSLASHED" backslashed
55+
'
56+
5257
test_expect_success push '
5358
(
5459
cd clone &&

0 commit comments

Comments
 (0)