Skip to content

Commit fb7bee9

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 b15e7bc + 4953fa4 commit fb7bee9

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

compat/mingw.c

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1069,7 +1069,7 @@ char *mingw_getcwd(char *pointer, int len)
10691069
* See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
10701070
* (Parsing C++ Command-Line Arguments)
10711071
*/
1072-
static const char *quote_arg(const char *arg)
1072+
static const char *quote_arg_msvc(const char *arg)
10731073
{
10741074
/* count chars to quote */
10751075
int len = 0, n = 0;
@@ -1124,6 +1124,37 @@ static const char *quote_arg(const char *arg)
11241124
return q;
11251125
}
11261126

1127+
#include "quote.h"
1128+
1129+
static const char *quote_arg_msys2(const char *arg)
1130+
{
1131+
struct strbuf buf = STRBUF_INIT;
1132+
const char *p2 = arg, *p;
1133+
1134+
for (p = arg; *p; p++) {
1135+
int ws = isspace(*p);
1136+
if (!ws && *p != '\\' && *p != '"')
1137+
continue;
1138+
if (!buf.len)
1139+
strbuf_addch(&buf, '"');
1140+
if (p != p2)
1141+
strbuf_add(&buf, p2, p - p2);
1142+
if (!ws)
1143+
strbuf_addch(&buf, '\\');
1144+
p2 = p;
1145+
}
1146+
1147+
if (p == arg)
1148+
strbuf_addch(&buf, '"');
1149+
else if (!buf.len)
1150+
return arg;
1151+
else
1152+
strbuf_add(&buf, p2, p - p2),
1153+
1154+
strbuf_addch(&buf, '"');
1155+
return strbuf_detach(&buf, 0);
1156+
}
1157+
11271158
static const char *parse_interpreter(const char *cmd)
11281159
{
11291160
static char buf[100];
@@ -1467,6 +1498,34 @@ static void kill_child_processes_on_signal(void)
14671498
LeaveCriticalSection(&pinfo_cs);
14681499
}
14691500

1501+
static int is_msys2_sh(const char *cmd)
1502+
{
1503+
if (cmd && !strcmp(cmd, "sh")) {
1504+
static int ret = -1;
1505+
char *p;
1506+
1507+
if (ret >= 0)
1508+
return ret;
1509+
1510+
p = path_lookup(cmd, 0);
1511+
if (!p)
1512+
ret = 0;
1513+
else {
1514+
size_t len = strlen(p);
1515+
ret = len > 15 &&
1516+
is_dir_sep(p[len - 15]) &&
1517+
!strncasecmp(p + len - 14, "usr", 3) &&
1518+
is_dir_sep(p[len - 11]) &&
1519+
!strncasecmp(p + len - 10, "bin", 3) &&
1520+
is_dir_sep(p[len - 7]) &&
1521+
!strcasecmp(p + len - 6, "sh.exe");
1522+
free(p);
1523+
}
1524+
return ret;
1525+
}
1526+
return 0;
1527+
}
1528+
14701529
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
14711530
const char *dir,
14721531
int prepend_cmd, int fhin, int fhout, int fherr)
@@ -1480,6 +1539,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
14801539
BOOL ret;
14811540
HANDLE cons;
14821541
const char *strace_env;
1542+
const char *(*quote_arg)(const char *arg) =
1543+
is_msys2_sh(*argv) ? quote_arg_msys2 : quote_arg_msvc;
14831544

14841545
if (!atexit_handler_initialized) {
14851546
atexit_handler_initialized = 1;

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)