Merge branch 'jk/fsck-indices-in-worktrees'
"git fsck" learned to check the index files in other worktrees, just like "git gc" honors them as anchoring points. * jk/fsck-indices-in-worktrees: fsck: check even zero-entry index files fsck: mention file path for index errors fsck: check index files in all worktrees fsck: factor out index fsck
This commit is contained in:
commit
2d019f46b0
@ -1,4 +1,3 @@
|
|||||||
#define USE_THE_INDEX_VARIABLE
|
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "repository.h"
|
#include "repository.h"
|
||||||
@ -732,19 +731,19 @@ static int fsck_head_link(const char *head_ref_name,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fsck_cache_tree(struct cache_tree *it)
|
static int fsck_cache_tree(struct cache_tree *it, const char *index_path)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
fprintf_ln(stderr, _("Checking cache tree"));
|
fprintf_ln(stderr, _("Checking cache tree of %s"), index_path);
|
||||||
|
|
||||||
if (0 <= it->entry_count) {
|
if (0 <= it->entry_count) {
|
||||||
struct object *obj = parse_object(the_repository, &it->oid);
|
struct object *obj = parse_object(the_repository, &it->oid);
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
error(_("%s: invalid sha1 pointer in cache-tree"),
|
error(_("%s: invalid sha1 pointer in cache-tree of %s"),
|
||||||
oid_to_hex(&it->oid));
|
oid_to_hex(&it->oid), index_path);
|
||||||
errors_found |= ERROR_REFS;
|
errors_found |= ERROR_REFS;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -755,11 +754,12 @@ static int fsck_cache_tree(struct cache_tree *it)
|
|||||||
err |= objerror(obj, _("non-tree in cache-tree"));
|
err |= objerror(obj, _("non-tree in cache-tree"));
|
||||||
}
|
}
|
||||||
for (i = 0; i < it->subtree_nr; i++)
|
for (i = 0; i < it->subtree_nr; i++)
|
||||||
err |= fsck_cache_tree(it->down[i]->cache_tree);
|
err |= fsck_cache_tree(it->down[i]->cache_tree, index_path);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fsck_resolve_undo(struct index_state *istate)
|
static int fsck_resolve_undo(struct index_state *istate,
|
||||||
|
const char *index_path)
|
||||||
{
|
{
|
||||||
struct string_list_item *item;
|
struct string_list_item *item;
|
||||||
struct string_list *resolve_undo = istate->resolve_undo;
|
struct string_list *resolve_undo = istate->resolve_undo;
|
||||||
@ -782,8 +782,9 @@ static int fsck_resolve_undo(struct index_state *istate)
|
|||||||
|
|
||||||
obj = parse_object(the_repository, &ru->oid[i]);
|
obj = parse_object(the_repository, &ru->oid[i]);
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
error(_("%s: invalid sha1 pointer in resolve-undo"),
|
error(_("%s: invalid sha1 pointer in resolve-undo of %s"),
|
||||||
oid_to_hex(&ru->oid[i]));
|
oid_to_hex(&ru->oid[i]),
|
||||||
|
index_path);
|
||||||
errors_found |= ERROR_REFS;
|
errors_found |= ERROR_REFS;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -796,6 +797,38 @@ static int fsck_resolve_undo(struct index_state *istate)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fsck_index(struct index_state *istate, const char *index_path,
|
||||||
|
int is_main_index)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
/* TODO: audit for interaction with sparse-index. */
|
||||||
|
ensure_full_index(istate);
|
||||||
|
for (i = 0; i < istate->cache_nr; i++) {
|
||||||
|
unsigned int mode;
|
||||||
|
struct blob *blob;
|
||||||
|
struct object *obj;
|
||||||
|
|
||||||
|
mode = istate->cache[i]->ce_mode;
|
||||||
|
if (S_ISGITLINK(mode))
|
||||||
|
continue;
|
||||||
|
blob = lookup_blob(the_repository,
|
||||||
|
&istate->cache[i]->oid);
|
||||||
|
if (!blob)
|
||||||
|
continue;
|
||||||
|
obj = &blob->object;
|
||||||
|
obj->flags |= USED;
|
||||||
|
fsck_put_object_name(&fsck_walk_options, &obj->oid,
|
||||||
|
"%s:%s",
|
||||||
|
is_main_index ? "" : index_path,
|
||||||
|
istate->cache[i]->name);
|
||||||
|
mark_object_reachable(obj);
|
||||||
|
}
|
||||||
|
if (istate->cache_tree)
|
||||||
|
fsck_cache_tree(istate->cache_tree, index_path);
|
||||||
|
fsck_resolve_undo(istate, index_path);
|
||||||
|
}
|
||||||
|
|
||||||
static void mark_object_for_connectivity(const struct object_id *oid)
|
static void mark_object_for_connectivity(const struct object_id *oid)
|
||||||
{
|
{
|
||||||
struct object *obj = lookup_unknown_object(the_repository, oid);
|
struct object *obj = lookup_unknown_object(the_repository, oid);
|
||||||
@ -956,32 +989,30 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (keep_cache_objects) {
|
if (keep_cache_objects) {
|
||||||
|
struct worktree **worktrees, **p;
|
||||||
|
|
||||||
verify_index_checksum = 1;
|
verify_index_checksum = 1;
|
||||||
verify_ce_order = 1;
|
verify_ce_order = 1;
|
||||||
repo_read_index(the_repository);
|
|
||||||
/* TODO: audit for interaction with sparse-index. */
|
|
||||||
ensure_full_index(&the_index);
|
|
||||||
for (i = 0; i < the_index.cache_nr; i++) {
|
|
||||||
unsigned int mode;
|
|
||||||
struct blob *blob;
|
|
||||||
struct object *obj;
|
|
||||||
|
|
||||||
mode = the_index.cache[i]->ce_mode;
|
worktrees = get_worktrees();
|
||||||
if (S_ISGITLINK(mode))
|
for (p = worktrees; *p; p++) {
|
||||||
continue;
|
struct worktree *wt = *p;
|
||||||
blob = lookup_blob(the_repository,
|
struct index_state istate =
|
||||||
&the_index.cache[i]->oid);
|
INDEX_STATE_INIT(the_repository);
|
||||||
if (!blob)
|
char *path;
|
||||||
continue;
|
|
||||||
obj = &blob->object;
|
/*
|
||||||
obj->flags |= USED;
|
* Make a copy since the buffer is reusable
|
||||||
fsck_put_object_name(&fsck_walk_options, &obj->oid,
|
* and may get overwritten by other calls
|
||||||
":%s", the_index.cache[i]->name);
|
* while we're examining the index.
|
||||||
mark_object_reachable(obj);
|
*/
|
||||||
|
path = xstrdup(worktree_git_path(wt, "index"));
|
||||||
|
read_index_from(&istate, path, get_worktree_git_dir(wt));
|
||||||
|
fsck_index(&istate, path, wt->is_current);
|
||||||
|
discard_index(&istate);
|
||||||
|
free(path);
|
||||||
}
|
}
|
||||||
if (the_index.cache_tree)
|
free_worktrees(worktrees);
|
||||||
fsck_cache_tree(the_index.cache_tree);
|
|
||||||
fsck_resolve_undo(&the_index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
check_connectivity();
|
check_connectivity();
|
||||||
|
@ -1023,4 +1023,34 @@ test_expect_success 'fsck error on gitattributes with excessive size' '
|
|||||||
test_cmp expected actual
|
test_cmp expected actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'fsck detects problems in worktree index' '
|
||||||
|
test_when_finished "git worktree remove -f wt" &&
|
||||||
|
git worktree add wt &&
|
||||||
|
|
||||||
|
echo "this will be removed to break the worktree index" >wt/file &&
|
||||||
|
git -C wt add file &&
|
||||||
|
blob=$(git -C wt rev-parse :file) &&
|
||||||
|
remove_object $blob &&
|
||||||
|
|
||||||
|
test_must_fail git fsck --name-objects >actual 2>&1 &&
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
missing blob $blob (.git/worktrees/wt/index:file)
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'fsck reports problems in main index without filename' '
|
||||||
|
test_when_finished "rm -f .git/index && git read-tree HEAD" &&
|
||||||
|
echo "this object will be removed to break the main index" >file &&
|
||||||
|
git add file &&
|
||||||
|
blob=$(git rev-parse :file) &&
|
||||||
|
remove_object $blob &&
|
||||||
|
|
||||||
|
test_must_fail git fsck --name-objects >actual 2>&1 &&
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
missing blob $blob (:file)
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
Loading…
x
Reference in New Issue
Block a user