about summary refs log tree commit diff
path: root/third_party/git/replace-object.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/git/replace-object.c')
-rw-r--r--third_party/git/replace-object.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/third_party/git/replace-object.c b/third_party/git/replace-object.c
new file mode 100644
index 000000000000..7bd9aba6ee6c
--- /dev/null
+++ b/third_party/git/replace-object.c
@@ -0,0 +1,83 @@
+#include "cache.h"
+#include "oidmap.h"
+#include "object-store.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, void *cb_data)
+{
+	/* 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 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));
+}