commit_packed_refs(): use reference iteration
Use reference iteration rather than do_for_each_entry_in_dir() in the definition of commit_packed_refs(). Note that an internal consistency check that was previously done in `write_packed_entry_fn()` is not there anymore. This is actually an improvement: The old error message was emitted when there is an entry in the packed-ref cache that is not `REF_KNOWS_PEELED`, and when we attempted to peel the reference, the result was `PEEL_INVALID`, `PEEL_IS_SYMREF`, or `PEEL_BROKEN`. Since a packed ref cannot be a symref, `PEEL_IS_SYMREF` and `PEEL_BROKEN` can be ruled out. So we're left with `PEEL_INVALID`. An entry without `REF_KNOWS_PEELED` can get into the packed-refs cache in the following two ways: * The reference was read from a `packed-refs` file that didn't have the `fully-peeled` attribute. In that case, we *don't want* to emit an error, because the broken value is presumably a stale value of the reference that is now masked by a loose version of the same reference (which we just don't happen to be packing this time). This is a perfectly legitimate situation and doesn't indicate that the repository is corrupt. The old code incorrectly emits an error message in this case. (It was probably never reported as a bug because this scenario is rare.) * The reference was a loose reference that was just added to the packed ref cache by `files_packed_refs()` via `pack_if_possible_fn()` in preparation for being packed. The latter function refuses to pack a reference for which `entry_resolves_to_object()` returns false, and otherwise calls `peel_entry()` itself and checks the return value. So an entry added this way should always have `REF_KNOWS_PEELED` and shouldn't trigger the error message in either the old code or the new. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
059ae35a48
commit
1710fbafb6
@ -1290,30 +1290,15 @@ static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs,
|
|||||||
* Write an entry to the packed-refs file for the specified refname.
|
* Write an entry to the packed-refs file for the specified refname.
|
||||||
* If peeled is non-NULL, write it as the entry's peeled value.
|
* If peeled is non-NULL, write it as the entry's peeled value.
|
||||||
*/
|
*/
|
||||||
static void write_packed_entry(FILE *fh, char *refname, unsigned char *sha1,
|
static void write_packed_entry(FILE *fh, const char *refname,
|
||||||
unsigned char *peeled)
|
const unsigned char *sha1,
|
||||||
|
const unsigned char *peeled)
|
||||||
{
|
{
|
||||||
fprintf_or_die(fh, "%s %s\n", sha1_to_hex(sha1), refname);
|
fprintf_or_die(fh, "%s %s\n", sha1_to_hex(sha1), refname);
|
||||||
if (peeled)
|
if (peeled)
|
||||||
fprintf_or_die(fh, "^%s\n", sha1_to_hex(peeled));
|
fprintf_or_die(fh, "^%s\n", sha1_to_hex(peeled));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* An each_ref_entry_fn that writes the entry to a packed-refs file.
|
|
||||||
*/
|
|
||||||
static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)
|
|
||||||
{
|
|
||||||
enum peel_status peel_status = peel_entry(entry, 0);
|
|
||||||
|
|
||||||
if (peel_status != PEEL_PEELED && peel_status != PEEL_NON_TAG)
|
|
||||||
error("internal error: %s is not a valid packed reference!",
|
|
||||||
entry->name);
|
|
||||||
write_packed_entry(cb_data, entry->name, entry->u.value.oid.hash,
|
|
||||||
peel_status == PEEL_PEELED ?
|
|
||||||
entry->u.value.peeled.hash : NULL);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lock the packed-refs file for writing. Flags is passed to
|
* Lock the packed-refs file for writing. Flags is passed to
|
||||||
* hold_lock_file_for_update(). Return 0 on success. On errors, set
|
* hold_lock_file_for_update(). Return 0 on success. On errors, set
|
||||||
@ -1359,9 +1344,10 @@ static int commit_packed_refs(struct files_ref_store *refs)
|
|||||||
{
|
{
|
||||||
struct packed_ref_cache *packed_ref_cache =
|
struct packed_ref_cache *packed_ref_cache =
|
||||||
get_packed_ref_cache(refs);
|
get_packed_ref_cache(refs);
|
||||||
int error = 0;
|
int ok, error = 0;
|
||||||
int save_errno = 0;
|
int save_errno = 0;
|
||||||
FILE *out;
|
FILE *out;
|
||||||
|
struct ref_iterator *iter;
|
||||||
|
|
||||||
files_assert_main_repository(refs, "commit_packed_refs");
|
files_assert_main_repository(refs, "commit_packed_refs");
|
||||||
|
|
||||||
@ -1373,8 +1359,18 @@ static int commit_packed_refs(struct files_ref_store *refs)
|
|||||||
die_errno("unable to fdopen packed-refs descriptor");
|
die_errno("unable to fdopen packed-refs descriptor");
|
||||||
|
|
||||||
fprintf_or_die(out, "%s", PACKED_REFS_HEADER);
|
fprintf_or_die(out, "%s", PACKED_REFS_HEADER);
|
||||||
do_for_each_entry_in_dir(get_packed_ref_dir(packed_ref_cache),
|
|
||||||
write_packed_entry_fn, out);
|
iter = cache_ref_iterator_begin(packed_ref_cache->cache, NULL, 0);
|
||||||
|
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
|
||||||
|
struct object_id peeled;
|
||||||
|
int peel_error = ref_iterator_peel(iter, &peeled);
|
||||||
|
|
||||||
|
write_packed_entry(out, iter->refname, iter->oid->hash,
|
||||||
|
peel_error ? NULL : peeled.hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok != ITER_DONE)
|
||||||
|
die("error while iterating over references");
|
||||||
|
|
||||||
if (commit_lock_file(packed_ref_cache->lock)) {
|
if (commit_lock_file(packed_ref_cache->lock)) {
|
||||||
save_errno = errno;
|
save_errno = errno;
|
||||||
|
Loading…
Reference in New Issue
Block a user