Skip to content

Commit 7b40d39

Browse files
mhaggergitster
authored andcommitted
repack_without_ref(): split list curation and entry writing
The repack_without_ref() function first removes the deleted ref from the internal packed-refs list, then writes the packed-refs list to disk, omitting any broken or stale entries. This patch splits that second step into multiple passes: * collect the list of refnames that should be deleted from packed_refs * delete those refnames from the cache * write the remainder to the packed-refs file The purpose of this change is to make the "write the remainder" part reusable. Signed-off-by: Michael Haggerty <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent ede63a1 commit 7b40d39

File tree

1 file changed

+50
-12
lines changed

1 file changed

+50
-12
lines changed

refs.c

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1998,6 +1998,23 @@ static void write_packed_entry(int fd, char *refname, unsigned char *sha1,
19981998
}
19991999
}
20002000

2001+
/*
2002+
* An each_ref_entry_fn that writes the entry to a packed-refs file.
2003+
*/
2004+
static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)
2005+
{
2006+
int *fd = cb_data;
2007+
enum peel_status peel_status = peel_entry(entry, 0);
2008+
2009+
if (peel_status != PEEL_PEELED && peel_status != PEEL_NON_TAG)
2010+
error("internal error: %s is not a valid packed reference!",
2011+
entry->name);
2012+
write_packed_entry(*fd, entry->name, entry->u.value.sha1,
2013+
peel_status == PEEL_PEELED ?
2014+
entry->u.value.peeled : NULL);
2015+
return 0;
2016+
}
2017+
20012018
struct ref_to_prune {
20022019
struct ref_to_prune *next;
20032020
unsigned char sha1[20];
@@ -2117,14 +2134,25 @@ int pack_refs(unsigned int flags)
21172134
return 0;
21182135
}
21192136

2120-
static int repack_ref_fn(struct ref_entry *entry, void *cb_data)
2137+
/*
2138+
* If entry is no longer needed in packed-refs, add it to the string
2139+
* list pointed to by cb_data. Reasons for deleting entries:
2140+
*
2141+
* - Entry is broken.
2142+
* - Entry is overridden by a loose ref.
2143+
* - Entry does not point at a valid object.
2144+
*
2145+
* In the first and third cases, also emit an error message because these
2146+
* are indications of repository corruption.
2147+
*/
2148+
static int curate_packed_ref_fn(struct ref_entry *entry, void *cb_data)
21212149
{
2122-
int *fd = cb_data;
2123-
enum peel_status peel_status;
2150+
struct string_list *refs_to_delete = cb_data;
21242151

21252152
if (entry->flag & REF_ISBROKEN) {
21262153
/* This shouldn't happen to packed refs. */
21272154
error("%s is broken!", entry->name);
2155+
string_list_append(refs_to_delete, entry->name);
21282156
return 0;
21292157
}
21302158
if (!has_sha1_file(entry->u.value.sha1)) {
@@ -2134,7 +2162,7 @@ static int repack_ref_fn(struct ref_entry *entry, void *cb_data)
21342162
if (read_ref_full(entry->name, sha1, 0, &flags))
21352163
/* We should at least have found the packed ref. */
21362164
die("Internal error");
2137-
if ((flags & REF_ISSYMREF) || !(flags & REF_ISPACKED))
2165+
if ((flags & REF_ISSYMREF) || !(flags & REF_ISPACKED)) {
21382166
/*
21392167
* This packed reference is overridden by a
21402168
* loose reference, so it is OK that its value
@@ -2143,9 +2171,11 @@ static int repack_ref_fn(struct ref_entry *entry, void *cb_data)
21432171
* collected. For this purpose we don't even
21442172
* care whether the loose reference itself is
21452173
* invalid, broken, symbolic, etc. Silently
2146-
* omit the packed reference from the output.
2174+
* remove the packed reference.
21472175
*/
2176+
string_list_append(refs_to_delete, entry->name);
21482177
return 0;
2178+
}
21492179
/*
21502180
* There is no overriding loose reference, so the fact
21512181
* that this reference doesn't refer to a valid object
@@ -2154,21 +2184,19 @@ static int repack_ref_fn(struct ref_entry *entry, void *cb_data)
21542184
* the output.
21552185
*/
21562186
error("%s does not point to a valid object!", entry->name);
2187+
string_list_append(refs_to_delete, entry->name);
21572188
return 0;
21582189
}
21592190

2160-
peel_status = peel_entry(entry, 0);
2161-
write_packed_entry(*fd, entry->name, entry->u.value.sha1,
2162-
peel_status == PEEL_PEELED ?
2163-
entry->u.value.peeled : NULL);
2164-
21652191
return 0;
21662192
}
21672193

21682194
static int repack_without_ref(const char *refname)
21692195
{
21702196
int fd;
21712197
struct ref_dir *packed;
2198+
struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
2199+
struct string_list_item *ref_to_delete;
21722200

21732201
if (!get_packed_ref(refname))
21742202
return 0; /* refname does not exist in packed refs */
@@ -2180,7 +2208,8 @@ static int repack_without_ref(const char *refname)
21802208
}
21812209
clear_packed_ref_cache(&ref_cache);
21822210
packed = get_packed_refs(&ref_cache);
2183-
/* Remove refname from the cache. */
2211+
2212+
/* Remove refname from the cache: */
21842213
if (remove_entry(packed, refname) == -1) {
21852214
/*
21862215
* The packed entry disappeared while we were
@@ -2189,8 +2218,17 @@ static int repack_without_ref(const char *refname)
21892218
rollback_lock_file(&packlock);
21902219
return 0;
21912220
}
2221+
2222+
/* Remove any other accumulated cruft: */
2223+
do_for_each_entry_in_dir(packed, 0, curate_packed_ref_fn, &refs_to_delete);
2224+
for_each_string_list_item(ref_to_delete, &refs_to_delete) {
2225+
if (remove_entry(packed, ref_to_delete->string) == -1)
2226+
die("internal error");
2227+
}
2228+
2229+
/* Write what remains: */
21922230
write_or_die(fd, PACKED_REFS_HEADER, strlen(PACKED_REFS_HEADER));
2193-
do_for_each_entry_in_dir(packed, 0, repack_ref_fn, &fd);
2231+
do_for_each_entry_in_dir(packed, 0, write_packed_entry_fn, &fd);
21942232
return commit_lock_file(&packlock);
21952233
}
21962234

0 commit comments

Comments
 (0)