Skip to content

Commit eedf61c

Browse files
SyntevoAlexdscho
andcommitted
mingw_strbuf_realpath(): handle case of non existent last path component
git often requests `strbuf_realpath(path + "/.git")`, where "./git" does not yet exist on disk. This causes the following to happen: 1. `mingw_strbuf_realpath()` fails 2. Non-mingw `strbuf_realpath()` does the work 3. Result of `strbuf_realpath()` is slightly different, for example it will not normalize the case of disk/folder names 4. `needs_work_tree_config()` becomes confused by these differences 5. clone adds `core.worktree` setting This in turn causes various problems, for example: 1. Repository folder can no longer be renamed/moved without breaking it 2. Using the repository on WSL (Windows Subsystem for Linux) doesn't work, because it has windows-style path saved This fixes #2569 Co-Authored-By: Johannes Schindelin <[email protected]> Signed-off-by: Alexandr Miloslavskiy <[email protected]>
1 parent a26dde4 commit eedf61c

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

compat/mingw.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,13 +1293,38 @@ char *mingw_strbuf_realpath(struct strbuf *resolved, const char *path)
12931293
HANDLE h;
12941294
DWORD ret;
12951295
int len;
1296+
const char *last_component = NULL;
12961297

12971298
if (xutftowcs_path(wpath, path) < 0)
12981299
return NULL;
12991300

13001301
h = CreateFileW(wpath, 0,
13011302
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
13021303
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1304+
1305+
/*
1306+
* strbuf_realpath() allows the last path component to not exist. If
1307+
* that is the case, now it's time to try without last component.
1308+
*/
1309+
if (h == INVALID_HANDLE_VALUE &&
1310+
GetLastError() == ERROR_FILE_NOT_FOUND) {
1311+
/* cut last component off of `wpath` */
1312+
wchar_t *p = wpath + wcslen(wpath);
1313+
1314+
while (p != wpath)
1315+
if (*(--p) == L'/' || *p == L'\\')
1316+
break; /* found start of last component */
1317+
1318+
if (p != wpath && (last_component = find_last_dir_sep(path))) {
1319+
last_component++; /* skip directory separator */
1320+
*p = L'\0';
1321+
h = CreateFileW(wpath, 0, FILE_SHARE_READ |
1322+
FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1323+
NULL, OPEN_EXISTING,
1324+
FILE_FLAG_BACKUP_SEMANTICS, NULL);
1325+
}
1326+
}
1327+
13031328
if (h == INVALID_HANDLE_VALUE)
13041329
return NULL;
13051330

@@ -1314,6 +1339,13 @@ char *mingw_strbuf_realpath(struct strbuf *resolved, const char *path)
13141339
if (len < 0)
13151340
return NULL;
13161341
resolved->len = len;
1342+
1343+
if (last_component) {
1344+
/* Use forward-slash, like `normalize_ntpath()` */
1345+
strbuf_addch(resolved, '/');
1346+
strbuf_addstr(resolved, last_component);
1347+
}
1348+
13171349
return resolved->buf;
13181350

13191351
}

t/t5601-clone.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ test_expect_success 'clone respects GIT_WORK_TREE' '
6868
6969
'
7070

71+
test_expect_success CASE_INSENSITIVE_FS 'core.worktree is not added due to path case' '
72+
73+
mkdir UPPERCASE &&
74+
git clone src "$(pwd)/uppercase" &&
75+
test "unset" = "$(git -C UPPERCASE config --default unset core.worktree)"
76+
'
77+
7178
test_expect_success 'clone from hooks' '
7279
7380
test_create_repo r0 &&

0 commit comments

Comments
 (0)