Skip to content

Commit ea56c4e

Browse files
peffgitster
authored andcommitted
refs.c: drop curate_packed_refs
When we delete a ref, we have to rewrite the entire packed-refs file. We take this opportunity to "curate" the packed-refs file and drop any entries that are crufty or broken. Dropping broken entries (e.g., with bogus names, or ones that point to missing objects) is actively a bad idea, as it means that we lose any notion that the data was there in the first place. Aside from the general hackiness that we might lose any information about ref "foo" while deleting an unrelated ref "bar", this may seriously hamper any attempts by the user at recovering from the corruption in "foo". They will lose the sha1 and name of "foo"; the exact pointer may still be useful even if they recover missing objects from a different copy of the repository. But worse, once the ref is gone, there is no trace of the corruption. A follow-up "git prune" may delete objects, even though it would otherwise bail when seeing corruption. We could just drop the "broken" bits from curate_packed_refs, and continue to drop the "crufty" bits: refs whose loose counterpart exists in the filesystem. This is not wrong to do, and it does have the advantage that we may write out a slightly smaller packed-refs file. But it has two disadvantages: 1. It is a potential source of races or mistakes with respect to these refs that are otherwise unrelated to the operation. To my knowledge, there aren't any active problems in this area, but it seems like an unnecessary risk. 2. We have to spend time looking up the matching loose refs for every item in the packed-refs file. If you have a large number of packed refs that do not change, that outweighs the benefit from writing out a smaller packed-refs file (it doesn't get smaller, and you do a bunch of directory traversal to find that out). Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 8d42299 commit ea56c4e

File tree

2 files changed

+2
-67
lines changed

2 files changed

+2
-67
lines changed

refs.c

Lines changed: 1 addition & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2596,68 +2596,10 @@ int pack_refs(unsigned int flags)
25962596
return 0;
25972597
}
25982598

2599-
/*
2600-
* If entry is no longer needed in packed-refs, add it to the string
2601-
* list pointed to by cb_data. Reasons for deleting entries:
2602-
*
2603-
* - Entry is broken.
2604-
* - Entry is overridden by a loose ref.
2605-
* - Entry does not point at a valid object.
2606-
*
2607-
* In the first and third cases, also emit an error message because these
2608-
* are indications of repository corruption.
2609-
*/
2610-
static int curate_packed_ref_fn(struct ref_entry *entry, void *cb_data)
2611-
{
2612-
struct string_list *refs_to_delete = cb_data;
2613-
2614-
if (entry->flag & REF_ISBROKEN) {
2615-
/* This shouldn't happen to packed refs. */
2616-
error("%s is broken!", entry->name);
2617-
string_list_append(refs_to_delete, entry->name);
2618-
return 0;
2619-
}
2620-
if (!has_sha1_file(entry->u.value.sha1)) {
2621-
unsigned char sha1[20];
2622-
int flags;
2623-
2624-
if (read_ref_full(entry->name, 0, sha1, &flags))
2625-
/* We should at least have found the packed ref. */
2626-
die("Internal error");
2627-
if ((flags & REF_ISSYMREF) || !(flags & REF_ISPACKED)) {
2628-
/*
2629-
* This packed reference is overridden by a
2630-
* loose reference, so it is OK that its value
2631-
* is no longer valid; for example, it might
2632-
* refer to an object that has been garbage
2633-
* collected. For this purpose we don't even
2634-
* care whether the loose reference itself is
2635-
* invalid, broken, symbolic, etc. Silently
2636-
* remove the packed reference.
2637-
*/
2638-
string_list_append(refs_to_delete, entry->name);
2639-
return 0;
2640-
}
2641-
/*
2642-
* There is no overriding loose reference, so the fact
2643-
* that this reference doesn't refer to a valid object
2644-
* indicates some kind of repository corruption.
2645-
* Report the problem, then omit the reference from
2646-
* the output.
2647-
*/
2648-
error("%s does not point to a valid object!", entry->name);
2649-
string_list_append(refs_to_delete, entry->name);
2650-
return 0;
2651-
}
2652-
2653-
return 0;
2654-
}
2655-
26562599
int repack_without_refs(struct string_list *refnames, struct strbuf *err)
26572600
{
26582601
struct ref_dir *packed;
2659-
struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
2660-
struct string_list_item *refname, *ref_to_delete;
2602+
struct string_list_item *refname;
26612603
int ret, needs_repacking = 0, removed = 0;
26622604

26632605
assert(err);
@@ -2693,13 +2635,6 @@ int repack_without_refs(struct string_list *refnames, struct strbuf *err)
26932635
return 0;
26942636
}
26952637

2696-
/* Remove any other accumulated cruft */
2697-
do_for_each_entry_in_dir(packed, 0, curate_packed_ref_fn, &refs_to_delete);
2698-
for_each_string_list_item(ref_to_delete, &refs_to_delete) {
2699-
if (remove_entry(packed, ref_to_delete->string) == -1)
2700-
die("internal error");
2701-
}
2702-
27032638
/* Write what remains */
27042639
ret = commit_packed_refs();
27052640
if (ret)

t/t5312-prune-corruption.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ test_expect_success 'pack-refs does not silently delete broken packed ref' '
105105
test_cmp expect actual
106106
'
107107

108-
test_expect_failure 'pack-refs does not drop broken refs during deletion' '
108+
test_expect_success 'pack-refs does not drop broken refs during deletion' '
109109
git update-ref -d refs/heads/other &&
110110
git rev-parse refs/heads/master >actual &&
111111
test_cmp expect actual

0 commit comments

Comments
 (0)