Skip to content

Commit 6a3ea67

Browse files
committed
Merge branch 'long-paths'
2 parents f34ba77 + e2b2c87 commit 6a3ea67

37 files changed

+1733
-140
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
@@ -491,6 +491,10 @@ int cmd_add(int argc,
491491
die_in_unpopulated_submodule(repo->index, prefix);
492492
die_path_inside_submodule(repo->index, &pathspec);
493493

494+
enable_fscache(0);
495+
/* We do not really re-read the index but update the up-to-date flags */
496+
preload_index(repo->index, &pathspec, 0);
497+
494498
if (add_new_files) {
495499
int baselen;
496500

@@ -603,5 +607,6 @@ int cmd_add(int argc,
603607
free(ps_matched);
604608
dir_clear(&dir);
605609
clear_pathspec(&pathspec);
610+
enable_fscache(0);
606611
return exit_status;
607612
}

builtin/checkout.c

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

418+
enable_fscache(the_repository->index->cache_nr);
418419
for (pos = 0; pos < the_repository->index->cache_nr; pos++) {
419420
struct cache_entry *ce = the_repository->index->cache[pos];
420421
if (ce->ce_flags & CE_MATCHED) {
@@ -440,6 +441,7 @@ static int checkout_worktree(const struct checkout_opts *opts,
440441
errs |= run_parallel_checkout(&state, pc_workers, pc_threshold,
441442
NULL, NULL);
442443
mem_pool_discard(&ce_mem_pool, should_validate_cache_entries());
444+
disable_fscache();
443445
remove_marked_cache_entries(the_repository->index, 1);
444446
remove_scheduled_dirs();
445447
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
@@ -26,6 +26,7 @@
2626
#include "pathspec.h"
2727
#include "help.h"
2828
#include "prompt.h"
29+
#include "advice.h"
2930

3031
static int require_force = -1; /* unset */
3132
static int interactive;
@@ -221,6 +222,9 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
221222
quote_path(path->buf, prefix, &quoted, 0);
222223
errno = saved_errno;
223224
warning_errno(_(msg_warn_remove_failed), quoted.buf);
225+
if (saved_errno == ENAMETOOLONG) {
226+
advise_if_enabled(ADVICE_NAME_TOO_LONG, _("Setting `core.longPaths` may allow the deletion to succeed."));
227+
}
224228
*dir_gone = 0;
225229
}
226230
ret = res;
@@ -256,6 +260,9 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
256260
quote_path(path->buf, prefix, &quoted, 0);
257261
errno = saved_errno;
258262
warning_errno(_(msg_warn_remove_failed), quoted.buf);
263+
if (saved_errno == ENAMETOOLONG) {
264+
advise_if_enabled(ADVICE_NAME_TOO_LONG, _("Setting `core.longPaths` may allow the deletion to succeed."));
265+
}
259266
*dir_gone = 0;
260267
ret = 1;
261268
}
@@ -299,6 +306,9 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
299306
quote_path(path->buf, prefix, &quoted, 0);
300307
errno = saved_errno;
301308
warning_errno(_(msg_warn_remove_failed), quoted.buf);
309+
if (saved_errno == ENAMETOOLONG) {
310+
advise_if_enabled(ADVICE_NAME_TOO_LONG, _("Setting `core.longPaths` may allow the deletion to succeed."));
311+
}
302312
*dir_gone = 0;
303313
ret = 1;
304314
}
@@ -1044,6 +1054,7 @@ int cmd_clean(int argc,
10441054

10451055
if (repo_read_index(the_repository) < 0)
10461056
die(_("index file corrupt"));
1057+
enable_fscache(the_repository->index->cache_nr);
10471058

10481059
pl = add_pattern_list(&dir, EXC_CMDL, "--exclude option");
10491060
for (i = 0; i < exclude_list.nr; i++)
@@ -1110,6 +1121,9 @@ int cmd_clean(int argc,
11101121
qname = quote_path(item->string, NULL, &buf, 0);
11111122
errno = saved_errno;
11121123
warning_errno(_(msg_warn_remove_failed), qname);
1124+
if (saved_errno == ENAMETOOLONG) {
1125+
advise_if_enabled(ADVICE_NAME_TOO_LONG, _("Setting `core.longPaths` may allow the deletion to succeed."));
1126+
}
11131127
errors++;
11141128
} else if (!quiet) {
11151129
qname = quote_path(item->string, NULL, &buf, 0);
@@ -1118,6 +1132,7 @@ int cmd_clean(int argc,
11181132
}
11191133
}
11201134

1135+
disable_fscache();
11211136
strbuf_release(&abs_path);
11221137
strbuf_release(&buf);
11231138
string_list_clear(&del_list, 0);

builtin/commit.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,6 +1618,7 @@ struct repository *repo UNUSED)
16181618
PATHSPEC_PREFER_FULL,
16191619
prefix, argv);
16201620

1621+
enable_fscache(0);
16211622
if (status_format != STATUS_FORMAT_PORCELAIN &&
16221623
status_format != STATUS_FORMAT_PORCELAIN_V2)
16231624
progress_flag = REFRESH_PROGRESS;
@@ -1658,6 +1659,7 @@ struct repository *repo UNUSED)
16581659
wt_status_print(&s);
16591660
wt_status_collect_free_buffers(&s);
16601661

1662+
disable_fscache();
16611663
return 0;
16621664
}
16631665

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

0 commit comments

Comments
 (0)