Merge branch 'js/fsck-opt'

Allow ignoring fsck errors on specific set of known-to-be-bad
objects, and also tweaking warning level of various kinds of non
critical breakages reported.

* js/fsck-opt:
  fsck: support ignoring objects in `git fsck` via fsck.skiplist
  fsck: git receive-pack: support excluding objects from fsck'ing
  fsck: introduce `git fsck --connectivity-only`
  fsck: support demoting errors to warnings
  fsck: document the new receive.fsck.<msg-id> options
  fsck: allow upgrading fsck warnings to errors
  fsck: optionally ignore specific fsck issues completely
  fsck: disallow demoting grave fsck errors to warnings
  fsck: add a simple test for receive.fsck.<msg-id>
  fsck: make fsck_tag() warn-friendly
  fsck: handle multiple authors in commits specially
  fsck: make fsck_commit() warn-friendly
  fsck: make fsck_ident() warn-friendly
  fsck: report the ID of the error/warning
  fsck (receive-pack): allow demoting errors to warnings
  fsck: offer a function to demote fsck errors to warnings
  fsck: provide a function to parse fsck message IDs
  fsck: introduce identifiers for fsck messages
  fsck: introduce fsck options
This commit is contained in:
Junio C Hamano
2015-08-03 11:01:18 -07:00
11 changed files with 693 additions and 165 deletions

View File

@ -23,8 +23,11 @@ static int show_tags;
static int show_unreachable;
static int include_reflogs = 1;
static int check_full = 1;
static int connectivity_only;
static int check_strict;
static int keep_cache_objects;
static struct fsck_options fsck_walk_options = FSCK_OPTIONS_DEFAULT;
static struct fsck_options fsck_obj_options = FSCK_OPTIONS_DEFAULT;
static struct object_id head_oid;
static const char *head_points_at;
static int errors_found;
@ -44,39 +47,52 @@ static int show_dangling = 1;
#define DIRENT_SORT_HINT(de) ((de)->d_ino)
#endif
static void objreport(struct object *obj, const char *severity,
const char *err, va_list params)
static int fsck_config(const char *var, const char *value, void *cb)
{
fprintf(stderr, "%s in %s %s: ",
severity, typename(obj->type), sha1_to_hex(obj->sha1));
vfprintf(stderr, err, params);
fputs("\n", stderr);
if (strcmp(var, "fsck.skiplist") == 0) {
const char *path;
struct strbuf sb = STRBUF_INIT;
if (git_config_pathname(&path, var, value))
return 1;
strbuf_addf(&sb, "skiplist=%s", path);
free((char *)path);
fsck_set_msg_types(&fsck_obj_options, sb.buf);
strbuf_release(&sb);
return 0;
}
if (skip_prefix(var, "fsck.", &var)) {
fsck_set_msg_type(&fsck_obj_options, var, value);
return 0;
}
return git_default_config(var, value, cb);
}
__attribute__((format (printf, 2, 3)))
static int objerror(struct object *obj, const char *err, ...)
static void objreport(struct object *obj, const char *msg_type,
const char *err)
{
fprintf(stderr, "%s in %s %s: %s\n",
msg_type, typename(obj->type), sha1_to_hex(obj->sha1), err);
}
static int objerror(struct object *obj, const char *err)
{
va_list params;
va_start(params, err);
errors_found |= ERROR_OBJECT;
objreport(obj, "error", err, params);
va_end(params);
objreport(obj, "error", err);
return -1;
}
__attribute__((format (printf, 3, 4)))
static int fsck_error_func(struct object *obj, int type, const char *err, ...)
static int fsck_error_func(struct object *obj, int type, const char *message)
{
va_list params;
va_start(params, err);
objreport(obj, (type == FSCK_WARN) ? "warning" : "error", err, params);
va_end(params);
objreport(obj, (type == FSCK_WARN) ? "warning" : "error", message);
return (type == FSCK_WARN) ? 0 : 1;
}
static struct object_array pending;
static int mark_object(struct object *obj, int type, void *data)
static int mark_object(struct object *obj, int type, void *data, struct fsck_options *options)
{
struct object *parent = data;
@ -119,7 +135,7 @@ static int mark_object(struct object *obj, int type, void *data)
static void mark_object_reachable(struct object *obj)
{
mark_object(obj, OBJ_ANY, NULL);
mark_object(obj, OBJ_ANY, NULL, NULL);
}
static int traverse_one_object(struct object *obj)
@ -132,7 +148,7 @@ static int traverse_one_object(struct object *obj)
if (parse_tree(tree) < 0)
return 1; /* error already displayed */
}
result = fsck_walk(obj, mark_object, obj);
result = fsck_walk(obj, obj, &fsck_walk_options);
if (tree)
free_tree_buffer(tree);
return result;
@ -158,7 +174,7 @@ static int traverse_reachable(void)
return !!result;
}
static int mark_used(struct object *obj, int type, void *data)
static int mark_used(struct object *obj, int type, void *data, struct fsck_options *options)
{
if (!obj)
return 1;
@ -179,6 +195,8 @@ static void check_reachable_object(struct object *obj)
if (!(obj->flags & HAS_OBJ)) {
if (has_sha1_pack(obj->sha1))
return; /* it is in pack - forget about it */
if (connectivity_only && has_sha1_file(obj->sha1))
return;
printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
errors_found |= ERROR_REACHABLE;
return;
@ -296,9 +314,9 @@ static int fsck_obj(struct object *obj)
fprintf(stderr, "Checking %s %s\n",
typename(obj->type), sha1_to_hex(obj->sha1));
if (fsck_walk(obj, mark_used, NULL))
if (fsck_walk(obj, NULL, &fsck_obj_options))
objerror(obj, "broken links");
if (fsck_object(obj, NULL, 0, check_strict, fsck_error_func))
if (fsck_object(obj, NULL, 0, &fsck_obj_options))
return -1;
if (obj->type == OBJ_TREE) {
@ -621,6 +639,7 @@ static struct option fsck_opts[] = {
OPT_BOOL(0, "cache", &keep_cache_objects, N_("make index objects head nodes")),
OPT_BOOL(0, "reflogs", &include_reflogs, N_("make reflogs head nodes (default)")),
OPT_BOOL(0, "full", &check_full, N_("also consider packs and alternate objects")),
OPT_BOOL(0, "connectivity-only", &connectivity_only, N_("check only connectivity")),
OPT_BOOL(0, "strict", &check_strict, N_("enable more strict checking")),
OPT_BOOL(0, "lost-found", &write_lost_and_found,
N_("write dangling objects in .git/lost-found")),
@ -638,6 +657,12 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);
fsck_walk_options.walk = mark_object;
fsck_obj_options.walk = mark_used;
fsck_obj_options.error_func = fsck_error_func;
if (check_strict)
fsck_obj_options.strict = 1;
if (show_progress == -1)
show_progress = isatty(2);
if (verbose)
@ -648,8 +673,11 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
include_reflogs = 0;
}
git_config(fsck_config, NULL);
fsck_head_link();
fsck_object_dir(get_object_directory());
if (!connectivity_only)
fsck_object_dir(get_object_directory());
prepare_alt_odb();
for (alt = alt_odb_list; alt; alt = alt->next) {