mirror of
https://github.com/git/git.git
synced 2026-01-11 13:23:12 +09:00
Merge branch 'en/fsck-snapshot-ref-state' into jch
"git fsck" used inconsistent set of refs to show a confused warning, which has been corrected. * en/fsck-snapshot-ref-state: fsck: snapshot default refs before object walk
This commit is contained in:
commit
9e4e51d991
164
builtin/fsck.c
164
builtin/fsck.c
@ -51,6 +51,7 @@ static int show_progress = -1;
|
||||
static int show_dangling = 1;
|
||||
static int name_objects;
|
||||
static int check_references = 1;
|
||||
static timestamp_t now;
|
||||
#define ERROR_OBJECT 01
|
||||
#define ERROR_REACHABLE 02
|
||||
#define ERROR_PACK 04
|
||||
@ -510,6 +511,9 @@ static int fsck_handle_reflog_ent(const char *refname,
|
||||
timestamp_t timestamp, int tz UNUSED,
|
||||
const char *message UNUSED, void *cb_data UNUSED)
|
||||
{
|
||||
if (now && timestamp > now)
|
||||
return 0;
|
||||
|
||||
if (verbose)
|
||||
fprintf_ln(stderr, _("Checking reflog %s->%s"),
|
||||
oid_to_hex(ooid), oid_to_hex(noid));
|
||||
@ -531,8 +535,22 @@ static int fsck_handle_reflog(const char *logname, void *cb_data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsck_handle_ref(const struct reference *ref, void *cb_data UNUSED)
|
||||
struct ref_snapshot {
|
||||
char *refname;
|
||||
struct object_id oid;
|
||||
/* TODO: Maybe supplement with latest reflog entry info too? */
|
||||
};
|
||||
|
||||
struct snapshot {
|
||||
size_t nr;
|
||||
size_t alloc;
|
||||
struct ref_snapshot *ref;
|
||||
/* TODO: Consider also snapshotting the index of each worktree. */
|
||||
};
|
||||
|
||||
static int snapshot_ref(const struct reference *ref, void *cb_data)
|
||||
{
|
||||
struct snapshot *snap = cb_data;
|
||||
struct object *obj;
|
||||
|
||||
obj = parse_object(the_repository, ref->oid);
|
||||
@ -556,6 +574,20 @@ static int fsck_handle_ref(const struct reference *ref, void *cb_data UNUSED)
|
||||
errors_found |= ERROR_REFS;
|
||||
}
|
||||
default_refs++;
|
||||
|
||||
ALLOC_GROW(snap->ref, snap->nr + 1, snap->alloc);
|
||||
snap->ref[snap->nr].refname = xstrdup(ref->name);
|
||||
oidcpy(&snap->ref[snap->nr].oid, ref->oid);
|
||||
snap->nr++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsck_handle_ref(const struct reference *ref, void *cb_data UNUSED)
|
||||
{
|
||||
struct object *obj;
|
||||
|
||||
obj = parse_object(the_repository, ref->oid);
|
||||
obj->flags |= USED;
|
||||
fsck_put_object_name(&fsck_walk_options,
|
||||
ref->oid, "%s", ref->name);
|
||||
@ -568,14 +600,35 @@ static int fsck_head_link(const char *head_ref_name,
|
||||
const char **head_points_at,
|
||||
struct object_id *head_oid);
|
||||
|
||||
static void get_default_heads(void)
|
||||
static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)
|
||||
{
|
||||
struct worktree **worktrees, **p;
|
||||
const char *head_points_at;
|
||||
struct object_id head_oid;
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
struct object_id oid;
|
||||
if (!repo_get_oid(the_repository, arg, &oid)) {
|
||||
struct reference ref = {
|
||||
.name = arg,
|
||||
.oid = &oid,
|
||||
};
|
||||
|
||||
snapshot_ref(&ref, snap);
|
||||
continue;
|
||||
}
|
||||
error(_("invalid parameter: expected sha1, got '%s'"), arg);
|
||||
errors_found |= ERROR_OBJECT;
|
||||
}
|
||||
|
||||
if (argc) {
|
||||
include_reflogs = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
refs_for_each_rawref(get_main_ref_store(the_repository),
|
||||
fsck_handle_ref, NULL);
|
||||
snapshot_ref, snap);
|
||||
|
||||
worktrees = get_worktrees();
|
||||
for (p = worktrees; *p; p++) {
|
||||
@ -590,16 +643,53 @@ static void get_default_heads(void)
|
||||
.oid = &head_oid,
|
||||
};
|
||||
|
||||
fsck_handle_ref(&ref, NULL);
|
||||
snapshot_ref(&ref, snap);
|
||||
}
|
||||
strbuf_release(&refname);
|
||||
|
||||
if (include_reflogs)
|
||||
refs_for_each_reflog(get_worktree_ref_store(wt),
|
||||
fsck_handle_reflog, wt);
|
||||
/*
|
||||
* TODO: Could use refs_for_each_reflog(...) to find
|
||||
* latest entry instead of using a global 'now' for that
|
||||
* purpose.
|
||||
*/
|
||||
}
|
||||
free_worktrees(worktrees);
|
||||
|
||||
/* Ignore reflogs newer than now */
|
||||
now = time(NULL);
|
||||
}
|
||||
|
||||
|
||||
static void free_snapshot_refs(struct snapshot *snap)
|
||||
{
|
||||
for (size_t i = 0; i < snap->nr; i++)
|
||||
free(snap->ref[i].refname);
|
||||
free(snap->ref);
|
||||
}
|
||||
|
||||
static void process_refs(struct snapshot *snap)
|
||||
{
|
||||
struct worktree **worktrees, **p;
|
||||
|
||||
for (size_t i = 0; i < snap->nr; i++) {
|
||||
struct reference ref = {
|
||||
.name = snap->ref[i].refname,
|
||||
.oid = &snap->ref[i].oid,
|
||||
};
|
||||
fsck_handle_ref(&ref, NULL);
|
||||
}
|
||||
|
||||
if (include_reflogs) {
|
||||
worktrees = get_worktrees();
|
||||
for (p = worktrees; *p; p++) {
|
||||
struct worktree *wt = *p;
|
||||
|
||||
refs_for_each_reflog(get_worktree_ref_store(wt),
|
||||
fsck_handle_reflog, wt);
|
||||
}
|
||||
free_worktrees(worktrees);
|
||||
}
|
||||
|
||||
/*
|
||||
* Not having any default heads isn't really fatal, but
|
||||
* it does mean that "--unreachable" no longer makes any
|
||||
@ -963,8 +1053,12 @@ int cmd_fsck(int argc,
|
||||
const char *prefix,
|
||||
struct repository *repo UNUSED)
|
||||
{
|
||||
int i;
|
||||
struct odb_source *source;
|
||||
struct snapshot snap = {
|
||||
.nr = 0,
|
||||
.alloc = 0,
|
||||
.ref = NULL
|
||||
};
|
||||
|
||||
/* fsck knows how to handle missing promisor objects */
|
||||
fetch_if_missing = 0;
|
||||
@ -1000,6 +1094,17 @@ int cmd_fsck(int argc,
|
||||
if (check_references)
|
||||
fsck_refs(the_repository);
|
||||
|
||||
/*
|
||||
* Take a snapshot of the refs before walking objects to avoid looking
|
||||
* at a set of refs that may be changed by the user while we are walking
|
||||
* objects. We can still walk over new objects that are added during the
|
||||
* execution of fsck but won't miss any objects that were reachable.
|
||||
*/
|
||||
snapshot_refs(&snap, argc, argv);
|
||||
|
||||
/* Ensure we get a "fresh" view of the odb */
|
||||
odb_reprepare(the_repository->objects);
|
||||
|
||||
if (connectivity_only) {
|
||||
for_each_loose_object(the_repository->objects,
|
||||
mark_loose_for_connectivity, NULL, 0);
|
||||
@ -1041,42 +1146,18 @@ int cmd_fsck(int argc,
|
||||
errors_found |= ERROR_OBJECT;
|
||||
}
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
struct object_id oid;
|
||||
if (!repo_get_oid(the_repository, arg, &oid)) {
|
||||
struct object *obj = lookup_object(the_repository,
|
||||
&oid);
|
||||
/* Process the snapshotted refs and the reflogs. */
|
||||
process_refs(&snap);
|
||||
|
||||
if (!obj || !(obj->flags & HAS_OBJ)) {
|
||||
if (is_promisor_object(the_repository, &oid))
|
||||
continue;
|
||||
error(_("%s: object missing"), oid_to_hex(&oid));
|
||||
errors_found |= ERROR_OBJECT;
|
||||
continue;
|
||||
}
|
||||
|
||||
obj->flags |= USED;
|
||||
fsck_put_object_name(&fsck_walk_options, &oid,
|
||||
"%s", arg);
|
||||
mark_object_reachable(obj);
|
||||
continue;
|
||||
}
|
||||
error(_("invalid parameter: expected sha1, got '%s'"), arg);
|
||||
errors_found |= ERROR_OBJECT;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we've not been given any explicit head information, do the
|
||||
* default ones from .git/refs. We also consider the index file
|
||||
* in this case (ie this implies --cache).
|
||||
*/
|
||||
if (!argc) {
|
||||
get_default_heads();
|
||||
/* If not given any explicit objects, process index files too. */
|
||||
if (!argc)
|
||||
keep_cache_objects = 1;
|
||||
}
|
||||
|
||||
if (keep_cache_objects) {
|
||||
/*
|
||||
* TODO: Consider first walking these indexes in snapshot_refs,
|
||||
* to snapshot where the index entries used to point, and then
|
||||
* check those snapshotted locations here.
|
||||
*/
|
||||
struct worktree **worktrees, **p;
|
||||
|
||||
verify_index_checksum = 1;
|
||||
@ -1149,5 +1230,6 @@ int cmd_fsck(int argc,
|
||||
}
|
||||
}
|
||||
|
||||
free_snapshot_refs(&snap);
|
||||
return errors_found;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user