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:
@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user