2005-04-08 02:16:10 +04:00
|
|
|
/*
|
|
|
|
* GIT - The information manager from hell
|
|
|
|
*
|
|
|
|
* Copyright (C) Linus Torvalds, 2005
|
|
|
|
*/
|
2005-04-08 02:13:13 +04:00
|
|
|
#include "cache.h"
|
2017-06-14 21:07:36 +03:00
|
|
|
#include "config.h"
|
2015-06-22 17:03:05 +03:00
|
|
|
#include "refs.h"
|
2006-05-19 14:03:57 +04:00
|
|
|
#include "builtin.h"
|
2018-04-11 00:26:18 +03:00
|
|
|
#include "exec-cmd.h"
|
2009-07-12 14:24:32 +04:00
|
|
|
#include "parse-options.h"
|
2020-08-31 09:57:59 +03:00
|
|
|
#include "worktree.h"
|
2005-04-08 02:13:13 +04:00
|
|
|
|
2005-08-06 23:50:14 +04:00
|
|
|
#ifndef DEFAULT_GIT_TEMPLATE_DIR
|
2007-06-11 13:10:47 +04:00
|
|
|
#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
|
2005-08-06 23:50:14 +04:00
|
|
|
#endif
|
|
|
|
|
2006-12-31 07:53:55 +03:00
|
|
|
#ifdef NO_TRUSTABLE_FILEMODE
|
|
|
|
#define TEST_FILEMODE 0
|
|
|
|
#else
|
|
|
|
#define TEST_FILEMODE 1
|
|
|
|
#endif
|
|
|
|
|
2020-02-22 23:17:39 +03:00
|
|
|
#define GIT_DEFAULT_HASH_ENVIRONMENT "GIT_DEFAULT_HASH"
|
|
|
|
|
git init: --bare/--shared overrides system/global config
If core.bare or core.sharedRepository are set in /etc/gitconfig or
~/.gitconfig, then 'git init' will read the values when constructing a
new config file; reading them, however, will override the values
specified on the command line. In the case of --bare, this ends up
causing a segfault, without the repository being properly initialised;
in the case of --shared, the permissions are set according to the
existing config settings, not what was specified on the command line.
This fix saves any specified values for --bare and --shared prior to
reading existing config settings, and restores them after reading but
before writing the new config file. core.bare is ignored in all
situations, while core.sharedRepository will only be used if --shared
is not specified to git init.
Also includes testcases which use a specified global config file
override, demonstrating the former failure scenario.
Signed-off-by: Deskin Miller <deskinm@umich.edu>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2008-10-07 09:37:48 +04:00
|
|
|
static int init_is_bare_repository = 0;
|
|
|
|
static int init_shared_repository = -1;
|
2010-02-17 02:42:31 +03:00
|
|
|
static const char *init_db_template_dir;
|
git init: --bare/--shared overrides system/global config
If core.bare or core.sharedRepository are set in /etc/gitconfig or
~/.gitconfig, then 'git init' will read the values when constructing a
new config file; reading them, however, will override the values
specified on the command line. In the case of --bare, this ends up
causing a segfault, without the repository being properly initialised;
in the case of --shared, the permissions are set according to the
existing config settings, not what was specified on the command line.
This fix saves any specified values for --bare and --shared prior to
reading existing config settings, and restores them after reading but
before writing the new config file. core.bare is ignored in all
situations, while core.sharedRepository will only be used if --shared
is not specified to git init.
Also includes testcases which use a specified global config file
override, demonstrating the former failure scenario.
Signed-off-by: Deskin Miller <deskinm@umich.edu>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2008-10-07 09:37:48 +04:00
|
|
|
|
2018-02-14 21:59:52 +03:00
|
|
|
static void copy_templates_1(struct strbuf *path, struct strbuf *template_path,
|
2005-08-03 03:45:21 +04:00
|
|
|
DIR *dir)
|
|
|
|
{
|
2015-10-05 06:46:04 +03:00
|
|
|
size_t path_baselen = path->len;
|
2018-02-14 21:59:52 +03:00
|
|
|
size_t template_baselen = template_path->len;
|
2005-08-03 03:45:21 +04:00
|
|
|
struct dirent *de;
|
|
|
|
|
|
|
|
/* Note: if ".git/hooks" file exists in the repository being
|
|
|
|
* re-initialized, /etc/core-git/templates/hooks/update would
|
2008-09-13 21:18:36 +04:00
|
|
|
* cause "git init" to fail here. I think this is sane but
|
2005-08-03 03:45:21 +04:00
|
|
|
* it means that the set of templates we ship by default, along
|
|
|
|
* with the way the namespace under .git/ is organized, should
|
|
|
|
* be really carefully chosen.
|
|
|
|
*/
|
2015-10-05 06:46:04 +03:00
|
|
|
safe_create_dir(path->buf, 1);
|
2005-08-03 03:45:21 +04:00
|
|
|
while ((de = readdir(dir)) != NULL) {
|
|
|
|
struct stat st_git, st_template;
|
|
|
|
int exists = 0;
|
|
|
|
|
2015-10-05 06:46:04 +03:00
|
|
|
strbuf_setlen(path, path_baselen);
|
2018-02-14 21:59:52 +03:00
|
|
|
strbuf_setlen(template_path, template_baselen);
|
2015-10-05 06:46:04 +03:00
|
|
|
|
2005-08-03 03:45:21 +04:00
|
|
|
if (de->d_name[0] == '.')
|
|
|
|
continue;
|
2015-10-05 06:46:04 +03:00
|
|
|
strbuf_addstr(path, de->d_name);
|
2018-02-14 21:59:52 +03:00
|
|
|
strbuf_addstr(template_path, de->d_name);
|
2015-10-05 06:46:04 +03:00
|
|
|
if (lstat(path->buf, &st_git)) {
|
2005-08-03 03:45:21 +04:00
|
|
|
if (errno != ENOENT)
|
2015-10-05 06:46:04 +03:00
|
|
|
die_errno(_("cannot stat '%s'"), path->buf);
|
2005-08-03 03:45:21 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
exists = 1;
|
|
|
|
|
2018-02-14 21:59:52 +03:00
|
|
|
if (lstat(template_path->buf, &st_template))
|
|
|
|
die_errno(_("cannot stat template '%s'"), template_path->buf);
|
2005-08-03 03:45:21 +04:00
|
|
|
|
|
|
|
if (S_ISDIR(st_template.st_mode)) {
|
2018-02-14 21:59:52 +03:00
|
|
|
DIR *subdir = opendir(template_path->buf);
|
2005-08-03 03:45:21 +04:00
|
|
|
if (!subdir)
|
2018-02-14 21:59:52 +03:00
|
|
|
die_errno(_("cannot opendir '%s'"), template_path->buf);
|
2015-10-05 06:46:04 +03:00
|
|
|
strbuf_addch(path, '/');
|
2018-02-14 21:59:52 +03:00
|
|
|
strbuf_addch(template_path, '/');
|
|
|
|
copy_templates_1(path, template_path, subdir);
|
2005-08-03 03:45:21 +04:00
|
|
|
closedir(subdir);
|
|
|
|
}
|
|
|
|
else if (exists)
|
|
|
|
continue;
|
|
|
|
else if (S_ISLNK(st_template.st_mode)) {
|
2015-10-05 06:46:04 +03:00
|
|
|
struct strbuf lnk = STRBUF_INIT;
|
pass st.st_size as hint for strbuf_readlink()
When we initially added the strbuf_readlink() function in
b11b7e13f4 (Add generic 'strbuf_readlink()' helper function,
2008-12-17), the point was that we generally have a _guess_
as to the correct size based on the stat information, but we
can't necessarily trust it.
Over the years, a few callers have grown up that simply pass
in 0, even though they have the stat information. Let's have
them pass in their hint for consistency (and in theory
efficiency, since it may avoid an extra resize/syscall loop,
but neither location is probably performance critical).
Note that st.st_size is actually an off_t, so in theory we
need xsize_t() here. But none of the other callsites use it,
and since this is just a hint, it doesn't matter either way
(if we wrap we'll simply start with a too-small hint and
then eventually complain when we cannot allocate the
memory).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-07-24 13:51:39 +03:00
|
|
|
if (strbuf_readlink(&lnk, template_path->buf,
|
|
|
|
st_template.st_size) < 0)
|
2018-02-14 21:59:52 +03:00
|
|
|
die_errno(_("cannot readlink '%s'"), template_path->buf);
|
2015-10-05 06:46:04 +03:00
|
|
|
if (symlink(lnk.buf, path->buf))
|
|
|
|
die_errno(_("cannot symlink '%s' '%s'"),
|
|
|
|
lnk.buf, path->buf);
|
|
|
|
strbuf_release(&lnk);
|
2005-08-03 03:45:21 +04:00
|
|
|
}
|
|
|
|
else if (S_ISREG(st_template.st_mode)) {
|
2018-02-14 21:59:52 +03:00
|
|
|
if (copy_file(path->buf, template_path->buf, st_template.st_mode))
|
2015-10-05 06:46:04 +03:00
|
|
|
die_errno(_("cannot copy '%s' to '%s'"),
|
2018-02-14 21:59:52 +03:00
|
|
|
template_path->buf, path->buf);
|
2005-08-03 03:45:21 +04:00
|
|
|
}
|
|
|
|
else
|
2018-02-14 21:59:52 +03:00
|
|
|
error(_("ignoring template %s"), template_path->buf);
|
2005-08-03 03:45:21 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-27 21:39:27 +04:00
|
|
|
static void copy_templates(const char *template_dir)
|
2005-08-03 03:45:21 +04:00
|
|
|
{
|
2015-10-05 06:46:04 +03:00
|
|
|
struct strbuf path = STRBUF_INIT;
|
|
|
|
struct strbuf template_path = STRBUF_INIT;
|
|
|
|
size_t template_len;
|
setup: fix memory leaks with `struct repository_format`
After we set up a `struct repository_format`, it owns various pieces of
allocated memory. We then either use those members, because we decide we
want to use the "candidate" repository format, or we discard the
candidate / scratch space. In the first case, we transfer ownership of
the memory to a few global variables. In the latter case, we just
silently drop the struct and end up leaking memory.
Introduce an initialization macro `REPOSITORY_FORMAT_INIT` and a
function `clear_repository_format()`, to be used on each side of
`read_repository_format()`. To have a clear and simple memory ownership,
let all users of `struct repository_format` duplicate the strings that
they take from it, rather than stealing the pointers.
Call `clear_...()` at the start of `read_...()` instead of just zeroing
the struct, since we sometimes enter the function multiple times. Thus,
it is important to initialize the struct before calling `read_...()`, so
document that. It's also important because we might not even call
`read_...()` before we call `clear_...()`, see, e.g., builtin/init-db.c.
Teach `read_...()` to clear the struct on error, so that it is reset to
a safe state, and document this. (In `setup_git_directory_gently()`, we
look at `repo_fmt.hash_algo` even if `repo_fmt.version` is -1, which we
weren't actually supposed to do per the API. After this commit, that's
ok.)
We inherit the existing code's combining "error" and "no version found".
Both are signalled through `version == -1` and now both cause us to
clear any partial configuration we have picked up. For "extensions.*",
that's fine, since they require a positive version number. For
"core.bare" and "core.worktree", we're already verifying that we have a
non-negative version number before using them.
Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-02-28 23:36:28 +03:00
|
|
|
struct repository_format template_format = REPOSITORY_FORMAT_INIT;
|
2016-03-12 01:37:11 +03:00
|
|
|
struct strbuf err = STRBUF_INIT;
|
2005-08-03 03:45:21 +04:00
|
|
|
DIR *dir;
|
2014-11-24 22:33:54 +03:00
|
|
|
char *to_free = NULL;
|
2005-08-03 03:45:21 +04:00
|
|
|
|
2007-11-13 23:05:04 +03:00
|
|
|
if (!template_dir)
|
2006-12-19 12:28:15 +03:00
|
|
|
template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
|
2010-02-17 02:42:31 +03:00
|
|
|
if (!template_dir)
|
|
|
|
template_dir = init_db_template_dir;
|
2008-07-14 00:31:18 +04:00
|
|
|
if (!template_dir)
|
2014-11-24 22:33:54 +03:00
|
|
|
template_dir = to_free = system_path(DEFAULT_GIT_TEMPLATE_DIR);
|
|
|
|
if (!template_dir[0]) {
|
|
|
|
free(to_free);
|
2008-07-28 10:02:04 +04:00
|
|
|
return;
|
2014-11-24 22:33:54 +03:00
|
|
|
}
|
2015-10-05 06:46:04 +03:00
|
|
|
|
|
|
|
strbuf_addstr(&template_path, template_dir);
|
|
|
|
strbuf_complete(&template_path, '/');
|
|
|
|
template_len = template_path.len;
|
|
|
|
|
|
|
|
dir = opendir(template_path.buf);
|
2005-08-06 23:50:14 +04:00
|
|
|
if (!dir) {
|
2018-05-29 15:14:35 +03:00
|
|
|
warning(_("templates not found in %s"), template_dir);
|
2014-11-24 22:33:54 +03:00
|
|
|
goto free_return;
|
2005-08-06 23:50:14 +04:00
|
|
|
}
|
|
|
|
|
2005-11-26 03:03:56 +03:00
|
|
|
/* Make sure that template is from the correct vintage */
|
2015-10-05 06:46:04 +03:00
|
|
|
strbuf_addstr(&template_path, "config");
|
2016-03-12 01:37:11 +03:00
|
|
|
read_repository_format(&template_format, template_path.buf);
|
2015-10-05 06:46:04 +03:00
|
|
|
strbuf_setlen(&template_path, template_len);
|
2005-11-26 03:03:56 +03:00
|
|
|
|
2016-03-12 01:37:11 +03:00
|
|
|
/*
|
|
|
|
* No mention of version at all is OK, but anything else should be
|
|
|
|
* verified.
|
|
|
|
*/
|
|
|
|
if (template_format.version >= 0 &&
|
|
|
|
verify_repository_format(&template_format, &err) < 0) {
|
|
|
|
warning(_("not copying templates from '%s': %s"),
|
|
|
|
template_dir, err.buf);
|
|
|
|
strbuf_release(&err);
|
2014-11-24 22:33:54 +03:00
|
|
|
goto close_free_return;
|
2005-11-26 03:03:56 +03:00
|
|
|
}
|
|
|
|
|
2016-09-25 06:14:36 +03:00
|
|
|
strbuf_addstr(&path, get_git_common_dir());
|
2015-10-05 06:46:04 +03:00
|
|
|
strbuf_complete(&path, '/');
|
|
|
|
copy_templates_1(&path, &template_path, dir);
|
2014-11-24 22:33:54 +03:00
|
|
|
close_free_return:
|
2005-08-03 03:45:21 +04:00
|
|
|
closedir(dir);
|
2014-11-24 22:33:54 +03:00
|
|
|
free_return:
|
|
|
|
free(to_free);
|
2015-10-05 06:46:04 +03:00
|
|
|
strbuf_release(&path);
|
|
|
|
strbuf_release(&template_path);
|
setup: fix memory leaks with `struct repository_format`
After we set up a `struct repository_format`, it owns various pieces of
allocated memory. We then either use those members, because we decide we
want to use the "candidate" repository format, or we discard the
candidate / scratch space. In the first case, we transfer ownership of
the memory to a few global variables. In the latter case, we just
silently drop the struct and end up leaking memory.
Introduce an initialization macro `REPOSITORY_FORMAT_INIT` and a
function `clear_repository_format()`, to be used on each side of
`read_repository_format()`. To have a clear and simple memory ownership,
let all users of `struct repository_format` duplicate the strings that
they take from it, rather than stealing the pointers.
Call `clear_...()` at the start of `read_...()` instead of just zeroing
the struct, since we sometimes enter the function multiple times. Thus,
it is important to initialize the struct before calling `read_...()`, so
document that. It's also important because we might not even call
`read_...()` before we call `clear_...()`, see, e.g., builtin/init-db.c.
Teach `read_...()` to clear the struct on error, so that it is reset to
a safe state, and document this. (In `setup_git_directory_gently()`, we
look at `repo_fmt.hash_algo` even if `repo_fmt.version` is -1, which we
weren't actually supposed to do per the API. After this commit, that's
ok.)
We inherit the existing code's combining "error" and "no version found".
Both are signalled through `version == -1` and now both cause us to
clear any partial configuration we have picked up. For "extensions.*",
that's fine, since they require a positive version number. For
"core.bare" and "core.worktree", we're already verifying that we have a
non-negative version number before using them.
Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-02-28 23:36:28 +03:00
|
|
|
clear_repository_format(&template_format);
|
2005-08-03 03:45:21 +04:00
|
|
|
}
|
|
|
|
|
2010-02-17 02:42:31 +03:00
|
|
|
static int git_init_db_config(const char *k, const char *v, void *cb)
|
|
|
|
{
|
|
|
|
if (!strcmp(k, "init.templatedir"))
|
|
|
|
return git_config_pathname(&init_db_template_dir, k, v);
|
|
|
|
|
2019-03-11 23:10:58 +03:00
|
|
|
if (starts_with(k, "core."))
|
|
|
|
return platform_core_config(k, v, cb);
|
|
|
|
|
2010-02-17 02:42:31 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-02 21:37:40 +03:00
|
|
|
/*
|
|
|
|
* If the git_dir is not directly inside the working tree, then git will not
|
|
|
|
* find it by default, and we need to set the worktree explicitly.
|
|
|
|
*/
|
|
|
|
static int needs_work_tree_config(const char *git_dir, const char *work_tree)
|
|
|
|
{
|
|
|
|
if (!strcmp(work_tree, "/") && !strcmp(git_dir, "/.git"))
|
|
|
|
return 0;
|
|
|
|
if (skip_prefix(git_dir, work_tree, &git_dir) &&
|
|
|
|
!strcmp(git_dir, "/.git"))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
builtin/clone: avoid failure with GIT_DEFAULT_HASH
If a user is cloning a SHA-1 repository with GIT_DEFAULT_HASH set to
"sha256", then we can end up with a repository where the repository
format version is 0 but the extensions.objectformat key is set to
"sha256". This is both wrong (the user has a SHA-1 repository) and
nonfunctional (because the extension cannot be used in a v0 repository).
This happens because in a clone, we initially set up the repository, and
then change its algorithm based on what the remote side tells us it's
using. We've initially set up the repository as SHA-256 in this case,
and then later on reset the repository version without clearing the
extension.
We could just always set the extension in this case, but that would mean
that our SHA-1 repositories weren't compatible with older Git versions,
even though there's no reason why they shouldn't be. And we also don't
want to initialize the repository as SHA-1 initially, since that means
if we're cloning an empty repository, we'll have failed to honor the
GIT_DEFAULT_HASH variable and will end up with a SHA-1 repository, not a
SHA-256 repository.
Neither of those are appealing, so let's tell the repository
initialization code if we're doing a reinit like this, and if so, to
clear the extension if we're using SHA-1. This makes sure we produce a
valid and functional repository and doesn't break any of our other use
cases.
Reported-by: Matheus Tavares <matheus.bernardino@usp.br>
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-09-21 01:35:41 +03:00
|
|
|
void initialize_repository_version(int hash_algo, int reinit)
|
2020-02-22 23:17:40 +03:00
|
|
|
{
|
|
|
|
char repo_version_string[10];
|
|
|
|
int repo_version = GIT_REPO_VERSION;
|
|
|
|
|
|
|
|
if (hash_algo != GIT_HASH_SHA1)
|
|
|
|
repo_version = GIT_REPO_VERSION_READ;
|
|
|
|
|
|
|
|
/* This forces creation of new config file */
|
|
|
|
xsnprintf(repo_version_string, sizeof(repo_version_string),
|
|
|
|
"%d", repo_version);
|
|
|
|
git_config_set("core.repositoryformatversion", repo_version_string);
|
|
|
|
|
|
|
|
if (hash_algo != GIT_HASH_SHA1)
|
|
|
|
git_config_set("extensions.objectformat",
|
|
|
|
hash_algos[hash_algo].name);
|
builtin/clone: avoid failure with GIT_DEFAULT_HASH
If a user is cloning a SHA-1 repository with GIT_DEFAULT_HASH set to
"sha256", then we can end up with a repository where the repository
format version is 0 but the extensions.objectformat key is set to
"sha256". This is both wrong (the user has a SHA-1 repository) and
nonfunctional (because the extension cannot be used in a v0 repository).
This happens because in a clone, we initially set up the repository, and
then change its algorithm based on what the remote side tells us it's
using. We've initially set up the repository as SHA-256 in this case,
and then later on reset the repository version without clearing the
extension.
We could just always set the extension in this case, but that would mean
that our SHA-1 repositories weren't compatible with older Git versions,
even though there's no reason why they shouldn't be. And we also don't
want to initialize the repository as SHA-1 initially, since that means
if we're cloning an empty repository, we'll have failed to honor the
GIT_DEFAULT_HASH variable and will end up with a SHA-1 repository, not a
SHA-256 repository.
Neither of those are appealing, so let's tell the repository
initialization code if we're doing a reinit like this, and if so, to
clear the extension if we're using SHA-1. This makes sure we produce a
valid and functional repository and doesn't break any of our other use
cases.
Reported-by: Matheus Tavares <matheus.bernardino@usp.br>
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-09-21 01:35:41 +03:00
|
|
|
else if (reinit)
|
|
|
|
git_config_set_gently("extensions.objectformat", NULL);
|
2020-02-22 23:17:40 +03:00
|
|
|
}
|
|
|
|
|
2016-09-25 06:14:39 +03:00
|
|
|
static int create_default_files(const char *template_path,
|
2020-02-22 23:17:38 +03:00
|
|
|
const char *original_git_dir,
|
2020-06-24 17:46:32 +03:00
|
|
|
const char *initial_branch,
|
2020-12-11 14:36:56 +03:00
|
|
|
const struct repository_format *fmt,
|
|
|
|
int quiet)
|
2005-05-30 21:20:44 +04:00
|
|
|
{
|
2005-11-26 03:03:56 +03:00
|
|
|
struct stat st1;
|
2015-10-05 06:46:04 +03:00
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
char *path;
|
2008-03-24 18:14:52 +03:00
|
|
|
char junk[2];
|
2006-12-15 08:44:58 +03:00
|
|
|
int reinit;
|
2006-12-31 07:53:55 +03:00
|
|
|
int filemode;
|
2016-09-04 19:08:41 +03:00
|
|
|
struct strbuf err = STRBUF_INIT;
|
2005-05-30 21:20:44 +04:00
|
|
|
|
2010-02-17 02:42:31 +03:00
|
|
|
/* Just look for `init.templatedir` */
|
2019-03-11 23:10:58 +03:00
|
|
|
init_db_template_dir = NULL; /* re-set in case it was set before */
|
2010-02-17 02:42:31 +03:00
|
|
|
git_config(git_init_db_config, NULL);
|
|
|
|
|
2016-09-13 06:24:19 +03:00
|
|
|
/*
|
|
|
|
* First copy the templates -- we might have the default
|
2005-11-26 03:03:56 +03:00
|
|
|
* config file there, in which case we would want to read
|
|
|
|
* from it after installing.
|
2016-09-13 06:24:23 +03:00
|
|
|
*
|
|
|
|
* Before reading that config, we also need to clear out any cached
|
|
|
|
* values (since we've just potentially changed what's available on
|
|
|
|
* disk).
|
2005-11-26 03:03:56 +03:00
|
|
|
*/
|
2008-04-27 21:39:27 +04:00
|
|
|
copy_templates(template_path);
|
2016-09-13 06:24:23 +03:00
|
|
|
git_config_clear();
|
|
|
|
reset_shared_repository();
|
2008-05-14 21:46:53 +04:00
|
|
|
git_config(git_default_config, NULL);
|
2009-03-26 02:19:36 +03:00
|
|
|
|
2016-09-13 06:24:19 +03:00
|
|
|
/*
|
|
|
|
* We must make sure command-line options continue to override any
|
|
|
|
* values we might have just re-read from the config.
|
|
|
|
*/
|
|
|
|
is_bare_repository_cfg = init_is_bare_repository;
|
git init: --bare/--shared overrides system/global config
If core.bare or core.sharedRepository are set in /etc/gitconfig or
~/.gitconfig, then 'git init' will read the values when constructing a
new config file; reading them, however, will override the values
specified on the command line. In the case of --bare, this ends up
causing a segfault, without the repository being properly initialised;
in the case of --shared, the permissions are set according to the
existing config settings, not what was specified on the command line.
This fix saves any specified values for --bare and --shared prior to
reading existing config settings, and restores them after reading but
before writing the new config file. core.bare is ignored in all
situations, while core.sharedRepository will only be used if --shared
is not specified to git init.
Also includes testcases which use a specified global config file
override, demonstrating the former failure scenario.
Signed-off-by: Deskin Miller <deskinm@umich.edu>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2008-10-07 09:37:48 +04:00
|
|
|
if (init_shared_repository != -1)
|
2016-03-12 01:36:49 +03:00
|
|
|
set_shared_repository(init_shared_repository);
|
2005-11-26 03:03:56 +03:00
|
|
|
|
2006-06-10 09:07:23 +04:00
|
|
|
/*
|
|
|
|
* We would have created the above under user's umask -- under
|
|
|
|
* shared-repository settings, we would need to fix them up.
|
|
|
|
*/
|
2016-03-12 01:36:49 +03:00
|
|
|
if (get_shared_repository()) {
|
2008-04-27 21:39:27 +04:00
|
|
|
adjust_shared_perm(get_git_dir());
|
2006-06-10 09:07:23 +04:00
|
|
|
}
|
|
|
|
|
2016-09-04 19:08:41 +03:00
|
|
|
/*
|
|
|
|
* We need to create a "refs" dir in any case so that older
|
|
|
|
* versions of git can tell that this is a repository.
|
|
|
|
*/
|
|
|
|
safe_create_dir(git_path("refs"), 1);
|
|
|
|
adjust_shared_perm(git_path("refs"));
|
|
|
|
|
|
|
|
if (refs_init_db(&err))
|
|
|
|
die("failed to set up refs db: %s", err.buf);
|
|
|
|
|
2005-05-30 21:20:44 +04:00
|
|
|
/*
|
2020-06-24 17:46:32 +03:00
|
|
|
* Point the HEAD symref to the initial branch with if HEAD does
|
|
|
|
* not yet exist.
|
2005-05-30 21:20:44 +04:00
|
|
|
*/
|
2015-10-05 06:46:04 +03:00
|
|
|
path = git_path_buf(&buf, "HEAD");
|
2008-03-24 18:14:52 +03:00
|
|
|
reinit = (!access(path, R_OK)
|
|
|
|
|| readlink(path, junk, sizeof(junk)-1) != -1);
|
2006-12-15 08:44:58 +03:00
|
|
|
if (!reinit) {
|
2020-06-24 17:46:32 +03:00
|
|
|
char *ref;
|
|
|
|
|
|
|
|
if (!initial_branch)
|
2020-12-11 14:36:56 +03:00
|
|
|
initial_branch = git_default_branch_name(quiet);
|
2020-06-24 17:46:32 +03:00
|
|
|
|
|
|
|
ref = xstrfmt("refs/heads/%s", initial_branch);
|
|
|
|
if (check_refname_format(ref, 0) < 0)
|
|
|
|
die(_("invalid initial branch name: '%s'"),
|
|
|
|
initial_branch);
|
|
|
|
|
|
|
|
if (create_symref("HEAD", ref, NULL) < 0)
|
2005-05-30 21:20:44 +04:00
|
|
|
exit(1);
|
2020-06-24 17:46:32 +03:00
|
|
|
free(ref);
|
2005-05-30 21:20:44 +04:00
|
|
|
}
|
2005-10-26 03:43:03 +04:00
|
|
|
|
builtin/clone: avoid failure with GIT_DEFAULT_HASH
If a user is cloning a SHA-1 repository with GIT_DEFAULT_HASH set to
"sha256", then we can end up with a repository where the repository
format version is 0 but the extensions.objectformat key is set to
"sha256". This is both wrong (the user has a SHA-1 repository) and
nonfunctional (because the extension cannot be used in a v0 repository).
This happens because in a clone, we initially set up the repository, and
then change its algorithm based on what the remote side tells us it's
using. We've initially set up the repository as SHA-256 in this case,
and then later on reset the repository version without clearing the
extension.
We could just always set the extension in this case, but that would mean
that our SHA-1 repositories weren't compatible with older Git versions,
even though there's no reason why they shouldn't be. And we also don't
want to initialize the repository as SHA-1 initially, since that means
if we're cloning an empty repository, we'll have failed to honor the
GIT_DEFAULT_HASH variable and will end up with a SHA-1 repository, not a
SHA-256 repository.
Neither of those are appealing, so let's tell the repository
initialization code if we're doing a reinit like this, and if so, to
clear the extension if we're using SHA-1. This makes sure we produce a
valid and functional repository and doesn't break any of our other use
cases.
Reported-by: Matheus Tavares <matheus.bernardino@usp.br>
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-09-21 01:35:41 +03:00
|
|
|
initialize_repository_version(fmt->hash_algo, 0);
|
2005-11-26 03:03:56 +03:00
|
|
|
|
|
|
|
/* Check filemode trustability */
|
2015-10-05 06:46:04 +03:00
|
|
|
path = git_path_buf(&buf, "config");
|
2006-12-31 07:53:55 +03:00
|
|
|
filemode = TEST_FILEMODE;
|
|
|
|
if (TEST_FILEMODE && !lstat(path, &st1)) {
|
2005-11-26 03:03:56 +03:00
|
|
|
struct stat st2;
|
2006-12-31 07:53:55 +03:00
|
|
|
filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
|
2005-11-26 03:03:56 +03:00
|
|
|
!lstat(path, &st2) &&
|
2014-11-18 16:50:24 +03:00
|
|
|
st1.st_mode != st2.st_mode &&
|
|
|
|
!chmod(path, st1.st_mode));
|
2014-11-21 12:34:54 +03:00
|
|
|
if (filemode && !reinit && (st1.st_mode & S_IXUSR))
|
|
|
|
filemode = 0;
|
2005-10-26 03:43:03 +04:00
|
|
|
}
|
2016-02-22 14:23:36 +03:00
|
|
|
git_config_set("core.filemode", filemode ? "true" : "false");
|
2006-12-15 08:44:58 +03:00
|
|
|
|
Clean up work-tree handling
The old version of work-tree support was an unholy mess, barely readable,
and not to the point.
For example, why do you have to provide a worktree, when it is not used?
As in "git status". Now it works.
Another riddle was: if you can have work trees inside the git dir, why
are some programs complaining that they need a work tree?
IOW it is allowed to call
$ git --git-dir=../ --work-tree=. bla
when you really want to. In this case, you are both in the git directory
and in the working tree. So, programs have to actually test for the right
thing, namely if they are inside a working tree, and not if they are
inside a git directory.
Also, GIT_DIR=../.git should behave the same as if no GIT_DIR was
specified, unless there is a repository in the current working directory.
It does now.
The logic to determine if a repository is bare, or has a work tree
(tertium non datur), is this:
--work-tree=bla overrides GIT_WORK_TREE, which overrides core.bare = true,
which overrides core.worktree, which overrides GIT_DIR/.. when GIT_DIR
ends in /.git, which overrides the directory in which .git/ was found.
In related news, a long standing bug was fixed: when in .git/bla/x.git/,
which is a bare repository, git formerly assumed ../.. to be the
appropriate git dir. This problem was reported by Shawn Pearce to have
caused much pain, where a colleague mistakenly ran "git init" in "/" a
long time ago, and bare repositories just would not work.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-08-01 04:30:14 +04:00
|
|
|
if (is_bare_repository())
|
2016-02-22 14:23:36 +03:00
|
|
|
git_config_set("core.bare", "true");
|
2007-01-07 13:00:28 +03:00
|
|
|
else {
|
Clean up work-tree handling
The old version of work-tree support was an unholy mess, barely readable,
and not to the point.
For example, why do you have to provide a worktree, when it is not used?
As in "git status". Now it works.
Another riddle was: if you can have work trees inside the git dir, why
are some programs complaining that they need a work tree?
IOW it is allowed to call
$ git --git-dir=../ --work-tree=. bla
when you really want to. In this case, you are both in the git directory
and in the working tree. So, programs have to actually test for the right
thing, namely if they are inside a working tree, and not if they are
inside a git directory.
Also, GIT_DIR=../.git should behave the same as if no GIT_DIR was
specified, unless there is a repository in the current working directory.
It does now.
The logic to determine if a repository is bare, or has a work tree
(tertium non datur), is this:
--work-tree=bla overrides GIT_WORK_TREE, which overrides core.bare = true,
which overrides core.worktree, which overrides GIT_DIR/.. when GIT_DIR
ends in /.git, which overrides the directory in which .git/ was found.
In related news, a long standing bug was fixed: when in .git/bla/x.git/,
which is a bare repository, git formerly assumed ../.. to be the
appropriate git dir. This problem was reported by Shawn Pearce to have
caused much pain, where a colleague mistakenly ran "git init" in "/" a
long time ago, and bare repositories just would not work.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-08-01 04:30:14 +04:00
|
|
|
const char *work_tree = get_git_work_tree();
|
2016-02-22 14:23:36 +03:00
|
|
|
git_config_set("core.bare", "false");
|
2007-01-23 18:51:18 +03:00
|
|
|
/* allow template config file to override the default */
|
2017-01-27 13:09:47 +03:00
|
|
|
if (log_all_ref_updates == LOG_REFS_UNSET)
|
2016-02-22 14:23:36 +03:00
|
|
|
git_config_set("core.logallrefupdates", "true");
|
2016-09-25 06:14:39 +03:00
|
|
|
if (needs_work_tree_config(original_git_dir, work_tree))
|
2016-02-22 14:23:36 +03:00
|
|
|
git_config_set("core.worktree", work_tree);
|
2007-01-07 13:00:28 +03:00
|
|
|
}
|
2007-08-31 11:25:04 +04:00
|
|
|
|
|
|
|
if (!reinit) {
|
2008-05-11 20:16:39 +04:00
|
|
|
/* Check if symlink is supported in the work tree */
|
2015-10-05 06:46:04 +03:00
|
|
|
path = git_path_buf(&buf, "tXXXXXX");
|
2007-08-31 11:25:04 +04:00
|
|
|
if (!close(xmkstemp(path)) &&
|
|
|
|
!unlink(path) &&
|
|
|
|
!symlink("testing", path) &&
|
|
|
|
!lstat(path, &st1) &&
|
|
|
|
S_ISLNK(st1.st_mode))
|
|
|
|
unlink(path); /* good */
|
|
|
|
else
|
2016-02-22 14:23:36 +03:00
|
|
|
git_config_set("core.symlinks", "false");
|
2008-05-11 20:16:39 +04:00
|
|
|
|
|
|
|
/* Check if the filesystem is case-insensitive */
|
2015-10-05 06:46:04 +03:00
|
|
|
path = git_path_buf(&buf, "CoNfIg");
|
2008-05-11 20:16:39 +04:00
|
|
|
if (!access(path, F_OK))
|
2016-02-22 14:23:36 +03:00
|
|
|
git_config_set("core.ignorecase", "true");
|
2015-10-05 06:45:26 +03:00
|
|
|
probe_utf8_pathname_composition();
|
2007-08-31 11:25:04 +04:00
|
|
|
}
|
|
|
|
|
2015-10-05 06:46:04 +03:00
|
|
|
strbuf_release(&buf);
|
2006-12-15 08:44:58 +03:00
|
|
|
return reinit;
|
2005-05-30 21:20:44 +04:00
|
|
|
}
|
|
|
|
|
2010-10-04 08:34:27 +04:00
|
|
|
static void create_object_directory(void)
|
|
|
|
{
|
2015-10-05 06:46:04 +03:00
|
|
|
struct strbuf path = STRBUF_INIT;
|
|
|
|
size_t baselen;
|
|
|
|
|
|
|
|
strbuf_addstr(&path, get_object_directory());
|
|
|
|
baselen = path.len;
|
|
|
|
|
|
|
|
safe_create_dir(path.buf, 1);
|
2010-10-04 08:34:27 +04:00
|
|
|
|
2015-10-05 06:46:04 +03:00
|
|
|
strbuf_setlen(&path, baselen);
|
|
|
|
strbuf_addstr(&path, "/pack");
|
|
|
|
safe_create_dir(path.buf, 1);
|
2010-10-04 08:34:27 +04:00
|
|
|
|
2015-10-05 06:46:04 +03:00
|
|
|
strbuf_setlen(&path, baselen);
|
|
|
|
strbuf_addstr(&path, "/info");
|
|
|
|
safe_create_dir(path.buf, 1);
|
2010-10-04 08:34:27 +04:00
|
|
|
|
2015-10-05 06:46:04 +03:00
|
|
|
strbuf_release(&path);
|
2010-10-04 08:34:27 +04:00
|
|
|
}
|
|
|
|
|
2016-09-25 06:14:40 +03:00
|
|
|
static void separate_git_dir(const char *git_dir, const char *git_link)
|
2011-03-19 18:16:56 +03:00
|
|
|
{
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
if (!stat(git_link, &st)) {
|
|
|
|
const char *src;
|
|
|
|
|
|
|
|
if (S_ISREG(st.st_mode))
|
2011-08-23 01:04:56 +04:00
|
|
|
src = read_gitfile(git_link);
|
2011-03-19 18:16:56 +03:00
|
|
|
else if (S_ISDIR(st.st_mode))
|
|
|
|
src = git_link;
|
|
|
|
else
|
2011-12-21 03:27:41 +04:00
|
|
|
die(_("unable to handle file type %d"), (int)st.st_mode);
|
2011-03-19 18:16:56 +03:00
|
|
|
|
|
|
|
if (rename(src, git_dir))
|
2011-04-10 23:34:02 +04:00
|
|
|
die_errno(_("unable to move %s to %s"), src, git_dir);
|
2020-08-31 09:57:59 +03:00
|
|
|
repair_worktrees(NULL, NULL);
|
2011-03-19 18:16:56 +03:00
|
|
|
}
|
|
|
|
|
2015-08-24 23:20:39 +03:00
|
|
|
write_file(git_link, "gitdir: %s", git_dir);
|
2011-03-19 18:16:56 +03:00
|
|
|
}
|
|
|
|
|
2020-02-22 23:17:38 +03:00
|
|
|
static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash)
|
|
|
|
{
|
2020-02-22 23:17:39 +03:00
|
|
|
const char *env = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);
|
2020-02-22 23:17:38 +03:00
|
|
|
/*
|
|
|
|
* If we already have an initialized repo, don't allow the user to
|
|
|
|
* specify a different algorithm, as that could cause corruption.
|
|
|
|
* Otherwise, if the user has specified one on the command line, use it.
|
|
|
|
*/
|
|
|
|
if (repo_fmt->version >= 0 && hash != GIT_HASH_UNKNOWN && hash != repo_fmt->hash_algo)
|
|
|
|
die(_("attempt to reinitialize repository with different hash"));
|
|
|
|
else if (hash != GIT_HASH_UNKNOWN)
|
|
|
|
repo_fmt->hash_algo = hash;
|
2020-02-22 23:17:39 +03:00
|
|
|
else if (env) {
|
|
|
|
int env_algo = hash_algo_by_name(env);
|
|
|
|
if (env_algo == GIT_HASH_UNKNOWN)
|
|
|
|
die(_("unknown hash algorithm '%s'"), env);
|
|
|
|
repo_fmt->hash_algo = env_algo;
|
|
|
|
}
|
2020-02-22 23:17:38 +03:00
|
|
|
}
|
|
|
|
|
2016-09-25 06:14:37 +03:00
|
|
|
int init_db(const char *git_dir, const char *real_git_dir,
|
2020-06-24 17:46:32 +03:00
|
|
|
const char *template_dir, int hash, const char *initial_branch,
|
|
|
|
unsigned int flags)
|
2008-04-27 21:39:27 +04:00
|
|
|
{
|
2010-10-04 08:34:27 +04:00
|
|
|
int reinit;
|
2016-09-25 06:14:38 +03:00
|
|
|
int exist_ok = flags & INIT_DB_EXIST_OK;
|
2017-03-08 18:43:40 +03:00
|
|
|
char *original_git_dir = real_pathdup(git_dir, 1);
|
2020-02-22 23:17:38 +03:00
|
|
|
struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
|
2016-09-25 06:14:37 +03:00
|
|
|
|
2016-09-25 06:14:38 +03:00
|
|
|
if (real_git_dir) {
|
|
|
|
struct stat st;
|
2016-09-25 06:14:37 +03:00
|
|
|
|
2016-09-25 06:14:38 +03:00
|
|
|
if (!exist_ok && !stat(git_dir, &st))
|
|
|
|
die(_("%s already exists"), git_dir);
|
|
|
|
|
|
|
|
if (!exist_ok && !stat(real_git_dir, &st))
|
|
|
|
die(_("%s already exists"), real_git_dir);
|
2008-04-27 21:39:27 +04:00
|
|
|
|
2020-03-06 22:03:13 +03:00
|
|
|
set_git_dir(real_git_dir, 1);
|
2016-09-25 06:14:40 +03:00
|
|
|
git_dir = get_git_dir();
|
|
|
|
separate_git_dir(git_dir, original_git_dir);
|
2016-09-25 06:14:38 +03:00
|
|
|
}
|
|
|
|
else {
|
2020-03-06 22:03:13 +03:00
|
|
|
set_git_dir(git_dir, 1);
|
2016-09-25 06:14:40 +03:00
|
|
|
git_dir = get_git_dir();
|
2016-09-25 06:14:38 +03:00
|
|
|
}
|
|
|
|
startup_info->have_repository = 1;
|
2008-04-27 21:39:27 +04:00
|
|
|
|
2019-03-11 23:10:58 +03:00
|
|
|
/* Just look for `core.hidedotfiles` */
|
|
|
|
git_config(git_init_db_config, NULL);
|
|
|
|
|
2011-03-19 18:16:56 +03:00
|
|
|
safe_create_dir(git_dir, 0);
|
2008-04-27 21:39:27 +04:00
|
|
|
|
git init: --bare/--shared overrides system/global config
If core.bare or core.sharedRepository are set in /etc/gitconfig or
~/.gitconfig, then 'git init' will read the values when constructing a
new config file; reading them, however, will override the values
specified on the command line. In the case of --bare, this ends up
causing a segfault, without the repository being properly initialised;
in the case of --shared, the permissions are set according to the
existing config settings, not what was specified on the command line.
This fix saves any specified values for --bare and --shared prior to
reading existing config settings, and restores them after reading but
before writing the new config file. core.bare is ignored in all
situations, while core.sharedRepository will only be used if --shared
is not specified to git init.
Also includes testcases which use a specified global config file
override, demonstrating the former failure scenario.
Signed-off-by: Deskin Miller <deskinm@umich.edu>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2008-10-07 09:37:48 +04:00
|
|
|
init_is_bare_repository = is_bare_repository();
|
|
|
|
|
2008-04-27 21:39:27 +04:00
|
|
|
/* Check to see if the repository version is right.
|
|
|
|
* Note that a newly created repository does not have
|
|
|
|
* config file, so this will not fail. What we are catching
|
|
|
|
* is an attempt to reinitialize new repository with an old tool.
|
|
|
|
*/
|
2020-02-22 23:17:38 +03:00
|
|
|
check_repository_format(&repo_fmt);
|
2008-04-27 21:39:27 +04:00
|
|
|
|
2020-02-22 23:17:38 +03:00
|
|
|
validate_hash_algorithm(&repo_fmt, hash);
|
|
|
|
|
2020-06-24 17:46:32 +03:00
|
|
|
reinit = create_default_files(template_dir, original_git_dir,
|
2020-12-11 14:36:56 +03:00
|
|
|
initial_branch, &repo_fmt,
|
|
|
|
flags & INIT_DB_QUIET);
|
2020-06-24 17:46:32 +03:00
|
|
|
if (reinit && initial_branch)
|
|
|
|
warning(_("re-init: ignored --initial-branch=%s"),
|
|
|
|
initial_branch);
|
2008-04-27 21:39:27 +04:00
|
|
|
|
2010-10-04 08:34:27 +04:00
|
|
|
create_object_directory();
|
2008-04-27 21:39:27 +04:00
|
|
|
|
2016-03-12 01:36:49 +03:00
|
|
|
if (get_shared_repository()) {
|
2008-04-27 21:39:27 +04:00
|
|
|
char buf[10];
|
|
|
|
/* We do not spell "group" and such, so that
|
|
|
|
* the configuration can be read by older version
|
|
|
|
* of git. Note, we use octal numbers for new share modes,
|
|
|
|
* and compatibility values for PERM_GROUP and
|
|
|
|
* PERM_EVERYBODY.
|
|
|
|
*/
|
2016-03-12 01:36:49 +03:00
|
|
|
if (get_shared_repository() < 0)
|
2009-03-26 02:19:36 +03:00
|
|
|
/* force to the mode value */
|
2016-03-12 01:36:49 +03:00
|
|
|
xsnprintf(buf, sizeof(buf), "0%o", -get_shared_repository());
|
|
|
|
else if (get_shared_repository() == PERM_GROUP)
|
2015-09-25 00:06:08 +03:00
|
|
|
xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_GROUP);
|
2016-03-12 01:36:49 +03:00
|
|
|
else if (get_shared_repository() == PERM_EVERYBODY)
|
2015-09-25 00:06:08 +03:00
|
|
|
xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY);
|
2008-04-27 21:39:27 +04:00
|
|
|
else
|
2018-05-02 12:38:39 +03:00
|
|
|
BUG("invalid value for shared_repository");
|
2016-02-22 14:23:36 +03:00
|
|
|
git_config_set("core.sharedrepository", buf);
|
|
|
|
git_config_set("receive.denyNonFastforwards", "true");
|
2008-04-27 21:39:27 +04:00
|
|
|
}
|
|
|
|
|
2010-02-14 18:44:42 +03:00
|
|
|
if (!(flags & INIT_DB_QUIET)) {
|
|
|
|
int len = strlen(git_dir);
|
2011-02-23 02:41:25 +03:00
|
|
|
|
2016-06-18 00:54:11 +03:00
|
|
|
if (reinit)
|
|
|
|
printf(get_shared_repository()
|
|
|
|
? _("Reinitialized existing shared Git repository in %s%s\n")
|
|
|
|
: _("Reinitialized existing Git repository in %s%s\n"),
|
|
|
|
git_dir, len && git_dir[len-1] != '/' ? "/" : "");
|
|
|
|
else
|
|
|
|
printf(get_shared_repository()
|
|
|
|
? _("Initialized empty shared Git repository in %s%s\n")
|
|
|
|
: _("Initialized empty Git repository in %s%s\n"),
|
|
|
|
git_dir, len && git_dir[len-1] != '/' ? "/" : "");
|
2010-02-14 18:44:42 +03:00
|
|
|
}
|
2008-04-27 21:39:27 +04:00
|
|
|
|
2016-09-25 06:14:39 +03:00
|
|
|
free(original_git_dir);
|
2008-04-27 21:39:27 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int guess_repository_type(const char *git_dir)
|
2007-08-27 11:58:06 +04:00
|
|
|
{
|
|
|
|
const char *slash;
|
2014-07-28 22:30:39 +04:00
|
|
|
char *cwd;
|
|
|
|
int cwd_is_git_dir;
|
2007-08-27 11:58:06 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* "GIT_DIR=. git init" is always bare.
|
|
|
|
* "GIT_DIR=`pwd` git init" too.
|
|
|
|
*/
|
|
|
|
if (!strcmp(".", git_dir))
|
2008-04-27 21:39:27 +04:00
|
|
|
return 1;
|
2014-07-28 22:30:39 +04:00
|
|
|
cwd = xgetcwd();
|
|
|
|
cwd_is_git_dir = !strcmp(git_dir, cwd);
|
|
|
|
free(cwd);
|
|
|
|
if (cwd_is_git_dir)
|
2008-04-27 21:39:27 +04:00
|
|
|
return 1;
|
2007-08-27 11:58:06 +04:00
|
|
|
/*
|
|
|
|
* "GIT_DIR=.git or GIT_DIR=something/.git is usually not.
|
|
|
|
*/
|
|
|
|
if (!strcmp(git_dir, ".git"))
|
2008-04-27 21:39:27 +04:00
|
|
|
return 0;
|
2007-08-27 11:58:06 +04:00
|
|
|
slash = strrchr(git_dir, '/');
|
|
|
|
if (slash && !strcmp(slash, "/.git"))
|
2008-04-27 21:39:27 +04:00
|
|
|
return 0;
|
2007-08-27 11:58:06 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise it is often bare. At this point
|
|
|
|
* we are just guessing.
|
|
|
|
*/
|
2008-04-27 21:39:27 +04:00
|
|
|
return 1;
|
2007-08-27 11:58:06 +04:00
|
|
|
}
|
|
|
|
|
2009-07-12 14:24:32 +04:00
|
|
|
static int shared_callback(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
assert NOARG/NONEG behavior of parse-options callbacks
When we define a parse-options callback, the flags we put in the option
struct must match what the callback expects. For example, a callback
which does not handle the "unset" parameter should only be used with
PARSE_OPT_NONEG. But since the callback and the option struct are not
defined next to each other, it's easy to get this wrong (as earlier
patches in this series show).
Fortunately, the compiler can help us here: compiling with
-Wunused-parameters can show us which callbacks ignore their "unset"
parameters (and likewise, ones that ignore "arg" expect to be triggered
with PARSE_OPT_NOARG).
But after we've inspected a callback and determined that all of its
callers use the right flags, what do we do next? We'd like to silence
the compiler warning, but do so in a way that will catch any wrong calls
in the future.
We can do that by actually checking those variables and asserting that
they match our expectations. Because this is such a common pattern,
we'll introduce some helper macros. The resulting messages aren't
as descriptive as we could make them, but the file/line information from
BUG() is enough to identify the problem (and anyway, the point is that
these should never be seen).
Each of the annotated callbacks in this patch triggers
-Wunused-parameters, and was manually inspected to make sure all callers
use the correct options (so none of these BUGs should be triggerable).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-05 09:45:42 +03:00
|
|
|
BUG_ON_OPT_NEG(unset);
|
2009-07-12 14:24:32 +04:00
|
|
|
*((int *) opt->value) = (arg) ? git_config_perm("arg", arg) : PERM_GROUP;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *const init_db_usage[] = {
|
2015-01-13 10:44:47 +03:00
|
|
|
N_("git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [<directory>]"),
|
2009-07-12 14:24:32 +04:00
|
|
|
NULL
|
|
|
|
};
|
2005-08-06 23:50:14 +04:00
|
|
|
|
2005-04-20 08:48:15 +04:00
|
|
|
/*
|
|
|
|
* If you want to, you can share the DB area with any number of branches.
|
|
|
|
* That has advantages: you can save space by sharing all the SHA1 objects.
|
|
|
|
* On the other hand, it might just make lookup slower and messier. You
|
|
|
|
* be the judge. The default case is to have one DB per managed directory.
|
|
|
|
*/
|
2006-07-29 09:44:25 +04:00
|
|
|
int cmd_init_db(int argc, const char **argv, const char *prefix)
|
2005-04-08 02:13:13 +04:00
|
|
|
{
|
2005-05-30 21:20:44 +04:00
|
|
|
const char *git_dir;
|
2011-03-19 18:16:56 +03:00
|
|
|
const char *real_git_dir = NULL;
|
2010-11-26 18:32:40 +03:00
|
|
|
const char *work_tree;
|
2006-05-19 14:03:57 +04:00
|
|
|
const char *template_dir = NULL;
|
2008-04-27 21:39:27 +04:00
|
|
|
unsigned int flags = 0;
|
2020-02-22 23:17:38 +03:00
|
|
|
const char *object_format = NULL;
|
2020-06-24 17:46:32 +03:00
|
|
|
const char *initial_branch = NULL;
|
2020-02-22 23:17:38 +03:00
|
|
|
int hash_algo = GIT_HASH_UNKNOWN;
|
2009-07-12 14:24:32 +04:00
|
|
|
const struct option init_db_options[] = {
|
2012-08-20 16:32:18 +04:00
|
|
|
OPT_STRING(0, "template", &template_dir, N_("template-directory"),
|
|
|
|
N_("directory from which templates will be used")),
|
2009-07-12 14:24:32 +04:00
|
|
|
OPT_SET_INT(0, "bare", &is_bare_repository_cfg,
|
2012-08-20 16:32:18 +04:00
|
|
|
N_("create a bare repository"), 1),
|
2009-07-12 14:24:32 +04:00
|
|
|
{ OPTION_CALLBACK, 0, "shared", &init_shared_repository,
|
2012-08-20 16:32:18 +04:00
|
|
|
N_("permissions"),
|
|
|
|
N_("specify that the git repository is to be shared amongst several users"),
|
2009-07-12 14:24:32 +04:00
|
|
|
PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0},
|
2012-08-20 16:32:18 +04:00
|
|
|
OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET),
|
|
|
|
OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
|
|
|
|
N_("separate git dir from working tree")),
|
2020-06-24 17:46:32 +03:00
|
|
|
OPT_STRING('b', "initial-branch", &initial_branch, N_("name"),
|
|
|
|
N_("override the name of the initial branch")),
|
2020-02-22 23:17:38 +03:00
|
|
|
OPT_STRING(0, "object-format", &object_format, N_("hash"),
|
|
|
|
N_("specify the hash algorithm to use")),
|
2009-07-12 14:24:32 +04:00
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
2009-08-05 23:39:33 +04:00
|
|
|
argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0);
|
|
|
|
|
init: disallow --separate-git-dir with bare repository
The purpose of "git init --separate-git-dir" is to separate the
repository from the worktree. This is true even when --separate-git-dir
is used on an existing worktree, in which case, it moves the .git/
subdirectory to a new location outside the worktree.
However, an outright bare repository (such as one created by "git init
--bare"), has no worktree, so using --separate-git-dir to separate it
from its non-existent worktree is nonsensical. Therefore, make it an
error to use --separate-git-dir on a bare repository.
Implementation note: "git init" considers a repository bare if told so
explicitly via --bare or if it guesses it to be so based upon
heuristics. In the explicit --bare case, a conflict with
--separate-git-dir is easy to detect early. In the guessed case,
however, the conflict can only be detected once "bareness" is guessed,
which happens after "git init" has begun creating the repository.
Technically, we can get by with a single late check which would cover
both cases, however, erroring out early, when possible, without leaving
detritus provides a better user experience.
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-08-10 01:53:16 +03:00
|
|
|
if (real_git_dir && is_bare_repository_cfg == 1)
|
|
|
|
die(_("--separate-git-dir and --bare are mutually exclusive"));
|
|
|
|
|
2011-03-19 18:16:56 +03:00
|
|
|
if (real_git_dir && !is_absolute_path(real_git_dir))
|
2017-03-08 18:43:40 +03:00
|
|
|
real_git_dir = real_pathdup(real_git_dir, 1);
|
2011-03-19 18:16:56 +03:00
|
|
|
|
2019-05-10 13:46:57 +03:00
|
|
|
if (template_dir && *template_dir && !is_absolute_path(template_dir))
|
|
|
|
template_dir = absolute_pathdup(template_dir);
|
|
|
|
|
2009-08-05 23:39:33 +04:00
|
|
|
if (argc == 1) {
|
2009-07-25 01:59:28 +04:00
|
|
|
int mkdir_tried = 0;
|
|
|
|
retry:
|
2009-08-05 23:39:33 +04:00
|
|
|
if (chdir(argv[0]) < 0) {
|
2009-07-25 01:59:28 +04:00
|
|
|
if (!mkdir_tried) {
|
|
|
|
int saved;
|
|
|
|
/*
|
|
|
|
* At this point we haven't read any configuration,
|
|
|
|
* and we know shared_repository should always be 0;
|
|
|
|
* but just in case we play safe.
|
|
|
|
*/
|
2016-03-12 01:36:49 +03:00
|
|
|
saved = get_shared_repository();
|
|
|
|
set_shared_repository(0);
|
2009-08-05 23:39:33 +04:00
|
|
|
switch (safe_create_leading_directories_const(argv[0])) {
|
2014-01-06 17:45:26 +04:00
|
|
|
case SCLD_OK:
|
|
|
|
case SCLD_PERMS:
|
|
|
|
break;
|
2014-01-06 17:45:25 +04:00
|
|
|
case SCLD_EXISTS:
|
2009-07-25 01:59:28 +04:00
|
|
|
errno = EEXIST;
|
|
|
|
/* fallthru */
|
|
|
|
default:
|
2014-01-06 17:45:26 +04:00
|
|
|
die_errno(_("cannot mkdir %s"), argv[0]);
|
2009-07-25 01:59:28 +04:00
|
|
|
break;
|
|
|
|
}
|
2016-03-12 01:36:49 +03:00
|
|
|
set_shared_repository(saved);
|
2009-08-05 23:39:33 +04:00
|
|
|
if (mkdir(argv[0], 0777) < 0)
|
2011-02-23 02:41:24 +03:00
|
|
|
die_errno(_("cannot mkdir %s"), argv[0]);
|
2009-07-25 01:59:28 +04:00
|
|
|
mkdir_tried = 1;
|
|
|
|
goto retry;
|
|
|
|
}
|
2011-02-23 02:41:24 +03:00
|
|
|
die_errno(_("cannot chdir to %s"), argv[0]);
|
2009-07-25 01:59:28 +04:00
|
|
|
}
|
2009-08-05 23:39:33 +04:00
|
|
|
} else if (0 < argc) {
|
|
|
|
usage(init_db_usage[0]);
|
2005-08-06 23:50:14 +04:00
|
|
|
}
|
2009-08-05 23:39:33 +04:00
|
|
|
if (is_bare_repository_cfg == 1) {
|
2014-07-28 22:31:57 +04:00
|
|
|
char *cwd = xgetcwd();
|
|
|
|
setenv(GIT_DIR_ENVIRONMENT, cwd, argc > 0);
|
|
|
|
free(cwd);
|
2005-08-06 23:50:14 +04:00
|
|
|
}
|
|
|
|
|
2020-02-22 23:17:38 +03:00
|
|
|
if (object_format) {
|
|
|
|
hash_algo = hash_algo_by_name(object_format);
|
|
|
|
if (hash_algo == GIT_HASH_UNKNOWN)
|
|
|
|
die(_("unknown hash algorithm '%s'"), object_format);
|
|
|
|
}
|
|
|
|
|
2009-03-26 02:19:36 +03:00
|
|
|
if (init_shared_repository != -1)
|
2016-03-12 01:36:49 +03:00
|
|
|
set_shared_repository(init_shared_repository);
|
2009-03-26 02:19:36 +03:00
|
|
|
|
2007-08-27 11:58:06 +04:00
|
|
|
/*
|
|
|
|
* GIT_WORK_TREE makes sense only in conjunction with GIT_DIR
|
|
|
|
* without --bare. Catch the error early.
|
|
|
|
*/
|
2019-01-12 01:16:31 +03:00
|
|
|
git_dir = xstrdup_or_null(getenv(GIT_DIR_ENVIRONMENT));
|
|
|
|
work_tree = xstrdup_or_null(getenv(GIT_WORK_TREE_ENVIRONMENT));
|
2010-11-26 18:32:40 +03:00
|
|
|
if ((!git_dir || is_bare_repository_cfg == 1) && work_tree)
|
2011-02-23 02:41:24 +03:00
|
|
|
die(_("%s (or --work-tree=<directory>) not allowed without "
|
|
|
|
"specifying %s (or --git-dir=<directory>)"),
|
2007-08-27 11:58:06 +04:00
|
|
|
GIT_WORK_TREE_ENVIRONMENT,
|
|
|
|
GIT_DIR_ENVIRONMENT);
|
|
|
|
|
2005-05-30 21:20:44 +04:00
|
|
|
/*
|
|
|
|
* Set up the default .git directory contents
|
|
|
|
*/
|
2006-12-15 08:44:58 +03:00
|
|
|
if (!git_dir)
|
2005-05-30 21:20:44 +04:00
|
|
|
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
|
2005-12-23 01:19:37 +03:00
|
|
|
|
2020-08-31 09:58:00 +03:00
|
|
|
/*
|
|
|
|
* When --separate-git-dir is used inside a linked worktree, take
|
|
|
|
* care to ensure that the common .git/ directory is relocated, not
|
|
|
|
* the worktree-specific .git/worktrees/<id>/ directory.
|
|
|
|
*/
|
|
|
|
if (real_git_dir) {
|
|
|
|
int err;
|
|
|
|
const char *p;
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
|
|
|
|
p = read_gitfile_gently(git_dir, &err);
|
|
|
|
if (p && get_common_dir(&sb, p)) {
|
|
|
|
struct strbuf mainwt = STRBUF_INIT;
|
|
|
|
|
|
|
|
strbuf_addbuf(&mainwt, &sb);
|
|
|
|
strbuf_strip_suffix(&mainwt, "/.git");
|
|
|
|
if (chdir(mainwt.buf) < 0)
|
|
|
|
die_errno(_("cannot chdir to %s"), mainwt.buf);
|
|
|
|
strbuf_release(&mainwt);
|
|
|
|
git_dir = strbuf_detach(&sb, NULL);
|
|
|
|
}
|
|
|
|
strbuf_release(&sb);
|
|
|
|
}
|
|
|
|
|
2008-04-27 21:39:27 +04:00
|
|
|
if (is_bare_repository_cfg < 0)
|
|
|
|
is_bare_repository_cfg = guess_repository_type(git_dir);
|
|
|
|
|
|
|
|
if (!is_bare_repository_cfg) {
|
2011-03-03 15:34:51 +03:00
|
|
|
const char *git_dir_parent = strrchr(git_dir, '/');
|
|
|
|
if (git_dir_parent) {
|
|
|
|
char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
|
2017-03-08 18:43:40 +03:00
|
|
|
git_work_tree_cfg = real_pathdup(rel, 1);
|
2011-03-03 15:34:51 +03:00
|
|
|
free(rel);
|
2008-04-27 21:39:27 +04:00
|
|
|
}
|
2014-07-28 22:30:39 +04:00
|
|
|
if (!git_work_tree_cfg)
|
|
|
|
git_work_tree_cfg = xgetcwd();
|
2010-11-26 18:32:40 +03:00
|
|
|
if (work_tree)
|
2014-07-28 22:42:05 +04:00
|
|
|
set_git_work_tree(work_tree);
|
2010-11-26 18:32:40 +03:00
|
|
|
else
|
|
|
|
set_git_work_tree(git_work_tree_cfg);
|
2008-04-27 21:39:27 +04:00
|
|
|
if (access(get_git_work_tree(), X_OK))
|
2011-02-23 02:41:24 +03:00
|
|
|
die_errno (_("Cannot access work tree '%s'"),
|
2009-06-27 19:58:47 +04:00
|
|
|
get_git_work_tree());
|
2006-06-10 10:09:49 +04:00
|
|
|
}
|
2010-11-26 18:32:40 +03:00
|
|
|
else {
|
init: disallow --separate-git-dir with bare repository
The purpose of "git init --separate-git-dir" is to separate the
repository from the worktree. This is true even when --separate-git-dir
is used on an existing worktree, in which case, it moves the .git/
subdirectory to a new location outside the worktree.
However, an outright bare repository (such as one created by "git init
--bare"), has no worktree, so using --separate-git-dir to separate it
from its non-existent worktree is nonsensical. Therefore, make it an
error to use --separate-git-dir on a bare repository.
Implementation note: "git init" considers a repository bare if told so
explicitly via --bare or if it guesses it to be so based upon
heuristics. In the explicit --bare case, a conflict with
--separate-git-dir is easy to detect early. In the guessed case,
however, the conflict can only be detected once "bareness" is guessed,
which happens after "git init" has begun creating the repository.
Technically, we can get by with a single late check which would cover
both cases, however, erroring out early, when possible, without leaving
detritus provides a better user experience.
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-08-10 01:53:16 +03:00
|
|
|
if (real_git_dir)
|
|
|
|
die(_("--separate-git-dir incompatible with bare repository"));
|
2010-11-26 18:32:40 +03:00
|
|
|
if (work_tree)
|
2014-07-28 22:42:05 +04:00
|
|
|
set_git_work_tree(work_tree);
|
2010-11-26 18:32:40 +03:00
|
|
|
}
|
2005-12-23 01:19:37 +03:00
|
|
|
|
add UNLEAK annotation for reducing leak false positives
It's a common pattern in git commands to allocate some
memory that should last for the lifetime of the program and
then not bother to free it, relying on the OS to throw it
away.
This keeps the code simple, and it's fast (we don't waste
time traversing structures or calling free at the end of the
program). But it also triggers warnings from memory-leak
checkers like valgrind or LSAN. They know that the memory
was still allocated at program exit, but they don't know
_when_ the leaked memory stopped being useful. If it was
early in the program, then it's probably a real and
important leak. But if it was used right up until program
exit, it's not an interesting leak and we'd like to suppress
it so that we can see the real leaks.
This patch introduces an UNLEAK() macro that lets us do so.
To understand its design, let's first look at some of the
alternatives.
Unfortunately the suppression systems offered by
leak-checking tools don't quite do what we want. A
leak-checker basically knows two things:
1. Which blocks were allocated via malloc, and the
callstack during the allocation.
2. Which blocks were left un-freed at the end of the
program (and which are unreachable, but more on that
later).
Their suppressions work by mentioning the function or
callstack of a particular allocation, and marking it as OK
to leak. So imagine you have code like this:
int cmd_foo(...)
{
/* this allocates some memory */
char *p = some_function();
printf("%s", p);
return 0;
}
You can say "ignore allocations from some_function(),
they're not leaks". But that's not right. That function may
be called elsewhere, too, and we would potentially want to
know about those leaks.
So you can say "ignore the callstack when main calls
some_function". That works, but your annotations are
brittle. In this case it's only two functions, but you can
imagine that the actual allocation is much deeper. If any of
the intermediate code changes, you have to update the
suppression.
What we _really_ want to say is that "the value assigned to
p at the end of the function is not a real leak". But
leak-checkers can't understand that; they don't know about
"p" in the first place.
However, we can do something a little bit tricky if we make
some assumptions about how leak-checkers work. They
generally don't just report all un-freed blocks. That would
report even globals which are still accessible when the
leak-check is run. Instead they take some set of memory
(like BSS) as a root and mark it as "reachable". Then they
scan the reachable blocks for anything that looks like a
pointer to a malloc'd block, and consider that block
reachable. And then they scan those blocks, and so on,
transitively marking anything reachable from a global as
"not leaked" (or at least leaked in a different category).
So we can mark the value of "p" as reachable by putting it
into a variable with program lifetime. One way to do that is
to just mark "p" as static. But that actually affects the
run-time behavior if the function is called twice (you
aren't likely to call main() twice, but some of our cmd_*()
functions are called from other commands).
Instead, we can trick the leak-checker by putting the value
into _any_ reachable bytes. This patch keeps a global
linked-list of bytes copied from "unleaked" variables. That
list is reachable even at program exit, which confers
recursive reachability on whatever values we unleak.
In other words, you can do:
int cmd_foo(...)
{
char *p = some_function();
printf("%s", p);
UNLEAK(p);
return 0;
}
to annotate "p" and suppress the leak report.
But wait, couldn't we just say "free(p)"? In this toy
example, yes. But UNLEAK()'s byte-copying strategy has
several advantages over actually freeing the memory:
1. It's recursive across structures. In many cases our "p"
is not just a pointer, but a complex struct whose
fields may have been allocated by a sub-function. And
in some cases (e.g., dir_struct) we don't even have a
function which knows how to free all of the struct
members.
By marking the struct itself as reachable, that confers
reachability on any pointers it contains (including those
found in embedded structs, or reachable by walking
heap blocks recursively.
2. It works on cases where we're not sure if the value is
allocated or not. For example:
char *p = argc > 1 ? argv[1] : some_function();
It's safe to use UNLEAK(p) here, because it's not
freeing any memory. In the case that we're pointing to
argv here, the reachability checker will just ignore
our bytes.
3. Likewise, it works even if the variable has _already_
been freed. We're just copying the pointer bytes. If
the block has been freed, the leak-checker will skip
over those bytes as uninteresting.
4. Because it's not actually freeing memory, you can
UNLEAK() before we are finished accessing the variable.
This is helpful in cases like this:
char *p = some_function();
return another_function(p);
Writing this with free() requires:
int ret;
char *p = some_function();
ret = another_function(p);
free(p);
return ret;
But with unleak we can just write:
char *p = some_function();
UNLEAK(p);
return another_function(p);
This patch adds the UNLEAK() macro and enables it
automatically when Git is compiled with SANITIZE=leak. In
normal builds it's a noop, so we pay no runtime cost.
It also adds some UNLEAK() annotations to show off how the
feature works. On top of other recent leak fixes, these are
enough to get t0000 and t0001 to pass when compiled with
LSAN.
Note the case in commit.c which actually converts a
strbuf_release() into an UNLEAK. This code was already
non-leaky, but the free didn't do anything useful, since
we're exiting. Converting it to an annotation means that
non-leak-checking builds pay no runtime cost. The cost is
minimal enough that it's probably not worth going on a
crusade to convert these kinds of frees to UNLEAKS. I did it
here for consistency with the "sb" leak (though it would
have been equally correct to go the other way, and turn them
both into strbuf_release() calls).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-09-08 09:38:41 +03:00
|
|
|
UNLEAK(real_git_dir);
|
2019-01-12 01:16:31 +03:00
|
|
|
UNLEAK(git_dir);
|
|
|
|
UNLEAK(work_tree);
|
add UNLEAK annotation for reducing leak false positives
It's a common pattern in git commands to allocate some
memory that should last for the lifetime of the program and
then not bother to free it, relying on the OS to throw it
away.
This keeps the code simple, and it's fast (we don't waste
time traversing structures or calling free at the end of the
program). But it also triggers warnings from memory-leak
checkers like valgrind or LSAN. They know that the memory
was still allocated at program exit, but they don't know
_when_ the leaked memory stopped being useful. If it was
early in the program, then it's probably a real and
important leak. But if it was used right up until program
exit, it's not an interesting leak and we'd like to suppress
it so that we can see the real leaks.
This patch introduces an UNLEAK() macro that lets us do so.
To understand its design, let's first look at some of the
alternatives.
Unfortunately the suppression systems offered by
leak-checking tools don't quite do what we want. A
leak-checker basically knows two things:
1. Which blocks were allocated via malloc, and the
callstack during the allocation.
2. Which blocks were left un-freed at the end of the
program (and which are unreachable, but more on that
later).
Their suppressions work by mentioning the function or
callstack of a particular allocation, and marking it as OK
to leak. So imagine you have code like this:
int cmd_foo(...)
{
/* this allocates some memory */
char *p = some_function();
printf("%s", p);
return 0;
}
You can say "ignore allocations from some_function(),
they're not leaks". But that's not right. That function may
be called elsewhere, too, and we would potentially want to
know about those leaks.
So you can say "ignore the callstack when main calls
some_function". That works, but your annotations are
brittle. In this case it's only two functions, but you can
imagine that the actual allocation is much deeper. If any of
the intermediate code changes, you have to update the
suppression.
What we _really_ want to say is that "the value assigned to
p at the end of the function is not a real leak". But
leak-checkers can't understand that; they don't know about
"p" in the first place.
However, we can do something a little bit tricky if we make
some assumptions about how leak-checkers work. They
generally don't just report all un-freed blocks. That would
report even globals which are still accessible when the
leak-check is run. Instead they take some set of memory
(like BSS) as a root and mark it as "reachable". Then they
scan the reachable blocks for anything that looks like a
pointer to a malloc'd block, and consider that block
reachable. And then they scan those blocks, and so on,
transitively marking anything reachable from a global as
"not leaked" (or at least leaked in a different category).
So we can mark the value of "p" as reachable by putting it
into a variable with program lifetime. One way to do that is
to just mark "p" as static. But that actually affects the
run-time behavior if the function is called twice (you
aren't likely to call main() twice, but some of our cmd_*()
functions are called from other commands).
Instead, we can trick the leak-checker by putting the value
into _any_ reachable bytes. This patch keeps a global
linked-list of bytes copied from "unleaked" variables. That
list is reachable even at program exit, which confers
recursive reachability on whatever values we unleak.
In other words, you can do:
int cmd_foo(...)
{
char *p = some_function();
printf("%s", p);
UNLEAK(p);
return 0;
}
to annotate "p" and suppress the leak report.
But wait, couldn't we just say "free(p)"? In this toy
example, yes. But UNLEAK()'s byte-copying strategy has
several advantages over actually freeing the memory:
1. It's recursive across structures. In many cases our "p"
is not just a pointer, but a complex struct whose
fields may have been allocated by a sub-function. And
in some cases (e.g., dir_struct) we don't even have a
function which knows how to free all of the struct
members.
By marking the struct itself as reachable, that confers
reachability on any pointers it contains (including those
found in embedded structs, or reachable by walking
heap blocks recursively.
2. It works on cases where we're not sure if the value is
allocated or not. For example:
char *p = argc > 1 ? argv[1] : some_function();
It's safe to use UNLEAK(p) here, because it's not
freeing any memory. In the case that we're pointing to
argv here, the reachability checker will just ignore
our bytes.
3. Likewise, it works even if the variable has _already_
been freed. We're just copying the pointer bytes. If
the block has been freed, the leak-checker will skip
over those bytes as uninteresting.
4. Because it's not actually freeing memory, you can
UNLEAK() before we are finished accessing the variable.
This is helpful in cases like this:
char *p = some_function();
return another_function(p);
Writing this with free() requires:
int ret;
char *p = some_function();
ret = another_function(p);
free(p);
return ret;
But with unleak we can just write:
char *p = some_function();
UNLEAK(p);
return another_function(p);
This patch adds the UNLEAK() macro and enables it
automatically when Git is compiled with SANITIZE=leak. In
normal builds it's a noop, so we pay no runtime cost.
It also adds some UNLEAK() annotations to show off how the
feature works. On top of other recent leak fixes, these are
enough to get t0000 and t0001 to pass when compiled with
LSAN.
Note the case in commit.c which actually converts a
strbuf_release() into an UNLEAK. This code was already
non-leaky, but the free didn't do anything useful, since
we're exiting. Converting it to an annotation means that
non-leak-checking builds pay no runtime cost. The cost is
minimal enough that it's probably not worth going on a
crusade to convert these kinds of frees to UNLEAKS. I did it
here for consistency with the "sb" leak (though it would
have been equally correct to go the other way, and turn them
both into strbuf_release() calls).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-09-08 09:38:41 +03:00
|
|
|
|
2016-09-25 06:14:37 +03:00
|
|
|
flags |= INIT_DB_EXIST_OK;
|
2020-06-24 17:46:32 +03:00
|
|
|
return init_db(git_dir, real_git_dir, template_dir, hash_algo,
|
|
|
|
initial_branch, flags);
|
2005-04-08 02:13:13 +04:00
|
|
|
}
|