Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2022-07-20 02:40:16 +0300
committerJunio C Hamano <gitster@pobox.com>2022-07-20 02:40:16 +0300
commit418aef9055c3ca85ae6439e7e76c91558f04d94b (patch)
treeead11d6ddd5f0ba06e4ac5b9dbe05d3c77d289d7
parent71a8fab31b70c417e8f5b5f716581f89955a7082 (diff)
parente0ad13977a7f6226d753ec12aedaaa9db7e57dad (diff)
Merge branch 'jc/resolve-undo'
The resolve-undo information in the index was not protected against GC, which has been corrected. * jc/resolve-undo: fsck: do not dereference NULL while checking resolve-undo data revision: mark blobs needed for resolve-undo as reachable
-rw-r--r--builtin/fsck.c39
-rw-r--r--revision.c36
-rwxr-xr-xt/t2030-unresolve-info.sh71
3 files changed, 146 insertions, 0 deletions
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 9e54892311..6c73092f10 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -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();
diff --git a/revision.c b/revision.c
index 211352795c..0c6e26cd9c 100644
--- a/revision.c
+++ b/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)
diff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh
index f691e6d903..2d8c70b03a 100755
--- a/t/t2030-unresolve-info.sh
+++ b/t/t2030-unresolve-info.sh
@@ -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