diff options
Diffstat (limited to 'refs.c')
-rw-r--r-- | refs.c | 221 |
1 files changed, 176 insertions, 45 deletions
@@ -5,11 +5,13 @@ #include "cache.h" #include "hashmap.h" #include "lockfile.h" +#include "iterator.h" #include "refs.h" #include "refs/refs-internal.h" #include "object.h" #include "tag.h" #include "submodule.h" +#include "worktree.h" /* * List of all available backends @@ -881,9 +883,9 @@ struct ref_update *ref_transaction_add_update( update->flags = flags; if (flags & REF_HAVE_NEW) - hashcpy(update->new_sha1, new_sha1); + hashcpy(update->new_oid.hash, new_sha1); if (flags & REF_HAVE_OLD) - hashcpy(update->old_sha1, old_sha1); + hashcpy(update->old_oid.hash, old_sha1); update->msg = xstrdup_or_null(msg); return update; } @@ -1238,6 +1240,18 @@ int head_ref(each_ref_fn fn, void *cb_data) return head_ref_submodule(NULL, fn, cb_data); } +struct ref_iterator *refs_ref_iterator_begin( + struct ref_store *refs, + const char *prefix, int trim, int flags) +{ + struct ref_iterator *iter; + + iter = refs->be->iterator_begin(refs, prefix, flags); + iter = prefix_ref_iterator_begin(iter, prefix, trim); + + 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 @@ -1255,8 +1269,7 @@ static int do_for_each_ref(struct ref_store *refs, const char *prefix, if (!refs) return 0; - iter = refs->be->iterator_begin(refs, prefix, flags); - iter = prefix_ref_iterator_begin(iter, prefix, trim); + iter = refs_ref_iterator_begin(refs, prefix, trim, flags); return do_for_each_ref_iterator(iter, fn, cb_data); } @@ -1334,6 +1347,13 @@ int for_each_rawref(each_ref_fn fn, void *cb_data) return refs_for_each_rawref(get_main_ref_store(), fn, cb_data); } +int refs_read_raw_ref(struct ref_store *ref_store, + const char *refname, unsigned char *sha1, + struct strbuf *referent, unsigned int *type) +{ + return ref_store->be->read_raw_ref(ref_store, refname, sha1, referent, type); +} + /* This function needs to return a meaningful errno on failure */ const char *refs_resolve_ref_unsafe(struct ref_store *refs, const char *refname, @@ -1370,8 +1390,8 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, for (symref_count = 0; symref_count < SYMREF_MAXDEPTH; symref_count++) { unsigned int read_flags = 0; - if (refs->be->read_raw_ref(refs, refname, - sha1, &sb_refname, &read_flags)) { + if (refs_read_raw_ref(refs, refname, + sha1, &sb_refname, &read_flags)) { *flags |= read_flags; if (errno != ENOENT || (resolve_flags & RESOLVE_REF_READING)) return NULL; @@ -1458,32 +1478,32 @@ int resolve_gitlink_ref(const char *submodule, const char *refname, return 0; } -struct submodule_hash_entry +struct ref_store_hash_entry { struct hashmap_entry ent; /* must be the first member! */ struct ref_store *refs; - /* NUL-terminated name of submodule: */ - char submodule[FLEX_ARRAY]; + /* NUL-terminated identifier of the ref store: */ + char name[FLEX_ARRAY]; }; -static int submodule_hash_cmp(const void *entry, const void *entry_or_key, +static int ref_store_hash_cmp(const void *entry, const void *entry_or_key, const void *keydata) { - const struct submodule_hash_entry *e1 = entry, *e2 = entry_or_key; - const char *submodule = keydata ? keydata : e2->submodule; + const struct ref_store_hash_entry *e1 = entry, *e2 = entry_or_key; + const char *name = keydata ? keydata : e2->name; - return strcmp(e1->submodule, submodule); + return strcmp(e1->name, name); } -static struct submodule_hash_entry *alloc_submodule_hash_entry( - const char *submodule, struct ref_store *refs) +static struct ref_store_hash_entry *alloc_ref_store_hash_entry( + const char *name, struct ref_store *refs) { - struct submodule_hash_entry *entry; + struct ref_store_hash_entry *entry; - FLEX_ALLOC_STR(entry, submodule, submodule); - hashmap_entry_init(entry, strhash(submodule)); + FLEX_ALLOC_STR(entry, name, name); + hashmap_entry_init(entry, strhash(name)); entry->refs = refs; return entry; } @@ -1494,20 +1514,23 @@ static struct ref_store *main_ref_store; /* 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; + /* - * Return the ref_store instance for the specified submodule. If that - * ref_store hasn't been initialized yet, return NULL. + * Look up a ref store by name. If that ref_store hasn't been + * registered yet, return NULL. */ -static struct ref_store *lookup_submodule_ref_store(const char *submodule) +static struct ref_store *lookup_ref_store_map(struct hashmap *map, + const char *name) { - struct submodule_hash_entry *entry; + struct ref_store_hash_entry *entry; - if (!submodule_ref_stores.tablesize) + if (!map->tablesize) /* It's initialized on demand in register_ref_store(). */ return NULL; - entry = hashmap_get_from_hash(&submodule_ref_stores, - strhash(submodule), submodule); + entry = hashmap_get_from_hash(map, strhash(name), name); return entry ? entry->refs : NULL; } @@ -1534,29 +1557,24 @@ struct ref_store *get_main_ref_store(void) if (main_ref_store) return main_ref_store; - main_ref_store = ref_store_init(get_git_dir(), - (REF_STORE_READ | - REF_STORE_WRITE | - REF_STORE_ODB | - REF_STORE_MAIN)); + main_ref_store = ref_store_init(get_git_dir(), REF_STORE_ALL_CAPS); return main_ref_store; } /* - * Register the specified ref_store to be the one that should be used - * for submodule. It is a fatal error to call this function twice for - * the same submodule. + * Associate a ref store with a name. It is a fatal error to call this + * function twice for the same name. */ -static void register_submodule_ref_store(struct ref_store *refs, - const char *submodule) +static void register_ref_store_map(struct hashmap *map, + const char *type, + struct ref_store *refs, + const char *name) { - if (!submodule_ref_stores.tablesize) - hashmap_init(&submodule_ref_stores, submodule_hash_cmp, 0); + if (!map->tablesize) + hashmap_init(map, ref_store_hash_cmp, 0); - if (hashmap_put(&submodule_ref_stores, - alloc_submodule_hash_entry(submodule, refs))) - die("BUG: ref_store for submodule '%s' initialized twice", - submodule); + if (hashmap_put(map, alloc_ref_store_hash_entry(name, refs))) + die("BUG: %s ref_store '%s' initialized twice", type, name); } struct ref_store *get_submodule_ref_store(const char *submodule) @@ -1573,7 +1591,7 @@ struct ref_store *get_submodule_ref_store(const char *submodule) return get_main_ref_store(); } - refs = lookup_submodule_ref_store(submodule); + refs = lookup_ref_store_map(&submodule_ref_stores, submodule); if (refs) return refs; @@ -1592,12 +1610,39 @@ struct ref_store *get_submodule_ref_store(const char *submodule) /* assume that add_submodule_odb() has been called */ refs = ref_store_init(submodule_sb.buf, REF_STORE_READ | REF_STORE_ODB); - register_submodule_ref_store(refs, submodule); + register_ref_store_map(&submodule_ref_stores, "submodule", + refs, submodule); strbuf_release(&submodule_sb); return refs; } +struct ref_store *get_worktree_ref_store(const struct worktree *wt) +{ + struct ref_store *refs; + const char *id; + + if (wt->is_current) + return get_main_ref_store(); + + id = wt->id ? wt->id : "/"; + refs = lookup_ref_store_map(&worktree_ref_stores, id); + if (refs) + return refs; + + if (wt->id) + refs = ref_store_init(git_common_path("worktrees/%s", wt->id), + REF_STORE_ALL_CAPS); + else + refs = ref_store_init(get_git_common_dir(), + REF_STORE_ALL_CAPS); + + if (refs) + register_ref_store_map(&worktree_ref_stores, "worktree", + refs, id); + return refs; +} + void base_ref_store_init(struct ref_store *refs, const struct ref_storage_be *be) { @@ -1643,16 +1688,102 @@ int ref_transaction_commit(struct ref_transaction *transaction, { struct ref_store *refs = transaction->ref_store; + if (getenv(GIT_QUARANTINE_ENVIRONMENT)) { + strbuf_addstr(err, + _("ref updates forbidden inside quarantine environment")); + return -1; + } + return refs->be->transaction_commit(refs, transaction, err); } int refs_verify_refname_available(struct ref_store *refs, const char *refname, - const struct string_list *extra, + const struct string_list *extras, const struct string_list *skip, struct strbuf *err) { - return refs->be->verify_refname_available(refs, refname, extra, skip, err); + const char *slash; + const char *extra_refname; + struct strbuf dirname = STRBUF_INIT; + struct strbuf referent = STRBUF_INIT; + struct object_id oid; + unsigned int type; + struct ref_iterator *iter; + int ok; + int ret = -1; + + /* + * For the sake of comments in this function, suppose that + * refname is "refs/foo/bar". + */ + + assert(err); + + strbuf_grow(&dirname, strlen(refname) + 1); + for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) { + /* Expand dirname to the new prefix, not including the trailing slash: */ + strbuf_add(&dirname, refname + dirname.len, slash - refname - dirname.len); + + /* + * We are still at a leading dir of the refname (e.g., + * "refs/foo"; if there is a reference with that name, + * it is a conflict, *unless* it is in skip. + */ + if (skip && string_list_has_string(skip, dirname.buf)) + continue; + + if (!refs_read_raw_ref(refs, dirname.buf, oid.hash, &referent, &type)) { + strbuf_addf(err, "'%s' exists; cannot create '%s'", + dirname.buf, refname); + goto cleanup; + } + + if (extras && string_list_has_string(extras, dirname.buf)) { + strbuf_addf(err, "cannot process '%s' and '%s' at the same time", + refname, dirname.buf); + goto cleanup; + } + } + + /* + * We are at the leaf of our refname (e.g., "refs/foo/bar"). + * There is no point in searching for a reference with that + * name, because a refname isn't considered to conflict with + * itself. But we still need to check for references whose + * names are in the "refs/foo/bar/" namespace, because they + * *do* conflict. + */ + strbuf_addstr(&dirname, refname + dirname.len); + strbuf_addch(&dirname, '/'); + + iter = refs_ref_iterator_begin(refs, dirname.buf, 0, + DO_FOR_EACH_INCLUDE_BROKEN); + while ((ok = ref_iterator_advance(iter)) == ITER_OK) { + if (skip && + string_list_has_string(skip, iter->refname)) + continue; + + strbuf_addf(err, "'%s' exists; cannot create '%s'", + iter->refname, refname); + ref_iterator_abort(iter); + goto cleanup; + } + + if (ok != ITER_DONE) + die("BUG: error while iterating over references"); + + extra_refname = find_descendant_ref(dirname.buf, extras, skip); + if (extra_refname) + strbuf_addf(err, "cannot process '%s' and '%s' at the same time", + refname, extra_refname); + else + ret = 0; + +cleanup: + strbuf_release(&referent); + strbuf_release(&dirname); + return ret; } int refs_for_each_reflog(struct ref_store *refs, each_ref_fn fn, void *cb_data) |