diff options
Diffstat (limited to 'replace-object.c')
-rw-r--r-- | replace-object.c | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/replace-object.c b/replace-object.c new file mode 100644 index 0000000..5232155 --- /dev/null +++ b/replace-object.c @@ -0,0 +1,112 @@ +#include "git-compat-util.h" +#include "gettext.h" +#include "hex.h" +#include "oidmap.h" +#include "object-store-ll.h" +#include "replace-object.h" +#include "refs.h" +#include "repository.h" +#include "commit.h" + +static int register_replace_ref(struct repository *r, + const char *refname, + const struct object_id *oid, + int flag UNUSED, + void *cb_data UNUSED) +{ + /* Get sha1 from refname */ + const char *slash = strrchr(refname, '/'); + const char *hash = slash ? slash + 1 : refname; + struct replace_object *repl_obj = xmalloc(sizeof(*repl_obj)); + + if (get_oid_hex(hash, &repl_obj->original.oid)) { + free(repl_obj); + warning(_("bad replace ref name: %s"), refname); + return 0; + } + + /* Copy sha1 from the read ref */ + oidcpy(&repl_obj->replacement, oid); + + /* Register new object */ + if (oidmap_put(r->objects->replace_map, repl_obj)) + die(_("duplicate replace ref: %s"), refname); + + return 0; +} + +void prepare_replace_object(struct repository *r) +{ + if (r->objects->replace_map_initialized) + return; + + pthread_mutex_lock(&r->objects->replace_mutex); + if (r->objects->replace_map_initialized) { + pthread_mutex_unlock(&r->objects->replace_mutex); + return; + } + + r->objects->replace_map = + xmalloc(sizeof(*r->objects->replace_map)); + oidmap_init(r->objects->replace_map, 0); + + for_each_replace_ref(r, register_replace_ref, NULL); + r->objects->replace_map_initialized = 1; + + pthread_mutex_unlock(&r->objects->replace_mutex); +} + +/* We allow "recursive" replacement. Only within reason, though */ +#define MAXREPLACEDEPTH 5 + +/* + * If a replacement for object oid has been set up, return the + * replacement object's name (replaced recursively, if necessary). + * The return value is either oid or a pointer to a + * permanently-allocated value. This function always respects replace + * references, regardless of the value of r->settings.read_replace_refs. + */ +const struct object_id *do_lookup_replace_object(struct repository *r, + const struct object_id *oid) +{ + int depth = MAXREPLACEDEPTH; + const struct object_id *cur = oid; + + prepare_replace_object(r); + + /* Try to recursively replace the object */ + while (depth-- > 0) { + struct replace_object *repl_obj = + oidmap_get(r->objects->replace_map, cur); + if (!repl_obj) + return cur; + cur = &repl_obj->replacement; + } + die(_("replace depth too high for object %s"), oid_to_hex(oid)); +} + +/* + * This indicator determines whether replace references should be + * respected process-wide, regardless of which repository is being + * using at the time. + */ +static int read_replace_refs = 1; + +void disable_replace_refs(void) +{ + read_replace_refs = 0; +} + +int replace_refs_enabled(struct repository *r) +{ + if (!read_replace_refs) + return 0; + + if (r->gitdir) { + prepare_repo_settings(r); + return r->settings.read_replace_refs; + } + + /* repository has no objects or refs. */ + return 0; +} |