Skip to content

Commit 0de57fc

Browse files
committed
Merge branch 'kb/windows-wide-config'
2 parents 9c9dc30 + 303df68 commit 0de57fc

File tree

7 files changed

+112
-50
lines changed

7 files changed

+112
-50
lines changed

Documentation/config.txt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ the Git commands' behavior. The `.git/config` file in each repository
66
is used to store the configuration for that repository, and
77
`$HOME/.gitconfig` is used to store a per-user configuration as
88
fallback values for the `.git/config` file. The file `/etc/gitconfig`
9-
can be used to store a system-wide default configuration. On Windows,
10-
configuration can also be stored in `C:\ProgramData\Git\config`; This
11-
file will be used also by libgit2-based software.
9+
can be used to store a system-wide default configuration
10+
(`%PROGRAMDATA%\Git\gitconfig` on Windows).
1211

1312
The configuration variables are used by both the Git plumbing
1413
and the porcelains. The variables are divided into sections, wherein

Documentation/git-config.txt

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,14 @@ See also <<FILES>>.
117117

118118
--system::
119119
For writing options: write to system-wide
120-
`$(prefix)/etc/gitconfig` rather than the repository
120+
`/etc/gitconfig` rather than the repository
121121
`.git/config`.
122122
+
123-
For reading options: read only from system-wide `$(prefix)/etc/gitconfig`
123+
For reading options: read only from system-wide `/etc/gitconfig`
124124
rather than from all available files.
125125
+
126+
On Windows, the system-wide config file is `%PROGRAMDATA%\Git\gitconfig`.
127+
+
126128
See also <<FILES>>.
127129

128130
--local::
@@ -221,11 +223,21 @@ See also <<FILES>>.
221223
FILES
222224
-----
223225

224-
If not set explicitly with '--file', there are four files where
226+
If not set explicitly with '--file', there are five files where
225227
'git config' will search for configuration options:
226228

227229
$(prefix)/etc/gitconfig::
228-
System-wide configuration file.
230+
Installation-specific configuration file, where '$(prefix)' is the
231+
installation root directory specified via 'make prefix=...'. This allows
232+
software distributions to provide installation-specific default values
233+
(e.g. 'help.format=html' if the installation only includes html pages).
234+
235+
/etc/gitconfig::
236+
System-wide configuration file (`%PROGRAMDATA%\Git\gitconfig` on Windows).
237+
+
238+
If git was built with relative `$(sysconfdir)`, this file will not be
239+
used, and the '--system' option refers to the installation-specific
240+
`$(prefix)/etc/gitconfig` instead.
229241

230242
$XDG_CONFIG_HOME/git/config::
231243
Second user-specific configuration file. If $XDG_CONFIG_HOME is not set
@@ -268,11 +280,11 @@ ENVIRONMENT
268280
GIT_CONFIG::
269281
Take the configuration from the given file instead of .git/config.
270282
Using the "--global" option forces this to ~/.gitconfig. Using the
271-
"--system" option forces this to $(prefix)/etc/gitconfig.
283+
"--system" option forces this to /etc/gitconfig.
272284

273285
GIT_CONFIG_NOSYSTEM::
274-
Whether to skip reading settings from the system-wide
275-
$(prefix)/etc/gitconfig file. See linkgit:git[1] for details.
286+
Whether to skip reading settings from the installation-specific and
287+
system-wide /etc/gitconfig files. See linkgit:git[1] for details.
276288

277289
See also <<FILES>>.
278290

Documentation/git.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -939,8 +939,8 @@ for further details.
939939
on the terminal (e.g., when asking for HTTP authentication).
940940

941941
'GIT_CONFIG_NOSYSTEM'::
942-
Whether to skip reading settings from the system-wide
943-
`$(prefix)/etc/gitconfig` file. This environment variable can
942+
Whether to skip reading settings from the installation-specific and
943+
system-wide `/etc/gitconfig` files. This environment variable can
944944
be used along with `$HOME` and `$XDG_CONFIG_HOME` to create a
945945
predictable environment for a picky script, or you can set it
946946
temporarily to avoid using a buggy `/etc/gitconfig` file while

Documentation/gitattributes.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ for a single user should be placed in a file specified by the
8484
Its default value is $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME
8585
is either not set or empty, $HOME/.config/git/attributes is used instead.
8686
Attributes for all users on a system should be placed in the
87-
`$(prefix)/etc/gitattributes` file.
87+
`/etc/gitattributes` file (`%PROGRAMDATA%\Git\gitattributes` on Windows).
8888

8989
Sometimes you would need to override an setting of an attribute
9090
for a path to `Unspecified` state. This can be done by listing

config.c

Lines changed: 65 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,14 +1166,32 @@ static int git_config_from_blob_ref(config_fn_t fn,
11661166
return git_config_from_blob_sha1(fn, name, sha1, data);
11671167
}
11681168

1169+
static const char *etc_gitconfig = ETC_GITCONFIG;
1170+
11691171
const char *git_etc_gitconfig(void)
11701172
{
11711173
static const char *system_wide;
11721174
if (!system_wide)
1173-
system_wide = system_path(ETC_GITCONFIG);
1175+
system_wide = system_path(etc_gitconfig);
11741176
return system_wide;
11751177
}
11761178

1179+
static const char *git_inst_gitconfig(void)
1180+
{
1181+
static const char *installation_defaults;
1182+
if (!installation_defaults) {
1183+
/*
1184+
* if ETC_GITCONFIG as configured in the Makefile is an absolute path,
1185+
* also load installation-specific defaults (relative to $(prefix))
1186+
*/
1187+
if (is_dir_sep(*etc_gitconfig))
1188+
installation_defaults = system_path(etc_gitconfig + 1);
1189+
else
1190+
installation_defaults = "";
1191+
}
1192+
return *installation_defaults ? installation_defaults : NULL;
1193+
}
1194+
11771195
/*
11781196
* Parse environment variable 'k' as a boolean (in various
11791197
* possible spellings); if missing, use the default value 'def'.
@@ -1201,41 +1219,38 @@ int git_config_system(void)
12011219
return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
12021220
}
12031221

1222+
static inline int config_early_helper(config_fn_t fn, const char *filename,
1223+
void *data, unsigned access_flags, int count) {
1224+
if (!filename || access_or_die(filename, R_OK, access_flags))
1225+
/* no file: return unchanged */
1226+
return count;
1227+
1228+
if (git_config_from_file(fn, filename, data))
1229+
/* error: decrement or start counting errors at -1 */
1230+
return count < 0 ? count - 1 : -1;
1231+
else
1232+
/* ok: increment unless we had errors before */
1233+
return count < 0 ? count : count + 1;
1234+
}
1235+
12041236
int git_config_early(config_fn_t fn, void *data, const char *repo_config)
12051237
{
1206-
int ret = 0, found = 0;
1207-
const char *super_config = git_super_config();
1238+
/* count loaded files (> 0) or errors (< 0) */
1239+
int cnt = 0;
12081240
char *xdg_config = NULL;
12091241
char *user_config = NULL;
12101242

12111243
home_config_paths(&user_config, &xdg_config, "config");
12121244

1213-
if (super_config && git_config_system() &&
1214-
!access(super_config, R_OK)) {
1215-
ret += git_config_from_file(fn, super_config, data);
1216-
found += 1;
1245+
if (git_config_system()) {
1246+
cnt = config_early_helper(fn, git_inst_gitconfig(), data, 0, cnt);
1247+
cnt = config_early_helper(fn, git_etc_gitconfig(), data, 0, cnt);
12171248
}
12181249

1219-
if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0)) {
1220-
ret += git_config_from_file(fn, git_etc_gitconfig(),
1221-
data);
1222-
found += 1;
1223-
}
1250+
cnt = config_early_helper(fn, xdg_config, data, ACCESS_EACCES_OK, cnt);
1251+
cnt = config_early_helper(fn, user_config, data, ACCESS_EACCES_OK, cnt);
12241252

1225-
if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK)) {
1226-
ret += git_config_from_file(fn, xdg_config, data);
1227-
found += 1;
1228-
}
1229-
1230-
if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK)) {
1231-
ret += git_config_from_file(fn, user_config, data);
1232-
found += 1;
1233-
}
1234-
1235-
if (repo_config && !access_or_die(repo_config, R_OK, 0)) {
1236-
ret += git_config_from_file(fn, repo_config, data);
1237-
found += 1;
1238-
}
1253+
cnt = config_early_helper(fn, repo_config, data, 0, cnt);
12391254

12401255
switch (git_config_from_parameters(fn, data)) {
12411256
case -1: /* error */
@@ -1244,13 +1259,14 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
12441259
case 0: /* found nothing */
12451260
break;
12461261
default: /* found at least one item */
1247-
found++;
1262+
if (cnt >= 0)
1263+
cnt++;
12481264
break;
12491265
}
12501266

12511267
free(xdg_config);
12521268
free(user_config);
1253-
return ret == 0 ? found : ret;
1269+
return cnt;
12541270
}
12551271

12561272
int git_config_with_options(config_fn_t fn, void *data,
@@ -1932,6 +1948,24 @@ int git_config_parse_key(const char *key, char **store_key, int *baselen_)
19321948
return -CONFIG_INVALID_KEY;
19331949
}
19341950

1951+
1952+
static int lock_config_file(const char *config_filename,
1953+
struct lock_file **result)
1954+
{
1955+
int fd;
1956+
/* make sure the parent directory exists */
1957+
if (safe_create_leading_directories_const(config_filename)) {
1958+
error("could not create parent directory of %s", config_filename);
1959+
return -1;
1960+
}
1961+
*result = xcalloc(1, sizeof(struct lock_file));
1962+
fd = hold_lock_file_for_update(*result, config_filename, 0);
1963+
if (fd < 0)
1964+
error("could not lock config file %s: %s", config_filename,
1965+
strerror(errno));
1966+
return fd;
1967+
}
1968+
19351969
/*
19361970
* If value==NULL, unset in (remove from) config,
19371971
* if value_regex!=NULL, disregard key/value pairs where value does not match.
@@ -1980,10 +2014,8 @@ int git_config_set_multivar_in_file(const char *config_filename,
19802014
* The lock serves a purpose in addition to locking: the new
19812015
* contents of .git/config will be written into it.
19822016
*/
1983-
lock = xcalloc(1, sizeof(struct lock_file));
1984-
fd = hold_lock_file_for_update(lock, config_filename, 0);
2017+
fd = lock_config_file(config_filename, &lock);
19852018
if (fd < 0) {
1986-
error("could not lock config file %s: %s", config_filename, strerror(errno));
19872019
free(store.key);
19882020
ret = CONFIG_NO_LOCK;
19892021
goto out_free;
@@ -2251,12 +2283,9 @@ int git_config_rename_section_in_file(const char *config_filename,
22512283
if (!config_filename)
22522284
config_filename = filename_buf = git_pathdup("config");
22532285

2254-
lock = xcalloc(1, sizeof(struct lock_file));
2255-
out_fd = hold_lock_file_for_update(lock, config_filename, 0);
2256-
if (out_fd < 0) {
2257-
ret = error("could not lock config file %s", config_filename);
2286+
out_fd = lock_config_file(config_filename, &lock);
2287+
if (out_fd < 0)
22582288
goto out;
2259-
}
22602289

22612290
if (!(config_file = fopen(config_filename, "rb"))) {
22622291
/* no config file means nothing to rename, no error */

config.mak.uname

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ endif
330330
ifeq ($(uname_S),Windows)
331331
GIT_VERSION := $(GIT_VERSION).MSVC
332332
pathsep = ;
333+
sysconfdir = /etc
333334
HAVE_ALLOCA_H = YesPlease
334335
NO_PREAD = YesPlease
335336
NEEDS_CRYPTO_WITH_SSL = YesPlease
@@ -484,6 +485,7 @@ ifeq ($(uname_S),NONSTOP_KERNEL)
484485
endif
485486
ifneq (,$(findstring MINGW,$(uname_S)))
486487
pathsep = ;
488+
sysconfdir = /etc
487489
HAVE_ALLOCA_H = YesPlease
488490
NO_PREAD = YesPlease
489491
NEEDS_CRYPTO_WITH_SSL = YesPlease
@@ -532,6 +534,10 @@ ifneq (,$(findstring MINGW,$(uname_S)))
532534
ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
533535
htmldir = share/doc/git/$(firstword $(subst -, ,$(GIT_VERSION)))/html
534536
prefix =
537+
# prevent conversion to Windows path on MSys1 (see
538+
# http://www.mingw.org/wiki/Posix_path_conversion)
539+
ETC_GITCONFIG = //etc\gitconfig
540+
ETC_GITATTRIBUTES = //etc\gitattributes
535541
INSTALL = /bin/install
536542
EXTLIBS += /mingw/lib/libz.a
537543
NO_R_TO_GCC_LINKER = YesPlease

exec_cmd.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,24 @@ char *system_path(const char *path)
1515
#endif
1616
struct strbuf d = STRBUF_INIT;
1717

18-
if (is_absolute_path(path))
18+
if (is_absolute_path(path)) {
19+
#ifdef _WIN32
20+
/*
21+
* On Windows (all variants), replace '/etc/' with '%PROGRAMDATA%/Git/'
22+
* (or '%ALLUSERSPROFILE%/Git' in case of Windows XP)
23+
*/
24+
if (!strncmp(path, "/etc/", 5)) {
25+
const char *sysconfdir = getenv("PROGRAMDATA");
26+
if (!sysconfdir)
27+
sysconfdir = getenv("ALLUSERSPROFILE");
28+
if (sysconfdir) {
29+
strbuf_addf(&d, "%s/Git/%s", sysconfdir, path + 5);
30+
return strbuf_detach(&d, NULL);
31+
}
32+
}
33+
#endif
1934
return xstrdup(path);
35+
}
2036

2137
#ifdef RUNTIME_PREFIX
2238
assert(argv0_path);

0 commit comments

Comments
 (0)