36
FILE *newlog;
37
const char *ref;
38
struct commit *ref_commit;
39
+ struct commit_list *mark_list;
40
+ unsigned long mark_limit;
41
struct cmd_reflog_expire_cb *cmd;
42
unsigned char last_kept_sha1[20];
43
};
212
return 1;
213
}
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)
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;
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;
230
252
- commit_list_insert(commit, &pending);
231
+ pending = cb->mark_list;
232
while (pending) {
233
struct commit_list *entry = pending;
234
struct commit_list *parent;
240
if (parse_commit(commit))
241
continue;
242
commit->object.flags |= REACHABLE;
264
- if (commit->date < expire_limit)
243
+ if (commit->date < expire_limit) {
244
+ commit_list_insert(commit, &leftover);
245
continue;
246
+ }
247
+ commit->object.flags |= REACHABLE;
248
parent = commit->parents;
249
while (parent) {
250
commit = parent->item;
254
commit_list_insert(commit, &pending);
255
}
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);
287
}
288
289
static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
360
cb.ref_commit = lookup_commit_reference_gently(sha1, 1);
361
cb.ref = ref;
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
+ }
369
for_each_reflog_ent(ref, expire_reflog_ent, &cb);
370
if (cb.ref_commit)
371
clear_commit_marks(cb.ref_commit, REACHABLE);