Merge branch 'jc/resolve-undo' into maint
The resolve-undo information in the index was not protected against GC, which has been corrected. source: <xmqq35f7kzad.fsf@gitster.g> * jc/resolve-undo: fsck: do not dereference NULL while checking resolve-undo data revision: mark blobs needed for resolve-undo as reachable
This commit is contained in:
commit
a6aeb2fef9
@ -19,6 +19,7 @@
|
||||
#include "decorate.h"
|
||||
#include "packfile.h"
|
||||
#include "object-store.h"
|
||||
#include "resolve-undo.h"
|
||||
#include "run-command.h"
|
||||
#include "worktree.h"
|
||||
|
||||
@ -757,6 +758,43 @@ static int fsck_cache_tree(struct cache_tree *it)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fsck_resolve_undo(struct index_state *istate)
|
||||
{
|
||||
struct string_list_item *item;
|
||||
struct string_list *resolve_undo = istate->resolve_undo;
|
||||
|
||||
if (!resolve_undo)
|
||||
return 0;
|
||||
|
||||
for_each_string_list_item(item, resolve_undo) {
|
||||
const char *path = item->string;
|
||||
struct resolve_undo_info *ru = item->util;
|
||||
int i;
|
||||
|
||||
if (!ru)
|
||||
continue;
|
||||
for (i = 0; i < 3; i++) {
|
||||
struct object *obj;
|
||||
|
||||
if (!ru->mode[i] || !S_ISREG(ru->mode[i]))
|
||||
continue;
|
||||
|
||||
obj = parse_object(the_repository, &ru->oid[i]);
|
||||
if (!obj) {
|
||||
error(_("%s: invalid sha1 pointer in resolve-undo"),
|
||||
oid_to_hex(&ru->oid[i]));
|
||||
errors_found |= ERROR_REFS;
|
||||
continue;
|
||||
}
|
||||
obj->flags |= USED;
|
||||
fsck_put_object_name(&fsck_walk_options, &ru->oid[i],
|
||||
":(%d):%s", i, path);
|
||||
mark_object_reachable(obj);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mark_object_for_connectivity(const struct object_id *oid)
|
||||
{
|
||||
struct object *obj = lookup_unknown_object(the_repository, oid);
|
||||
@ -938,6 +976,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
if (active_cache_tree)
|
||||
fsck_cache_tree(active_cache_tree);
|
||||
fsck_resolve_undo(&the_index);
|
||||
}
|
||||
|
||||
check_connectivity();
|
||||
|
36
revision.c
36
revision.c
@ -33,6 +33,7 @@
|
||||
#include "bloom.h"
|
||||
#include "json-writer.h"
|
||||
#include "list-objects-filter-options.h"
|
||||
#include "resolve-undo.h"
|
||||
|
||||
volatile show_early_output_fn_t show_early_output;
|
||||
|
||||
@ -1696,6 +1697,39 @@ static void add_cache_tree(struct cache_tree *it, struct rev_info *revs,
|
||||
|
||||
}
|
||||
|
||||
static void add_resolve_undo_to_pending(struct index_state *istate, struct rev_info *revs)
|
||||
{
|
||||
struct string_list_item *item;
|
||||
struct string_list *resolve_undo = istate->resolve_undo;
|
||||
|
||||
if (!resolve_undo)
|
||||
return;
|
||||
|
||||
for_each_string_list_item(item, resolve_undo) {
|
||||
const char *path = item->string;
|
||||
struct resolve_undo_info *ru = item->util;
|
||||
int i;
|
||||
|
||||
if (!ru)
|
||||
continue;
|
||||
for (i = 0; i < 3; i++) {
|
||||
struct blob *blob;
|
||||
|
||||
if (!ru->mode[i] || !S_ISREG(ru->mode[i]))
|
||||
continue;
|
||||
|
||||
blob = lookup_blob(revs->repo, &ru->oid[i]);
|
||||
if (!blob) {
|
||||
warning(_("resolve-undo records `%s` which is missing"),
|
||||
oid_to_hex(&ru->oid[i]));
|
||||
continue;
|
||||
}
|
||||
add_pending_object_with_path(revs, &blob->object, "",
|
||||
ru->mode[i], path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_add_index_objects_to_pending(struct rev_info *revs,
|
||||
struct index_state *istate,
|
||||
unsigned int flags)
|
||||
@ -1724,6 +1758,8 @@ static void do_add_index_objects_to_pending(struct rev_info *revs,
|
||||
add_cache_tree(istate->cache_tree, revs, &path, flags);
|
||||
strbuf_release(&path);
|
||||
}
|
||||
|
||||
add_resolve_undo_to_pending(istate, revs);
|
||||
}
|
||||
|
||||
void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
|
||||
|
@ -194,4 +194,75 @@ test_expect_success 'rerere forget (add-add conflict)' '
|
||||
test_i18ngrep "no remembered" actual
|
||||
'
|
||||
|
||||
test_expect_success 'resolve-undo keeps blobs from gc' '
|
||||
git checkout -f main &&
|
||||
|
||||
# First make sure we do not have any cruft left in the object store
|
||||
git repack -a -d &&
|
||||
git prune --expire=now &&
|
||||
git prune-packed &&
|
||||
git gc --prune=now &&
|
||||
git fsck --unreachable >cruft &&
|
||||
test_must_be_empty cruft &&
|
||||
|
||||
# Now add three otherwise unreferenced blob objects to the index
|
||||
git reset --hard &&
|
||||
B1=$(echo "resolve undo test data 1" | git hash-object -w --stdin) &&
|
||||
B2=$(echo "resolve undo test data 2" | git hash-object -w --stdin) &&
|
||||
B3=$(echo "resolve undo test data 3" | git hash-object -w --stdin) &&
|
||||
git update-index --add --index-info <<-EOF &&
|
||||
100644 $B1 1 frotz
|
||||
100644 $B2 2 frotz
|
||||
100644 $B3 3 frotz
|
||||
EOF
|
||||
|
||||
# These three blob objects are reachable (only) from the index
|
||||
git fsck --unreachable >cruft &&
|
||||
test_must_be_empty cruft &&
|
||||
# and they should be protected from GC
|
||||
git gc --prune=now &&
|
||||
git cat-file -e $B1 &&
|
||||
git cat-file -e $B2 &&
|
||||
git cat-file -e $B3 &&
|
||||
|
||||
# Now resolve the conflicted path
|
||||
B0=$(echo "resolve undo test data 0" | git hash-object -w --stdin) &&
|
||||
git update-index --add --cacheinfo 100644,$B0,frotz &&
|
||||
|
||||
# These three blob objects are now reachable only from the resolve-undo
|
||||
git fsck --unreachable >cruft &&
|
||||
test_must_be_empty cruft &&
|
||||
|
||||
# and they should survive GC
|
||||
git gc --prune=now &&
|
||||
git cat-file -e $B0 &&
|
||||
git cat-file -e $B1 &&
|
||||
git cat-file -e $B2 &&
|
||||
git cat-file -e $B3 &&
|
||||
|
||||
# Now we switch away, which nukes resolve-undo, and
|
||||
# blobs B0..B3 would become dangling. fsck should
|
||||
# notice that they are now unreachable.
|
||||
git checkout -f side &&
|
||||
git fsck --unreachable >cruft &&
|
||||
sort cruft >actual &&
|
||||
sort <<-EOF >expect &&
|
||||
unreachable blob $B0
|
||||
unreachable blob $B1
|
||||
unreachable blob $B2
|
||||
unreachable blob $B3
|
||||
EOF
|
||||
test_cmp expect actual &&
|
||||
|
||||
# And they should go away when gc runs.
|
||||
git gc --prune=now &&
|
||||
git fsck --unreachable >cruft &&
|
||||
test_must_be_empty cruft &&
|
||||
|
||||
test_must_fail git cat-file -e $B0 &&
|
||||
test_must_fail git cat-file -e $B1 &&
|
||||
test_must_fail git cat-file -e $B2 &&
|
||||
test_must_fail git cat-file -e $B3
|
||||
'
|
||||
|
||||
test_done
|
||||
|
Loading…
Reference in New Issue
Block a user