git-commit-vandalism/replace_object.c
Stefan Beller c3c36d7de2 replace-object: check_replace_refs is safe in multi repo environment
In e1111cef23 (inline lookup_replace_object() calls, 2011-05-15) a shortcut
for checking the object replacement was added by setting check_replace_refs
to 0 once the replacements were evaluated to not exist. This works fine in
with the assumption of only one repository in existence.

The assumption won't hold true any more when we work on multiple instances
of a repository structs (e.g. one struct per submodule), as the first
repository to be inspected may have no replacements and would set the
global variable. Other repositories would then completely omit their
evaluation of replacements.

This reverts back the meaning of the flag `check_replace_refs` of
"Do we need to check with the lookup table?" to "Do we need to read
the replacement definition?", adding the bypassing logic to
lookup_replace_object after the replacement definition was read.
As with the original patch, delay the renaming of the global variable

Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-12 11:38:56 +09:00

73 lines
2.0 KiB
C

#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(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(the_repository->objects->replace_map, repl_obj))
die("duplicate replace ref: %s", refname);
return 0;
}
static void prepare_replace_object(void)
{
if (the_repository->objects->replace_map)
return;
the_repository->objects->replace_map =
xmalloc(sizeof(*the_repository->objects->replace_map));
oidmap_init(the_repository->objects->replace_map, 0);
for_each_replace_ref(register_replace_ref, NULL);
}
/* 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 check_replace_refs.
*/
const struct object_id *do_lookup_replace_object(const struct object_id *oid)
{
int depth = MAXREPLACEDEPTH;
const struct object_id *cur = oid;
prepare_replace_object();
/* Try to recursively replace the object */
while (depth-- > 0) {
struct replace_object *repl_obj =
oidmap_get(the_repository->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));
}