git
/
repository.c
415 строк · 10.8 Кб
1#include "git-compat-util.h"2#include "abspath.h"3#include "repository.h"4#include "object-store-ll.h"5#include "config.h"6#include "object.h"7#include "lockfile.h"8#include "path.h"9#include "read-cache-ll.h"10#include "remote.h"11#include "setup.h"12#include "loose.h"13#include "submodule-config.h"14#include "sparse-index.h"15#include "trace2.h"16#include "promisor-remote.h"17#include "refs.h"18
19/*
20* We do not define `USE_THE_REPOSITORY_VARIABLE` in this file because we do
21* not want to rely on functions that implicitly use `the_repository`. This
22* means that the `extern` declaration of `the_repository` isn't visible here,
23* which makes sparse unhappy. We thus declare it here.
24*/
25extern struct repository *the_repository;26
27/* The main repository */
28static struct repository the_repo;29struct repository *the_repository = &the_repo;30
31/*
32* An escape hatch: if we hit a bug in the production code that fails
33* to set an appropriate hash algorithm (most likely to happen when
34* running outside a repository), we can tell the user who reported
35* the crash to set the environment variable to "sha1" (all lowercase)
36* to revert to the historical behaviour of defaulting to SHA-1.
37*/
38static void set_default_hash_algo(struct repository *repo)39{
40const char *hash_name;41int algo;42
43hash_name = getenv("GIT_TEST_DEFAULT_HASH_ALGO");44if (!hash_name)45return;46algo = hash_algo_by_name(hash_name);47if (algo == GIT_HASH_UNKNOWN)48return;49
50repo_set_hash_algo(repo, algo);51}
52
53void initialize_repository(struct repository *repo)54{
55repo->objects = raw_object_store_new();56repo->remote_state = remote_state_new();57repo->parsed_objects = parsed_object_pool_new();58ALLOC_ARRAY(repo->index, 1);59index_state_init(repo->index, repo);60
61/*62* When a command runs inside a repository, it learns what
63* hash algorithm is in use from the repository, but some
64* commands are designed to work outside a repository, yet
65* they want to access the_hash_algo, if only for the length
66* of the hashed value to see if their input looks like a
67* plausible hash value.
68*
69* We are in the process of identifying such code paths and
70* giving them an appropriate default individually; any
71* unconverted code paths that try to access the_hash_algo
72* will thus fail. The end-users however have an escape hatch
73* to set GIT_TEST_DEFAULT_HASH_ALGO environment variable to
74* "sha1" to get back the old behaviour of defaulting to SHA-1.
75*
76* This escape hatch is deliberately kept unadvertised, so
77* that they see crashes and we can get a report before
78* telling them about it.
79*/
80if (repo == the_repository)81set_default_hash_algo(repo);82}
83
84static void expand_base_dir(char **out, const char *in,85const char *base_dir, const char *def_in)86{
87free(*out);88if (in)89*out = xstrdup(in);90else91*out = xstrfmt("%s/%s", base_dir, def_in);92}
93
94static void repo_set_commondir(struct repository *repo,95const char *commondir)96{
97struct strbuf sb = STRBUF_INIT;98
99free(repo->commondir);100
101if (commondir) {102repo->different_commondir = 1;103repo->commondir = xstrdup(commondir);104return;105}106
107repo->different_commondir = get_common_dir_noenv(&sb, repo->gitdir);108repo->commondir = strbuf_detach(&sb, NULL);109}
110
111void repo_set_gitdir(struct repository *repo,112const char *root,113const struct set_gitdir_args *o)114{
115const char *gitfile = read_gitfile(root);116/*117* repo->gitdir is saved because the caller could pass "root"
118* that also points to repo->gitdir. We want to keep it alive
119* until after xstrdup(root). Then we can free it.
120*/
121char *old_gitdir = repo->gitdir;122
123repo->gitdir = xstrdup(gitfile ? gitfile : root);124free(old_gitdir);125
126repo_set_commondir(repo, o->commondir);127
128if (!repo->objects->odb) {129CALLOC_ARRAY(repo->objects->odb, 1);130repo->objects->odb_tail = &repo->objects->odb->next;131}132expand_base_dir(&repo->objects->odb->path, o->object_dir,133repo->commondir, "objects");134
135repo->objects->odb->disable_ref_updates = o->disable_ref_updates;136
137free(repo->objects->alternate_db);138repo->objects->alternate_db = xstrdup_or_null(o->alternate_db);139expand_base_dir(&repo->graft_file, o->graft_file,140repo->commondir, "info/grafts");141expand_base_dir(&repo->index_file, o->index_file,142repo->gitdir, "index");143}
144
145void repo_set_hash_algo(struct repository *repo, int hash_algo)146{
147repo->hash_algo = &hash_algos[hash_algo];148}
149
150void repo_set_compat_hash_algo(struct repository *repo, int algo)151{
152if (hash_algo_by_ptr(repo->hash_algo) == algo)153BUG("hash_algo and compat_hash_algo match");154repo->compat_hash_algo = algo ? &hash_algos[algo] : NULL;155if (repo->compat_hash_algo)156repo_read_loose_object_map(repo);157}
158
159void repo_set_ref_storage_format(struct repository *repo,160enum ref_storage_format format)161{
162repo->ref_storage_format = format;163}
164
165/*
166* Attempt to resolve and set the provided 'gitdir' for repository 'repo'.
167* Return 0 upon success and a non-zero value upon failure.
168*/
169static int repo_init_gitdir(struct repository *repo, const char *gitdir)170{
171int ret = 0;172int error = 0;173char *abspath = NULL;174const char *resolved_gitdir;175struct set_gitdir_args args = { NULL };176
177abspath = real_pathdup(gitdir, 0);178if (!abspath) {179ret = -1;180goto out;181}182
183/* 'gitdir' must reference the gitdir directly */184resolved_gitdir = resolve_gitdir_gently(abspath, &error);185if (!resolved_gitdir) {186ret = -1;187goto out;188}189
190repo_set_gitdir(repo, resolved_gitdir, &args);191
192out:193free(abspath);194return ret;195}
196
197void repo_set_worktree(struct repository *repo, const char *path)198{
199repo->worktree = real_pathdup(path, 1);200
201trace2_def_repo(repo);202}
203
204static int read_and_verify_repository_format(struct repository_format *format,205const char *commondir)206{
207int ret = 0;208struct strbuf sb = STRBUF_INIT;209
210strbuf_addf(&sb, "%s/config", commondir);211read_repository_format(format, sb.buf);212strbuf_reset(&sb);213
214if (verify_repository_format(format, &sb) < 0) {215warning("%s", sb.buf);216ret = -1;217}218
219strbuf_release(&sb);220return ret;221}
222
223/*
224* Initialize 'repo' based on the provided 'gitdir'.
225* Return 0 upon success and a non-zero value upon failure.
226*/
227int repo_init(struct repository *repo,228const char *gitdir,229const char *worktree)230{
231struct repository_format format = REPOSITORY_FORMAT_INIT;232memset(repo, 0, sizeof(*repo));233
234initialize_repository(repo);235
236if (repo_init_gitdir(repo, gitdir))237goto error;238
239if (read_and_verify_repository_format(&format, repo->commondir))240goto error;241
242repo_set_hash_algo(repo, format.hash_algo);243repo_set_compat_hash_algo(repo, format.compat_hash_algo);244repo_set_ref_storage_format(repo, format.ref_storage_format);245repo->repository_format_worktree_config = format.worktree_config;246
247/* take ownership of format.partial_clone */248repo->repository_format_partial_clone = format.partial_clone;249format.partial_clone = NULL;250
251if (worktree)252repo_set_worktree(repo, worktree);253
254if (repo->compat_hash_algo)255repo_read_loose_object_map(repo);256
257clear_repository_format(&format);258return 0;259
260error:261repo_clear(repo);262return -1;263}
264
265int repo_submodule_init(struct repository *subrepo,266struct repository *superproject,267const char *path,268const struct object_id *treeish_name)269{
270struct strbuf gitdir = STRBUF_INIT;271struct strbuf worktree = STRBUF_INIT;272int ret = 0;273
274strbuf_repo_worktree_path(&gitdir, superproject, "%s/.git", path);275strbuf_repo_worktree_path(&worktree, superproject, "%s", path);276
277if (repo_init(subrepo, gitdir.buf, worktree.buf)) {278/*279* If initialization fails then it may be due to the submodule
280* not being populated in the superproject's worktree. Instead
281* we can try to initialize the submodule by finding it's gitdir
282* in the superproject's 'modules' directory. In this case the
283* submodule would not have a worktree.
284*/
285const struct submodule *sub =286submodule_from_path(superproject, treeish_name, path);287if (!sub) {288ret = -1;289goto out;290}291
292strbuf_reset(&gitdir);293submodule_name_to_gitdir(&gitdir, superproject, sub->name);294
295if (repo_init(subrepo, gitdir.buf, NULL)) {296ret = -1;297goto out;298}299}300
301subrepo->submodule_prefix = xstrfmt("%s%s/",302superproject->submodule_prefix ?303superproject->submodule_prefix :304"", path);305
306out:307strbuf_release(&gitdir);308strbuf_release(&worktree);309return ret;310}
311
312static void repo_clear_path_cache(struct repo_path_cache *cache)313{
314FREE_AND_NULL(cache->squash_msg);315FREE_AND_NULL(cache->squash_msg);316FREE_AND_NULL(cache->merge_msg);317FREE_AND_NULL(cache->merge_rr);318FREE_AND_NULL(cache->merge_mode);319FREE_AND_NULL(cache->merge_head);320FREE_AND_NULL(cache->fetch_head);321FREE_AND_NULL(cache->shallow);322}
323
324void repo_clear(struct repository *repo)325{
326struct hashmap_iter iter;327struct strmap_entry *e;328
329FREE_AND_NULL(repo->gitdir);330FREE_AND_NULL(repo->commondir);331FREE_AND_NULL(repo->graft_file);332FREE_AND_NULL(repo->index_file);333FREE_AND_NULL(repo->worktree);334FREE_AND_NULL(repo->submodule_prefix);335
336raw_object_store_clear(repo->objects);337FREE_AND_NULL(repo->objects);338
339parsed_object_pool_clear(repo->parsed_objects);340FREE_AND_NULL(repo->parsed_objects);341
342FREE_AND_NULL(repo->settings.fsmonitor);343
344if (repo->config) {345git_configset_clear(repo->config);346FREE_AND_NULL(repo->config);347}348
349if (repo->submodule_cache) {350submodule_cache_free(repo->submodule_cache);351repo->submodule_cache = NULL;352}353
354if (repo->index) {355discard_index(repo->index);356FREE_AND_NULL(repo->index);357}358
359if (repo->promisor_remote_config) {360promisor_remote_clear(repo->promisor_remote_config);361FREE_AND_NULL(repo->promisor_remote_config);362}363
364if (repo->remote_state) {365remote_state_clear(repo->remote_state);366FREE_AND_NULL(repo->remote_state);367}368
369strmap_for_each_entry(&repo->submodule_ref_stores, &iter, e)370ref_store_release(e->value);371strmap_clear(&repo->submodule_ref_stores, 1);372
373strmap_for_each_entry(&repo->worktree_ref_stores, &iter, e)374ref_store_release(e->value);375strmap_clear(&repo->worktree_ref_stores, 1);376
377repo_clear_path_cache(&repo->cached_paths);378}
379
380int repo_read_index(struct repository *repo)381{
382int res;383
384/* Complete the double-reference */385if (!repo->index) {386ALLOC_ARRAY(repo->index, 1);387index_state_init(repo->index, repo);388} else if (repo->index->repo != repo) {389BUG("repo's index should point back at itself");390}391
392res = read_index_from(repo->index, repo->index_file, repo->gitdir);393
394prepare_repo_settings(repo);395if (repo->settings.command_requires_full_index)396ensure_full_index(repo->index);397
398/*399* If sparse checkouts are in use, check whether paths with the
400* SKIP_WORKTREE attribute are missing from the worktree; if not,
401* clear that attribute for that path.
402*/
403clear_skip_worktree_from_present_files(repo->index);404
405return res;406}
407
408int repo_hold_locked_index(struct repository *repo,409struct lock_file *lf,410int flags)411{
412if (!repo->index_file)413BUG("the repo hasn't been setup");414return hold_lock_file_for_update(lf, repo->index_file, flags);415}
416