-#include <sys/types.h>
-#include <dirent.h>
-
#include "cache.h"
#include "commit.h"
#include "tree.h"
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)
{
/* Look up all the requirements, warn about missing objects.. */
max = get_max_object_index();
for (i = 0; i < max; i++) {
- const struct object_refs *refs;
struct object *obj = get_indexed_object(i);
- if (!obj)
- continue;
-
- 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));
- }
+ if (obj)
+ check_object(obj);
}
}
{
struct object *obj = parse_object(sha1);
if (!obj)
- return error("%s: object not found", sha1_to_hex(sha1));
+ return error("%s: object corrupt or missing", sha1_to_hex(sha1));
if (obj->flags & SEEN)
return 0;
obj->flags |= SEEN;
static int default_refs;
-static int fsck_handle_ref(const char *refname, const unsigned char *sha1)
+static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
+ const char *email, unsigned long timestamp, int tz,
+ const char *message, void *cb_data)
+{
+ struct object *obj;
+
+ if (!is_null_sha1(osha1)) {
+ obj = lookup_object(osha1);
+ if (obj) {
+ obj->used = 1;
+ mark_reachable(obj, REACHABLE);
+ }
+ }
+ obj = lookup_object(nsha1);
+ if (obj) {
+ obj->used = 1;
+ mark_reachable(obj, REACHABLE);
+ }
+ return 0;
+}
+
+static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
struct object *obj;
default_refs++;
obj->used = 1;
mark_reachable(obj, REACHABLE);
+
+ for_each_reflog_ent(refname, fsck_handle_reflog_ent, NULL);
+
return 0;
}
static void get_default_heads(void)
{
- for_each_ref(fsck_handle_ref);
+ for_each_ref(fsck_handle_ref, NULL);
/*
* Not having any default heads isn't really fatal, but
static int fsck_head_link(void)
{
unsigned char sha1[20];
- const char *git_HEAD = strdup(git_path("HEAD"));
- const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1, 1);
- int pfxlen = strlen(git_HEAD) - 4; /* strip .../.git/ part */
+ int flag;
+ const char *head_points_at = resolve_ref("HEAD", sha1, 1, &flag);
- if (!git_refs_heads_master)
+ if (!head_points_at || !(flag & REF_ISSYMREF))
return error("HEAD is not a symbolic ref");
- if (strncmp(git_refs_heads_master + pfxlen, "refs/heads/", 11))
+ if (strncmp(head_points_at, "refs/heads/", 11))
return error("HEAD points to something strange (%s)",
- git_refs_heads_master + pfxlen);
+ head_points_at);
if (is_null_sha1(sha1))
return error("HEAD: not a valid git pointer");
return 0;