fsck-objects: refactor checking for connectivity
This separates the connectivity check into separate codepaths, one for reachable objects and the other for unreachable ones, while adding a lot of comments to explain what is going on. When checking an unreachable object, unlike a reachable one, we do not have to complain if it does not exist (we used to complain about a missing blob even when the only thing that references it is a tree that is dangling). Also we do not have to check and complain about objects that are referenced by an unreachable object. This makes the messages from fsck-objects a lot less noisy and more useful. Signed-off-by: Linus Torvalds <torvalds@osdl.org> Signed-off-by: Junio C Hamano <junkio@cox.net>maint
parent
e3ff4b2447
commit
18af29f247
133
fsck-objects.c
133
fsck-objects.c
|
@ -54,6 +54,99 @@ static int objwarning(struct object *obj, const char *err, ...)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check a single reachable object
|
||||||
|
*/
|
||||||
|
static void check_reachable_object(struct object *obj)
|
||||||
|
{
|
||||||
|
const struct object_refs *refs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We obviously want the object to be parsed,
|
||||||
|
* except if it was in a pack-file and we didn't
|
||||||
|
* do a full fsck
|
||||||
|
*/
|
||||||
|
if (!obj->parsed) {
|
||||||
|
if (has_sha1_file(obj->sha1))
|
||||||
|
return; /* it is in pack - forget about it */
|
||||||
|
printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that everything that we try to reference is also good.
|
||||||
|
*/
|
||||||
|
refs = lookup_object_refs(obj);
|
||||||
|
if (refs) {
|
||||||
|
unsigned j;
|
||||||
|
for (j = 0; j < refs->count; j++) {
|
||||||
|
struct object *ref = refs->ref[j];
|
||||||
|
if (ref->parsed ||
|
||||||
|
(has_sha1_file(ref->sha1)))
|
||||||
|
continue;
|
||||||
|
printf("broken link from %7s %s\n",
|
||||||
|
typename(obj->type), sha1_to_hex(obj->sha1));
|
||||||
|
printf(" to %7s %s\n",
|
||||||
|
typename(ref->type), sha1_to_hex(ref->sha1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check a single unreachable object
|
||||||
|
*/
|
||||||
|
static void check_unreachable_object(struct object *obj)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Missing unreachable object? Ignore it. It's not like
|
||||||
|
* we miss it (since it can't be reached), nor do we want
|
||||||
|
* to complain about it being unreachable (since it does
|
||||||
|
* not exist).
|
||||||
|
*/
|
||||||
|
if (!obj->parsed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unreachable object that exists? Show it if asked to,
|
||||||
|
* since this is something that is prunable.
|
||||||
|
*/
|
||||||
|
if (show_unreachable) {
|
||||||
|
printf("unreachable %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "!used" means that nothing at all points to it, including
|
||||||
|
* other unreacahble objects. In other words, it's the "tip"
|
||||||
|
* of some set of unreachable objects, usually a commit that
|
||||||
|
* got dropped.
|
||||||
|
*
|
||||||
|
* Such starting points are more interesting than some random
|
||||||
|
* set of unreachable objects, so we show them even if the user
|
||||||
|
* hasn't asked for _all_ unreachable objects. If you have
|
||||||
|
* deleted a branch by mistake, this is a prime candidate to
|
||||||
|
* start looking at, for example.
|
||||||
|
*/
|
||||||
|
if (!obj->used) {
|
||||||
|
printf("dangling %s %s\n", typename(obj->type),
|
||||||
|
sha1_to_hex(obj->sha1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Otherwise? It's there, it's unreachable, and some other unreachable
|
||||||
|
* object points to it. Ignore it - it's not interesting, and we showed
|
||||||
|
* all the interesting cases above.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_object(struct object *obj)
|
||||||
|
{
|
||||||
|
if (obj->flags & REACHABLE)
|
||||||
|
check_reachable_object(obj);
|
||||||
|
else
|
||||||
|
check_unreachable_object(obj);
|
||||||
|
}
|
||||||
|
|
||||||
static void check_connectivity(void)
|
static void check_connectivity(void)
|
||||||
{
|
{
|
||||||
|
@ -62,46 +155,10 @@ static void check_connectivity(void)
|
||||||
/* Look up all the requirements, warn about missing objects.. */
|
/* Look up all the requirements, warn about missing objects.. */
|
||||||
max = get_max_object_index();
|
max = get_max_object_index();
|
||||||
for (i = 0; i < max; i++) {
|
for (i = 0; i < max; i++) {
|
||||||
const struct object_refs *refs;
|
|
||||||
struct object *obj = get_indexed_object(i);
|
struct object *obj = get_indexed_object(i);
|
||||||
|
|
||||||
if (!obj)
|
if (obj)
|
||||||
continue;
|
check_object(obj);
|
||||||
|
|
||||||
if (!obj->parsed) {
|
|
||||||
if (has_sha1_file(obj->sha1))
|
|
||||||
; /* it is in pack */
|
|
||||||
else
|
|
||||||
printf("missing %s %s\n",
|
|
||||||
typename(obj->type), sha1_to_hex(obj->sha1));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
refs = lookup_object_refs(obj);
|
|
||||||
if (refs) {
|
|
||||||
unsigned j;
|
|
||||||
for (j = 0; j < refs->count; j++) {
|
|
||||||
struct object *ref = refs->ref[j];
|
|
||||||
if (ref->parsed ||
|
|
||||||
(has_sha1_file(ref->sha1)))
|
|
||||||
continue;
|
|
||||||
printf("broken link from %7s %s\n",
|
|
||||||
typename(obj->type), sha1_to_hex(obj->sha1));
|
|
||||||
printf(" to %7s %s\n",
|
|
||||||
typename(ref->type), sha1_to_hex(ref->sha1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (show_unreachable && !(obj->flags & REACHABLE)) {
|
|
||||||
printf("unreachable %s %s\n",
|
|
||||||
typename(obj->type), sha1_to_hex(obj->sha1));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!obj->used) {
|
|
||||||
printf("dangling %s %s\n", typename(obj->type),
|
|
||||||
sha1_to_hex(obj->sha1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue