Merge branch 'ps/refs-without-the-repository-updates'

Further clean-up the refs subsystem to stop relying on
the_repository, and instead use the repository associated to the
ref_store object.

* ps/refs-without-the-repository-updates:
  refs/packed: remove references to `the_hash_algo`
  refs/files: remove references to `the_hash_algo`
  refs/files: use correct repository
  refs: remove `dwim_log()`
  refs: drop `git_default_branch_name()`
  refs: pass repo when peeling objects
  refs: move object peeling into "object.c"
  refs: pass ref store when detecting dangling symrefs
  refs: convert iteration over replace refs to accept ref store
  refs: retrieve worktree ref stores via associated repository
  refs: refactor `resolve_gitlink_ref()` to accept a repository
  refs: pass repo when retrieving submodule ref store
  refs: track ref stores via strmap
  refs: implement releasing ref storages
  refs: rename `init_db` callback to avoid confusion
  refs: adjust names for `init` and `init_db` callbacks
This commit is contained in:
Junio C Hamano 2024-05-30 14:15:12 -07:00
commit 988499e295
52 changed files with 408 additions and 392 deletions

3
attr.c
View file

@ -1301,7 +1301,8 @@ static const char *builtin_object_mode_attr(struct index_state *istate, const ch
if (pos >= 0) {
if (S_ISGITLINK(istate->cache[pos]->ce_mode))
mode = istate->cache[pos]->ce_mode;
} else if (resolve_gitlink_ref(path, "HEAD", &oid) == 0) {
} else if (repo_resolve_gitlink_ref(the_repository, path,
"HEAD", &oid) == 0) {
mode = S_IFGITLINK;
}
}

View file

@ -1468,6 +1468,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
} else if (remote_head) {
our_head_points_at = NULL;
} else {
char *to_free = NULL;
const char *branch;
if (!mapped_refs) {
@ -1480,7 +1481,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
"refs/heads/", &branch)) {
unborn_head = xstrdup(transport_ls_refs_options.unborn_head_target);
} else {
branch = git_default_branch_name(0);
branch = to_free = repo_default_branch_name(the_repository, 0);
unborn_head = xstrfmt("refs/heads/%s", branch);
}
@ -1496,6 +1497,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
* a match.
*/
our_head_points_at = find_remote_branch(mapped_refs, branch);
free(to_free);
}
write_refspec_config(src_ref_prefix, our_head_points_at,

View file

@ -200,7 +200,7 @@ static int get_name(const char *path, const struct object_id *oid,
}
/* Is it annotated? */
if (!peel_iterated_oid(oid, &peeled)) {
if (!peel_iterated_oid(the_repository, oid, &peeled)) {
is_annotated = !oideq(oid, &peeled);
} else {
oidcpy(&peeled, oid);

View file

@ -1412,7 +1412,8 @@ static int prune_refs(struct display_state *display_state,
_("(none)"), ref->name,
&ref->new_oid, &ref->old_oid,
summary_width);
warn_dangling_symref(stderr, dangling_msg, ref->name);
refs_warn_dangling_symref(get_main_ref_store(the_repository),
stderr, dangling_msg, ref->name);
}
}

View file

@ -846,7 +846,7 @@ static int dfs_on_ref(const char *refname UNUSED,
struct commit_list *stack = NULL;
struct commit *commit;
if (!peel_iterated_oid(oid, &peeled))
if (!peel_iterated_oid(the_repository, oid, &peeled))
oid = &peeled;
if (oid_object_info(the_repository, oid, NULL) != OBJ_COMMIT)
return 0;

View file

@ -779,7 +779,7 @@ static int mark_tagged(const char *path UNUSED, const struct object_id *oid,
if (entry)
entry->tagged = 1;
if (!peel_iterated_oid(oid, &peeled)) {
if (!peel_iterated_oid(the_repository, oid, &peeled)) {
entry = packlist_find(&to_pack, &peeled);
if (entry)
entry->tagged = 1;
@ -3132,7 +3132,7 @@ static int add_ref_tag(const char *tag UNUSED, const struct object_id *oid,
{
struct object_id peeled;
if (!peel_iterated_oid(oid, &peeled) && obj_is_packed(&peeled))
if (!peel_iterated_oid(the_repository, oid, &peeled) && obj_is_packed(&peeled))
add_tag_chain(oid);
return 0;
}
@ -4081,7 +4081,7 @@ static int mark_bitmap_preferred_tip(const char *refname,
struct object_id peeled;
struct object *object;
if (!peel_iterated_oid(oid, &peeled))
if (!peel_iterated_oid(the_repository, oid, &peeled))
oid = &peeled;
object = parse_object_or_die(oid, refname);

View file

@ -378,7 +378,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
char *ref;
struct expire_reflog_policy_cb cb = { .cmd = cmd };
if (!dwim_log(argv[i], strlen(argv[i]), NULL, &ref)) {
if (!repo_dwim_log(the_repository, argv[i], strlen(argv[i]), NULL, &ref)) {
status |= error(_("%s points nowhere!"), argv[i]);
continue;
}

View file

@ -1477,7 +1477,8 @@ static int prune_remote(const char *remote, int dry_run)
abbrev_ref(refname, "refs/remotes/"));
}
warn_dangling_symrefs(stdout, dangling_msg, &refs_to_prune);
refs_warn_dangling_symrefs(get_main_ref_store(the_repository),
stdout, dangling_msg, &refs_to_prune);
string_list_clear(&refs_to_prune, 0);
free_remote_ref_states(&states);

View file

@ -673,7 +673,7 @@ static int midx_snapshot_ref_one(const char *refname UNUSED,
struct midx_snapshot_ref_data *data = _data;
struct object_id peeled;
if (!peel_iterated_oid(oid, &peeled))
if (!peel_iterated_oid(the_repository, oid, &peeled))
oid = &peeled;
if (oidset_insert(&data->seen, oid))

View file

@ -43,11 +43,12 @@ enum replace_format {
};
struct show_data {
struct repository *repo;
const char *pattern;
enum replace_format format;
};
static int show_reference(struct repository *r, const char *refname,
static int show_reference(const char *refname,
const struct object_id *oid,
int flag UNUSED, void *cb_data)
{
@ -62,11 +63,11 @@ static int show_reference(struct repository *r, const char *refname,
struct object_id object;
enum object_type obj_type, repl_type;
if (repo_get_oid(r, refname, &object))
if (repo_get_oid(data->repo, refname, &object))
return error(_("failed to resolve '%s' as a valid ref"), refname);
obj_type = oid_object_info(r, &object, NULL);
repl_type = oid_object_info(r, oid, NULL);
obj_type = oid_object_info(data->repo, &object, NULL);
repl_type = oid_object_info(data->repo, oid, NULL);
printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type),
oid_to_hex(oid), type_name(repl_type));
@ -80,6 +81,7 @@ static int list_replace_refs(const char *pattern, const char *format)
{
struct show_data data;
data.repo = the_repository;
if (!pattern)
pattern = "*";
data.pattern = pattern;
@ -99,7 +101,8 @@ static int list_replace_refs(const char *pattern, const char *format)
"valid formats are 'short', 'medium' and 'long'"),
format);
for_each_replace_ref(the_repository, show_reference, (void *)&data);
refs_for_each_replace_ref(get_main_ref_store(the_repository),
show_reference, (void *)&data);
return 0;
}

View file

@ -50,7 +50,7 @@ static void show_one(const struct show_one_options *opts,
if (!opts->deref_tags)
return;
if (!peel_iterated_oid(oid, &peeled)) {
if (!peel_iterated_oid(the_repository, oid, &peeled)) {
hex = repo_find_unique_abbrev(the_repository, &peeled, opts->abbrev);
printf("%s %s^{}\n", hex, refname);
}

View file

@ -679,7 +679,8 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
displaypath);
} else if (!(flags & OPT_CACHED)) {
struct object_id oid;
struct ref_store *refs = get_submodule_ref_store(path);
struct ref_store *refs = repo_get_submodule_ref_store(the_repository,
path);
if (!refs) {
print_status(flags, '-', path, ce_oid, displaypath);
@ -903,7 +904,8 @@ static void generate_submodule_summary(struct summary_cb *info,
if (!info->cached && oideq(&p->oid_dst, null_oid())) {
if (S_ISGITLINK(p->mod_dst)) {
struct ref_store *refs = get_submodule_ref_store(p->sm_path);
struct ref_store *refs = repo_get_submodule_ref_store(the_repository,
p->sm_path);
if (refs)
refs_head_ref(refs, handle_submodule_head_ref, &p->oid_dst);
@ -2598,7 +2600,8 @@ static int update_submodule(struct update_data *update_data)
if (update_data->just_cloned)
oidcpy(&update_data->suboid, null_oid());
else if (resolve_gitlink_ref(update_data->sm_path, "HEAD", &update_data->suboid))
else if (repo_resolve_gitlink_ref(the_repository, update_data->sm_path,
"HEAD", &update_data->suboid))
return die_message(_("Unable to find current revision in submodule path '%s'"),
update_data->displaypath);
@ -2625,7 +2628,8 @@ static int update_submodule(struct update_data *update_data)
update_data->sm_path);
}
if (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))
if (repo_resolve_gitlink_ref(the_repository, update_data->sm_path,
remote_ref, &update_data->oid))
return die_message(_("Unable to find %s revision in submodule path '%s'"),
remote_ref, update_data->sm_path);
@ -3355,7 +3359,7 @@ static void die_on_repo_without_commits(const char *path)
strbuf_addstr(&sb, path);
if (is_nonbare_repository_dir(&sb)) {
struct object_id oid;
if (resolve_gitlink_ref(path, "HEAD", &oid) < 0)
if (repo_resolve_gitlink_ref(the_repository, path, "HEAD", &oid) < 0)
die(_("'%s' does not have a commit checked out"), path);
}
strbuf_release(&sb);

View file

@ -349,7 +349,8 @@ static int process_directory(const char *path, int len, struct stat *st)
if (S_ISGITLINK(ce->ce_mode)) {
/* Do nothing to the index if there is no HEAD! */
if (resolve_gitlink_ref(path, "HEAD", &oid) < 0)
if (repo_resolve_gitlink_ref(the_repository, path,
"HEAD", &oid) < 0)
return 0;
return add_one_path(ce, path, len, st);
@ -375,7 +376,7 @@ static int process_directory(const char *path, int len, struct stat *st)
}
/* No match - should we add it as a gitlink? */
if (!resolve_gitlink_ref(path, "HEAD", &oid))
if (!repo_resolve_gitlink_ref(the_repository, path, "HEAD", &oid))
return add_one_path(NULL, path, len, st);
/* Error out. */

View file

@ -46,7 +46,7 @@ static char *pager(int ident_flag UNUSED)
static char *default_branch(int ident_flag UNUSED)
{
return xstrdup_or_null(git_default_branch_name(1));
return repo_default_branch_name(the_repository, 1);
}
static char *shell_path(int ident_flag UNUSED)

View file

@ -509,7 +509,7 @@ static int add_worktree(const char *path, const char *refname,
}
wt_refs = get_worktree_ref_store(wt);
ret = refs_init_db(wt_refs, REFS_INIT_DB_IS_WORKTREE, &sb);
ret = ref_store_create_on_disk(wt_refs, REF_STORE_CREATE_ON_DISK_IS_WORKTREE, &sb);
if (ret)
goto done;

View file

@ -1066,7 +1066,8 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
elem->mode = canon_mode(st.st_mode);
} else if (S_ISDIR(st.st_mode)) {
struct object_id oid;
if (resolve_gitlink_ref(elem->path, "HEAD", &oid) < 0)
if (repo_resolve_gitlink_ref(the_repository, elem->path,
"HEAD", &oid) < 0)
result = grab_blob(opt->repo, &elem->oid,
elem->mode, &result_size,
NULL, NULL);

View file

@ -1821,7 +1821,7 @@ static int add_ref_to_set(const char *refname UNUSED,
struct object_id peeled;
struct refs_cb_data *data = (struct refs_cb_data *)cb_data;
if (!peel_iterated_oid(oid, &peeled))
if (!peel_iterated_oid(the_repository, oid, &peeled))
oid = &peeled;
if (oid_object_info(the_repository, oid, NULL) == OBJ_COMMIT)
oidset_insert(data->commits, oid);

View file

@ -66,7 +66,8 @@ static int check_removed(const struct cache_entry *ce, struct stat *st)
* a directory --- the blob was removed!
*/
if (!S_ISGITLINK(ce->ce_mode) &&
resolve_gitlink_ref(ce->name, "HEAD", &sub))
repo_resolve_gitlink_ref(the_repository, ce->name,
"HEAD", &sub))
return 1;
}
return 0;

3
dir.c
View file

@ -3318,7 +3318,8 @@ static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up)
struct object_id submodule_head;
if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
!resolve_gitlink_ref(path->buf, "HEAD", &submodule_head)) {
!repo_resolve_gitlink_ref(the_repository, path->buf,
"HEAD", &submodule_head)) {
/* Do not descend and nuke a nested git work tree. */
if (kept_up)
*kept_up = 1;

View file

@ -110,7 +110,7 @@ static int send_ref(const char *refname, const struct object_id *oid,
if (data->peel && oid) {
struct object_id peeled;
if (!peel_iterated_oid(oid, &peeled))
if (!peel_iterated_oid(the_repository, oid, &peeled))
strbuf_addf(&data->buf, " peeled:%s", oid_to_hex(&peeled));
}

View file

@ -664,7 +664,7 @@ static int add_ref_to_pending(const char *refname,
return 0;
}
if (!peel_iterated_oid(oid, &peeled))
if (!peel_iterated_oid(the_repository, oid, &peeled))
oid = &peeled;
object = parse_object_or_die(oid, refname);

View file

@ -2669,7 +2669,7 @@ int index_path(struct index_state *istate, struct object_id *oid,
strbuf_release(&sb);
break;
case S_IFDIR:
return resolve_gitlink_ref(path, "HEAD", oid);
return repo_resolve_gitlink_ref(the_repository, path, "HEAD", oid);
default:
return error(_("%s: unsupported file type"), path);
}

View file

@ -207,6 +207,29 @@ struct object *lookup_object_by_type(struct repository *r,
}
}
enum peel_status peel_object(struct repository *r,
const struct object_id *name,
struct object_id *oid)
{
struct object *o = lookup_unknown_object(r, name);
if (o->type == OBJ_NONE) {
int type = oid_object_info(r, name, NULL);
if (type < 0 || !object_as_type(o, type, 0))
return PEEL_INVALID;
}
if (o->type != OBJ_TAG)
return PEEL_NON_TAG;
o = deref_tag_noverify(r, o);
if (!o)
return PEEL_INVALID;
oidcpy(oid, &o->oid);
return PEEL_PEELED;
}
struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p)
{
struct object *obj;

View file

@ -257,6 +257,41 @@ struct object *lookup_unknown_object(struct repository *r, const struct object_i
struct object *lookup_object_by_type(struct repository *r, const struct object_id *oid,
enum object_type type);
enum peel_status {
/* object was peeled successfully: */
PEEL_PEELED = 0,
/*
* object cannot be peeled because the named object (or an
* object referred to by a tag in the peel chain), does not
* exist.
*/
PEEL_INVALID = -1,
/* object cannot be peeled because it is not a tag: */
PEEL_NON_TAG = -2,
/* ref_entry contains no peeled value because it is a symref: */
PEEL_IS_SYMREF = -3,
/*
* ref_entry cannot be peeled because it is broken (i.e., the
* symbolic reference cannot even be resolved to an object
* name):
*/
PEEL_BROKEN = -4
};
/*
* Peel the named object; i.e., if the object is a tag, resolve the
* tag recursively until a non-tag is found. If successful, store the
* result to oid and return PEEL_PEELED. If the object is not a tag
* or is not valid, return PEEL_NON_TAG or PEEL_INVALID, respectively,
* and leave oid unchanged.
*/
enum peel_status peel_object(struct repository *r,
const struct object_id *name, struct object_id *oid);
struct object_list *object_list_insert(struct object *item,
struct object_list **list_p);

View file

@ -271,7 +271,8 @@ static int ce_compare_gitlink(const struct cache_entry *ce)
*
* If so, we consider it always to match.
*/
if (resolve_gitlink_ref(ce->name, "HEAD", &oid) < 0)
if (repo_resolve_gitlink_ref(the_repository, ce->name,
"HEAD", &oid) < 0)
return 0;
return !oideq(&oid, &ce->oid);
}
@ -711,7 +712,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
namelen = strlen(path);
if (S_ISDIR(st_mode)) {
if (resolve_gitlink_ref(path, "HEAD", &oid) < 0)
if (repo_resolve_gitlink_ref(the_repository, path, "HEAD", &oid) < 0)
return error(_("'%s' does not have a commit checked out"), path);
while (namelen && path[namelen-1] == '/')
namelen--;

View file

@ -2520,7 +2520,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
* If it is a tag object, see if we use the peeled value. If we do,
* grab the peeled OID.
*/
if (need_tagged && peel_iterated_oid(&obj->oid, &oi_deref.oid))
if (need_tagged && peel_iterated_oid(the_repository, &obj->oid, &oi_deref.oid))
die("bad tag");
return get_object(ref, 1, &obj, &oi_deref, err);

View file

@ -191,7 +191,7 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
reflogs = read_complete_reflog(branch);
if (!reflogs || reflogs->nr == 0) {
char *b;
int ret = dwim_log(branch, strlen(branch),
int ret = repo_dwim_log(the_repository, branch, strlen(branch),
NULL, &b);
if (ret > 1)
free(b);

View file

@ -409,7 +409,7 @@ int reflog_delete(const char *rev, enum expire_reflog_flags flags, int verbose)
if (!spec)
return error(_("not a reflog: %s"), rev);
if (!dwim_log(rev, spec - rev, NULL, &ref)) {
if (!repo_dwim_log(the_repository, rev, spec - rev, NULL, &ref)) {
status |= error(_("no reflog for '%s'"), rev);
goto cleanup;
}

260
refs.c
View file

@ -6,7 +6,7 @@
#include "advice.h"
#include "config.h"
#include "environment.h"
#include "hashmap.h"
#include "strmap.h"
#include "gettext.h"
#include "hex.h"
#include "lockfile.h"
@ -19,7 +19,6 @@
#include "object-store-ll.h"
#include "object.h"
#include "path.h"
#include "tag.h"
#include "submodule.h"
#include "worktree.h"
#include "strvec.h"
@ -425,28 +424,8 @@ static int for_each_filter_refs(const char *refname,
return filter->fn(refname, oid, flags, filter->cb_data);
}
enum peel_status peel_object(const struct object_id *name, struct object_id *oid)
{
struct object *o = lookup_unknown_object(the_repository, name);
if (o->type == OBJ_NONE) {
int type = oid_object_info(the_repository, name, NULL);
if (type < 0 || !object_as_type(o, type, 0))
return PEEL_INVALID;
}
if (o->type != OBJ_TAG)
return PEEL_NON_TAG;
o = deref_tag_noverify(o);
if (!o)
return PEEL_INVALID;
oidcpy(oid, &o->oid);
return PEEL_PEELED;
}
struct warn_if_dangling_data {
struct ref_store *refs;
FILE *fp;
const char *refname;
const struct string_list *refnames;
@ -463,8 +442,7 @@ static int warn_if_dangling_symref(const char *refname,
if (!(flags & REF_ISSYMREF))
return 0;
resolves_to = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
refname, 0, NULL, NULL);
resolves_to = refs_resolve_ref_unsafe(d->refs, refname, 0, NULL, NULL);
if (!resolves_to
|| (d->refname
? strcmp(resolves_to, d->refname)
@ -477,28 +455,28 @@ static int warn_if_dangling_symref(const char *refname,
return 0;
}
void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)
void refs_warn_dangling_symref(struct ref_store *refs, FILE *fp,
const char *msg_fmt, const char *refname)
{
struct warn_if_dangling_data data;
data.fp = fp;
data.refname = refname;
data.refnames = NULL;
data.msg_fmt = msg_fmt;
refs_for_each_rawref(get_main_ref_store(the_repository),
warn_if_dangling_symref, &data);
struct warn_if_dangling_data data = {
.refs = refs,
.fp = fp,
.refname = refname,
.msg_fmt = msg_fmt,
};
refs_for_each_rawref(refs, warn_if_dangling_symref, &data);
}
void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_list *refnames)
void refs_warn_dangling_symrefs(struct ref_store *refs, FILE *fp,
const char *msg_fmt, const struct string_list *refnames)
{
struct warn_if_dangling_data data;
data.fp = fp;
data.refname = NULL;
data.refnames = refnames;
data.msg_fmt = msg_fmt;
refs_for_each_rawref(get_main_ref_store(the_repository),
warn_if_dangling_symref, &data);
struct warn_if_dangling_data data = {
.refs = refs,
.fp = fp,
.refnames = refnames,
.msg_fmt = msg_fmt,
};
refs_for_each_rawref(refs, warn_if_dangling_symref, &data);
}
int refs_for_each_tag_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
@ -686,16 +664,6 @@ char *repo_default_branch_name(struct repository *r, int quiet)
return ret;
}
const char *git_default_branch_name(int quiet)
{
static char *ret;
if (!ret)
ret = repo_default_branch_name(the_repository, quiet);
return ret;
}
/*
* *string and *len will only be substituted, and *string returned (for
* later free()ing) if the string passed in is a magic short-hand form
@ -807,11 +775,6 @@ int repo_dwim_log(struct repository *r, const char *str, int len,
return logs_found;
}
int dwim_log(const char *str, int len, struct object_id *oid, char **log)
{
return repo_dwim_log(the_repository, str, len, oid, log);
}
int is_per_worktree_ref(const char *refname)
{
return starts_with(refname, "refs/worktree/") ||
@ -1597,53 +1560,12 @@ struct ref_iterator *refs_ref_iterator_begin(
return iter;
}
/*
* Call fn for each reference in the specified submodule for which the
* refname begins with prefix. If trim is non-zero, then trim that
* many characters off the beginning of each refname before passing
* the refname to fn. flags can be DO_FOR_EACH_INCLUDE_BROKEN to
* include broken references in the iteration. If fn ever returns a
* non-zero value, stop the iteration and return that value;
* otherwise, return 0.
*/
static int do_for_each_repo_ref(struct repository *r, const char *prefix,
each_repo_ref_fn fn, int trim, int flags,
void *cb_data)
{
struct ref_iterator *iter;
struct ref_store *refs = get_main_ref_store(r);
if (!refs)
return 0;
iter = refs_ref_iterator_begin(refs, prefix, NULL, trim, flags);
return do_for_each_repo_ref_iterator(r, iter, fn, cb_data);
}
struct do_for_each_ref_help {
each_ref_fn *fn;
void *cb_data;
};
static int do_for_each_ref_helper(struct repository *r UNUSED,
const char *refname,
const struct object_id *oid,
int flags,
void *cb_data)
{
struct do_for_each_ref_help *hp = cb_data;
return hp->fn(refname, oid, flags, hp->cb_data);
}
static int do_for_each_ref(struct ref_store *refs, const char *prefix,
const char **exclude_patterns,
each_ref_fn fn, int trim,
enum do_for_each_ref_flags flags, void *cb_data)
{
struct ref_iterator *iter;
struct do_for_each_ref_help hp = { fn, cb_data };
if (!refs)
return 0;
@ -1651,8 +1573,7 @@ static int do_for_each_ref(struct ref_store *refs, const char *prefix,
iter = refs_ref_iterator_begin(refs, prefix, exclude_patterns, trim,
flags);
return do_for_each_repo_ref_iterator(the_repository, iter,
do_for_each_ref_helper, &hp);
return do_for_each_ref_iterator(iter, fn, cb_data);
}
int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
@ -1673,10 +1594,10 @@ int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
return do_for_each_ref(refs, prefix, exclude_patterns, fn, 0, 0, cb_data);
}
int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data)
int refs_for_each_replace_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
{
const char *git_replace_ref_base = ref_namespace[NAMESPACE_REPLACE].ref;
return do_for_each_repo_ref(r, git_replace_ref_base, fn,
return do_for_each_ref(refs, git_replace_ref_base, NULL, fn,
strlen(git_replace_ref_base),
DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
}
@ -1928,19 +1849,19 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
}
/* backend functions */
int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err)
int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err)
{
return refs->be->init_db(refs, flags, err);
return refs->be->create_on_disk(refs, flags, err);
}
int resolve_gitlink_ref(const char *submodule, const char *refname,
int repo_resolve_gitlink_ref(struct repository *r,
const char *submodule, const char *refname,
struct object_id *oid)
{
struct ref_store *refs;
int flags;
refs = get_submodule_ref_store(submodule);
refs = repo_get_submodule_ref_store(r, submodule);
if (!refs)
return -1;
@ -1950,66 +1871,21 @@ int resolve_gitlink_ref(const char *submodule, const char *refname,
return 0;
}
struct ref_store_hash_entry
{
struct hashmap_entry ent;
struct ref_store *refs;
/* NUL-terminated identifier of the ref store: */
char name[FLEX_ARRAY];
};
static int ref_store_hash_cmp(const void *cmp_data UNUSED,
const struct hashmap_entry *eptr,
const struct hashmap_entry *entry_or_key,
const void *keydata)
{
const struct ref_store_hash_entry *e1, *e2;
const char *name;
e1 = container_of(eptr, const struct ref_store_hash_entry, ent);
e2 = container_of(entry_or_key, const struct ref_store_hash_entry, ent);
name = keydata ? keydata : e2->name;
return strcmp(e1->name, name);
}
static struct ref_store_hash_entry *alloc_ref_store_hash_entry(
const char *name, struct ref_store *refs)
{
struct ref_store_hash_entry *entry;
FLEX_ALLOC_STR(entry, name, name);
hashmap_entry_init(&entry->ent, strhash(name));
entry->refs = refs;
return entry;
}
/* A hashmap of ref_stores, stored by submodule name: */
static struct hashmap submodule_ref_stores;
/* A hashmap of ref_stores, stored by worktree id: */
static struct hashmap worktree_ref_stores;
/*
* Look up a ref store by name. If that ref_store hasn't been
* registered yet, return NULL.
*/
static struct ref_store *lookup_ref_store_map(struct hashmap *map,
static struct ref_store *lookup_ref_store_map(struct strmap *map,
const char *name)
{
struct ref_store_hash_entry *entry;
unsigned int hash;
struct strmap_entry *entry;
if (!map->tablesize)
if (!map->map.tablesize)
/* It's initialized on demand in register_ref_store(). */
return NULL;
hash = strhash(name);
entry = hashmap_get_entry_from_hash(map, hash, name,
struct ref_store_hash_entry, ent);
return entry ? entry->refs : NULL;
entry = strmap_get_entry(map, name);
return entry ? entry->value : NULL;
}
/*
@ -2031,6 +1907,12 @@ static struct ref_store *ref_store_init(struct repository *repo,
return refs;
}
void ref_store_release(struct ref_store *ref_store)
{
ref_store->be->release(ref_store);
free(ref_store->gitdir);
}
struct ref_store *get_main_ref_store(struct repository *r)
{
if (r->refs_private)
@ -2048,22 +1930,19 @@ struct ref_store *get_main_ref_store(struct repository *r)
* Associate a ref store with a name. It is a fatal error to call this
* function twice for the same name.
*/
static void register_ref_store_map(struct hashmap *map,
static void register_ref_store_map(struct strmap *map,
const char *type,
struct ref_store *refs,
const char *name)
{
struct ref_store_hash_entry *entry;
if (!map->tablesize)
hashmap_init(map, ref_store_hash_cmp, NULL, 0);
entry = alloc_ref_store_hash_entry(name, refs);
if (hashmap_put(map, &entry->ent))
if (!map->map.tablesize)
strmap_init(map);
if (strmap_put(map, name, refs))
BUG("%s ref_store '%s' initialized twice", type, name);
}
struct ref_store *get_submodule_ref_store(const char *submodule)
struct ref_store *repo_get_submodule_ref_store(struct repository *repo,
const char *submodule)
{
struct strbuf submodule_sb = STRBUF_INIT;
struct ref_store *refs;
@ -2084,7 +1963,7 @@ struct ref_store *get_submodule_ref_store(const char *submodule)
/* We need to strip off one or more trailing slashes */
submodule = to_free = xmemdupz(submodule, len);
refs = lookup_ref_store_map(&submodule_ref_stores, submodule);
refs = lookup_ref_store_map(&repo->submodule_ref_stores, submodule);
if (refs)
goto done;
@ -2096,20 +1975,15 @@ struct ref_store *get_submodule_ref_store(const char *submodule)
goto done;
subrepo = xmalloc(sizeof(*subrepo));
/*
* NEEDSWORK: Make get_submodule_ref_store() work with arbitrary
* superprojects other than the_repository. This probably should be
* done by making it take a struct repository * parameter instead of a
* submodule path.
*/
if (repo_submodule_init(subrepo, the_repository, submodule,
if (repo_submodule_init(subrepo, repo, submodule,
null_oid())) {
free(subrepo);
goto done;
}
refs = ref_store_init(subrepo, submodule_sb.buf,
REF_STORE_READ | REF_STORE_ODB);
register_ref_store_map(&submodule_ref_stores, "submodule",
register_ref_store_map(&repo->submodule_ref_stores, "submodule",
refs, submodule);
done:
@ -2125,25 +1999,29 @@ struct ref_store *get_worktree_ref_store(const struct worktree *wt)
const char *id;
if (wt->is_current)
return get_main_ref_store(the_repository);
return get_main_ref_store(wt->repo);
id = wt->id ? wt->id : "/";
refs = lookup_ref_store_map(&worktree_ref_stores, id);
refs = lookup_ref_store_map(&wt->repo->worktree_ref_stores, id);
if (refs)
return refs;
if (wt->id)
refs = ref_store_init(the_repository,
git_common_path("worktrees/%s", wt->id),
if (wt->id) {
struct strbuf common_path = STRBUF_INIT;
strbuf_git_common_path(&common_path, wt->repo,
"worktrees/%s", wt->id);
refs = ref_store_init(wt->repo, common_path.buf,
REF_STORE_ALL_CAPS);
else
refs = ref_store_init(the_repository,
get_git_common_dir(),
strbuf_release(&common_path);
} else {
refs = ref_store_init(wt->repo, wt->repo->commondir,
REF_STORE_ALL_CAPS);
}
if (refs)
register_ref_store_map(&worktree_ref_stores, "worktree",
refs, id);
register_ref_store_map(&wt->repo->worktree_ref_stores,
"worktree", refs, id);
return refs;
}
@ -2161,14 +2039,14 @@ int refs_pack_refs(struct ref_store *refs, struct pack_refs_opts *opts)
return refs->be->pack_refs(refs, opts);
}
int peel_iterated_oid(const struct object_id *base, struct object_id *peeled)
int peel_iterated_oid(struct repository *r, const struct object_id *base, struct object_id *peeled)
{
if (current_ref_iter &&
(current_ref_iter->oid == base ||
oideq(current_ref_iter->oid, base)))
return ref_iterator_peel(current_ref_iter, peeled);
return peel_object(base, peeled) ? -1 : 0;
return peel_object(r, base, peeled) ? -1 : 0;
}
int refs_update_symref(struct ref_store *refs, const char *ref,
@ -2478,8 +2356,7 @@ struct do_for_each_reflog_help {
void *cb_data;
};
static int do_for_each_reflog_helper(struct repository *r UNUSED,
const char *refname,
static int do_for_each_reflog_helper(const char *refname,
const struct object_id *oid UNUSED,
int flags,
void *cb_data)
@ -2495,8 +2372,7 @@ int refs_for_each_reflog(struct ref_store *refs, each_reflog_fn fn, void *cb_dat
iter = refs->be->reflog_iterator_begin(refs);
return do_for_each_repo_ref_iterator(the_repository, iter,
do_for_each_reflog_helper, &hp);
return do_for_each_ref_iterator(iter, do_for_each_reflog_helper, &hp);
}
int refs_for_each_reflog_ent_reverse(struct ref_store *refs,

49
refs.h
View file

@ -114,21 +114,27 @@ int should_autocreate_reflog(const char *refname);
int is_branch(const char *refname);
#define REFS_INIT_DB_IS_WORKTREE (1 << 0)
#define REF_STORE_CREATE_ON_DISK_IS_WORKTREE (1 << 0)
int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err);
int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err);
/*
* Release all memory and resources associated with the ref store.
*/
void ref_store_release(struct ref_store *ref_store);
/*
* Return the peeled value of the oid currently being iterated via
* for_each_ref(), etc. This is equivalent to calling:
*
* peel_object(oid, &peeled);
* peel_object(r, oid, &peeled);
*
* with the "oid" value given to the each_ref_fn callback, except
* that some ref storage may be able to answer the query without
* actually loading the object in memory.
*/
int peel_iterated_oid(const struct object_id *base, struct object_id *peeled);
int peel_iterated_oid(struct repository *r,
const struct object_id *base, struct object_id *peeled);
/**
* Resolve refname in the nested "gitlink" repository in the specified
@ -136,7 +142,8 @@ int peel_iterated_oid(const struct object_id *base, struct object_id *peeled);
* successful, return 0 and set oid to the name of the object;
* otherwise, return a non-zero value.
*/
int resolve_gitlink_ref(const char *submodule, const char *refname,
int repo_resolve_gitlink_ref(struct repository *r,
const char *submodule, const char *refname,
struct object_id *oid);
/*
@ -157,15 +164,12 @@ int expand_ref(struct repository *r, const char *str, int len, struct object_id
int repo_dwim_ref(struct repository *r, const char *str, int len,
struct object_id *oid, char **ref, int nonfatal_dangling_mark);
int repo_dwim_log(struct repository *r, const char *str, int len, struct object_id *oid, char **ref);
int dwim_log(const char *str, int len, struct object_id *oid, char **ref);
/*
* Retrieves the default branch name for newly-initialized repositories.
*
* The return value of `repo_default_branch_name()` is an allocated string. The
* return value of `git_default_branch_name()` is a singleton.
* The return value is an allocated string.
*/
const char *git_default_branch_name(int quiet);
char *repo_default_branch_name(struct repository *r, int quiet);
/*
@ -292,16 +296,6 @@ struct ref_transaction;
typedef int each_ref_fn(const char *refname,
const struct object_id *oid, int flags, void *cb_data);
/*
* The same as each_ref_fn, but also with a repository argument that
* contains the repository associated with the callback.
*/
typedef int each_repo_ref_fn(struct repository *r,
const char *refname,
const struct object_id *oid,
int flags,
void *cb_data);
/*
* The following functions invoke the specified callback function for
* each reference indicated. If the function ever returns a nonzero
@ -323,6 +317,8 @@ int refs_for_each_branch_ref(struct ref_store *refs,
each_ref_fn fn, void *cb_data);
int refs_for_each_remote_ref(struct ref_store *refs,
each_ref_fn fn, void *cb_data);
int refs_for_each_replace_ref(struct ref_store *refs,
each_ref_fn fn, void *cb_data);
/*
* references matching any pattern in "exclude_patterns" are omitted from the
@ -347,11 +343,6 @@ int refs_for_each_fullref_in_prefixes(struct ref_store *refs,
const char **exclude_patterns,
each_ref_fn fn, void *cb_data);
/**
* iterate refs from the respective area.
*/
int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data);
/* iterates all refs that match the specified glob pattern. */
int refs_for_each_glob_ref(struct ref_store *refs, each_ref_fn fn,
const char *pattern, void *cb_data);
@ -395,9 +386,10 @@ static inline const char *has_glob_specials(const char *pattern)
return strpbrk(pattern, "?*[");
}
void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname);
void warn_dangling_symrefs(FILE *fp, const char *msg_fmt,
const struct string_list *refnames);
void refs_warn_dangling_symref(struct ref_store *refs, FILE *fp,
const char *msg_fmt, const char *refname);
void refs_warn_dangling_symrefs(struct ref_store *refs, FILE *fp,
const char *msg_fmt, const struct string_list *refnames);
/*
* Flags for controlling behaviour of pack_refs()
@ -965,7 +957,8 @@ struct ref_store *get_main_ref_store(struct repository *r);
* For backwards compatibility, submodule=="" is treated the same as
* submodule==NULL.
*/
struct ref_store *get_submodule_ref_store(const char *submodule);
struct ref_store *repo_get_submodule_ref_store(struct repository *repo,
const char *submodule);
struct ref_store *get_worktree_ref_store(const struct worktree *wt);
/*

View file

@ -33,11 +33,18 @@ struct ref_store *maybe_debug_wrap_ref_store(const char *gitdir, struct ref_stor
return (struct ref_store *)res;
}
static int debug_init_db(struct ref_store *refs, int flags, struct strbuf *err)
static void debug_release(struct ref_store *refs)
{
struct debug_ref_store *drefs = (struct debug_ref_store *)refs;
int res = drefs->refs->be->init_db(drefs->refs, flags, err);
trace_printf_key(&trace_refs, "init_db: %d\n", res);
drefs->refs->be->release(drefs->refs);
trace_printf_key(&trace_refs, "release\n");
}
static int debug_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err)
{
struct debug_ref_store *drefs = (struct debug_ref_store *)refs;
int res = drefs->refs->be->create_on_disk(drefs->refs, flags, err);
trace_printf_key(&trace_refs, "create_on_disk: %d\n", res);
return res;
}
@ -415,7 +422,8 @@ static int debug_reflog_expire(struct ref_store *ref_store, const char *refname,
struct ref_storage_be refs_be_debug = {
.name = "debug",
.init = NULL,
.init_db = debug_init_db,
.release = debug_release,
.create_on_disk = debug_create_on_disk,
/*
* None of these should be NULL. If the "files" backend (in

View file

@ -89,7 +89,7 @@ static void clear_loose_ref_cache(struct files_ref_store *refs)
* Create a new submodule ref cache and add it to the internal
* set of caches.
*/
static struct ref_store *files_ref_store_create(struct repository *repo,
static struct ref_store *files_ref_store_init(struct repository *repo,
const char *gitdir,
unsigned int flags)
{
@ -102,7 +102,7 @@ static struct ref_store *files_ref_store_create(struct repository *repo,
get_common_dir_noenv(&sb, gitdir);
refs->gitcommondir = strbuf_detach(&sb, NULL);
refs->packed_ref_store =
packed_ref_store_create(repo, refs->gitcommondir, flags);
packed_ref_store_init(repo, refs->gitcommondir, flags);
chdir_notify_reparent("files-backend $GIT_DIR", &refs->base.gitdir);
chdir_notify_reparent("files-backend $GIT_COMMONDIR",
@ -149,6 +149,14 @@ static struct files_ref_store *files_downcast(struct ref_store *ref_store,
return refs;
}
static void files_ref_store_release(struct ref_store *ref_store)
{
struct files_ref_store *refs = files_downcast(ref_store, 0, "release");
free_ref_cache(refs->loose);
free(refs->gitcommondir);
ref_store_release(refs->packed_ref_store);
}
static void files_reflog_path(struct files_ref_store *refs,
struct strbuf *sb,
const char *refname)
@ -1230,7 +1238,8 @@ static void prune_refs(struct files_ref_store *refs, struct ref_to_prune **refs_
/*
* Return true if the specified reference should be packed.
*/
static int should_pack_ref(const char *refname,
static int should_pack_ref(struct files_ref_store *refs,
const char *refname,
const struct object_id *oid, unsigned int ref_flags,
struct pack_refs_opts *opts)
{
@ -1246,7 +1255,7 @@ static int should_pack_ref(const char *refname,
return 0;
/* Do not pack broken refs: */
if (!ref_resolves_to_object(refname, the_repository, oid, ref_flags))
if (!ref_resolves_to_object(refname, refs->base.repo, oid, ref_flags))
return 0;
if (ref_excluded(opts->exclusions, refname))
@ -1278,14 +1287,14 @@ static int files_pack_refs(struct ref_store *ref_store,
packed_refs_lock(refs->packed_ref_store, LOCK_DIE_ON_ERROR, &err);
iter = cache_ref_iterator_begin(get_loose_ref_cache(refs, 0), NULL,
the_repository, 0);
refs->base.repo, 0);
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
/*
* If the loose reference can be packed, add an entry
* in the packed ref cache. If the reference should be
* pruned, also add it to refs_to_prune.
*/
if (!should_pack_ref(iter->refname, iter->oid, iter->flags, opts))
if (!should_pack_ref(refs, iter->refname, iter->oid, iter->flags, opts))
continue;
/*
@ -1382,7 +1391,8 @@ static int rename_tmp_log(struct files_ref_store *refs, const char *newrefname)
return ret;
}
static int write_ref_to_lockfile(struct ref_lock *lock,
static int write_ref_to_lockfile(struct files_ref_store *refs,
struct ref_lock *lock,
const struct object_id *oid,
int skip_oid_verification, struct strbuf *err);
static int commit_ref_update(struct files_ref_store *refs,
@ -1530,7 +1540,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
}
oidcpy(&lock->old_oid, &orig_oid);
if (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||
if (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||
commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) {
error("unable to write current sha1 into %s: %s", newrefname, err.buf);
strbuf_release(&err);
@ -1550,7 +1560,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
flag = log_all_ref_updates;
log_all_ref_updates = LOG_REFS_NONE;
if (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||
if (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||
commit_ref_update(refs, lock, &orig_oid, NULL, &err)) {
error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
strbuf_release(&err);
@ -1784,7 +1794,8 @@ static int files_log_ref_write(struct files_ref_store *refs,
* Write oid into the open lockfile, then close the lockfile. On
* errors, rollback the lockfile, fill in *err and return -1.
*/
static int write_ref_to_lockfile(struct ref_lock *lock,
static int write_ref_to_lockfile(struct files_ref_store *refs,
struct ref_lock *lock,
const struct object_id *oid,
int skip_oid_verification, struct strbuf *err)
{
@ -1793,7 +1804,7 @@ static int write_ref_to_lockfile(struct ref_lock *lock,
int fd;
if (!skip_oid_verification) {
o = parse_object(the_repository, oid);
o = parse_object(refs->base.repo, oid);
if (!o) {
strbuf_addf(
err,
@ -1812,7 +1823,7 @@ static int write_ref_to_lockfile(struct ref_lock *lock,
}
}
fd = get_lock_file_fd(&lock->lk);
if (write_in_full(fd, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||
if (write_in_full(fd, oid_to_hex(oid), refs->base.repo->hash_algo->hexsz) < 0 ||
write_in_full(fd, &term, 1) < 0 ||
fsync_component(FSYNC_COMPONENT_REFERENCE, get_lock_file_fd(&lock->lk)) < 0 ||
close_ref_gently(lock) < 0) {
@ -2547,7 +2558,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
* value, so we don't need to write it.
*/
} else if (write_ref_to_lockfile(
lock, &update->new_oid,
refs, lock, &update->new_oid,
update->flags & REF_SKIP_OID_VERIFICATION,
err)) {
char *write_err = strbuf_detach(err, NULL);
@ -3230,7 +3241,7 @@ static int files_reflog_expire(struct ref_store *ref_store,
rollback_lock_file(&reflog_lock);
} else if (update &&
(write_in_full(get_lock_file_fd(&lock->lk),
oid_to_hex(&cb.last_kept_oid), the_hash_algo->hexsz) < 0 ||
oid_to_hex(&cb.last_kept_oid), refs->base.repo->hash_algo->hexsz) < 0 ||
write_str_in_full(get_lock_file_fd(&lock->lk), "\n") < 0 ||
close_ref_gently(lock) < 0)) {
status |= error("couldn't write %s",
@ -3254,12 +3265,12 @@ static int files_reflog_expire(struct ref_store *ref_store,
return -1;
}
static int files_init_db(struct ref_store *ref_store,
static int files_ref_store_create_on_disk(struct ref_store *ref_store,
int flags,
struct strbuf *err UNUSED)
{
struct files_ref_store *refs =
files_downcast(ref_store, REF_STORE_WRITE, "init_db");
files_downcast(ref_store, REF_STORE_WRITE, "create");
struct strbuf sb = STRBUF_INIT;
/*
@ -3282,7 +3293,7 @@ static int files_init_db(struct ref_store *ref_store,
* There is no need to create directories for common refs when creating
* a worktree ref store.
*/
if (!(flags & REFS_INIT_DB_IS_WORKTREE)) {
if (!(flags & REF_STORE_CREATE_ON_DISK_IS_WORKTREE)) {
/*
* Create .git/refs/{heads,tags}
*/
@ -3301,8 +3312,10 @@ static int files_init_db(struct ref_store *ref_store,
struct ref_storage_be refs_be_files = {
.name = "files",
.init = files_ref_store_create,
.init_db = files_init_db,
.init = files_ref_store_init,
.release = files_ref_store_release,
.create_on_disk = files_ref_store_create_on_disk,
.transaction_prepare = files_transaction_prepare,
.transaction_finish = files_transaction_finish,
.transaction_abort = files_transaction_abort,

View file

@ -440,15 +440,15 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,
struct ref_iterator *current_ref_iter = NULL;
int do_for_each_repo_ref_iterator(struct repository *r, struct ref_iterator *iter,
each_repo_ref_fn fn, void *cb_data)
int do_for_each_ref_iterator(struct ref_iterator *iter,
each_ref_fn fn, void *cb_data)
{
int retval = 0, ok;
struct ref_iterator *old_ref_iter = current_ref_iter;
current_ref_iter = iter;
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
retval = fn(r, iter->refname, iter->oid, iter->flags, cb_data);
retval = fn(iter->refname, iter->oid, iter->flags, cb_data);
if (retval) {
/*
* If ref_iterator_abort() returns ITER_ERROR,

View file

@ -200,7 +200,12 @@ static int release_snapshot(struct snapshot *snapshot)
}
}
struct ref_store *packed_ref_store_create(struct repository *repo,
static size_t snapshot_hexsz(const struct snapshot *snapshot)
{
return snapshot->refs->base.repo->hash_algo->hexsz;
}
struct ref_store *packed_ref_store_init(struct repository *repo,
const char *gitdir,
unsigned int store_flags)
{
@ -252,6 +257,15 @@ static void clear_snapshot(struct packed_ref_store *refs)
}
}
static void packed_ref_store_release(struct ref_store *ref_store)
{
struct packed_ref_store *refs = packed_downcast(ref_store, 0, "release");
clear_snapshot(refs);
rollback_lock_file(&refs->lock);
delete_tempfile(&refs->tempfile);
free(refs->path);
}
static NORETURN void die_unterminated_line(const char *path,
const char *p, size_t len)
{
@ -280,11 +294,13 @@ struct snapshot_record {
size_t len;
};
static int cmp_packed_ref_records(const void *v1, const void *v2)
static int cmp_packed_ref_records(const void *v1, const void *v2,
void *cb_data)
{
const struct snapshot *snapshot = cb_data;
const struct snapshot_record *e1 = v1, *e2 = v2;
const char *r1 = e1->start + the_hash_algo->hexsz + 1;
const char *r2 = e2->start + the_hash_algo->hexsz + 1;
const char *r1 = e1->start + snapshot_hexsz(snapshot) + 1;
const char *r2 = e2->start + snapshot_hexsz(snapshot) + 1;
while (1) {
if (*r1 == '\n')
@ -305,9 +321,9 @@ static int cmp_packed_ref_records(const void *v1, const void *v2)
* refname.
*/
static int cmp_record_to_refname(const char *rec, const char *refname,
int start)
int start, const struct snapshot *snapshot)
{
const char *r1 = rec + the_hash_algo->hexsz + 1;
const char *r1 = rec + snapshot_hexsz(snapshot) + 1;
const char *r2 = refname;
while (1) {
@ -354,7 +370,7 @@ static void sort_snapshot(struct snapshot *snapshot)
if (!eol)
/* The safety check should prevent this. */
BUG("unterminated line found in packed-refs");
if (eol - pos < the_hash_algo->hexsz + 2)
if (eol - pos < snapshot_hexsz(snapshot) + 2)
die_invalid_line(snapshot->refs->path,
pos, eof - pos);
eol++;
@ -380,7 +396,7 @@ static void sort_snapshot(struct snapshot *snapshot)
if (sorted &&
nr > 1 &&
cmp_packed_ref_records(&records[nr - 2],
&records[nr - 1]) >= 0)
&records[nr - 1], snapshot) >= 0)
sorted = 0;
pos = eol;
@ -390,7 +406,7 @@ static void sort_snapshot(struct snapshot *snapshot)
goto cleanup;
/* We need to sort the memory. First we sort the records array: */
QSORT(records, nr, cmp_packed_ref_records);
QSORT_S(records, nr, cmp_packed_ref_records, snapshot);
/*
* Allocate a new chunk of memory, and copy the old memory to
@ -466,7 +482,8 @@ static void verify_buffer_safe(struct snapshot *snapshot)
return;
last_line = find_start_of_record(start, eof - 1);
if (*(eof - 1) != '\n' || eof - last_line < the_hash_algo->hexsz + 2)
if (*(eof - 1) != '\n' ||
eof - last_line < snapshot_hexsz(snapshot) + 2)
die_invalid_line(snapshot->refs->path,
last_line, eof - last_line);
}
@ -561,7 +578,7 @@ static const char *find_reference_location_1(struct snapshot *snapshot,
mid = lo + (hi - lo) / 2;
rec = find_start_of_record(lo, mid);
cmp = cmp_record_to_refname(rec, refname, start);
cmp = cmp_record_to_refname(rec, refname, start, snapshot);
if (cmp < 0) {
lo = find_end_of_record(mid, hi);
} else if (cmp > 0) {
@ -858,7 +875,7 @@ static int next_record(struct packed_ref_iterator *iter)
iter->base.flags = REF_ISPACKED;
p = iter->pos;
if (iter->eof - p < the_hash_algo->hexsz + 2 ||
if (iter->eof - p < snapshot_hexsz(iter->snapshot) + 2 ||
parse_oid_hex(p, &iter->oid, &p) ||
!isspace(*p++))
die_invalid_line(iter->snapshot->refs->path,
@ -888,7 +905,7 @@ static int next_record(struct packed_ref_iterator *iter)
if (iter->pos < iter->eof && *iter->pos == '^') {
p = iter->pos + 1;
if (iter->eof - p < the_hash_algo->hexsz + 1 ||
if (iter->eof - p < snapshot_hexsz(iter->snapshot) + 1 ||
parse_oid_hex(p, &iter->peeled, &p) ||
*p++ != '\n')
die_invalid_line(iter->snapshot->refs->path,
@ -944,16 +961,13 @@ static int packed_ref_iterator_peel(struct ref_iterator *ref_iterator,
struct packed_ref_iterator *iter =
(struct packed_ref_iterator *)ref_iterator;
if (iter->repo != the_repository)
BUG("peeling for non-the_repository is not supported");
if ((iter->base.flags & REF_KNOWS_PEELED)) {
oidcpy(peeled, &iter->peeled);
return is_null_oid(&iter->peeled) ? -1 : 0;
} else if ((iter->base.flags & (REF_ISBROKEN | REF_ISSYMREF))) {
return -1;
} else {
return peel_object(&iter->oid, peeled) ? -1 : 0;
return peel_object(iter->repo, &iter->oid, peeled) ? -1 : 0;
}
}
@ -1244,7 +1258,7 @@ int packed_refs_is_locked(struct ref_store *ref_store)
static const char PACKED_REFS_HEADER[] =
"# pack-refs with: peeled fully-peeled sorted \n";
static int packed_init_db(struct ref_store *ref_store UNUSED,
static int packed_ref_store_create_on_disk(struct ref_store *ref_store UNUSED,
int flags UNUSED,
struct strbuf *err UNUSED)
{
@ -1412,7 +1426,8 @@ static int write_with_updates(struct packed_ref_store *refs,
i++;
} else {
struct object_id peeled;
int peel_error = peel_object(&update->new_oid,
int peel_error = peel_object(refs->base.repo,
&update->new_oid,
&peeled);
if (write_packed_entry(out, update->refname,
@ -1706,8 +1721,10 @@ static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_s
struct ref_storage_be refs_be_packed = {
.name = "packed",
.init = packed_ref_store_create,
.init_db = packed_init_db,
.init = packed_ref_store_init,
.release = packed_ref_store_release,
.create_on_disk = packed_ref_store_create_on_disk,
.transaction_prepare = packed_transaction_prepare,
.transaction_finish = packed_transaction_finish,
.transaction_abort = packed_transaction_abort,

View file

@ -13,7 +13,7 @@ struct ref_transaction;
* even among packed refs.
*/
struct ref_store *packed_ref_store_create(struct repository *repo,
struct ref_store *packed_ref_store_init(struct repository *repo,
const char *gitdir,
unsigned int store_flags);

View file

@ -441,10 +441,7 @@ static int cache_ref_iterator_peel(struct ref_iterator *ref_iterator,
{
struct cache_ref_iterator *iter =
(struct cache_ref_iterator *)ref_iterator;
if (iter->repo != the_repository)
BUG("peeling for non-the_repository is not supported");
return peel_object(ref_iterator->oid, peeled) ? -1 : 0;
return peel_object(iter->repo, ref_iterator->oid, peeled) ? -1 : 0;
}
static int cache_ref_iterator_abort(struct ref_iterator *ref_iterator)

View file

@ -69,40 +69,6 @@ int ref_resolves_to_object(const char *refname,
const struct object_id *oid,
unsigned int flags);
enum peel_status {
/* object was peeled successfully: */
PEEL_PEELED = 0,
/*
* object cannot be peeled because the named object (or an
* object referred to by a tag in the peel chain), does not
* exist.
*/
PEEL_INVALID = -1,
/* object cannot be peeled because it is not a tag: */
PEEL_NON_TAG = -2,
/* ref_entry contains no peeled value because it is a symref: */
PEEL_IS_SYMREF = -3,
/*
* ref_entry cannot be peeled because it is broken (i.e., the
* symbolic reference cannot even be resolved to an object
* name):
*/
PEEL_BROKEN = -4
};
/*
* Peel the named object; i.e., if the object is a tag, resolve the
* tag recursively until a non-tag is found. If successful, store the
* result to oid and return PEEL_PEELED. If the object is not a tag
* or is not valid, return PEEL_NON_TAG or PEEL_INVALID, respectively,
* and leave oid unchanged.
*/
enum peel_status peel_object(const struct object_id *name, struct object_id *oid);
/**
* Information needed for a single ref update. Set new_oid to the new
* value or to null_oid to delete the ref. To check the old value
@ -517,9 +483,8 @@ extern struct ref_iterator *current_ref_iter;
* adapter between the callback style of reference iteration and the
* iterator style.
*/
int do_for_each_repo_ref_iterator(struct repository *r,
struct ref_iterator *iter,
each_repo_ref_fn fn, void *cb_data);
int do_for_each_ref_iterator(struct ref_iterator *iter,
each_ref_fn fn, void *cb_data);
struct ref_store;
@ -543,8 +508,12 @@ struct ref_store;
typedef struct ref_store *ref_store_init_fn(struct repository *repo,
const char *gitdir,
unsigned int flags);
/*
* Release all memory and resources associated with the ref store.
*/
typedef void ref_store_release_fn(struct ref_store *refs);
typedef int ref_init_db_fn(struct ref_store *refs,
typedef int ref_store_create_on_disk_fn(struct ref_store *refs,
int flags,
struct strbuf *err);
@ -678,7 +647,8 @@ typedef int read_symbolic_ref_fn(struct ref_store *ref_store, const char *refnam
struct ref_storage_be {
const char *name;
ref_store_init_fn *init;
ref_init_db_fn *init_db;
ref_store_release_fn *release;
ref_store_create_on_disk_fn *create_on_disk;
ref_transaction_prepare_fn *transaction_prepare;
ref_transaction_finish_fn *transaction_finish;
@ -709,7 +679,7 @@ extern struct ref_storage_be refs_be_packed;
/*
* A representation of the reference store for the main repository or
* a submodule. The ref_store instances for submodules are kept in a
* hash map; see get_submodule_ref_store() for more info.
* hash map; see repo_get_submodule_ref_store() for more info.
*/
struct ref_store {
/* The backend describing this ref_store's storage scheme: */

View file

@ -333,12 +333,33 @@ static struct ref_store *reftable_be_init(struct repository *repo,
return &refs->base;
}
static int reftable_be_init_db(struct ref_store *ref_store,
static void reftable_be_release(struct ref_store *ref_store)
{
struct reftable_ref_store *refs = reftable_be_downcast(ref_store, 0, "release");
struct strmap_entry *entry;
struct hashmap_iter iter;
if (refs->main_stack) {
reftable_stack_destroy(refs->main_stack);
refs->main_stack = NULL;
}
if (refs->worktree_stack) {
reftable_stack_destroy(refs->worktree_stack);
refs->worktree_stack = NULL;
}
strmap_for_each_entry(&refs->worktree_stacks, &iter, entry)
reftable_stack_destroy(entry->value);
strmap_clear(&refs->worktree_stacks, 0);
}
static int reftable_be_create_on_disk(struct ref_store *ref_store,
int flags UNUSED,
struct strbuf *err UNUSED)
{
struct reftable_ref_store *refs =
reftable_be_downcast(ref_store, REF_STORE_WRITE, "init_db");
reftable_be_downcast(ref_store, REF_STORE_WRITE, "create");
struct strbuf sb = STRBUF_INIT;
strbuf_addf(&sb, "%s/reftable", refs->base.gitdir);
@ -1187,7 +1208,7 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
ref.refname = (char *)u->refname;
ref.update_index = ts;
peel_error = peel_object(&u->new_oid, &peeled);
peel_error = peel_object(arg->refs->base.repo, &u->new_oid, &peeled);
if (!peel_error) {
ref.value_type = REFTABLE_REF_VAL2;
memcpy(ref.value.val2.target_value, peeled.hash, GIT_MAX_RAWSZ);
@ -1980,6 +2001,7 @@ static int reftable_be_delete_reflog(struct ref_store *ref_store,
}
struct reflog_expiry_arg {
struct reftable_ref_store *refs;
struct reftable_stack *stack;
struct reftable_log_record *records;
struct object_id update_oid;
@ -2008,7 +2030,7 @@ static int write_reflog_expiry_table(struct reftable_writer *writer, void *cb_da
ref.refname = (char *)arg->refname;
ref.update_index = ts;
if (!peel_object(&arg->update_oid, &peeled)) {
if (!peel_object(arg->refs->base.repo, &arg->update_oid, &peeled)) {
ref.value_type = REFTABLE_REF_VAL2;
memcpy(ref.value.val2.target_value, peeled.hash, GIT_MAX_RAWSZ);
memcpy(ref.value.val2.value, arg->update_oid.hash, GIT_MAX_RAWSZ);
@ -2171,6 +2193,7 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
reftable_ref_record_val1(&ref_record))
oidread(&arg.update_oid, last_hash);
arg.refs = refs;
arg.records = rewritten;
arg.len = logs_nr;
arg.stack = stack,
@ -2205,7 +2228,9 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
struct ref_storage_be refs_be_reftable = {
.name = "reftable",
.init = reftable_be_init,
.init_db = reftable_be_init_db,
.release = reftable_be_release,
.create_on_disk = reftable_be_create_on_disk,
.transaction_prepare = reftable_be_transaction_prepare,
.transaction_finish = reftable_be_transaction_finish,
.transaction_abort = reftable_be_transaction_abort,

View file

@ -305,7 +305,7 @@ static void read_remotes_file(struct remote_state *remote_state,
static void read_branches_file(struct remote_state *remote_state,
struct remote *remote)
{
char *frag;
char *frag, *to_free = NULL;
struct strbuf buf = STRBUF_INIT;
FILE *f = fopen_or_warn(git_path("branches/%s", remote->name), "r");
@ -333,7 +333,7 @@ static void read_branches_file(struct remote_state *remote_state,
if (frag)
*(frag++) = '\0';
else
frag = (char *)git_default_branch_name(0);
frag = to_free = repo_default_branch_name(the_repository, 0);
add_url_alias(remote_state, remote, strbuf_detach(&buf, NULL));
refspec_appendf(&remote->fetch, "refs/heads/%s:refs/heads/%s",
@ -345,6 +345,8 @@ static void read_branches_file(struct remote_state *remote_state,
*/
refspec_appendf(&remote->push, "HEAD:refs/heads/%s", frag);
remote->fetch_tags = 1; /* always auto-follow */
free(to_free);
}
static int handle_config(const char *key, const char *value,
@ -2388,11 +2390,13 @@ struct ref *guess_remote_head(const struct ref *head,
/* If a remote branch exists with the default branch name, let's use it. */
if (!all) {
char *ref = xstrfmt("refs/heads/%s",
git_default_branch_name(0));
char *default_branch = repo_default_branch_name(the_repository, 0);
char *ref = xstrfmt("refs/heads/%s", default_branch);
r = find_ref_by_name(refs, ref);
free(ref);
free(default_branch);
if (r && oideq(&r->old_oid, &head->old_oid))
return copy_ref(r);

View file

@ -8,12 +8,13 @@
#include "repository.h"
#include "commit.h"
static int register_replace_ref(struct repository *r,
const char *refname,
static int register_replace_ref(const char *refname,
const struct object_id *oid,
int flag UNUSED,
void *cb_data UNUSED)
void *cb_data)
{
struct repository *r = cb_data;
/* Get sha1 from refname */
const char *slash = strrchr(refname, '/');
const char *hash = slash ? slash + 1 : refname;
@ -50,7 +51,8 @@ void prepare_replace_object(struct repository *r)
xmalloc(sizeof(*r->objects->replace_map));
oidmap_init(r->objects->replace_map, 0);
for_each_replace_ref(r, register_replace_ref, NULL);
refs_for_each_replace_ref(get_main_ref_store(r),
register_replace_ref, r);
r->objects->replace_map_initialized = 1;
pthread_mutex_unlock(&r->objects->replace_mutex);

View file

@ -14,6 +14,7 @@
#include "sparse-index.h"
#include "trace2.h"
#include "promisor-remote.h"
#include "refs.h"
/* The main repository */
static struct repository the_repo;
@ -269,6 +270,9 @@ static void repo_clear_path_cache(struct repo_path_cache *cache)
void repo_clear(struct repository *repo)
{
struct hashmap_iter iter;
struct strmap_entry *e;
FREE_AND_NULL(repo->gitdir);
FREE_AND_NULL(repo->commondir);
FREE_AND_NULL(repo->graft_file);
@ -309,6 +313,14 @@ void repo_clear(struct repository *repo)
FREE_AND_NULL(repo->remote_state);
}
strmap_for_each_entry(&repo->submodule_ref_stores, &iter, e)
ref_store_release(e->value);
strmap_clear(&repo->submodule_ref_stores, 1);
strmap_for_each_entry(&repo->worktree_ref_stores, &iter, e)
ref_store_release(e->value);
strmap_clear(&repo->worktree_ref_stores, 1);
repo_clear_path_cache(&repo->cached_paths);
}

View file

@ -1,6 +1,8 @@
#ifndef REPOSITORY_H
#define REPOSITORY_H
#include "strmap.h"
struct config_set;
struct fsmonitor_settings;
struct git_hash_algo;
@ -108,6 +110,18 @@ struct repository {
*/
struct ref_store *refs_private;
/*
* A strmap of ref_stores, stored by submodule name, accessible via
* `repo_get_submodule_ref_store()`.
*/
struct strmap submodule_ref_stores;
/*
* A strmap of ref_stores, stored by worktree id, accessible via
* `get_worktree_ref_store()`.
*/
struct strmap worktree_ref_stores;
/*
* Contains path to often used file names.
*/

View file

@ -2099,10 +2099,11 @@ void create_reference_database(unsigned int ref_storage_format,
const char *initial_branch, int quiet)
{
struct strbuf err = STRBUF_INIT;
char *to_free = NULL;
int reinit = is_reinit();
repo_set_ref_storage_format(the_repository, ref_storage_format);
if (refs_init_db(get_main_ref_store(the_repository), 0, &err))
if (ref_store_create_on_disk(get_main_ref_store(the_repository), 0, &err))
die("failed to set up refs db: %s", err.buf);
/*
@ -2113,7 +2114,8 @@ void create_reference_database(unsigned int ref_storage_format,
char *ref;
if (!initial_branch)
initial_branch = git_default_branch_name(quiet);
initial_branch = to_free =
repo_default_branch_name(the_repository, quiet);
ref = xstrfmt("refs/heads/%s", initial_branch);
if (check_refname_format(ref, 0) < 0)
@ -2130,6 +2132,7 @@ void create_reference_database(unsigned int ref_storage_format,
initial_branch);
strbuf_release(&err);
free(to_free);
}
static int create_default_files(const char *template_path,

View file

@ -99,7 +99,8 @@ int is_staging_gitmodules_ok(struct index_state *istate)
static int for_each_remote_ref_submodule(const char *submodule,
each_ref_fn fn, void *cb_data)
{
return refs_for_each_remote_ref(get_submodule_ref_store(submodule),
return refs_for_each_remote_ref(repo_get_submodule_ref_store(the_repository,
submodule),
fn, cb_data);
}

View file

@ -62,7 +62,7 @@ int cmd__reach(int ac, const char **av)
die("failed to resolve %s", buf.buf + 2);
orig = parse_object(r, &oid);
peeled = deref_tag_noverify(orig);
peeled = deref_tag_noverify(the_repository, orig);
if (!peeled)
die("failed to load commit for input %s resulting in oid %s\n",

View file

@ -82,7 +82,7 @@ static const char **get_store(const char **argv, struct ref_store **refs)
add_to_alternates_memory(sb.buf);
strbuf_release(&sb);
*refs = get_submodule_ref_store(gitdir);
*refs = repo_get_submodule_ref_store(the_repository, gitdir);
} else if (skip_prefix(argv[0], "worktree:", &gitdir)) {
struct worktree **p, **worktrees = get_worktrees();

4
tag.c
View file

@ -91,10 +91,10 @@ struct object *deref_tag(struct repository *r, struct object *o, const char *war
return o;
}
struct object *deref_tag_noverify(struct object *o)
struct object *deref_tag_noverify(struct repository *r, struct object *o)
{
while (o && o->type == OBJ_TAG) {
o = parse_object(the_repository, &o->oid);
o = parse_object(r, &o->oid);
if (o && o->type == OBJ_TAG && ((struct tag *)o)->tagged)
o = ((struct tag *)o)->tagged;
else

2
tag.h
View file

@ -16,7 +16,7 @@ int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, u
int parse_tag(struct tag *item);
void release_tag_memory(struct tag *t);
struct object *deref_tag(struct repository *r, struct object *, const char *, int);
struct object *deref_tag_noverify(struct object *);
struct object *deref_tag_noverify(struct repository *r, struct object *);
int gpg_verify_tag(const struct object_id *oid,
const char *name_to_report, unsigned flags);
struct object_id *get_tagged_oid(struct tag *tag);

View file

@ -2318,7 +2318,8 @@ static int verify_clean_subdirectory(const struct cache_entry *ce,
if (S_ISGITLINK(ce->ce_mode)) {
struct object_id oid;
int sub_head = resolve_gitlink_ref(ce->name, "HEAD", &oid);
int sub_head = repo_resolve_gitlink_ref(the_repository, ce->name,
"HEAD", &oid);
/*
* If we are not going to update the submodule, then
* we don't care.

View file

@ -1269,7 +1269,7 @@ static void write_v0_ref(struct upload_pack_data *data,
packet_fwrite_fmt(stdout, "%s %s\n", oid_to_hex(oid), refname_nons);
}
capabilities = NULL;
if (!peel_iterated_oid(oid, &peeled))
if (!peel_iterated_oid(the_repository, oid, &peeled))
packet_fwrite_fmt(stdout, "%s %s^{}\n", oid_to_hex(&peeled), refname_nons);
return;
}

View file

@ -65,6 +65,7 @@ static struct worktree *get_main_worktree(int skip_reading_head)
strbuf_strip_suffix(&worktree_path, "/.git");
CALLOC_ARRAY(worktree, 1);
worktree->repo = the_repository;
worktree->path = strbuf_detach(&worktree_path, NULL);
/*
* NEEDSWORK: If this function is called from a secondary worktree and
@ -98,6 +99,7 @@ struct worktree *get_linked_worktree(const char *id,
strbuf_strip_suffix(&worktree_path, "/.git");
CALLOC_ARRAY(worktree, 1);
worktree->repo = the_repository;
worktree->path = strbuf_detach(&worktree_path, NULL);
worktree->id = xstrdup(id);
if (!skip_reading_head)

View file

@ -6,6 +6,8 @@
struct strbuf;
struct worktree {
/* The repository this worktree belongs to. */
struct repository *repo;
char *path;
char *id;
char *head_ref; /* NULL if HEAD is broken or detached */