Skip to content

Commit be3a78c

Browse files
committed
repo: support safe.directory with %(prefix)/
Git for Windows does some truly bizarre things with paths that start with a forward slash; and expects you to escape that with `%(prefix)`. This syntax generally means to add the prefix that Git was installed to -- eg `/usr/local` -- unless it's an absolute path, in which case the leading `%(prefix)/` is just removed. And Git for Windows expects you to use this syntax for absolute Unix-style paths (in "Git Bash" or Windows Subsystem for Linux). Worse, the behavior used to be that a leading `/` was not absolute. It would indicate that Git for Windows should add the prefix. So `//` is required for absolute Unix-style paths. Yes, this is truly horrifying. Emulate that behavior, I guess, but only for absolute paths. We won't deal with the Git install prefix. Also, give WSL users an escape hatch where they don't have to think about this and can use the literal path that the filesystem APIs provide (`//wsl.localhost/...`).
1 parent 1be7064 commit be3a78c

1 file changed

Lines changed: 39 additions & 6 deletions

File tree

src/libgit2/repository.c

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -496,14 +496,47 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload)
496496
{
497497
validate_ownership_data *data = payload;
498498

499-
if (strcmp(entry->value, "") == 0)
499+
if (strcmp(entry->value, "") == 0) {
500500
*data->is_safe = false;
501-
502-
if (strcmp(entry->value, "*") == 0)
503-
*data->is_safe = true;
504-
else if (git_fs_path_prettify_dir(&data->tmp, entry->value, NULL) == 0 &&
505-
strcmp(data->tmp.ptr, data->repo_path) == 0)
501+
} else if (strcmp(entry->value, "*") == 0) {
506502
*data->is_safe = true;
503+
} else {
504+
const char *test_path = entry->value;
505+
506+
#ifdef GIT_WIN32
507+
/*
508+
* Git for Windows does some truly bizarre things with
509+
* paths that start with a forward slash; and expects you
510+
* to escape that with `%(prefix)`. This syntax generally
511+
* means to add the prefix that Git was installed to -- eg
512+
* `/usr/local` -- unless it's an absolute path, in which
513+
* case the leading `%(prefix)/` is just removed. And Git
514+
* for Windows expects you to use this syntax for absolute
515+
* Unix-style paths (in "Git Bash" or Windows Subsystem for
516+
* Linux).
517+
*
518+
* Worse, the behavior used to be that a leading `/` was
519+
* not absolute. It would indicate that Git for Windows
520+
* should add the prefix. So `//` is required for absolute
521+
* Unix-style paths. Yes, this is truly horrifying.
522+
*
523+
* Emulate that behavior, I guess, but only for absolute
524+
* paths. We won't deal with the Git install prefix. Also,
525+
* give WSL users an escape hatch where they don't have to
526+
* think about this and can use the literal path that the
527+
* filesystem APIs provide (`//wsl.localhost/...`).
528+
*/
529+
if (strncmp(test_path, "%(prefix)//", strlen("%(prefix)//")) == 0)
530+
test_path += strlen("%(prefix)/");
531+
else if (strncmp(test_path, "//", 2) == 0 &&
532+
strncmp(test_path, "//wsl.localhost/", strlen("//wsl.localhost/")) != 0)
533+
test_path++;
534+
#endif
535+
536+
if (git_fs_path_prettify_dir(&data->tmp, test_path, NULL) == 0 &&
537+
strcmp(data->tmp.ptr, data->repo_path) == 0)
538+
*data->is_safe = true;
539+
}
507540

508541
return 0;
509542
}

0 commit comments

Comments
 (0)