Skip to content

Commit 44138c4

Browse files
dschoGit for Windows Build Agent
authored and
Git for Windows Build Agent
committed
Merge branch 'long-paths'
2 parents a36ba6c + 788d03b commit 44138c4

36 files changed

+1709
-139
lines changed

Documentation/config/advice.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ all advice messages.
6464
set their identity configuration.
6565
mergeConflict::
6666
Shown when various commands stop because of conflicts.
67+
nameTooLong::
68+
Advice shown if a filepath operation is attempted where the
69+
path was too long.
6770
nestedTag::
6871
Shown when a user attempts to recursively tag a tag object.
6972
pushAlreadyExists::

Documentation/config/core.adoc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,19 @@ relatively high IO latencies. When enabled, Git will do the
690690
index comparison to the filesystem data in parallel, allowing
691691
overlapping IO's. Defaults to true.
692692

693+
core.fscache::
694+
Enable additional caching of file system data for some operations.
695+
+
696+
Git for Windows uses this to bulk-read and cache lstat data of entire
697+
directories (instead of doing lstat file by file).
698+
699+
core.longpaths::
700+
Enable long path (> 260) support for builtin commands in Git for
701+
Windows. This is disabled by default, as long paths are not supported
702+
by Windows Explorer, cmd.exe and the Git for Windows tool chain
703+
(msys, bash, tcl, perl...). Only enable this if you know what you're
704+
doing and are prepared to live with a few quirks.
705+
693706
core.unsetenvvars::
694707
Windows-only: comma-separated list of environment variables'
695708
names that need to be unset before spawning any other process.

advice.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ static struct {
6161
[ADVICE_IGNORED_HOOK] = { "ignoredHook" },
6262
[ADVICE_IMPLICIT_IDENTITY] = { "implicitIdentity" },
6363
[ADVICE_MERGE_CONFLICT] = { "mergeConflict" },
64+
[ADVICE_NAME_TOO_LONG] = { "nameTooLong" },
6465
[ADVICE_NESTED_TAG] = { "nestedTag" },
6566
[ADVICE_OBJECT_NAME_WARNING] = { "objectNameWarning" },
6667
[ADVICE_PUSH_ALREADY_EXISTS] = { "pushAlreadyExists" },

advice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ enum advice_type {
2828
ADVICE_IGNORED_HOOK,
2929
ADVICE_IMPLICIT_IDENTITY,
3030
ADVICE_MERGE_CONFLICT,
31+
ADVICE_NAME_TOO_LONG,
3132
ADVICE_NESTED_TAG,
3233
ADVICE_OBJECT_NAME_WARNING,
3334
ADVICE_PUSH_ALREADY_EXISTS,

builtin/add.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,10 @@ int cmd_add(int argc,
476476
die_in_unpopulated_submodule(repo->index, prefix);
477477
die_path_inside_submodule(repo->index, &pathspec);
478478

479+
enable_fscache(0);
480+
/* We do not really re-read the index but update the up-to-date flags */
481+
preload_index(repo->index, &pathspec, 0);
482+
479483
if (add_new_files) {
480484
int baselen;
481485

@@ -588,5 +592,6 @@ int cmd_add(int argc,
588592
free(ps_matched);
589593
dir_clear(&dir);
590594
clear_pathspec(&pathspec);
595+
enable_fscache(0);
591596
return exit_status;
592597
}

builtin/checkout.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ static int checkout_worktree(const struct checkout_opts *opts,
408408
if (pc_workers > 1)
409409
init_parallel_checkout();
410410

411+
enable_fscache(the_repository->index->cache_nr);
411412
for (pos = 0; pos < the_repository->index->cache_nr; pos++) {
412413
struct cache_entry *ce = the_repository->index->cache[pos];
413414
if (ce->ce_flags & CE_MATCHED) {
@@ -433,6 +434,7 @@ static int checkout_worktree(const struct checkout_opts *opts,
433434
errs |= run_parallel_checkout(&state, pc_workers, pc_threshold,
434435
NULL, NULL);
435436
mem_pool_discard(&ce_mem_pool, should_validate_cache_entries());
437+
disable_fscache();
436438
remove_marked_cache_entries(the_repository->index, 1);
437439
remove_scheduled_dirs();
438440
errs |= finish_delayed_checkout(&state, opts->show_progress);

builtin/clean.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "pathspec.h"
2626
#include "help.h"
2727
#include "prompt.h"
28+
#include "advice.h"
2829

2930
static int require_force = -1; /* unset */
3031
static int interactive;
@@ -220,6 +221,9 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
220221
quote_path(path->buf, prefix, &quoted, 0);
221222
errno = saved_errno;
222223
warning_errno(_(msg_warn_remove_failed), quoted.buf);
224+
if (saved_errno == ENAMETOOLONG) {
225+
advise_if_enabled(ADVICE_NAME_TOO_LONG, _("Setting `core.longPaths` may allow the deletion to succeed."));
226+
}
223227
*dir_gone = 0;
224228
}
225229
ret = res;
@@ -255,6 +259,9 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
255259
quote_path(path->buf, prefix, &quoted, 0);
256260
errno = saved_errno;
257261
warning_errno(_(msg_warn_remove_failed), quoted.buf);
262+
if (saved_errno == ENAMETOOLONG) {
263+
advise_if_enabled(ADVICE_NAME_TOO_LONG, _("Setting `core.longPaths` may allow the deletion to succeed."));
264+
}
258265
*dir_gone = 0;
259266
ret = 1;
260267
}
@@ -298,6 +305,9 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
298305
quote_path(path->buf, prefix, &quoted, 0);
299306
errno = saved_errno;
300307
warning_errno(_(msg_warn_remove_failed), quoted.buf);
308+
if (saved_errno == ENAMETOOLONG) {
309+
advise_if_enabled(ADVICE_NAME_TOO_LONG, _("Setting `core.longPaths` may allow the deletion to succeed."));
310+
}
301311
*dir_gone = 0;
302312
ret = 1;
303313
}
@@ -1043,6 +1053,7 @@ int cmd_clean(int argc,
10431053

10441054
if (repo_read_index(the_repository) < 0)
10451055
die(_("index file corrupt"));
1056+
enable_fscache(the_repository->index->cache_nr);
10461057

10471058
pl = add_pattern_list(&dir, EXC_CMDL, "--exclude option");
10481059
for (i = 0; i < exclude_list.nr; i++)
@@ -1109,6 +1120,9 @@ int cmd_clean(int argc,
11091120
qname = quote_path(item->string, NULL, &buf, 0);
11101121
errno = saved_errno;
11111122
warning_errno(_(msg_warn_remove_failed), qname);
1123+
if (saved_errno == ENAMETOOLONG) {
1124+
advise_if_enabled(ADVICE_NAME_TOO_LONG, _("Setting `core.longPaths` may allow the deletion to succeed."));
1125+
}
11121126
errors++;
11131127
} else if (!quiet) {
11141128
qname = quote_path(item->string, NULL, &buf, 0);
@@ -1117,6 +1131,7 @@ int cmd_clean(int argc,
11171131
}
11181132
}
11191133

1134+
disable_fscache();
11201135
strbuf_release(&abs_path);
11211136
strbuf_release(&buf);
11221137
string_list_clear(&del_list, 0);

builtin/commit.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,6 +1602,7 @@ struct repository *repo UNUSED)
16021602
PATHSPEC_PREFER_FULL,
16031603
prefix, argv);
16041604

1605+
enable_fscache(0);
16051606
if (status_format != STATUS_FORMAT_PORCELAIN &&
16061607
status_format != STATUS_FORMAT_PORCELAIN_V2)
16071608
progress_flag = REFRESH_PROGRESS;
@@ -1642,6 +1643,7 @@ struct repository *repo UNUSED)
16421643
wt_status_print(&s);
16431644
wt_status_collect_free_buffers(&s);
16441645

1646+
disable_fscache();
16451647
return 0;
16461648
}
16471649

compat/fsmonitor/fsm-health-win32.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ struct fsm_health_data
3434

3535
struct wt_moved
3636
{
37-
wchar_t wpath[MAX_PATH + 1];
37+
wchar_t wpath[MAX_LONG_PATH + 1];
3838
BY_HANDLE_FILE_INFORMATION bhfi;
3939
} wt_moved;
4040
};
@@ -143,8 +143,8 @@ static int has_worktree_moved(struct fsmonitor_daemon_state *state,
143143
return 0;
144144

145145
case CTX_INIT:
146-
if (xutftowcs_path(data->wt_moved.wpath,
147-
state->path_worktree_watch.buf) < 0) {
146+
if (xutftowcs_long_path(data->wt_moved.wpath,
147+
state->path_worktree_watch.buf) < 0) {
148148
error(_("could not convert to wide characters: '%s'"),
149149
state->path_worktree_watch.buf);
150150
return -1;

compat/fsmonitor/fsm-listen-win32.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ struct one_watch
2828
DWORD count;
2929

3030
struct strbuf path;
31-
wchar_t wpath_longname[MAX_PATH + 1];
31+
wchar_t wpath_longname[MAX_LONG_PATH + 1];
3232
DWORD wpath_longname_len;
3333

3434
HANDLE hDir;
@@ -131,8 +131,8 @@ static int normalize_path_in_utf8(wchar_t *wpath, DWORD wpath_len,
131131
*/
132132
static void check_for_shortnames(struct one_watch *watch)
133133
{
134-
wchar_t buf_in[MAX_PATH + 1];
135-
wchar_t buf_out[MAX_PATH + 1];
134+
wchar_t buf_in[MAX_LONG_PATH + 1];
135+
wchar_t buf_out[MAX_LONG_PATH + 1];
136136
wchar_t *last;
137137
wchar_t *p;
138138

@@ -197,8 +197,8 @@ static enum get_relative_result get_relative_longname(
197197
const wchar_t *wpath, DWORD wpath_len,
198198
wchar_t *wpath_longname, size_t bufsize_wpath_longname)
199199
{
200-
wchar_t buf_in[2 * MAX_PATH + 1];
201-
wchar_t buf_out[MAX_PATH + 1];
200+
wchar_t buf_in[2 * MAX_LONG_PATH + 1];
201+
wchar_t buf_out[MAX_LONG_PATH + 1];
202202
DWORD root_len;
203203
DWORD out_len;
204204

@@ -298,10 +298,10 @@ static struct one_watch *create_watch(const char *path)
298298
FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE;
299299
HANDLE hDir;
300300
DWORD len_longname;
301-
wchar_t wpath[MAX_PATH + 1];
302-
wchar_t wpath_longname[MAX_PATH + 1];
301+
wchar_t wpath[MAX_LONG_PATH + 1];
302+
wchar_t wpath_longname[MAX_LONG_PATH + 1];
303303

304-
if (xutftowcs_path(wpath, path) < 0) {
304+
if (xutftowcs_long_path(wpath, path) < 0) {
305305
error(_("could not convert to wide characters: '%s'"), path);
306306
return NULL;
307307
}
@@ -545,7 +545,7 @@ static int process_worktree_events(struct fsmonitor_daemon_state *state)
545545
struct string_list cookie_list = STRING_LIST_INIT_DUP;
546546
struct fsmonitor_batch *batch = NULL;
547547
const char *p = watch->buffer;
548-
wchar_t wpath_longname[MAX_PATH + 1];
548+
wchar_t wpath_longname[MAX_LONG_PATH + 1];
549549

550550
/*
551551
* If the kernel gets more events than will fit in the kernel

compat/fsmonitor/fsm-path-utils-win32.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,16 @@ static int check_remote_protocol(wchar_t *wpath)
6969
*/
7070
int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
7171
{
72-
wchar_t wpath[MAX_PATH];
73-
wchar_t wfullpath[MAX_PATH];
72+
wchar_t wpath[MAX_LONG_PATH];
73+
wchar_t wfullpath[MAX_LONG_PATH];
7474
size_t wlen;
7575
UINT driveType;
7676

7777
/*
7878
* Do everything in wide chars because the drive letter might be
7979
* a multi-byte sequence. See win32_has_dos_drive_prefix().
8080
*/
81-
if (xutftowcs_path(wpath, path) < 0) {
81+
if (xutftowcs_long_path(wpath, path) < 0) {
8282
return -1;
8383
}
8484

@@ -97,7 +97,7 @@ int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
9797
* slashes to backslashes. This is essential to get GetDriveTypeW()
9898
* correctly handle some UNC "\\server\share\..." paths.
9999
*/
100-
if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) {
100+
if (!GetFullPathNameW(wpath, MAX_LONG_PATH, wfullpath, NULL)) {
101101
return -1;
102102
}
103103

0 commit comments

Comments
 (0)