Skip to content

Commit 40ff106

Browse files
committed
Fix error: "fatal: '$GIT_DIR' too big" when checking out in a long path on
Windows with core.longpaths = true. This is a fix for issue: #3372 Use case: Allow git to checkout a repository or submodule in a directory with a long path when core.longpaths = true. Example: > ./git.exe config --global core.longpaths true > ./git.exe clone https://github.com/git/git.git --recurse-submodules \ /c/eval/git_test/loooooooooooooooooooooooooooooooooooooooooooooooooooooooo\ oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\ oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\ oooooooong Context: $ sh --version GNU bash, version 4.4.23(1)-release (x86_64-pc-msys) $ ./git.exe --version --build-options git version 2.36.1.windows.1 cpu: x86_64 built from commit: e2ff68a sizeof-long: 4 sizeof-size_t: 8 shell-path: /bin/sh feature: fsmonitor--daemon Error: fatal: '$GIT_DIR' too big. Problem analysis: setup_explicit_git_dir in setup.c uses PATH_MAX to check if the git dir is to long. On Windows PATH_MAX is set by limit.h to 260 and setup_explicit_git_dir ignores core.longpaths. Solution: The implementation is based on the solution proposed by Johannes Schindelin, see: #3372 (comment) * Refactor the part of trace2_initialize() that reads the config. * Make tr2_sysenv_cb() a public function. * No longer calling it from trace2_initialize(), but from a static callback function in common-main.c. * Calling read_very_early_config() explicitly in main(), with that static callback function that calls into tr2_sysenv_cb(). * Extend the static callback function for Windows, and parse core.longPaths in that function. * Extend startup_info struct in cache.h with 'int max_long_path' so we can use it in setup_explicit_git_dir instead of PATH_MAX. Signed-off-by: Kevin Worm <[email protected]>
1 parent 590ade5 commit 40ff106

File tree

6 files changed

+34
-14
lines changed

6 files changed

+34
-14
lines changed

cache.h

+1
Original file line numberDiff line numberDiff line change
@@ -1869,6 +1869,7 @@ void overlay_tree_on_index(struct index_state *istate,
18691869

18701870
/* setup.c */
18711871
struct startup_info {
1872+
int max_long_path;
18721873
int have_repository;
18731874
const char *prefix;
18741875
const char *original_cwd;

common-main.c

+20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "cache.h"
2+
#include "config.h"
23
#include "exec-cmd.h"
34
#include "attr.h"
5+
#include "trace2/tr2_sysenv.h"
46

57
/*
68
* Many parts of Git have subprograms communicate via pipe, expect the
@@ -23,6 +25,21 @@ static void restore_sigpipe_to_default(void)
2325
signal(SIGPIPE, SIG_DFL);
2426
}
2527

28+
static int read_very_early_config_cb(const char *key, const char *value, void *d)
29+
{
30+
tr2_sysenv_cb(key, value, d);
31+
32+
#if defined(__MINGW32__)
33+
if (!strcmp(key, "core.longpaths") && git_config_bool(key, value)) {
34+
startup_info->max_long_path = MAX_LONG_PATH;
35+
}
36+
#else
37+
startup_info->max_long_path = PATH_MAX;
38+
#endif
39+
40+
return 0;
41+
}
42+
2643
int main(int argc, const char **argv)
2744
{
2845
int result;
@@ -47,6 +64,9 @@ int main(int argc, const char **argv)
4764
attr_start();
4865

4966
trace2_initialize();
67+
68+
read_very_early_config(read_very_early_config_cb, NULL);
69+
5070
trace2_cmd_start(argv);
5171
trace2_collect_process_info(TRACE2_PROCESS_INFO_STARTUP);
5272

setup.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -875,7 +875,7 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
875875
char *gitfile;
876876
int offset;
877877

878-
if (PATH_MAX - 40 < strlen(gitdirenv))
878+
if (startup_info->max_long_path - 40 < strlen(gitdirenv))
879879
die(_("'$%s' too big"), GIT_DIR_ENVIRONMENT);
880880

881881
gitfile = (char*)read_gitfile(gitdirenv);

trace2.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ void trace2_initialize_fl(const char *file, int line)
158158
if (trace2_enabled)
159159
return;
160160

161-
tr2_sysenv_load();
161+
tr2_sysenv_check_size();
162162

163163
if (!tr2_tgt_want_builtins())
164164
return;

trace2/tr2_sysenv.c

+9-11
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,14 @@ static struct tr2_sysenv_entry tr2_sysenv_settings[] = {
5757
};
5858
/* clang-format on */
5959

60-
static int tr2_sysenv_cb(const char *key, const char *value, void *d)
60+
/*
61+
* Load Trace2 settings from the system config (usually "/etc/gitconfig"
62+
* unless we were built with a runtime-prefix). These are intended to
63+
* define the default values for Trace2 as requested by the administrator.
64+
*
65+
* Then override with the Trace2 settings from the global config.
66+
*/
67+
int tr2_sysenv_cb(const char *key, const char *value, void *d)
6168
{
6269
int k;
6370

@@ -75,19 +82,10 @@ static int tr2_sysenv_cb(const char *key, const char *value, void *d)
7582
return 0;
7683
}
7784

78-
/*
79-
* Load Trace2 settings from the system config (usually "/etc/gitconfig"
80-
* unless we were built with a runtime-prefix). These are intended to
81-
* define the default values for Trace2 as requested by the administrator.
82-
*
83-
* Then override with the Trace2 settings from the global config.
84-
*/
85-
void tr2_sysenv_load(void)
85+
void tr2_sysenv_check_size(void)
8686
{
8787
if (ARRAY_SIZE(tr2_sysenv_settings) != TR2_SYSENV_MUST_BE_LAST)
8888
BUG("tr2_sysenv_settings size is wrong");
89-
90-
read_very_early_config(tr2_sysenv_cb, NULL);
9189
}
9290

9391
/*

trace2/tr2_sysenv.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ enum tr2_sysenv_variable {
3030
TR2_SYSENV_MUST_BE_LAST
3131
};
3232

33-
void tr2_sysenv_load(void);
33+
int tr2_sysenv_cb(const char *key, const char *value, void *d);
34+
void tr2_sysenv_check_size(void);
3435

3536
const char *tr2_sysenv_get(enum tr2_sysenv_variable);
3637
const char *tr2_sysenv_display_name(enum tr2_sysenv_variable var);

0 commit comments

Comments
 (0)