@@ -36,6 +36,8 @@ struct expire_reflog_cb {
36
36
FILE * newlog ;
37
37
const char * ref ;
38
38
struct commit * ref_commit ;
39
+ struct commit_list * mark_list ;
40
+ unsigned long mark_limit ;
39
41
struct cmd_reflog_expire_cb * cmd ;
40
42
unsigned char last_kept_sha1 [20 ];
41
43
};
@@ -210,46 +212,23 @@ static int keep_entry(struct commit **it, unsigned char *sha1)
210
212
return 1 ;
211
213
}
212
214
213
- static int unreachable (struct expire_reflog_cb * cb , struct commit * commit , unsigned char * sha1 )
215
+ /*
216
+ * Starting from commits in the cb->mark_list, mark commits that are
217
+ * reachable from them. Stop the traversal at commits older than
218
+ * the expire_limit and queue them back, so that the caller can call
219
+ * us again to restart the traversal with longer expire_limit.
220
+ */
221
+ static void mark_reachable (struct expire_reflog_cb * cb )
214
222
{
215
- /*
216
- * We may or may not have the commit yet - if not, look it
217
- * up using the supplied sha1.
218
- */
219
- if (!commit ) {
220
- if (is_null_sha1 (sha1 ))
221
- return 0 ;
222
-
223
- commit = lookup_commit_reference_gently (sha1 , 1 );
224
-
225
- /* Not a commit -- keep it */
226
- if (!commit )
227
- return 0 ;
228
- }
229
-
230
- /* Reachable from the current ref? Don't prune. */
231
- if (commit -> object .flags & REACHABLE )
232
- return 0 ;
233
- if (in_merge_bases (commit , & cb -> ref_commit , 1 ))
234
- return 0 ;
235
-
236
- /* We can't reach it - prune it. */
237
- return 1 ;
238
- }
223
+ struct commit * commit ;
224
+ struct commit_list * pending ;
225
+ unsigned long expire_limit = cb -> mark_limit ;
226
+ struct commit_list * leftover = NULL ;
239
227
240
- static void mark_reachable (struct commit * commit , unsigned long expire_limit )
241
- {
242
- /*
243
- * We need to compute whether the commit on either side of a reflog
244
- * entry is reachable from the tip of the ref for all entries.
245
- * Mark commits that are reachable from the tip down to the
246
- * time threshold first; we know a commit marked thusly is
247
- * reachable from the tip without running in_merge_bases()
248
- * at all.
249
- */
250
- struct commit_list * pending = NULL ;
228
+ for (pending = cb -> mark_list ; pending ; pending = pending -> next )
229
+ pending -> item -> object .flags &= ~REACHABLE ;
251
230
252
- commit_list_insert ( commit , & pending ) ;
231
+ pending = cb -> mark_list ;
253
232
while (pending ) {
254
233
struct commit_list * entry = pending ;
255
234
struct commit_list * parent ;
@@ -261,8 +240,11 @@ static void mark_reachable(struct commit *commit, unsigned long expire_limit)
261
240
if (parse_commit (commit ))
262
241
continue ;
263
242
commit -> object .flags |= REACHABLE ;
264
- if (commit -> date < expire_limit )
243
+ if (commit -> date < expire_limit ) {
244
+ commit_list_insert (commit , & leftover );
265
245
continue ;
246
+ }
247
+ commit -> object .flags |= REACHABLE ;
266
248
parent = commit -> parents ;
267
249
while (parent ) {
268
250
commit = parent -> item ;
@@ -272,6 +254,36 @@ static void mark_reachable(struct commit *commit, unsigned long expire_limit)
272
254
commit_list_insert (commit , & pending );
273
255
}
274
256
}
257
+ cb -> mark_list = leftover ;
258
+ }
259
+
260
+ static int unreachable (struct expire_reflog_cb * cb , struct commit * commit , unsigned char * sha1 )
261
+ {
262
+ /*
263
+ * We may or may not have the commit yet - if not, look it
264
+ * up using the supplied sha1.
265
+ */
266
+ if (!commit ) {
267
+ if (is_null_sha1 (sha1 ))
268
+ return 0 ;
269
+
270
+ commit = lookup_commit_reference_gently (sha1 , 1 );
271
+
272
+ /* Not a commit -- keep it */
273
+ if (!commit )
274
+ return 0 ;
275
+ }
276
+
277
+ /* Reachable from the current ref? Don't prune. */
278
+ if (commit -> object .flags & REACHABLE )
279
+ return 0 ;
280
+
281
+ if (cb -> mark_list && cb -> mark_limit ) {
282
+ cb -> mark_limit = 0 ; /* dig down to the root */
283
+ mark_reachable (cb );
284
+ }
285
+
286
+ return !(commit -> object .flags & REACHABLE );
275
287
}
276
288
277
289
static int expire_reflog_ent (unsigned char * osha1 , unsigned char * nsha1 ,
@@ -348,8 +360,12 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
348
360
cb .ref_commit = lookup_commit_reference_gently (sha1 , 1 );
349
361
cb .ref = ref ;
350
362
cb .cmd = cmd ;
351
- if (cb .ref_commit )
352
- mark_reachable (cb .ref_commit , cmd -> expire_total );
363
+ if (cb .ref_commit ) {
364
+ cb .mark_list = NULL ;
365
+ commit_list_insert (cb .ref_commit , & cb .mark_list );
366
+ cb .mark_limit = cmd -> expire_total ;
367
+ mark_reachable (& cb );
368
+ }
353
369
for_each_reflog_ent (ref , expire_reflog_ent , & cb );
354
370
if (cb .ref_commit )
355
371
clear_commit_marks (cb .ref_commit , REACHABLE );
0 commit comments