Skip to content

Commit 5a5ea14

Browse files
committed
revision: mark blobs needed for resolve-undo as reachable
The resolve-undo extension was added to the index in cfc5789 (resolve-undo: record resolved conflicts in a new index extension section, 2009-12-25). This extension records the blob object names and their modes of conflicted paths when the path gets resolved (e.g. with "git add"), to allow "undoing" the resolution with "checkout -m path". These blob objects should be guarded from garbage-collection while we have the resolve-undo information in the index (otherwise unresolve operation may try to use a blob object that has already been pruned away). But the code called from mark_reachable_objects() for the index forgets to do so. Teach add_index_objects_to_pending() helper to also add objects referred to by the resolve-undo extension. Also make matching changes to "fsck", which has code that is fairly similar to the reachability stuff, but have parallel implementations for all these stuff, which may (or may not) someday want to be unified. Signed-off-by: Junio C Hamano <[email protected]>
1 parent dc8c8de commit 5a5ea14

File tree

3 files changed

+145
-0
lines changed

3 files changed

+145
-0
lines changed

builtin/fsck.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "decorate.h"
2020
#include "packfile.h"
2121
#include "object-store.h"
22+
#include "resolve-undo.h"
2223
#include "run-command.h"
2324
#include "worktree.h"
2425

@@ -757,6 +758,42 @@ static int fsck_cache_tree(struct cache_tree *it)
757758
return err;
758759
}
759760

761+
static int fsck_resolve_undo(struct index_state *istate)
762+
{
763+
struct string_list_item *item;
764+
struct string_list *resolve_undo = istate->resolve_undo;
765+
766+
if (!resolve_undo)
767+
return 0;
768+
769+
for_each_string_list_item(item, resolve_undo) {
770+
const char *path = item->string;
771+
struct resolve_undo_info *ru = item->util;
772+
int i;
773+
774+
if (!ru)
775+
continue;
776+
for (i = 0; i < 3; i++) {
777+
struct object *obj;
778+
779+
if (!ru->mode[i] || !S_ISREG(ru->mode[i]))
780+
continue;
781+
782+
obj = parse_object(the_repository, &ru->oid[i]);
783+
if (!obj) {
784+
error(_("%s: invalid sha1 pointer in resolve-undo"),
785+
oid_to_hex(&ru->oid[i]));
786+
errors_found |= ERROR_REFS;
787+
}
788+
obj->flags |= USED;
789+
fsck_put_object_name(&fsck_walk_options, &ru->oid[i],
790+
":(%d):%s", i, path);
791+
mark_object_reachable(obj);
792+
}
793+
}
794+
return 0;
795+
}
796+
760797
static void mark_object_for_connectivity(const struct object_id *oid)
761798
{
762799
struct object *obj = lookup_unknown_object(the_repository, oid);
@@ -938,6 +975,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
938975
}
939976
if (active_cache_tree)
940977
fsck_cache_tree(active_cache_tree);
978+
fsck_resolve_undo(&the_index);
941979
}
942980

943981
check_connectivity();

revision.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "bloom.h"
3434
#include "json-writer.h"
3535
#include "list-objects-filter-options.h"
36+
#include "resolve-undo.h"
3637

3738
volatile show_early_output_fn_t show_early_output;
3839

@@ -1690,6 +1691,39 @@ static void add_cache_tree(struct cache_tree *it, struct rev_info *revs,
16901691

16911692
}
16921693

1694+
static void add_resolve_undo_to_pending(struct index_state *istate, struct rev_info *revs)
1695+
{
1696+
struct string_list_item *item;
1697+
struct string_list *resolve_undo = istate->resolve_undo;
1698+
1699+
if (!resolve_undo)
1700+
return;
1701+
1702+
for_each_string_list_item(item, resolve_undo) {
1703+
const char *path = item->string;
1704+
struct resolve_undo_info *ru = item->util;
1705+
int i;
1706+
1707+
if (!ru)
1708+
continue;
1709+
for (i = 0; i < 3; i++) {
1710+
struct blob *blob;
1711+
1712+
if (!ru->mode[i] || !S_ISREG(ru->mode[i]))
1713+
continue;
1714+
1715+
blob = lookup_blob(revs->repo, &ru->oid[i]);
1716+
if (!blob) {
1717+
warning(_("resolve-undo records `%s` which is missing"),
1718+
oid_to_hex(&ru->oid[i]));
1719+
continue;
1720+
}
1721+
add_pending_object_with_path(revs, &blob->object, "",
1722+
ru->mode[i], path);
1723+
}
1724+
}
1725+
}
1726+
16931727
static void do_add_index_objects_to_pending(struct rev_info *revs,
16941728
struct index_state *istate,
16951729
unsigned int flags)
@@ -1718,6 +1752,8 @@ static void do_add_index_objects_to_pending(struct rev_info *revs,
17181752
add_cache_tree(istate->cache_tree, revs, &path, flags);
17191753
strbuf_release(&path);
17201754
}
1755+
1756+
add_resolve_undo_to_pending(istate, revs);
17211757
}
17221758

17231759
void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)

t/t2030-unresolve-info.sh

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,75 @@ test_expect_success 'rerere forget (add-add conflict)' '
194194
test_i18ngrep "no remembered" actual
195195
'
196196

197+
test_expect_success 'resolve-undo keeps blobs from gc' '
198+
git checkout -f main &&
199+
200+
# First make sure we do not have any cruft left in the object store
201+
git repack -a -d &&
202+
git prune --expire=now &&
203+
git prune-packed &&
204+
git gc --prune=now &&
205+
git fsck --unreachable >cruft &&
206+
test_must_be_empty cruft &&
207+
208+
# Now add three otherwise unreferenced blob objects to the index
209+
git reset --hard &&
210+
B1=$(echo "resolve undo test data 1" | git hash-object -w --stdin) &&
211+
B2=$(echo "resolve undo test data 2" | git hash-object -w --stdin) &&
212+
B3=$(echo "resolve undo test data 3" | git hash-object -w --stdin) &&
213+
git update-index --add --index-info <<-EOF &&
214+
100644 $B1 1 frotz
215+
100644 $B2 2 frotz
216+
100644 $B3 3 frotz
217+
EOF
218+
219+
# These three blob objects are reachable (only) from the index
220+
git fsck --unreachable >cruft &&
221+
test_must_be_empty cruft &&
222+
# and they should be protected from GC
223+
git gc --prune=now &&
224+
git cat-file -e $B1 &&
225+
git cat-file -e $B2 &&
226+
git cat-file -e $B3 &&
227+
228+
# Now resolve the conflicted path
229+
B0=$(echo "resolve undo test data 0" | git hash-object -w --stdin) &&
230+
git update-index --add --cacheinfo 100644,$B0,frotz &&
231+
232+
# These three blob objects are now reachable only from the resolve-undo
233+
git fsck --unreachable >cruft &&
234+
test_must_be_empty cruft &&
235+
236+
# and they should survive GC
237+
git gc --prune=now &&
238+
git cat-file -e $B0 &&
239+
git cat-file -e $B1 &&
240+
git cat-file -e $B2 &&
241+
git cat-file -e $B3 &&
242+
243+
# Now we switch away, which nukes resolve-undo, and
244+
# blobs B0..B3 would become dangling. fsck should
245+
# notice that they are now unreachable.
246+
git checkout -f side &&
247+
git fsck --unreachable >cruft &&
248+
sort cruft >actual &&
249+
sort <<-EOF >expect &&
250+
unreachable blob $B0
251+
unreachable blob $B1
252+
unreachable blob $B2
253+
unreachable blob $B3
254+
EOF
255+
test_cmp expect actual &&
256+
257+
# And they should go away when gc runs.
258+
git gc --prune=now &&
259+
git fsck --unreachable >cruft &&
260+
test_must_be_empty cruft &&
261+
262+
test_must_fail git cat-file -e $B0 &&
263+
test_must_fail git cat-file -e $B1 &&
264+
test_must_fail git cat-file -e $B2 &&
265+
test_must_fail git cat-file -e $B3
266+
'
267+
197268
test_done

0 commit comments

Comments
 (0)