зеркало из https://github.com/microsoft/git.git
Merge branch 'bw/repo-object'
Introduce a "repository" object to eventually make it easier to work in multiple repositories (the primary focus is to work with the superproject and its submodules) in a single process. * bw/repo-object: ls-files: use repository object repository: enable initialization of submodules submodule: convert is_submodule_initialized to work on a repository submodule: add repo_read_gitmodules submodule-config: store the_submodule_cache in the_repository repository: add index_state to struct repo config: read config from a repository object path: add repo_worktree_path and strbuf_repo_worktree_path path: add repo_git_path and strbuf_repo_git_path path: worktree_git_path() should not use file relocation path: convert do_git_path to take a 'struct repository' path: convert strbuf_git_common_path to take a 'struct repository' path: always pass in commondir to update_common_dir path: create path.h environment: store worktree in the_repository environment: place key repository state in the_repository repository: introduce the repository object environment: remove namespace_len variable setup: add comment indicating a hack setup: don't perform lazy initialization of repository state
This commit is contained in:
Коммит
85ce4a6828
1
Makefile
1
Makefile
|
@ -840,6 +840,7 @@ LIB_OBJS += refs/ref-cache.o
|
|||
LIB_OBJS += ref-filter.o
|
||||
LIB_OBJS += remote.o
|
||||
LIB_OBJS += replace_object.o
|
||||
LIB_OBJS += repository.o
|
||||
LIB_OBJS += rerere.o
|
||||
LIB_OBJS += resolve-undo.o
|
||||
LIB_OBJS += revision.o
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* Copyright (c) 2006 Junio C Hamano
|
||||
*/
|
||||
#include "cache.h"
|
||||
#include "repository.h"
|
||||
#include "config.h"
|
||||
#include "blob.h"
|
||||
#include "tree.h"
|
||||
|
@ -643,7 +644,7 @@ static int grep_submodule_launch(struct grep_opt *opt,
|
|||
static int grep_submodule(struct grep_opt *opt, const struct object_id *oid,
|
||||
const char *filename, const char *path)
|
||||
{
|
||||
if (!is_submodule_initialized(path))
|
||||
if (!is_submodule_active(the_repository, path))
|
||||
return 0;
|
||||
if (!is_submodule_populated_gently(path, NULL)) {
|
||||
/*
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
*
|
||||
* Copyright (C) Linus Torvalds, 2005
|
||||
*/
|
||||
#define NO_THE_INDEX_COMPATIBILITY_MACROS
|
||||
#include "cache.h"
|
||||
#include "repository.h"
|
||||
#include "config.h"
|
||||
#include "quote.h"
|
||||
#include "dir.h"
|
||||
|
@ -32,10 +34,8 @@ static int line_terminator = '\n';
|
|||
static int debug_mode;
|
||||
static int show_eol;
|
||||
static int recurse_submodules;
|
||||
static struct argv_array submodule_options = ARGV_ARRAY_INIT;
|
||||
|
||||
static const char *prefix;
|
||||
static const char *super_prefix;
|
||||
static int max_prefix_len;
|
||||
static int prefix_len;
|
||||
static struct pathspec pathspec;
|
||||
|
@ -73,25 +73,12 @@ static void write_eolinfo(const struct index_state *istate,
|
|||
|
||||
static void write_name(const char *name)
|
||||
{
|
||||
/*
|
||||
* Prepend the super_prefix to name to construct the full_name to be
|
||||
* written.
|
||||
*/
|
||||
struct strbuf full_name = STRBUF_INIT;
|
||||
if (super_prefix) {
|
||||
strbuf_addstr(&full_name, super_prefix);
|
||||
strbuf_addstr(&full_name, name);
|
||||
name = full_name.buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* With "--full-name", prefix_len=0; this caller needs to pass
|
||||
* an empty string in that case (a NULL is good for "").
|
||||
*/
|
||||
write_name_quoted_relative(name, prefix_len ? prefix : NULL,
|
||||
stdout, line_terminator);
|
||||
|
||||
strbuf_release(&full_name);
|
||||
}
|
||||
|
||||
static const char *get_tag(const struct cache_entry *ce, const char *tag)
|
||||
|
@ -210,83 +197,38 @@ static void show_killed_files(const struct index_state *istate,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compile an argv_array with all of the options supported by --recurse_submodules
|
||||
*/
|
||||
static void compile_submodule_options(const char **argv,
|
||||
const struct dir_struct *dir,
|
||||
int show_tag)
|
||||
{
|
||||
if (line_terminator == '\0')
|
||||
argv_array_push(&submodule_options, "-z");
|
||||
if (show_tag)
|
||||
argv_array_push(&submodule_options, "-t");
|
||||
if (show_valid_bit)
|
||||
argv_array_push(&submodule_options, "-v");
|
||||
if (show_cached)
|
||||
argv_array_push(&submodule_options, "--cached");
|
||||
if (show_eol)
|
||||
argv_array_push(&submodule_options, "--eol");
|
||||
if (debug_mode)
|
||||
argv_array_push(&submodule_options, "--debug");
|
||||
static void show_files(struct repository *repo, struct dir_struct *dir);
|
||||
|
||||
/* Add Pathspecs */
|
||||
argv_array_push(&submodule_options, "--");
|
||||
for (; *argv; argv++)
|
||||
argv_array_push(&submodule_options, *argv);
|
||||
static void show_submodule(struct repository *superproject,
|
||||
struct dir_struct *dir, const char *path)
|
||||
{
|
||||
struct repository submodule;
|
||||
|
||||
if (repo_submodule_init(&submodule, superproject, path))
|
||||
return;
|
||||
|
||||
if (repo_read_index(&submodule) < 0)
|
||||
die("index file corrupt");
|
||||
|
||||
repo_read_gitmodules(&submodule);
|
||||
|
||||
show_files(&submodule, dir);
|
||||
|
||||
repo_clear(&submodule);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively call ls-files on a submodule
|
||||
*/
|
||||
static void show_gitlink(const struct cache_entry *ce)
|
||||
static void show_ce(struct repository *repo, struct dir_struct *dir,
|
||||
const struct cache_entry *ce, const char *fullname,
|
||||
const char *tag)
|
||||
{
|
||||
struct child_process cp = CHILD_PROCESS_INIT;
|
||||
int status;
|
||||
char *dir;
|
||||
|
||||
prepare_submodule_repo_env(&cp.env_array);
|
||||
argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT);
|
||||
|
||||
if (prefix_len)
|
||||
argv_array_pushf(&cp.env_array, "%s=%s",
|
||||
GIT_TOPLEVEL_PREFIX_ENVIRONMENT,
|
||||
prefix);
|
||||
argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
|
||||
super_prefix ? super_prefix : "",
|
||||
ce->name);
|
||||
argv_array_push(&cp.args, "ls-files");
|
||||
argv_array_push(&cp.args, "--recurse-submodules");
|
||||
|
||||
/* add supported options */
|
||||
argv_array_pushv(&cp.args, submodule_options.argv);
|
||||
|
||||
cp.git_cmd = 1;
|
||||
dir = mkpathdup("%s/%s", get_git_work_tree(), ce->name);
|
||||
cp.dir = dir;
|
||||
status = run_command(&cp);
|
||||
free(dir);
|
||||
if (status)
|
||||
exit(status);
|
||||
}
|
||||
|
||||
static void show_ce_entry(const struct index_state *istate,
|
||||
const char *tag, const struct cache_entry *ce)
|
||||
{
|
||||
struct strbuf name = STRBUF_INIT;
|
||||
int len = max_prefix_len;
|
||||
if (super_prefix)
|
||||
strbuf_addstr(&name, super_prefix);
|
||||
strbuf_addstr(&name, ce->name);
|
||||
|
||||
if (len > ce_namelen(ce))
|
||||
if (max_prefix_len > strlen(fullname))
|
||||
die("git ls-files: internal error - cache entry not superset of prefix");
|
||||
|
||||
if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
|
||||
submodule_path_match(&pathspec, name.buf, ps_matched)) {
|
||||
show_gitlink(ce);
|
||||
} else if (match_pathspec(&pathspec, name.buf, name.len,
|
||||
len, ps_matched,
|
||||
is_submodule_active(repo, ce->name)) {
|
||||
show_submodule(repo, dir, ce->name);
|
||||
} else if (match_pathspec(&pathspec, fullname, strlen(fullname),
|
||||
max_prefix_len, ps_matched,
|
||||
S_ISDIR(ce->ce_mode) ||
|
||||
S_ISGITLINK(ce->ce_mode))) {
|
||||
tag = get_tag(ce, tag);
|
||||
|
@ -300,12 +242,10 @@ static void show_ce_entry(const struct index_state *istate,
|
|||
find_unique_abbrev(ce->oid.hash, abbrev),
|
||||
ce_stage(ce));
|
||||
}
|
||||
write_eolinfo(istate, ce, ce->name);
|
||||
write_name(ce->name);
|
||||
write_eolinfo(repo->index, ce, fullname);
|
||||
write_name(fullname);
|
||||
print_debug(ce);
|
||||
}
|
||||
|
||||
strbuf_release(&name);
|
||||
}
|
||||
|
||||
static void show_ru_info(const struct index_state *istate)
|
||||
|
@ -338,59 +278,79 @@ static void show_ru_info(const struct index_state *istate)
|
|||
}
|
||||
|
||||
static int ce_excluded(struct dir_struct *dir, struct index_state *istate,
|
||||
const struct cache_entry *ce)
|
||||
const char *fullname, const struct cache_entry *ce)
|
||||
{
|
||||
int dtype = ce_to_dtype(ce);
|
||||
return is_excluded(dir, istate, ce->name, &dtype);
|
||||
return is_excluded(dir, istate, fullname, &dtype);
|
||||
}
|
||||
|
||||
static void show_files(struct index_state *istate, struct dir_struct *dir)
|
||||
static void construct_fullname(struct strbuf *out, const struct repository *repo,
|
||||
const struct cache_entry *ce)
|
||||
{
|
||||
strbuf_reset(out);
|
||||
if (repo->submodule_prefix)
|
||||
strbuf_addstr(out, repo->submodule_prefix);
|
||||
strbuf_addstr(out, ce->name);
|
||||
}
|
||||
|
||||
static void show_files(struct repository *repo, struct dir_struct *dir)
|
||||
{
|
||||
int i;
|
||||
struct strbuf fullname = STRBUF_INIT;
|
||||
|
||||
/* For cached/deleted files we don't need to even do the readdir */
|
||||
if (show_others || show_killed) {
|
||||
if (!show_others)
|
||||
dir->flags |= DIR_COLLECT_KILLED_ONLY;
|
||||
fill_directory(dir, istate, &pathspec);
|
||||
fill_directory(dir, repo->index, &pathspec);
|
||||
if (show_others)
|
||||
show_other_files(istate, dir);
|
||||
show_other_files(repo->index, dir);
|
||||
if (show_killed)
|
||||
show_killed_files(istate, dir);
|
||||
show_killed_files(repo->index, dir);
|
||||
}
|
||||
if (show_cached || show_stage) {
|
||||
for (i = 0; i < istate->cache_nr; i++) {
|
||||
const struct cache_entry *ce = istate->cache[i];
|
||||
for (i = 0; i < repo->index->cache_nr; i++) {
|
||||
const struct cache_entry *ce = repo->index->cache[i];
|
||||
|
||||
construct_fullname(&fullname, repo, ce);
|
||||
|
||||
if ((dir->flags & DIR_SHOW_IGNORED) &&
|
||||
!ce_excluded(dir, istate, ce))
|
||||
!ce_excluded(dir, repo->index, fullname.buf, ce))
|
||||
continue;
|
||||
if (show_unmerged && !ce_stage(ce))
|
||||
continue;
|
||||
if (ce->ce_flags & CE_UPDATE)
|
||||
continue;
|
||||
show_ce_entry(istate, ce_stage(ce) ? tag_unmerged :
|
||||
(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);
|
||||
show_ce(repo, dir, ce, fullname.buf,
|
||||
ce_stage(ce) ? tag_unmerged :
|
||||
(ce_skip_worktree(ce) ? tag_skip_worktree :
|
||||
tag_cached));
|
||||
}
|
||||
}
|
||||
if (show_deleted || show_modified) {
|
||||
for (i = 0; i < istate->cache_nr; i++) {
|
||||
const struct cache_entry *ce = istate->cache[i];
|
||||
for (i = 0; i < repo->index->cache_nr; i++) {
|
||||
const struct cache_entry *ce = repo->index->cache[i];
|
||||
struct stat st;
|
||||
int err;
|
||||
|
||||
construct_fullname(&fullname, repo, ce);
|
||||
|
||||
if ((dir->flags & DIR_SHOW_IGNORED) &&
|
||||
!ce_excluded(dir, istate, ce))
|
||||
!ce_excluded(dir, repo->index, fullname.buf, ce))
|
||||
continue;
|
||||
if (ce->ce_flags & CE_UPDATE)
|
||||
continue;
|
||||
if (ce_skip_worktree(ce))
|
||||
continue;
|
||||
err = lstat(ce->name, &st);
|
||||
err = lstat(fullname.buf, &st);
|
||||
if (show_deleted && err)
|
||||
show_ce_entry(istate, tag_removed, ce);
|
||||
if (show_modified && ie_modified(istate, ce, &st, 0))
|
||||
show_ce_entry(istate, tag_modified, ce);
|
||||
show_ce(repo, dir, ce, fullname.buf, tag_removed);
|
||||
if (show_modified && ie_modified(repo->index, ce, &st, 0))
|
||||
show_ce(repo, dir, ce, fullname.buf, tag_modified);
|
||||
}
|
||||
}
|
||||
|
||||
strbuf_release(&fullname);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -615,10 +575,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
|
|||
prefix = cmd_prefix;
|
||||
if (prefix)
|
||||
prefix_len = strlen(prefix);
|
||||
super_prefix = get_super_prefix();
|
||||
git_config(git_default_config, NULL);
|
||||
|
||||
if (read_cache() < 0)
|
||||
if (repo_read_index(the_repository) < 0)
|
||||
die("index file corrupt");
|
||||
|
||||
argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
|
||||
|
@ -652,7 +611,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
|
|||
setup_work_tree();
|
||||
|
||||
if (recurse_submodules)
|
||||
compile_submodule_options(argv, &dir, show_tag);
|
||||
repo_read_gitmodules(the_repository);
|
||||
|
||||
if (recurse_submodules &&
|
||||
(show_stage || show_deleted || show_others || show_unmerged ||
|
||||
|
@ -670,7 +629,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
|
|||
/*
|
||||
* Find common prefix for all pathspec's
|
||||
* This is used as a performance optimization which unfortunately cannot
|
||||
* be done when recursing into submodules
|
||||
* be done when recursing into submodules because when a pathspec is
|
||||
* given which spans repository boundaries you can't simply remove the
|
||||
* submodule entry because the pathspec may match something inside the
|
||||
* submodule.
|
||||
*/
|
||||
if (recurse_submodules)
|
||||
max_prefix = NULL;
|
||||
|
@ -678,7 +640,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
|
|||
max_prefix = common_prefix(&pathspec);
|
||||
max_prefix_len = get_common_prefix_len(max_prefix);
|
||||
|
||||
prune_index(&the_index, max_prefix, max_prefix_len);
|
||||
prune_index(the_repository->index, max_prefix, max_prefix_len);
|
||||
|
||||
/* Treat unmatching pathspec elements as errors */
|
||||
if (pathspec.nr && error_unmatch)
|
||||
|
@ -699,11 +661,13 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
|
|||
*/
|
||||
if (show_stage || show_unmerged)
|
||||
die("ls-files --with-tree is incompatible with -s or -u");
|
||||
overlay_tree_on_index(&the_index, with_tree, max_prefix);
|
||||
overlay_tree_on_index(the_repository->index, with_tree, max_prefix);
|
||||
}
|
||||
show_files(&the_index, &dir);
|
||||
|
||||
show_files(the_repository, &dir);
|
||||
|
||||
if (show_resolve_undo)
|
||||
show_ru_info(&the_index);
|
||||
show_ru_info(the_repository->index);
|
||||
|
||||
if (ps_matched) {
|
||||
int bad;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "builtin.h"
|
||||
#include "repository.h"
|
||||
#include "cache.h"
|
||||
#include "config.h"
|
||||
#include "parse-options.h"
|
||||
|
@ -280,7 +281,7 @@ static void module_list_active(struct module_list *list)
|
|||
for (i = 0; i < list->nr; i++) {
|
||||
const struct cache_entry *ce = list->entries[i];
|
||||
|
||||
if (!is_submodule_initialized(ce->name))
|
||||
if (!is_submodule_active(the_repository, ce->name))
|
||||
continue;
|
||||
|
||||
ALLOC_GROW(active_modules.entries,
|
||||
|
@ -362,7 +363,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
|
|||
*
|
||||
* Set active flag for the submodule being initialized
|
||||
*/
|
||||
if (!is_submodule_initialized(path)) {
|
||||
if (!is_submodule_active(the_repository, path)) {
|
||||
strbuf_reset(&sb);
|
||||
strbuf_addf(&sb, "submodule.%s.active", sub->name);
|
||||
git_config_set_gently(sb.buf, "true");
|
||||
|
@ -817,7 +818,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
|
|||
}
|
||||
|
||||
/* Check if the submodule has been initialized. */
|
||||
if (!is_submodule_initialized(ce->name)) {
|
||||
if (!is_submodule_active(the_repository, ce->name)) {
|
||||
next_submodule_warn_missing(suc, out, displaypath);
|
||||
goto cleanup;
|
||||
}
|
||||
|
@ -1193,7 +1194,7 @@ static int is_active(int argc, const char **argv, const char *prefix)
|
|||
|
||||
gitmodules_config();
|
||||
|
||||
return !is_submodule_initialized(argv[1]);
|
||||
return !is_submodule_active(the_repository, argv[1]);
|
||||
}
|
||||
|
||||
#define SUPPORT_SUPER_PREFIX (1<<0)
|
||||
|
|
62
cache.h
62
cache.h
|
@ -11,6 +11,7 @@
|
|||
#include "string-list.h"
|
||||
#include "pack-revindex.h"
|
||||
#include "hash.h"
|
||||
#include "path.h"
|
||||
|
||||
#ifndef platform_SHA_CTX
|
||||
/*
|
||||
|
@ -462,6 +463,8 @@ static inline enum object_type object_type(unsigned int mode)
|
|||
*/
|
||||
extern const char * const local_repo_env[];
|
||||
|
||||
extern void setup_git_env(void);
|
||||
|
||||
/*
|
||||
* Returns true iff we have a configured git repository (either via
|
||||
* setup_git_directory, or in the environment via $GIT_DIR).
|
||||
|
@ -769,7 +772,6 @@ extern int core_apply_sparse_checkout;
|
|||
extern int precomposed_unicode;
|
||||
extern int protect_hfs;
|
||||
extern int protect_ntfs;
|
||||
extern int git_db_env, git_index_env, git_graft_env, git_common_dir_env;
|
||||
|
||||
/*
|
||||
* Include broken refs in all ref iterations, which will
|
||||
|
@ -891,64 +893,6 @@ extern void check_repository_format(void);
|
|||
#define DATA_CHANGED 0x0020
|
||||
#define TYPE_CHANGED 0x0040
|
||||
|
||||
/*
|
||||
* Return a statically allocated filename, either generically (mkpath), in
|
||||
* the repository directory (git_path), or in a submodule's repository
|
||||
* directory (git_path_submodule). In all cases, note that the result
|
||||
* may be overwritten by another call to _any_ of the functions. Consider
|
||||
* using the safer "dup" or "strbuf" formats below (in some cases, the
|
||||
* unsafe versions have already been removed).
|
||||
*/
|
||||
extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
|
||||
extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
|
||||
extern const char *git_common_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
|
||||
|
||||
extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
|
||||
__attribute__((format (printf, 3, 4)));
|
||||
extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
|
||||
__attribute__((format (printf, 2, 3)));
|
||||
extern void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)
|
||||
__attribute__((format (printf, 2, 3)));
|
||||
extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
|
||||
__attribute__((format (printf, 2, 3)));
|
||||
extern int strbuf_git_path_submodule(struct strbuf *sb, const char *path,
|
||||
const char *fmt, ...)
|
||||
__attribute__((format (printf, 3, 4)));
|
||||
extern char *git_pathdup(const char *fmt, ...)
|
||||
__attribute__((format (printf, 1, 2)));
|
||||
extern char *mkpathdup(const char *fmt, ...)
|
||||
__attribute__((format (printf, 1, 2)));
|
||||
extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)
|
||||
__attribute__((format (printf, 2, 3)));
|
||||
|
||||
extern void report_linked_checkout_garbage(void);
|
||||
|
||||
/*
|
||||
* You can define a static memoized git path like:
|
||||
*
|
||||
* static GIT_PATH_FUNC(git_path_foo, "FOO");
|
||||
*
|
||||
* or use one of the global ones below.
|
||||
*/
|
||||
#define GIT_PATH_FUNC(func, filename) \
|
||||
const char *func(void) \
|
||||
{ \
|
||||
static char *ret; \
|
||||
if (!ret) \
|
||||
ret = git_pathdup(filename); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
const char *git_path_cherry_pick_head(void);
|
||||
const char *git_path_revert_head(void);
|
||||
const char *git_path_squash_msg(void);
|
||||
const char *git_path_merge_msg(void);
|
||||
const char *git_path_merge_rr(void);
|
||||
const char *git_path_merge_mode(void);
|
||||
const char *git_path_merge_head(void);
|
||||
const char *git_path_fetch_head(void);
|
||||
const char *git_path_shallow(void);
|
||||
|
||||
/*
|
||||
* Return the name of the file in the local object database that would
|
||||
* be used to store a loose object with the specified sha1. The
|
||||
|
|
218
config.c
218
config.c
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
#include "cache.h"
|
||||
#include "config.h"
|
||||
#include "repository.h"
|
||||
#include "lockfile.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "strbuf.h"
|
||||
|
@ -72,13 +73,6 @@ static int core_compression_seen;
|
|||
static int pack_compression_seen;
|
||||
static int zlib_compression_seen;
|
||||
|
||||
/*
|
||||
* Default config_set that contains key-value pairs from the usual set of config
|
||||
* config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG
|
||||
* config file and the global /etc/gitconfig)
|
||||
*/
|
||||
static struct config_set the_config_set;
|
||||
|
||||
static int config_file_fgetc(struct config_source *conf)
|
||||
{
|
||||
return getc_unlocked(conf->u.file);
|
||||
|
@ -1604,31 +1598,6 @@ int config_with_options(config_fn_t fn, void *data,
|
|||
return do_git_config_sequence(opts, fn, data);
|
||||
}
|
||||
|
||||
static void git_config_raw(config_fn_t fn, void *data)
|
||||
{
|
||||
struct config_options opts = {0};
|
||||
|
||||
opts.respect_includes = 1;
|
||||
if (have_git_dir()) {
|
||||
opts.commondir = get_git_common_dir();
|
||||
opts.git_dir = get_git_dir();
|
||||
}
|
||||
|
||||
if (config_with_options(fn, data, 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 configset_iter(struct config_set *cs, config_fn_t fn, void *data)
|
||||
{
|
||||
int i, value_index;
|
||||
|
@ -1682,14 +1651,6 @@ void read_early_config(config_fn_t cb, void *data)
|
|||
strbuf_release(&gitdir);
|
||||
}
|
||||
|
||||
static void git_config_check_init(void);
|
||||
|
||||
void git_config(config_fn_t fn, void *data)
|
||||
{
|
||||
git_config_check_init();
|
||||
configset_iter(&the_config_set, fn, data);
|
||||
}
|
||||
|
||||
static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)
|
||||
{
|
||||
struct config_set_element k;
|
||||
|
@ -1899,87 +1860,194 @@ int git_configset_get_pathname(struct config_set *cs, const char *key, const cha
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void git_config_check_init(void)
|
||||
/* Functions use to read configuration from a repository */
|
||||
static void repo_read_config(struct repository *repo)
|
||||
{
|
||||
if (the_config_set.hash_initialized)
|
||||
struct config_options opts;
|
||||
|
||||
opts.respect_includes = 1;
|
||||
opts.commondir = repo->commondir;
|
||||
opts.git_dir = repo->gitdir;
|
||||
|
||||
if (!repo->config)
|
||||
repo->config = xcalloc(1, sizeof(struct config_set));
|
||||
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)
|
||||
return;
|
||||
git_configset_init(&the_config_set);
|
||||
git_config_raw(config_set_callback, &the_config_set);
|
||||
repo_read_config(repo);
|
||||
}
|
||||
|
||||
static void repo_config_clear(struct repository *repo)
|
||||
{
|
||||
if (!repo->config || !repo->config->hash_initialized)
|
||||
return;
|
||||
git_configset_clear(repo->config);
|
||||
}
|
||||
|
||||
void repo_config(struct repository *repo, config_fn_t fn, void *data)
|
||||
{
|
||||
git_config_check_init(repo);
|
||||
configset_iter(repo->config, fn, data);
|
||||
}
|
||||
|
||||
int repo_config_get_value(struct repository *repo,
|
||||
const char *key, const char **value)
|
||||
{
|
||||
git_config_check_init(repo);
|
||||
return git_configset_get_value(repo->config, key, value);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int repo_config_get_string_const(struct repository *repo,
|
||||
const char *key, const char **dest)
|
||||
{
|
||||
int ret;
|
||||
git_config_check_init(repo);
|
||||
ret = git_configset_get_string_const(repo->config, key, dest);
|
||||
if (ret < 0)
|
||||
git_die_config(key, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int repo_config_get_string(struct repository *repo,
|
||||
const char *key, char **dest)
|
||||
{
|
||||
git_config_check_init(repo);
|
||||
return repo_config_get_string_const(repo, key, (const char **)dest);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
git_config_check_init(repo);
|
||||
ret = git_configset_get_pathname(repo->config, key, dest);
|
||||
if (ret < 0)
|
||||
git_die_config(key, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
if (!the_config_set.hash_initialized)
|
||||
return;
|
||||
git_configset_clear(&the_config_set);
|
||||
repo_config_clear(the_repository);
|
||||
}
|
||||
|
||||
int git_config_get_value(const char *key, const char **value)
|
||||
{
|
||||
git_config_check_init();
|
||||
return git_configset_get_value(&the_config_set, key, value);
|
||||
return repo_config_get_value(the_repository, key, value);
|
||||
}
|
||||
|
||||
const struct string_list *git_config_get_value_multi(const char *key)
|
||||
{
|
||||
git_config_check_init();
|
||||
return git_configset_get_value_multi(&the_config_set, key);
|
||||
return repo_config_get_value_multi(the_repository, key);
|
||||
}
|
||||
|
||||
int git_config_get_string_const(const char *key, const char **dest)
|
||||
{
|
||||
int ret;
|
||||
git_config_check_init();
|
||||
ret = git_configset_get_string_const(&the_config_set, key, dest);
|
||||
if (ret < 0)
|
||||
git_die_config(key, NULL);
|
||||
return ret;
|
||||
return repo_config_get_string_const(the_repository, key, dest);
|
||||
}
|
||||
|
||||
int git_config_get_string(const char *key, char **dest)
|
||||
{
|
||||
git_config_check_init();
|
||||
return git_config_get_string_const(key, (const char **)dest);
|
||||
return repo_config_get_string(the_repository, key, dest);
|
||||
}
|
||||
|
||||
int git_config_get_int(const char *key, int *dest)
|
||||
{
|
||||
git_config_check_init();
|
||||
return git_configset_get_int(&the_config_set, key, dest);
|
||||
return repo_config_get_int(the_repository, key, dest);
|
||||
}
|
||||
|
||||
int git_config_get_ulong(const char *key, unsigned long *dest)
|
||||
{
|
||||
git_config_check_init();
|
||||
return git_configset_get_ulong(&the_config_set, key, dest);
|
||||
return repo_config_get_ulong(the_repository, key, dest);
|
||||
}
|
||||
|
||||
int git_config_get_bool(const char *key, int *dest)
|
||||
{
|
||||
git_config_check_init();
|
||||
return git_configset_get_bool(&the_config_set, key, dest);
|
||||
return repo_config_get_bool(the_repository, key, dest);
|
||||
}
|
||||
|
||||
int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)
|
||||
{
|
||||
git_config_check_init();
|
||||
return git_configset_get_bool_or_int(&the_config_set, key, is_bool, dest);
|
||||
return repo_config_get_bool_or_int(the_repository, key, is_bool, dest);
|
||||
}
|
||||
|
||||
int git_config_get_maybe_bool(const char *key, int *dest)
|
||||
{
|
||||
git_config_check_init();
|
||||
return git_configset_get_maybe_bool(&the_config_set, key, dest);
|
||||
return repo_config_get_maybe_bool(the_repository, key, dest);
|
||||
}
|
||||
|
||||
int git_config_get_pathname(const char *key, const char **dest)
|
||||
{
|
||||
int ret;
|
||||
git_config_check_init();
|
||||
ret = git_configset_get_pathname(&the_config_set, key, dest);
|
||||
if (ret < 0)
|
||||
git_die_config(key, NULL);
|
||||
return ret;
|
||||
return repo_config_get_pathname(the_repository, key, dest);
|
||||
}
|
||||
|
||||
int git_config_get_expiry(const char *key, const char **output)
|
||||
|
|
24
config.h
24
config.h
|
@ -163,6 +163,30 @@ extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key,
|
|||
extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);
|
||||
extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);
|
||||
|
||||
/* Functions for reading a repository's config */
|
||||
struct repository;
|
||||
extern void repo_config(struct repository *repo, config_fn_t fn, void *data);
|
||||
extern int repo_config_get_value(struct repository *repo,
|
||||
const char *key, const char **value);
|
||||
extern const struct string_list *repo_config_get_value_multi(struct repository *repo,
|
||||
const char *key);
|
||||
extern int repo_config_get_string_const(struct repository *repo,
|
||||
const char *key, const char **dest);
|
||||
extern int repo_config_get_string(struct repository *repo,
|
||||
const char *key, char **dest);
|
||||
extern int repo_config_get_int(struct repository *repo,
|
||||
const char *key, int *dest);
|
||||
extern int repo_config_get_ulong(struct repository *repo,
|
||||
const char *key, unsigned long *dest);
|
||||
extern int repo_config_get_bool(struct repository *repo,
|
||||
const char *key, int *dest);
|
||||
extern int repo_config_get_bool_or_int(struct repository *repo,
|
||||
const char *key, int *is_bool, int *dest);
|
||||
extern int repo_config_get_maybe_bool(struct repository *repo,
|
||||
const char *key, int *dest);
|
||||
extern int repo_config_get_pathname(struct repository *repo,
|
||||
const char *key, const char **dest);
|
||||
|
||||
extern int git_config_get_value(const char *key, const char **value);
|
||||
extern const struct string_list *git_config_get_value_multi(const char *key);
|
||||
extern void git_config_clear(void);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
* are.
|
||||
*/
|
||||
#include "cache.h"
|
||||
#include "repository.h"
|
||||
#include "config.h"
|
||||
#include "refs.h"
|
||||
#include "fmt-merge-msg.h"
|
||||
|
@ -95,17 +96,11 @@ int ignore_untracked_cache_config;
|
|||
|
||||
/* This is set by setup_git_dir_gently() and/or git_default_config() */
|
||||
char *git_work_tree_cfg;
|
||||
static char *work_tree;
|
||||
|
||||
static const char *namespace;
|
||||
static size_t namespace_len;
|
||||
|
||||
static const char *super_prefix;
|
||||
|
||||
static const char *git_dir, *git_common_dir;
|
||||
static char *git_object_dir, *git_index_file, *git_graft_file;
|
||||
int git_db_env, git_index_env, git_graft_env, git_common_dir_env;
|
||||
|
||||
/*
|
||||
* Repository-local GIT_* environment variables; see cache.h for details.
|
||||
*/
|
||||
|
@ -149,48 +144,17 @@ static char *expand_namespace(const char *raw_namespace)
|
|||
return strbuf_detach(&buf, NULL);
|
||||
}
|
||||
|
||||
static char *git_path_from_env(const char *envvar, const char *git_dir,
|
||||
const char *path, int *fromenv)
|
||||
void setup_git_env(void)
|
||||
{
|
||||
const char *value = getenv(envvar);
|
||||
if (!value)
|
||||
return xstrfmt("%s/%s", git_dir, path);
|
||||
if (fromenv)
|
||||
*fromenv = 1;
|
||||
return xstrdup(value);
|
||||
}
|
||||
|
||||
static void setup_git_env(void)
|
||||
{
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
const char *gitfile;
|
||||
const char *shallow_file;
|
||||
const char *replace_ref_base;
|
||||
|
||||
git_dir = getenv(GIT_DIR_ENVIRONMENT);
|
||||
if (!git_dir) {
|
||||
if (!startup_info->have_repository)
|
||||
BUG("setup_git_env called without repository");
|
||||
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
|
||||
}
|
||||
gitfile = read_gitfile(git_dir);
|
||||
git_dir = xstrdup(gitfile ? gitfile : git_dir);
|
||||
if (get_common_dir(&sb, git_dir))
|
||||
git_common_dir_env = 1;
|
||||
git_common_dir = strbuf_detach(&sb, NULL);
|
||||
git_object_dir = git_path_from_env(DB_ENVIRONMENT, git_common_dir,
|
||||
"objects", &git_db_env);
|
||||
git_index_file = git_path_from_env(INDEX_ENVIRONMENT, git_dir,
|
||||
"index", &git_index_env);
|
||||
git_graft_file = git_path_from_env(GRAFT_ENVIRONMENT, git_common_dir,
|
||||
"info/grafts", &git_graft_env);
|
||||
if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
|
||||
check_replace_refs = 0;
|
||||
replace_ref_base = getenv(GIT_REPLACE_REF_BASE_ENVIRONMENT);
|
||||
git_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base
|
||||
: "refs/replace/");
|
||||
namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));
|
||||
namespace_len = strlen(namespace);
|
||||
shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);
|
||||
if (shallow_file)
|
||||
set_alternate_shallow_file(shallow_file, 0);
|
||||
|
@ -205,36 +169,36 @@ int is_bare_repository(void)
|
|||
int have_git_dir(void)
|
||||
{
|
||||
return startup_info->have_repository
|
||||
|| git_dir
|
||||
|| getenv(GIT_DIR_ENVIRONMENT);
|
||||
|| the_repository->gitdir;
|
||||
}
|
||||
|
||||
const char *get_git_dir(void)
|
||||
{
|
||||
if (!git_dir)
|
||||
setup_git_env();
|
||||
return git_dir;
|
||||
if (!the_repository->gitdir)
|
||||
BUG("git environment hasn't been setup");
|
||||
return the_repository->gitdir;
|
||||
}
|
||||
|
||||
const char *get_git_common_dir(void)
|
||||
{
|
||||
if (!git_dir)
|
||||
setup_git_env();
|
||||
return git_common_dir;
|
||||
if (!the_repository->commondir)
|
||||
BUG("git environment hasn't been setup");
|
||||
return the_repository->commondir;
|
||||
}
|
||||
|
||||
const char *get_git_namespace(void)
|
||||
{
|
||||
if (!namespace)
|
||||
setup_git_env();
|
||||
BUG("git environment hasn't been setup");
|
||||
return namespace;
|
||||
}
|
||||
|
||||
const char *strip_namespace(const char *namespaced_ref)
|
||||
{
|
||||
if (!starts_with(namespaced_ref, get_git_namespace()))
|
||||
const char *out;
|
||||
if (skip_prefix(namespaced_ref, get_git_namespace(), &out))
|
||||
return out;
|
||||
return NULL;
|
||||
return namespaced_ref + namespace_len;
|
||||
}
|
||||
|
||||
const char *get_super_prefix(void)
|
||||
|
@ -258,26 +222,26 @@ void set_git_work_tree(const char *new_work_tree)
|
|||
{
|
||||
if (git_work_tree_initialized) {
|
||||
new_work_tree = real_path(new_work_tree);
|
||||
if (strcmp(new_work_tree, work_tree))
|
||||
if (strcmp(new_work_tree, the_repository->worktree))
|
||||
die("internal error: work tree has already been set\n"
|
||||
"Current worktree: %s\nNew worktree: %s",
|
||||
work_tree, new_work_tree);
|
||||
the_repository->worktree, new_work_tree);
|
||||
return;
|
||||
}
|
||||
git_work_tree_initialized = 1;
|
||||
work_tree = real_pathdup(new_work_tree, 1);
|
||||
repo_set_worktree(the_repository, new_work_tree);
|
||||
}
|
||||
|
||||
const char *get_git_work_tree(void)
|
||||
{
|
||||
return work_tree;
|
||||
return the_repository->worktree;
|
||||
}
|
||||
|
||||
char *get_object_directory(void)
|
||||
{
|
||||
if (!git_object_dir)
|
||||
setup_git_env();
|
||||
return git_object_dir;
|
||||
if (!the_repository->objectdir)
|
||||
BUG("git environment hasn't been setup");
|
||||
return the_repository->objectdir;
|
||||
}
|
||||
|
||||
int odb_mkstemp(struct strbuf *template, const char *pattern)
|
||||
|
@ -315,22 +279,23 @@ int odb_pack_keep(const char *name)
|
|||
|
||||
char *get_index_file(void)
|
||||
{
|
||||
if (!git_index_file)
|
||||
setup_git_env();
|
||||
return git_index_file;
|
||||
if (!the_repository->index_file)
|
||||
BUG("git environment hasn't been setup");
|
||||
return the_repository->index_file;
|
||||
}
|
||||
|
||||
char *get_graft_file(void)
|
||||
{
|
||||
if (!git_graft_file)
|
||||
setup_git_env();
|
||||
return git_graft_file;
|
||||
if (!the_repository->graft_file)
|
||||
BUG("git environment hasn't been setup");
|
||||
return the_repository->graft_file;
|
||||
}
|
||||
|
||||
int set_git_dir(const char *path)
|
||||
{
|
||||
if (setenv(GIT_DIR_ENVIRONMENT, path, 1))
|
||||
return error("Could not set GIT_DIR to '%s'", path);
|
||||
repo_set_gitdir(the_repository, path);
|
||||
setup_git_env();
|
||||
return 0;
|
||||
}
|
||||
|
|
2
git.c
2
git.c
|
@ -400,7 +400,7 @@ static struct cmd_struct commands[] = {
|
|||
{ "init-db", cmd_init_db },
|
||||
{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY },
|
||||
{ "log", cmd_log, RUN_SETUP },
|
||||
{ "ls-files", cmd_ls_files, RUN_SETUP | SUPPORT_SUPER_PREFIX },
|
||||
{ "ls-files", cmd_ls_files, RUN_SETUP },
|
||||
{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
|
||||
{ "ls-tree", cmd_ls_tree, RUN_SETUP },
|
||||
{ "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY },
|
||||
|
|
130
path.c
130
path.c
|
@ -2,11 +2,13 @@
|
|||
* Utilities for paths and pathnames
|
||||
*/
|
||||
#include "cache.h"
|
||||
#include "repository.h"
|
||||
#include "strbuf.h"
|
||||
#include "string-list.h"
|
||||
#include "dir.h"
|
||||
#include "worktree.h"
|
||||
#include "submodule-config.h"
|
||||
#include "path.h"
|
||||
|
||||
static int get_st_mode_bits(const char *path, int *mode)
|
||||
{
|
||||
|
@ -343,8 +345,6 @@ static void update_common_dir(struct strbuf *buf, int git_dir_len,
|
|||
{
|
||||
char *base = buf->buf + git_dir_len;
|
||||
init_common_trie();
|
||||
if (!common_dir)
|
||||
common_dir = get_git_common_dir();
|
||||
if (trie_find(&common_trie, base, check_common, NULL) > 0)
|
||||
replace_dir(buf, git_dir_len, common_dir);
|
||||
}
|
||||
|
@ -355,7 +355,7 @@ void report_linked_checkout_garbage(void)
|
|||
const struct common_dir *p;
|
||||
int len;
|
||||
|
||||
if (!git_common_dir_env)
|
||||
if (!the_repository->different_commondir)
|
||||
return;
|
||||
strbuf_addf(&sb, "%s/", get_git_dir());
|
||||
len = sb.len;
|
||||
|
@ -371,42 +371,78 @@ void report_linked_checkout_garbage(void)
|
|||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
static void adjust_git_path(struct strbuf *buf, int git_dir_len)
|
||||
static void adjust_git_path(const struct repository *repo,
|
||||
struct strbuf *buf, int git_dir_len)
|
||||
{
|
||||
const char *base = buf->buf + git_dir_len;
|
||||
if (git_graft_env && is_dir_file(base, "info", "grafts"))
|
||||
if (is_dir_file(base, "info", "grafts"))
|
||||
strbuf_splice(buf, 0, buf->len,
|
||||
get_graft_file(), strlen(get_graft_file()));
|
||||
else if (git_index_env && !strcmp(base, "index"))
|
||||
repo->graft_file, strlen(repo->graft_file));
|
||||
else if (!strcmp(base, "index"))
|
||||
strbuf_splice(buf, 0, buf->len,
|
||||
get_index_file(), strlen(get_index_file()));
|
||||
else if (git_db_env && dir_prefix(base, "objects"))
|
||||
replace_dir(buf, git_dir_len + 7, get_object_directory());
|
||||
repo->index_file, strlen(repo->index_file));
|
||||
else if (dir_prefix(base, "objects"))
|
||||
replace_dir(buf, git_dir_len + 7, repo->objectdir);
|
||||
else if (git_hooks_path && dir_prefix(base, "hooks"))
|
||||
replace_dir(buf, git_dir_len + 5, git_hooks_path);
|
||||
else if (git_common_dir_env)
|
||||
update_common_dir(buf, git_dir_len, NULL);
|
||||
else if (repo->different_commondir)
|
||||
update_common_dir(buf, git_dir_len, repo->commondir);
|
||||
}
|
||||
|
||||
static void do_git_path(const struct worktree *wt, struct strbuf *buf,
|
||||
static void strbuf_worktree_gitdir(struct strbuf *buf,
|
||||
const struct repository *repo,
|
||||
const struct worktree *wt)
|
||||
{
|
||||
if (!wt)
|
||||
strbuf_addstr(buf, repo->gitdir);
|
||||
else if (!wt->id)
|
||||
strbuf_addstr(buf, repo->commondir);
|
||||
else
|
||||
strbuf_git_common_path(buf, repo, "worktrees/%s", wt->id);
|
||||
}
|
||||
|
||||
static void do_git_path(const struct repository *repo,
|
||||
const struct worktree *wt, struct strbuf *buf,
|
||||
const char *fmt, va_list args)
|
||||
{
|
||||
int gitdir_len;
|
||||
strbuf_addstr(buf, get_worktree_git_dir(wt));
|
||||
strbuf_worktree_gitdir(buf, repo, wt);
|
||||
if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
|
||||
strbuf_addch(buf, '/');
|
||||
gitdir_len = buf->len;
|
||||
strbuf_vaddf(buf, fmt, args);
|
||||
adjust_git_path(buf, gitdir_len);
|
||||
if (!wt)
|
||||
adjust_git_path(repo, buf, gitdir_len);
|
||||
strbuf_cleanup_path(buf);
|
||||
}
|
||||
|
||||
char *repo_git_path(const struct repository *repo,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
struct strbuf path = STRBUF_INIT;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_git_path(repo, NULL, &path, fmt, args);
|
||||
va_end(args);
|
||||
return strbuf_detach(&path, NULL);
|
||||
}
|
||||
|
||||
void strbuf_repo_git_path(struct strbuf *sb,
|
||||
const struct repository *repo,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_git_path(repo, NULL, sb, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
strbuf_reset(buf);
|
||||
va_start(args, fmt);
|
||||
do_git_path(NULL, buf, fmt, args);
|
||||
do_git_path(the_repository, NULL, buf, fmt, args);
|
||||
va_end(args);
|
||||
return buf->buf;
|
||||
}
|
||||
|
@ -415,7 +451,7 @@ void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
|
|||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_git_path(NULL, sb, fmt, args);
|
||||
do_git_path(the_repository, NULL, sb, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
@ -424,7 +460,7 @@ const char *git_path(const char *fmt, ...)
|
|||
struct strbuf *pathname = get_pathname();
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_git_path(NULL, pathname, fmt, args);
|
||||
do_git_path(the_repository, NULL, pathname, fmt, args);
|
||||
va_end(args);
|
||||
return pathname->buf;
|
||||
}
|
||||
|
@ -434,7 +470,7 @@ char *git_pathdup(const char *fmt, ...)
|
|||
struct strbuf path = STRBUF_INIT;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_git_path(NULL, &path, fmt, args);
|
||||
do_git_path(the_repository, NULL, &path, fmt, args);
|
||||
va_end(args);
|
||||
return strbuf_detach(&path, NULL);
|
||||
}
|
||||
|
@ -465,11 +501,52 @@ const char *worktree_git_path(const struct worktree *wt, const char *fmt, ...)
|
|||
struct strbuf *pathname = get_pathname();
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_git_path(wt, pathname, fmt, args);
|
||||
do_git_path(the_repository, wt, pathname, fmt, args);
|
||||
va_end(args);
|
||||
return pathname->buf;
|
||||
}
|
||||
|
||||
static void do_worktree_path(const struct repository *repo,
|
||||
struct strbuf *buf,
|
||||
const char *fmt, va_list args)
|
||||
{
|
||||
strbuf_addstr(buf, repo->worktree);
|
||||
if(buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
|
||||
strbuf_addch(buf, '/');
|
||||
|
||||
strbuf_vaddf(buf, fmt, args);
|
||||
strbuf_cleanup_path(buf);
|
||||
}
|
||||
|
||||
char *repo_worktree_path(const struct repository *repo, const char *fmt, ...)
|
||||
{
|
||||
struct strbuf path = STRBUF_INIT;
|
||||
va_list args;
|
||||
|
||||
if (!repo->worktree)
|
||||
return NULL;
|
||||
|
||||
va_start(args, fmt);
|
||||
do_worktree_path(repo, &path, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return strbuf_detach(&path, NULL);
|
||||
}
|
||||
|
||||
void strbuf_repo_worktree_path(struct strbuf *sb,
|
||||
const struct repository *repo,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!repo->worktree)
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
do_worktree_path(repo, sb, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* Returns 0 on success, negative on failure. */
|
||||
static int do_submodule_path(struct strbuf *buf, const char *path,
|
||||
const char *fmt, va_list args)
|
||||
|
@ -524,11 +601,12 @@ int strbuf_git_path_submodule(struct strbuf *buf, const char *path,
|
|||
return err;
|
||||
}
|
||||
|
||||
static void do_git_common_path(struct strbuf *buf,
|
||||
static void do_git_common_path(const struct repository *repo,
|
||||
struct strbuf *buf,
|
||||
const char *fmt,
|
||||
va_list args)
|
||||
{
|
||||
strbuf_addstr(buf, get_git_common_dir());
|
||||
strbuf_addstr(buf, repo->commondir);
|
||||
if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
|
||||
strbuf_addch(buf, '/');
|
||||
strbuf_vaddf(buf, fmt, args);
|
||||
|
@ -540,16 +618,18 @@ const char *git_common_path(const char *fmt, ...)
|
|||
struct strbuf *pathname = get_pathname();
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_git_common_path(pathname, fmt, args);
|
||||
do_git_common_path(the_repository, pathname, fmt, args);
|
||||
va_end(args);
|
||||
return pathname->buf;
|
||||
}
|
||||
|
||||
void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)
|
||||
void strbuf_git_common_path(struct strbuf *sb,
|
||||
const struct repository *repo,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
do_git_common_path(sb, fmt, args);
|
||||
do_git_common_path(repo, sb, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
#ifndef PATH_H
|
||||
#define PATH_H
|
||||
|
||||
struct repository;
|
||||
|
||||
/*
|
||||
* Return a statically allocated filename, either generically (mkpath), in
|
||||
* the repository directory (git_path), or in a submodule's repository
|
||||
* directory (git_path_submodule). In all cases, note that the result
|
||||
* may be overwritten by another call to _any_ of the functions. Consider
|
||||
* using the safer "dup" or "strbuf" formats below (in some cases, the
|
||||
* unsafe versions have already been removed).
|
||||
*/
|
||||
extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
|
||||
extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
|
||||
extern const char *git_common_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
|
||||
|
||||
extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
|
||||
__attribute__((format (printf, 3, 4)));
|
||||
extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
|
||||
__attribute__((format (printf, 2, 3)));
|
||||
extern void strbuf_git_common_path(struct strbuf *sb,
|
||||
const struct repository *repo,
|
||||
const char *fmt, ...)
|
||||
__attribute__((format (printf, 3, 4)));
|
||||
extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
|
||||
__attribute__((format (printf, 2, 3)));
|
||||
extern int strbuf_git_path_submodule(struct strbuf *sb, const char *path,
|
||||
const char *fmt, ...)
|
||||
__attribute__((format (printf, 3, 4)));
|
||||
extern char *git_pathdup(const char *fmt, ...)
|
||||
__attribute__((format (printf, 1, 2)));
|
||||
extern char *mkpathdup(const char *fmt, ...)
|
||||
__attribute__((format (printf, 1, 2)));
|
||||
extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)
|
||||
__attribute__((format (printf, 2, 3)));
|
||||
|
||||
extern char *repo_git_path(const struct repository *repo,
|
||||
const char *fmt, ...)
|
||||
__attribute__((format (printf, 2, 3)));
|
||||
extern void strbuf_repo_git_path(struct strbuf *sb,
|
||||
const struct repository *repo,
|
||||
const char *fmt, ...)
|
||||
__attribute__((format (printf, 3, 4)));
|
||||
|
||||
extern char *repo_worktree_path(const struct repository *repo,
|
||||
const char *fmt, ...)
|
||||
__attribute__((format (printf, 2, 3)));
|
||||
extern void strbuf_repo_worktree_path(struct strbuf *sb,
|
||||
const struct repository *repo,
|
||||
const char *fmt, ...)
|
||||
__attribute__((format (printf, 3, 4)));
|
||||
|
||||
extern void report_linked_checkout_garbage(void);
|
||||
|
||||
/*
|
||||
* You can define a static memoized git path like:
|
||||
*
|
||||
* static GIT_PATH_FUNC(git_path_foo, "FOO");
|
||||
*
|
||||
* or use one of the global ones below.
|
||||
*/
|
||||
#define GIT_PATH_FUNC(func, filename) \
|
||||
const char *func(void) \
|
||||
{ \
|
||||
static char *ret; \
|
||||
if (!ret) \
|
||||
ret = git_pathdup(filename); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
const char *git_path_cherry_pick_head(void);
|
||||
const char *git_path_revert_head(void);
|
||||
const char *git_path_squash_msg(void);
|
||||
const char *git_path_merge_msg(void);
|
||||
const char *git_path_merge_rr(void);
|
||||
const char *git_path_merge_mode(void);
|
||||
const char *git_path_merge_head(void);
|
||||
const char *git_path_fetch_head(void);
|
||||
const char *git_path_shallow(void);
|
||||
|
||||
#endif /* PATH_H */
|
|
@ -0,0 +1,242 @@
|
|||
#include "cache.h"
|
||||
#include "repository.h"
|
||||
#include "config.h"
|
||||
#include "submodule-config.h"
|
||||
|
||||
/* The main repository */
|
||||
static struct repository the_repo;
|
||||
struct repository *the_repository = &the_repo;
|
||||
|
||||
static char *git_path_from_env(const char *envvar, const char *git_dir,
|
||||
const char *path, int fromenv)
|
||||
{
|
||||
if (fromenv) {
|
||||
const char *value = getenv(envvar);
|
||||
if (value)
|
||||
return xstrdup(value);
|
||||
}
|
||||
|
||||
return xstrfmt("%s/%s", git_dir, path);
|
||||
}
|
||||
|
||||
static int find_common_dir(struct strbuf *sb, const char *gitdir, int fromenv)
|
||||
{
|
||||
if (fromenv) {
|
||||
const char *value = getenv(GIT_COMMON_DIR_ENVIRONMENT);
|
||||
if (value) {
|
||||
strbuf_addstr(sb, value);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return get_common_dir_noenv(sb, gitdir);
|
||||
}
|
||||
|
||||
static void repo_setup_env(struct repository *repo)
|
||||
{
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
repo->different_commondir = find_common_dir(&sb, repo->gitdir,
|
||||
!repo->ignore_env);
|
||||
repo->commondir = strbuf_detach(&sb, NULL);
|
||||
repo->objectdir = git_path_from_env(DB_ENVIRONMENT, repo->commondir,
|
||||
"objects", !repo->ignore_env);
|
||||
repo->graft_file = git_path_from_env(GRAFT_ENVIRONMENT, repo->commondir,
|
||||
"info/grafts", !repo->ignore_env);
|
||||
repo->index_file = git_path_from_env(INDEX_ENVIRONMENT, repo->gitdir,
|
||||
"index", !repo->ignore_env);
|
||||
}
|
||||
|
||||
void repo_set_gitdir(struct repository *repo, const char *path)
|
||||
{
|
||||
const char *gitfile = read_gitfile(path);
|
||||
|
||||
/*
|
||||
* NEEDSWORK: Eventually we want to be able to free gitdir and the rest
|
||||
* of the environment before reinitializing it again, but we have some
|
||||
* crazy code paths where we try to set gitdir with the current gitdir
|
||||
* and we don't want to free gitdir before copying the passed in value.
|
||||
*/
|
||||
repo->gitdir = xstrdup(gitfile ? gitfile : path);
|
||||
|
||||
repo_setup_env(repo);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to resolve and set the provided 'gitdir' for repository 'repo'.
|
||||
* Return 0 upon success and a non-zero value upon failure.
|
||||
*/
|
||||
static int repo_init_gitdir(struct repository *repo, const char *gitdir)
|
||||
{
|
||||
int ret = 0;
|
||||
int error = 0;
|
||||
char *abspath = NULL;
|
||||
const char *resolved_gitdir;
|
||||
|
||||
abspath = real_pathdup(gitdir, 0);
|
||||
if (!abspath) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 'gitdir' must reference the gitdir directly */
|
||||
resolved_gitdir = resolve_gitdir_gently(abspath, &error);
|
||||
if (!resolved_gitdir) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
repo_set_gitdir(repo, resolved_gitdir);
|
||||
|
||||
out:
|
||||
free(abspath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void repo_set_worktree(struct repository *repo, const char *path)
|
||||
{
|
||||
repo->worktree = real_pathdup(path, 1);
|
||||
}
|
||||
|
||||
static int read_and_verify_repository_format(struct repository_format *format,
|
||||
const char *commondir)
|
||||
{
|
||||
int ret = 0;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
strbuf_addf(&sb, "%s/config", commondir);
|
||||
read_repository_format(format, sb.buf);
|
||||
strbuf_reset(&sb);
|
||||
|
||||
if (verify_repository_format(format, &sb) < 0) {
|
||||
warning("%s", sb.buf);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
strbuf_release(&sb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize 'repo' based on the provided 'gitdir'.
|
||||
* Return 0 upon success and a non-zero value upon failure.
|
||||
*/
|
||||
int repo_init(struct repository *repo, const char *gitdir, const char *worktree)
|
||||
{
|
||||
struct repository_format format;
|
||||
memset(repo, 0, sizeof(*repo));
|
||||
|
||||
repo->ignore_env = 1;
|
||||
|
||||
if (repo_init_gitdir(repo, gitdir))
|
||||
goto error;
|
||||
|
||||
if (read_and_verify_repository_format(&format, repo->commondir))
|
||||
goto error;
|
||||
|
||||
if (worktree)
|
||||
repo_set_worktree(repo, worktree);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
repo_clear(repo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize 'submodule' as the submodule given by 'path' in parent repository
|
||||
* 'superproject'.
|
||||
* Return 0 upon success and a non-zero value upon failure.
|
||||
*/
|
||||
int repo_submodule_init(struct repository *submodule,
|
||||
struct repository *superproject,
|
||||
const char *path)
|
||||
{
|
||||
const struct submodule *sub;
|
||||
struct strbuf gitdir = STRBUF_INIT;
|
||||
struct strbuf worktree = STRBUF_INIT;
|
||||
int ret = 0;
|
||||
|
||||
sub = submodule_from_cache(superproject, null_sha1, path);
|
||||
if (!sub) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
strbuf_repo_worktree_path(&gitdir, superproject, "%s/.git", path);
|
||||
strbuf_repo_worktree_path(&worktree, superproject, "%s", path);
|
||||
|
||||
if (repo_init(submodule, gitdir.buf, worktree.buf)) {
|
||||
/*
|
||||
* If initilization fails then it may be due to the submodule
|
||||
* not being populated in the superproject's worktree. Instead
|
||||
* we can try to initilize the submodule by finding it's gitdir
|
||||
* in the superproject's 'modules' directory. In this case the
|
||||
* submodule would not have a worktree.
|
||||
*/
|
||||
strbuf_reset(&gitdir);
|
||||
strbuf_repo_git_path(&gitdir, superproject,
|
||||
"modules/%s", sub->name);
|
||||
|
||||
if (repo_init(submodule, gitdir.buf, NULL)) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
submodule->submodule_prefix = xstrfmt("%s%s/",
|
||||
superproject->submodule_prefix ?
|
||||
superproject->submodule_prefix :
|
||||
"", path);
|
||||
|
||||
out:
|
||||
strbuf_release(&gitdir);
|
||||
strbuf_release(&worktree);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void repo_clear(struct repository *repo)
|
||||
{
|
||||
free(repo->gitdir);
|
||||
repo->gitdir = NULL;
|
||||
free(repo->commondir);
|
||||
repo->commondir = NULL;
|
||||
free(repo->objectdir);
|
||||
repo->objectdir = NULL;
|
||||
free(repo->graft_file);
|
||||
repo->graft_file = NULL;
|
||||
free(repo->index_file);
|
||||
repo->index_file = NULL;
|
||||
free(repo->worktree);
|
||||
repo->worktree = NULL;
|
||||
free(repo->submodule_prefix);
|
||||
repo->submodule_prefix = NULL;
|
||||
|
||||
if (repo->config) {
|
||||
git_configset_clear(repo->config);
|
||||
free(repo->config);
|
||||
repo->config = NULL;
|
||||
}
|
||||
|
||||
if (repo->submodule_cache) {
|
||||
submodule_cache_free(repo->submodule_cache);
|
||||
repo->submodule_cache = NULL;
|
||||
}
|
||||
|
||||
if (repo->index) {
|
||||
discard_index(repo->index);
|
||||
free(repo->index);
|
||||
repo->index = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int repo_read_index(struct repository *repo)
|
||||
{
|
||||
if (!repo->index)
|
||||
repo->index = xcalloc(1, sizeof(*repo->index));
|
||||
else
|
||||
discard_index(repo->index);
|
||||
|
||||
return read_index_from(repo->index, repo->index_file);
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
#ifndef REPOSITORY_H
|
||||
#define REPOSITORY_H
|
||||
|
||||
struct config_set;
|
||||
struct index_state;
|
||||
struct submodule_cache;
|
||||
|
||||
struct repository {
|
||||
/* Environment */
|
||||
/*
|
||||
* Path to the git directory.
|
||||
* Cannot be NULL after initialization.
|
||||
*/
|
||||
char *gitdir;
|
||||
|
||||
/*
|
||||
* Path to the common git directory.
|
||||
* Cannot be NULL after initialization.
|
||||
*/
|
||||
char *commondir;
|
||||
|
||||
/*
|
||||
* Path to the repository's object store.
|
||||
* Cannot be NULL after initialization.
|
||||
*/
|
||||
char *objectdir;
|
||||
|
||||
/*
|
||||
* Path to the repository's graft file.
|
||||
* Cannot be NULL after initialization.
|
||||
*/
|
||||
char *graft_file;
|
||||
|
||||
/*
|
||||
* Path to the current worktree's index file.
|
||||
* Cannot be NULL after initialization.
|
||||
*/
|
||||
char *index_file;
|
||||
|
||||
/*
|
||||
* Path to the working directory.
|
||||
* A NULL value indicates that there is no working directory.
|
||||
*/
|
||||
char *worktree;
|
||||
|
||||
/*
|
||||
* Path from the root of the top-level superproject down to this
|
||||
* repository. This is only non-NULL if the repository is initialized
|
||||
* as a submodule of another repository.
|
||||
*/
|
||||
char *submodule_prefix;
|
||||
|
||||
/* Subsystems */
|
||||
/*
|
||||
* Repository's config which contains key-value pairs from the usual
|
||||
* set of config files (i.e. repo specific .git/config, user wide
|
||||
* ~/.gitconfig, XDG config file and the global /etc/gitconfig)
|
||||
*/
|
||||
struct config_set *config;
|
||||
|
||||
/* Repository's submodule config as defined by '.gitmodules' */
|
||||
struct submodule_cache *submodule_cache;
|
||||
|
||||
/*
|
||||
* Repository's in-memory index.
|
||||
* 'repo_read_index()' can be used to populate 'index'.
|
||||
*/
|
||||
struct index_state *index;
|
||||
|
||||
/* Configurations */
|
||||
/*
|
||||
* Bit used during initialization to indicate if repository state (like
|
||||
* the location of the 'objectdir') should be read from the
|
||||
* environment. By default this bit will be set at the begining of
|
||||
* 'repo_init()' so that all repositories will ignore the environment.
|
||||
* The exception to this is 'the_repository', which doesn't go through
|
||||
* the normal 'repo_init()' process.
|
||||
*/
|
||||
unsigned ignore_env:1;
|
||||
|
||||
/* Indicate if a repository has a different 'commondir' from 'gitdir' */
|
||||
unsigned different_commondir:1;
|
||||
};
|
||||
|
||||
extern struct repository *the_repository;
|
||||
|
||||
extern void repo_set_gitdir(struct repository *repo, const char *path);
|
||||
extern void repo_set_worktree(struct repository *repo, const char *path);
|
||||
extern int repo_init(struct repository *repo, const char *gitdir, const char *worktree);
|
||||
extern int repo_submodule_init(struct repository *submodule,
|
||||
struct repository *superproject,
|
||||
const char *path);
|
||||
extern void repo_clear(struct repository *repo);
|
||||
|
||||
extern int repo_read_index(struct repository *repo);
|
||||
|
||||
#endif /* REPOSITORY_H */
|
33
setup.c
33
setup.c
|
@ -1,4 +1,5 @@
|
|||
#include "cache.h"
|
||||
#include "repository.h"
|
||||
#include "config.h"
|
||||
#include "dir.h"
|
||||
#include "string-list.h"
|
||||
|
@ -398,6 +399,11 @@ void setup_work_tree(void)
|
|||
if (getenv(GIT_WORK_TREE_ENVIRONMENT))
|
||||
setenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1);
|
||||
|
||||
/*
|
||||
* NEEDSWORK: this call can essentially be set_git_dir(get_git_dir())
|
||||
* which can cause some problems when trying to free the old value of
|
||||
* gitdir.
|
||||
*/
|
||||
set_git_dir(remove_leading_path(git_dir, work_tree));
|
||||
initialized = 1;
|
||||
}
|
||||
|
@ -1079,6 +1085,12 @@ const char *setup_git_directory_gently(int *nongit_ok)
|
|||
die("BUG: unhandled setup_git_directory_1() result");
|
||||
}
|
||||
|
||||
/*
|
||||
* NEEDSWORK: This was a hack in order to get ls-files and grep to have
|
||||
* properly formated output when recursing submodules. Once ls-files
|
||||
* and grep have been changed to perform this recursing in-process this
|
||||
* needs to be removed.
|
||||
*/
|
||||
env_prefix = getenv(GIT_TOPLEVEL_PREFIX_ENVIRONMENT);
|
||||
if (env_prefix)
|
||||
prefix = env_prefix;
|
||||
|
@ -1091,6 +1103,27 @@ const char *setup_git_directory_gently(int *nongit_ok)
|
|||
startup_info->have_repository = !nongit_ok || !*nongit_ok;
|
||||
startup_info->prefix = prefix;
|
||||
|
||||
/*
|
||||
* Not all paths through the setup code will call 'set_git_dir()' (which
|
||||
* directly sets up the environment) so in order to guarantee that the
|
||||
* environment is in a consistent state after setup, explicitly setup
|
||||
* the environment if we have a repository.
|
||||
*
|
||||
* NEEDSWORK: currently we allow bogus GIT_DIR values to be set in some
|
||||
* code paths so we also need to explicitly setup the environment if
|
||||
* the user has set GIT_DIR. It may be beneficial to disallow bogus
|
||||
* GIT_DIR values at some point in the future.
|
||||
*/
|
||||
if (startup_info->have_repository || getenv(GIT_DIR_ENVIRONMENT)) {
|
||||
if (!the_repository->gitdir) {
|
||||
const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
|
||||
if (!gitdir)
|
||||
gitdir = DEFAULT_GIT_DIR_ENVIRONMENT;
|
||||
repo_set_gitdir(the_repository, gitdir);
|
||||
setup_git_env();
|
||||
}
|
||||
}
|
||||
|
||||
strbuf_release(&dir);
|
||||
strbuf_release(&gitdir);
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "cache.h"
|
||||
#include "repository.h"
|
||||
#include "config.h"
|
||||
#include "submodule-config.h"
|
||||
#include "submodule.h"
|
||||
|
@ -15,6 +16,7 @@
|
|||
struct submodule_cache {
|
||||
struct hashmap for_path;
|
||||
struct hashmap for_name;
|
||||
unsigned initialized:1;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -31,9 +33,6 @@ enum lookup_type {
|
|||
lookup_path
|
||||
};
|
||||
|
||||
static struct submodule_cache the_submodule_cache;
|
||||
static int is_cache_init;
|
||||
|
||||
static int config_path_cmp(const struct submodule_entry *a,
|
||||
const struct submodule_entry *b,
|
||||
const void *unused)
|
||||
|
@ -50,10 +49,16 @@ static int config_name_cmp(const struct submodule_entry *a,
|
|||
hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
|
||||
}
|
||||
|
||||
static void cache_init(struct submodule_cache *cache)
|
||||
static struct submodule_cache *submodule_cache_alloc(void)
|
||||
{
|
||||
return xcalloc(1, sizeof(struct submodule_cache));
|
||||
}
|
||||
|
||||
static void submodule_cache_init(struct submodule_cache *cache)
|
||||
{
|
||||
hashmap_init(&cache->for_path, (hashmap_cmp_fn) config_path_cmp, 0);
|
||||
hashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, 0);
|
||||
cache->initialized = 1;
|
||||
}
|
||||
|
||||
static void free_one_config(struct submodule_entry *entry)
|
||||
|
@ -65,11 +70,14 @@ static void free_one_config(struct submodule_entry *entry)
|
|||
free(entry->config);
|
||||
}
|
||||
|
||||
static void cache_free(struct submodule_cache *cache)
|
||||
static void submodule_cache_clear(struct submodule_cache *cache)
|
||||
{
|
||||
struct hashmap_iter iter;
|
||||
struct submodule_entry *entry;
|
||||
|
||||
if (!cache->initialized)
|
||||
return;
|
||||
|
||||
/*
|
||||
* We iterate over the name hash here to be symmetric with the
|
||||
* allocation of struct submodule entries. Each is allocated by
|
||||
|
@ -81,6 +89,13 @@ static void cache_free(struct submodule_cache *cache)
|
|||
|
||||
hashmap_free(&cache->for_path, 1);
|
||||
hashmap_free(&cache->for_name, 1);
|
||||
cache->initialized = 0;
|
||||
}
|
||||
|
||||
void submodule_cache_free(struct submodule_cache *cache)
|
||||
{
|
||||
submodule_cache_clear(cache);
|
||||
free(cache);
|
||||
}
|
||||
|
||||
static unsigned int hash_sha1_string(const unsigned char *sha1,
|
||||
|
@ -494,43 +509,62 @@ out:
|
|||
return submodule;
|
||||
}
|
||||
|
||||
static void ensure_cache_init(void)
|
||||
static void submodule_cache_check_init(struct repository *repo)
|
||||
{
|
||||
if (is_cache_init)
|
||||
if (repo->submodule_cache && repo->submodule_cache->initialized)
|
||||
return;
|
||||
|
||||
cache_init(&the_submodule_cache);
|
||||
is_cache_init = 1;
|
||||
if (!repo->submodule_cache)
|
||||
repo->submodule_cache = submodule_cache_alloc();
|
||||
|
||||
submodule_cache_init(repo->submodule_cache);
|
||||
}
|
||||
|
||||
int parse_submodule_config_option(const char *var, const char *value)
|
||||
int submodule_config_option(struct repository *repo,
|
||||
const char *var, const char *value)
|
||||
{
|
||||
struct parse_config_parameter parameter;
|
||||
parameter.cache = &the_submodule_cache;
|
||||
|
||||
submodule_cache_check_init(repo);
|
||||
|
||||
parameter.cache = repo->submodule_cache;
|
||||
parameter.treeish_name = NULL;
|
||||
parameter.gitmodules_sha1 = null_sha1;
|
||||
parameter.overwrite = 1;
|
||||
|
||||
ensure_cache_init();
|
||||
return parse_config(var, value, ¶meter);
|
||||
}
|
||||
|
||||
int parse_submodule_config_option(const char *var, const char *value)
|
||||
{
|
||||
return submodule_config_option(the_repository, var, value);
|
||||
}
|
||||
|
||||
const struct submodule *submodule_from_name(const unsigned char *treeish_name,
|
||||
const char *name)
|
||||
{
|
||||
ensure_cache_init();
|
||||
return config_from(&the_submodule_cache, treeish_name, name, lookup_name);
|
||||
submodule_cache_check_init(the_repository);
|
||||
return config_from(the_repository->submodule_cache, treeish_name, name, lookup_name);
|
||||
}
|
||||
|
||||
const struct submodule *submodule_from_path(const unsigned char *treeish_name,
|
||||
const char *path)
|
||||
{
|
||||
ensure_cache_init();
|
||||
return config_from(&the_submodule_cache, treeish_name, path, lookup_path);
|
||||
submodule_cache_check_init(the_repository);
|
||||
return config_from(the_repository->submodule_cache, treeish_name, path, lookup_path);
|
||||
}
|
||||
|
||||
const struct submodule *submodule_from_cache(struct repository *repo,
|
||||
const unsigned char *treeish_name,
|
||||
const char *key)
|
||||
{
|
||||
submodule_cache_check_init(repo);
|
||||
return config_from(repo->submodule_cache, treeish_name,
|
||||
key, lookup_path);
|
||||
}
|
||||
|
||||
void submodule_free(void)
|
||||
{
|
||||
cache_free(&the_submodule_cache);
|
||||
is_cache_init = 0;
|
||||
if (the_repository->submodule_cache)
|
||||
submodule_cache_clear(the_repository->submodule_cache);
|
||||
}
|
||||
|
|
|
@ -22,14 +22,24 @@ struct submodule {
|
|||
int recommend_shallow;
|
||||
};
|
||||
|
||||
struct submodule_cache;
|
||||
struct repository;
|
||||
|
||||
extern void submodule_cache_free(struct submodule_cache *cache);
|
||||
|
||||
extern int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);
|
||||
extern int parse_update_recurse_submodules_arg(const char *opt, const char *arg);
|
||||
extern int parse_push_recurse_submodules_arg(const char *opt, const char *arg);
|
||||
extern int parse_submodule_config_option(const char *var, const char *value);
|
||||
extern int submodule_config_option(struct repository *repo,
|
||||
const char *var, const char *value);
|
||||
extern const struct submodule *submodule_from_name(
|
||||
const unsigned char *commit_or_tree, const char *name);
|
||||
extern const struct submodule *submodule_from_path(
|
||||
const unsigned char *commit_or_tree, const char *path);
|
||||
extern const struct submodule *submodule_from_cache(struct repository *repo,
|
||||
const unsigned char *treeish_name,
|
||||
const char *key);
|
||||
extern int gitmodule_sha1_from_commit(const unsigned char *commit_sha1,
|
||||
unsigned char *gitmodules_sha1,
|
||||
struct strbuf *rev);
|
||||
|
|
35
submodule.c
35
submodule.c
|
@ -1,4 +1,5 @@
|
|||
#include "cache.h"
|
||||
#include "repository.h"
|
||||
#include "config.h"
|
||||
#include "submodule-config.h"
|
||||
#include "submodule.h"
|
||||
|
@ -255,6 +256,20 @@ void gitmodules_config(void)
|
|||
}
|
||||
}
|
||||
|
||||
static int gitmodules_cb(const char *var, const char *value, void *data)
|
||||
{
|
||||
struct repository *repo = data;
|
||||
return submodule_config_option(repo, var, value);
|
||||
}
|
||||
|
||||
void repo_read_gitmodules(struct repository *repo)
|
||||
{
|
||||
char *gitmodules_path = repo_worktree_path(repo, ".gitmodules");
|
||||
|
||||
git_config_from_file(gitmodules_cb, gitmodules_path, repo);
|
||||
free(gitmodules_path);
|
||||
}
|
||||
|
||||
void gitmodules_config_sha1(const unsigned char *commit_sha1)
|
||||
{
|
||||
struct strbuf rev = STRBUF_INIT;
|
||||
|
@ -268,21 +283,17 @@ void gitmodules_config_sha1(const unsigned char *commit_sha1)
|
|||
}
|
||||
|
||||
/*
|
||||
* NEEDSWORK: With the addition of different configuration options to determine
|
||||
* if a submodule is of interests, the validity of this function's name comes
|
||||
* into question. Once the dust has settled and more concrete terminology is
|
||||
* decided upon, come up with a more proper name for this function. One
|
||||
* potential candidate could be 'is_submodule_active()'.
|
||||
*
|
||||
* Determine if a submodule has been initialized at a given 'path'
|
||||
*/
|
||||
int is_submodule_initialized(const char *path)
|
||||
int is_submodule_active(struct repository *repo, const char *path)
|
||||
{
|
||||
int ret = 0;
|
||||
char *key = NULL;
|
||||
char *value = NULL;
|
||||
const struct string_list *sl;
|
||||
const struct submodule *module = submodule_from_path(null_sha1, path);
|
||||
const struct submodule *module;
|
||||
|
||||
module = submodule_from_cache(repo, null_sha1, path);
|
||||
|
||||
/* early return if there isn't a path->module mapping */
|
||||
if (!module)
|
||||
|
@ -290,14 +301,14 @@ int is_submodule_initialized(const char *path)
|
|||
|
||||
/* submodule.<name>.active is set */
|
||||
key = xstrfmt("submodule.%s.active", module->name);
|
||||
if (!git_config_get_bool(key, &ret)) {
|
||||
if (!repo_config_get_bool(repo, key, &ret)) {
|
||||
free(key);
|
||||
return ret;
|
||||
}
|
||||
free(key);
|
||||
|
||||
/* submodule.active is set */
|
||||
sl = git_config_get_value_multi("submodule.active");
|
||||
sl = repo_config_get_value_multi(repo, "submodule.active");
|
||||
if (sl) {
|
||||
struct pathspec ps;
|
||||
struct argv_array args = ARGV_ARRAY_INIT;
|
||||
|
@ -317,7 +328,7 @@ int is_submodule_initialized(const char *path)
|
|||
|
||||
/* fallback to checking if the URL is set */
|
||||
key = xstrfmt("submodule.%s.url", module->name);
|
||||
ret = !git_config_get_string(key, &value);
|
||||
ret = !repo_config_get_string(repo, key, &value);
|
||||
|
||||
free(value);
|
||||
free(key);
|
||||
|
@ -1517,7 +1528,7 @@ int submodule_move_head(const char *path,
|
|||
const struct submodule *sub;
|
||||
int *error_code_ptr, error_code;
|
||||
|
||||
if (!is_submodule_initialized(path))
|
||||
if (!is_submodule_active(the_repository, path))
|
||||
return 0;
|
||||
|
||||
if (flags & SUBMODULE_MOVE_HEAD_FORCE)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef SUBMODULE_H
|
||||
#define SUBMODULE_H
|
||||
|
||||
struct repository;
|
||||
struct diff_options;
|
||||
struct argv_array;
|
||||
struct oid_array;
|
||||
|
@ -46,8 +47,9 @@ int option_parse_recurse_submodules_worktree_updater(const struct option *opt,
|
|||
const char *arg, int unset);
|
||||
void load_submodule_cache(void);
|
||||
extern void gitmodules_config(void);
|
||||
extern void repo_read_gitmodules(struct repository *repo);
|
||||
extern void gitmodules_config_sha1(const unsigned char *commit_sha1);
|
||||
extern int is_submodule_initialized(const char *path);
|
||||
extern int is_submodule_active(struct repository *repo, const char *path);
|
||||
/*
|
||||
* Determine if a submodule has been populated at a given 'path' by checking if
|
||||
* the <path>/.git resolves to a valid git repository.
|
||||
|
|
|
@ -135,6 +135,45 @@ test_expect_success '--recurse-submodules and pathspecs setup' '
|
|||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'inactive submodule' '
|
||||
test_when_finished "git config --bool submodule.submodule.active true" &&
|
||||
test_when_finished "git -C submodule config --bool submodule.subsub.active true" &&
|
||||
git config --bool submodule.submodule.active "false" &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
.gitmodules
|
||||
a
|
||||
b/b
|
||||
h.txt
|
||||
sib/file
|
||||
sub/file
|
||||
submodule
|
||||
EOF
|
||||
|
||||
git ls-files --recurse-submodules >actual &&
|
||||
test_cmp expect actual &&
|
||||
|
||||
git config --bool submodule.submodule.active "true" &&
|
||||
git -C submodule config --bool submodule.subsub.active "false" &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
.gitmodules
|
||||
a
|
||||
b/b
|
||||
h.txt
|
||||
sib/file
|
||||
sub/file
|
||||
submodule/.gitmodules
|
||||
submodule/c
|
||||
submodule/f.TXT
|
||||
submodule/g.txt
|
||||
submodule/subsub
|
||||
EOF
|
||||
|
||||
git ls-files --recurse-submodules >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '--recurse-submodules and pathspecs' '
|
||||
cat >expect <<-\EOF &&
|
||||
h.txt
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "cache.h"
|
||||
#include "repository.h"
|
||||
#include "refs.h"
|
||||
#include "strbuf.h"
|
||||
#include "worktree.h"
|
||||
|
@ -76,7 +77,7 @@ static struct worktree *get_linked_worktree(const char *id)
|
|||
if (!id)
|
||||
die("Missing linked worktree name");
|
||||
|
||||
strbuf_git_common_path(&path, "worktrees/%s/gitdir", id);
|
||||
strbuf_git_common_path(&path, the_repository, "worktrees/%s/gitdir", id);
|
||||
if (strbuf_read_file(&worktree_path, path.buf, 0) <= 0)
|
||||
/* invalid gitdir file */
|
||||
goto done;
|
||||
|
|
Загрузка…
Ссылка в новой задаче