2005-11-17 21:32:36 +00:00
|
|
|
/*
|
|
|
|
* GIT - The information manager from hell
|
|
|
|
*
|
|
|
|
* Copyright (C) Linus Torvalds, 2005
|
|
|
|
* Copyright (C) Johannes Schindelin, 2005
|
|
|
|
*
|
|
|
|
*/
|
2005-10-10 23:31:08 +00:00
|
|
|
#include "cache.h"
|
date API: create a date.h, split from cache.h
Move the declaration of the date.c functions from cache.h, and adjust
the relevant users to include the new date.h header.
The show_ident_date() function belonged in pretty.h (it's defined in
pretty.c), its two users outside of pretty.c didn't strictly need to
include pretty.h, as they get it indirectly, but let's add it to them
anyway.
Similarly, the change to "builtin/{fast-import,show-branch,tag}.c"
isn't needed as far as the compiler is concerned, but since they all
use the "DATE_MODE()" macro we now define in date.h, let's have them
include it.
We could simply include this new header in "cache.h", but as this
change shows these functions weren't common enough to warrant
including in it in the first place. By moving them out of cache.h
changes to this API will no longer cause a (mostly) full re-build of
the project when "make" is run.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-16 08:14:02 +00:00
|
|
|
#include "date.h"
|
2018-08-15 17:54:07 +00:00
|
|
|
#include "branch.h"
|
2017-06-14 18:07:36 +00:00
|
|
|
#include "config.h"
|
2021-01-12 12:27:14 +00:00
|
|
|
#include "environment.h"
|
2017-06-22 18:43:42 +00:00
|
|
|
#include "repository.h"
|
2014-10-01 10:28:42 +00:00
|
|
|
#include "lockfile.h"
|
2018-04-10 21:26:18 +00:00
|
|
|
#include "exec-cmd.h"
|
2010-03-26 22:56:01 +00:00
|
|
|
#include "strbuf.h"
|
2010-08-23 19:16:00 +00:00
|
|
|
#include "quote.h"
|
2014-07-28 10:10:38 +00:00
|
|
|
#include "hashmap.h"
|
|
|
|
#include "string-list.h"
|
2018-05-15 23:42:15 +00:00
|
|
|
#include "object-store.h"
|
2015-04-16 17:47:45 +00:00
|
|
|
#include "utf8.h"
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
#include "dir.h"
|
2018-04-10 00:18:28 +00:00
|
|
|
#include "color.h"
|
2019-06-05 21:21:59 +00:00
|
|
|
#include "refs.h"
|
2022-02-07 21:33:00 +00:00
|
|
|
#include "worktree.h"
|
2005-10-10 23:31:08 +00:00
|
|
|
|
2013-07-11 22:44:39 +00:00
|
|
|
struct config_source {
|
|
|
|
struct config_source *prev;
|
|
|
|
union {
|
|
|
|
FILE *file;
|
2013-07-11 22:46:47 +00:00
|
|
|
struct config_buf {
|
|
|
|
const char *buf;
|
|
|
|
size_t len;
|
|
|
|
size_t pos;
|
|
|
|
} buf;
|
2013-07-11 22:44:39 +00:00
|
|
|
} u;
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
enum config_origin_type origin_type;
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
const char *name;
|
2014-02-18 22:58:52 +00:00
|
|
|
const char *path;
|
2018-06-28 22:05:00 +00:00
|
|
|
enum config_error_action default_error_action;
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
int linenr;
|
|
|
|
int eof;
|
config: reject parsing of files over INT_MAX
While the last few commits have made it possible for the config parser
to handle config files up to the limits of size_t, the rest of the code
isn't really ready for this. In particular, we often feed the keys as
strings into printf "%s" format specifiers. And because the printf
family of functions must return an int to specify the result, they
complain. Here are two concrete examples (using glibc; we're in
uncharted territory here so results may vary):
Generate a gigantic .gitmodules file like this:
git submodule add /some/other/repo foo
{
printf '[submodule "'
perl -e 'print "a" x 2**31'
echo '"]path = foo'
} >.gitmodules
git commit -m 'huge gitmodule'
then try this:
$ git show
BUG: strbuf.c:397: your vsnprintf is broken (returned -1)
The problem is that we end up calling:
strbuf_addf(&sb, "submodule.%s.ignore", submodule_name);
which relies on vsnprintf(), and that function has no way to report back
a size larger than INT_MAX.
Taking that same file, try this:
git config --file=.gitmodules --list --name-only
On my system it produces an output with exactly 4GB of spaces. I
confirmed in a debugger that we reach the config callback with the key
intact: it's 2147483663 bytes and full of a's. But when we print it with
this call:
printf("%s%c", key_, term);
we just get the spaces.
So given the fact that these are insane cases which we have no need to
support, the weird behavior from feeding the results to printf even if
the code is careful, and the possibility of uncareful code introducing
its own integer truncation issues, let's just declare INT_MAX as a limit
for parsing config files.
We'll enforce the limit in get_next_char(), which generalizes over all
sources (blobs, files, etc) and covers any element we're parsing
(whether section, key, value, etc). For simplicity, the limit is over
the length of the _whole_ file, so you couldn't have two 1GB values in
the same file. This should be perfectly fine, as the expected size for
config files is generally kilobytes at most.
With this patch both cases above will yield:
fatal: bad config line 1 in file .gitmodules
That's not an amazing error message, but the parser isn't set up to
provide specific messages (it just breaks out of the parsing loop and
gives that generic error even if see a syntactic issue). And we really
wouldn't expect to see this case outside of somebody maliciously probing
the limits of the config system.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-10 19:50:07 +00:00
|
|
|
size_t total_len;
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
struct strbuf value;
|
2012-09-30 19:44:36 +00:00
|
|
|
struct strbuf var;
|
2018-08-08 19:50:19 +00:00
|
|
|
unsigned subsection_case_sensitive : 1;
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
|
2013-08-26 21:57:18 +00:00
|
|
|
int (*do_fgetc)(struct config_source *c);
|
|
|
|
int (*do_ungetc)(int c, struct config_source *conf);
|
|
|
|
long (*do_ftell)(struct config_source *c);
|
2013-07-11 22:44:39 +00:00
|
|
|
};
|
|
|
|
|
2016-05-27 00:32:23 +00:00
|
|
|
/*
|
|
|
|
* These variables record the "current" config source, which
|
|
|
|
* can be accessed by parsing callbacks.
|
|
|
|
*
|
|
|
|
* The "cf" variable will be non-NULL only when we are actually parsing a real
|
|
|
|
* config source (file, blob, cmdline, etc).
|
|
|
|
*
|
|
|
|
* The "current_config_kvi" variable will be non-NULL only when we are feeding
|
|
|
|
* cached config from a configset into a callback.
|
|
|
|
*
|
|
|
|
* They should generally never be non-NULL at the same time. If they are both
|
|
|
|
* NULL, then we aren't parsing anything (and depending on the function looking
|
|
|
|
* at the variables, it's either a bug for it to be called in the first place,
|
|
|
|
* or it's a function which can be reused for non-config purposes, and should
|
|
|
|
* fall back to some sane behavior).
|
|
|
|
*/
|
2013-07-11 22:44:39 +00:00
|
|
|
static struct config_source *cf;
|
2016-05-27 00:32:23 +00:00
|
|
|
static struct key_value_info *current_config_kvi;
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
|
config: add a notion of "scope"
A config callback passed to git_config() doesn't know very
much about the context in which it sees a variable. It can
ask whether the variable comes from a file, and get the file
name. But without analyzing the filename (which is hard to
do accurately), it cannot tell whether it is in system-level
config, user-level config, or repo-specific config.
Generally this doesn't matter; the point of not passing this
to the callback is that it should treat the config the same
no matter where it comes from. But some programs, like
upload-pack, are a special case: we should be able to run
them in an untrusted repository, which means we cannot use
any "dangerous" config from the repository config file (but
it is OK to use it from system or user config).
This patch teaches the config code to record the "scope" of
each variable, and make it available inside config
callbacks, similar to how we give access to the filename.
The scope is the starting source for a particular parsing
operation, and remains the same even if we include other
files (so a .git/config which includes another file will
remain CONFIG_SCOPE_REPO, as it would be similarly
untrusted).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-05-18 22:44:23 +00:00
|
|
|
/*
|
|
|
|
* Similar to the variables above, this gives access to the "scope" of the
|
|
|
|
* current value (repo, global, etc). For cached values, it can be found via
|
|
|
|
* the current_config_kvi as above. During parsing, the current value can be
|
|
|
|
* found in this variable. It's not part of "cf" because it transcends a single
|
|
|
|
* file (i.e., a file included from .git/config is still in "repo" scope).
|
|
|
|
*/
|
|
|
|
static enum config_scope current_parsing_scope;
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
|
2016-11-16 01:42:40 +00:00
|
|
|
static int pack_compression_seen;
|
Custom compression levels for objects and packs
Add config variables pack.compression and core.loosecompression ,
and switch --compression=level to pack-objects.
Loose objects will be compressed using core.loosecompression if set,
else core.compression if set, else Z_BEST_SPEED.
Packed objects will be compressed using --compression=level if seen,
else pack.compression if set, else core.compression if set,
else Z_DEFAULT_COMPRESSION. This is the "pack compression level".
Loose objects added to a pack undeltified will be recompressed
to the pack compression level if it is unequal to the current
loose compression level by the preceding rules, or if the loose
object was written while core.legacyheaders = true. Newly
deltified loose objects are always compressed to the current
pack compression level.
Previously packed objects added to a pack are recompressed
to the current pack compression level exactly when their
deltification status changes, since the previous pack data
cannot be reused.
In either case, the --no-reuse-object switch from the first
patch below will always force recompression to the current pack
compression level, instead of assuming the pack compression level
hasn't changed and pack data can be reused when possible.
This applies on top of the following patches from Nicolas Pitre:
[PATCH] allow for undeltified objects not to be reused
[PATCH] make "repack -f" imply "pack-objects --no-reuse-object"
Signed-off-by: Dana L. How <danahow@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-09 20:56:50 +00:00
|
|
|
static int zlib_compression_seen;
|
|
|
|
|
config: learn `git_protected_config()`
`uploadpack.packObjectsHook` is the only 'protected configuration only'
variable today, but we've noted that `safe.directory` and the upcoming
`safe.bareRepository` should also be 'protected configuration only'. So,
for consistency, we'd like to have a single implementation for protected
configuration.
The primary constraints are:
1. Reading from protected configuration should be fast. Nearly all "git"
commands inside a bare repository will read both `safe.directory` and
`safe.bareRepository`, so we cannot afford to be slow.
2. Protected configuration must be readable when the gitdir is not
known. `safe.directory` and `safe.bareRepository` both affect
repository discovery and the gitdir is not known at that point [1].
The chosen implementation in this commit is to read protected
configuration and cache the values in a global configset. This is
similar to the caching behavior we get with the_repository->config.
Introduce git_protected_config(), which reads protected configuration
and caches them in the global configset protected_config. Then, refactor
`uploadpack.packObjectsHook` to use git_protected_config().
The protected configuration functions are named similarly to their
non-protected counterparts, e.g. git_protected_config_check_init() vs
git_config_check_init().
In light of constraint 1, this implementation can still be improved.
git_protected_config() iterates through every variable in
protected_config, which is wasteful, but it makes the conversion simple
because it matches existing patterns. We will likely implement constant
time lookup functions for protected configuration in a future series
(such functions already exist for non-protected configuration, i.e.
repo_config_get_*()).
An alternative that avoids introducing another configset is to continue
to read all config using git_config(), but only accept values that have
the correct config scope [2]. This technically fulfills constraint 2,
because git_config() simply ignores the local and worktree config when
the gitdir is not known. However, this would read incomplete config into
the_repository->config, which would need to be reset when the gitdir is
known and git_config() needs to read the local and worktree config.
Resetting the_repository->config might be reasonable while we only have
these 'protected configuration only' variables, but it's not clear
whether this extends well to future variables.
[1] In this case, we do have a candidate gitdir though, so with a little
refactoring, it might be possible to provide a gitdir.
[2] This is how `uploadpack.packObjectsHook` was implemented prior to
this commit.
Signed-off-by: Glen Choo <chooglen@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-14 21:27:59 +00:00
|
|
|
/*
|
|
|
|
* Config that comes from trusted scopes, namely:
|
|
|
|
* - CONFIG_SCOPE_SYSTEM (e.g. /etc/gitconfig)
|
|
|
|
* - CONFIG_SCOPE_GLOBAL (e.g. $HOME/.gitconfig, $XDG_CONFIG_HOME/git)
|
|
|
|
* - CONFIG_SCOPE_COMMAND (e.g. "-c" option, environment variables)
|
|
|
|
*
|
|
|
|
* This is declared here for code cleanliness, but unlike the other
|
|
|
|
* static variables, this does not hold config parser state.
|
|
|
|
*/
|
|
|
|
static struct config_set protected_config;
|
|
|
|
|
2013-07-11 22:44:39 +00:00
|
|
|
static int config_file_fgetc(struct config_source *conf)
|
|
|
|
{
|
2015-04-16 08:51:18 +00:00
|
|
|
return getc_unlocked(conf->u.file);
|
2013-07-11 22:44:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int config_file_ungetc(int c, struct config_source *conf)
|
|
|
|
{
|
|
|
|
return ungetc(c, conf->u.file);
|
|
|
|
}
|
|
|
|
|
|
|
|
static long config_file_ftell(struct config_source *conf)
|
|
|
|
{
|
|
|
|
return ftell(conf->u.file);
|
|
|
|
}
|
|
|
|
|
2013-07-11 22:46:47 +00:00
|
|
|
|
|
|
|
static int config_buf_fgetc(struct config_source *conf)
|
|
|
|
{
|
|
|
|
if (conf->u.buf.pos < conf->u.buf.len)
|
|
|
|
return conf->u.buf.buf[conf->u.buf.pos++];
|
|
|
|
|
|
|
|
return EOF;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int config_buf_ungetc(int c, struct config_source *conf)
|
|
|
|
{
|
config_buf_ungetc: warn when pushing back a random character
Our config code simulates a stdio stream around a buffer,
but our fake ungetc() does not behave quite like the real
one. In particular, we only rewind the position by one
character, but do _not_ actually put the character from the
caller into position.
It turns out that this does not matter, because we only ever
push back the character we just read. In other words, such
an assignment would be a noop. But because the function is
called ungetc, and because it takes a character parameter,
it is a mistake waiting to happen.
Actually assigning the character into the buffer would be
ideal, but our pointer is actually a "const" copy of the
buffer. We do not know who the real owner of the buffer is
in this code, and would not want to munge their contents.
Instead, we can simply add an assertion that matches what
the current caller does, and will let us know if new callers
are added that violate the contract.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-02-05 21:00:24 +00:00
|
|
|
if (conf->u.buf.pos > 0) {
|
|
|
|
conf->u.buf.pos--;
|
|
|
|
if (conf->u.buf.buf[conf->u.buf.pos] != c)
|
2018-05-02 09:38:39 +00:00
|
|
|
BUG("config_buf can only ungetc the same character");
|
config_buf_ungetc: warn when pushing back a random character
Our config code simulates a stdio stream around a buffer,
but our fake ungetc() does not behave quite like the real
one. In particular, we only rewind the position by one
character, but do _not_ actually put the character from the
caller into position.
It turns out that this does not matter, because we only ever
push back the character we just read. In other words, such
an assignment would be a noop. But because the function is
called ungetc, and because it takes a character parameter,
it is a mistake waiting to happen.
Actually assigning the character into the buffer would be
ideal, but our pointer is actually a "const" copy of the
buffer. We do not know who the real owner of the buffer is
in this code, and would not want to munge their contents.
Instead, we can simply add an assertion that matches what
the current caller does, and will let us know if new callers
are added that violate the contract.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-02-05 21:00:24 +00:00
|
|
|
return c;
|
|
|
|
}
|
2013-07-11 22:46:47 +00:00
|
|
|
|
|
|
|
return EOF;
|
|
|
|
}
|
|
|
|
|
|
|
|
static long config_buf_ftell(struct config_source *conf)
|
|
|
|
{
|
|
|
|
return conf->u.buf.pos;
|
|
|
|
}
|
|
|
|
|
2022-01-18 17:47:39 +00:00
|
|
|
struct config_include_data {
|
|
|
|
int depth;
|
|
|
|
config_fn_t fn;
|
|
|
|
void *data;
|
|
|
|
const struct config_options *opts;
|
2022-01-18 17:47:40 +00:00
|
|
|
struct git_config_source *config_source;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* All remote URLs discovered when reading all config files.
|
|
|
|
*/
|
|
|
|
struct string_list *remote_urls;
|
2022-01-18 17:47:39 +00:00
|
|
|
};
|
|
|
|
#define CONFIG_INCLUDE_INIT { 0 }
|
|
|
|
|
|
|
|
static int git_config_include(const char *var, const char *value, void *data);
|
|
|
|
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
#define MAX_INCLUDE_DEPTH 10
|
2018-07-21 07:49:27 +00:00
|
|
|
static const char include_depth_advice[] = N_(
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
"exceeded maximum include depth (%d) while including\n"
|
|
|
|
" %s\n"
|
|
|
|
"from\n"
|
|
|
|
" %s\n"
|
2018-08-23 21:00:56 +00:00
|
|
|
"This might be due to circular includes.");
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
static int handle_path_include(const char *path, struct config_include_data *inc)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
2014-01-28 01:37:30 +00:00
|
|
|
char *expanded;
|
2012-04-25 12:00:36 +00:00
|
|
|
|
2014-01-28 01:37:30 +00:00
|
|
|
if (!path)
|
|
|
|
return config_error_nonbool("include.path");
|
|
|
|
|
2021-07-24 22:06:52 +00:00
|
|
|
expanded = interpolate_path(path, 0);
|
2012-04-25 12:00:36 +00:00
|
|
|
if (!expanded)
|
2018-07-21 07:49:27 +00:00
|
|
|
return error(_("could not expand include path '%s'"), path);
|
2012-04-25 12:00:36 +00:00
|
|
|
path = expanded;
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Use an absolute path as-is, but interpret relative paths
|
|
|
|
* based on the including config file.
|
|
|
|
*/
|
|
|
|
if (!is_absolute_path(path)) {
|
|
|
|
char *slash;
|
|
|
|
|
2021-10-21 19:54:14 +00:00
|
|
|
if (!cf || !cf->path) {
|
|
|
|
ret = error(_("relative config includes must come from files"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
|
2014-02-18 22:58:52 +00:00
|
|
|
slash = find_last_dir_sep(cf->path);
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
if (slash)
|
2014-02-18 22:58:52 +00:00
|
|
|
strbuf_add(&buf, cf->path, slash - cf->path + 1);
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
strbuf_addstr(&buf, path);
|
|
|
|
path = buf.buf;
|
|
|
|
}
|
|
|
|
|
config: allow inaccessible configuration under $HOME
The changes v1.7.12.1~2^2~4 (config: warn on inaccessible files,
2012-08-21) and v1.8.1.1~22^2~2 (config: treat user and xdg config
permission problems as errors, 2012-10-13) were intended to prevent
important configuration (think "[transfer] fsckobjects") from being
ignored when the configuration is unintentionally unreadable (for
example with EIO on a flaky filesystem, or with ENOMEM due to a DoS
attack). Usually ~/.gitconfig and ~/.config/git are readable by the
current user, and if they aren't then it would be easy to fix those
permissions, so the damage from adding this check should have been
minimal.
Unfortunately the access() check often trips when git is being run as
a server. A daemon (such as inetd or git-daemon) starts as "root",
creates a listening socket, and then drops privileges, meaning that
when git commands are invoked they cannot access $HOME and die with
fatal: unable to access '/root/.config/git/config': Permission denied
Any patch to fix this would have one of three problems:
1. We annoy sysadmins who need to take an extra step to handle HOME
when dropping privileges (the current behavior, or any other
proposal that they have to opt into).
2. We annoy sysadmins who want to set HOME when dropping privileges,
either by making what they want to do impossible, or making them
set an extra variable or option to accomplish what used to work
(e.g., a patch to git-daemon to set HOME when --user is passed).
3. We loosen the check, so some cases which might be noteworthy are
not caught.
This patch is of type (3).
Treat user and xdg configuration that are inaccessible due to
permissions (EACCES) as though no user configuration was provided at
all.
An alternative method would be to check if $HOME is readable, but that
would not help in cases where the user who dropped privileges had a
globally readable HOME with only .config or .gitconfig being private.
This does not change the behavior when /etc/gitconfig or .git/config
is unreadable (since those are more serious configuration errors),
nor when ~/.gitconfig or ~/.config/git is unreadable due to problems
other than permissions.
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Improved-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-12 21:03:18 +00:00
|
|
|
if (!access_or_die(path, R_OK, 0)) {
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
if (++inc->depth > MAX_INCLUDE_DEPTH)
|
2018-07-21 07:49:27 +00:00
|
|
|
die(_(include_depth_advice), MAX_INCLUDE_DEPTH, path,
|
2016-05-18 22:41:08 +00:00
|
|
|
!cf ? "<unknown>" :
|
|
|
|
cf->name ? cf->name :
|
|
|
|
"the command line");
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
ret = git_config_from_file(git_config_include, path, inc);
|
|
|
|
inc->depth--;
|
|
|
|
}
|
2021-10-21 19:54:14 +00:00
|
|
|
cleanup:
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
strbuf_release(&buf);
|
2012-04-25 12:00:36 +00:00
|
|
|
free(expanded);
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-06-05 21:21:59 +00:00
|
|
|
static void add_trailing_starstar_for_dir(struct strbuf *pat)
|
|
|
|
{
|
|
|
|
if (pat->len && is_dir_sep(pat->buf[pat->len - 1]))
|
|
|
|
strbuf_addstr(pat, "**");
|
|
|
|
}
|
|
|
|
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
static int prepare_include_condition_pattern(struct strbuf *pat)
|
|
|
|
{
|
|
|
|
struct strbuf path = STRBUF_INIT;
|
|
|
|
char *expanded;
|
|
|
|
int prefix = 0;
|
|
|
|
|
2021-07-24 22:06:52 +00:00
|
|
|
expanded = interpolate_path(pat->buf, 1);
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
if (expanded) {
|
|
|
|
strbuf_reset(pat);
|
|
|
|
strbuf_addstr(pat, expanded);
|
|
|
|
free(expanded);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pat->buf[0] == '.' && is_dir_sep(pat->buf[1])) {
|
|
|
|
const char *slash;
|
|
|
|
|
|
|
|
if (!cf || !cf->path)
|
|
|
|
return error(_("relative config include "
|
|
|
|
"conditionals must come from files"));
|
|
|
|
|
2017-04-05 10:24:39 +00:00
|
|
|
strbuf_realpath(&path, cf->path, 1);
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
slash = find_last_dir_sep(path.buf);
|
|
|
|
if (!slash)
|
2018-05-02 09:38:39 +00:00
|
|
|
BUG("how is this possible?");
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
strbuf_splice(pat, 0, 1, path.buf, slash - path.buf);
|
|
|
|
prefix = slash - path.buf + 1 /* slash */;
|
|
|
|
} else if (!is_absolute_path(pat->buf))
|
2020-02-09 13:44:23 +00:00
|
|
|
strbuf_insertstr(pat, 0, "**/");
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
|
2019-06-05 21:21:59 +00:00
|
|
|
add_trailing_starstar_for_dir(pat);
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
|
|
|
|
strbuf_release(&path);
|
|
|
|
return prefix;
|
|
|
|
}
|
|
|
|
|
2017-04-17 10:10:01 +00:00
|
|
|
static int include_by_gitdir(const struct config_options *opts,
|
|
|
|
const char *cond, size_t cond_len, int icase)
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
{
|
|
|
|
struct strbuf text = STRBUF_INIT;
|
|
|
|
struct strbuf pattern = STRBUF_INIT;
|
|
|
|
int ret = 0, prefix;
|
2017-04-17 10:10:01 +00:00
|
|
|
const char *git_dir;
|
2017-05-16 08:28:46 +00:00
|
|
|
int already_tried_absolute = 0;
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
|
2017-04-17 10:10:01 +00:00
|
|
|
if (opts->git_dir)
|
|
|
|
git_dir = opts->git_dir;
|
|
|
|
else
|
|
|
|
goto done;
|
|
|
|
|
2017-04-26 06:39:05 +00:00
|
|
|
strbuf_realpath(&text, git_dir, 1);
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
strbuf_add(&pattern, cond, cond_len);
|
|
|
|
prefix = prepare_include_condition_pattern(&pattern);
|
|
|
|
|
2017-05-16 08:28:46 +00:00
|
|
|
again:
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
if (prefix < 0)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
if (prefix > 0) {
|
|
|
|
/*
|
|
|
|
* perform literal matching on the prefix part so that
|
|
|
|
* any wildcard character in it can't create side effects.
|
|
|
|
*/
|
|
|
|
if (text.len < prefix)
|
|
|
|
goto done;
|
|
|
|
if (!icase && strncmp(pattern.buf, text.buf, prefix))
|
|
|
|
goto done;
|
|
|
|
if (icase && strncasecmp(pattern.buf, text.buf, prefix))
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = !wildmatch(pattern.buf + prefix, text.buf + prefix,
|
2019-03-26 09:41:01 +00:00
|
|
|
WM_PATHNAME | (icase ? WM_CASEFOLD : 0));
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
|
2017-05-16 08:28:46 +00:00
|
|
|
if (!ret && !already_tried_absolute) {
|
|
|
|
/*
|
|
|
|
* We've tried e.g. matching gitdir:~/work, but if
|
|
|
|
* ~/work is a symlink to /mnt/storage/work
|
|
|
|
* strbuf_realpath() will expand it, so the rule won't
|
|
|
|
* match. Let's match against a
|
|
|
|
* strbuf_add_absolute_path() version of the path,
|
|
|
|
* which'll do the right thing
|
|
|
|
*/
|
|
|
|
strbuf_reset(&text);
|
|
|
|
strbuf_add_absolute_path(&text, git_dir);
|
|
|
|
already_tried_absolute = 1;
|
|
|
|
goto again;
|
|
|
|
}
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
done:
|
|
|
|
strbuf_release(&pattern);
|
|
|
|
strbuf_release(&text);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-06-05 21:21:59 +00:00
|
|
|
static int include_by_branch(const char *cond, size_t cond_len)
|
|
|
|
{
|
|
|
|
int flags;
|
|
|
|
int ret;
|
|
|
|
struct strbuf pattern = STRBUF_INIT;
|
2019-08-06 12:27:58 +00:00
|
|
|
const char *refname = !the_repository->gitdir ?
|
config: work around bug with includeif:onbranch and early config
Since 07b2c0eacac (config: learn the "onbranch:" includeIf condition,
2019-06-05), there is a potential catch-22 in the early config path: if
the `include.onbranch:` feature is used, Git assumes that the Git
directory has been initialized already. However, in the early config
code path that is not true.
One way to trigger this is to call the following commands in any
repository:
git config includeif.onbranch:refs/heads/master.path broken
git help -a
The symptom triggered by the `git help -a` invocation reads like this:
BUG: refs.c:1851: attempting to get main_ref_store outside of repository
Let's work around this, simply by ignoring the `includeif.onbranch:`
setting when parsing the config when the ref store has not been
initialized (yet).
Technically, there is a way to solve this properly: teach the refs
machinery to initialize the ref_store from a given gitdir/commondir pair
(which we _do_ have in the early config code path), and then use that in
`include_by_branch()`. This, however, is a pretty involved project, and
we're already in the feature freeze for Git v2.23.0.
Note: when calling above-mentioned two commands _outside_ of any Git
worktree (passing the `--global` flag to `git config`, as there is
obviously no repository config available), at the point when
`include_by_branch()` is called, `the_repository` is `NULL`, therefore
we have to be extra careful not to dereference it in that case.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-07-31 20:06:42 +00:00
|
|
|
NULL : resolve_ref_unsafe("HEAD", 0, NULL, &flags);
|
2019-06-05 21:21:59 +00:00
|
|
|
const char *shortname;
|
|
|
|
|
|
|
|
if (!refname || !(flags & REF_ISSYMREF) ||
|
|
|
|
!skip_prefix(refname, "refs/heads/", &shortname))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
strbuf_add(&pattern, cond, cond_len);
|
|
|
|
add_trailing_starstar_for_dir(&pattern);
|
|
|
|
ret = !wildmatch(pattern.buf, shortname, WM_PATHNAME);
|
|
|
|
strbuf_release(&pattern);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-01-18 17:47:40 +00:00
|
|
|
static int add_remote_url(const char *var, const char *value, void *data)
|
|
|
|
{
|
|
|
|
struct string_list *remote_urls = data;
|
|
|
|
const char *remote_name;
|
|
|
|
size_t remote_name_len;
|
|
|
|
const char *key;
|
|
|
|
|
|
|
|
if (!parse_config_key(var, "remote", &remote_name, &remote_name_len,
|
|
|
|
&key) &&
|
|
|
|
remote_name &&
|
|
|
|
!strcmp(key, "url"))
|
|
|
|
string_list_append(remote_urls, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void populate_remote_urls(struct config_include_data *inc)
|
|
|
|
{
|
|
|
|
struct config_options opts;
|
|
|
|
|
|
|
|
struct config_source *store_cf = cf;
|
|
|
|
struct key_value_info *store_kvi = current_config_kvi;
|
|
|
|
enum config_scope store_scope = current_parsing_scope;
|
|
|
|
|
|
|
|
opts = *inc->opts;
|
|
|
|
opts.unconditional_remote_url = 1;
|
|
|
|
|
|
|
|
cf = NULL;
|
|
|
|
current_config_kvi = NULL;
|
|
|
|
current_parsing_scope = 0;
|
|
|
|
|
|
|
|
inc->remote_urls = xmalloc(sizeof(*inc->remote_urls));
|
|
|
|
string_list_init_dup(inc->remote_urls);
|
|
|
|
config_with_options(add_remote_url, inc->remote_urls, inc->config_source, &opts);
|
|
|
|
|
|
|
|
cf = store_cf;
|
|
|
|
current_config_kvi = store_kvi;
|
|
|
|
current_parsing_scope = store_scope;
|
|
|
|
}
|
|
|
|
|
2022-08-25 17:09:48 +00:00
|
|
|
static int forbid_remote_url(const char *var, const char *value UNUSED,
|
|
|
|
void *data UNUSED)
|
2022-01-18 17:47:40 +00:00
|
|
|
{
|
|
|
|
const char *remote_name;
|
|
|
|
size_t remote_name_len;
|
|
|
|
const char *key;
|
|
|
|
|
|
|
|
if (!parse_config_key(var, "remote", &remote_name, &remote_name_len,
|
|
|
|
&key) &&
|
|
|
|
remote_name &&
|
|
|
|
!strcmp(key, "url"))
|
|
|
|
die(_("remote URLs cannot be configured in file directly or indirectly included by includeIf.hasconfig:remote.*.url"));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int at_least_one_url_matches_glob(const char *glob, int glob_len,
|
|
|
|
struct string_list *remote_urls)
|
|
|
|
{
|
|
|
|
struct strbuf pattern = STRBUF_INIT;
|
|
|
|
struct string_list_item *url_item;
|
|
|
|
int found = 0;
|
|
|
|
|
|
|
|
strbuf_add(&pattern, glob, glob_len);
|
|
|
|
for_each_string_list_item(url_item, remote_urls) {
|
|
|
|
if (!wildmatch(pattern.buf, url_item->string, WM_PATHNAME)) {
|
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
strbuf_release(&pattern);
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int include_by_remote_url(struct config_include_data *inc,
|
|
|
|
const char *cond, size_t cond_len)
|
|
|
|
{
|
|
|
|
if (inc->opts->unconditional_remote_url)
|
|
|
|
return 1;
|
|
|
|
if (!inc->remote_urls)
|
|
|
|
populate_remote_urls(inc);
|
|
|
|
return at_least_one_url_matches_glob(cond, cond_len,
|
|
|
|
inc->remote_urls);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int include_condition_is_true(struct config_include_data *inc,
|
2017-04-17 10:10:01 +00:00
|
|
|
const char *cond, size_t cond_len)
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
{
|
2022-01-18 17:47:40 +00:00
|
|
|
const struct config_options *opts = inc->opts;
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
|
|
|
|
if (skip_prefix_mem(cond, cond_len, "gitdir:", &cond, &cond_len))
|
2017-04-17 10:10:01 +00:00
|
|
|
return include_by_gitdir(opts, cond, cond_len, 0);
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", &cond, &cond_len))
|
2017-04-17 10:10:01 +00:00
|
|
|
return include_by_gitdir(opts, cond, cond_len, 1);
|
2019-06-05 21:21:59 +00:00
|
|
|
else if (skip_prefix_mem(cond, cond_len, "onbranch:", &cond, &cond_len))
|
|
|
|
return include_by_branch(cond, cond_len);
|
2022-01-18 17:47:40 +00:00
|
|
|
else if (skip_prefix_mem(cond, cond_len, "hasconfig:remote.*.url:", &cond,
|
|
|
|
&cond_len))
|
|
|
|
return include_by_remote_url(inc, cond, cond_len);
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
|
|
|
|
/* unknown conditionals are always false */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-01-18 17:47:39 +00:00
|
|
|
static int git_config_include(const char *var, const char *value, void *data)
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
{
|
|
|
|
struct config_include_data *inc = data;
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
const char *cond, *key;
|
2020-04-10 19:44:28 +00:00
|
|
|
size_t cond_len;
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pass along all values, including "include" directives; this makes it
|
|
|
|
* possible to query information on the includes themselves.
|
|
|
|
*/
|
|
|
|
ret = inc->fn(var, value, inc->data);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2014-08-30 16:07:05 +00:00
|
|
|
if (!strcmp(var, "include.path"))
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
ret = handle_path_include(value, inc);
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
|
|
|
|
if (!parse_config_key(var, "includeif", &cond, &cond_len, &key) &&
|
2022-01-18 17:47:40 +00:00
|
|
|
cond && include_condition_is_true(inc, cond, cond_len) &&
|
|
|
|
!strcmp(key, "path")) {
|
|
|
|
config_fn_t old_fn = inc->fn;
|
|
|
|
|
|
|
|
if (inc->opts->unconditional_remote_url)
|
|
|
|
inc->fn = forbid_remote_url;
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
ret = handle_path_include(value, inc);
|
2022-01-18 17:47:40 +00:00
|
|
|
inc->fn = old_fn;
|
|
|
|
}
|
config: add conditional include
Sometimes a set of repositories want to share configuration settings
among themselves that are distinct from other such sets of repositories.
A user may work on two projects, each of which have multiple
repositories, and use one user.email for one project while using another
for the other.
Setting $GIT_DIR/.config works, but if the penalty of forgetting to
update $GIT_DIR/.config is high (especially when you end up cloning
often), it may not be the best way to go. Having the settings in
~/.gitconfig, which would work for just one set of repositories, would
not well in such a situation. Having separate ${HOME}s may add more
problems than it solves.
Extend the include.path mechanism that lets a config file include
another config file, so that the inclusion can be done only when some
conditions hold. Then ~/.gitconfig can say "include config-project-A
only when working on project-A" for each project A the user works on.
In this patch, the only supported grouping is based on $GIT_DIR (in
absolute path), so you would need to group repositories by directory, or
something like that to take advantage of it.
We already have include.path for unconditional includes. This patch goes
with includeIf.<condition>.path to make it clearer that a condition is
required. The new config has the same backward compatibility approach as
include.path: older git versions that don't understand includeIf will
simply ignore them.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-01 11:26:31 +00:00
|
|
|
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-01-12 12:27:01 +00:00
|
|
|
static void git_config_push_split_parameter(const char *key, const char *value)
|
2010-08-23 19:16:00 +00:00
|
|
|
{
|
|
|
|
struct strbuf env = STRBUF_INIT;
|
|
|
|
const char *old = getenv(CONFIG_DATA_ENVIRONMENT);
|
git_config_push_parameter: handle empty GIT_CONFIG_PARAMETERS
The "git -c var=value" option stuffs the config value into
$GIT_CONFIG_PARAMETERS, so that sub-processes can see it.
When the config is later read via git_config() or similar,
we parse it back out of that variable. The parsing end is a
little bit picky; it assumes that each entry was generated
with sq_quote_buf(), and that there is no extraneous
whitespace.
On the generating end, we are careful to append to an
existing $GIT_CONFIG_PARAMETERS variable if it exists.
However, our test for "should we add a space separator" is
too liberal: it will add one even if the environment
variable exists but is empty. As a result, you might end up
with:
GIT_CONFIG_PARAMETERS=" 'core.foo=bar'"
which the parser will choke on.
This was hard to trigger in older versions of git, since we
only set the variable when we had something to put into it
(though you could certainly trigger it manually). But since
14111fc (git: submodule honor -c credential.* from command
line, 2016-02-29), the submodule code will unconditionally
put the $GIT_CONFIG_PARAMETERS variable into the environment
of any operation in the submodule, whether it is empty or
not. So any of those operations which themselves use "git
-c" will generate the unparseable value and fail.
We can easily fix it by catching this case on the generating
side. While we're adding a test, let's also check that
multiple layers of "git -c" work, which was previously not
tested at all.
Reported-by: Shin Fan <shinfan@google.com>
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Tested-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-22 19:50:51 +00:00
|
|
|
if (old && *old) {
|
2010-08-23 19:16:00 +00:00
|
|
|
strbuf_addstr(&env, old);
|
|
|
|
strbuf_addch(&env, ' ');
|
|
|
|
}
|
2021-01-12 12:27:01 +00:00
|
|
|
sq_quote_buf(&env, key);
|
|
|
|
strbuf_addch(&env, '=');
|
|
|
|
if (value)
|
|
|
|
sq_quote_buf(&env, value);
|
2010-08-23 19:16:00 +00:00
|
|
|
setenv(CONFIG_DATA_ENVIRONMENT, env.buf, 1);
|
|
|
|
strbuf_release(&env);
|
|
|
|
}
|
|
|
|
|
2021-01-12 12:27:01 +00:00
|
|
|
void git_config_push_parameter(const char *text)
|
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When we see:
|
|
|
|
*
|
|
|
|
* section.subsection=with=equals.key=value
|
|
|
|
*
|
|
|
|
* we cannot tell if it means:
|
|
|
|
*
|
|
|
|
* [section "subsection=with=equals"]
|
|
|
|
* key = value
|
|
|
|
*
|
|
|
|
* or:
|
|
|
|
*
|
|
|
|
* [section]
|
|
|
|
* subsection = with=equals.key=value
|
|
|
|
*
|
|
|
|
* We parse left-to-right for the first "=", meaning we'll prefer to
|
|
|
|
* keep the value intact over the subsection. This is historical, but
|
|
|
|
* also sensible since values are more likely to contain odd or
|
|
|
|
* untrusted input than a section name.
|
|
|
|
*
|
|
|
|
* A missing equals is explicitly allowed (as a bool-only entry).
|
|
|
|
*/
|
|
|
|
value = strchr(text, '=');
|
|
|
|
if (value) {
|
|
|
|
char *key = xmemdupz(text, value - text);
|
|
|
|
git_config_push_split_parameter(key, value + 1);
|
|
|
|
free(key);
|
|
|
|
} else {
|
|
|
|
git_config_push_split_parameter(text, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-12 12:26:45 +00:00
|
|
|
void git_config_push_env(const char *spec)
|
|
|
|
{
|
2021-01-12 12:27:01 +00:00
|
|
|
char *key;
|
2021-01-12 12:26:45 +00:00
|
|
|
const char *env_name;
|
|
|
|
const char *env_value;
|
|
|
|
|
|
|
|
env_name = strrchr(spec, '=');
|
|
|
|
if (!env_name)
|
|
|
|
die(_("invalid config format: %s"), spec);
|
2021-01-12 12:27:01 +00:00
|
|
|
key = xmemdupz(spec, env_name - spec);
|
2021-01-12 12:26:45 +00:00
|
|
|
env_name++;
|
|
|
|
if (!*env_name)
|
|
|
|
die(_("missing environment variable name for configuration '%.*s'"),
|
|
|
|
(int)(env_name - spec - 1), spec);
|
|
|
|
|
|
|
|
env_value = getenv(env_name);
|
|
|
|
if (!env_value)
|
|
|
|
die(_("missing environment variable '%s' for configuration '%.*s'"),
|
|
|
|
env_name, (int)(env_name - spec - 1), spec);
|
|
|
|
|
2021-01-12 12:27:01 +00:00
|
|
|
git_config_push_split_parameter(key, env_value);
|
|
|
|
free(key);
|
2021-01-12 12:26:45 +00:00
|
|
|
}
|
|
|
|
|
2017-02-23 22:44:07 +00:00
|
|
|
static inline int iskeychar(int c)
|
|
|
|
{
|
|
|
|
return isalnum(c) || c == '-';
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Auxiliary function to sanity-check and split the key into the section
|
|
|
|
* identifier and variable name.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 when there is an invalid character in the key and
|
|
|
|
* -2 if there is no section name in the key.
|
|
|
|
*
|
|
|
|
* store_key - pointer to char* which will hold a copy of the key with
|
|
|
|
* lowercase section and variable name
|
2020-04-10 19:46:07 +00:00
|
|
|
* baselen - pointer to size_t which will hold the length of the
|
2017-02-23 22:44:07 +00:00
|
|
|
* section + subsection part, can be NULL
|
|
|
|
*/
|
2021-09-28 12:56:03 +00:00
|
|
|
int git_config_parse_key(const char *key, char **store_key, size_t *baselen_)
|
2017-02-23 22:44:07 +00:00
|
|
|
{
|
2020-04-10 19:46:07 +00:00
|
|
|
size_t i, baselen;
|
|
|
|
int dot;
|
2017-02-23 22:44:07 +00:00
|
|
|
const char *last_dot = strrchr(key, '.');
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Since "key" actually contains the section name and the real
|
|
|
|
* key name separated by a dot, we have to know where the dot is.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (last_dot == NULL || last_dot == key) {
|
2021-09-28 12:56:03 +00:00
|
|
|
error(_("key does not contain a section: %s"), key);
|
2017-02-23 22:44:07 +00:00
|
|
|
return -CONFIG_NO_SECTION_OR_NAME;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!last_dot[1]) {
|
2021-09-28 12:56:03 +00:00
|
|
|
error(_("key does not contain variable name: %s"), key);
|
2017-02-23 22:44:07 +00:00
|
|
|
return -CONFIG_NO_SECTION_OR_NAME;
|
|
|
|
}
|
|
|
|
|
|
|
|
baselen = last_dot - key;
|
|
|
|
if (baselen_)
|
|
|
|
*baselen_ = baselen;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Validate the key and while at it, lower case it for matching.
|
|
|
|
*/
|
2021-09-28 12:56:03 +00:00
|
|
|
*store_key = xmallocz(strlen(key));
|
2017-02-23 22:44:07 +00:00
|
|
|
|
|
|
|
dot = 0;
|
|
|
|
for (i = 0; key[i]; i++) {
|
|
|
|
unsigned char c = key[i];
|
|
|
|
if (c == '.')
|
|
|
|
dot = 1;
|
|
|
|
/* Leave the extended basename untouched.. */
|
|
|
|
if (!dot || i > baselen) {
|
|
|
|
if (!iskeychar(c) ||
|
|
|
|
(i == baselen + 1 && !isalpha(c))) {
|
2021-09-28 12:56:03 +00:00
|
|
|
error(_("invalid key: %s"), key);
|
2017-02-23 22:44:07 +00:00
|
|
|
goto out_free_ret_1;
|
|
|
|
}
|
|
|
|
c = tolower(c);
|
|
|
|
} else if (c == '\n') {
|
2021-09-28 12:56:03 +00:00
|
|
|
error(_("invalid key (newline): %s"), key);
|
2017-02-23 22:44:07 +00:00
|
|
|
goto out_free_ret_1;
|
|
|
|
}
|
2021-09-28 12:56:03 +00:00
|
|
|
(*store_key)[i] = c;
|
2017-02-23 22:44:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
out_free_ret_1:
|
2021-09-28 12:56:03 +00:00
|
|
|
FREE_AND_NULL(*store_key);
|
2017-02-23 22:44:07 +00:00
|
|
|
return -CONFIG_INVALID_KEY;
|
|
|
|
}
|
|
|
|
|
2021-01-12 12:26:54 +00:00
|
|
|
static int config_parse_pair(const char *key, const char *value,
|
|
|
|
config_fn_t fn, void *data)
|
|
|
|
{
|
|
|
|
char *canonical_name;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!strlen(key))
|
|
|
|
return error(_("empty config key"));
|
|
|
|
if (git_config_parse_key(key, &canonical_name, NULL))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ret = (fn(canonical_name, value, data) < 0) ? -1 : 0;
|
|
|
|
free(canonical_name);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-06-09 15:56:42 +00:00
|
|
|
int git_config_parse_parameter(const char *text,
|
|
|
|
config_fn_t fn, void *data)
|
2010-03-26 22:53:57 +00:00
|
|
|
{
|
2014-08-04 22:40:19 +00:00
|
|
|
const char *value;
|
2010-03-26 22:56:01 +00:00
|
|
|
struct strbuf **pair;
|
2017-02-23 23:04:40 +00:00
|
|
|
int ret;
|
2014-08-04 22:40:19 +00:00
|
|
|
|
2011-06-09 15:55:09 +00:00
|
|
|
pair = strbuf_split_str(text, '=', 2);
|
2011-06-09 15:52:43 +00:00
|
|
|
if (!pair[0])
|
2018-07-21 07:49:27 +00:00
|
|
|
return error(_("bogus config parameter: %s"), text);
|
2014-08-04 22:40:19 +00:00
|
|
|
|
|
|
|
if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=') {
|
2010-03-26 22:56:01 +00:00
|
|
|
strbuf_setlen(pair[0], pair[0]->len - 1);
|
2014-08-04 22:40:19 +00:00
|
|
|
value = pair[1] ? pair[1]->buf : "";
|
|
|
|
} else {
|
|
|
|
value = NULL;
|
|
|
|
}
|
|
|
|
|
2010-03-26 22:56:01 +00:00
|
|
|
strbuf_trim(pair[0]);
|
|
|
|
if (!pair[0]->len) {
|
|
|
|
strbuf_list_free(pair);
|
2018-07-21 07:49:27 +00:00
|
|
|
return error(_("bogus config parameter: %s"), text);
|
2010-03-26 22:53:57 +00:00
|
|
|
}
|
2017-02-23 23:04:40 +00:00
|
|
|
|
2021-01-12 12:26:54 +00:00
|
|
|
ret = config_parse_pair(pair[0]->buf, value, fn, data);
|
2010-03-26 22:56:01 +00:00
|
|
|
strbuf_list_free(pair);
|
2017-02-23 23:04:40 +00:00
|
|
|
return ret;
|
2010-03-26 22:53:57 +00:00
|
|
|
}
|
|
|
|
|
config: parse more robust format in GIT_CONFIG_PARAMETERS
When we stuff config options into GIT_CONFIG_PARAMETERS, we shell-quote
each one as a single unit, like:
'section.one=value1' 'section.two=value2'
On the reading side, we de-quote to get the individual strings, and then
parse them by splitting on the first "=" we find. This format is
ambiguous, because an "=" may appear in a subsection. So the config
represented in a file by both:
[section "subsection=with=equals"]
key = value
and:
[section]
subsection = with=equals.key=value
ends up in this flattened format like:
'section.subsection=with=equals.key=value'
and we can't tell which was desired. We have traditionally resolved this
by taking the first "=" we see starting from the left, meaning that we
allowed arbitrary content in the value, but not in the subsection.
Let's make our environment format a bit more robust by separately
quoting the key and value. That turns those examples into:
'section.subsection=with=equals.key'='value'
and:
'section.subsection'='with=equals.key=value'
respectively, and we can tell the difference between them. We can detect
which format is in use for any given element of the list based on the
presence of the unquoted "=". That means we can continue to allow the
old format to work to support any callers which manually used the old
format, and we can even intermingle the two formats. The old format
wasn't documented, and nobody was supposed to be using it. But it's
likely that such callers exist in the wild, so it's nice if we can avoid
breaking them. Likewise, it may be possible to trigger an older version
of "git -c" that runs a script that calls into a newer version of "git
-c"; that new version would see the intermingled format.
This does create one complication, which is that the obvious format in
the new scheme for
[section]
some-bool
is:
'section.some-bool'
with no equals. We'd mistake that for an old-style variable. And it even
has the same meaning in the old style, but:
[section "with=equals"]
some-bool
does not. It would be:
'section.with=equals=some-bool'
which we'd take to mean:
[section]
with = equals=some-bool
in the old, ambiguous style. Likewise, we can't use:
'section.some-bool'=''
because that's ambiguous with an actual empty string. Instead, we'll
again use the shell-quoting to give us a hint, and use:
'section.some-bool'=
to show that we have no value.
Note that this commit just expands the reading side. We'll start writing
the new format via "git -c" in a future patch. In the meantime, the
existing "git -c" tests will make sure we didn't break reading the old
format. But we'll also add some explicit coverage of the two formats to
make sure we continue to handle the old one after we move the writing
side over.
And one final note: since we're now using the shell-quoting as a
semantically meaningful hint, this closes the door to us ever allowing
arbitrary shell quoting, like:
'a'shell'would'be'ok'with'this'.key=value
But we have never supported that (only what sq_quote() would produce),
and we are probably better off keeping things simple, robust, and
backwards-compatible, than trying to make it easier for humans. We'll
continue not to advertise the format of the variable to users, and
instead keep "git -c" as the recommended mechanism for setting config
(even if we are trying to be kind not to break users who may be relying
on the current undocumented format).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-01-12 12:27:06 +00:00
|
|
|
static int parse_config_env_list(char *env, config_fn_t fn, void *data)
|
|
|
|
{
|
|
|
|
char *cur = env;
|
|
|
|
while (cur && *cur) {
|
|
|
|
const char *key = sq_dequote_step(cur, &cur);
|
|
|
|
if (!key)
|
|
|
|
return error(_("bogus format in %s"),
|
|
|
|
CONFIG_DATA_ENVIRONMENT);
|
|
|
|
|
|
|
|
if (!cur || isspace(*cur)) {
|
|
|
|
/* old-style 'key=value' */
|
|
|
|
if (git_config_parse_parameter(key, fn, data) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else if (*cur == '=') {
|
|
|
|
/* new-style 'key'='value' */
|
|
|
|
const char *value;
|
|
|
|
|
|
|
|
cur++;
|
|
|
|
if (*cur == '\'') {
|
|
|
|
/* quoted value */
|
|
|
|
value = sq_dequote_step(cur, &cur);
|
|
|
|
if (!value || (cur && !isspace(*cur))) {
|
|
|
|
return error(_("bogus format in %s"),
|
|
|
|
CONFIG_DATA_ENVIRONMENT);
|
|
|
|
}
|
|
|
|
} else if (!*cur || isspace(*cur)) {
|
|
|
|
/* implicit bool: 'key'= */
|
|
|
|
value = NULL;
|
|
|
|
} else {
|
|
|
|
return error(_("bogus format in %s"),
|
|
|
|
CONFIG_DATA_ENVIRONMENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config_parse_pair(key, value, fn, data) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* unknown format */
|
|
|
|
return error(_("bogus format in %s"),
|
|
|
|
CONFIG_DATA_ENVIRONMENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cur) {
|
|
|
|
while (isspace(*cur))
|
|
|
|
cur++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-05-24 22:49:55 +00:00
|
|
|
int git_config_from_parameters(config_fn_t fn, void *data)
|
|
|
|
{
|
2021-01-12 12:27:14 +00:00
|
|
|
const char *env;
|
|
|
|
struct strbuf envvar = STRBUF_INIT;
|
|
|
|
struct strvec to_free = STRVEC_INIT;
|
2016-05-18 22:39:49 +00:00
|
|
|
int ret = 0;
|
2021-01-12 12:27:14 +00:00
|
|
|
char *envw = NULL;
|
2016-05-18 22:41:08 +00:00
|
|
|
struct config_source source;
|
2010-08-23 19:16:00 +00:00
|
|
|
|
2016-05-18 22:41:08 +00:00
|
|
|
memset(&source, 0, sizeof(source));
|
|
|
|
source.prev = cf;
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
source.origin_type = CONFIG_ORIGIN_CMDLINE;
|
2016-05-18 22:41:08 +00:00
|
|
|
cf = &source;
|
|
|
|
|
2021-01-12 12:27:14 +00:00
|
|
|
env = getenv(CONFIG_COUNT_ENVIRONMENT);
|
|
|
|
if (env) {
|
|
|
|
unsigned long count;
|
|
|
|
char *endp;
|
|
|
|
int i;
|
2010-08-23 19:16:00 +00:00
|
|
|
|
2021-01-12 12:27:14 +00:00
|
|
|
count = strtoul(env, &endp, 10);
|
|
|
|
if (*endp) {
|
|
|
|
ret = error(_("bogus count in %s"), CONFIG_COUNT_ENVIRONMENT);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (count > INT_MAX) {
|
|
|
|
ret = error(_("too many entries in %s"), CONFIG_COUNT_ENVIRONMENT);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
const char *key, *value;
|
|
|
|
|
|
|
|
strbuf_addf(&envvar, "GIT_CONFIG_KEY_%d", i);
|
|
|
|
key = getenv_safe(&to_free, envvar.buf);
|
|
|
|
if (!key) {
|
|
|
|
ret = error(_("missing config key %s"), envvar.buf);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
strbuf_reset(&envvar);
|
|
|
|
|
|
|
|
strbuf_addf(&envvar, "GIT_CONFIG_VALUE_%d", i);
|
|
|
|
value = getenv_safe(&to_free, envvar.buf);
|
|
|
|
if (!value) {
|
|
|
|
ret = error(_("missing config value %s"), envvar.buf);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
strbuf_reset(&envvar);
|
|
|
|
|
|
|
|
if (config_parse_pair(key, value, fn, data) < 0) {
|
|
|
|
ret = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
2010-08-23 19:16:00 +00:00
|
|
|
}
|
|
|
|
|
2021-01-12 12:27:14 +00:00
|
|
|
env = getenv(CONFIG_DATA_ENVIRONMENT);
|
|
|
|
if (env) {
|
|
|
|
/* sq_dequote will write over it */
|
|
|
|
envw = xstrdup(env);
|
|
|
|
if (parse_config_env_list(envw, fn, data) < 0) {
|
2016-05-18 22:39:49 +00:00
|
|
|
ret = -1;
|
|
|
|
goto out;
|
2010-08-23 19:16:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-18 22:39:49 +00:00
|
|
|
out:
|
2021-01-12 12:27:14 +00:00
|
|
|
strbuf_release(&envvar);
|
|
|
|
strvec_clear(&to_free);
|
2010-08-23 19:16:00 +00:00
|
|
|
free(envw);
|
2016-05-18 22:41:08 +00:00
|
|
|
cf = source.prev;
|
2016-05-18 22:39:49 +00:00
|
|
|
return ret;
|
2010-08-23 19:16:00 +00:00
|
|
|
}
|
|
|
|
|
2005-10-10 23:31:08 +00:00
|
|
|
static int get_next_char(void)
|
|
|
|
{
|
2013-08-26 21:57:18 +00:00
|
|
|
int c = cf->do_fgetc(cf);
|
2005-10-10 23:31:08 +00:00
|
|
|
|
2013-05-11 13:19:29 +00:00
|
|
|
if (c == '\r') {
|
|
|
|
/* DOS like systems */
|
2013-08-26 21:57:18 +00:00
|
|
|
c = cf->do_fgetc(cf);
|
2013-05-11 13:19:29 +00:00
|
|
|
if (c != '\n') {
|
config: do not ungetc EOF
When we are parsing a config value, if we see a carriage
return, we fgetc the next character to see if it is a
line feed (in which case we silently drop the CR). If it
isn't, we then ungetc the character, and take the literal
CR.
But we never check whether we in fact got a character at
all. If the config file ends in CR, we will get EOF here,
and try to ungetc EOF. This works OK for a real stdio
stream. The ungetc returns an error, and the next fgetc will
then return EOF again.
However, our custom buffer-based stream is not so fortunate.
It happily rewinds the position of the stream by one
character, ignoring the fact that we fed it EOF. The next
fgetc call returns the final CR again, over and over, and we
end up in an infinite loop.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-02-05 06:53:28 +00:00
|
|
|
if (c != EOF)
|
|
|
|
cf->do_ungetc(c, cf);
|
2013-05-11 13:19:29 +00:00
|
|
|
c = '\r';
|
2005-10-10 23:31:08 +00:00
|
|
|
}
|
|
|
|
}
|
config: reject parsing of files over INT_MAX
While the last few commits have made it possible for the config parser
to handle config files up to the limits of size_t, the rest of the code
isn't really ready for this. In particular, we often feed the keys as
strings into printf "%s" format specifiers. And because the printf
family of functions must return an int to specify the result, they
complain. Here are two concrete examples (using glibc; we're in
uncharted territory here so results may vary):
Generate a gigantic .gitmodules file like this:
git submodule add /some/other/repo foo
{
printf '[submodule "'
perl -e 'print "a" x 2**31'
echo '"]path = foo'
} >.gitmodules
git commit -m 'huge gitmodule'
then try this:
$ git show
BUG: strbuf.c:397: your vsnprintf is broken (returned -1)
The problem is that we end up calling:
strbuf_addf(&sb, "submodule.%s.ignore", submodule_name);
which relies on vsnprintf(), and that function has no way to report back
a size larger than INT_MAX.
Taking that same file, try this:
git config --file=.gitmodules --list --name-only
On my system it produces an output with exactly 4GB of spaces. I
confirmed in a debugger that we reach the config callback with the key
intact: it's 2147483663 bytes and full of a's. But when we print it with
this call:
printf("%s%c", key_, term);
we just get the spaces.
So given the fact that these are insane cases which we have no need to
support, the weird behavior from feeding the results to printf even if
the code is careful, and the possibility of uncareful code introducing
its own integer truncation issues, let's just declare INT_MAX as a limit
for parsing config files.
We'll enforce the limit in get_next_char(), which generalizes over all
sources (blobs, files, etc) and covers any element we're parsing
(whether section, key, value, etc). For simplicity, the limit is over
the length of the _whole_ file, so you couldn't have two 1GB values in
the same file. This should be perfectly fine, as the expected size for
config files is generally kilobytes at most.
With this patch both cases above will yield:
fatal: bad config line 1 in file .gitmodules
That's not an amazing error message, but the parser isn't set up to
provide specific messages (it just breaks out of the parsing loop and
gives that generic error even if see a syntactic issue). And we really
wouldn't expect to see this case outside of somebody maliciously probing
the limits of the config system.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-10 19:50:07 +00:00
|
|
|
|
|
|
|
if (c != EOF && ++cf->total_len > INT_MAX) {
|
|
|
|
/*
|
|
|
|
* This is an absurdly long config file; refuse to parse
|
|
|
|
* further in order to protect downstream code from integer
|
|
|
|
* overflows. Note that we can't return an error specifically,
|
|
|
|
* but we can mark EOF and put trash in the return value,
|
|
|
|
* which will trigger a parse error.
|
|
|
|
*/
|
|
|
|
cf->eof = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-05-11 13:19:29 +00:00
|
|
|
if (c == '\n')
|
|
|
|
cf->linenr++;
|
|
|
|
if (c == EOF) {
|
|
|
|
cf->eof = 1;
|
2014-08-07 11:59:13 +00:00
|
|
|
cf->linenr++;
|
2013-05-11 13:19:29 +00:00
|
|
|
c = '\n';
|
|
|
|
}
|
2005-10-10 23:31:08 +00:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *parse_value(void)
|
|
|
|
{
|
2011-04-10 20:54:18 +00:00
|
|
|
int quote = 0, comment = 0, space = 0;
|
2005-10-10 23:31:08 +00:00
|
|
|
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
strbuf_reset(&cf->value);
|
2005-10-10 23:31:08 +00:00
|
|
|
for (;;) {
|
|
|
|
int c = get_next_char();
|
|
|
|
if (c == '\n') {
|
2012-03-09 21:57:54 +00:00
|
|
|
if (quote) {
|
|
|
|
cf->linenr--;
|
2005-10-10 23:31:08 +00:00
|
|
|
return NULL;
|
2012-03-09 21:57:54 +00:00
|
|
|
}
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
return cf->value.buf;
|
2005-10-10 23:31:08 +00:00
|
|
|
}
|
|
|
|
if (comment)
|
|
|
|
continue;
|
|
|
|
if (isspace(c) && !quote) {
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
if (cf->value.len)
|
2009-07-30 11:41:57 +00:00
|
|
|
space++;
|
2005-10-10 23:31:08 +00:00
|
|
|
continue;
|
|
|
|
}
|
2006-05-02 14:58:37 +00:00
|
|
|
if (!quote) {
|
|
|
|
if (c == ';' || c == '#') {
|
|
|
|
comment = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2009-07-30 11:41:57 +00:00
|
|
|
for (; space; space--)
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
strbuf_addch(&cf->value, ' ');
|
2005-10-10 23:31:08 +00:00
|
|
|
if (c == '\\') {
|
|
|
|
c = get_next_char();
|
|
|
|
switch (c) {
|
|
|
|
case '\n':
|
|
|
|
continue;
|
|
|
|
case 't':
|
|
|
|
c = '\t';
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
c = '\b';
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
c = '\n';
|
|
|
|
break;
|
2005-10-11 22:24:11 +00:00
|
|
|
/* Some characters escape as themselves */
|
|
|
|
case '\\': case '"':
|
|
|
|
break;
|
|
|
|
/* Reject unknown escape sequences */
|
|
|
|
default:
|
|
|
|
return NULL;
|
2005-10-10 23:31:08 +00:00
|
|
|
}
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
strbuf_addch(&cf->value, c);
|
2005-10-10 23:31:08 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c == '"') {
|
|
|
|
quote = 1-quote;
|
|
|
|
continue;
|
|
|
|
}
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
strbuf_addch(&cf->value, c);
|
2005-10-10 23:31:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-30 19:44:36 +00:00
|
|
|
static int get_value(config_fn_t fn, void *data, struct strbuf *name)
|
2005-10-10 23:31:08 +00:00
|
|
|
{
|
|
|
|
int c;
|
|
|
|
char *value;
|
2014-08-07 11:59:13 +00:00
|
|
|
int ret;
|
2005-10-10 23:31:08 +00:00
|
|
|
|
|
|
|
/* Get the full name */
|
|
|
|
for (;;) {
|
|
|
|
c = get_next_char();
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
if (cf->eof)
|
2005-10-10 23:31:08 +00:00
|
|
|
break;
|
2006-10-30 16:25:36 +00:00
|
|
|
if (!iskeychar(c))
|
2005-10-10 23:31:08 +00:00
|
|
|
break;
|
2012-09-30 19:44:36 +00:00
|
|
|
strbuf_addch(name, tolower(c));
|
2005-10-10 23:31:08 +00:00
|
|
|
}
|
2012-09-30 19:44:36 +00:00
|
|
|
|
2005-10-10 23:31:08 +00:00
|
|
|
while (c == ' ' || c == '\t')
|
|
|
|
c = get_next_char();
|
|
|
|
|
|
|
|
value = NULL;
|
|
|
|
if (c != '\n') {
|
|
|
|
if (c != '=')
|
|
|
|
return -1;
|
|
|
|
value = parse_value();
|
|
|
|
if (!value)
|
|
|
|
return -1;
|
|
|
|
}
|
2014-08-07 11:59:13 +00:00
|
|
|
/*
|
|
|
|
* We already consumed the \n, but we need linenr to point to
|
|
|
|
* the line we just parsed during the call to fn to get
|
|
|
|
* accurate line number in error messages.
|
|
|
|
*/
|
|
|
|
cf->linenr--;
|
|
|
|
ret = fn(name->buf, value, data);
|
2017-06-14 11:35:46 +00:00
|
|
|
if (ret >= 0)
|
|
|
|
cf->linenr++;
|
2014-08-07 11:59:13 +00:00
|
|
|
return ret;
|
2005-10-10 23:31:08 +00:00
|
|
|
}
|
|
|
|
|
2012-09-30 19:44:36 +00:00
|
|
|
static int get_extended_base_var(struct strbuf *name, int c)
|
2006-05-09 19:24:02 +00:00
|
|
|
{
|
2018-08-08 19:50:19 +00:00
|
|
|
cf->subsection_case_sensitive = 0;
|
2006-05-09 19:24:02 +00:00
|
|
|
do {
|
|
|
|
if (c == '\n')
|
2012-03-09 21:57:54 +00:00
|
|
|
goto error_incomplete_line;
|
2006-05-09 19:24:02 +00:00
|
|
|
c = get_next_char();
|
|
|
|
} while (isspace(c));
|
|
|
|
|
|
|
|
/* We require the format to be '[base "extension"]' */
|
|
|
|
if (c != '"')
|
|
|
|
return -1;
|
2012-09-30 19:44:36 +00:00
|
|
|
strbuf_addch(name, '.');
|
2006-05-09 19:24:02 +00:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
int c = get_next_char();
|
|
|
|
if (c == '\n')
|
2012-03-09 21:57:54 +00:00
|
|
|
goto error_incomplete_line;
|
2006-05-09 19:24:02 +00:00
|
|
|
if (c == '"')
|
|
|
|
break;
|
|
|
|
if (c == '\\') {
|
|
|
|
c = get_next_char();
|
|
|
|
if (c == '\n')
|
2012-03-09 21:57:54 +00:00
|
|
|
goto error_incomplete_line;
|
2006-05-09 19:24:02 +00:00
|
|
|
}
|
2012-09-30 19:44:36 +00:00
|
|
|
strbuf_addch(name, c);
|
2006-05-09 19:24:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Final ']' */
|
|
|
|
if (get_next_char() != ']')
|
|
|
|
return -1;
|
2012-09-30 19:44:36 +00:00
|
|
|
return 0;
|
2012-03-09 21:57:54 +00:00
|
|
|
error_incomplete_line:
|
|
|
|
cf->linenr--;
|
|
|
|
return -1;
|
2006-05-09 19:24:02 +00:00
|
|
|
}
|
|
|
|
|
2012-09-30 19:44:36 +00:00
|
|
|
static int get_base_var(struct strbuf *name)
|
2005-10-10 23:31:08 +00:00
|
|
|
{
|
2018-08-08 19:50:19 +00:00
|
|
|
cf->subsection_case_sensitive = 1;
|
2005-10-10 23:31:08 +00:00
|
|
|
for (;;) {
|
|
|
|
int c = get_next_char();
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
if (cf->eof)
|
2005-10-10 23:31:08 +00:00
|
|
|
return -1;
|
|
|
|
if (c == ']')
|
2012-09-30 19:44:36 +00:00
|
|
|
return 0;
|
2006-05-09 19:24:02 +00:00
|
|
|
if (isspace(c))
|
2012-09-30 19:44:36 +00:00
|
|
|
return get_extended_base_var(name, c);
|
2006-10-30 16:25:36 +00:00
|
|
|
if (!iskeychar(c) && c != '.')
|
2005-10-10 23:31:08 +00:00
|
|
|
return -1;
|
2012-09-30 19:44:36 +00:00
|
|
|
strbuf_addch(name, tolower(c));
|
2005-10-10 23:31:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-09 08:32:05 +00:00
|
|
|
struct parse_event_data {
|
|
|
|
enum config_event_t previous_type;
|
|
|
|
size_t previous_offset;
|
|
|
|
const struct config_options *opts;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int do_event(enum config_event_t type, struct parse_event_data *data)
|
|
|
|
{
|
|
|
|
size_t offset;
|
|
|
|
|
|
|
|
if (!data->opts || !data->opts->event_fn)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (type == CONFIG_EVENT_WHITESPACE &&
|
|
|
|
data->previous_type == type)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
offset = cf->do_ftell(cf);
|
|
|
|
/*
|
|
|
|
* At EOF, the parser always "inserts" an extra '\n', therefore
|
|
|
|
* the end offset of the event is the current file position, otherwise
|
|
|
|
* we will already have advanced to the next event.
|
|
|
|
*/
|
|
|
|
if (type != CONFIG_EVENT_EOF)
|
|
|
|
offset--;
|
|
|
|
|
|
|
|
if (data->previous_type != CONFIG_EVENT_EOF &&
|
|
|
|
data->opts->event_fn(data->previous_type, data->previous_offset,
|
|
|
|
offset, data->opts->event_fn_data) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
data->previous_type = type;
|
|
|
|
data->previous_offset = offset;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int git_parse_source(config_fn_t fn, void *data,
|
|
|
|
const struct config_options *opts)
|
2005-10-10 23:31:08 +00:00
|
|
|
{
|
|
|
|
int comment = 0;
|
config: use size_t to store parsed variable baselen
Most of the config parsing infrastructure is limited in what it can
parse only by the size of memory, because it parses character by
character, building up strbufs for keys, values, etc. One exception is
the "baselen" value we keep in git_parse_source(), which is an int.
That stores the length of the section.subsection base, to which we can
then append individual key names (by truncating back to the baselen with
strbuf_setlen(), and then appending characters for the key name). But
because it's an int, if we see an absurdly long section or subsection,
we may overflow the integer, wrapping negative. That negative value is
then implicitly cast to a size_t when we pass it to strbuf_setlen(),
creating a very large value and triggering a BUG. For example:
$ {
printf '[foo "'
perl -e 'print "a" x 2**31'
echo '"]bar = value'
} >huge
$ git config --file=huge --list
fatal: BUG: strbuf_setlen() beyond buffer
While this is obviously a silly case that we don't care about
supporting, it's worth fixing it by switching to a size_t for a few
reasons:
- we should try to avoid hitting BUG assertions at all
- avoiding integer truncation or overflow sets a good example and
makes it easier to audit the code for more important issues
- the BUG outcome is what happens in _this_ instance, because we wrap
negative. If we used a 2**32 subsection, we'd wrap to a small
positive value and actually generate wrong output (the subsection of
our key would be truncated).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-10 19:47:51 +00:00
|
|
|
size_t baselen = 0;
|
2012-09-30 19:44:36 +00:00
|
|
|
struct strbuf *var = &cf->var;
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
int error_return = 0;
|
|
|
|
char *error_msg = NULL;
|
2005-10-10 23:31:08 +00:00
|
|
|
|
2008-10-01 20:13:02 +00:00
|
|
|
/* U+FEFF Byte Order Mark in UTF8 */
|
2015-04-16 17:47:45 +00:00
|
|
|
const char *bomptr = utf8_bom;
|
2008-10-01 20:13:02 +00:00
|
|
|
|
2018-04-09 08:32:05 +00:00
|
|
|
/* For the parser event callback */
|
|
|
|
struct parse_event_data event_data = {
|
|
|
|
CONFIG_EVENT_EOF, 0, opts
|
|
|
|
};
|
|
|
|
|
2005-10-10 23:31:08 +00:00
|
|
|
for (;;) {
|
2018-04-09 08:32:05 +00:00
|
|
|
int c;
|
|
|
|
|
|
|
|
c = get_next_char();
|
2008-10-01 20:13:02 +00:00
|
|
|
if (bomptr && *bomptr) {
|
|
|
|
/* We are at the file beginning; skip UTF8-encoded BOM
|
|
|
|
* if present. Sane editors won't put this in on their
|
|
|
|
* own, but e.g. Windows Notepad will do it happily. */
|
2015-04-16 17:47:45 +00:00
|
|
|
if (c == (*bomptr & 0377)) {
|
2008-10-01 20:13:02 +00:00
|
|
|
bomptr++;
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
/* Do not tolerate partial BOM. */
|
|
|
|
if (bomptr != utf8_bom)
|
|
|
|
break;
|
|
|
|
/* No BOM at file beginning. Cool. */
|
|
|
|
bomptr = NULL;
|
|
|
|
}
|
|
|
|
}
|
2005-10-10 23:31:08 +00:00
|
|
|
if (c == '\n') {
|
2018-04-09 08:32:05 +00:00
|
|
|
if (cf->eof) {
|
|
|
|
if (do_event(CONFIG_EVENT_EOF, &event_data) < 0)
|
|
|
|
return -1;
|
2005-10-10 23:31:08 +00:00
|
|
|
return 0;
|
2018-04-09 08:32:05 +00:00
|
|
|
}
|
|
|
|
if (do_event(CONFIG_EVENT_WHITESPACE, &event_data) < 0)
|
|
|
|
return -1;
|
2005-10-10 23:31:08 +00:00
|
|
|
comment = 0;
|
|
|
|
continue;
|
|
|
|
}
|
2018-04-09 08:32:05 +00:00
|
|
|
if (comment)
|
2005-10-10 23:31:08 +00:00
|
|
|
continue;
|
2018-04-09 08:32:05 +00:00
|
|
|
if (isspace(c)) {
|
|
|
|
if (do_event(CONFIG_EVENT_WHITESPACE, &event_data) < 0)
|
|
|
|
return -1;
|
2005-10-10 23:31:08 +00:00
|
|
|
continue;
|
2018-04-09 08:32:05 +00:00
|
|
|
}
|
2005-10-10 23:31:08 +00:00
|
|
|
if (c == '#' || c == ';') {
|
2018-04-09 08:32:05 +00:00
|
|
|
if (do_event(CONFIG_EVENT_COMMENT, &event_data) < 0)
|
|
|
|
return -1;
|
2005-10-10 23:31:08 +00:00
|
|
|
comment = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c == '[') {
|
2018-04-09 08:32:05 +00:00
|
|
|
if (do_event(CONFIG_EVENT_SECTION, &event_data) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2012-09-30 19:44:36 +00:00
|
|
|
/* Reset prior to determining a new stem */
|
|
|
|
strbuf_reset(var);
|
|
|
|
if (get_base_var(var) < 0 || var->len < 1)
|
2005-10-10 23:31:08 +00:00
|
|
|
break;
|
2012-09-30 19:44:36 +00:00
|
|
|
strbuf_addch(var, '.');
|
|
|
|
baselen = var->len;
|
2005-10-10 23:31:08 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!isalpha(c))
|
|
|
|
break;
|
2018-04-09 08:32:05 +00:00
|
|
|
|
|
|
|
if (do_event(CONFIG_EVENT_ENTRY, &event_data) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2012-09-30 19:44:36 +00:00
|
|
|
/*
|
|
|
|
* Truncate the var name back to the section header
|
|
|
|
* stem prior to grabbing the suffix part of the name
|
|
|
|
* and the value.
|
|
|
|
*/
|
|
|
|
strbuf_setlen(var, baselen);
|
|
|
|
strbuf_addch(var, tolower(c));
|
|
|
|
if (get_value(fn, data, var) < 0)
|
2005-10-10 23:31:08 +00:00
|
|
|
break;
|
|
|
|
}
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
|
2018-04-09 08:32:05 +00:00
|
|
|
if (do_event(CONFIG_EVENT_ERROR, &event_data) < 0)
|
|
|
|
return -1;
|
|
|
|
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
switch (cf->origin_type) {
|
|
|
|
case CONFIG_ORIGIN_BLOB:
|
|
|
|
error_msg = xstrfmt(_("bad config line %d in blob %s"),
|
|
|
|
cf->linenr, cf->name);
|
|
|
|
break;
|
|
|
|
case CONFIG_ORIGIN_FILE:
|
|
|
|
error_msg = xstrfmt(_("bad config line %d in file %s"),
|
|
|
|
cf->linenr, cf->name);
|
|
|
|
break;
|
|
|
|
case CONFIG_ORIGIN_STDIN:
|
|
|
|
error_msg = xstrfmt(_("bad config line %d in standard input"),
|
|
|
|
cf->linenr);
|
|
|
|
break;
|
|
|
|
case CONFIG_ORIGIN_SUBMODULE_BLOB:
|
|
|
|
error_msg = xstrfmt(_("bad config line %d in submodule-blob %s"),
|
|
|
|
cf->linenr, cf->name);
|
|
|
|
break;
|
|
|
|
case CONFIG_ORIGIN_CMDLINE:
|
|
|
|
error_msg = xstrfmt(_("bad config line %d in command line %s"),
|
|
|
|
cf->linenr, cf->name);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error_msg = xstrfmt(_("bad config line %d in %s"),
|
|
|
|
cf->linenr, cf->name);
|
|
|
|
}
|
|
|
|
|
2018-06-28 22:05:00 +00:00
|
|
|
switch (opts && opts->error_action ?
|
|
|
|
opts->error_action :
|
|
|
|
cf->default_error_action) {
|
|
|
|
case CONFIG_ERROR_DIE:
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
die("%s", error_msg);
|
2018-06-28 22:05:00 +00:00
|
|
|
break;
|
|
|
|
case CONFIG_ERROR_ERROR:
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
error_return = error("%s", error_msg);
|
2018-06-28 22:05:00 +00:00
|
|
|
break;
|
2018-06-28 22:05:09 +00:00
|
|
|
case CONFIG_ERROR_SILENT:
|
|
|
|
error_return = -1;
|
|
|
|
break;
|
2018-06-28 22:05:00 +00:00
|
|
|
case CONFIG_ERROR_UNSET:
|
|
|
|
BUG("config error action unset");
|
|
|
|
}
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
|
|
|
|
free(error_msg);
|
|
|
|
return error_return;
|
2005-10-10 23:31:08 +00:00
|
|
|
}
|
|
|
|
|
2019-06-22 10:03:40 +00:00
|
|
|
static uintmax_t get_unit_factor(const char *end)
|
2007-07-12 13:32:26 +00:00
|
|
|
{
|
|
|
|
if (!*end)
|
|
|
|
return 1;
|
2019-06-22 10:03:40 +00:00
|
|
|
else if (!strcasecmp(end, "k"))
|
|
|
|
return 1024;
|
|
|
|
else if (!strcasecmp(end, "m"))
|
|
|
|
return 1024 * 1024;
|
|
|
|
else if (!strcasecmp(end, "g"))
|
|
|
|
return 1024 * 1024 * 1024;
|
2007-12-25 07:18:05 +00:00
|
|
|
return 0;
|
2007-07-12 13:32:26 +00:00
|
|
|
}
|
|
|
|
|
2013-09-08 08:29:27 +00:00
|
|
|
static int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
|
2007-07-12 13:32:26 +00:00
|
|
|
{
|
|
|
|
if (value && *value) {
|
|
|
|
char *end;
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 15:46:23 +00:00
|
|
|
intmax_t val;
|
|
|
|
uintmax_t uval;
|
2019-06-22 10:03:36 +00:00
|
|
|
uintmax_t factor;
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 15:46:23 +00:00
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
val = strtoimax(value, &end, 0);
|
|
|
|
if (errno == ERANGE)
|
|
|
|
return 0;
|
2019-06-22 10:03:40 +00:00
|
|
|
factor = get_unit_factor(end);
|
|
|
|
if (!factor) {
|
2013-09-08 08:36:42 +00:00
|
|
|
errno = EINVAL;
|
2007-12-25 07:18:05 +00:00
|
|
|
return 0;
|
2013-09-08 08:36:42 +00:00
|
|
|
}
|
2019-06-13 11:49:47 +00:00
|
|
|
uval = val < 0 ? -val : val;
|
config: use unsigned_mult_overflows to check for overflows
parse_unit_factor() checks if a K, M or G is present after a number and
multiplies it by 2^10, 2^20 or 2^30, respectively. One of its callers
checks if the result is smaller than the number alone to detect
overflows. The other one passes 1 as the number and does multiplication
and overflow check itself in a similar manner.
This works, but is inconsistent, and it would break if we added support
for a bigger unit factor. E.g. 16777217T is 2^64 + 2^40, i.e. too big
for a 64-bit number. Modulo 2^64 we get 2^40 == 1TB, which is bigger
than the raw number 16777217 == 2^24 + 1, so the overflow would go
undetected by that method.
Let both callers pass 1 and handle overflow check and multiplication
themselves. Do the check before the multiplication, using
unsigned_mult_overflows, which is simpler and can deal with larger unit
factors.
Signed-off-by: Rene Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-06-22 10:03:30 +00:00
|
|
|
if (unsigned_mult_overflows(factor, uval) ||
|
|
|
|
factor * uval > max) {
|
2013-09-08 08:36:42 +00:00
|
|
|
errno = ERANGE;
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 15:46:23 +00:00
|
|
|
return 0;
|
2013-09-08 08:36:42 +00:00
|
|
|
}
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 15:46:23 +00:00
|
|
|
val *= factor;
|
|
|
|
*ret = val;
|
2007-07-12 13:32:26 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2013-09-08 08:36:42 +00:00
|
|
|
errno = EINVAL;
|
2007-07-12 13:32:26 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-06 20:48:29 +00:00
|
|
|
static int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
|
2005-10-10 23:31:08 +00:00
|
|
|
{
|
|
|
|
if (value && *value) {
|
|
|
|
char *end;
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 15:46:23 +00:00
|
|
|
uintmax_t val;
|
2019-06-22 10:03:36 +00:00
|
|
|
uintmax_t factor;
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 15:46:23 +00:00
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
val = strtoumax(value, &end, 0);
|
|
|
|
if (errno == ERANGE)
|
|
|
|
return 0;
|
2019-06-22 10:03:40 +00:00
|
|
|
factor = get_unit_factor(end);
|
|
|
|
if (!factor) {
|
2013-09-08 08:36:42 +00:00
|
|
|
errno = EINVAL;
|
2007-12-25 07:18:05 +00:00
|
|
|
return 0;
|
2013-09-08 08:36:42 +00:00
|
|
|
}
|
config: use unsigned_mult_overflows to check for overflows
parse_unit_factor() checks if a K, M or G is present after a number and
multiplies it by 2^10, 2^20 or 2^30, respectively. One of its callers
checks if the result is smaller than the number alone to detect
overflows. The other one passes 1 as the number and does multiplication
and overflow check itself in a similar manner.
This works, but is inconsistent, and it would break if we added support
for a bigger unit factor. E.g. 16777217T is 2^64 + 2^40, i.e. too big
for a 64-bit number. Modulo 2^64 we get 2^40 == 1TB, which is bigger
than the raw number 16777217 == 2^24 + 1, so the overflow would go
undetected by that method.
Let both callers pass 1 and handle overflow check and multiplication
themselves. Do the check before the multiplication, using
unsigned_mult_overflows, which is simpler and can deal with larger unit
factors.
Signed-off-by: Rene Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-06-22 10:03:30 +00:00
|
|
|
if (unsigned_mult_overflows(factor, val) ||
|
|
|
|
factor * val > max) {
|
2013-09-08 08:36:42 +00:00
|
|
|
errno = ERANGE;
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 15:46:23 +00:00
|
|
|
return 0;
|
2013-09-08 08:36:42 +00:00
|
|
|
}
|
config: use unsigned_mult_overflows to check for overflows
parse_unit_factor() checks if a K, M or G is present after a number and
multiplies it by 2^10, 2^20 or 2^30, respectively. One of its callers
checks if the result is smaller than the number alone to detect
overflows. The other one passes 1 as the number and does multiplication
and overflow check itself in a similar manner.
This works, but is inconsistent, and it would break if we added support
for a bigger unit factor. E.g. 16777217T is 2^64 + 2^40, i.e. too big
for a 64-bit number. Modulo 2^64 we get 2^40 == 1TB, which is bigger
than the raw number 16777217 == 2^24 + 1, so the overflow would go
undetected by that method.
Let both callers pass 1 and handle overflow check and multiplication
themselves. Do the check before the multiplication, using
unsigned_mult_overflows, which is simpler and can deal with larger unit
factors.
Signed-off-by: Rene Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-06-22 10:03:30 +00:00
|
|
|
val *= factor;
|
2007-12-25 07:18:05 +00:00
|
|
|
*ret = val;
|
2007-07-12 13:32:26 +00:00
|
|
|
return 1;
|
2005-10-10 23:31:08 +00:00
|
|
|
}
|
2013-09-08 08:36:42 +00:00
|
|
|
errno = EINVAL;
|
2007-07-12 13:32:26 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-10-12 12:52:30 +00:00
|
|
|
int git_parse_int(const char *value, int *ret)
|
2008-02-21 00:00:32 +00:00
|
|
|
{
|
2013-09-08 08:29:27 +00:00
|
|
|
intmax_t tmp;
|
2013-09-08 08:33:08 +00:00
|
|
|
if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int)))
|
2013-09-08 08:29:27 +00:00
|
|
|
return 0;
|
|
|
|
*ret = tmp;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
git-config: always treat --int as 64-bit internally
When you run "git config --int", the maximum size of integer
you get depends on how git was compiled, and what it
considers to be an "int".
This is almost useful, because your scripts calling "git
config" will behave similarly to git internally. But relying
on this is dubious; you have to actually know how git treats
each value internally (e.g., int versus unsigned long),
which is not documented and is subject to change. And even
if you know it is "unsigned long", we do not have a
git-config option to match that behavior.
Furthermore, you may simply be asking git to store a value
on your behalf (e.g., configuration for a hook). In that
case, the relevant range check has nothing at all to do with
git, but rather with whatever scripting tools you are using
(and git has no way of knowing what the appropriate range is
there).
Not only is the range check useless, but it is actively
harmful, as there is no way at all for scripts to look
at config variables with large values. For instance, one
cannot reliably get the value of pack.packSizeLimit via
git-config. On an LP64 system, git happily uses a 64-bit
"unsigned long" internally to represent the value, but the
script cannot read any value over 2G.
Ideally, the "--int" option would simply represent an
arbitrarily large integer. For practical purposes, however,
a 64-bit integer is large enough, and is much easier to
implement (and if somebody overflows it, we will still
notice the problem, and not simply return garbage).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-09-08 08:40:02 +00:00
|
|
|
static int git_parse_int64(const char *value, int64_t *ret)
|
|
|
|
{
|
|
|
|
intmax_t tmp;
|
|
|
|
if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int64_t)))
|
|
|
|
return 0;
|
|
|
|
*ret = tmp;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-09-08 08:29:27 +00:00
|
|
|
int git_parse_ulong(const char *value, unsigned long *ret)
|
|
|
|
{
|
|
|
|
uintmax_t tmp;
|
|
|
|
if (!git_parse_unsigned(value, &tmp, maximum_unsigned_value_of_type(long)))
|
|
|
|
return 0;
|
|
|
|
*ret = tmp;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-06-10 15:05:20 +00:00
|
|
|
int git_parse_ssize_t(const char *value, ssize_t *ret)
|
2017-04-11 18:13:57 +00:00
|
|
|
{
|
|
|
|
intmax_t tmp;
|
|
|
|
if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(ssize_t)))
|
|
|
|
return 0;
|
|
|
|
*ret = tmp;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-04-16 16:51:47 +00:00
|
|
|
NORETURN
|
2013-09-08 08:38:22 +00:00
|
|
|
static void die_bad_number(const char *name, const char *value)
|
2008-02-21 00:00:32 +00:00
|
|
|
{
|
2019-06-21 10:18:07 +00:00
|
|
|
const char *error_type = (errno == ERANGE) ?
|
|
|
|
N_("out of range") : N_("invalid unit");
|
|
|
|
const char *bad_numeric = N_("bad numeric config value '%s' for '%s': %s");
|
2016-08-21 14:50:39 +00:00
|
|
|
|
2013-09-08 08:38:22 +00:00
|
|
|
if (!value)
|
|
|
|
value = "";
|
|
|
|
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
if (!(cf && cf->name))
|
2019-06-21 10:18:07 +00:00
|
|
|
die(_(bad_numeric), value, name, _(error_type));
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
|
|
|
|
switch (cf->origin_type) {
|
|
|
|
case CONFIG_ORIGIN_BLOB:
|
2016-08-21 14:50:39 +00:00
|
|
|
die(_("bad numeric config value '%s' for '%s' in blob %s: %s"),
|
2019-06-21 10:18:07 +00:00
|
|
|
value, name, cf->name, _(error_type));
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
case CONFIG_ORIGIN_FILE:
|
2016-08-21 14:50:39 +00:00
|
|
|
die(_("bad numeric config value '%s' for '%s' in file %s: %s"),
|
2019-06-21 10:18:07 +00:00
|
|
|
value, name, cf->name, _(error_type));
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
case CONFIG_ORIGIN_STDIN:
|
2016-08-21 14:50:39 +00:00
|
|
|
die(_("bad numeric config value '%s' for '%s' in standard input: %s"),
|
2019-06-21 10:18:07 +00:00
|
|
|
value, name, _(error_type));
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
case CONFIG_ORIGIN_SUBMODULE_BLOB:
|
2016-08-21 14:50:39 +00:00
|
|
|
die(_("bad numeric config value '%s' for '%s' in submodule-blob %s: %s"),
|
2019-06-21 10:18:07 +00:00
|
|
|
value, name, cf->name, _(error_type));
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
case CONFIG_ORIGIN_CMDLINE:
|
2016-08-21 14:50:39 +00:00
|
|
|
die(_("bad numeric config value '%s' for '%s' in command line %s: %s"),
|
2019-06-21 10:18:07 +00:00
|
|
|
value, name, cf->name, _(error_type));
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
default:
|
2016-08-21 14:50:39 +00:00
|
|
|
die(_("bad numeric config value '%s' for '%s' in %s: %s"),
|
2019-06-21 10:18:07 +00:00
|
|
|
value, name, cf->name, _(error_type));
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
}
|
2008-02-21 00:00:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-12 13:32:26 +00:00
|
|
|
int git_config_int(const char *name, const char *value)
|
|
|
|
{
|
2013-09-08 08:33:08 +00:00
|
|
|
int ret;
|
|
|
|
if (!git_parse_int(value, &ret))
|
2013-09-08 08:38:22 +00:00
|
|
|
die_bad_number(name, value);
|
2007-07-12 13:32:26 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
git-config: always treat --int as 64-bit internally
When you run "git config --int", the maximum size of integer
you get depends on how git was compiled, and what it
considers to be an "int".
This is almost useful, because your scripts calling "git
config" will behave similarly to git internally. But relying
on this is dubious; you have to actually know how git treats
each value internally (e.g., int versus unsigned long),
which is not documented and is subject to change. And even
if you know it is "unsigned long", we do not have a
git-config option to match that behavior.
Furthermore, you may simply be asking git to store a value
on your behalf (e.g., configuration for a hook). In that
case, the relevant range check has nothing at all to do with
git, but rather with whatever scripting tools you are using
(and git has no way of knowing what the appropriate range is
there).
Not only is the range check useless, but it is actively
harmful, as there is no way at all for scripts to look
at config variables with large values. For instance, one
cannot reliably get the value of pack.packSizeLimit via
git-config. On an LP64 system, git happily uses a 64-bit
"unsigned long" internally to represent the value, but the
script cannot read any value over 2G.
Ideally, the "--int" option would simply represent an
arbitrarily large integer. For practical purposes, however,
a 64-bit integer is large enough, and is much easier to
implement (and if somebody overflows it, we will still
notice the problem, and not simply return garbage).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-09-08 08:40:02 +00:00
|
|
|
int64_t git_config_int64(const char *name, const char *value)
|
|
|
|
{
|
|
|
|
int64_t ret;
|
|
|
|
if (!git_parse_int64(value, &ret))
|
|
|
|
die_bad_number(name, value);
|
2007-07-12 13:32:26 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long git_config_ulong(const char *name, const char *value)
|
|
|
|
{
|
|
|
|
unsigned long ret;
|
|
|
|
if (!git_parse_ulong(value, &ret))
|
2013-09-08 08:38:22 +00:00
|
|
|
die_bad_number(name, value);
|
2007-07-12 13:32:26 +00:00
|
|
|
return ret;
|
2005-10-10 23:31:08 +00:00
|
|
|
}
|
|
|
|
|
2017-04-11 18:13:57 +00:00
|
|
|
ssize_t git_config_ssize_t(const char *name, const char *value)
|
|
|
|
{
|
|
|
|
ssize_t ret;
|
|
|
|
if (!git_parse_ssize_t(value, &ret))
|
|
|
|
die_bad_number(name, value);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-08-07 18:20:47 +00:00
|
|
|
static int git_parse_maybe_bool_text(const char *value)
|
2005-10-10 23:31:08 +00:00
|
|
|
{
|
|
|
|
if (!value)
|
|
|
|
return 1;
|
|
|
|
if (!*value)
|
|
|
|
return 0;
|
2010-02-17 07:59:46 +00:00
|
|
|
if (!strcasecmp(value, "true")
|
|
|
|
|| !strcasecmp(value, "yes")
|
|
|
|
|| !strcasecmp(value, "on"))
|
2005-10-10 23:31:08 +00:00
|
|
|
return 1;
|
2010-02-17 07:59:46 +00:00
|
|
|
if (!strcasecmp(value, "false")
|
|
|
|
|| !strcasecmp(value, "no")
|
|
|
|
|| !strcasecmp(value, "off"))
|
2005-10-10 23:31:08 +00:00
|
|
|
return 0;
|
2010-02-17 07:59:46 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-03-10 22:43:22 +00:00
|
|
|
static const struct fsync_component_name {
|
|
|
|
const char *name;
|
|
|
|
enum fsync_component component_bits;
|
|
|
|
} fsync_component_names[] = {
|
|
|
|
{ "loose-object", FSYNC_COMPONENT_LOOSE_OBJECT },
|
|
|
|
{ "pack", FSYNC_COMPONENT_PACK },
|
|
|
|
{ "pack-metadata", FSYNC_COMPONENT_PACK_METADATA },
|
|
|
|
{ "commit-graph", FSYNC_COMPONENT_COMMIT_GRAPH },
|
2022-03-10 22:43:23 +00:00
|
|
|
{ "index", FSYNC_COMPONENT_INDEX },
|
2022-03-15 19:12:45 +00:00
|
|
|
{ "objects", FSYNC_COMPONENTS_OBJECTS },
|
2022-03-11 09:58:59 +00:00
|
|
|
{ "reference", FSYNC_COMPONENT_REFERENCE },
|
2022-03-15 19:12:45 +00:00
|
|
|
{ "derived-metadata", FSYNC_COMPONENTS_DERIVED_METADATA },
|
|
|
|
{ "committed", FSYNC_COMPONENTS_COMMITTED },
|
|
|
|
{ "added", FSYNC_COMPONENTS_ADDED },
|
|
|
|
{ "all", FSYNC_COMPONENTS_ALL },
|
2022-03-10 22:43:22 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static enum fsync_component parse_fsync_components(const char *var, const char *string)
|
|
|
|
{
|
2022-04-05 05:20:14 +00:00
|
|
|
enum fsync_component current = FSYNC_COMPONENTS_PLATFORM_DEFAULT;
|
2022-03-10 22:43:22 +00:00
|
|
|
enum fsync_component positive = 0, negative = 0;
|
|
|
|
|
|
|
|
while (string) {
|
|
|
|
int i;
|
|
|
|
size_t len;
|
|
|
|
const char *ep;
|
|
|
|
int negated = 0;
|
|
|
|
int found = 0;
|
|
|
|
|
|
|
|
string = string + strspn(string, ", \t\n\r");
|
|
|
|
ep = strchrnul(string, ',');
|
|
|
|
len = ep - string;
|
|
|
|
if (!strcmp(string, "none")) {
|
|
|
|
current = FSYNC_COMPONENT_NONE;
|
|
|
|
goto next_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*string == '-') {
|
|
|
|
negated = 1;
|
|
|
|
string++;
|
|
|
|
len--;
|
|
|
|
if (!len)
|
|
|
|
warning(_("invalid value for variable %s"), var);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!len)
|
|
|
|
break;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(fsync_component_names); ++i) {
|
|
|
|
const struct fsync_component_name *n = &fsync_component_names[i];
|
|
|
|
|
|
|
|
if (strncmp(n->name, string, len))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
found = 1;
|
|
|
|
if (negated)
|
|
|
|
negative |= n->component_bits;
|
|
|
|
else
|
|
|
|
positive |= n->component_bits;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
char *component = xstrndup(string, len);
|
|
|
|
warning(_("ignoring unknown core.fsync component '%s'"), component);
|
|
|
|
free(component);
|
|
|
|
}
|
|
|
|
|
|
|
|
next_name:
|
|
|
|
string = ep;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (current & ~negative) | positive;
|
|
|
|
}
|
|
|
|
|
2017-08-07 18:20:47 +00:00
|
|
|
int git_parse_maybe_bool(const char *value)
|
2010-11-17 17:00:45 +00:00
|
|
|
{
|
2017-08-07 18:20:47 +00:00
|
|
|
int v = git_parse_maybe_bool_text(value);
|
2010-11-17 17:00:45 +00:00
|
|
|
if (0 <= v)
|
|
|
|
return v;
|
2013-09-08 08:33:08 +00:00
|
|
|
if (git_parse_int(value, &v))
|
2010-12-19 03:36:41 +00:00
|
|
|
return !!v;
|
2010-11-17 17:00:45 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-02-17 07:59:46 +00:00
|
|
|
int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
|
|
|
|
{
|
2017-08-07 18:20:47 +00:00
|
|
|
int v = git_parse_maybe_bool_text(value);
|
2010-02-17 07:59:46 +00:00
|
|
|
if (0 <= v) {
|
|
|
|
*is_bool = 1;
|
|
|
|
return v;
|
|
|
|
}
|
2008-04-13 01:33:31 +00:00
|
|
|
*is_bool = 0;
|
2008-04-13 19:11:11 +00:00
|
|
|
return git_config_int(name, value);
|
2005-10-10 23:31:08 +00:00
|
|
|
}
|
|
|
|
|
2008-04-13 01:33:31 +00:00
|
|
|
int git_config_bool(const char *name, const char *value)
|
|
|
|
{
|
2021-02-11 20:30:53 +00:00
|
|
|
int v = git_parse_maybe_bool(value);
|
|
|
|
if (v < 0)
|
2021-04-08 13:25:55 +00:00
|
|
|
die(_("bad boolean config value '%s' for '%s'"), value, name);
|
2021-02-11 20:30:53 +00:00
|
|
|
return v;
|
2008-04-13 01:33:31 +00:00
|
|
|
}
|
|
|
|
|
2008-02-16 05:00:24 +00:00
|
|
|
int git_config_string(const char **dest, const char *var, const char *value)
|
|
|
|
{
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
|
|
|
*dest = xstrdup(value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-11-17 17:24:25 +00:00
|
|
|
int git_config_pathname(const char **dest, const char *var, const char *value)
|
|
|
|
{
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
2021-07-24 22:06:52 +00:00
|
|
|
*dest = interpolate_path(value, 0);
|
2009-11-17 17:24:25 +00:00
|
|
|
if (!*dest)
|
2014-08-07 11:59:12 +00:00
|
|
|
die(_("failed to expand user dir in: '%s'"), value);
|
2009-11-17 17:24:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-11-18 02:27:27 +00:00
|
|
|
int git_config_expiry_date(timestamp_t *timestamp, const char *var, const char *value)
|
|
|
|
{
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
|
|
|
if (parse_expiry_date(value, timestamp))
|
|
|
|
return error(_("'%s' for '%s' is not a valid timestamp"),
|
|
|
|
value, var);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-10 00:18:28 +00:00
|
|
|
int git_config_color(char *dest, const char *var, const char *value)
|
|
|
|
{
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
|
|
|
if (color_parse(value, dest) < 0)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-30 18:40:04 +00:00
|
|
|
static int git_default_core_config(const char *var, const char *value, void *cb)
|
2005-10-10 23:31:08 +00:00
|
|
|
{
|
|
|
|
/* This needs a better name */
|
|
|
|
if (!strcmp(var, "core.filemode")) {
|
|
|
|
trust_executable_bit = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
2008-07-28 06:31:28 +00:00
|
|
|
if (!strcmp(var, "core.trustctime")) {
|
|
|
|
trust_ctime = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
2013-05-07 05:32:58 +00:00
|
|
|
if (!strcmp(var, "core.checkstat")) {
|
2013-01-22 07:49:22 +00:00
|
|
|
if (!strcasecmp(value, "default"))
|
|
|
|
check_stat = 1;
|
|
|
|
else if (!strcasecmp(value, "minimal"))
|
|
|
|
check_stat = 0;
|
|
|
|
}
|
2005-10-10 23:31:08 +00:00
|
|
|
|
2007-06-24 22:11:24 +00:00
|
|
|
if (!strcmp(var, "core.quotepath")) {
|
|
|
|
quote_path_fully = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-03-02 21:11:30 +00:00
|
|
|
if (!strcmp(var, "core.symlinks")) {
|
|
|
|
has_symlinks = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-03-21 23:52:46 +00:00
|
|
|
if (!strcmp(var, "core.ignorecase")) {
|
|
|
|
ignore_case = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-10-06 18:22:24 +00:00
|
|
|
if (!strcmp(var, "core.attributesfile"))
|
|
|
|
return git_config_pathname(&git_attributes_file, var, value);
|
|
|
|
|
2016-05-04 22:58:12 +00:00
|
|
|
if (!strcmp(var, "core.hookspath"))
|
|
|
|
return git_config_pathname(&git_hooks_path, var, value);
|
|
|
|
|
2007-01-07 10:00:28 +00:00
|
|
|
if (!strcmp(var, "core.bare")) {
|
|
|
|
is_bare_repository_cfg = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-02-09 05:15:24 +00:00
|
|
|
if (!strcmp(var, "core.ignorestat")) {
|
|
|
|
assume_unchanged = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-05-02 07:40:24 +00:00
|
|
|
if (!strcmp(var, "core.prefersymlinkrefs")) {
|
|
|
|
prefer_symlink_refs = git_config_bool(var, value);
|
2005-11-15 18:24:19 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-05-17 09:55:40 +00:00
|
|
|
if (!strcmp(var, "core.logallrefupdates")) {
|
2017-01-27 10:09:47 +00:00
|
|
|
if (value && !strcasecmp(value, "always"))
|
|
|
|
log_all_ref_updates = LOG_REFS_ALWAYS;
|
|
|
|
else if (git_config_bool(var, value))
|
|
|
|
log_all_ref_updates = LOG_REFS_NORMAL;
|
|
|
|
else
|
|
|
|
log_all_ref_updates = LOG_REFS_NONE;
|
2006-05-17 09:55:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-21 02:45:47 +00:00
|
|
|
if (!strcmp(var, "core.warnambiguousrefs")) {
|
|
|
|
warn_ambiguous_refs = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-03-21 05:26:24 +00:00
|
|
|
if (!strcmp(var, "core.abbrev")) {
|
2016-11-02 01:34:07 +00:00
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
|
|
|
if (!strcasecmp(value, "auto"))
|
|
|
|
default_abbrev = -1;
|
2020-09-01 07:43:55 +00:00
|
|
|
else if (!git_parse_maybe_bool_text(value))
|
|
|
|
default_abbrev = the_hash_algo->hexsz;
|
2016-11-02 01:34:07 +00:00
|
|
|
else {
|
|
|
|
int abbrev = git_config_int(var, value);
|
2019-08-18 20:04:13 +00:00
|
|
|
if (abbrev < minimum_abbrev || abbrev > the_hash_algo->hexsz)
|
2018-07-21 07:49:27 +00:00
|
|
|
return error(_("abbrev length out of range: %d"), abbrev);
|
2016-11-02 01:34:07 +00:00
|
|
|
default_abbrev = abbrev;
|
|
|
|
}
|
2010-10-28 18:28:04 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-09-27 12:38:01 +00:00
|
|
|
if (!strcmp(var, "core.disambiguate"))
|
|
|
|
return set_disambiguate_hint_config(var, value);
|
|
|
|
|
Custom compression levels for objects and packs
Add config variables pack.compression and core.loosecompression ,
and switch --compression=level to pack-objects.
Loose objects will be compressed using core.loosecompression if set,
else core.compression if set, else Z_BEST_SPEED.
Packed objects will be compressed using --compression=level if seen,
else pack.compression if set, else core.compression if set,
else Z_DEFAULT_COMPRESSION. This is the "pack compression level".
Loose objects added to a pack undeltified will be recompressed
to the pack compression level if it is unequal to the current
loose compression level by the preceding rules, or if the loose
object was written while core.legacyheaders = true. Newly
deltified loose objects are always compressed to the current
pack compression level.
Previously packed objects added to a pack are recompressed
to the current pack compression level exactly when their
deltification status changes, since the previous pack data
cannot be reused.
In either case, the --no-reuse-object switch from the first
patch below will always force recompression to the current pack
compression level, instead of assuming the pack compression level
hasn't changed and pack data can be reused when possible.
This applies on top of the following patches from Nicolas Pitre:
[PATCH] allow for undeltified objects not to be reused
[PATCH] make "repack -f" imply "pack-objects --no-reuse-object"
Signed-off-by: Dana L. How <danahow@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-09 20:56:50 +00:00
|
|
|
if (!strcmp(var, "core.loosecompression")) {
|
2006-07-03 20:11:47 +00:00
|
|
|
int level = git_config_int(var, value);
|
|
|
|
if (level == -1)
|
|
|
|
level = Z_DEFAULT_COMPRESSION;
|
|
|
|
else if (level < 0 || level > Z_BEST_COMPRESSION)
|
2014-08-07 11:59:12 +00:00
|
|
|
die(_("bad zlib compression level %d"), level);
|
2006-07-03 20:11:47 +00:00
|
|
|
zlib_compression_level = level;
|
Custom compression levels for objects and packs
Add config variables pack.compression and core.loosecompression ,
and switch --compression=level to pack-objects.
Loose objects will be compressed using core.loosecompression if set,
else core.compression if set, else Z_BEST_SPEED.
Packed objects will be compressed using --compression=level if seen,
else pack.compression if set, else core.compression if set,
else Z_DEFAULT_COMPRESSION. This is the "pack compression level".
Loose objects added to a pack undeltified will be recompressed
to the pack compression level if it is unequal to the current
loose compression level by the preceding rules, or if the loose
object was written while core.legacyheaders = true. Newly
deltified loose objects are always compressed to the current
pack compression level.
Previously packed objects added to a pack are recompressed
to the current pack compression level exactly when their
deltification status changes, since the previous pack data
cannot be reused.
In either case, the --no-reuse-object switch from the first
patch below will always force recompression to the current pack
compression level, instead of assuming the pack compression level
hasn't changed and pack data can be reused when possible.
This applies on top of the following patches from Nicolas Pitre:
[PATCH] allow for undeltified objects not to be reused
[PATCH] make "repack -f" imply "pack-objects --no-reuse-object"
Signed-off-by: Dana L. How <danahow@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-09 20:56:50 +00:00
|
|
|
zlib_compression_seen = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(var, "core.compression")) {
|
|
|
|
int level = git_config_int(var, value);
|
|
|
|
if (level == -1)
|
|
|
|
level = Z_DEFAULT_COMPRESSION;
|
|
|
|
else if (level < 0 || level > Z_BEST_COMPRESSION)
|
2014-08-07 11:59:12 +00:00
|
|
|
die(_("bad zlib compression level %d"), level);
|
Custom compression levels for objects and packs
Add config variables pack.compression and core.loosecompression ,
and switch --compression=level to pack-objects.
Loose objects will be compressed using core.loosecompression if set,
else core.compression if set, else Z_BEST_SPEED.
Packed objects will be compressed using --compression=level if seen,
else pack.compression if set, else core.compression if set,
else Z_DEFAULT_COMPRESSION. This is the "pack compression level".
Loose objects added to a pack undeltified will be recompressed
to the pack compression level if it is unequal to the current
loose compression level by the preceding rules, or if the loose
object was written while core.legacyheaders = true. Newly
deltified loose objects are always compressed to the current
pack compression level.
Previously packed objects added to a pack are recompressed
to the current pack compression level exactly when their
deltification status changes, since the previous pack data
cannot be reused.
In either case, the --no-reuse-object switch from the first
patch below will always force recompression to the current pack
compression level, instead of assuming the pack compression level
hasn't changed and pack data can be reused when possible.
This applies on top of the following patches from Nicolas Pitre:
[PATCH] allow for undeltified objects not to be reused
[PATCH] make "repack -f" imply "pack-objects --no-reuse-object"
Signed-off-by: Dana L. How <danahow@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-09 20:56:50 +00:00
|
|
|
if (!zlib_compression_seen)
|
|
|
|
zlib_compression_level = level;
|
2016-11-16 01:42:40 +00:00
|
|
|
if (!pack_compression_seen)
|
|
|
|
pack_compression_level = level;
|
2006-07-03 20:11:47 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-23 07:34:28 +00:00
|
|
|
if (!strcmp(var, "core.packedgitwindowsize")) {
|
2007-02-14 21:20:41 +00:00
|
|
|
int pgsz_x2 = getpagesize() * 2;
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 15:46:23 +00:00
|
|
|
packed_git_window_size = git_config_ulong(var, value);
|
2007-02-14 21:20:41 +00:00
|
|
|
|
|
|
|
/* This value must be multiple of (pagesize * 2) */
|
|
|
|
packed_git_window_size /= pgsz_x2;
|
|
|
|
if (packed_git_window_size < 1)
|
|
|
|
packed_git_window_size = 1;
|
|
|
|
packed_git_window_size *= pgsz_x2;
|
2006-12-23 07:34:28 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-04-05 17:44:11 +00:00
|
|
|
if (!strcmp(var, "core.bigfilethreshold")) {
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 15:46:23 +00:00
|
|
|
big_file_threshold = git_config_ulong(var, value);
|
2011-04-05 17:44:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-23 07:33:35 +00:00
|
|
|
if (!strcmp(var, "core.packedgitlimit")) {
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 15:46:23 +00:00
|
|
|
packed_git_limit = git_config_ulong(var, value);
|
2006-12-23 07:33:35 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-03-19 05:14:37 +00:00
|
|
|
if (!strcmp(var, "core.deltabasecachelimit")) {
|
Support sizes >=2G in various config options accepting 'g' sizes.
The config options core.packedGitWindowSize, core.packedGitLimit,
core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and
pack.packSizeLimit all claim to support suffixes up to and including
'g'. This implies that they should accept sizes >=2G on 64-bit
systems: certainly, specifying a size of 3g should not silently be
translated to zero or transformed into a large negative value due to
integer overflow. However, due to use of git_config_int() rather than
git_config_ulong(), that is exactly what happens:
% git config core.bigFileThreshold 2g
% git gc --aggressive # with extra debugging code to print out
# core.bigfilethreshold after parsing
bigfilethreshold: -2147483648
[...]
This is probably irrelevant for core.deltaBaseCacheLimit, but is
problematic for the other values. (It is particularly problematic for
core.packedGitLimit, which can't even be set to its default value in
the config file due to this bug.)
This fixes things for 32-bit platforms as well. They get the usual bad
config error if an overlarge value is specified, e.g.:
fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig
This is detected in all cases, even if the 32-bit platform has no size
larger than 'long'. For signed integral configuration values, we also
detect the case where the value is too large for the signed type but
not the unsigned type.
Signed-off-by: Nick Alcock <nix@esperi.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-02 15:46:23 +00:00
|
|
|
delta_base_cache_limit = git_config_ulong(var, value);
|
2007-03-19 05:14:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 19:07:23 +00:00
|
|
|
if (!strcmp(var, "core.autocrlf")) {
|
2007-02-14 02:16:12 +00:00
|
|
|
if (value && !strcasecmp(value, "input")) {
|
2010-05-19 20:43:10 +00:00
|
|
|
auto_crlf = AUTO_CRLF_INPUT;
|
2007-02-14 02:16:12 +00:00
|
|
|
return 0;
|
|
|
|
}
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 19:07:23 +00:00
|
|
|
auto_crlf = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 11:25:58 +00:00
|
|
|
if (!strcmp(var, "core.safecrlf")) {
|
2018-01-13 22:49:31 +00:00
|
|
|
int eol_rndtrp_die;
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 11:25:58 +00:00
|
|
|
if (value && !strcasecmp(value, "warn")) {
|
2018-01-13 22:49:31 +00:00
|
|
|
global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 11:25:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2018-01-13 22:49:31 +00:00
|
|
|
eol_rndtrp_die = git_config_bool(var, value);
|
|
|
|
global_conv_flags_eol = eol_rndtrp_die ?
|
2018-06-04 20:17:42 +00:00
|
|
|
CONV_EOL_RNDTRP_DIE : 0;
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 11:25:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-06-04 19:29:08 +00:00
|
|
|
if (!strcmp(var, "core.eol")) {
|
|
|
|
if (value && !strcasecmp(value, "lf"))
|
2011-05-09 19:52:12 +00:00
|
|
|
core_eol = EOL_LF;
|
2010-06-04 19:29:08 +00:00
|
|
|
else if (value && !strcasecmp(value, "crlf"))
|
2011-05-09 19:52:12 +00:00
|
|
|
core_eol = EOL_CRLF;
|
2010-06-04 19:29:08 +00:00
|
|
|
else if (value && !strcasecmp(value, "native"))
|
2011-05-09 19:52:12 +00:00
|
|
|
core_eol = EOL_NATIVE;
|
2010-06-04 19:29:08 +00:00
|
|
|
else
|
2011-05-09 19:52:12 +00:00
|
|
|
core_eol = EOL_UNSET;
|
2010-06-04 19:29:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-15 18:16:10 +00:00
|
|
|
if (!strcmp(var, "core.checkroundtripencoding")) {
|
|
|
|
check_roundtrip_encoding = xstrdup(value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-10-09 10:21:57 +00:00
|
|
|
if (!strcmp(var, "core.notesref")) {
|
|
|
|
notes_ref_name = xstrdup(value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-06-18 21:37:18 +00:00
|
|
|
if (!strcmp(var, "core.editor"))
|
|
|
|
return git_config_string(&editor_program, var, value);
|
|
|
|
|
2013-01-16 19:18:48 +00:00
|
|
|
if (!strcmp(var, "core.commentchar")) {
|
2014-07-24 04:42:39 +00:00
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
2014-07-28 18:30:41 +00:00
|
|
|
else if (!strcasecmp(value, "auto"))
|
2014-05-17 01:52:23 +00:00
|
|
|
auto_comment_line_char = 1;
|
2014-07-28 18:30:41 +00:00
|
|
|
else if (value[0] && !value[1]) {
|
2014-07-24 04:42:39 +00:00
|
|
|
comment_line_char = value[0];
|
2014-05-17 01:52:23 +00:00
|
|
|
auto_comment_line_char = 0;
|
2014-05-17 01:52:22 +00:00
|
|
|
} else
|
2018-07-21 07:49:27 +00:00
|
|
|
return error(_("core.commentChar should only be one character"));
|
2014-05-17 01:52:22 +00:00
|
|
|
return 0;
|
2013-01-16 19:18:48 +00:00
|
|
|
}
|
|
|
|
|
2010-08-30 13:38:38 +00:00
|
|
|
if (!strcmp(var, "core.askpass"))
|
|
|
|
return git_config_string(&askpass_program, var, value);
|
|
|
|
|
2008-06-18 21:37:18 +00:00
|
|
|
if (!strcmp(var, "core.excludesfile"))
|
2009-11-17 17:24:25 +00:00
|
|
|
return git_config_pathname(&excludes_file, var, value);
|
2008-06-18 21:37:18 +00:00
|
|
|
|
|
|
|
if (!strcmp(var, "core.whitespace")) {
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
|
|
|
whitespace_rule_cfg = parse_whitespace_rule(value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-03-10 22:43:22 +00:00
|
|
|
if (!strcmp(var, "core.fsync")) {
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
|
|
|
fsync_components = parse_fsync_components(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-03-10 22:43:20 +00:00
|
|
|
if (!strcmp(var, "core.fsyncmethod")) {
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
|
|
|
if (!strcmp(value, "fsync"))
|
|
|
|
fsync_method = FSYNC_METHOD_FSYNC;
|
|
|
|
else if (!strcmp(value, "writeout-only"))
|
|
|
|
fsync_method = FSYNC_METHOD_WRITEOUT_ONLY;
|
core.fsyncmethod: batched disk flushes for loose-objects
When adding many objects to a repo with `core.fsync=loose-object`,
the cost of fsync'ing each object file can become prohibitive.
One major source of the cost of fsync is the implied flush of the
hardware writeback cache within the disk drive. This commit introduces
a new `core.fsyncMethod=batch` option that batches up hardware flushes.
It hooks into the bulk-checkin odb-transaction functionality, takes
advantage of tmp-objdir, and uses the writeout-only support code.
When the new mode is enabled, we do the following for each new object:
1a. Create the object in a tmp-objdir.
2a. Issue a pagecache writeback request and wait for it to complete.
At the end of the entire transaction when unplugging bulk checkin:
1b. Issue an fsync against a dummy file to flush the log and hardware
writeback cache, which should by now have seen the tmp-objdir writes.
2b. Rename all of the tmp-objdir files to their final names.
3b. When updating the index and/or refs, we assume that Git will issue
another fsync internal to that operation. This is not the default
today, but the user now has the option of syncing the index and there
is a separate patch series to implement syncing of refs.
On a filesystem with a singular journal that is updated during name
operations (e.g. create, link, rename, etc), such as NTFS, HFS+, or XFS
we would expect the fsync to trigger a journal writeout so that this
sequence is enough to ensure that the user's data is durable by the time
the git command returns. This sequence also ensures that no object files
appear in the main object store unless they are fsync-durable.
Batch mode is only enabled if core.fsync includes loose-objects. If
the legacy core.fsyncObjectFiles setting is enabled, but core.fsync does
not include loose-objects, we will use file-by-file fsyncing.
In step (1a) of the sequence, the tmp-objdir is created lazily to avoid
work if no loose objects are ever added to the ODB. We use a tmp-objdir
to maintain the invariant that no loose-objects are visible in the main
ODB unless they are properly fsync-durable. This is important since
future ODB operations that try to create an object with specific
contents will silently drop the new data if an object with the target
hash exists without checking that the loose-object contents match the
hash. Only a full git-fsck would restore the ODB to a functional state
where dataloss doesn't occur.
In step (1b) of the sequence, we issue a fsync against a dummy file
created specifically for the purpose. This method has a little higher
cost than using one of the input object files, but makes adding new
callers of this mechanism easier, since we don't need to figure out
which object file is "last" or risk sharing violations by caching the fd
of the last object file.
_Performance numbers_:
Linux - Hyper-V VM running Kernel 5.11 (Ubuntu 20.04) on a fast SSD.
Mac - macOS 11.5.1 running on a Mac mini on a 1TB Apple SSD.
Windows - Same host as Linux, a preview version of Windows 11.
Adding 500 files to the repo with 'git add' Times reported in seconds.
object file syncing | Linux | Mac | Windows
--------------------|-------|-------|--------
disabled | 0.06 | 0.35 | 0.61
fsync | 1.88 | 11.18 | 2.47
batch | 0.15 | 0.41 | 1.53
Signed-off-by: Neeraj Singh <neerajsi@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-04-05 05:20:09 +00:00
|
|
|
else if (!strcmp(value, "batch"))
|
|
|
|
fsync_method = FSYNC_METHOD_BATCH;
|
2022-03-10 22:43:20 +00:00
|
|
|
else
|
|
|
|
warning(_("ignoring unknown core.fsyncMethod value '%s'"), value);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-06-18 22:18:44 +00:00
|
|
|
if (!strcmp(var, "core.fsyncobjectfiles")) {
|
2022-03-10 22:43:22 +00:00
|
|
|
if (fsync_object_files < 0)
|
2022-03-30 18:08:36 +00:00
|
|
|
warning(_("core.fsyncObjectFiles is deprecated; use core.fsync instead"));
|
2008-06-18 22:18:44 +00:00
|
|
|
fsync_object_files = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-14 00:36:30 +00:00
|
|
|
if (!strcmp(var, "core.preloadindex")) {
|
|
|
|
core_preload_index = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-04-27 22:32:25 +00:00
|
|
|
if (!strcmp(var, "core.createobject")) {
|
|
|
|
if (!strcmp(value, "rename"))
|
|
|
|
object_creation_mode = OBJECT_CREATION_USES_RENAMES;
|
|
|
|
else if (!strcmp(value, "link"))
|
|
|
|
object_creation_mode = OBJECT_CREATION_USES_HARDLINKS;
|
|
|
|
else
|
2014-08-07 11:59:12 +00:00
|
|
|
die(_("invalid mode for object creation: %s"), value);
|
2009-04-25 09:57:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-08-20 13:47:08 +00:00
|
|
|
if (!strcmp(var, "core.sparsecheckout")) {
|
|
|
|
core_apply_sparse_checkout = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-21 22:04:40 +00:00
|
|
|
if (!strcmp(var, "core.sparsecheckoutcone")) {
|
|
|
|
core_sparse_checkout_cone = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
git on Mac OS and precomposed unicode
Mac OS X mangles file names containing unicode on file systems HFS+,
VFAT or SAMBA. When a file using unicode code points outside ASCII
is created on a HFS+ drive, the file name is converted into
decomposed unicode and written to disk. No conversion is done if
the file name is already decomposed unicode.
Calling open("\xc3\x84", ...) with a precomposed "Ä" yields the same
result as open("\x41\xcc\x88",...) with a decomposed "Ä".
As a consequence, readdir() returns the file names in decomposed
unicode, even if the user expects precomposed unicode. Unlike on
HFS+, Mac OS X stores files on a VFAT drive (e.g. an USB drive) in
precomposed unicode, but readdir() still returns file names in
decomposed unicode. When a git repository is stored on a network
share using SAMBA, file names are send over the wire and written to
disk on the remote system in precomposed unicode, but Mac OS X
readdir() returns decomposed unicode to be compatible with its
behaviour on HFS+ and VFAT.
The unicode decomposition causes many problems:
- The names "git add" and other commands get from the end user may
often be precomposed form (the decomposed form is not easily input
from the keyboard), but when the commands read from the filesystem
to see what it is going to update the index with already is on the
filesystem, readdir() will give decomposed form, which is different.
- Similarly "git log", "git mv" and all other commands that need to
compare pathnames found on the command line (often but not always
precomposed form; a command line input resulting from globbing may
be in decomposed) with pathnames found in the tree objects (should
be precomposed form to be compatible with other systems and for
consistency in general).
- The same for names stored in the index, which should be
precomposed, that may need to be compared with the names read from
readdir().
NFS mounted from Linux is fully transparent and does not suffer from
the above.
As Mac OS X treats precomposed and decomposed file names as equal,
we can
- wrap readdir() on Mac OS X to return the precomposed form, and
- normalize decomposed form given from the command line also to the
precomposed form,
to ensure that all pathnames used in Git are always in the
precomposed form. This behaviour can be requested by setting
"core.precomposedunicode" configuration variable to true.
The code in compat/precomposed_utf8.c implements basically 4 new
functions: precomposed_utf8_opendir(), precomposed_utf8_readdir(),
precomposed_utf8_closedir() and precompose_argv(). The first three
are to wrap opendir(3), readdir(3), and closedir(3) functions.
The argv[] conversion allows to use the TAB filename completion done
by the shell on command line. It tolerates other tools which use
readdir() to feed decomposed file names into git.
When creating a new git repository with "git init" or "git clone",
"core.precomposedunicode" will be set "false".
The user needs to activate this feature manually. She typically
sets core.precomposedunicode to "true" on HFS and VFAT, or file
systems mounted via SAMBA.
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-07-08 13:50:25 +00:00
|
|
|
if (!strcmp(var, "core.precomposeunicode")) {
|
|
|
|
precomposed_unicode = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-15 23:15:20 +00:00
|
|
|
if (!strcmp(var, "core.protecthfs")) {
|
|
|
|
protect_hfs = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-16 22:46:59 +00:00
|
|
|
if (!strcmp(var, "core.protectntfs")) {
|
|
|
|
protect_ntfs = git_config_bool(var, value);
|
|
|
|
return 0;
|
git on Mac OS and precomposed unicode
Mac OS X mangles file names containing unicode on file systems HFS+,
VFAT or SAMBA. When a file using unicode code points outside ASCII
is created on a HFS+ drive, the file name is converted into
decomposed unicode and written to disk. No conversion is done if
the file name is already decomposed unicode.
Calling open("\xc3\x84", ...) with a precomposed "Ä" yields the same
result as open("\x41\xcc\x88",...) with a decomposed "Ä".
As a consequence, readdir() returns the file names in decomposed
unicode, even if the user expects precomposed unicode. Unlike on
HFS+, Mac OS X stores files on a VFAT drive (e.g. an USB drive) in
precomposed unicode, but readdir() still returns file names in
decomposed unicode. When a git repository is stored on a network
share using SAMBA, file names are send over the wire and written to
disk on the remote system in precomposed unicode, but Mac OS X
readdir() returns decomposed unicode to be compatible with its
behaviour on HFS+ and VFAT.
The unicode decomposition causes many problems:
- The names "git add" and other commands get from the end user may
often be precomposed form (the decomposed form is not easily input
from the keyboard), but when the commands read from the filesystem
to see what it is going to update the index with already is on the
filesystem, readdir() will give decomposed form, which is different.
- Similarly "git log", "git mv" and all other commands that need to
compare pathnames found on the command line (often but not always
precomposed form; a command line input resulting from globbing may
be in decomposed) with pathnames found in the tree objects (should
be precomposed form to be compatible with other systems and for
consistency in general).
- The same for names stored in the index, which should be
precomposed, that may need to be compared with the names read from
readdir().
NFS mounted from Linux is fully transparent and does not suffer from
the above.
As Mac OS X treats precomposed and decomposed file names as equal,
we can
- wrap readdir() on Mac OS X to return the precomposed form, and
- normalize decomposed form given from the command line also to the
precomposed form,
to ensure that all pathnames used in Git are always in the
precomposed form. This behaviour can be requested by setting
"core.precomposedunicode" configuration variable to true.
The code in compat/precomposed_utf8.c implements basically 4 new
functions: precomposed_utf8_opendir(), precomposed_utf8_readdir(),
precomposed_utf8_closedir() and precompose_argv(). The first three
are to wrap opendir(3), readdir(3), and closedir(3) functions.
The argv[] conversion allows to use the TAB filename completion done
by the shell on command line. It tolerates other tools which use
readdir() to feed decomposed file names into git.
When creating a new git repository with "git init" or "git clone",
"core.precomposedunicode" will be set "false".
The user needs to activate this feature manually. She typically
sets core.precomposedunicode to "true" on HFS and VFAT, or file
systems mounted via SAMBA.
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-07-08 13:50:25 +00:00
|
|
|
}
|
|
|
|
|
2018-07-18 20:45:25 +00:00
|
|
|
if (!strcmp(var, "core.usereplacerefs")) {
|
|
|
|
read_replace_refs = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-06-18 21:37:18 +00:00
|
|
|
/* Add other config variables here and to Documentation/config.txt. */
|
2018-10-30 18:40:04 +00:00
|
|
|
return platform_core_config(var, value, cb);
|
2008-06-18 21:37:18 +00:00
|
|
|
}
|
|
|
|
|
repo_read_index: add config to expect files outside sparse patterns
Typically with sparse checkouts, we expect files outside the sparsity
patterns to be marked as SKIP_WORKTREE and be missing from the working
tree. Sometimes this expectation would be violated however; including
in cases such as:
* users grabbing files from elsewhere and writing them to the worktree
(perhaps by editing a cached copy in an editor, copying/renaming, or
even untarring)
* various git commands having incomplete or no support for the
SKIP_WORKTREE bit[1,2]
* users attempting to "abort" a sparse-checkout operation with a
not-so-early Ctrl+C (updating $GIT_DIR/info/sparse-checkout and the
working tree is not atomic)[3].
When the SKIP_WORKTREE bit in the index did not reflect the presence of
the file in the working tree, it traditionally caused confusion and was
difficult to detect and recover from. So, in a sparse checkout, since
af6a51875a (repo_read_index: clear SKIP_WORKTREE bit from files present
in worktree, 2022-01-14), Git automatically clears the SKIP_WORKTREE
bit at index read time for entries corresponding to files that are
present in the working tree.
There is another workflow, however, where it is expected that paths
outside the sparsity patterns appear to exist in the working tree and
that they do not lose the SKIP_WORKTREE bit, at least until they get
modified. A Git-aware virtual file system[4] takes advantage of its
position as a file system driver to expose all files in the working
tree, fetch them on demand using partial clone on access, and tell Git
to pay attention to them on demand by updating the sparse checkout
pattern on writes. This means that commands like "git status" only have
to examine files that have potentially been modified, whereas commands
like "ls" are able to show the entire codebase without requiring manual
updates to the sparse checkout pattern.
Thus since af6a51875a, Git with such Git-aware virtual file systems
unsets the SKIP_WORKTREE bit for all files and commands like "git
status" have to fetch and examine them all.
Introduce a configuration setting sparse.expectFilesOutsideOfPatterns to
allow limiting the tracked set of files to a small set once again. A
Git-aware virtual file system or other application that wants to
maintain files outside of the sparse checkout can set this in a
repository to instruct Git not to check for the presence of
SKIP_WORKTREE files. The setting defaults to false, so most users of
sparse checkout will still get the benefit of an automatically updating
index to recover from the variety of difficult issues detailed in
af6a51875a for paths with SKIP_WORKTREE set despite the path being
present.
[1] https://lore.kernel.org/git/xmqqbmb1a7ga.fsf@gitster-ct.c.googlers.com/
[2] The three long paragraphs in the middle of
https://lore.kernel.org/git/CABPp-BH9tju7WVm=QZDOvaMDdZbpNXrVWQdN-jmfN8wC6YVhmw@mail.gmail.com/
[3] https://lore.kernel.org/git/CABPp-BFnFpzwGC11TLoLs8YK5yiisA5D5-fFjXnJsbESVDwZsA@mail.gmail.com/
[4] such as the vfsd described in
https://lore.kernel.org/git/20220207190320.2960362-1-jonathantanmy@google.com/
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-26 06:12:22 +00:00
|
|
|
static int git_default_sparse_config(const char *var, const char *value)
|
|
|
|
{
|
|
|
|
if (!strcmp(var, "sparse.expectfilesoutsideofpatterns")) {
|
|
|
|
sparse_expect_files_outside_of_patterns = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add other config variables here and to Documentation/config/sparse.txt. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-06-18 22:00:11 +00:00
|
|
|
static int git_default_i18n_config(const char *var, const char *value)
|
2008-06-18 21:40:35 +00:00
|
|
|
{
|
2008-02-16 05:00:24 +00:00
|
|
|
if (!strcmp(var, "i18n.commitencoding"))
|
|
|
|
return git_config_string(&git_commit_encoding, var, value);
|
2006-12-28 00:41:33 +00:00
|
|
|
|
2008-02-16 05:00:24 +00:00
|
|
|
if (!strcmp(var, "i18n.logoutputencoding"))
|
|
|
|
return git_config_string(&git_log_output_encoding, var, value);
|
2006-12-28 00:41:33 +00:00
|
|
|
|
2008-06-18 22:00:11 +00:00
|
|
|
/* Add other config variables here and to Documentation/config.txt. */
|
|
|
|
return 0;
|
|
|
|
}
|
core.excludesfile clean-up
There are inconsistencies in the way commands currently handle
the core.excludesfile configuration variable. The problem is
the variable is too new to be noticed by anything other than
git-add and git-status.
* git-ls-files does not notice any of the "ignore" files by
default, as it predates the standardized set of ignore files.
The calling scripts established the convention to use
.git/info/exclude, .gitignore, and later core.excludesfile.
* git-add and git-status know about it because they call
add_excludes_from_file() directly with their own notion of
which standard set of ignore files to use. This is just a
stupid duplication of code that need to be updated every time
the definition of the standard set of ignore files is
changed.
* git-read-tree takes --exclude-per-directory=<gitignore>,
not because the flexibility was needed. Again, this was
because the option predates the standardization of the ignore
files.
* git-merge-recursive uses hardcoded per-directory .gitignore
and nothing else. git-clean (scripted version) does not
honor core.* because its call to underlying ls-files does not
know about it. git-clean in C (parked in 'pu') doesn't either.
We probably could change git-ls-files to use the standard set
when no excludes are specified on the command line and ignore
processing was asked, or something like that, but that will be a
change in semantics and might break people's scripts in a subtle
way. I am somewhat reluctant to make such a change.
On the other hand, I think it makes perfect sense to fix
git-read-tree, git-merge-recursive and git-clean to follow the
same rule as other commands. I do not think of a valid use case
to give an exclude-per-directory that is nonstandard to
read-tree command, outside a "negative" test in the t1004 test
script.
This patch is the first step to untangle this mess.
The next step would be to teach read-tree, merge-recursive and
clean (in C) to use setup_standard_excludes().
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-14 08:05:00 +00:00
|
|
|
|
2008-06-18 22:00:11 +00:00
|
|
|
static int git_default_branch_config(const char *var, const char *value)
|
|
|
|
{
|
2008-02-19 16:24:37 +00:00
|
|
|
if (!strcmp(var, "branch.autosetupmerge")) {
|
2021-12-21 03:30:24 +00:00
|
|
|
if (value && !strcmp(value, "always")) {
|
2008-02-19 16:24:37 +00:00
|
|
|
git_branch_track = BRANCH_TRACK_ALWAYS;
|
|
|
|
return 0;
|
branch: add flags and config to inherit tracking
It can be helpful when creating a new branch to use the existing
tracking configuration from the branch point. However, there is
currently not a method to automatically do so.
Teach git-{branch,checkout,switch} an "inherit" argument to the
"--track" option. When this is set, creating a new branch will cause the
tracking configuration to default to the configuration of the branch
point, if set.
For example, if branch "main" tracks "origin/main", and we run
`git checkout --track=inherit -b feature main`, then branch "feature"
will track "origin/main". Thus, `git status` will show us how far
ahead/behind we are from origin, and `git pull` will pull from origin.
This is particularly useful when creating branches across many
submodules, such as with `git submodule foreach ...` (or if running with
a patch such as [1], which we use at $job), as it avoids having to
manually set tracking info for each submodule.
Since we've added an argument to "--track", also add "--track=direct" as
another way to explicitly get the original "--track" behavior ("--track"
without an argument still works as well).
Finally, teach branch.autoSetupMerge a new "inherit" option. When this
is set, "--track=inherit" becomes the default behavior.
[1]: https://lore.kernel.org/git/20180927221603.148025-1-sbeller@google.com/
Signed-off-by: Josh Steadmon <steadmon@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-12-21 03:30:23 +00:00
|
|
|
} else if (value && !strcmp(value, "inherit")) {
|
|
|
|
git_branch_track = BRANCH_TRACK_INHERIT;
|
|
|
|
return 0;
|
branch: new autosetupmerge option 'simple' for matching branches
With the default push.default option, "simple", beginners are
protected from accidentally pushing to the "wrong" branch in
centralized workflows: if the remote tracking branch they would push
to does not have the same name as the local branch, and they try to do
a "default push", they get an error and explanation with options.
There is a particular centralized workflow where this often happens:
a user branches to a new local topic branch from an existing
remote branch, eg with "checkout -b feature1 origin/master". With
the default branch.autosetupmerge configuration (value "true"), git
will automatically add origin/master as the upstream tracking branch.
When the user pushes with a default "git push", with the intention of
pushing their (new) topic branch to the remote, they get an error, and
(amongst other things) a suggestion to run "git push origin HEAD".
If they follow this suggestion the push succeeds, but on subsequent
default pushes they continue to get an error - so eventually they
figure out to add "-u" to change the tracking branch, or they spelunk
the push.default config doc as proposed and set it to "current", or
some GUI tooling does one or the other of these things for them.
When one of their coworkers later works on the same topic branch,
they don't get any of that "weirdness". They just "git checkout
feature1" and everything works exactly as they expect, with the shared
remote branch set up as remote tracking branch, and push and pull
working out of the box.
The "stable state" for this way of working is that local branches have
the same-name remote tracking branch (origin/feature1 in this
example), and multiple people can work on that remote feature branch
at the same time, trusting "git pull" to merge or rebase as required
for them to be able to push their interim changes to that same feature
branch on that same remote.
(merging from the upstream "master" branch, and merging back to it,
are separate more involved processes in this flow).
There is a problem in this flow/way of working, however, which is that
the first user, when they first branched from origin/master, ended up
with the "wrong" remote tracking branch (different from the stable
state). For a while, before they pushed (and maybe longer, if they
don't use -u/--set-upstream), their "git pull" wasn't getting other
users' changes to the feature branch - it was getting any changes from
the remote "master" branch instead (a completely different class of
changes!)
An experienced git user might say "well yeah, that's what it means to
have the remote tracking branch set to origin/master!" - but the
original user above didn't *ask* to have the remote master branch
added as remote tracking branch - that just happened automatically
when they branched their feature branch. They didn't necessarily even
notice or understand the meaning of the "set up to track 'origin/master'"
message when they created the branch - especially if they are using a
GUI.
Looking at how to fix this, you might think "OK, so disable auto setup
of remote tracking - set branch.autosetupmerge to false" - but that
will inconvenience the *second* user in this story - the one who just
wanted to start working on the topic branch. The first and second
users swap roles at different points in time of course - they should
both have a sane configuration that does the right thing in both
situations.
Make this "branches have the same name locally as on the remote"
workflow less painful / more obvious by introducing a new
branch.autosetupmerge option called "simple", to match the same-name
"push.default" option that makes similar assumptions.
This new option automatically sets up tracking in a *subset* of the
current default situations: when the original ref is a remote tracking
branch *and* has the same branch name on the remote (as the new local
branch name).
Update the error displayed when the 'push.default=simple' configuration
rejects a mismatching-upstream-name default push, to offer this new
branch.autosetupmerge option that will prevent this class of error.
With this new configuration, in the example situation above, the first
user does *not* get origin/master set up as the tracking branch for
the new local branch. If they "git pull" in their new local-only
branch, they get an error explaining there is no upstream branch -
which makes sense and is helpful. If they "git push", they get an
error explaining how to push *and* suggesting they specify
--set-upstream - which is exactly the right thing to do for them.
This new option is likely not appropriate for users intentionally
implementing a "triangular workflow" with a shared upstream tracking
branch, that they "git pull" in and a "private" feature branch that
they push/force-push to just for remote safe-keeping until they are
ready to push up to the shared branch explicitly/separately. Such
users are likely to prefer keeping the current default
merge.autosetupmerge=true behavior, and change their push.default to
"current".
Also extend the existing branch tests with three new cases testing
this option - the obvious matching-name and non-matching-name cases,
and also a non-matching-ref-type case. The matching-name case needs to
temporarily create an independent repo to fetch from, as the general
strategy of using the local repo as the remote in these tests
precludes locally branching with the same name as in the "remote".
Signed-off-by: Tao Klerks <tao@klerks.biz>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-04-29 09:56:44 +00:00
|
|
|
} else if (value && !strcmp(value, "simple")) {
|
|
|
|
git_branch_track = BRANCH_TRACK_SIMPLE;
|
|
|
|
return 0;
|
2008-02-19 16:24:37 +00:00
|
|
|
}
|
|
|
|
git_branch_track = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
2008-05-10 22:36:29 +00:00
|
|
|
if (!strcmp(var, "branch.autosetuprebase")) {
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
|
|
|
else if (!strcmp(value, "never"))
|
|
|
|
autorebase = AUTOREBASE_NEVER;
|
|
|
|
else if (!strcmp(value, "local"))
|
|
|
|
autorebase = AUTOREBASE_LOCAL;
|
|
|
|
else if (!strcmp(value, "remote"))
|
|
|
|
autorebase = AUTOREBASE_REMOTE;
|
|
|
|
else if (!strcmp(value, "always"))
|
|
|
|
autorebase = AUTOREBASE_ALWAYS;
|
|
|
|
else
|
2018-07-21 07:49:27 +00:00
|
|
|
return error(_("malformed value for %s"), var);
|
2008-05-10 22:36:29 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2007-11-02 07:24:27 +00:00
|
|
|
|
2006-04-24 22:59:33 +00:00
|
|
|
/* Add other config variables here and to Documentation/config.txt. */
|
2005-10-10 23:31:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-16 15:42:51 +00:00
|
|
|
static int git_default_push_config(const char *var, const char *value)
|
|
|
|
{
|
|
|
|
if (!strcmp(var, "push.default")) {
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
|
|
|
else if (!strcmp(value, "nothing"))
|
|
|
|
push_default = PUSH_DEFAULT_NOTHING;
|
|
|
|
else if (!strcmp(value, "matching"))
|
|
|
|
push_default = PUSH_DEFAULT_MATCHING;
|
2012-04-24 07:50:03 +00:00
|
|
|
else if (!strcmp(value, "simple"))
|
|
|
|
push_default = PUSH_DEFAULT_SIMPLE;
|
2011-02-16 00:54:24 +00:00
|
|
|
else if (!strcmp(value, "upstream"))
|
|
|
|
push_default = PUSH_DEFAULT_UPSTREAM;
|
|
|
|
else if (!strcmp(value, "tracking")) /* deprecated */
|
|
|
|
push_default = PUSH_DEFAULT_UPSTREAM;
|
2009-03-16 15:42:51 +00:00
|
|
|
else if (!strcmp(value, "current"))
|
|
|
|
push_default = PUSH_DEFAULT_CURRENT;
|
|
|
|
else {
|
2018-07-21 07:49:27 +00:00
|
|
|
error(_("malformed value for %s: %s"), var, value);
|
|
|
|
return error(_("must be one of nothing, matching, simple, "
|
|
|
|
"upstream or current"));
|
2009-03-16 15:42:51 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add other config variables here and to Documentation/config.txt. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-02-08 14:34:27 +00:00
|
|
|
static int git_default_mailmap_config(const char *var, const char *value)
|
|
|
|
{
|
|
|
|
if (!strcmp(var, "mailmap.file"))
|
2014-05-27 08:45:58 +00:00
|
|
|
return git_config_pathname(&git_mailmap_file, var, value);
|
2012-12-12 11:04:04 +00:00
|
|
|
if (!strcmp(var, "mailmap.blob"))
|
|
|
|
return git_config_string(&git_mailmap_blob, var, value);
|
2009-02-08 14:34:27 +00:00
|
|
|
|
|
|
|
/* Add other config variables here and to Documentation/config.txt. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-30 18:40:03 +00:00
|
|
|
int git_default_config(const char *var, const char *value, void *cb)
|
2008-06-18 22:00:11 +00:00
|
|
|
{
|
2013-11-30 20:55:40 +00:00
|
|
|
if (starts_with(var, "core."))
|
2018-10-30 18:40:04 +00:00
|
|
|
return git_default_core_config(var, value, cb);
|
2008-06-18 22:00:11 +00:00
|
|
|
|
2019-02-04 18:48:50 +00:00
|
|
|
if (starts_with(var, "user.") ||
|
|
|
|
starts_with(var, "author.") ||
|
|
|
|
starts_with(var, "committer."))
|
2018-10-30 18:40:03 +00:00
|
|
|
return git_ident_config(var, value, cb);
|
2008-06-18 22:00:11 +00:00
|
|
|
|
2013-11-30 20:55:40 +00:00
|
|
|
if (starts_with(var, "i18n."))
|
2008-06-18 22:00:11 +00:00
|
|
|
return git_default_i18n_config(var, value);
|
|
|
|
|
2013-11-30 20:55:40 +00:00
|
|
|
if (starts_with(var, "branch."))
|
2008-06-18 22:00:11 +00:00
|
|
|
return git_default_branch_config(var, value);
|
|
|
|
|
2013-11-30 20:55:40 +00:00
|
|
|
if (starts_with(var, "push."))
|
2009-03-16 15:42:51 +00:00
|
|
|
return git_default_push_config(var, value);
|
|
|
|
|
2013-11-30 20:55:40 +00:00
|
|
|
if (starts_with(var, "mailmap."))
|
2009-02-08 14:34:27 +00:00
|
|
|
return git_default_mailmap_config(var, value);
|
|
|
|
|
2018-04-21 10:10:00 +00:00
|
|
|
if (starts_with(var, "advice.") || starts_with(var, "color.advice"))
|
2009-09-09 11:38:58 +00:00
|
|
|
return git_default_advice_config(var, value);
|
|
|
|
|
2008-06-18 22:00:11 +00:00
|
|
|
if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
|
|
|
|
pager_use_color = git_config_bool(var,value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-10-28 21:48:40 +00:00
|
|
|
if (!strcmp(var, "pack.packsizelimit")) {
|
|
|
|
pack_size_limit_cfg = git_config_ulong(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
2016-11-16 01:42:40 +00:00
|
|
|
|
|
|
|
if (!strcmp(var, "pack.compression")) {
|
|
|
|
int level = git_config_int(var, value);
|
|
|
|
if (level == -1)
|
|
|
|
level = Z_DEFAULT_COMPRESSION;
|
|
|
|
else if (level < 0 || level > Z_BEST_COMPRESSION)
|
|
|
|
die(_("bad pack compression level %d"), level);
|
|
|
|
pack_compression_level = level;
|
|
|
|
pack_compression_seen = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
repo_read_index: add config to expect files outside sparse patterns
Typically with sparse checkouts, we expect files outside the sparsity
patterns to be marked as SKIP_WORKTREE and be missing from the working
tree. Sometimes this expectation would be violated however; including
in cases such as:
* users grabbing files from elsewhere and writing them to the worktree
(perhaps by editing a cached copy in an editor, copying/renaming, or
even untarring)
* various git commands having incomplete or no support for the
SKIP_WORKTREE bit[1,2]
* users attempting to "abort" a sparse-checkout operation with a
not-so-early Ctrl+C (updating $GIT_DIR/info/sparse-checkout and the
working tree is not atomic)[3].
When the SKIP_WORKTREE bit in the index did not reflect the presence of
the file in the working tree, it traditionally caused confusion and was
difficult to detect and recover from. So, in a sparse checkout, since
af6a51875a (repo_read_index: clear SKIP_WORKTREE bit from files present
in worktree, 2022-01-14), Git automatically clears the SKIP_WORKTREE
bit at index read time for entries corresponding to files that are
present in the working tree.
There is another workflow, however, where it is expected that paths
outside the sparsity patterns appear to exist in the working tree and
that they do not lose the SKIP_WORKTREE bit, at least until they get
modified. A Git-aware virtual file system[4] takes advantage of its
position as a file system driver to expose all files in the working
tree, fetch them on demand using partial clone on access, and tell Git
to pay attention to them on demand by updating the sparse checkout
pattern on writes. This means that commands like "git status" only have
to examine files that have potentially been modified, whereas commands
like "ls" are able to show the entire codebase without requiring manual
updates to the sparse checkout pattern.
Thus since af6a51875a, Git with such Git-aware virtual file systems
unsets the SKIP_WORKTREE bit for all files and commands like "git
status" have to fetch and examine them all.
Introduce a configuration setting sparse.expectFilesOutsideOfPatterns to
allow limiting the tracked set of files to a small set once again. A
Git-aware virtual file system or other application that wants to
maintain files outside of the sparse checkout can set this in a
repository to instruct Git not to check for the presence of
SKIP_WORKTREE files. The setting defaults to false, so most users of
sparse checkout will still get the benefit of an automatically updating
index to recover from the variety of difficult issues detailed in
af6a51875a for paths with SKIP_WORKTREE set despite the path being
present.
[1] https://lore.kernel.org/git/xmqqbmb1a7ga.fsf@gitster-ct.c.googlers.com/
[2] The three long paragraphs in the middle of
https://lore.kernel.org/git/CABPp-BH9tju7WVm=QZDOvaMDdZbpNXrVWQdN-jmfN8wC6YVhmw@mail.gmail.com/
[3] https://lore.kernel.org/git/CABPp-BFnFpzwGC11TLoLs8YK5yiisA5D5-fFjXnJsbESVDwZsA@mail.gmail.com/
[4] such as the vfsd described in
https://lore.kernel.org/git/20220207190320.2960362-1-jonathantanmy@google.com/
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-26 06:12:22 +00:00
|
|
|
if (starts_with(var, "sparse."))
|
|
|
|
return git_default_sparse_config(var, value);
|
|
|
|
|
2008-06-18 22:00:11 +00:00
|
|
|
/* Add other config variables here and to Documentation/config.txt. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-05-11 13:18:52 +00:00
|
|
|
/*
|
2013-07-11 22:48:30 +00:00
|
|
|
* All source specific fields in the union, die_on_error, name and the callbacks
|
2013-07-11 22:44:39 +00:00
|
|
|
* fgetc, ungetc, ftell of top need to be initialized before calling
|
2013-05-11 13:18:52 +00:00
|
|
|
* this function.
|
|
|
|
*/
|
2018-04-09 08:32:05 +00:00
|
|
|
static int do_config_from(struct config_source *top, config_fn_t fn, void *data,
|
|
|
|
const struct config_options *opts)
|
2013-05-11 13:18:52 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* push config-file parsing state stack */
|
|
|
|
top->prev = cf;
|
|
|
|
top->linenr = 1;
|
|
|
|
top->eof = 0;
|
config: reject parsing of files over INT_MAX
While the last few commits have made it possible for the config parser
to handle config files up to the limits of size_t, the rest of the code
isn't really ready for this. In particular, we often feed the keys as
strings into printf "%s" format specifiers. And because the printf
family of functions must return an int to specify the result, they
complain. Here are two concrete examples (using glibc; we're in
uncharted territory here so results may vary):
Generate a gigantic .gitmodules file like this:
git submodule add /some/other/repo foo
{
printf '[submodule "'
perl -e 'print "a" x 2**31'
echo '"]path = foo'
} >.gitmodules
git commit -m 'huge gitmodule'
then try this:
$ git show
BUG: strbuf.c:397: your vsnprintf is broken (returned -1)
The problem is that we end up calling:
strbuf_addf(&sb, "submodule.%s.ignore", submodule_name);
which relies on vsnprintf(), and that function has no way to report back
a size larger than INT_MAX.
Taking that same file, try this:
git config --file=.gitmodules --list --name-only
On my system it produces an output with exactly 4GB of spaces. I
confirmed in a debugger that we reach the config callback with the key
intact: it's 2147483663 bytes and full of a's. But when we print it with
this call:
printf("%s%c", key_, term);
we just get the spaces.
So given the fact that these are insane cases which we have no need to
support, the weird behavior from feeding the results to printf even if
the code is careful, and the possibility of uncareful code introducing
its own integer truncation issues, let's just declare INT_MAX as a limit
for parsing config files.
We'll enforce the limit in get_next_char(), which generalizes over all
sources (blobs, files, etc) and covers any element we're parsing
(whether section, key, value, etc). For simplicity, the limit is over
the length of the _whole_ file, so you couldn't have two 1GB values in
the same file. This should be perfectly fine, as the expected size for
config files is generally kilobytes at most.
With this patch both cases above will yield:
fatal: bad config line 1 in file .gitmodules
That's not an amazing error message, but the parser isn't set up to
provide specific messages (it just breaks out of the parsing loop and
gives that generic error even if see a syntactic issue). And we really
wouldn't expect to see this case outside of somebody maliciously probing
the limits of the config system.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-10 19:50:07 +00:00
|
|
|
top->total_len = 0;
|
2013-05-11 13:18:52 +00:00
|
|
|
strbuf_init(&top->value, 1024);
|
|
|
|
strbuf_init(&top->var, 1024);
|
|
|
|
cf = top;
|
|
|
|
|
2018-04-09 08:32:05 +00:00
|
|
|
ret = git_parse_source(fn, data, opts);
|
2013-05-11 13:18:52 +00:00
|
|
|
|
|
|
|
/* pop config-file parsing state stack */
|
|
|
|
strbuf_release(&top->value);
|
|
|
|
strbuf_release(&top->var);
|
|
|
|
cf = top->prev;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-02-18 22:58:55 +00:00
|
|
|
static int do_config_from_file(config_fn_t fn,
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
const enum config_origin_type origin_type,
|
|
|
|
const char *name, const char *path, FILE *f,
|
2018-04-09 08:32:05 +00:00
|
|
|
void *data, const struct config_options *opts)
|
2005-10-10 23:31:08 +00:00
|
|
|
{
|
2014-02-18 22:58:55 +00:00
|
|
|
struct config_source top;
|
2018-03-30 19:26:15 +00:00
|
|
|
int ret;
|
2005-10-10 23:31:08 +00:00
|
|
|
|
2014-02-18 22:58:55 +00:00
|
|
|
top.u.file = f;
|
2016-02-19 09:16:01 +00:00
|
|
|
top.origin_type = origin_type;
|
2014-02-18 22:58:55 +00:00
|
|
|
top.name = name;
|
|
|
|
top.path = path;
|
2018-06-28 22:05:00 +00:00
|
|
|
top.default_error_action = CONFIG_ERROR_DIE;
|
2014-02-18 22:58:55 +00:00
|
|
|
top.do_fgetc = config_file_fgetc;
|
|
|
|
top.do_ungetc = config_file_ungetc;
|
|
|
|
top.do_ftell = config_file_ftell;
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
|
2018-03-30 19:26:15 +00:00
|
|
|
flockfile(f);
|
2018-05-08 06:59:18 +00:00
|
|
|
ret = do_config_from(&top, fn, data, opts);
|
2018-03-30 19:26:15 +00:00
|
|
|
funlockfile(f);
|
|
|
|
return ret;
|
2014-02-18 22:58:55 +00:00
|
|
|
}
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
|
2014-02-18 22:58:55 +00:00
|
|
|
static int git_config_from_stdin(config_fn_t fn, void *data)
|
|
|
|
{
|
2018-04-09 08:32:05 +00:00
|
|
|
return do_config_from_file(fn, CONFIG_ORIGIN_STDIN, "", NULL, stdin,
|
|
|
|
data, NULL);
|
2014-02-18 22:58:55 +00:00
|
|
|
}
|
|
|
|
|
2018-04-09 08:32:05 +00:00
|
|
|
int git_config_from_file_with_options(config_fn_t fn, const char *filename,
|
|
|
|
void *data,
|
|
|
|
const struct config_options *opts)
|
2014-02-18 22:58:55 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
FILE *f;
|
config.c: Make git_config() work correctly when called recursively
On Cygwin, this fixes a test failure in t3301-notes.sh (test 98,
"git notes copy --for-rewrite (disabled)").
The test failure is caused by a recursive call to git_config() which
has the effect of skipping to the end-of-file while processing the
"notes.rewriteref" config variable. Thus, any config variables that
appear after "notes.rewriteref" are simply ignored by git_config().
Also, we note that the original FILE handle is leaked as a result
of the recursive call.
The recursive call to git_config() is due to the "schizophrenic stat"
functions on cygwin, where one of two different implementations of
the l/stat functions is selected lazily, depending on some config
variables.
In this case, the init_copy_notes_for_rewrite() function calls
git_config() with the notes_rewrite_config() callback function.
This callback, while processing the "notes.rewriteref" variable,
in turn calls string_list_add_refs_by_glob() to process the
associated ref value. This eventually leads to a call to the
get_ref_dir() function, which in turn calls stat(). On cygwin,
the stat() macro leads to an indirect call to cygwin_stat_stub()
which, via init_stat(), then calls git_config() in order to
determine which l/stat implementation to bind to.
In order to solve this problem, we modify git_config() so that the
global state variables used by the config reading code is packaged
up and managed on a local state stack.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-06-16 20:24:51 +00:00
|
|
|
|
2022-07-26 22:21:06 +00:00
|
|
|
if (!filename)
|
|
|
|
BUG("filename cannot be NULL");
|
2017-05-03 10:16:50 +00:00
|
|
|
f = fopen_or_warn(filename, "r");
|
2014-02-18 22:58:55 +00:00
|
|
|
if (f) {
|
2018-04-09 08:32:05 +00:00
|
|
|
ret = do_config_from_file(fn, CONFIG_ORIGIN_FILE, filename,
|
|
|
|
filename, f, data, opts);
|
2005-10-10 23:31:08 +00:00
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2005-11-17 21:32:36 +00:00
|
|
|
|
2018-04-09 08:32:05 +00:00
|
|
|
int git_config_from_file(config_fn_t fn, const char *filename, void *data)
|
|
|
|
{
|
|
|
|
return git_config_from_file_with_options(fn, filename, data, NULL);
|
|
|
|
}
|
|
|
|
|
2018-06-28 22:05:24 +00:00
|
|
|
int git_config_from_mem(config_fn_t fn,
|
|
|
|
const enum config_origin_type origin_type,
|
|
|
|
const char *name, const char *buf, size_t len,
|
|
|
|
void *data, const struct config_options *opts)
|
2013-07-11 22:46:47 +00:00
|
|
|
{
|
|
|
|
struct config_source top;
|
|
|
|
|
|
|
|
top.u.buf.buf = buf;
|
|
|
|
top.u.buf.len = len;
|
|
|
|
top.u.buf.pos = 0;
|
2016-02-19 09:16:01 +00:00
|
|
|
top.origin_type = origin_type;
|
2013-07-11 22:46:47 +00:00
|
|
|
top.name = name;
|
2014-02-18 22:58:52 +00:00
|
|
|
top.path = NULL;
|
2018-06-28 22:05:00 +00:00
|
|
|
top.default_error_action = CONFIG_ERROR_ERROR;
|
2013-08-26 21:57:18 +00:00
|
|
|
top.do_fgetc = config_buf_fgetc;
|
|
|
|
top.do_ungetc = config_buf_ungetc;
|
|
|
|
top.do_ftell = config_buf_ftell;
|
2013-07-11 22:46:47 +00:00
|
|
|
|
2018-06-28 22:05:24 +00:00
|
|
|
return do_config_from(&top, fn, data, opts);
|
2013-07-11 22:46:47 +00:00
|
|
|
}
|
|
|
|
|
2017-07-13 23:49:20 +00:00
|
|
|
int git_config_from_blob_oid(config_fn_t fn,
|
2016-12-16 19:03:18 +00:00
|
|
|
const char *name,
|
2021-08-16 21:09:57 +00:00
|
|
|
struct repository *repo,
|
2017-07-13 23:49:20 +00:00
|
|
|
const struct object_id *oid,
|
2016-12-16 19:03:18 +00:00
|
|
|
void *data)
|
2013-07-11 22:46:47 +00:00
|
|
|
{
|
|
|
|
enum object_type type;
|
|
|
|
char *buf;
|
|
|
|
unsigned long size;
|
|
|
|
int ret;
|
|
|
|
|
2021-08-16 21:09:57 +00:00
|
|
|
buf = repo_read_object_file(repo, oid, &type, &size);
|
2013-07-11 22:46:47 +00:00
|
|
|
if (!buf)
|
2018-07-21 07:49:27 +00:00
|
|
|
return error(_("unable to load config blob object '%s'"), name);
|
2013-07-11 22:46:47 +00:00
|
|
|
if (type != OBJ_BLOB) {
|
|
|
|
free(buf);
|
2018-07-21 07:49:27 +00:00
|
|
|
return error(_("reference '%s' does not point to a blob"), name);
|
2013-07-11 22:46:47 +00:00
|
|
|
}
|
|
|
|
|
2018-06-28 22:05:24 +00:00
|
|
|
ret = git_config_from_mem(fn, CONFIG_ORIGIN_BLOB, name, buf, size,
|
|
|
|
data, NULL);
|
2013-07-11 22:46:47 +00:00
|
|
|
free(buf);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int git_config_from_blob_ref(config_fn_t fn,
|
2021-08-16 21:09:57 +00:00
|
|
|
struct repository *repo,
|
2013-07-11 22:46:47 +00:00
|
|
|
const char *name,
|
|
|
|
void *data)
|
|
|
|
{
|
2017-07-13 23:49:20 +00:00
|
|
|
struct object_id oid;
|
2013-07-11 22:46:47 +00:00
|
|
|
|
2021-08-16 21:09:57 +00:00
|
|
|
if (repo_get_oid(repo, name, &oid) < 0)
|
2018-07-21 07:49:27 +00:00
|
|
|
return error(_("unable to resolve config blob '%s'"), name);
|
2021-08-16 21:09:57 +00:00
|
|
|
return git_config_from_blob_oid(fn, name, repo, &oid, data);
|
2013-07-11 22:46:47 +00:00
|
|
|
}
|
|
|
|
|
2021-04-19 12:31:08 +00:00
|
|
|
char *git_system_config(void)
|
2007-11-13 20:05:05 +00:00
|
|
|
{
|
config: allow overriding of global and system configuration
In order to have git run in a fully controlled environment without any
misconfiguration, it may be desirable for users or scripts to override
global- and system-level configuration files. We already have a way of
doing this, which is to unset both HOME and XDG_CONFIG_HOME environment
variables and to set `GIT_CONFIG_NOGLOBAL=true`. This is quite kludgy,
and unsetting the first two variables likely has an impact on other
executables spawned by such a script.
The obvious way to fix this would be to introduce `GIT_CONFIG_NOGLOBAL`
as an equivalent to `GIT_CONFIG_NOSYSTEM`. But in the past, it has
turned out that this design is inflexible: we cannot test system-level
parsing of the git configuration in our test harness because there is no
way to change its location, so all tests run with `GIT_CONFIG_NOSYSTEM`
set.
Instead of doing the same mistake with `GIT_CONFIG_NOGLOBAL`, introduce
two new variables `GIT_CONFIG_GLOBAL` and `GIT_CONFIG_SYSTEM`:
- If unset, git continues to use the usual locations.
- If set to a specific path, we skip reading the normal
configuration files and instead take the path. By setting the path
to `/dev/null`, no configuration will be loaded for the respective
level.
This implements the usecase where we want to execute code in a sanitized
environment without any potential misconfigurations via `/dev/null`, but
is more flexible and allows for more usecases than simply adding
`GIT_CONFIG_NOGLOBAL`.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-04-19 12:31:16 +00:00
|
|
|
char *system_config = xstrdup_or_null(getenv("GIT_CONFIG_SYSTEM"));
|
2021-06-22 10:46:48 +00:00
|
|
|
if (!system_config)
|
|
|
|
system_config = system_path(ETC_GITCONFIG);
|
|
|
|
normalize_path_copy(system_config, system_config);
|
|
|
|
return system_config;
|
2007-11-13 20:05:05 +00:00
|
|
|
}
|
|
|
|
|
config: allow overriding of global and system configuration
In order to have git run in a fully controlled environment without any
misconfiguration, it may be desirable for users or scripts to override
global- and system-level configuration files. We already have a way of
doing this, which is to unset both HOME and XDG_CONFIG_HOME environment
variables and to set `GIT_CONFIG_NOGLOBAL=true`. This is quite kludgy,
and unsetting the first two variables likely has an impact on other
executables spawned by such a script.
The obvious way to fix this would be to introduce `GIT_CONFIG_NOGLOBAL`
as an equivalent to `GIT_CONFIG_NOSYSTEM`. But in the past, it has
turned out that this design is inflexible: we cannot test system-level
parsing of the git configuration in our test harness because there is no
way to change its location, so all tests run with `GIT_CONFIG_NOSYSTEM`
set.
Instead of doing the same mistake with `GIT_CONFIG_NOGLOBAL`, introduce
two new variables `GIT_CONFIG_GLOBAL` and `GIT_CONFIG_SYSTEM`:
- If unset, git continues to use the usual locations.
- If set to a specific path, we skip reading the normal
configuration files and instead take the path. By setting the path
to `/dev/null`, no configuration will be loaded for the respective
level.
This implements the usecase where we want to execute code in a sanitized
environment without any potential misconfigurations via `/dev/null`, but
is more flexible and allows for more usecases than simply adding
`GIT_CONFIG_NOGLOBAL`.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-04-19 12:31:16 +00:00
|
|
|
void git_global_config(char **user_out, char **xdg_out)
|
2021-04-19 12:31:12 +00:00
|
|
|
{
|
config: allow overriding of global and system configuration
In order to have git run in a fully controlled environment without any
misconfiguration, it may be desirable for users or scripts to override
global- and system-level configuration files. We already have a way of
doing this, which is to unset both HOME and XDG_CONFIG_HOME environment
variables and to set `GIT_CONFIG_NOGLOBAL=true`. This is quite kludgy,
and unsetting the first two variables likely has an impact on other
executables spawned by such a script.
The obvious way to fix this would be to introduce `GIT_CONFIG_NOGLOBAL`
as an equivalent to `GIT_CONFIG_NOSYSTEM`. But in the past, it has
turned out that this design is inflexible: we cannot test system-level
parsing of the git configuration in our test harness because there is no
way to change its location, so all tests run with `GIT_CONFIG_NOSYSTEM`
set.
Instead of doing the same mistake with `GIT_CONFIG_NOGLOBAL`, introduce
two new variables `GIT_CONFIG_GLOBAL` and `GIT_CONFIG_SYSTEM`:
- If unset, git continues to use the usual locations.
- If set to a specific path, we skip reading the normal
configuration files and instead take the path. By setting the path
to `/dev/null`, no configuration will be loaded for the respective
level.
This implements the usecase where we want to execute code in a sanitized
environment without any potential misconfigurations via `/dev/null`, but
is more flexible and allows for more usecases than simply adding
`GIT_CONFIG_NOGLOBAL`.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-04-19 12:31:16 +00:00
|
|
|
char *user_config = xstrdup_or_null(getenv("GIT_CONFIG_GLOBAL"));
|
|
|
|
char *xdg_config = NULL;
|
|
|
|
|
|
|
|
if (!user_config) {
|
2021-07-24 22:06:52 +00:00
|
|
|
user_config = interpolate_path("~/.gitconfig", 0);
|
config: allow overriding of global and system configuration
In order to have git run in a fully controlled environment without any
misconfiguration, it may be desirable for users or scripts to override
global- and system-level configuration files. We already have a way of
doing this, which is to unset both HOME and XDG_CONFIG_HOME environment
variables and to set `GIT_CONFIG_NOGLOBAL=true`. This is quite kludgy,
and unsetting the first two variables likely has an impact on other
executables spawned by such a script.
The obvious way to fix this would be to introduce `GIT_CONFIG_NOGLOBAL`
as an equivalent to `GIT_CONFIG_NOSYSTEM`. But in the past, it has
turned out that this design is inflexible: we cannot test system-level
parsing of the git configuration in our test harness because there is no
way to change its location, so all tests run with `GIT_CONFIG_NOSYSTEM`
set.
Instead of doing the same mistake with `GIT_CONFIG_NOGLOBAL`, introduce
two new variables `GIT_CONFIG_GLOBAL` and `GIT_CONFIG_SYSTEM`:
- If unset, git continues to use the usual locations.
- If set to a specific path, we skip reading the normal
configuration files and instead take the path. By setting the path
to `/dev/null`, no configuration will be loaded for the respective
level.
This implements the usecase where we want to execute code in a sanitized
environment without any potential misconfigurations via `/dev/null`, but
is more flexible and allows for more usecases than simply adding
`GIT_CONFIG_NOGLOBAL`.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-04-19 12:31:16 +00:00
|
|
|
xdg_config = xdg_config_home("config");
|
|
|
|
}
|
|
|
|
|
|
|
|
*user_out = user_config;
|
|
|
|
*xdg_out = xdg_config;
|
2007-11-13 20:05:05 +00:00
|
|
|
}
|
|
|
|
|
2014-08-26 15:23:21 +00:00
|
|
|
/*
|
|
|
|
* Parse environment variable 'k' as a boolean (in various
|
|
|
|
* possible spellings); if missing, use the default value 'def'.
|
|
|
|
*/
|
2010-03-17 19:55:51 +00:00
|
|
|
int git_env_bool(const char *k, int def)
|
2008-02-06 10:11:18 +00:00
|
|
|
{
|
|
|
|
const char *v = getenv(k);
|
|
|
|
return v ? git_config_bool(k, v) : def;
|
|
|
|
}
|
|
|
|
|
2014-08-26 15:23:21 +00:00
|
|
|
/*
|
|
|
|
* Parse environment variable 'k' as ulong with possibly a unit
|
|
|
|
* suffix; if missing, use the default value 'val'.
|
|
|
|
*/
|
|
|
|
unsigned long git_env_ulong(const char *k, unsigned long val)
|
|
|
|
{
|
|
|
|
const char *v = getenv(k);
|
|
|
|
if (v && !git_parse_ulong(v, &val))
|
2018-07-21 07:49:27 +00:00
|
|
|
die(_("failed to parse %s"), k);
|
2014-08-26 15:23:21 +00:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2008-02-06 10:11:18 +00:00
|
|
|
int git_config_system(void)
|
|
|
|
{
|
|
|
|
return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
|
|
|
|
}
|
|
|
|
|
2017-04-17 10:10:02 +00:00
|
|
|
static int do_git_config_sequence(const struct config_options *opts,
|
|
|
|
config_fn_t fn, void *data)
|
2005-11-26 00:03:56 +00:00
|
|
|
{
|
2016-05-18 22:39:02 +00:00
|
|
|
int ret = 0;
|
2021-04-19 12:31:08 +00:00
|
|
|
char *system_config = git_system_config();
|
2021-04-19 12:31:12 +00:00
|
|
|
char *xdg_config = NULL;
|
|
|
|
char *user_config = NULL;
|
2017-04-17 10:10:02 +00:00
|
|
|
char *repo_config;
|
2020-02-10 00:30:56 +00:00
|
|
|
enum config_scope prev_parsing_scope = current_parsing_scope;
|
2017-04-17 10:10:02 +00:00
|
|
|
|
2017-06-14 18:07:38 +00:00
|
|
|
if (opts->commondir)
|
|
|
|
repo_config = mkpathdup("%s/config", opts->commondir);
|
2018-11-14 13:59:02 +00:00
|
|
|
else if (opts->git_dir)
|
|
|
|
BUG("git_dir without commondir");
|
2017-04-17 10:10:02 +00:00
|
|
|
else
|
|
|
|
repo_config = NULL;
|
Read configuration also from $HOME/.gitconfig
This patch is based on Pasky's, with three notable differences:
- I did not yet update the documentation
- I named it .gitconfig, not .gitrc
- git-repo-config does not barf when a unique key is overridden locally
The last means that if you have something like
[alias]
l = log --stat -M
in ~/.gitconfig, and
[alias]
l = log --stat -M next..
in $GIT_DIR/config, then
git-repo-config alias.l
returns only one value, namely the value from $GIT_DIR/config.
If you set the environment variable GIT_CONFIG, $HOME/.gitconfig is not
read, and neither $GIT_DIR/config, but $GIT_CONFIG instead.
If you set GIT_CONFIG_LOCAL instead, it is interpreted instead of
$GIT_DIR/config, but $HOME/.gitconfig is still read.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-19 23:48:03 +00:00
|
|
|
|
config: add a notion of "scope"
A config callback passed to git_config() doesn't know very
much about the context in which it sees a variable. It can
ask whether the variable comes from a file, and get the file
name. But without analyzing the filename (which is hard to
do accurately), it cannot tell whether it is in system-level
config, user-level config, or repo-specific config.
Generally this doesn't matter; the point of not passing this
to the callback is that it should treat the config the same
no matter where it comes from. But some programs, like
upload-pack, are a special case: we should be able to run
them in an untrusted repository, which means we cannot use
any "dangerous" config from the repository config file (but
it is OK to use it from system or user config).
This patch teaches the config code to record the "scope" of
each variable, and make it available inside config
callbacks, similar to how we give access to the filename.
The scope is the starting source for a particular parsing
operation, and remains the same even if we include other
files (so a .git/config which includes another file will
remain CONFIG_SCOPE_REPO, as it would be similarly
untrusted).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-05-18 22:44:23 +00:00
|
|
|
current_parsing_scope = CONFIG_SCOPE_SYSTEM;
|
2021-04-19 12:31:08 +00:00
|
|
|
if (git_config_system() && system_config &&
|
|
|
|
!access_or_die(system_config, R_OK,
|
|
|
|
opts->system_gently ? ACCESS_EACCES_OK : 0))
|
|
|
|
ret += git_config_from_file(fn, system_config, data);
|
Read configuration also from $HOME/.gitconfig
This patch is based on Pasky's, with three notable differences:
- I did not yet update the documentation
- I named it .gitconfig, not .gitrc
- git-repo-config does not barf when a unique key is overridden locally
The last means that if you have something like
[alias]
l = log --stat -M
in ~/.gitconfig, and
[alias]
l = log --stat -M next..
in $GIT_DIR/config, then
git-repo-config alias.l
returns only one value, namely the value from $GIT_DIR/config.
If you set the environment variable GIT_CONFIG, $HOME/.gitconfig is not
read, and neither $GIT_DIR/config, but $GIT_CONFIG instead.
If you set GIT_CONFIG_LOCAL instead, it is interpreted instead of
$GIT_DIR/config, but $HOME/.gitconfig is still read.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-19 23:48:03 +00:00
|
|
|
|
config: add a notion of "scope"
A config callback passed to git_config() doesn't know very
much about the context in which it sees a variable. It can
ask whether the variable comes from a file, and get the file
name. But without analyzing the filename (which is hard to
do accurately), it cannot tell whether it is in system-level
config, user-level config, or repo-specific config.
Generally this doesn't matter; the point of not passing this
to the callback is that it should treat the config the same
no matter where it comes from. But some programs, like
upload-pack, are a special case: we should be able to run
them in an untrusted repository, which means we cannot use
any "dangerous" config from the repository config file (but
it is OK to use it from system or user config).
This patch teaches the config code to record the "scope" of
each variable, and make it available inside config
callbacks, similar to how we give access to the filename.
The scope is the starting source for a particular parsing
operation, and remains the same even if we include other
files (so a .git/config which includes another file will
remain CONFIG_SCOPE_REPO, as it would be similarly
untrusted).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-05-18 22:44:23 +00:00
|
|
|
current_parsing_scope = CONFIG_SCOPE_GLOBAL;
|
2021-04-19 12:31:12 +00:00
|
|
|
git_global_config(&user_config, &xdg_config);
|
|
|
|
|
2016-05-18 22:39:02 +00:00
|
|
|
if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK))
|
2012-06-22 09:03:23 +00:00
|
|
|
ret += git_config_from_file(fn, xdg_config, data);
|
|
|
|
|
2016-05-18 22:39:02 +00:00
|
|
|
if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
|
2012-06-22 09:03:23 +00:00
|
|
|
ret += git_config_from_file(fn, user_config, data);
|
Read configuration also from $HOME/.gitconfig
This patch is based on Pasky's, with three notable differences:
- I did not yet update the documentation
- I named it .gitconfig, not .gitrc
- git-repo-config does not barf when a unique key is overridden locally
The last means that if you have something like
[alias]
l = log --stat -M
in ~/.gitconfig, and
[alias]
l = log --stat -M next..
in $GIT_DIR/config, then
git-repo-config alias.l
returns only one value, namely the value from $GIT_DIR/config.
If you set the environment variable GIT_CONFIG, $HOME/.gitconfig is not
read, and neither $GIT_DIR/config, but $GIT_CONFIG instead.
If you set GIT_CONFIG_LOCAL instead, it is interpreted instead of
$GIT_DIR/config, but $HOME/.gitconfig is still read.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-19 23:48:03 +00:00
|
|
|
|
2020-02-10 00:30:54 +00:00
|
|
|
current_parsing_scope = CONFIG_SCOPE_LOCAL;
|
2019-04-15 20:39:46 +00:00
|
|
|
if (!opts->ignore_repo && repo_config &&
|
|
|
|
!access_or_die(repo_config, R_OK, 0))
|
2009-02-21 00:48:55 +00:00
|
|
|
ret += git_config_from_file(fn, repo_config, data);
|
2010-03-26 22:53:57 +00:00
|
|
|
|
2020-02-10 00:30:54 +00:00
|
|
|
current_parsing_scope = CONFIG_SCOPE_WORKTREE;
|
2019-04-15 20:39:46 +00:00
|
|
|
if (!opts->ignore_worktree && repository_format_worktree_config) {
|
2018-10-21 14:02:28 +00:00
|
|
|
char *path = git_pathdup("config.worktree");
|
|
|
|
if (!access_or_die(path, R_OK, 0))
|
|
|
|
ret += git_config_from_file(fn, path, data);
|
|
|
|
free(path);
|
|
|
|
}
|
|
|
|
|
2020-02-10 00:30:55 +00:00
|
|
|
current_parsing_scope = CONFIG_SCOPE_COMMAND;
|
2019-04-15 20:39:46 +00:00
|
|
|
if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
|
2014-08-07 11:59:12 +00:00
|
|
|
die(_("unable to parse command-line config"));
|
2010-03-26 22:53:57 +00:00
|
|
|
|
2020-02-10 00:30:56 +00:00
|
|
|
current_parsing_scope = prev_parsing_scope;
|
2021-04-19 12:31:08 +00:00
|
|
|
free(system_config);
|
2012-06-22 09:03:23 +00:00
|
|
|
free(xdg_config);
|
|
|
|
free(user_config);
|
2016-03-11 22:37:03 +00:00
|
|
|
free(repo_config);
|
2016-05-18 22:39:02 +00:00
|
|
|
return ret;
|
2005-11-26 00:03:56 +00:00
|
|
|
}
|
|
|
|
|
2017-06-14 18:07:39 +00:00
|
|
|
int config_with_options(config_fn_t fn, void *data,
|
|
|
|
struct git_config_source *config_source,
|
|
|
|
const struct config_options *opts)
|
2010-11-26 15:32:33 +00:00
|
|
|
{
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
struct config_include_data inc = CONFIG_INCLUDE_INIT;
|
2022-01-18 17:47:40 +00:00
|
|
|
int ret;
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
|
2017-04-17 10:10:00 +00:00
|
|
|
if (opts->respect_includes) {
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
inc.fn = fn;
|
|
|
|
inc.data = data;
|
2017-04-17 10:10:00 +00:00
|
|
|
inc.opts = opts;
|
2022-01-18 17:47:40 +00:00
|
|
|
inc.config_source = config_source;
|
config: add include directive
It can be useful to split your ~/.gitconfig across multiple
files. For example, you might have a "main" file which is
used on many machines, but a small set of per-machine
tweaks. Or you may want to make some of your config public
(e.g., clever aliases) while keeping other data back (e.g.,
your name or other identifying information). Or you may want
to include a number of config options in some subset of your
repos without copying and pasting (e.g., you want to
reference them from the .git/config of participating repos).
This patch introduces an include directive for config files.
It looks like:
[include]
path = /path/to/file
This is syntactically backwards-compatible with existing git
config parsers (i.e., they will see it as another config
entry and ignore it unless you are looking up include.path).
The implementation provides a "git_config_include" callback
which wraps regular config callbacks. Callers can pass it to
git_config_from_file, and it will transparently follow any
include directives, passing all of the discovered options to
the real callback.
Include directives are turned on automatically for "regular"
git config parsing. This includes calls to git_config, as
well as calls to the "git config" program that do not
specify a single file (e.g., using "-f", "--global", etc).
They are not turned on in other cases, including:
1. Parsing of other config-like files, like .gitmodules.
There isn't a real need, and I'd rather be conservative
and avoid unnecessary incompatibility or confusion.
2. Reading single files via "git config". This is for two
reasons:
a. backwards compatibility with scripts looking at
config-like files.
b. inspection of a specific file probably means you
care about just what's in that file, not a general
lookup for "do we have this value anywhere at
all". If that is not the case, the caller can
always specify "--includes".
3. Writing files via "git config"; we want to treat
include.* variables as literal items to be copied (or
modified), and not expand them. So "git config
--unset-all foo.bar" would operate _only_ on
.git/config, not any of its included files (just as it
also does not operate on ~/.gitconfig).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-06 09:54:04 +00:00
|
|
|
fn = git_config_include;
|
|
|
|
data = &inc;
|
|
|
|
}
|
2010-11-26 15:32:33 +00:00
|
|
|
|
2020-02-10 00:30:57 +00:00
|
|
|
if (config_source)
|
|
|
|
current_parsing_scope = config_source->scope;
|
|
|
|
|
config: provide a version of git_config with more options
Callers may want to provide a specific version of a file in which to look
for config. Right now this can be done by setting the magic global
config_exclusive_filename variable. By providing a version of git_config
that takes a filename, we can take a step towards making this magic global
go away.
Furthermore, by providing a more "advanced" interface, we now have a a
natural place to add new options for callers like git-config, which care
about tweaking the specifics of config lookup, without disturbing the
large number of "simple" users (i.e., every other part of git).
The astute reader of this patch may notice that the logic for handling
config_exclusive_filename was taken out of git_config_early, but added
into git_config. This means that git_config_early will no longer respect
config_exclusive_filename. That's OK, because the only other caller of
git_config_early is check_repository_format_gently, but the only function
which sets config_exclusive_filename is cmd_config, which does not call
check_repository_format_gently (and if it did, it would have been a bug,
anyway, as we would be checking the repository format in the wrong file).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-16 08:05:56 +00:00
|
|
|
/*
|
|
|
|
* If we have a specific filename, use it. Otherwise, follow the
|
|
|
|
* regular lookup sequence.
|
|
|
|
*/
|
2021-08-16 21:09:57 +00:00
|
|
|
if (config_source && config_source->use_stdin) {
|
2022-01-18 17:47:40 +00:00
|
|
|
ret = git_config_from_stdin(fn, data);
|
2021-08-16 21:09:57 +00:00
|
|
|
} else if (config_source && config_source->file) {
|
2022-01-18 17:47:40 +00:00
|
|
|
ret = git_config_from_file(fn, config_source->file, data);
|
2021-08-16 21:09:57 +00:00
|
|
|
} else if (config_source && config_source->blob) {
|
|
|
|
struct repository *repo = config_source->repo ?
|
|
|
|
config_source->repo : the_repository;
|
2022-01-18 17:47:40 +00:00
|
|
|
ret = git_config_from_blob_ref(fn, repo, config_source->blob,
|
2021-08-16 21:09:57 +00:00
|
|
|
data);
|
2022-01-18 17:47:40 +00:00
|
|
|
} else {
|
|
|
|
ret = do_git_config_sequence(opts, fn, data);
|
2021-08-16 21:09:57 +00:00
|
|
|
}
|
config: provide a version of git_config with more options
Callers may want to provide a specific version of a file in which to look
for config. Right now this can be done by setting the magic global
config_exclusive_filename variable. By providing a version of git_config
that takes a filename, we can take a step towards making this magic global
go away.
Furthermore, by providing a more "advanced" interface, we now have a a
natural place to add new options for callers like git-config, which care
about tweaking the specifics of config lookup, without disturbing the
large number of "simple" users (i.e., every other part of git).
The astute reader of this patch may notice that the logic for handling
config_exclusive_filename was taken out of git_config_early, but added
into git_config. This means that git_config_early will no longer respect
config_exclusive_filename. That's OK, because the only other caller of
git_config_early is check_repository_format_gently, but the only function
which sets config_exclusive_filename is cmd_config, which does not call
check_repository_format_gently (and if it did, it would have been a bug,
anyway, as we would be checking the repository format in the wrong file).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-16 08:05:56 +00:00
|
|
|
|
2022-01-18 17:47:40 +00:00
|
|
|
if (inc.remote_urls) {
|
|
|
|
string_list_clear(inc.remote_urls, 0);
|
|
|
|
FREE_AND_NULL(inc.remote_urls);
|
|
|
|
}
|
|
|
|
return ret;
|
2010-11-26 15:32:33 +00:00
|
|
|
}
|
|
|
|
|
2014-08-07 11:59:17 +00:00
|
|
|
static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)
|
config: provide a version of git_config with more options
Callers may want to provide a specific version of a file in which to look
for config. Right now this can be done by setting the magic global
config_exclusive_filename variable. By providing a version of git_config
that takes a filename, we can take a step towards making this magic global
go away.
Furthermore, by providing a more "advanced" interface, we now have a a
natural place to add new options for callers like git-config, which care
about tweaking the specifics of config lookup, without disturbing the
large number of "simple" users (i.e., every other part of git).
The astute reader of this patch may notice that the logic for handling
config_exclusive_filename was taken out of git_config_early, but added
into git_config. This means that git_config_early will no longer respect
config_exclusive_filename. That's OK, because the only other caller of
git_config_early is check_repository_format_gently, but the only function
which sets config_exclusive_filename is cmd_config, which does not call
check_repository_format_gently (and if it did, it would have been a bug,
anyway, as we would be checking the repository format in the wrong file).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-16 08:05:56 +00:00
|
|
|
{
|
2014-08-07 11:59:17 +00:00
|
|
|
int i, value_index;
|
|
|
|
struct string_list *values;
|
|
|
|
struct config_set_element *entry;
|
|
|
|
struct configset_list *list = &cs->list;
|
|
|
|
|
|
|
|
for (i = 0; i < list->nr; i++) {
|
|
|
|
entry = list->items[i].e;
|
|
|
|
value_index = list->items[i].value_index;
|
|
|
|
values = &entry->value_list;
|
2016-05-27 00:32:23 +00:00
|
|
|
|
|
|
|
current_config_kvi = values->items[value_index].util;
|
|
|
|
|
|
|
|
if (fn(entry->key, values->items[value_index].string, data) < 0)
|
|
|
|
git_die_config_linenr(entry->key,
|
|
|
|
current_config_kvi->filename,
|
|
|
|
current_config_kvi->linenr);
|
|
|
|
|
|
|
|
current_config_kvi = NULL;
|
2014-08-07 11:59:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-13 20:11:04 +00:00
|
|
|
void read_early_config(config_fn_t cb, void *data)
|
|
|
|
{
|
2017-04-17 10:10:00 +00:00
|
|
|
struct config_options opts = {0};
|
2017-06-14 18:07:37 +00:00
|
|
|
struct strbuf commondir = STRBUF_INIT;
|
|
|
|
struct strbuf gitdir = STRBUF_INIT;
|
2017-03-13 20:11:12 +00:00
|
|
|
|
2017-04-17 10:10:00 +00:00
|
|
|
opts.respect_includes = 1;
|
2017-03-13 20:11:04 +00:00
|
|
|
|
2017-06-14 18:07:38 +00:00
|
|
|
if (have_git_dir()) {
|
|
|
|
opts.commondir = get_git_common_dir();
|
2017-04-17 10:10:01 +00:00
|
|
|
opts.git_dir = get_git_dir();
|
2017-03-13 20:11:04 +00:00
|
|
|
/*
|
2017-03-13 20:11:12 +00:00
|
|
|
* When setup_git_directory() was not yet asked to discover the
|
|
|
|
* GIT_DIR, we ask discover_git_directory() to figure out whether there
|
|
|
|
* is any repository config we should use (but unlike
|
|
|
|
* setup_git_directory_gently(), no global state is changed, most
|
|
|
|
* notably, the current working directory is still the same after the
|
|
|
|
* call).
|
2017-03-13 20:11:04 +00:00
|
|
|
*/
|
2017-06-14 18:07:38 +00:00
|
|
|
} else if (!discover_git_directory(&commondir, &gitdir)) {
|
|
|
|
opts.commondir = commondir.buf;
|
2017-06-14 18:07:37 +00:00
|
|
|
opts.git_dir = gitdir.buf;
|
2017-06-14 18:07:38 +00:00
|
|
|
}
|
2017-04-17 10:10:01 +00:00
|
|
|
|
2017-06-14 18:07:39 +00:00
|
|
|
config_with_options(cb, data, NULL, &opts);
|
2017-03-13 20:11:04 +00:00
|
|
|
|
2017-06-14 18:07:37 +00:00
|
|
|
strbuf_release(&commondir);
|
|
|
|
strbuf_release(&gitdir);
|
2017-03-13 20:11:04 +00:00
|
|
|
}
|
|
|
|
|
2019-04-15 20:39:46 +00:00
|
|
|
/*
|
|
|
|
* Read config but only enumerate system and global settings.
|
|
|
|
* Omit any repo-local, worktree-local, or command-line settings.
|
|
|
|
*/
|
|
|
|
void read_very_early_config(config_fn_t cb, void *data)
|
|
|
|
{
|
|
|
|
struct config_options opts = { 0 };
|
|
|
|
|
|
|
|
opts.respect_includes = 1;
|
|
|
|
opts.ignore_repo = 1;
|
|
|
|
opts.ignore_worktree = 1;
|
|
|
|
opts.ignore_cmdline = 1;
|
2019-04-29 20:14:22 +00:00
|
|
|
opts.system_gently = 1;
|
2019-04-15 20:39:46 +00:00
|
|
|
|
|
|
|
config_with_options(cb, data, NULL, &opts);
|
|
|
|
}
|
|
|
|
|
2014-07-28 10:10:38 +00:00
|
|
|
static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)
|
|
|
|
{
|
|
|
|
struct config_set_element k;
|
|
|
|
struct config_set_element *found_entry;
|
|
|
|
char *normalized_key;
|
|
|
|
/*
|
|
|
|
* `key` may come from the user, so normalize it before using it
|
|
|
|
* for querying entries from the hashmap.
|
|
|
|
*/
|
2016-04-27 21:30:39 +00:00
|
|
|
if (git_config_parse_key(key, &normalized_key, NULL))
|
2014-07-28 10:10:38 +00:00
|
|
|
return NULL;
|
|
|
|
|
2019-10-06 23:30:27 +00:00
|
|
|
hashmap_entry_init(&k.ent, strhash(normalized_key));
|
2014-07-28 10:10:38 +00:00
|
|
|
k.key = normalized_key;
|
2019-10-06 23:30:42 +00:00
|
|
|
found_entry = hashmap_get_entry(&cs->config_hash, &k, ent, NULL);
|
2014-07-28 10:10:38 +00:00
|
|
|
free(normalized_key);
|
|
|
|
return found_entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int configset_add_value(struct config_set *cs, const char *key, const char *value)
|
|
|
|
{
|
|
|
|
struct config_set_element *e;
|
2014-08-07 11:59:14 +00:00
|
|
|
struct string_list_item *si;
|
2014-08-07 11:59:17 +00:00
|
|
|
struct configset_list_item *l_item;
|
2014-08-07 11:59:14 +00:00
|
|
|
struct key_value_info *kv_info = xmalloc(sizeof(*kv_info));
|
|
|
|
|
2014-07-28 10:10:38 +00:00
|
|
|
e = configset_find_element(cs, key);
|
|
|
|
/*
|
|
|
|
* Since the keys are being fed by git_config*() callback mechanism, they
|
|
|
|
* are already normalized. So simply add them without any further munging.
|
|
|
|
*/
|
|
|
|
if (!e) {
|
|
|
|
e = xmalloc(sizeof(*e));
|
2019-10-06 23:30:27 +00:00
|
|
|
hashmap_entry_init(&e->ent, strhash(key));
|
2014-07-28 10:10:38 +00:00
|
|
|
e->key = xstrdup(key);
|
2021-07-01 10:51:29 +00:00
|
|
|
string_list_init_dup(&e->value_list);
|
2019-10-06 23:30:29 +00:00
|
|
|
hashmap_add(&cs->config_hash, &e->ent);
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
2015-01-13 01:59:09 +00:00
|
|
|
si = string_list_append_nodup(&e->value_list, xstrdup_or_null(value));
|
2014-08-07 11:59:17 +00:00
|
|
|
|
|
|
|
ALLOC_GROW(cs->list.items, cs->list.nr + 1, cs->list.alloc);
|
|
|
|
l_item = &cs->list.items[cs->list.nr++];
|
|
|
|
l_item->e = e;
|
|
|
|
l_item->value_index = e->value_list.nr - 1;
|
|
|
|
|
2016-05-18 22:41:08 +00:00
|
|
|
if (!cf)
|
2018-05-02 09:38:39 +00:00
|
|
|
BUG("configset_add_value has no source");
|
2016-05-18 22:41:08 +00:00
|
|
|
if (cf->name) {
|
2014-08-07 11:59:14 +00:00
|
|
|
kv_info->filename = strintern(cf->name);
|
|
|
|
kv_info->linenr = cf->linenr;
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
kv_info->origin_type = cf->origin_type;
|
2014-08-07 11:59:14 +00:00
|
|
|
} else {
|
|
|
|
/* for values read from `git_config_from_parameters()` */
|
|
|
|
kv_info->filename = NULL;
|
|
|
|
kv_info->linenr = -1;
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
kv_info->origin_type = CONFIG_ORIGIN_CMDLINE;
|
2014-08-07 11:59:14 +00:00
|
|
|
}
|
config: add a notion of "scope"
A config callback passed to git_config() doesn't know very
much about the context in which it sees a variable. It can
ask whether the variable comes from a file, and get the file
name. But without analyzing the filename (which is hard to
do accurately), it cannot tell whether it is in system-level
config, user-level config, or repo-specific config.
Generally this doesn't matter; the point of not passing this
to the callback is that it should treat the config the same
no matter where it comes from. But some programs, like
upload-pack, are a special case: we should be able to run
them in an untrusted repository, which means we cannot use
any "dangerous" config from the repository config file (but
it is OK to use it from system or user config).
This patch teaches the config code to record the "scope" of
each variable, and make it available inside config
callbacks, similar to how we give access to the filename.
The scope is the starting source for a particular parsing
operation, and remains the same even if we include other
files (so a .git/config which includes another file will
remain CONFIG_SCOPE_REPO, as it would be similarly
untrusted).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-05-18 22:44:23 +00:00
|
|
|
kv_info->scope = current_parsing_scope;
|
2014-08-07 11:59:14 +00:00
|
|
|
si->util = kv_info;
|
2014-07-28 10:10:38 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-25 17:09:48 +00:00
|
|
|
static int config_set_element_cmp(const void *cmp_data UNUSED,
|
2019-10-06 23:30:37 +00:00
|
|
|
const struct hashmap_entry *eptr,
|
|
|
|
const struct hashmap_entry *entry_or_key,
|
2022-08-25 17:09:48 +00:00
|
|
|
const void *keydata UNUSED)
|
2014-07-28 10:10:38 +00:00
|
|
|
{
|
2019-10-06 23:30:37 +00:00
|
|
|
const struct config_set_element *e1, *e2;
|
|
|
|
|
|
|
|
e1 = container_of(eptr, const struct config_set_element, ent);
|
|
|
|
e2 = container_of(entry_or_key, const struct config_set_element, ent);
|
2017-07-01 00:28:32 +00:00
|
|
|
|
2014-07-28 10:10:38 +00:00
|
|
|
return strcmp(e1->key, e2->key);
|
|
|
|
}
|
|
|
|
|
|
|
|
void git_configset_init(struct config_set *cs)
|
|
|
|
{
|
2017-07-01 00:28:32 +00:00
|
|
|
hashmap_init(&cs->config_hash, config_set_element_cmp, NULL, 0);
|
2014-07-28 10:10:38 +00:00
|
|
|
cs->hash_initialized = 1;
|
2014-08-07 11:59:17 +00:00
|
|
|
cs->list.nr = 0;
|
|
|
|
cs->list.alloc = 0;
|
|
|
|
cs->list.items = NULL;
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void git_configset_clear(struct config_set *cs)
|
|
|
|
{
|
|
|
|
struct config_set_element *entry;
|
|
|
|
struct hashmap_iter iter;
|
|
|
|
if (!cs->hash_initialized)
|
|
|
|
return;
|
|
|
|
|
2019-10-06 23:30:38 +00:00
|
|
|
hashmap_for_each_entry(&cs->config_hash, &iter, entry,
|
|
|
|
ent /* member name */) {
|
2014-07-28 10:10:38 +00:00
|
|
|
free(entry->key);
|
2014-08-07 11:59:14 +00:00
|
|
|
string_list_clear(&entry->value_list, 1);
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
2020-11-02 18:55:05 +00:00
|
|
|
hashmap_clear_and_free(&cs->config_hash, struct config_set_element, ent);
|
2014-07-28 10:10:38 +00:00
|
|
|
cs->hash_initialized = 0;
|
2014-08-07 11:59:17 +00:00
|
|
|
free(cs->list.items);
|
|
|
|
cs->list.nr = 0;
|
|
|
|
cs->list.alloc = 0;
|
|
|
|
cs->list.items = NULL;
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int config_set_callback(const char *key, const char *value, void *cb)
|
|
|
|
{
|
|
|
|
struct config_set *cs = cb;
|
|
|
|
configset_add_value(cs, key, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_add_file(struct config_set *cs, const char *filename)
|
|
|
|
{
|
|
|
|
return git_config_from_file(config_set_callback, filename, cs);
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_get_value(struct config_set *cs, const char *key, const char **value)
|
|
|
|
{
|
|
|
|
const struct string_list *values = NULL;
|
|
|
|
/*
|
|
|
|
* Follows "last one wins" semantic, i.e., if there are multiple matches for the
|
|
|
|
* queried key in the files of the configset, the value returned will be the last
|
|
|
|
* value in the value list for that key.
|
|
|
|
*/
|
|
|
|
values = git_configset_get_value_multi(cs, key);
|
|
|
|
|
|
|
|
if (!values)
|
|
|
|
return 1;
|
|
|
|
assert(values->nr > 0);
|
|
|
|
*value = values->items[values->nr - 1].string;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key)
|
|
|
|
{
|
|
|
|
struct config_set_element *e = configset_find_element(cs, key);
|
|
|
|
return e ? &e->value_list : NULL;
|
|
|
|
}
|
|
|
|
|
config: drop git_config_get_string_const()
As evidenced by the leak fixes in the previous commit, the "const" in
git_config_get_string_const() clearly misleads people into thinking that
it does not allocate a copy of the string. We can fix this by renaming
it, but it's easier still to just drop it. Of the four remaining
callers:
- The one in git_config_parse_expiry() still needs to allocate, since
that's what its callers expect. We can just use the non-const
version and cast our pointer. Slightly ugly, but the damage is
contained in one spot.
- The two in apply are writing to global "const char *" variables, and
need to continue allocating. We often mark these as const because we
assign default string literals to them. But in this case we don't do
that, so we can just declare them as real "char *" pointers and use
the non-const version.
- The call in checkout doesn't actually need a copy; it can just use
the non-allocating "tmp" version of the function.
The function is also mentioned in the MyFirstContribution document. We
can swap that call out for the non-allocating "tmp" variant, which fits
well in the example given.
We'll drop the "configset" and "repo" variants, as well (which are
unused).
Note that this frees up the "const" name, so we could rename the "tmp"
variant back to that. But let's give some time for topics in flight to
adapt to the new code before doing so (if we do it too soon, the
function semantics will change but the compiler won't alert us).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-08-17 21:33:11 +00:00
|
|
|
int git_configset_get_string(struct config_set *cs, const char *key, char **dest)
|
2014-07-28 10:10:38 +00:00
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
if (!git_configset_get_value(cs, key, &value))
|
config: drop git_config_get_string_const()
As evidenced by the leak fixes in the previous commit, the "const" in
git_config_get_string_const() clearly misleads people into thinking that
it does not allocate a copy of the string. We can fix this by renaming
it, but it's easier still to just drop it. Of the four remaining
callers:
- The one in git_config_parse_expiry() still needs to allocate, since
that's what its callers expect. We can just use the non-const
version and cast our pointer. Slightly ugly, but the damage is
contained in one spot.
- The two in apply are writing to global "const char *" variables, and
need to continue allocating. We often mark these as const because we
assign default string literals to them. But in this case we don't do
that, so we can just declare them as real "char *" pointers and use
the non-const version.
- The call in checkout doesn't actually need a copy; it can just use
the non-allocating "tmp" version of the function.
The function is also mentioned in the MyFirstContribution document. We
can swap that call out for the non-allocating "tmp" variant, which fits
well in the example given.
We'll drop the "configset" and "repo" variants, as well (which are
unused).
Note that this frees up the "const" name, so we could rename the "tmp"
variant back to that. But let's give some time for topics in flight to
adapt to the new code before doing so (if we do it too soon, the
function semantics will change but the compiler won't alert us).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-08-17 21:33:11 +00:00
|
|
|
return git_config_string((const char **)dest, key, value);
|
2014-07-28 10:10:38 +00:00
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-02-07 21:33:03 +00:00
|
|
|
static int git_configset_get_string_tmp(struct config_set *cs, const char *key,
|
|
|
|
const char **dest)
|
2014-07-28 10:10:38 +00:00
|
|
|
{
|
2020-08-14 16:17:36 +00:00
|
|
|
const char *value;
|
|
|
|
if (!git_configset_get_value(cs, key, &value)) {
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(key);
|
|
|
|
*dest = value;
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return 1;
|
|
|
|
}
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_get_int(struct config_set *cs, const char *key, int *dest)
|
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
if (!git_configset_get_value(cs, key, &value)) {
|
|
|
|
*dest = git_config_int(key, value);
|
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest)
|
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
if (!git_configset_get_value(cs, key, &value)) {
|
|
|
|
*dest = git_config_ulong(key, value);
|
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_get_bool(struct config_set *cs, const char *key, int *dest)
|
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
if (!git_configset_get_value(cs, key, &value)) {
|
|
|
|
*dest = git_config_bool(key, value);
|
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_get_bool_or_int(struct config_set *cs, const char *key,
|
|
|
|
int *is_bool, int *dest)
|
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
if (!git_configset_get_value(cs, key, &value)) {
|
|
|
|
*dest = git_config_bool_or_int(key, value, is_bool);
|
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest)
|
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
if (!git_configset_get_value(cs, key, &value)) {
|
2017-08-07 18:20:49 +00:00
|
|
|
*dest = git_parse_maybe_bool(value);
|
2014-07-28 10:10:38 +00:00
|
|
|
if (*dest == -1)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest)
|
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
if (!git_configset_get_value(cs, key, &value))
|
|
|
|
return git_config_pathname(dest, key, value);
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-06-22 18:43:42 +00:00
|
|
|
/* Functions use to read configuration from a repository */
|
|
|
|
static void repo_read_config(struct repository *repo)
|
2014-07-28 10:10:38 +00:00
|
|
|
{
|
2019-04-15 20:39:42 +00:00
|
|
|
struct config_options opts = { 0 };
|
2017-06-22 18:43:42 +00:00
|
|
|
|
|
|
|
opts.respect_includes = 1;
|
|
|
|
opts.commondir = repo->commondir;
|
|
|
|
opts.git_dir = repo->gitdir;
|
|
|
|
|
|
|
|
if (!repo->config)
|
2021-03-13 16:17:22 +00:00
|
|
|
CALLOC_ARRAY(repo->config, 1);
|
2017-06-22 18:43:42 +00:00
|
|
|
else
|
|
|
|
git_configset_clear(repo->config);
|
|
|
|
|
|
|
|
git_configset_init(repo->config);
|
|
|
|
|
|
|
|
if (config_with_options(config_set_callback, repo->config, NULL, &opts) < 0)
|
|
|
|
/*
|
|
|
|
* config_with_options() normally returns only
|
|
|
|
* zero, as most errors are fatal, and
|
|
|
|
* non-fatal potential errors are guarded by "if"
|
|
|
|
* statements that are entered only when no error is
|
|
|
|
* possible.
|
|
|
|
*
|
|
|
|
* If we ever encounter a non-fatal error, it means
|
|
|
|
* something went really wrong and we should stop
|
|
|
|
* immediately.
|
|
|
|
*/
|
|
|
|
die(_("unknown error occurred while reading the configuration files"));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void git_config_check_init(struct repository *repo)
|
|
|
|
{
|
|
|
|
if (repo->config && repo->config->hash_initialized)
|
2014-07-28 10:10:38 +00:00
|
|
|
return;
|
2017-06-22 18:43:42 +00:00
|
|
|
repo_read_config(repo);
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
|
|
|
|
2017-06-22 18:43:42 +00:00
|
|
|
static void repo_config_clear(struct repository *repo)
|
2014-07-28 10:10:38 +00:00
|
|
|
{
|
2017-06-22 18:43:42 +00:00
|
|
|
if (!repo->config || !repo->config->hash_initialized)
|
2014-07-28 10:10:38 +00:00
|
|
|
return;
|
2017-06-22 18:43:42 +00:00
|
|
|
git_configset_clear(repo->config);
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
|
|
|
|
2017-06-22 18:43:42 +00:00
|
|
|
void repo_config(struct repository *repo, config_fn_t fn, void *data)
|
2014-07-28 10:10:38 +00:00
|
|
|
{
|
2017-06-22 18:43:42 +00:00
|
|
|
git_config_check_init(repo);
|
|
|
|
configset_iter(repo->config, fn, data);
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
|
|
|
|
2017-06-22 18:43:42 +00:00
|
|
|
int repo_config_get_value(struct repository *repo,
|
|
|
|
const char *key, const char **value)
|
2014-07-28 10:10:38 +00:00
|
|
|
{
|
2017-06-22 18:43:42 +00:00
|
|
|
git_config_check_init(repo);
|
|
|
|
return git_configset_get_value(repo->config, key, value);
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
|
|
|
|
2017-06-22 18:43:42 +00:00
|
|
|
const struct string_list *repo_config_get_value_multi(struct repository *repo,
|
|
|
|
const char *key)
|
|
|
|
{
|
|
|
|
git_config_check_init(repo);
|
|
|
|
return git_configset_get_value_multi(repo->config, key);
|
|
|
|
}
|
|
|
|
|
config: drop git_config_get_string_const()
As evidenced by the leak fixes in the previous commit, the "const" in
git_config_get_string_const() clearly misleads people into thinking that
it does not allocate a copy of the string. We can fix this by renaming
it, but it's easier still to just drop it. Of the four remaining
callers:
- The one in git_config_parse_expiry() still needs to allocate, since
that's what its callers expect. We can just use the non-const
version and cast our pointer. Slightly ugly, but the damage is
contained in one spot.
- The two in apply are writing to global "const char *" variables, and
need to continue allocating. We often mark these as const because we
assign default string literals to them. But in this case we don't do
that, so we can just declare them as real "char *" pointers and use
the non-const version.
- The call in checkout doesn't actually need a copy; it can just use
the non-allocating "tmp" version of the function.
The function is also mentioned in the MyFirstContribution document. We
can swap that call out for the non-allocating "tmp" variant, which fits
well in the example given.
We'll drop the "configset" and "repo" variants, as well (which are
unused).
Note that this frees up the "const" name, so we could rename the "tmp"
variant back to that. But let's give some time for topics in flight to
adapt to the new code before doing so (if we do it too soon, the
function semantics will change but the compiler won't alert us).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-08-17 21:33:11 +00:00
|
|
|
int repo_config_get_string(struct repository *repo,
|
|
|
|
const char *key, char **dest)
|
2017-06-22 18:43:42 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
git_config_check_init(repo);
|
config: drop git_config_get_string_const()
As evidenced by the leak fixes in the previous commit, the "const" in
git_config_get_string_const() clearly misleads people into thinking that
it does not allocate a copy of the string. We can fix this by renaming
it, but it's easier still to just drop it. Of the four remaining
callers:
- The one in git_config_parse_expiry() still needs to allocate, since
that's what its callers expect. We can just use the non-const
version and cast our pointer. Slightly ugly, but the damage is
contained in one spot.
- The two in apply are writing to global "const char *" variables, and
need to continue allocating. We often mark these as const because we
assign default string literals to them. But in this case we don't do
that, so we can just declare them as real "char *" pointers and use
the non-const version.
- The call in checkout doesn't actually need a copy; it can just use
the non-allocating "tmp" version of the function.
The function is also mentioned in the MyFirstContribution document. We
can swap that call out for the non-allocating "tmp" variant, which fits
well in the example given.
We'll drop the "configset" and "repo" variants, as well (which are
unused).
Note that this frees up the "const" name, so we could rename the "tmp"
variant back to that. But let's give some time for topics in flight to
adapt to the new code before doing so (if we do it too soon, the
function semantics will change but the compiler won't alert us).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-08-17 21:33:11 +00:00
|
|
|
ret = git_configset_get_string(repo->config, key, dest);
|
2017-06-22 18:43:42 +00:00
|
|
|
if (ret < 0)
|
|
|
|
git_die_config(key, NULL);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-08-14 16:17:36 +00:00
|
|
|
int repo_config_get_string_tmp(struct repository *repo,
|
|
|
|
const char *key, const char **dest)
|
2017-06-22 18:43:42 +00:00
|
|
|
{
|
2020-08-14 16:17:36 +00:00
|
|
|
int ret;
|
2017-06-22 18:43:42 +00:00
|
|
|
git_config_check_init(repo);
|
2020-08-14 16:17:36 +00:00
|
|
|
ret = git_configset_get_string_tmp(repo->config, key, dest);
|
|
|
|
if (ret < 0)
|
|
|
|
git_die_config(key, NULL);
|
|
|
|
return ret;
|
2017-06-22 18:43:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int repo_config_get_int(struct repository *repo,
|
|
|
|
const char *key, int *dest)
|
|
|
|
{
|
|
|
|
git_config_check_init(repo);
|
|
|
|
return git_configset_get_int(repo->config, key, dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
int repo_config_get_ulong(struct repository *repo,
|
|
|
|
const char *key, unsigned long *dest)
|
|
|
|
{
|
|
|
|
git_config_check_init(repo);
|
|
|
|
return git_configset_get_ulong(repo->config, key, dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
int repo_config_get_bool(struct repository *repo,
|
|
|
|
const char *key, int *dest)
|
|
|
|
{
|
|
|
|
git_config_check_init(repo);
|
|
|
|
return git_configset_get_bool(repo->config, key, dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
int repo_config_get_bool_or_int(struct repository *repo,
|
|
|
|
const char *key, int *is_bool, int *dest)
|
|
|
|
{
|
|
|
|
git_config_check_init(repo);
|
|
|
|
return git_configset_get_bool_or_int(repo->config, key, is_bool, dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
int repo_config_get_maybe_bool(struct repository *repo,
|
|
|
|
const char *key, int *dest)
|
|
|
|
{
|
|
|
|
git_config_check_init(repo);
|
|
|
|
return git_configset_get_maybe_bool(repo->config, key, dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
int repo_config_get_pathname(struct repository *repo,
|
|
|
|
const char *key, const char **dest)
|
2014-07-28 10:10:38 +00:00
|
|
|
{
|
2014-08-07 11:59:16 +00:00
|
|
|
int ret;
|
2017-06-22 18:43:42 +00:00
|
|
|
git_config_check_init(repo);
|
|
|
|
ret = git_configset_get_pathname(repo->config, key, dest);
|
2014-08-07 11:59:16 +00:00
|
|
|
if (ret < 0)
|
|
|
|
git_die_config(key, NULL);
|
|
|
|
return ret;
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
|
|
|
|
config: learn `git_protected_config()`
`uploadpack.packObjectsHook` is the only 'protected configuration only'
variable today, but we've noted that `safe.directory` and the upcoming
`safe.bareRepository` should also be 'protected configuration only'. So,
for consistency, we'd like to have a single implementation for protected
configuration.
The primary constraints are:
1. Reading from protected configuration should be fast. Nearly all "git"
commands inside a bare repository will read both `safe.directory` and
`safe.bareRepository`, so we cannot afford to be slow.
2. Protected configuration must be readable when the gitdir is not
known. `safe.directory` and `safe.bareRepository` both affect
repository discovery and the gitdir is not known at that point [1].
The chosen implementation in this commit is to read protected
configuration and cache the values in a global configset. This is
similar to the caching behavior we get with the_repository->config.
Introduce git_protected_config(), which reads protected configuration
and caches them in the global configset protected_config. Then, refactor
`uploadpack.packObjectsHook` to use git_protected_config().
The protected configuration functions are named similarly to their
non-protected counterparts, e.g. git_protected_config_check_init() vs
git_config_check_init().
In light of constraint 1, this implementation can still be improved.
git_protected_config() iterates through every variable in
protected_config, which is wasteful, but it makes the conversion simple
because it matches existing patterns. We will likely implement constant
time lookup functions for protected configuration in a future series
(such functions already exist for non-protected configuration, i.e.
repo_config_get_*()).
An alternative that avoids introducing another configset is to continue
to read all config using git_config(), but only accept values that have
the correct config scope [2]. This technically fulfills constraint 2,
because git_config() simply ignores the local and worktree config when
the gitdir is not known. However, this would read incomplete config into
the_repository->config, which would need to be reset when the gitdir is
known and git_config() needs to read the local and worktree config.
Resetting the_repository->config might be reasonable while we only have
these 'protected configuration only' variables, but it's not clear
whether this extends well to future variables.
[1] In this case, we do have a candidate gitdir though, so with a little
refactoring, it might be possible to provide a gitdir.
[2] This is how `uploadpack.packObjectsHook` was implemented prior to
this commit.
Signed-off-by: Glen Choo <chooglen@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-14 21:27:59 +00:00
|
|
|
/* Read values into protected_config. */
|
|
|
|
static void read_protected_config(void)
|
|
|
|
{
|
2022-10-13 17:43:47 +00:00
|
|
|
struct config_options opts = {
|
|
|
|
.respect_includes = 1,
|
|
|
|
.ignore_repo = 1,
|
|
|
|
.ignore_worktree = 1,
|
|
|
|
.system_gently = 1,
|
|
|
|
};
|
config: learn `git_protected_config()`
`uploadpack.packObjectsHook` is the only 'protected configuration only'
variable today, but we've noted that `safe.directory` and the upcoming
`safe.bareRepository` should also be 'protected configuration only'. So,
for consistency, we'd like to have a single implementation for protected
configuration.
The primary constraints are:
1. Reading from protected configuration should be fast. Nearly all "git"
commands inside a bare repository will read both `safe.directory` and
`safe.bareRepository`, so we cannot afford to be slow.
2. Protected configuration must be readable when the gitdir is not
known. `safe.directory` and `safe.bareRepository` both affect
repository discovery and the gitdir is not known at that point [1].
The chosen implementation in this commit is to read protected
configuration and cache the values in a global configset. This is
similar to the caching behavior we get with the_repository->config.
Introduce git_protected_config(), which reads protected configuration
and caches them in the global configset protected_config. Then, refactor
`uploadpack.packObjectsHook` to use git_protected_config().
The protected configuration functions are named similarly to their
non-protected counterparts, e.g. git_protected_config_check_init() vs
git_config_check_init().
In light of constraint 1, this implementation can still be improved.
git_protected_config() iterates through every variable in
protected_config, which is wasteful, but it makes the conversion simple
because it matches existing patterns. We will likely implement constant
time lookup functions for protected configuration in a future series
(such functions already exist for non-protected configuration, i.e.
repo_config_get_*()).
An alternative that avoids introducing another configset is to continue
to read all config using git_config(), but only accept values that have
the correct config scope [2]. This technically fulfills constraint 2,
because git_config() simply ignores the local and worktree config when
the gitdir is not known. However, this would read incomplete config into
the_repository->config, which would need to be reset when the gitdir is
known and git_config() needs to read the local and worktree config.
Resetting the_repository->config might be reasonable while we only have
these 'protected configuration only' variables, but it's not clear
whether this extends well to future variables.
[1] In this case, we do have a candidate gitdir though, so with a little
refactoring, it might be possible to provide a gitdir.
[2] This is how `uploadpack.packObjectsHook` was implemented prior to
this commit.
Signed-off-by: Glen Choo <chooglen@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-14 21:27:59 +00:00
|
|
|
git_configset_init(&protected_config);
|
2022-10-13 17:43:47 +00:00
|
|
|
config_with_options(config_set_callback, &protected_config,
|
|
|
|
NULL, &opts);
|
config: learn `git_protected_config()`
`uploadpack.packObjectsHook` is the only 'protected configuration only'
variable today, but we've noted that `safe.directory` and the upcoming
`safe.bareRepository` should also be 'protected configuration only'. So,
for consistency, we'd like to have a single implementation for protected
configuration.
The primary constraints are:
1. Reading from protected configuration should be fast. Nearly all "git"
commands inside a bare repository will read both `safe.directory` and
`safe.bareRepository`, so we cannot afford to be slow.
2. Protected configuration must be readable when the gitdir is not
known. `safe.directory` and `safe.bareRepository` both affect
repository discovery and the gitdir is not known at that point [1].
The chosen implementation in this commit is to read protected
configuration and cache the values in a global configset. This is
similar to the caching behavior we get with the_repository->config.
Introduce git_protected_config(), which reads protected configuration
and caches them in the global configset protected_config. Then, refactor
`uploadpack.packObjectsHook` to use git_protected_config().
The protected configuration functions are named similarly to their
non-protected counterparts, e.g. git_protected_config_check_init() vs
git_config_check_init().
In light of constraint 1, this implementation can still be improved.
git_protected_config() iterates through every variable in
protected_config, which is wasteful, but it makes the conversion simple
because it matches existing patterns. We will likely implement constant
time lookup functions for protected configuration in a future series
(such functions already exist for non-protected configuration, i.e.
repo_config_get_*()).
An alternative that avoids introducing another configset is to continue
to read all config using git_config(), but only accept values that have
the correct config scope [2]. This technically fulfills constraint 2,
because git_config() simply ignores the local and worktree config when
the gitdir is not known. However, this would read incomplete config into
the_repository->config, which would need to be reset when the gitdir is
known and git_config() needs to read the local and worktree config.
Resetting the_repository->config might be reasonable while we only have
these 'protected configuration only' variables, but it's not clear
whether this extends well to future variables.
[1] In this case, we do have a candidate gitdir though, so with a little
refactoring, it might be possible to provide a gitdir.
[2] This is how `uploadpack.packObjectsHook` was implemented prior to
this commit.
Signed-off-by: Glen Choo <chooglen@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-14 21:27:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void git_protected_config(config_fn_t fn, void *data)
|
|
|
|
{
|
|
|
|
if (!protected_config.hash_initialized)
|
|
|
|
read_protected_config();
|
|
|
|
configset_iter(&protected_config, fn, data);
|
|
|
|
}
|
|
|
|
|
2017-06-22 18:43:42 +00:00
|
|
|
/* Functions used historically to read configuration from 'the_repository' */
|
|
|
|
void git_config(config_fn_t fn, void *data)
|
|
|
|
{
|
|
|
|
repo_config(the_repository, fn, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
void git_config_clear(void)
|
|
|
|
{
|
|
|
|
repo_config_clear(the_repository);
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_get_value(const char *key, const char **value)
|
|
|
|
{
|
|
|
|
return repo_config_get_value(the_repository, key, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct string_list *git_config_get_value_multi(const char *key)
|
|
|
|
{
|
|
|
|
return repo_config_get_value_multi(the_repository, key);
|
|
|
|
}
|
|
|
|
|
2014-07-28 10:10:38 +00:00
|
|
|
int git_config_get_string(const char *key, char **dest)
|
2017-06-22 18:43:42 +00:00
|
|
|
{
|
|
|
|
return repo_config_get_string(the_repository, key, dest);
|
|
|
|
}
|
|
|
|
|
2020-08-14 16:17:36 +00:00
|
|
|
int git_config_get_string_tmp(const char *key, const char **dest)
|
2014-07-28 10:10:38 +00:00
|
|
|
{
|
2020-08-14 16:17:36 +00:00
|
|
|
return repo_config_get_string_tmp(the_repository, key, dest);
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_get_int(const char *key, int *dest)
|
|
|
|
{
|
2017-06-22 18:43:42 +00:00
|
|
|
return repo_config_get_int(the_repository, key, dest);
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_get_ulong(const char *key, unsigned long *dest)
|
|
|
|
{
|
2017-06-22 18:43:42 +00:00
|
|
|
return repo_config_get_ulong(the_repository, key, dest);
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_get_bool(const char *key, int *dest)
|
|
|
|
{
|
2017-06-22 18:43:42 +00:00
|
|
|
return repo_config_get_bool(the_repository, key, dest);
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)
|
|
|
|
{
|
2017-06-22 18:43:42 +00:00
|
|
|
return repo_config_get_bool_or_int(the_repository, key, is_bool, dest);
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_get_maybe_bool(const char *key, int *dest)
|
|
|
|
{
|
2017-06-22 18:43:42 +00:00
|
|
|
return repo_config_get_maybe_bool(the_repository, key, dest);
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_get_pathname(const char *key, const char **dest)
|
|
|
|
{
|
2017-06-22 18:43:42 +00:00
|
|
|
return repo_config_get_pathname(the_repository, key, dest);
|
2014-08-07 11:59:16 +00:00
|
|
|
}
|
|
|
|
|
2017-02-27 18:00:13 +00:00
|
|
|
int git_config_get_expiry(const char *key, const char **output)
|
|
|
|
{
|
config: drop git_config_get_string_const()
As evidenced by the leak fixes in the previous commit, the "const" in
git_config_get_string_const() clearly misleads people into thinking that
it does not allocate a copy of the string. We can fix this by renaming
it, but it's easier still to just drop it. Of the four remaining
callers:
- The one in git_config_parse_expiry() still needs to allocate, since
that's what its callers expect. We can just use the non-const
version and cast our pointer. Slightly ugly, but the damage is
contained in one spot.
- The two in apply are writing to global "const char *" variables, and
need to continue allocating. We often mark these as const because we
assign default string literals to them. But in this case we don't do
that, so we can just declare them as real "char *" pointers and use
the non-const version.
- The call in checkout doesn't actually need a copy; it can just use
the non-allocating "tmp" version of the function.
The function is also mentioned in the MyFirstContribution document. We
can swap that call out for the non-allocating "tmp" variant, which fits
well in the example given.
We'll drop the "configset" and "repo" variants, as well (which are
unused).
Note that this frees up the "const" name, so we could rename the "tmp"
variant back to that. But let's give some time for topics in flight to
adapt to the new code before doing so (if we do it too soon, the
function semantics will change but the compiler won't alert us).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-08-17 21:33:11 +00:00
|
|
|
int ret = git_config_get_string(key, (char **)output);
|
2017-02-27 18:00:13 +00:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
if (strcmp(*output, "now")) {
|
2017-04-26 19:29:31 +00:00
|
|
|
timestamp_t now = approxidate("now");
|
2017-02-27 18:00:13 +00:00
|
|
|
if (approxidate(*output) >= now)
|
|
|
|
git_die_config(key, _("Invalid %s: '%s'"), key, *output);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-08-19 18:43:39 +00:00
|
|
|
int git_config_get_expiry_in_days(const char *key, timestamp_t *expiry, timestamp_t now)
|
|
|
|
{
|
2020-08-17 21:33:13 +00:00
|
|
|
const char *expiry_string;
|
2017-08-19 18:43:39 +00:00
|
|
|
intmax_t days;
|
|
|
|
timestamp_t when;
|
|
|
|
|
2020-08-17 21:33:13 +00:00
|
|
|
if (git_config_get_string_tmp(key, &expiry_string))
|
2017-08-19 18:43:39 +00:00
|
|
|
return 1; /* no such thing */
|
|
|
|
|
|
|
|
if (git_parse_signed(expiry_string, &days, maximum_signed_value_of_type(int))) {
|
|
|
|
const int scale = 86400;
|
|
|
|
*expiry = now - days * scale;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!parse_expiry_date(expiry_string, &when)) {
|
|
|
|
*expiry = when;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1; /* thing exists but cannot be parsed */
|
|
|
|
}
|
|
|
|
|
2017-02-27 18:00:00 +00:00
|
|
|
int git_config_get_split_index(void)
|
|
|
|
{
|
|
|
|
int val;
|
|
|
|
|
|
|
|
if (!git_config_get_maybe_bool("core.splitindex", &val))
|
|
|
|
return val;
|
|
|
|
|
|
|
|
return -1; /* default value */
|
|
|
|
}
|
|
|
|
|
2017-02-27 18:00:07 +00:00
|
|
|
int git_config_get_max_percent_split_change(void)
|
|
|
|
{
|
|
|
|
int val = -1;
|
|
|
|
|
|
|
|
if (!git_config_get_int("splitindex.maxpercentchange", &val)) {
|
|
|
|
if (0 <= val && val <= 100)
|
|
|
|
return val;
|
|
|
|
|
|
|
|
return error(_("splitIndex.maxPercentChange value '%d' "
|
|
|
|
"should be between 0 and 100"), val);
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1; /* default value */
|
|
|
|
}
|
|
|
|
|
index: make index.threads=true enable ieot and eoie
If a user explicitly sets
[index]
threads = true
to read the index using multiple threads, ensure that index writes
include the offset table by default to make that possible. This
ensures that the user's intent of turning on threading is respected.
In other words, permit the following configurations:
- index.threads and index.recordOffsetTable unspecified: do not write
the offset table yet (to avoid alarming the user with "ignoring IEOT
extension" messages when an older version of Git accesses the
repository) but do make use of multiple threads to read the index if
the supporting offset table is present.
This can also be requested explicitly by setting index.threads=true,
0, or >1 and index.recordOffsetTable=false.
- index.threads=false or 1: do not write the offset table, and do not
make use of the offset table.
One can set index.recordOffsetTable=false as well, to be more
explicit.
- index.threads=true, 0, or >1 and index.recordOffsetTable unspecified:
write the offset table and make use of threads at read time.
This can also be requested by setting index.threads=true, 0, >1, or
unspecified and index.recordOffsetTable=true.
Fortunately the complication is temporary: once most Git installations
have upgraded to a version with support for the IEOT and EOIE
extensions, we can flip the defaults for index.recordEndOfIndexEntries
and index.recordOffsetTable to true and eliminate the settings.
Helped-by: Ben Peart <benpeart@microsoft.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-20 06:14:26 +00:00
|
|
|
int git_config_get_index_threads(int *dest)
|
2018-10-10 15:59:35 +00:00
|
|
|
{
|
index: make index.threads=true enable ieot and eoie
If a user explicitly sets
[index]
threads = true
to read the index using multiple threads, ensure that index writes
include the offset table by default to make that possible. This
ensures that the user's intent of turning on threading is respected.
In other words, permit the following configurations:
- index.threads and index.recordOffsetTable unspecified: do not write
the offset table yet (to avoid alarming the user with "ignoring IEOT
extension" messages when an older version of Git accesses the
repository) but do make use of multiple threads to read the index if
the supporting offset table is present.
This can also be requested explicitly by setting index.threads=true,
0, or >1 and index.recordOffsetTable=false.
- index.threads=false or 1: do not write the offset table, and do not
make use of the offset table.
One can set index.recordOffsetTable=false as well, to be more
explicit.
- index.threads=true, 0, or >1 and index.recordOffsetTable unspecified:
write the offset table and make use of threads at read time.
This can also be requested by setting index.threads=true, 0, >1, or
unspecified and index.recordOffsetTable=true.
Fortunately the complication is temporary: once most Git installations
have upgraded to a version with support for the IEOT and EOIE
extensions, we can flip the defaults for index.recordEndOfIndexEntries
and index.recordOffsetTable to true and eliminate the settings.
Helped-by: Ben Peart <benpeart@microsoft.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-20 06:14:26 +00:00
|
|
|
int is_bool, val;
|
2018-10-10 15:59:35 +00:00
|
|
|
|
|
|
|
val = git_env_ulong("GIT_TEST_INDEX_THREADS", 0);
|
index: make index.threads=true enable ieot and eoie
If a user explicitly sets
[index]
threads = true
to read the index using multiple threads, ensure that index writes
include the offset table by default to make that possible. This
ensures that the user's intent of turning on threading is respected.
In other words, permit the following configurations:
- index.threads and index.recordOffsetTable unspecified: do not write
the offset table yet (to avoid alarming the user with "ignoring IEOT
extension" messages when an older version of Git accesses the
repository) but do make use of multiple threads to read the index if
the supporting offset table is present.
This can also be requested explicitly by setting index.threads=true,
0, or >1 and index.recordOffsetTable=false.
- index.threads=false or 1: do not write the offset table, and do not
make use of the offset table.
One can set index.recordOffsetTable=false as well, to be more
explicit.
- index.threads=true, 0, or >1 and index.recordOffsetTable unspecified:
write the offset table and make use of threads at read time.
This can also be requested by setting index.threads=true, 0, >1, or
unspecified and index.recordOffsetTable=true.
Fortunately the complication is temporary: once most Git installations
have upgraded to a version with support for the IEOT and EOIE
extensions, we can flip the defaults for index.recordEndOfIndexEntries
and index.recordOffsetTable to true and eliminate the settings.
Helped-by: Ben Peart <benpeart@microsoft.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-20 06:14:26 +00:00
|
|
|
if (val) {
|
|
|
|
*dest = val;
|
|
|
|
return 0;
|
|
|
|
}
|
2018-10-10 15:59:35 +00:00
|
|
|
|
|
|
|
if (!git_config_get_bool_or_int("index.threads", &is_bool, &val)) {
|
|
|
|
if (is_bool)
|
index: make index.threads=true enable ieot and eoie
If a user explicitly sets
[index]
threads = true
to read the index using multiple threads, ensure that index writes
include the offset table by default to make that possible. This
ensures that the user's intent of turning on threading is respected.
In other words, permit the following configurations:
- index.threads and index.recordOffsetTable unspecified: do not write
the offset table yet (to avoid alarming the user with "ignoring IEOT
extension" messages when an older version of Git accesses the
repository) but do make use of multiple threads to read the index if
the supporting offset table is present.
This can also be requested explicitly by setting index.threads=true,
0, or >1 and index.recordOffsetTable=false.
- index.threads=false or 1: do not write the offset table, and do not
make use of the offset table.
One can set index.recordOffsetTable=false as well, to be more
explicit.
- index.threads=true, 0, or >1 and index.recordOffsetTable unspecified:
write the offset table and make use of threads at read time.
This can also be requested by setting index.threads=true, 0, >1, or
unspecified and index.recordOffsetTable=true.
Fortunately the complication is temporary: once most Git installations
have upgraded to a version with support for the IEOT and EOIE
extensions, we can flip the defaults for index.recordEndOfIndexEntries
and index.recordOffsetTable to true and eliminate the settings.
Helped-by: Ben Peart <benpeart@microsoft.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-20 06:14:26 +00:00
|
|
|
*dest = val ? 0 : 1;
|
2018-10-10 15:59:35 +00:00
|
|
|
else
|
index: make index.threads=true enable ieot and eoie
If a user explicitly sets
[index]
threads = true
to read the index using multiple threads, ensure that index writes
include the offset table by default to make that possible. This
ensures that the user's intent of turning on threading is respected.
In other words, permit the following configurations:
- index.threads and index.recordOffsetTable unspecified: do not write
the offset table yet (to avoid alarming the user with "ignoring IEOT
extension" messages when an older version of Git accesses the
repository) but do make use of multiple threads to read the index if
the supporting offset table is present.
This can also be requested explicitly by setting index.threads=true,
0, or >1 and index.recordOffsetTable=false.
- index.threads=false or 1: do not write the offset table, and do not
make use of the offset table.
One can set index.recordOffsetTable=false as well, to be more
explicit.
- index.threads=true, 0, or >1 and index.recordOffsetTable unspecified:
write the offset table and make use of threads at read time.
This can also be requested by setting index.threads=true, 0, >1, or
unspecified and index.recordOffsetTable=true.
Fortunately the complication is temporary: once most Git installations
have upgraded to a version with support for the IEOT and EOIE
extensions, we can flip the defaults for index.recordEndOfIndexEntries
and index.recordOffsetTable to true and eliminate the settings.
Helped-by: Ben Peart <benpeart@microsoft.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-20 06:14:26 +00:00
|
|
|
*dest = val;
|
|
|
|
return 0;
|
2018-10-10 15:59:35 +00:00
|
|
|
}
|
|
|
|
|
index: make index.threads=true enable ieot and eoie
If a user explicitly sets
[index]
threads = true
to read the index using multiple threads, ensure that index writes
include the offset table by default to make that possible. This
ensures that the user's intent of turning on threading is respected.
In other words, permit the following configurations:
- index.threads and index.recordOffsetTable unspecified: do not write
the offset table yet (to avoid alarming the user with "ignoring IEOT
extension" messages when an older version of Git accesses the
repository) but do make use of multiple threads to read the index if
the supporting offset table is present.
This can also be requested explicitly by setting index.threads=true,
0, or >1 and index.recordOffsetTable=false.
- index.threads=false or 1: do not write the offset table, and do not
make use of the offset table.
One can set index.recordOffsetTable=false as well, to be more
explicit.
- index.threads=true, 0, or >1 and index.recordOffsetTable unspecified:
write the offset table and make use of threads at read time.
This can also be requested by setting index.threads=true, 0, >1, or
unspecified and index.recordOffsetTable=true.
Fortunately the complication is temporary: once most Git installations
have upgraded to a version with support for the IEOT and EOIE
extensions, we can flip the defaults for index.recordEndOfIndexEntries
and index.recordOffsetTable to true and eliminate the settings.
Helped-by: Ben Peart <benpeart@microsoft.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-20 06:14:26 +00:00
|
|
|
return 1;
|
2018-10-10 15:59:35 +00:00
|
|
|
}
|
|
|
|
|
2014-08-07 11:59:16 +00:00
|
|
|
NORETURN
|
|
|
|
void git_die_config_linenr(const char *key, const char *filename, int linenr)
|
|
|
|
{
|
|
|
|
if (!filename)
|
|
|
|
die(_("unable to parse '%s' from command-line config"), key);
|
|
|
|
else
|
|
|
|
die(_("bad config variable '%s' in file '%s' at line %d"),
|
|
|
|
key, filename, linenr);
|
|
|
|
}
|
|
|
|
|
|
|
|
NORETURN __attribute__((format(printf, 2, 3)))
|
|
|
|
void git_die_config(const char *key, const char *err, ...)
|
|
|
|
{
|
|
|
|
const struct string_list *values;
|
|
|
|
struct key_value_info *kv_info;
|
2021-12-07 18:26:34 +00:00
|
|
|
report_fn error_fn = get_error_routine();
|
2014-08-07 11:59:16 +00:00
|
|
|
|
|
|
|
if (err) {
|
|
|
|
va_list params;
|
|
|
|
va_start(params, err);
|
2021-12-07 18:26:34 +00:00
|
|
|
error_fn(err, params);
|
2014-08-07 11:59:16 +00:00
|
|
|
va_end(params);
|
|
|
|
}
|
|
|
|
values = git_config_get_value_multi(key);
|
|
|
|
kv_info = values->items[values->nr - 1].util;
|
|
|
|
git_die_config_linenr(key, kv_info->filename, kv_info->linenr);
|
2014-07-28 10:10:38 +00:00
|
|
|
}
|
|
|
|
|
2005-11-17 21:32:36 +00:00
|
|
|
/*
|
|
|
|
* Find all the stuff for git_config_set() below.
|
|
|
|
*/
|
2005-11-20 05:52:22 +00:00
|
|
|
|
2018-04-09 08:32:09 +00:00
|
|
|
struct config_store_data {
|
2020-04-10 19:46:07 +00:00
|
|
|
size_t baselen;
|
2009-05-01 09:06:36 +00:00
|
|
|
char *key;
|
2005-11-20 12:24:18 +00:00
|
|
|
int do_not_match;
|
2020-11-25 22:12:54 +00:00
|
|
|
const char *fixed_value;
|
2020-11-25 22:12:50 +00:00
|
|
|
regex_t *value_pattern;
|
2005-11-20 05:52:22 +00:00
|
|
|
int multi_replace;
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
struct {
|
|
|
|
size_t begin, end;
|
|
|
|
enum config_event_t type;
|
git config --unset: remove empty sections (in the common case)
The original reasoning for not removing section headers upon removal of
the last entry went like this: the user could have added comments about
the section, or about the entries therein, and if there were other
comments there, we would not know whether we should remove them.
In particular, a concocted example was presented that looked like this
(and was added to t1300):
# some generic comment on the configuration file itself
# a comment specific to this "section" section.
[section]
# some intervening lines
# that should also be dropped
key = value
# please be careful when you update the above variable
The ideal thing for `git config --unset section.key` in this case would
be to leave only the first line behind, because all the other comments
are now obsolete.
However, this is unfeasible, short of adding a complete Natural Language
Processing module to Git, which seems not only a lot of work, but a
totally unreasonable feature (for little benefit to most users).
Now, the real kicker about this problem is: most users do not edit their
config files at all! In their use case, the config looks like this
instead:
[section]
key = value
... and it is totally obvious what should happen if the entry is
removed: the entire section should vanish.
Let's generalize this observation to this conservative strategy: if we
are removing the last entry from a section, and there are no comments
inside that section nor surrounding it, then remove the entire section.
Otherwise behave as before: leave the now-empty section (including those
comments, even ones about the now-deleted entry).
We have to be extra careful to handle the case where more than one entry
is removed: any subset of them might be the last entries of their
respective sections (and if there are no comments in or around that
section, the section should be removed, too).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:24 +00:00
|
|
|
int is_keys_section;
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
} *parsed;
|
|
|
|
unsigned int parsed_nr, parsed_alloc, *seen, seen_nr, seen_alloc;
|
2018-04-09 08:32:17 +00:00
|
|
|
unsigned int key_seen:1, section_seen:1, is_keys_section:1;
|
2018-04-09 08:32:09 +00:00
|
|
|
};
|
2005-11-17 21:32:36 +00:00
|
|
|
|
2018-05-20 10:42:33 +00:00
|
|
|
static void config_store_data_clear(struct config_store_data *store)
|
|
|
|
{
|
2018-05-20 10:42:35 +00:00
|
|
|
free(store->key);
|
2020-11-25 22:12:50 +00:00
|
|
|
if (store->value_pattern != NULL &&
|
|
|
|
store->value_pattern != CONFIG_REGEX_NONE) {
|
|
|
|
regfree(store->value_pattern);
|
|
|
|
free(store->value_pattern);
|
2018-05-20 10:42:34 +00:00
|
|
|
}
|
2018-05-20 10:42:33 +00:00
|
|
|
free(store->parsed);
|
|
|
|
free(store->seen);
|
|
|
|
memset(store, 0, sizeof(*store));
|
|
|
|
}
|
|
|
|
|
2018-04-09 08:32:09 +00:00
|
|
|
static int matches(const char *key, const char *value,
|
|
|
|
const struct config_store_data *store)
|
2005-11-20 12:24:18 +00:00
|
|
|
{
|
2018-04-09 08:32:09 +00:00
|
|
|
if (strcmp(key, store->key))
|
2014-08-19 06:20:00 +00:00
|
|
|
return 0; /* not ours */
|
2020-11-25 22:12:54 +00:00
|
|
|
if (store->fixed_value)
|
|
|
|
return !strcmp(store->fixed_value, value);
|
2020-11-25 22:12:50 +00:00
|
|
|
if (!store->value_pattern)
|
2014-08-19 06:20:00 +00:00
|
|
|
return 1; /* always matches */
|
2020-11-25 22:12:50 +00:00
|
|
|
if (store->value_pattern == CONFIG_REGEX_NONE)
|
2014-08-19 06:20:00 +00:00
|
|
|
return 0; /* never matches */
|
|
|
|
|
2018-04-09 08:32:09 +00:00
|
|
|
return store->do_not_match ^
|
2020-11-25 22:12:50 +00:00
|
|
|
(value && !regexec(store->value_pattern, value, 0, NULL, 0));
|
2005-11-20 12:24:18 +00:00
|
|
|
}
|
|
|
|
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
static int store_aux_event(enum config_event_t type,
|
|
|
|
size_t begin, size_t end, void *data)
|
|
|
|
{
|
|
|
|
struct config_store_data *store = data;
|
|
|
|
|
|
|
|
ALLOC_GROW(store->parsed, store->parsed_nr + 1, store->parsed_alloc);
|
|
|
|
store->parsed[store->parsed_nr].begin = begin;
|
|
|
|
store->parsed[store->parsed_nr].end = end;
|
|
|
|
store->parsed[store->parsed_nr].type = type;
|
|
|
|
|
|
|
|
if (type == CONFIG_EVENT_SECTION) {
|
2018-08-08 19:50:19 +00:00
|
|
|
int (*cmpfn)(const char *, const char *, size_t);
|
|
|
|
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
if (cf->var.len < 2 || cf->var.buf[cf->var.len - 1] != '.')
|
2018-07-21 07:49:27 +00:00
|
|
|
return error(_("invalid section name '%s'"), cf->var.buf);
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
|
2018-08-08 19:50:19 +00:00
|
|
|
if (cf->subsection_case_sensitive)
|
|
|
|
cmpfn = strncasecmp;
|
|
|
|
else
|
|
|
|
cmpfn = strncmp;
|
|
|
|
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
/* Is this the section we were looking for? */
|
git config --unset: remove empty sections (in the common case)
The original reasoning for not removing section headers upon removal of
the last entry went like this: the user could have added comments about
the section, or about the entries therein, and if there were other
comments there, we would not know whether we should remove them.
In particular, a concocted example was presented that looked like this
(and was added to t1300):
# some generic comment on the configuration file itself
# a comment specific to this "section" section.
[section]
# some intervening lines
# that should also be dropped
key = value
# please be careful when you update the above variable
The ideal thing for `git config --unset section.key` in this case would
be to leave only the first line behind, because all the other comments
are now obsolete.
However, this is unfeasible, short of adding a complete Natural Language
Processing module to Git, which seems not only a lot of work, but a
totally unreasonable feature (for little benefit to most users).
Now, the real kicker about this problem is: most users do not edit their
config files at all! In their use case, the config looks like this
instead:
[section]
key = value
... and it is totally obvious what should happen if the entry is
removed: the entire section should vanish.
Let's generalize this observation to this conservative strategy: if we
are removing the last entry from a section, and there are no comments
inside that section nor surrounding it, then remove the entire section.
Otherwise behave as before: leave the now-empty section (including those
comments, even ones about the now-deleted entry).
We have to be extra careful to handle the case where more than one entry
is removed: any subset of them might be the last entries of their
respective sections (and if there are no comments in or around that
section, the section should be removed, too).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:24 +00:00
|
|
|
store->is_keys_section =
|
|
|
|
store->parsed[store->parsed_nr].is_keys_section =
|
|
|
|
cf->var.len - 1 == store->baselen &&
|
2018-08-08 19:50:19 +00:00
|
|
|
!cmpfn(cf->var.buf, store->key, store->baselen);
|
2018-04-09 08:32:29 +00:00
|
|
|
if (store->is_keys_section) {
|
|
|
|
store->section_seen = 1;
|
|
|
|
ALLOC_GROW(store->seen, store->seen_nr + 1,
|
|
|
|
store->seen_alloc);
|
|
|
|
store->seen[store->seen_nr] = store->parsed_nr;
|
|
|
|
}
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
}
|
|
|
|
|
git config --unset: remove empty sections (in the common case)
The original reasoning for not removing section headers upon removal of
the last entry went like this: the user could have added comments about
the section, or about the entries therein, and if there were other
comments there, we would not know whether we should remove them.
In particular, a concocted example was presented that looked like this
(and was added to t1300):
# some generic comment on the configuration file itself
# a comment specific to this "section" section.
[section]
# some intervening lines
# that should also be dropped
key = value
# please be careful when you update the above variable
The ideal thing for `git config --unset section.key` in this case would
be to leave only the first line behind, because all the other comments
are now obsolete.
However, this is unfeasible, short of adding a complete Natural Language
Processing module to Git, which seems not only a lot of work, but a
totally unreasonable feature (for little benefit to most users).
Now, the real kicker about this problem is: most users do not edit their
config files at all! In their use case, the config looks like this
instead:
[section]
key = value
... and it is totally obvious what should happen if the entry is
removed: the entire section should vanish.
Let's generalize this observation to this conservative strategy: if we
are removing the last entry from a section, and there are no comments
inside that section nor surrounding it, then remove the entire section.
Otherwise behave as before: leave the now-empty section (including those
comments, even ones about the now-deleted entry).
We have to be extra careful to handle the case where more than one entry
is removed: any subset of them might be the last entries of their
respective sections (and if there are no comments in or around that
section, the section should be removed, too).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:24 +00:00
|
|
|
store->parsed_nr++;
|
|
|
|
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
return 0;
|
2005-11-20 12:24:18 +00:00
|
|
|
}
|
|
|
|
|
2009-05-01 09:06:36 +00:00
|
|
|
static int store_aux(const char *key, const char *value, void *cb)
|
2005-11-17 21:32:36 +00:00
|
|
|
{
|
2018-04-09 08:32:09 +00:00
|
|
|
struct config_store_data *store = cb;
|
2007-05-13 04:49:33 +00:00
|
|
|
|
2018-04-09 08:32:17 +00:00
|
|
|
if (store->key_seen) {
|
2018-04-09 08:32:09 +00:00
|
|
|
if (matches(key, value, store)) {
|
2018-04-09 08:32:13 +00:00
|
|
|
if (store->seen_nr == 1 && store->multi_replace == 0) {
|
2014-08-07 11:59:12 +00:00
|
|
|
warning(_("%s has multiple values"), key);
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
2005-11-20 05:52:22 +00:00
|
|
|
|
2018-04-09 08:32:13 +00:00
|
|
|
ALLOC_GROW(store->seen, store->seen_nr + 1,
|
|
|
|
store->seen_alloc);
|
2013-11-13 10:19:00 +00:00
|
|
|
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
store->seen[store->seen_nr] = store->parsed_nr;
|
2018-04-09 08:32:13 +00:00
|
|
|
store->seen_nr++;
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
2018-04-09 08:32:17 +00:00
|
|
|
} else if (store->is_keys_section) {
|
2007-05-13 04:49:33 +00:00
|
|
|
/*
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
* Do not increment matches yet: this may not be a match, but we
|
|
|
|
* are in the desired section.
|
2007-05-13 04:49:33 +00:00
|
|
|
*/
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
ALLOC_GROW(store->seen, store->seen_nr + 1, store->seen_alloc);
|
|
|
|
store->seen[store->seen_nr] = store->parsed_nr;
|
2018-04-09 08:32:17 +00:00
|
|
|
store->section_seen = 1;
|
2007-05-13 04:49:33 +00:00
|
|
|
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
if (matches(key, value, store)) {
|
|
|
|
store->seen_nr++;
|
|
|
|
store->key_seen = 1;
|
2006-05-06 18:14:02 +00:00
|
|
|
}
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
2018-04-09 08:32:17 +00:00
|
|
|
|
2005-11-17 21:32:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-05-12 21:41:04 +00:00
|
|
|
static int write_error(const char *filename)
|
2007-01-08 15:58:38 +00:00
|
|
|
{
|
2018-07-21 07:49:27 +00:00
|
|
|
error(_("failed to write new configuration file %s"), filename);
|
2007-01-08 15:58:38 +00:00
|
|
|
|
|
|
|
/* Same error code as "failed to rename". */
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
|
2018-04-09 08:32:09 +00:00
|
|
|
static struct strbuf store_create_section(const char *key,
|
|
|
|
const struct config_store_data *store)
|
2005-11-17 21:32:36 +00:00
|
|
|
{
|
2007-12-14 20:59:58 +00:00
|
|
|
const char *dot;
|
2020-04-10 19:46:07 +00:00
|
|
|
size_t i;
|
2008-10-09 19:12:12 +00:00
|
|
|
struct strbuf sb = STRBUF_INIT;
|
2006-05-09 19:24:02 +00:00
|
|
|
|
2018-04-09 08:32:09 +00:00
|
|
|
dot = memchr(key, '.', store->baselen);
|
2006-05-09 19:24:02 +00:00
|
|
|
if (dot) {
|
2007-12-14 20:59:58 +00:00
|
|
|
strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
|
2018-04-09 08:32:09 +00:00
|
|
|
for (i = dot - key + 1; i < store->baselen; i++) {
|
2008-05-04 05:37:52 +00:00
|
|
|
if (key[i] == '"' || key[i] == '\\')
|
2007-12-14 20:59:58 +00:00
|
|
|
strbuf_addch(&sb, '\\');
|
|
|
|
strbuf_addch(&sb, key[i]);
|
2006-05-09 19:24:02 +00:00
|
|
|
}
|
2007-12-14 20:59:58 +00:00
|
|
|
strbuf_addstr(&sb, "\"]\n");
|
|
|
|
} else {
|
2020-04-10 19:46:07 +00:00
|
|
|
strbuf_addch(&sb, '[');
|
|
|
|
strbuf_add(&sb, key, store->baselen);
|
|
|
|
strbuf_addstr(&sb, "]\n");
|
2006-05-09 19:24:02 +00:00
|
|
|
}
|
|
|
|
|
2017-06-18 21:16:31 +00:00
|
|
|
return sb;
|
|
|
|
}
|
|
|
|
|
2018-04-09 08:32:09 +00:00
|
|
|
static ssize_t write_section(int fd, const char *key,
|
|
|
|
const struct config_store_data *store)
|
2017-06-18 21:16:31 +00:00
|
|
|
{
|
2018-04-09 08:32:09 +00:00
|
|
|
struct strbuf sb = store_create_section(key, store);
|
2017-10-03 06:42:48 +00:00
|
|
|
ssize_t ret;
|
2017-06-18 21:16:31 +00:00
|
|
|
|
2017-11-18 10:20:04 +00:00
|
|
|
ret = write_in_full(fd, sb.buf, sb.len);
|
2007-12-14 20:59:58 +00:00
|
|
|
strbuf_release(&sb);
|
2007-01-08 15:58:38 +00:00
|
|
|
|
2017-09-13 17:17:57 +00:00
|
|
|
return ret;
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
|
|
|
|
2018-04-09 08:32:09 +00:00
|
|
|
static ssize_t write_pair(int fd, const char *key, const char *value,
|
|
|
|
const struct config_store_data *store)
|
2005-11-17 21:32:36 +00:00
|
|
|
{
|
2017-09-13 17:17:57 +00:00
|
|
|
int i;
|
|
|
|
ssize_t ret;
|
2007-12-14 20:59:58 +00:00
|
|
|
const char *quote = "";
|
2008-10-09 19:12:12 +00:00
|
|
|
struct strbuf sb = STRBUF_INIT;
|
2007-01-09 05:27:41 +00:00
|
|
|
|
2007-12-08 15:48:05 +00:00
|
|
|
/*
|
|
|
|
* Check to see if the value needs to be surrounded with a dq pair.
|
|
|
|
* Note that problematic characters are always backslash-quoted; this
|
|
|
|
* check is about not losing leading or trailing SP and strings that
|
|
|
|
* follow beginning-of-comment characters (i.e. ';' and '#') by the
|
|
|
|
* configuration parser.
|
|
|
|
*/
|
2007-01-09 05:27:41 +00:00
|
|
|
if (value[0] == ' ')
|
2007-12-14 20:59:58 +00:00
|
|
|
quote = "\"";
|
2007-01-09 05:27:41 +00:00
|
|
|
for (i = 0; value[i]; i++)
|
|
|
|
if (value[i] == ';' || value[i] == '#')
|
2007-12-14 20:59:58 +00:00
|
|
|
quote = "\"";
|
|
|
|
if (i && value[i - 1] == ' ')
|
|
|
|
quote = "\"";
|
|
|
|
|
2020-04-10 19:44:45 +00:00
|
|
|
strbuf_addf(&sb, "\t%s = %s", key + store->baselen + 1, quote);
|
2005-11-17 21:32:36 +00:00
|
|
|
|
|
|
|
for (i = 0; value[i]; i++)
|
|
|
|
switch (value[i]) {
|
2007-01-08 15:58:38 +00:00
|
|
|
case '\n':
|
2007-12-14 20:59:58 +00:00
|
|
|
strbuf_addstr(&sb, "\\n");
|
2007-01-08 15:58:38 +00:00
|
|
|
break;
|
|
|
|
case '\t':
|
2007-12-14 20:59:58 +00:00
|
|
|
strbuf_addstr(&sb, "\\t");
|
2007-01-08 15:58:38 +00:00
|
|
|
break;
|
|
|
|
case '"':
|
|
|
|
case '\\':
|
2007-12-14 20:59:58 +00:00
|
|
|
strbuf_addch(&sb, '\\');
|
consistently use "fallthrough" comments in switches
Gcc 7 adds -Wimplicit-fallthrough, which can warn when a
switch case falls through to the next case. The general idea
is that the compiler can't tell if this was intentional or
not, so you should annotate any intentional fall-throughs as
such, leaving it to complain about any unannotated ones.
There's a GNU __attribute__ which can be used for
annotation, but of course we'd have to #ifdef it away on
non-gcc compilers. Gcc will also recognize
specially-formatted comments, which matches our current
practice. Let's extend that practice to all of the
unannotated sites (which I did look over and verify that
they were behaving as intended).
Ideally in each case we'd actually give some reasons in the
comment about why we're falling through, or what we're
falling through to. And gcc does support that with
-Wimplicit-fallthrough=2, which relaxes the comment pattern
matching to anything that contains "fallthrough" (or a
variety of spelling variants). However, this isn't the
default for -Wimplicit-fallthrough, nor for -Wextra. In the
name of simplicity, it's probably better for us to support
the default level, which requires "fallthrough" to be the
only thing in the comment (modulo some window dressing like
"else" and some punctuation; see the gcc manual for the
complete set of patterns).
This patch suppresses all warnings due to
-Wimplicit-fallthrough. We might eventually want to add that
to the DEVELOPER Makefile knob, but we should probably wait
until gcc 7 is more widely adopted (since earlier versions
will complain about the unknown warning type).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-09-21 06:25:41 +00:00
|
|
|
/* fallthrough */
|
2007-01-08 15:58:38 +00:00
|
|
|
default:
|
2007-12-14 20:59:58 +00:00
|
|
|
strbuf_addch(&sb, value[i]);
|
2007-01-08 15:58:38 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-12-14 20:59:58 +00:00
|
|
|
strbuf_addf(&sb, "%s\n", quote);
|
|
|
|
|
2017-09-13 17:17:57 +00:00
|
|
|
ret = write_in_full(fd, sb.buf, sb.len);
|
2007-12-14 20:59:58 +00:00
|
|
|
strbuf_release(&sb);
|
|
|
|
|
2017-09-13 17:17:57 +00:00
|
|
|
return ret;
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
|
|
|
|
git config --unset: remove empty sections (in the common case)
The original reasoning for not removing section headers upon removal of
the last entry went like this: the user could have added comments about
the section, or about the entries therein, and if there were other
comments there, we would not know whether we should remove them.
In particular, a concocted example was presented that looked like this
(and was added to t1300):
# some generic comment on the configuration file itself
# a comment specific to this "section" section.
[section]
# some intervening lines
# that should also be dropped
key = value
# please be careful when you update the above variable
The ideal thing for `git config --unset section.key` in this case would
be to leave only the first line behind, because all the other comments
are now obsolete.
However, this is unfeasible, short of adding a complete Natural Language
Processing module to Git, which seems not only a lot of work, but a
totally unreasonable feature (for little benefit to most users).
Now, the real kicker about this problem is: most users do not edit their
config files at all! In their use case, the config looks like this
instead:
[section]
key = value
... and it is totally obvious what should happen if the entry is
removed: the entire section should vanish.
Let's generalize this observation to this conservative strategy: if we
are removing the last entry from a section, and there are no comments
inside that section nor surrounding it, then remove the entire section.
Otherwise behave as before: leave the now-empty section (including those
comments, even ones about the now-deleted entry).
We have to be extra careful to handle the case where more than one entry
is removed: any subset of them might be the last entries of their
respective sections (and if there are no comments in or around that
section, the section should be removed, too).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:24 +00:00
|
|
|
/*
|
|
|
|
* If we are about to unset the last key(s) in a section, and if there are
|
|
|
|
* no comments surrounding (or included in) the section, we will want to
|
|
|
|
* extend begin/end to remove the entire section.
|
|
|
|
*
|
|
|
|
* Note: the parameter `seen_ptr` points to the index into the store.seen
|
|
|
|
* array. * This index may be incremented if a section has more than one
|
|
|
|
* entry (which all are to be removed).
|
|
|
|
*/
|
|
|
|
static void maybe_remove_section(struct config_store_data *store,
|
|
|
|
size_t *begin_offset, size_t *end_offset,
|
|
|
|
int *seen_ptr)
|
2005-11-20 05:52:22 +00:00
|
|
|
{
|
git config --unset: remove empty sections (in the common case)
The original reasoning for not removing section headers upon removal of
the last entry went like this: the user could have added comments about
the section, or about the entries therein, and if there were other
comments there, we would not know whether we should remove them.
In particular, a concocted example was presented that looked like this
(and was added to t1300):
# some generic comment on the configuration file itself
# a comment specific to this "section" section.
[section]
# some intervening lines
# that should also be dropped
key = value
# please be careful when you update the above variable
The ideal thing for `git config --unset section.key` in this case would
be to leave only the first line behind, because all the other comments
are now obsolete.
However, this is unfeasible, short of adding a complete Natural Language
Processing module to Git, which seems not only a lot of work, but a
totally unreasonable feature (for little benefit to most users).
Now, the real kicker about this problem is: most users do not edit their
config files at all! In their use case, the config looks like this
instead:
[section]
key = value
... and it is totally obvious what should happen if the entry is
removed: the entire section should vanish.
Let's generalize this observation to this conservative strategy: if we
are removing the last entry from a section, and there are no comments
inside that section nor surrounding it, then remove the entire section.
Otherwise behave as before: leave the now-empty section (including those
comments, even ones about the now-deleted entry).
We have to be extra careful to handle the case where more than one entry
is removed: any subset of them might be the last entries of their
respective sections (and if there are no comments in or around that
section, the section should be removed, too).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:24 +00:00
|
|
|
size_t begin;
|
|
|
|
int i, seen, section_seen = 0;
|
2005-11-20 05:52:22 +00:00
|
|
|
|
git config --unset: remove empty sections (in the common case)
The original reasoning for not removing section headers upon removal of
the last entry went like this: the user could have added comments about
the section, or about the entries therein, and if there were other
comments there, we would not know whether we should remove them.
In particular, a concocted example was presented that looked like this
(and was added to t1300):
# some generic comment on the configuration file itself
# a comment specific to this "section" section.
[section]
# some intervening lines
# that should also be dropped
key = value
# please be careful when you update the above variable
The ideal thing for `git config --unset section.key` in this case would
be to leave only the first line behind, because all the other comments
are now obsolete.
However, this is unfeasible, short of adding a complete Natural Language
Processing module to Git, which seems not only a lot of work, but a
totally unreasonable feature (for little benefit to most users).
Now, the real kicker about this problem is: most users do not edit their
config files at all! In their use case, the config looks like this
instead:
[section]
key = value
... and it is totally obvious what should happen if the entry is
removed: the entire section should vanish.
Let's generalize this observation to this conservative strategy: if we
are removing the last entry from a section, and there are no comments
inside that section nor surrounding it, then remove the entire section.
Otherwise behave as before: leave the now-empty section (including those
comments, even ones about the now-deleted entry).
We have to be extra careful to handle the case where more than one entry
is removed: any subset of them might be the last entries of their
respective sections (and if there are no comments in or around that
section, the section should be removed, too).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:24 +00:00
|
|
|
/*
|
|
|
|
* First, ensure that this is the first key, and that there are no
|
|
|
|
* comments before the entry nor before the section header.
|
|
|
|
*/
|
|
|
|
seen = *seen_ptr;
|
|
|
|
for (i = store->seen[seen]; i > 0; i--) {
|
|
|
|
enum config_event_t type = store->parsed[i - 1].type;
|
|
|
|
|
|
|
|
if (type == CONFIG_EVENT_COMMENT)
|
|
|
|
/* There is a comment before this entry or section */
|
|
|
|
return;
|
|
|
|
if (type == CONFIG_EVENT_ENTRY) {
|
|
|
|
if (!section_seen)
|
|
|
|
/* This is not the section's first entry. */
|
|
|
|
return;
|
|
|
|
/* We encountered no comment before the section. */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (type == CONFIG_EVENT_SECTION) {
|
|
|
|
if (!store->parsed[i - 1].is_keys_section)
|
|
|
|
break;
|
|
|
|
section_seen = 1;
|
2005-11-20 05:52:22 +00:00
|
|
|
}
|
2008-02-11 00:23:03 +00:00
|
|
|
}
|
git config --unset: remove empty sections (in the common case)
The original reasoning for not removing section headers upon removal of
the last entry went like this: the user could have added comments about
the section, or about the entries therein, and if there were other
comments there, we would not know whether we should remove them.
In particular, a concocted example was presented that looked like this
(and was added to t1300):
# some generic comment on the configuration file itself
# a comment specific to this "section" section.
[section]
# some intervening lines
# that should also be dropped
key = value
# please be careful when you update the above variable
The ideal thing for `git config --unset section.key` in this case would
be to leave only the first line behind, because all the other comments
are now obsolete.
However, this is unfeasible, short of adding a complete Natural Language
Processing module to Git, which seems not only a lot of work, but a
totally unreasonable feature (for little benefit to most users).
Now, the real kicker about this problem is: most users do not edit their
config files at all! In their use case, the config looks like this
instead:
[section]
key = value
... and it is totally obvious what should happen if the entry is
removed: the entire section should vanish.
Let's generalize this observation to this conservative strategy: if we
are removing the last entry from a section, and there are no comments
inside that section nor surrounding it, then remove the entire section.
Otherwise behave as before: leave the now-empty section (including those
comments, even ones about the now-deleted entry).
We have to be extra careful to handle the case where more than one entry
is removed: any subset of them might be the last entries of their
respective sections (and if there are no comments in or around that
section, the section should be removed, too).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:24 +00:00
|
|
|
begin = store->parsed[i].begin;
|
|
|
|
|
|
|
|
/*
|
2021-06-15 14:11:11 +00:00
|
|
|
* Next, make sure that we are removing the last key(s) in the section,
|
git config --unset: remove empty sections (in the common case)
The original reasoning for not removing section headers upon removal of
the last entry went like this: the user could have added comments about
the section, or about the entries therein, and if there were other
comments there, we would not know whether we should remove them.
In particular, a concocted example was presented that looked like this
(and was added to t1300):
# some generic comment on the configuration file itself
# a comment specific to this "section" section.
[section]
# some intervening lines
# that should also be dropped
key = value
# please be careful when you update the above variable
The ideal thing for `git config --unset section.key` in this case would
be to leave only the first line behind, because all the other comments
are now obsolete.
However, this is unfeasible, short of adding a complete Natural Language
Processing module to Git, which seems not only a lot of work, but a
totally unreasonable feature (for little benefit to most users).
Now, the real kicker about this problem is: most users do not edit their
config files at all! In their use case, the config looks like this
instead:
[section]
key = value
... and it is totally obvious what should happen if the entry is
removed: the entire section should vanish.
Let's generalize this observation to this conservative strategy: if we
are removing the last entry from a section, and there are no comments
inside that section nor surrounding it, then remove the entire section.
Otherwise behave as before: leave the now-empty section (including those
comments, even ones about the now-deleted entry).
We have to be extra careful to handle the case where more than one entry
is removed: any subset of them might be the last entries of their
respective sections (and if there are no comments in or around that
section, the section should be removed, too).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:24 +00:00
|
|
|
* and that there are no comments that are possibly about the current
|
|
|
|
* section.
|
|
|
|
*/
|
|
|
|
for (i = store->seen[seen] + 1; i < store->parsed_nr; i++) {
|
|
|
|
enum config_event_t type = store->parsed[i].type;
|
2005-11-20 05:52:22 +00:00
|
|
|
|
git config --unset: remove empty sections (in the common case)
The original reasoning for not removing section headers upon removal of
the last entry went like this: the user could have added comments about
the section, or about the entries therein, and if there were other
comments there, we would not know whether we should remove them.
In particular, a concocted example was presented that looked like this
(and was added to t1300):
# some generic comment on the configuration file itself
# a comment specific to this "section" section.
[section]
# some intervening lines
# that should also be dropped
key = value
# please be careful when you update the above variable
The ideal thing for `git config --unset section.key` in this case would
be to leave only the first line behind, because all the other comments
are now obsolete.
However, this is unfeasible, short of adding a complete Natural Language
Processing module to Git, which seems not only a lot of work, but a
totally unreasonable feature (for little benefit to most users).
Now, the real kicker about this problem is: most users do not edit their
config files at all! In their use case, the config looks like this
instead:
[section]
key = value
... and it is totally obvious what should happen if the entry is
removed: the entire section should vanish.
Let's generalize this observation to this conservative strategy: if we
are removing the last entry from a section, and there are no comments
inside that section nor surrounding it, then remove the entire section.
Otherwise behave as before: leave the now-empty section (including those
comments, even ones about the now-deleted entry).
We have to be extra careful to handle the case where more than one entry
is removed: any subset of them might be the last entries of their
respective sections (and if there are no comments in or around that
section, the section should be removed, too).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:24 +00:00
|
|
|
if (type == CONFIG_EVENT_COMMENT)
|
|
|
|
return;
|
|
|
|
if (type == CONFIG_EVENT_SECTION) {
|
|
|
|
if (store->parsed[i].is_keys_section)
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (type == CONFIG_EVENT_ENTRY) {
|
|
|
|
if (++seen < store->seen_nr &&
|
|
|
|
i == store->seen[seen])
|
|
|
|
/* We want to remove this entry, too */
|
|
|
|
continue;
|
|
|
|
/* There is another entry in this section. */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We are really removing the last entry/entries from this section, and
|
|
|
|
* there are no enclosed or surrounding comments. Remove the entire,
|
|
|
|
* now-empty section.
|
|
|
|
*/
|
|
|
|
*seen_ptr = seen;
|
|
|
|
*begin_offset = begin;
|
|
|
|
if (i < store->parsed_nr)
|
|
|
|
*end_offset = store->parsed[i].begin;
|
|
|
|
else
|
|
|
|
*end_offset = store->parsed[store->parsed_nr - 1].end;
|
2005-11-20 05:52:22 +00:00
|
|
|
}
|
|
|
|
|
2016-02-22 11:23:35 +00:00
|
|
|
int git_config_set_in_file_gently(const char *config_filename,
|
|
|
|
const char *key, const char *value)
|
2011-08-04 10:39:00 +00:00
|
|
|
{
|
2016-02-22 11:23:35 +00:00
|
|
|
return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, 0);
|
2011-08-04 10:39:00 +00:00
|
|
|
}
|
|
|
|
|
2016-02-22 11:23:36 +00:00
|
|
|
void git_config_set_in_file(const char *config_filename,
|
|
|
|
const char *key, const char *value)
|
2005-11-17 21:32:36 +00:00
|
|
|
{
|
2016-02-22 11:23:36 +00:00
|
|
|
git_config_set_multivar_in_file(config_filename, key, value, NULL, 0);
|
2016-02-16 12:56:28 +00:00
|
|
|
}
|
|
|
|
|
2016-02-22 11:23:35 +00:00
|
|
|
int git_config_set_gently(const char *key, const char *value)
|
2005-11-17 21:32:36 +00:00
|
|
|
{
|
2016-02-22 11:23:35 +00:00
|
|
|
return git_config_set_multivar_gently(key, value, NULL, 0);
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 21:33:00 +00:00
|
|
|
int repo_config_set_worktree_gently(struct repository *r,
|
|
|
|
const char *key, const char *value)
|
|
|
|
{
|
|
|
|
/* Only use worktree-specific config if it is is already enabled. */
|
|
|
|
if (repository_format_worktree_config) {
|
|
|
|
char *file = repo_git_path(r, "config.worktree");
|
|
|
|
int ret = git_config_set_multivar_in_file_gently(
|
|
|
|
file, key, value, NULL, 0);
|
|
|
|
free(file);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
return repo_config_set_multivar_gently(r, key, value, NULL, 0);
|
|
|
|
}
|
|
|
|
|
2016-02-22 11:23:36 +00:00
|
|
|
void git_config_set(const char *key, const char *value)
|
2016-02-16 12:56:28 +00:00
|
|
|
{
|
2016-02-22 11:23:36 +00:00
|
|
|
git_config_set_multivar(key, value, NULL, 0);
|
2019-02-22 22:25:01 +00:00
|
|
|
|
|
|
|
trace2_cmd_set_config(key, value);
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If value==NULL, unset in (remove from) config,
|
2020-11-25 22:12:50 +00:00
|
|
|
* if value_pattern!=NULL, disregard key/value pairs where value does not match.
|
|
|
|
* if value_pattern==CONFIG_REGEX_NONE, do not match any existing values
|
2014-08-19 06:20:00 +00:00
|
|
|
* (only add a new one)
|
2020-11-25 22:12:49 +00:00
|
|
|
* if flags contains the CONFIG_FLAGS_MULTI_REPLACE flag, all matching
|
|
|
|
* key/values are removed before a single new pair is written. If the
|
|
|
|
* flag is not present, then replace only the first match.
|
2005-11-17 21:32:36 +00:00
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*
|
|
|
|
* This function does this:
|
|
|
|
*
|
|
|
|
* - it locks the config file by creating ".git/config.lock"
|
|
|
|
*
|
|
|
|
* - it then parses the config using store_aux() as validator to find
|
|
|
|
* the position on the key/value pair to replace. If it is to be unset,
|
|
|
|
* it must be found exactly once.
|
|
|
|
*
|
|
|
|
* - the config file is mmap()ed and the part before the match (if any) is
|
|
|
|
* written to the lock file, then the changed part and the rest.
|
|
|
|
*
|
|
|
|
* - the config file is removed and the lock file rename()d to it.
|
|
|
|
*
|
|
|
|
*/
|
2016-02-22 11:23:35 +00:00
|
|
|
int git_config_set_multivar_in_file_gently(const char *config_filename,
|
|
|
|
const char *key, const char *value,
|
2020-11-25 22:12:50 +00:00
|
|
|
const char *value_pattern,
|
2020-11-25 22:12:49 +00:00
|
|
|
unsigned flags)
|
2005-11-17 21:32:36 +00:00
|
|
|
{
|
2015-08-14 20:21:17 +00:00
|
|
|
int fd = -1, in_fd = -1;
|
2006-04-17 15:14:48 +00:00
|
|
|
int ret;
|
2017-09-05 12:15:21 +00:00
|
|
|
struct lock_file lock = LOCK_INIT;
|
2012-02-16 08:04:05 +00:00
|
|
|
char *filename_buf = NULL;
|
2015-05-28 07:54:43 +00:00
|
|
|
char *contents = NULL;
|
|
|
|
size_t contents_sz;
|
2018-04-09 08:32:09 +00:00
|
|
|
struct config_store_data store;
|
|
|
|
|
|
|
|
memset(&store, 0, sizeof(store));
|
2005-11-20 05:52:22 +00:00
|
|
|
|
2011-01-30 19:40:41 +00:00
|
|
|
/* parse-key returns negative; flip the sign to feed exit(3) */
|
|
|
|
ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
|
|
|
|
if (ret)
|
2006-04-17 15:14:48 +00:00
|
|
|
goto out_free;
|
2005-11-20 20:22:19 +00:00
|
|
|
|
2020-11-25 22:12:49 +00:00
|
|
|
store.multi_replace = (flags & CONFIG_FLAGS_MULTI_REPLACE) != 0;
|
2005-11-17 21:32:36 +00:00
|
|
|
|
2012-02-16 08:04:05 +00:00
|
|
|
if (!config_filename)
|
|
|
|
config_filename = filename_buf = git_pathdup("config");
|
2005-11-17 21:32:36 +00:00
|
|
|
|
|
|
|
/*
|
2007-07-26 16:55:28 +00:00
|
|
|
* The lock serves a purpose in addition to locking: the new
|
2005-11-17 21:32:36 +00:00
|
|
|
* contents of .git/config will be written into it.
|
|
|
|
*/
|
2017-09-05 12:15:21 +00:00
|
|
|
fd = hold_lock_file_for_update(&lock, config_filename, 0);
|
2007-07-26 16:55:28 +00:00
|
|
|
if (fd < 0) {
|
2018-07-21 07:49:27 +00:00
|
|
|
error_errno(_("could not lock config file %s"), config_filename);
|
2011-05-17 15:38:52 +00:00
|
|
|
ret = CONFIG_NO_LOCK;
|
2006-04-17 15:14:48 +00:00
|
|
|
goto out_free;
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If .git/config does not exist yet, write a minimal version.
|
|
|
|
*/
|
2006-01-05 11:43:34 +00:00
|
|
|
in_fd = open(config_filename, O_RDONLY);
|
|
|
|
if ( in_fd < 0 ) {
|
|
|
|
if ( ENOENT != errno ) {
|
2018-07-21 07:49:27 +00:00
|
|
|
error_errno(_("opening %s"), config_filename);
|
2011-05-17 15:38:52 +00:00
|
|
|
ret = CONFIG_INVALID_FILE; /* same as "invalid config file" */
|
2006-04-17 15:14:48 +00:00
|
|
|
goto out_free;
|
2006-01-05 11:43:34 +00:00
|
|
|
}
|
2005-11-17 21:32:36 +00:00
|
|
|
/* if nothing to unset, error out */
|
2022-05-02 16:50:37 +00:00
|
|
|
if (!value) {
|
2011-05-17 15:38:52 +00:00
|
|
|
ret = CONFIG_NOTHING_SET;
|
2006-04-17 15:14:48 +00:00
|
|
|
goto out_free;
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
|
|
|
|
2018-05-20 10:42:35 +00:00
|
|
|
free(store.key);
|
|
|
|
store.key = xstrdup(key);
|
2018-04-09 08:32:09 +00:00
|
|
|
if (write_section(fd, key, &store) < 0 ||
|
|
|
|
write_pair(fd, key, value, &store) < 0)
|
2007-01-11 21:16:26 +00:00
|
|
|
goto write_err_out;
|
|
|
|
} else {
|
2006-01-05 11:43:34 +00:00
|
|
|
struct stat st;
|
2015-05-28 07:54:43 +00:00
|
|
|
size_t copy_begin, copy_end;
|
2007-03-07 01:44:37 +00:00
|
|
|
int i, new_line = 0;
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
struct config_options opts;
|
2005-11-17 21:32:36 +00:00
|
|
|
|
2022-05-02 16:50:37 +00:00
|
|
|
if (!value_pattern)
|
2020-11-25 22:12:50 +00:00
|
|
|
store.value_pattern = NULL;
|
|
|
|
else if (value_pattern == CONFIG_REGEX_NONE)
|
|
|
|
store.value_pattern = CONFIG_REGEX_NONE;
|
2020-11-25 22:12:54 +00:00
|
|
|
else if (flags & CONFIG_FLAGS_FIXED_VALUE)
|
|
|
|
store.fixed_value = value_pattern;
|
2005-11-17 21:32:36 +00:00
|
|
|
else {
|
2020-11-25 22:12:50 +00:00
|
|
|
if (value_pattern[0] == '!') {
|
2005-11-20 12:24:18 +00:00
|
|
|
store.do_not_match = 1;
|
2020-11-25 22:12:50 +00:00
|
|
|
value_pattern++;
|
2005-11-20 12:24:18 +00:00
|
|
|
} else
|
|
|
|
store.do_not_match = 0;
|
|
|
|
|
2020-11-25 22:12:50 +00:00
|
|
|
store.value_pattern = (regex_t*)xmalloc(sizeof(regex_t));
|
|
|
|
if (regcomp(store.value_pattern, value_pattern,
|
2005-11-17 21:32:36 +00:00
|
|
|
REG_EXTENDED)) {
|
2020-11-25 22:12:50 +00:00
|
|
|
error(_("invalid pattern: %s"), value_pattern);
|
|
|
|
FREE_AND_NULL(store.value_pattern);
|
2011-05-17 15:38:52 +00:00
|
|
|
ret = CONFIG_INVALID_PATTERN;
|
2006-04-17 15:14:48 +00:00
|
|
|
goto out_free;
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
ALLOC_GROW(store.parsed, 1, store.parsed_alloc);
|
|
|
|
store.parsed[0].end = 0;
|
|
|
|
|
|
|
|
memset(&opts, 0, sizeof(opts));
|
|
|
|
opts.event_fn = store_aux_event;
|
|
|
|
opts.event_fn_data = &store;
|
2005-11-17 21:32:36 +00:00
|
|
|
|
|
|
|
/*
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
* After this, store.parsed will contain offsets of all the
|
|
|
|
* parsed elements, and store.seen will contain a list of
|
|
|
|
* matches, as indices into store.parsed.
|
|
|
|
*
|
2005-11-17 21:32:36 +00:00
|
|
|
* As a side effect, we make sure to transform only a valid
|
|
|
|
* existing config file.
|
|
|
|
*/
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
if (git_config_from_file_with_options(store_aux,
|
|
|
|
config_filename,
|
|
|
|
&store, &opts)) {
|
2018-07-21 07:49:27 +00:00
|
|
|
error(_("invalid config file %s"), config_filename);
|
2011-05-17 15:38:52 +00:00
|
|
|
ret = CONFIG_INVALID_FILE;
|
2006-04-17 15:14:48 +00:00
|
|
|
goto out_free;
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
|
|
|
|
2005-11-20 05:52:22 +00:00
|
|
|
/* if nothing to unset, or too many matches, error out */
|
2018-04-09 08:32:13 +00:00
|
|
|
if ((store.seen_nr == 0 && value == NULL) ||
|
2020-11-25 22:12:49 +00:00
|
|
|
(store.seen_nr > 1 && !store.multi_replace)) {
|
2011-05-17 15:38:52 +00:00
|
|
|
ret = CONFIG_NOTHING_SET;
|
2006-04-17 15:14:48 +00:00
|
|
|
goto out_free;
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
|
|
|
|
2016-12-19 09:21:55 +00:00
|
|
|
if (fstat(in_fd, &st) == -1) {
|
|
|
|
error_errno(_("fstat on %s failed"), config_filename);
|
|
|
|
ret = CONFIG_INVALID_FILE;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
2007-03-07 01:44:37 +00:00
|
|
|
contents_sz = xsize_t(st.st_size);
|
2015-05-28 07:56:15 +00:00
|
|
|
contents = xmmap_gently(NULL, contents_sz, PROT_READ,
|
|
|
|
MAP_PRIVATE, in_fd, 0);
|
|
|
|
if (contents == MAP_FAILED) {
|
2015-05-28 08:03:01 +00:00
|
|
|
if (errno == ENODEV && S_ISDIR(st.st_mode))
|
|
|
|
errno = EISDIR;
|
2021-06-30 00:01:32 +00:00
|
|
|
error_errno(_("unable to mmap '%s'%s"),
|
|
|
|
config_filename, mmap_os_err());
|
2015-05-28 07:56:15 +00:00
|
|
|
ret = CONFIG_INVALID_FILE;
|
|
|
|
contents = NULL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
2005-11-17 21:32:36 +00:00
|
|
|
close(in_fd);
|
2015-08-14 20:21:17 +00:00
|
|
|
in_fd = -1;
|
2005-11-17 21:32:36 +00:00
|
|
|
|
2017-09-05 12:15:21 +00:00
|
|
|
if (chmod(get_lock_file_path(&lock), st.st_mode & 07777) < 0) {
|
2018-07-21 07:49:27 +00:00
|
|
|
error_errno(_("chmod on %s failed"), get_lock_file_path(&lock));
|
2014-05-06 00:17:14 +00:00
|
|
|
ret = CONFIG_NO_WRITE;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
if (store.seen_nr == 0) {
|
|
|
|
if (!store.seen_alloc) {
|
|
|
|
/* Did not see key nor section */
|
|
|
|
ALLOC_GROW(store.seen, 1, store.seen_alloc);
|
|
|
|
store.seen[0] = store.parsed_nr
|
|
|
|
- !!store.parsed_nr;
|
|
|
|
}
|
2018-04-09 08:32:13 +00:00
|
|
|
store.seen_nr = 1;
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
}
|
2005-11-20 05:52:22 +00:00
|
|
|
|
2018-04-09 08:32:13 +00:00
|
|
|
for (i = 0, copy_begin = 0; i < store.seen_nr; i++) {
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
size_t replace_end;
|
|
|
|
int j = store.seen[i];
|
|
|
|
|
2018-04-03 16:28:14 +00:00
|
|
|
new_line = 0;
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
if (!store.key_seen) {
|
2018-04-09 08:32:29 +00:00
|
|
|
copy_end = store.parsed[j].end;
|
|
|
|
/* include '\n' when copying section header */
|
|
|
|
if (copy_end > 0 && copy_end < contents_sz &&
|
|
|
|
contents[copy_end - 1] != '\n' &&
|
|
|
|
contents[copy_end] == '\n')
|
|
|
|
copy_end++;
|
|
|
|
replace_end = copy_end;
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
} else {
|
|
|
|
replace_end = store.parsed[j].end;
|
|
|
|
copy_end = store.parsed[j].begin;
|
git config --unset: remove empty sections (in the common case)
The original reasoning for not removing section headers upon removal of
the last entry went like this: the user could have added comments about
the section, or about the entries therein, and if there were other
comments there, we would not know whether we should remove them.
In particular, a concocted example was presented that looked like this
(and was added to t1300):
# some generic comment on the configuration file itself
# a comment specific to this "section" section.
[section]
# some intervening lines
# that should also be dropped
key = value
# please be careful when you update the above variable
The ideal thing for `git config --unset section.key` in this case would
be to leave only the first line behind, because all the other comments
are now obsolete.
However, this is unfeasible, short of adding a complete Natural Language
Processing module to Git, which seems not only a lot of work, but a
totally unreasonable feature (for little benefit to most users).
Now, the real kicker about this problem is: most users do not edit their
config files at all! In their use case, the config looks like this
instead:
[section]
key = value
... and it is totally obvious what should happen if the entry is
removed: the entire section should vanish.
Let's generalize this observation to this conservative strategy: if we
are removing the last entry from a section, and there are no comments
inside that section nor surrounding it, then remove the entire section.
Otherwise behave as before: leave the now-empty section (including those
comments, even ones about the now-deleted entry).
We have to be extra careful to handle the case where more than one entry
is removed: any subset of them might be the last entries of their
respective sections (and if there are no comments in or around that
section, the section should be removed, too).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:24 +00:00
|
|
|
if (!value)
|
2019-01-24 13:12:32 +00:00
|
|
|
maybe_remove_section(&store,
|
git config --unset: remove empty sections (in the common case)
The original reasoning for not removing section headers upon removal of
the last entry went like this: the user could have added comments about
the section, or about the entries therein, and if there were other
comments there, we would not know whether we should remove them.
In particular, a concocted example was presented that looked like this
(and was added to t1300):
# some generic comment on the configuration file itself
# a comment specific to this "section" section.
[section]
# some intervening lines
# that should also be dropped
key = value
# please be careful when you update the above variable
The ideal thing for `git config --unset section.key` in this case would
be to leave only the first line behind, because all the other comments
are now obsolete.
However, this is unfeasible, short of adding a complete Natural Language
Processing module to Git, which seems not only a lot of work, but a
totally unreasonable feature (for little benefit to most users).
Now, the real kicker about this problem is: most users do not edit their
config files at all! In their use case, the config looks like this
instead:
[section]
key = value
... and it is totally obvious what should happen if the entry is
removed: the entire section should vanish.
Let's generalize this observation to this conservative strategy: if we
are removing the last entry from a section, and there are no comments
inside that section nor surrounding it, then remove the entire section.
Otherwise behave as before: leave the now-empty section (including those
comments, even ones about the now-deleted entry).
We have to be extra careful to handle the case where more than one entry
is removed: any subset of them might be the last entries of their
respective sections (and if there are no comments in or around that
section, the section should be removed, too).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:24 +00:00
|
|
|
©_end,
|
|
|
|
&replace_end, &i);
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
/*
|
|
|
|
* Swallow preceding white-space on the same
|
|
|
|
* line.
|
|
|
|
*/
|
|
|
|
while (copy_end > 0 ) {
|
|
|
|
char c = contents[copy_end - 1];
|
|
|
|
|
|
|
|
if (isspace(c) && c != '\n')
|
|
|
|
copy_end--;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2005-11-20 05:52:22 +00:00
|
|
|
|
2008-01-01 06:17:34 +00:00
|
|
|
if (copy_end > 0 && contents[copy_end-1] != '\n')
|
|
|
|
new_line = 1;
|
|
|
|
|
2005-11-20 05:52:22 +00:00
|
|
|
/* write the first part of the config */
|
|
|
|
if (copy_end > copy_begin) {
|
2007-01-11 21:16:26 +00:00
|
|
|
if (write_in_full(fd, contents + copy_begin,
|
config: avoid "write_in_full(fd, buf, len) < len" pattern
The return type of write_in_full() is a signed ssize_t,
because we may return "-1" on failure (even if we succeeded
in writing some bytes). But "len" itself is may be an
unsigned type (the function takes a size_t, but of course we
may have something else in the calling function). So while
it seems like:
if (write_in_full(fd, buf, len) < len)
die_errno("write error");
would trigger on error, it won't if "len" is unsigned. The
compiler sees a signed/unsigned comparison and promotes the
signed value, resulting in (size_t)-1, the highest possible
size_t (or again, whatever type the caller has). This cannot
possibly be smaller than "len", and so the conditional can
never trigger.
I scoured the code base for cases of this, but it turns out
that these two in git_config_set_multivar_in_file_gently()
are the only ones. Here our "len" is the difference between
two size_t variables, making the result an unsigned size_t.
We can fix this by just checking for a negative return value
directly, as write_in_full() will never return any value
except -1 or the full count.
There's no addition to the test suite here, since you need
to convince write() to fail in order to see the problem. The
simplest reproduction recipe I came up with is to trigger
ENOSPC:
# make a limited-size filesystem
dd if=/dev/zero of=small.disk bs=1M count=1
mke2fs small.disk
mkdir mnt
sudo mount -o loop small.disk mnt
cd mnt
sudo chown $USER:$USER .
# make a config file with some content
git config --file=config one.key value
git config --file=config two.key value
# now fill up the disk
dd if=/dev/zero of=fill
# and try to delete a key, which requires copying the rest
# of the file to config.lock, and will fail on write()
git config --file=config --unset two.key
That final command should (and does after this patch)
produce an error message due to the failed write, and leave
the file intact. Instead, it silently ignores the failure
and renames config.lock into place, leaving you with a
totally empty config file!
Reported-by: demerphq <demerphq@gmail.com>
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-09-13 18:15:16 +00:00
|
|
|
copy_end - copy_begin) < 0)
|
2007-01-11 21:16:26 +00:00
|
|
|
goto write_err_out;
|
|
|
|
if (new_line &&
|
avoid "write_in_full(fd, buf, len) != len" pattern
The return value of write_in_full() is either "-1", or the
requested number of bytes[1]. If we make a partial write
before seeing an error, we still return -1, not a partial
value. This goes back to f6aa66cb95 (write_in_full: really
write in full or return error on disk full., 2007-01-11).
So checking anything except "was the return value negative"
is pointless. And there are a couple of reasons not to do
so:
1. It can do a funny signed/unsigned comparison. If your
"len" is signed (e.g., a size_t) then the compiler will
promote the "-1" to its unsigned variant.
This works out for "!= len" (unless you really were
trying to write the maximum size_t bytes), but is a
bug if you check "< len" (an example of which was fixed
recently in config.c).
We should avoid promoting the mental model that you
need to check the length at all, so that new sites are
not tempted to copy us.
2. Checking for a negative value is shorter to type,
especially when the length is an expression.
3. Linus says so. In d34cf19b89 (Clean up write_in_full()
users, 2007-01-11), right after the write_in_full()
semantics were changed, he wrote:
I really wish every "write_in_full()" user would just
check against "<0" now, but this fixes the nasty and
stupid ones.
Appeals to authority aside, this makes it clear that
writing it this way does not have an intentional
benefit. It's a historical curiosity that we never
bothered to clean up (and which was undoubtedly
cargo-culted into new sites).
So let's convert these obviously-correct cases (this
includes write_str_in_full(), which is just a wrapper for
write_in_full()).
[1] A careful reader may notice there is one way that
write_in_full() can return a different value. If we ask
write() to write N bytes and get a return value that is
_larger_ than N, we could return a larger total. But
besides the fact that this would imply a totally broken
version of write(), it would already invoke undefined
behavior. Our internal remaining counter is an unsigned
size_t, which means that subtracting too many byte will
wrap it around to a very large number. So we'll instantly
begin reading off the end of the buffer, trying to write
gigabytes (or petabytes) of data.
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-09-13 17:16:03 +00:00
|
|
|
write_str_in_full(fd, "\n") < 0)
|
2007-01-11 21:16:26 +00:00
|
|
|
goto write_err_out;
|
2005-11-20 05:52:22 +00:00
|
|
|
}
|
git_config_set: make use of the config parser's event stream
In the recent commit with the title "config: introduce an optional event
stream while parsing", we introduced an optional callback to keep track
of the config parser's events "comment", "white-space", "section header"
and "entry".
One motivation for this feature was to make use of it in the code that
edits the config. And this commit makes it so.
Note: this patch changes the meaning of the `seen` array that records
whether we saw the config entry that is to be edited: previously, it
contained the end offset of the found entry. Now, we introduce a new
array `parsed` that keeps a record of *all* config parser events (with
begin/end offsets), and the items in the `seen` array now point into the
`parsed` array.
There are two reasons why we do it this way:
1. To keep the implementation simple, the config parser's event stream
reports the event only after the config callback was called, so we
would not receive the begin offset otherwise.
2. In the following patches, we will re-use the `parsed` array to fix two
long-standing bugs related to empty sections.
Note that this also makes the code more robust with respect to finding the
begin offset of the part(s) of the config file to be edited, as we no
longer back-track to find the beginning of the line.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 08:32:20 +00:00
|
|
|
copy_begin = replace_end;
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* write the pair (value == NULL means unset) */
|
2022-05-02 16:50:37 +00:00
|
|
|
if (value) {
|
2018-04-09 08:32:17 +00:00
|
|
|
if (!store.section_seen) {
|
2018-04-09 08:32:09 +00:00
|
|
|
if (write_section(fd, key, &store) < 0)
|
2007-01-11 21:16:26 +00:00
|
|
|
goto write_err_out;
|
2007-01-08 15:58:38 +00:00
|
|
|
}
|
2018-04-09 08:32:09 +00:00
|
|
|
if (write_pair(fd, key, value, &store) < 0)
|
2007-01-11 21:16:26 +00:00
|
|
|
goto write_err_out;
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* write the rest of the config */
|
2007-03-07 01:44:37 +00:00
|
|
|
if (copy_begin < contents_sz)
|
2007-01-11 21:16:26 +00:00
|
|
|
if (write_in_full(fd, contents + copy_begin,
|
config: avoid "write_in_full(fd, buf, len) < len" pattern
The return type of write_in_full() is a signed ssize_t,
because we may return "-1" on failure (even if we succeeded
in writing some bytes). But "len" itself is may be an
unsigned type (the function takes a size_t, but of course we
may have something else in the calling function). So while
it seems like:
if (write_in_full(fd, buf, len) < len)
die_errno("write error");
would trigger on error, it won't if "len" is unsigned. The
compiler sees a signed/unsigned comparison and promotes the
signed value, resulting in (size_t)-1, the highest possible
size_t (or again, whatever type the caller has). This cannot
possibly be smaller than "len", and so the conditional can
never trigger.
I scoured the code base for cases of this, but it turns out
that these two in git_config_set_multivar_in_file_gently()
are the only ones. Here our "len" is the difference between
two size_t variables, making the result an unsigned size_t.
We can fix this by just checking for a negative return value
directly, as write_in_full() will never return any value
except -1 or the full count.
There's no addition to the test suite here, since you need
to convince write() to fail in order to see the problem. The
simplest reproduction recipe I came up with is to trigger
ENOSPC:
# make a limited-size filesystem
dd if=/dev/zero of=small.disk bs=1M count=1
mke2fs small.disk
mkdir mnt
sudo mount -o loop small.disk mnt
cd mnt
sudo chown $USER:$USER .
# make a config file with some content
git config --file=config one.key value
git config --file=config two.key value
# now fill up the disk
dd if=/dev/zero of=fill
# and try to delete a key, which requires copying the rest
# of the file to config.lock, and will fail on write()
git config --file=config --unset two.key
That final command should (and does after this patch)
produce an error message due to the failed write, and leave
the file intact. Instead, it silently ignores the failure
and renames config.lock into place, leaving you with a
totally empty config file!
Reported-by: demerphq <demerphq@gmail.com>
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-09-13 18:15:16 +00:00
|
|
|
contents_sz - copy_begin) < 0)
|
2007-01-11 21:16:26 +00:00
|
|
|
goto write_err_out;
|
2015-06-30 14:34:13 +00:00
|
|
|
|
|
|
|
munmap(contents, contents_sz);
|
|
|
|
contents = NULL;
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
|
|
|
|
2017-09-05 12:15:21 +00:00
|
|
|
if (commit_lock_file(&lock) < 0) {
|
2018-07-21 07:49:27 +00:00
|
|
|
error_errno(_("could not write config file %s"), config_filename);
|
2011-05-17 15:38:52 +00:00
|
|
|
ret = CONFIG_NO_WRITE;
|
2006-04-17 15:14:48 +00:00
|
|
|
goto out_free;
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
|
|
|
|
2006-04-17 15:14:48 +00:00
|
|
|
ret = 0;
|
|
|
|
|
2014-07-28 10:10:38 +00:00
|
|
|
/* Invalidate the config cache */
|
|
|
|
git_config_clear();
|
|
|
|
|
2006-04-17 15:14:48 +00:00
|
|
|
out_free:
|
2017-09-05 12:15:21 +00:00
|
|
|
rollback_lock_file(&lock);
|
2012-02-16 08:04:05 +00:00
|
|
|
free(filename_buf);
|
2015-05-28 07:54:43 +00:00
|
|
|
if (contents)
|
|
|
|
munmap(contents, contents_sz);
|
2015-08-14 20:21:17 +00:00
|
|
|
if (in_fd >= 0)
|
|
|
|
close(in_fd);
|
2018-05-20 10:42:33 +00:00
|
|
|
config_store_data_clear(&store);
|
2006-04-17 15:14:48 +00:00
|
|
|
return ret;
|
2007-01-11 21:16:26 +00:00
|
|
|
|
|
|
|
write_err_out:
|
2017-09-05 12:15:21 +00:00
|
|
|
ret = write_error(get_lock_file_path(&lock));
|
2007-01-11 21:16:26 +00:00
|
|
|
goto out_free;
|
|
|
|
|
2005-11-17 21:32:36 +00:00
|
|
|
}
|
|
|
|
|
2016-02-22 11:23:36 +00:00
|
|
|
void git_config_set_multivar_in_file(const char *config_filename,
|
|
|
|
const char *key, const char *value,
|
2020-11-25 22:12:50 +00:00
|
|
|
const char *value_pattern, unsigned flags)
|
2016-02-16 12:56:28 +00:00
|
|
|
{
|
2016-04-09 17:43:54 +00:00
|
|
|
if (!git_config_set_multivar_in_file_gently(config_filename, key, value,
|
2020-11-25 22:12:50 +00:00
|
|
|
value_pattern, flags))
|
2016-04-09 17:43:54 +00:00
|
|
|
return;
|
|
|
|
if (value)
|
2016-04-09 17:42:31 +00:00
|
|
|
die(_("could not set '%s' to '%s'"), key, value);
|
2016-04-09 17:43:54 +00:00
|
|
|
else
|
|
|
|
die(_("could not unset '%s'"), key);
|
2016-02-16 12:56:28 +00:00
|
|
|
}
|
|
|
|
|
2016-02-22 11:23:35 +00:00
|
|
|
int git_config_set_multivar_gently(const char *key, const char *value,
|
2020-11-25 22:12:50 +00:00
|
|
|
const char *value_pattern, unsigned flags)
|
2011-08-04 10:39:00 +00:00
|
|
|
{
|
2022-02-07 21:33:00 +00:00
|
|
|
return repo_config_set_multivar_gently(the_repository, key, value,
|
|
|
|
value_pattern, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
int repo_config_set_multivar_gently(struct repository *r, const char *key,
|
|
|
|
const char *value,
|
|
|
|
const char *value_pattern, unsigned flags)
|
|
|
|
{
|
|
|
|
char *file = repo_git_path(r, "config");
|
|
|
|
int res = git_config_set_multivar_in_file_gently(file,
|
|
|
|
key, value,
|
|
|
|
value_pattern,
|
|
|
|
flags);
|
|
|
|
free(file);
|
|
|
|
return res;
|
2011-08-04 10:39:00 +00:00
|
|
|
}
|
|
|
|
|
2016-02-22 11:23:36 +00:00
|
|
|
void git_config_set_multivar(const char *key, const char *value,
|
2020-11-25 22:12:50 +00:00
|
|
|
const char *value_pattern, unsigned flags)
|
2011-08-04 10:39:00 +00:00
|
|
|
{
|
2022-02-07 21:33:00 +00:00
|
|
|
git_config_set_multivar_in_file(git_path("config"),
|
|
|
|
key, value, value_pattern,
|
2020-11-25 22:12:49 +00:00
|
|
|
flags);
|
2011-08-04 10:39:00 +00:00
|
|
|
}
|
|
|
|
|
2007-03-02 20:53:33 +00:00
|
|
|
static int section_name_match (const char *buf, const char *name)
|
|
|
|
{
|
|
|
|
int i = 0, j = 0, dot = 0;
|
2009-07-24 21:21:43 +00:00
|
|
|
if (buf[i] != '[')
|
|
|
|
return 0;
|
|
|
|
for (i = 1; buf[i] && buf[i] != ']'; i++) {
|
2007-03-02 20:53:33 +00:00
|
|
|
if (!dot && isspace(buf[i])) {
|
|
|
|
dot = 1;
|
|
|
|
if (name[j++] != '.')
|
|
|
|
break;
|
|
|
|
for (i++; isspace(buf[i]); i++)
|
|
|
|
; /* do nothing */
|
|
|
|
if (buf[i] != '"')
|
|
|
|
break;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (buf[i] == '\\' && dot)
|
|
|
|
i++;
|
|
|
|
else if (buf[i] == '"' && dot) {
|
|
|
|
for (i++; isspace(buf[i]); i++)
|
|
|
|
; /* do_nothing */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (buf[i] != name[j++])
|
|
|
|
break;
|
|
|
|
}
|
2009-07-24 21:21:43 +00:00
|
|
|
if (buf[i] == ']' && name[j] == 0) {
|
|
|
|
/*
|
|
|
|
* We match, now just find the right length offset by
|
|
|
|
* gobbling up any whitespace after it, as well
|
|
|
|
*/
|
|
|
|
i++;
|
|
|
|
for (; buf[i] && isspace(buf[i]); i++)
|
|
|
|
; /* do nothing */
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return 0;
|
2007-03-02 20:53:33 +00:00
|
|
|
}
|
|
|
|
|
2012-04-26 01:47:14 +00:00
|
|
|
static int section_name_is_ok(const char *name)
|
|
|
|
{
|
|
|
|
/* Empty section names are bogus. */
|
|
|
|
if (!*name)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Before a dot, we must be alphanumeric or dash. After the first dot,
|
|
|
|
* anything goes, so we can stop checking.
|
|
|
|
*/
|
|
|
|
for (; *name && *name != '.'; name++)
|
|
|
|
if (*name != '-' && !isalnum(*name))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-03-02 20:53:33 +00:00
|
|
|
/* if new_name == NULL, the section is removed instead */
|
branch: add a --copy (-c) option to go with --move (-m)
Add the ability to --copy a branch and its reflog and configuration,
this uses the same underlying machinery as the --move (-m) option
except the reflog and configuration is copied instead of being moved.
This is useful for e.g. copying a topic branch to a new version,
e.g. work to work-2 after submitting the work topic to the list, while
preserving all the tracking info and other configuration that goes
with the branch, and unlike --move keeping the other already-submitted
branch around for reference.
Like --move, when the source branch is the currently checked out
branch the HEAD is moved to the destination branch. In the case of
--move we don't really have a choice (other than remaining on a
detached HEAD) and in order to keep the functionality consistent, we
are doing it in similar way for --copy too.
The most common usage of this feature is expected to be moving to a
new topic branch which is a copy of the current one, in that case
moving to the target branch is what the user wants, and doesn't
unexpectedly behave differently than --move would.
One outstanding caveat of this implementation is that:
git checkout maint &&
git checkout master &&
git branch -c topic &&
git checkout -
Will check out 'maint' instead of 'master'. This is because the @{-N}
feature (or its -1 shorthand "-") relies on HEAD reflogs created by
the checkout command, so in this case we'll checkout maint instead of
master, as the user might expect. What to do about that is left to a
future change.
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Sahil Dua <sahildua2305@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-18 21:19:16 +00:00
|
|
|
static int git_config_copy_or_rename_section_in_file(const char *config_filename,
|
2018-04-09 08:32:09 +00:00
|
|
|
const char *old_name,
|
|
|
|
const char *new_name, int copy)
|
2006-12-16 14:14:14 +00:00
|
|
|
{
|
2007-03-02 20:53:33 +00:00
|
|
|
int ret = 0, remove = 0;
|
2012-02-16 08:04:25 +00:00
|
|
|
char *filename_buf = NULL;
|
2017-10-05 20:32:04 +00:00
|
|
|
struct lock_file lock = LOCK_INIT;
|
2006-12-16 14:14:14 +00:00
|
|
|
int out_fd;
|
|
|
|
char buf[1024];
|
2017-05-04 13:55:41 +00:00
|
|
|
FILE *config_file = NULL;
|
2014-05-06 00:17:14 +00:00
|
|
|
struct stat st;
|
branch: add a --copy (-c) option to go with --move (-m)
Add the ability to --copy a branch and its reflog and configuration,
this uses the same underlying machinery as the --move (-m) option
except the reflog and configuration is copied instead of being moved.
This is useful for e.g. copying a topic branch to a new version,
e.g. work to work-2 after submitting the work topic to the list, while
preserving all the tracking info and other configuration that goes
with the branch, and unlike --move keeping the other already-submitted
branch around for reference.
Like --move, when the source branch is the currently checked out
branch the HEAD is moved to the destination branch. In the case of
--move we don't really have a choice (other than remaining on a
detached HEAD) and in order to keep the functionality consistent, we
are doing it in similar way for --copy too.
The most common usage of this feature is expected to be moving to a
new topic branch which is a copy of the current one, in that case
moving to the target branch is what the user wants, and doesn't
unexpectedly behave differently than --move would.
One outstanding caveat of this implementation is that:
git checkout maint &&
git checkout master &&
git branch -c topic &&
git checkout -
Will check out 'maint' instead of 'master'. This is because the @{-N}
feature (or its -1 shorthand "-") relies on HEAD reflogs created by
the checkout command, so in this case we'll checkout maint instead of
master, as the user might expect. What to do about that is left to a
future change.
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Sahil Dua <sahildua2305@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-18 21:19:16 +00:00
|
|
|
struct strbuf copystr = STRBUF_INIT;
|
2018-04-09 08:32:09 +00:00
|
|
|
struct config_store_data store;
|
|
|
|
|
|
|
|
memset(&store, 0, sizeof(store));
|
2006-12-16 14:14:14 +00:00
|
|
|
|
2012-04-26 01:47:14 +00:00
|
|
|
if (new_name && !section_name_is_ok(new_name)) {
|
2018-07-21 07:49:27 +00:00
|
|
|
ret = error(_("invalid section name: %s"), new_name);
|
2016-12-20 09:48:36 +00:00
|
|
|
goto out_no_rollback;
|
2012-04-26 01:47:14 +00:00
|
|
|
}
|
|
|
|
|
2012-02-16 08:04:25 +00:00
|
|
|
if (!config_filename)
|
|
|
|
config_filename = filename_buf = git_pathdup("config");
|
|
|
|
|
2017-10-05 20:32:04 +00:00
|
|
|
out_fd = hold_lock_file_for_update(&lock, config_filename, 0);
|
2006-12-20 05:55:27 +00:00
|
|
|
if (out_fd < 0) {
|
2018-07-21 07:49:27 +00:00
|
|
|
ret = error(_("could not lock config file %s"), config_filename);
|
2006-12-20 05:55:27 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2006-12-16 14:14:14 +00:00
|
|
|
|
2006-12-20 05:55:27 +00:00
|
|
|
if (!(config_file = fopen(config_filename, "rb"))) {
|
2017-05-03 10:16:49 +00:00
|
|
|
ret = warn_on_fopen_errors(config_filename);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
2007-04-05 14:20:55 +00:00
|
|
|
/* no config file means nothing to rename, no error */
|
2016-12-20 09:48:35 +00:00
|
|
|
goto commit_and_out;
|
2006-12-20 05:55:27 +00:00
|
|
|
}
|
2006-12-16 14:14:14 +00:00
|
|
|
|
2016-12-19 09:21:55 +00:00
|
|
|
if (fstat(fileno(config_file), &st) == -1) {
|
|
|
|
ret = error_errno(_("fstat on %s failed"), config_filename);
|
|
|
|
goto out;
|
|
|
|
}
|
2014-05-06 00:17:14 +00:00
|
|
|
|
2017-10-05 20:32:04 +00:00
|
|
|
if (chmod(get_lock_file_path(&lock), st.st_mode & 07777) < 0) {
|
2018-07-21 07:49:27 +00:00
|
|
|
ret = error_errno(_("chmod on %s failed"),
|
2017-10-05 20:32:04 +00:00
|
|
|
get_lock_file_path(&lock));
|
2014-05-06 00:17:14 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2006-12-16 14:14:14 +00:00
|
|
|
while (fgets(buf, sizeof(buf), config_file)) {
|
config: work around gcc-10 -Wstringop-overflow warning
Compiling with gcc-10, -O2, and -fsanitize=undefined results in a
compiler warning:
config.c: In function ‘git_config_copy_or_rename_section_in_file’:
config.c:3170:17: error: writing 1 byte into a region of size 0 [-Werror=stringop-overflow=]
3170 | output[0] = '\t';
| ~~~~~~~~~~^~~~~~
config.c:3076:7: note: at offset -1 to object ‘buf’ with size 1024 declared here
3076 | char buf[1024];
| ^~~
This is a false positive. The interesting lines of code are:
int i;
char *output = buf;
...
for (i = 0; buf[i] && isspace(buf[i]); i++)
; /* do nothing */
...
int offset;
offset = section_name_match(&buf[i], old_name);
if (offset > 0) {
...
output += offset + i;
if (strlen(output) > 0) {
/*
* More content means there's
* a declaration to put on the
* next line; indent with a
* tab
*/
output -= 1;
output[0] = '\t';
}
}
So we do assign output to buf initially. Later we increment it based on
"offset" and "i" and then subtract "1" from it. That latter step is what
the compiler is complaining about; it could lead to going off the left
side of the array if "output == buf" at the moment of the subtraction.
For that to be the case, then "offset + i" would have to be 0. But that
can't happen:
- we know that "offset" is at least 1, since we're in a conditional
block that checks that
- we know that "i" is not negative, since it started at 0 and only
incremented over whitespace
So the sum must be at least 1, and therefore it's OK to subtract one
from "output".
But that's not quite the whole story. Since "i" is an int, it could in
theory be possible to overflow to negative (when counting whitespace on
a very large string). But we know that's impossible because we're
counting the 1024-byte buffer we just fed to fgets(), so it can never be
larger than that.
Switching the type of "i" to "unsigned" makes the warning go away, so
let's do that.
Arguably size_t is an even better type (for this and for the other
length fields), but switching to it produces a similar but distinct
warning:
config.c: In function ‘git_config_copy_or_rename_section_in_file’:
config.c:3170:13: error: array subscript -1 is outside array bounds of ‘char[1024]’ [-Werror=array-bounds]
3170 | output[0] = '\t';
| ~~~~~~^~~
config.c:3076:7: note: while referencing ‘buf’
3076 | char buf[1024];
| ^~~
If we were to ever switch off of fgets() to strbuf_getline() or similar,
we'd probably need to use size_t to avoid other overflow problems. But
for now we know we're safe because of the small fixed size of our
buffer.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-08-04 07:43:53 +00:00
|
|
|
unsigned i;
|
2007-01-08 15:58:38 +00:00
|
|
|
int length;
|
branch: add a --copy (-c) option to go with --move (-m)
Add the ability to --copy a branch and its reflog and configuration,
this uses the same underlying machinery as the --move (-m) option
except the reflog and configuration is copied instead of being moved.
This is useful for e.g. copying a topic branch to a new version,
e.g. work to work-2 after submitting the work topic to the list, while
preserving all the tracking info and other configuration that goes
with the branch, and unlike --move keeping the other already-submitted
branch around for reference.
Like --move, when the source branch is the currently checked out
branch the HEAD is moved to the destination branch. In the case of
--move we don't really have a choice (other than remaining on a
detached HEAD) and in order to keep the functionality consistent, we
are doing it in similar way for --copy too.
The most common usage of this feature is expected to be moving to a
new topic branch which is a copy of the current one, in that case
moving to the target branch is what the user wants, and doesn't
unexpectedly behave differently than --move would.
One outstanding caveat of this implementation is that:
git checkout maint &&
git checkout master &&
git branch -c topic &&
git checkout -
Will check out 'maint' instead of 'master'. This is because the @{-N}
feature (or its -1 shorthand "-") relies on HEAD reflogs created by
the checkout command, so in this case we'll checkout maint instead of
master, as the user might expect. What to do about that is left to a
future change.
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Sahil Dua <sahildua2305@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-18 21:19:16 +00:00
|
|
|
int is_section = 0;
|
2009-07-24 21:21:44 +00:00
|
|
|
char *output = buf;
|
2006-12-16 14:14:14 +00:00
|
|
|
for (i = 0; buf[i] && isspace(buf[i]); i++)
|
|
|
|
; /* do nothing */
|
|
|
|
if (buf[i] == '[') {
|
|
|
|
/* it's a section */
|
branch: add a --copy (-c) option to go with --move (-m)
Add the ability to --copy a branch and its reflog and configuration,
this uses the same underlying machinery as the --move (-m) option
except the reflog and configuration is copied instead of being moved.
This is useful for e.g. copying a topic branch to a new version,
e.g. work to work-2 after submitting the work topic to the list, while
preserving all the tracking info and other configuration that goes
with the branch, and unlike --move keeping the other already-submitted
branch around for reference.
Like --move, when the source branch is the currently checked out
branch the HEAD is moved to the destination branch. In the case of
--move we don't really have a choice (other than remaining on a
detached HEAD) and in order to keep the functionality consistent, we
are doing it in similar way for --copy too.
The most common usage of this feature is expected to be moving to a
new topic branch which is a copy of the current one, in that case
moving to the target branch is what the user wants, and doesn't
unexpectedly behave differently than --move would.
One outstanding caveat of this implementation is that:
git checkout maint &&
git checkout master &&
git branch -c topic &&
git checkout -
Will check out 'maint' instead of 'master'. This is because the @{-N}
feature (or its -1 shorthand "-") relies on HEAD reflogs created by
the checkout command, so in this case we'll checkout maint instead of
master, as the user might expect. What to do about that is left to a
future change.
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Sahil Dua <sahildua2305@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-18 21:19:16 +00:00
|
|
|
int offset;
|
|
|
|
is_section = 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When encountering a new section under -c we
|
|
|
|
* need to flush out any section we're already
|
|
|
|
* coping and begin anew. There might be
|
|
|
|
* multiple [branch "$name"] sections.
|
|
|
|
*/
|
|
|
|
if (copystr.len > 0) {
|
2017-11-15 12:40:43 +00:00
|
|
|
if (write_in_full(out_fd, copystr.buf, copystr.len) < 0) {
|
2017-11-06 04:11:21 +00:00
|
|
|
ret = write_error(get_lock_file_path(&lock));
|
branch: add a --copy (-c) option to go with --move (-m)
Add the ability to --copy a branch and its reflog and configuration,
this uses the same underlying machinery as the --move (-m) option
except the reflog and configuration is copied instead of being moved.
This is useful for e.g. copying a topic branch to a new version,
e.g. work to work-2 after submitting the work topic to the list, while
preserving all the tracking info and other configuration that goes
with the branch, and unlike --move keeping the other already-submitted
branch around for reference.
Like --move, when the source branch is the currently checked out
branch the HEAD is moved to the destination branch. In the case of
--move we don't really have a choice (other than remaining on a
detached HEAD) and in order to keep the functionality consistent, we
are doing it in similar way for --copy too.
The most common usage of this feature is expected to be moving to a
new topic branch which is a copy of the current one, in that case
moving to the target branch is what the user wants, and doesn't
unexpectedly behave differently than --move would.
One outstanding caveat of this implementation is that:
git checkout maint &&
git checkout master &&
git branch -c topic &&
git checkout -
Will check out 'maint' instead of 'master'. This is because the @{-N}
feature (or its -1 shorthand "-") relies on HEAD reflogs created by
the checkout command, so in this case we'll checkout maint instead of
master, as the user might expect. What to do about that is left to a
future change.
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Sahil Dua <sahildua2305@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-18 21:19:16 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
strbuf_reset(©str);
|
|
|
|
}
|
|
|
|
|
|
|
|
offset = section_name_match(&buf[i], old_name);
|
2009-07-24 21:21:43 +00:00
|
|
|
if (offset > 0) {
|
2007-03-02 20:53:33 +00:00
|
|
|
ret++;
|
2022-05-02 16:50:37 +00:00
|
|
|
if (!new_name) {
|
2007-03-02 20:53:33 +00:00
|
|
|
remove = 1;
|
2006-12-16 14:14:14 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
store.baselen = strlen(new_name);
|
branch: add a --copy (-c) option to go with --move (-m)
Add the ability to --copy a branch and its reflog and configuration,
this uses the same underlying machinery as the --move (-m) option
except the reflog and configuration is copied instead of being moved.
This is useful for e.g. copying a topic branch to a new version,
e.g. work to work-2 after submitting the work topic to the list, while
preserving all the tracking info and other configuration that goes
with the branch, and unlike --move keeping the other already-submitted
branch around for reference.
Like --move, when the source branch is the currently checked out
branch the HEAD is moved to the destination branch. In the case of
--move we don't really have a choice (other than remaining on a
detached HEAD) and in order to keep the functionality consistent, we
are doing it in similar way for --copy too.
The most common usage of this feature is expected to be moving to a
new topic branch which is a copy of the current one, in that case
moving to the target branch is what the user wants, and doesn't
unexpectedly behave differently than --move would.
One outstanding caveat of this implementation is that:
git checkout maint &&
git checkout master &&
git branch -c topic &&
git checkout -
Will check out 'maint' instead of 'master'. This is because the @{-N}
feature (or its -1 shorthand "-") relies on HEAD reflogs created by
the checkout command, so in this case we'll checkout maint instead of
master, as the user might expect. What to do about that is left to a
future change.
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Sahil Dua <sahildua2305@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-18 21:19:16 +00:00
|
|
|
if (!copy) {
|
2018-04-09 08:32:09 +00:00
|
|
|
if (write_section(out_fd, new_name, &store) < 0) {
|
2017-11-06 04:11:21 +00:00
|
|
|
ret = write_error(get_lock_file_path(&lock));
|
branch: add a --copy (-c) option to go with --move (-m)
Add the ability to --copy a branch and its reflog and configuration,
this uses the same underlying machinery as the --move (-m) option
except the reflog and configuration is copied instead of being moved.
This is useful for e.g. copying a topic branch to a new version,
e.g. work to work-2 after submitting the work topic to the list, while
preserving all the tracking info and other configuration that goes
with the branch, and unlike --move keeping the other already-submitted
branch around for reference.
Like --move, when the source branch is the currently checked out
branch the HEAD is moved to the destination branch. In the case of
--move we don't really have a choice (other than remaining on a
detached HEAD) and in order to keep the functionality consistent, we
are doing it in similar way for --copy too.
The most common usage of this feature is expected to be moving to a
new topic branch which is a copy of the current one, in that case
moving to the target branch is what the user wants, and doesn't
unexpectedly behave differently than --move would.
One outstanding caveat of this implementation is that:
git checkout maint &&
git checkout master &&
git branch -c topic &&
git checkout -
Will check out 'maint' instead of 'master'. This is because the @{-N}
feature (or its -1 shorthand "-") relies on HEAD reflogs created by
the checkout command, so in this case we'll checkout maint instead of
master, as the user might expect. What to do about that is left to a
future change.
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Sahil Dua <sahildua2305@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-18 21:19:16 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2009-07-24 21:21:44 +00:00
|
|
|
/*
|
branch: add a --copy (-c) option to go with --move (-m)
Add the ability to --copy a branch and its reflog and configuration,
this uses the same underlying machinery as the --move (-m) option
except the reflog and configuration is copied instead of being moved.
This is useful for e.g. copying a topic branch to a new version,
e.g. work to work-2 after submitting the work topic to the list, while
preserving all the tracking info and other configuration that goes
with the branch, and unlike --move keeping the other already-submitted
branch around for reference.
Like --move, when the source branch is the currently checked out
branch the HEAD is moved to the destination branch. In the case of
--move we don't really have a choice (other than remaining on a
detached HEAD) and in order to keep the functionality consistent, we
are doing it in similar way for --copy too.
The most common usage of this feature is expected to be moving to a
new topic branch which is a copy of the current one, in that case
moving to the target branch is what the user wants, and doesn't
unexpectedly behave differently than --move would.
One outstanding caveat of this implementation is that:
git checkout maint &&
git checkout master &&
git branch -c topic &&
git checkout -
Will check out 'maint' instead of 'master'. This is because the @{-N}
feature (or its -1 shorthand "-") relies on HEAD reflogs created by
the checkout command, so in this case we'll checkout maint instead of
master, as the user might expect. What to do about that is left to a
future change.
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Sahil Dua <sahildua2305@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-18 21:19:16 +00:00
|
|
|
* We wrote out the new section, with
|
|
|
|
* a newline, now skip the old
|
|
|
|
* section's length
|
2009-07-24 21:21:44 +00:00
|
|
|
*/
|
branch: add a --copy (-c) option to go with --move (-m)
Add the ability to --copy a branch and its reflog and configuration,
this uses the same underlying machinery as the --move (-m) option
except the reflog and configuration is copied instead of being moved.
This is useful for e.g. copying a topic branch to a new version,
e.g. work to work-2 after submitting the work topic to the list, while
preserving all the tracking info and other configuration that goes
with the branch, and unlike --move keeping the other already-submitted
branch around for reference.
Like --move, when the source branch is the currently checked out
branch the HEAD is moved to the destination branch. In the case of
--move we don't really have a choice (other than remaining on a
detached HEAD) and in order to keep the functionality consistent, we
are doing it in similar way for --copy too.
The most common usage of this feature is expected to be moving to a
new topic branch which is a copy of the current one, in that case
moving to the target branch is what the user wants, and doesn't
unexpectedly behave differently than --move would.
One outstanding caveat of this implementation is that:
git checkout maint &&
git checkout master &&
git branch -c topic &&
git checkout -
Will check out 'maint' instead of 'master'. This is because the @{-N}
feature (or its -1 shorthand "-") relies on HEAD reflogs created by
the checkout command, so in this case we'll checkout maint instead of
master, as the user might expect. What to do about that is left to a
future change.
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Sahil Dua <sahildua2305@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-18 21:19:16 +00:00
|
|
|
output += offset + i;
|
|
|
|
if (strlen(output) > 0) {
|
|
|
|
/*
|
|
|
|
* More content means there's
|
|
|
|
* a declaration to put on the
|
|
|
|
* next line; indent with a
|
|
|
|
* tab
|
|
|
|
*/
|
|
|
|
output -= 1;
|
|
|
|
output[0] = '\t';
|
|
|
|
}
|
|
|
|
} else {
|
2018-04-09 08:32:09 +00:00
|
|
|
copystr = store_create_section(new_name, &store);
|
2009-07-24 21:21:44 +00:00
|
|
|
}
|
2006-12-16 14:14:14 +00:00
|
|
|
}
|
2007-03-02 20:53:33 +00:00
|
|
|
remove = 0;
|
2006-12-16 14:14:14 +00:00
|
|
|
}
|
2007-03-02 20:53:33 +00:00
|
|
|
if (remove)
|
|
|
|
continue;
|
2009-07-24 21:21:44 +00:00
|
|
|
length = strlen(output);
|
branch: add a --copy (-c) option to go with --move (-m)
Add the ability to --copy a branch and its reflog and configuration,
this uses the same underlying machinery as the --move (-m) option
except the reflog and configuration is copied instead of being moved.
This is useful for e.g. copying a topic branch to a new version,
e.g. work to work-2 after submitting the work topic to the list, while
preserving all the tracking info and other configuration that goes
with the branch, and unlike --move keeping the other already-submitted
branch around for reference.
Like --move, when the source branch is the currently checked out
branch the HEAD is moved to the destination branch. In the case of
--move we don't really have a choice (other than remaining on a
detached HEAD) and in order to keep the functionality consistent, we
are doing it in similar way for --copy too.
The most common usage of this feature is expected to be moving to a
new topic branch which is a copy of the current one, in that case
moving to the target branch is what the user wants, and doesn't
unexpectedly behave differently than --move would.
One outstanding caveat of this implementation is that:
git checkout maint &&
git checkout master &&
git branch -c topic &&
git checkout -
Will check out 'maint' instead of 'master'. This is because the @{-N}
feature (or its -1 shorthand "-") relies on HEAD reflogs created by
the checkout command, so in this case we'll checkout maint instead of
master, as the user might expect. What to do about that is left to a
future change.
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Sahil Dua <sahildua2305@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-18 21:19:16 +00:00
|
|
|
|
|
|
|
if (!is_section && copystr.len > 0) {
|
|
|
|
strbuf_add(©str, output, length);
|
|
|
|
}
|
|
|
|
|
avoid "write_in_full(fd, buf, len) != len" pattern
The return value of write_in_full() is either "-1", or the
requested number of bytes[1]. If we make a partial write
before seeing an error, we still return -1, not a partial
value. This goes back to f6aa66cb95 (write_in_full: really
write in full or return error on disk full., 2007-01-11).
So checking anything except "was the return value negative"
is pointless. And there are a couple of reasons not to do
so:
1. It can do a funny signed/unsigned comparison. If your
"len" is signed (e.g., a size_t) then the compiler will
promote the "-1" to its unsigned variant.
This works out for "!= len" (unless you really were
trying to write the maximum size_t bytes), but is a
bug if you check "< len" (an example of which was fixed
recently in config.c).
We should avoid promoting the mental model that you
need to check the length at all, so that new sites are
not tempted to copy us.
2. Checking for a negative value is shorter to type,
especially when the length is an expression.
3. Linus says so. In d34cf19b89 (Clean up write_in_full()
users, 2007-01-11), right after the write_in_full()
semantics were changed, he wrote:
I really wish every "write_in_full()" user would just
check against "<0" now, but this fixes the nasty and
stupid ones.
Appeals to authority aside, this makes it clear that
writing it this way does not have an intentional
benefit. It's a historical curiosity that we never
bothered to clean up (and which was undoubtedly
cargo-culted into new sites).
So let's convert these obviously-correct cases (this
includes write_str_in_full(), which is just a wrapper for
write_in_full()).
[1] A careful reader may notice there is one way that
write_in_full() can return a different value. If we ask
write() to write N bytes and get a return value that is
_larger_ than N, we could return a larger total. But
besides the fact that this would imply a totally broken
version of write(), it would already invoke undefined
behavior. Our internal remaining counter is an unsigned
size_t, which means that subtracting too many byte will
wrap it around to a very large number. So we'll instantly
begin reading off the end of the buffer, trying to write
gigabytes (or petabytes) of data.
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-09-13 17:16:03 +00:00
|
|
|
if (write_in_full(out_fd, output, length) < 0) {
|
2017-10-05 20:32:04 +00:00
|
|
|
ret = write_error(get_lock_file_path(&lock));
|
2007-01-08 15:58:38 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2006-12-16 14:14:14 +00:00
|
|
|
}
|
branch: add a --copy (-c) option to go with --move (-m)
Add the ability to --copy a branch and its reflog and configuration,
this uses the same underlying machinery as the --move (-m) option
except the reflog and configuration is copied instead of being moved.
This is useful for e.g. copying a topic branch to a new version,
e.g. work to work-2 after submitting the work topic to the list, while
preserving all the tracking info and other configuration that goes
with the branch, and unlike --move keeping the other already-submitted
branch around for reference.
Like --move, when the source branch is the currently checked out
branch the HEAD is moved to the destination branch. In the case of
--move we don't really have a choice (other than remaining on a
detached HEAD) and in order to keep the functionality consistent, we
are doing it in similar way for --copy too.
The most common usage of this feature is expected to be moving to a
new topic branch which is a copy of the current one, in that case
moving to the target branch is what the user wants, and doesn't
unexpectedly behave differently than --move would.
One outstanding caveat of this implementation is that:
git checkout maint &&
git checkout master &&
git branch -c topic &&
git checkout -
Will check out 'maint' instead of 'master'. This is because the @{-N}
feature (or its -1 shorthand "-") relies on HEAD reflogs created by
the checkout command, so in this case we'll checkout maint instead of
master, as the user might expect. What to do about that is left to a
future change.
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Sahil Dua <sahildua2305@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-18 21:19:16 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy a trailing section at the end of the config, won't be
|
|
|
|
* flushed by the usual "flush because we have a new section
|
|
|
|
* logic in the loop above.
|
|
|
|
*/
|
|
|
|
if (copystr.len > 0) {
|
2017-11-15 12:40:43 +00:00
|
|
|
if (write_in_full(out_fd, copystr.buf, copystr.len) < 0) {
|
2017-11-06 04:11:21 +00:00
|
|
|
ret = write_error(get_lock_file_path(&lock));
|
branch: add a --copy (-c) option to go with --move (-m)
Add the ability to --copy a branch and its reflog and configuration,
this uses the same underlying machinery as the --move (-m) option
except the reflog and configuration is copied instead of being moved.
This is useful for e.g. copying a topic branch to a new version,
e.g. work to work-2 after submitting the work topic to the list, while
preserving all the tracking info and other configuration that goes
with the branch, and unlike --move keeping the other already-submitted
branch around for reference.
Like --move, when the source branch is the currently checked out
branch the HEAD is moved to the destination branch. In the case of
--move we don't really have a choice (other than remaining on a
detached HEAD) and in order to keep the functionality consistent, we
are doing it in similar way for --copy too.
The most common usage of this feature is expected to be moving to a
new topic branch which is a copy of the current one, in that case
moving to the target branch is what the user wants, and doesn't
unexpectedly behave differently than --move would.
One outstanding caveat of this implementation is that:
git checkout maint &&
git checkout master &&
git branch -c topic &&
git checkout -
Will check out 'maint' instead of 'master'. This is because the @{-N}
feature (or its -1 shorthand "-") relies on HEAD reflogs created by
the checkout command, so in this case we'll checkout maint instead of
master, as the user might expect. What to do about that is left to a
future change.
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Sahil Dua <sahildua2305@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-18 21:19:16 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
strbuf_reset(©str);
|
|
|
|
}
|
|
|
|
|
2006-12-20 05:55:27 +00:00
|
|
|
fclose(config_file);
|
2017-05-04 13:55:41 +00:00
|
|
|
config_file = NULL;
|
2016-12-20 09:48:35 +00:00
|
|
|
commit_and_out:
|
2017-10-05 20:32:04 +00:00
|
|
|
if (commit_lock_file(&lock) < 0)
|
2018-07-21 07:49:27 +00:00
|
|
|
ret = error_errno(_("could not write config file %s"),
|
2016-05-08 09:47:38 +00:00
|
|
|
config_filename);
|
2011-07-16 21:55:52 +00:00
|
|
|
out:
|
2017-05-04 13:55:41 +00:00
|
|
|
if (config_file)
|
|
|
|
fclose(config_file);
|
2017-10-05 20:32:04 +00:00
|
|
|
rollback_lock_file(&lock);
|
2016-12-20 09:48:36 +00:00
|
|
|
out_no_rollback:
|
2012-02-16 08:04:25 +00:00
|
|
|
free(filename_buf);
|
2018-05-20 10:42:33 +00:00
|
|
|
config_store_data_clear(&store);
|
2006-12-16 14:14:14 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2008-02-11 18:41:18 +00:00
|
|
|
|
branch: add a --copy (-c) option to go with --move (-m)
Add the ability to --copy a branch and its reflog and configuration,
this uses the same underlying machinery as the --move (-m) option
except the reflog and configuration is copied instead of being moved.
This is useful for e.g. copying a topic branch to a new version,
e.g. work to work-2 after submitting the work topic to the list, while
preserving all the tracking info and other configuration that goes
with the branch, and unlike --move keeping the other already-submitted
branch around for reference.
Like --move, when the source branch is the currently checked out
branch the HEAD is moved to the destination branch. In the case of
--move we don't really have a choice (other than remaining on a
detached HEAD) and in order to keep the functionality consistent, we
are doing it in similar way for --copy too.
The most common usage of this feature is expected to be moving to a
new topic branch which is a copy of the current one, in that case
moving to the target branch is what the user wants, and doesn't
unexpectedly behave differently than --move would.
One outstanding caveat of this implementation is that:
git checkout maint &&
git checkout master &&
git branch -c topic &&
git checkout -
Will check out 'maint' instead of 'master'. This is because the @{-N}
feature (or its -1 shorthand "-") relies on HEAD reflogs created by
the checkout command, so in this case we'll checkout maint instead of
master, as the user might expect. What to do about that is left to a
future change.
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Sahil Dua <sahildua2305@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-18 21:19:16 +00:00
|
|
|
int git_config_rename_section_in_file(const char *config_filename,
|
|
|
|
const char *old_name, const char *new_name)
|
|
|
|
{
|
|
|
|
return git_config_copy_or_rename_section_in_file(config_filename,
|
|
|
|
old_name, new_name, 0);
|
|
|
|
}
|
|
|
|
|
2012-02-16 08:04:25 +00:00
|
|
|
int git_config_rename_section(const char *old_name, const char *new_name)
|
|
|
|
{
|
2012-02-16 08:09:32 +00:00
|
|
|
return git_config_rename_section_in_file(NULL, old_name, new_name);
|
2012-02-16 08:04:25 +00:00
|
|
|
}
|
|
|
|
|
branch: add a --copy (-c) option to go with --move (-m)
Add the ability to --copy a branch and its reflog and configuration,
this uses the same underlying machinery as the --move (-m) option
except the reflog and configuration is copied instead of being moved.
This is useful for e.g. copying a topic branch to a new version,
e.g. work to work-2 after submitting the work topic to the list, while
preserving all the tracking info and other configuration that goes
with the branch, and unlike --move keeping the other already-submitted
branch around for reference.
Like --move, when the source branch is the currently checked out
branch the HEAD is moved to the destination branch. In the case of
--move we don't really have a choice (other than remaining on a
detached HEAD) and in order to keep the functionality consistent, we
are doing it in similar way for --copy too.
The most common usage of this feature is expected to be moving to a
new topic branch which is a copy of the current one, in that case
moving to the target branch is what the user wants, and doesn't
unexpectedly behave differently than --move would.
One outstanding caveat of this implementation is that:
git checkout maint &&
git checkout master &&
git branch -c topic &&
git checkout -
Will check out 'maint' instead of 'master'. This is because the @{-N}
feature (or its -1 shorthand "-") relies on HEAD reflogs created by
the checkout command, so in this case we'll checkout maint instead of
master, as the user might expect. What to do about that is left to a
future change.
Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Sahil Dua <sahildua2305@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-18 21:19:16 +00:00
|
|
|
int git_config_copy_section_in_file(const char *config_filename,
|
|
|
|
const char *old_name, const char *new_name)
|
|
|
|
{
|
|
|
|
return git_config_copy_or_rename_section_in_file(config_filename,
|
|
|
|
old_name, new_name, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int git_config_copy_section(const char *old_name, const char *new_name)
|
|
|
|
{
|
|
|
|
return git_config_copy_section_in_file(NULL, old_name, new_name);
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:41:18 +00:00
|
|
|
/*
|
|
|
|
* Call this to report error for your variable that should not
|
|
|
|
* get a boolean value (i.e. "[my] var" means "true").
|
|
|
|
*/
|
2012-12-15 17:42:10 +00:00
|
|
|
#undef config_error_nonbool
|
2008-02-11 18:41:18 +00:00
|
|
|
int config_error_nonbool(const char *var)
|
|
|
|
{
|
2018-07-21 07:49:27 +00:00
|
|
|
return error(_("missing value for '%s'"), var);
|
2008-02-11 18:41:18 +00:00
|
|
|
}
|
2013-01-23 06:23:05 +00:00
|
|
|
|
|
|
|
int parse_config_key(const char *var,
|
|
|
|
const char *section,
|
2020-04-10 19:44:28 +00:00
|
|
|
const char **subsection, size_t *subsection_len,
|
2013-01-23 06:23:05 +00:00
|
|
|
const char **key)
|
|
|
|
{
|
|
|
|
const char *dot;
|
|
|
|
|
|
|
|
/* Does it start with "section." ? */
|
2017-02-24 21:07:19 +00:00
|
|
|
if (!skip_prefix(var, section, &var) || *var != '.')
|
2013-01-23 06:23:05 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the key; we don't know yet if we have a subsection, but we must
|
|
|
|
* parse backwards from the end, since the subsection may have dots in
|
|
|
|
* it, too.
|
|
|
|
*/
|
|
|
|
dot = strrchr(var, '.');
|
|
|
|
*key = dot + 1;
|
|
|
|
|
|
|
|
/* Did we have a subsection at all? */
|
2017-02-24 21:07:19 +00:00
|
|
|
if (dot == var) {
|
parse_config_key: allow matching single-level config
The parse_config_key() function was introduced to make it
easier to match "section.subsection.key" variables. It also
handles the simpler "section.key", and the caller is
responsible for distinguishing the two from its
out-parameters.
Most callers who _only_ want "section.key" would just use a
strcmp(var, "section.key"), since there is no parsing
required. However, they may still use parse_config_key() if
their "section" variable isn't a constant (an example of
this is in parse_hide_refs_config).
Using the parse_config_key is a bit clunky, though:
const char *subsection;
int subsection_len;
const char *key;
if (!parse_config_key(var, section, &subsection, &subsection_len, &key) &&
!subsection) {
/* matched! */
}
Instead, let's treat a NULL subsection as an indication that
the caller does not expect one. That lets us write:
const char *key;
if (!parse_config_key(var, section, NULL, NULL, &key)) {
/* matched! */
}
Existing callers should be unaffected, as passing a NULL
subsection would currently segfault.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-24 21:08:02 +00:00
|
|
|
if (subsection) {
|
|
|
|
*subsection = NULL;
|
|
|
|
*subsection_len = 0;
|
|
|
|
}
|
2013-01-23 06:23:05 +00:00
|
|
|
}
|
|
|
|
else {
|
parse_config_key: allow matching single-level config
The parse_config_key() function was introduced to make it
easier to match "section.subsection.key" variables. It also
handles the simpler "section.key", and the caller is
responsible for distinguishing the two from its
out-parameters.
Most callers who _only_ want "section.key" would just use a
strcmp(var, "section.key"), since there is no parsing
required. However, they may still use parse_config_key() if
their "section" variable isn't a constant (an example of
this is in parse_hide_refs_config).
Using the parse_config_key is a bit clunky, though:
const char *subsection;
int subsection_len;
const char *key;
if (!parse_config_key(var, section, &subsection, &subsection_len, &key) &&
!subsection) {
/* matched! */
}
Instead, let's treat a NULL subsection as an indication that
the caller does not expect one. That lets us write:
const char *key;
if (!parse_config_key(var, section, NULL, NULL, &key)) {
/* matched! */
}
Existing callers should be unaffected, as passing a NULL
subsection would currently segfault.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-24 21:08:02 +00:00
|
|
|
if (!subsection)
|
|
|
|
return -1;
|
2017-02-24 21:07:19 +00:00
|
|
|
*subsection = var + 1;
|
2013-01-23 06:23:05 +00:00
|
|
|
*subsection_len = dot - *subsection;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2016-02-19 09:16:01 +00:00
|
|
|
|
|
|
|
const char *current_config_origin_type(void)
|
|
|
|
{
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
int type;
|
2016-05-27 00:32:23 +00:00
|
|
|
if (current_config_kvi)
|
|
|
|
type = current_config_kvi->origin_type;
|
|
|
|
else if(cf)
|
|
|
|
type = cf->origin_type;
|
|
|
|
else
|
2018-05-02 09:38:39 +00:00
|
|
|
BUG("current_config_origin_type called outside config callback");
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case CONFIG_ORIGIN_BLOB:
|
|
|
|
return "blob";
|
|
|
|
case CONFIG_ORIGIN_FILE:
|
|
|
|
return "file";
|
|
|
|
case CONFIG_ORIGIN_STDIN:
|
|
|
|
return "standard input";
|
|
|
|
case CONFIG_ORIGIN_SUBMODULE_BLOB:
|
|
|
|
return "submodule-blob";
|
|
|
|
case CONFIG_ORIGIN_CMDLINE:
|
|
|
|
return "command line";
|
|
|
|
default:
|
2018-05-02 09:38:39 +00:00
|
|
|
BUG("unknown config origin type");
|
i18n: config: unfold error messages marked for translation
Introduced in 473166b ("config: add 'origin_type' to config_source
struct", 2016-02-19), Git can inform the user about the origin of a
config error, but the implementation does not allow translators to
translate the keywords 'file', 'blob, 'standard input', and
'submodule-blob'. Moreover, for the second message, a reason for the
error is appended to the message, not allowing translators to translate
that reason either.
Unfold the message into several templates for each known origin_type.
That would result in better translation at the expense of code
verbosity.
Add enum config_oringin_type to ease management of the various
configuration origin types (blob, file, etc). Previously origin type
was considered from command line if cf->origin_type == NULL, i.e.,
uninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in
git_config_from_parameters() and configset_add_value().
For error message in git_parse_source(), use xstrfmt() function to
prepare the message string, instead of doing something like it's done
for die_bad_number(), because intelligibility and code conciseness are
improved for that instance.
Signed-off-by: Vasco Almeida <vascomalmeida@sapo.pt>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-28 13:14:03 +00:00
|
|
|
}
|
2016-02-19 09:16:01 +00:00
|
|
|
}
|
|
|
|
|
2020-02-10 00:30:53 +00:00
|
|
|
const char *config_scope_name(enum config_scope scope)
|
|
|
|
{
|
|
|
|
switch (scope) {
|
|
|
|
case CONFIG_SCOPE_SYSTEM:
|
|
|
|
return "system";
|
|
|
|
case CONFIG_SCOPE_GLOBAL:
|
|
|
|
return "global";
|
2020-02-10 00:30:54 +00:00
|
|
|
case CONFIG_SCOPE_LOCAL:
|
|
|
|
return "local";
|
|
|
|
case CONFIG_SCOPE_WORKTREE:
|
|
|
|
return "worktree";
|
2020-02-10 00:30:55 +00:00
|
|
|
case CONFIG_SCOPE_COMMAND:
|
|
|
|
return "command";
|
2020-02-10 00:30:58 +00:00
|
|
|
case CONFIG_SCOPE_SUBMODULE:
|
|
|
|
return "submodule";
|
2020-02-10 00:30:53 +00:00
|
|
|
default:
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-19 09:16:01 +00:00
|
|
|
const char *current_config_name(void)
|
|
|
|
{
|
2016-05-27 00:32:23 +00:00
|
|
|
const char *name;
|
|
|
|
if (current_config_kvi)
|
|
|
|
name = current_config_kvi->filename;
|
|
|
|
else if (cf)
|
|
|
|
name = cf->name;
|
|
|
|
else
|
2018-05-02 09:38:39 +00:00
|
|
|
BUG("current_config_name called outside config callback");
|
2016-05-27 00:32:23 +00:00
|
|
|
return name ? name : "";
|
2016-02-19 09:16:01 +00:00
|
|
|
}
|
config: add a notion of "scope"
A config callback passed to git_config() doesn't know very
much about the context in which it sees a variable. It can
ask whether the variable comes from a file, and get the file
name. But without analyzing the filename (which is hard to
do accurately), it cannot tell whether it is in system-level
config, user-level config, or repo-specific config.
Generally this doesn't matter; the point of not passing this
to the callback is that it should treat the config the same
no matter where it comes from. But some programs, like
upload-pack, are a special case: we should be able to run
them in an untrusted repository, which means we cannot use
any "dangerous" config from the repository config file (but
it is OK to use it from system or user config).
This patch teaches the config code to record the "scope" of
each variable, and make it available inside config
callbacks, similar to how we give access to the filename.
The scope is the starting source for a particular parsing
operation, and remains the same even if we include other
files (so a .git/config which includes another file will
remain CONFIG_SCOPE_REPO, as it would be similarly
untrusted).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-05-18 22:44:23 +00:00
|
|
|
|
|
|
|
enum config_scope current_config_scope(void)
|
|
|
|
{
|
|
|
|
if (current_config_kvi)
|
|
|
|
return current_config_kvi->scope;
|
|
|
|
else
|
|
|
|
return current_parsing_scope;
|
2016-02-19 09:16:01 +00:00
|
|
|
}
|
2018-05-26 13:55:21 +00:00
|
|
|
|
2020-01-27 07:04:31 +00:00
|
|
|
int current_config_line(void)
|
|
|
|
{
|
|
|
|
if (current_config_kvi)
|
|
|
|
return current_config_kvi->linenr;
|
|
|
|
else
|
|
|
|
return cf->linenr;
|
|
|
|
}
|
|
|
|
|
2018-05-26 13:55:21 +00:00
|
|
|
int lookup_config(const char **mapping, int nr_mapping, const char *var)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < nr_mapping; i++) {
|
|
|
|
const char *name = mapping[i];
|
|
|
|
|
|
|
|
if (name && !strcasecmp(var, name))
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|