Skip to content

Commit a9eb304

Browse files
committed
Merge branch 'jc/maint-reflog-expire-unreachable'
* jc/maint-reflog-expire-unreachable: reflog --expire-unreachable: avoid merge-base computation
2 parents 72d9b22 + b4ca1db commit a9eb304

File tree

1 file changed

+56
-40
lines changed

1 file changed

+56
-40
lines changed

builtin/reflog.c

Lines changed: 56 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ struct expire_reflog_cb {
3636
FILE *newlog;
3737
const char *ref;
3838
struct commit *ref_commit;
39+
struct commit_list *mark_list;
40+
unsigned long mark_limit;
3941
struct cmd_reflog_expire_cb *cmd;
4042
unsigned char last_kept_sha1[20];
4143
};
@@ -210,46 +212,23 @@ static int keep_entry(struct commit **it, unsigned char *sha1)
210212
return 1;
211213
}
212214

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)
214222
{
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;
239227

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;
251230

252-
commit_list_insert(commit, &pending);
231+
pending = cb->mark_list;
253232
while (pending) {
254233
struct commit_list *entry = pending;
255234
struct commit_list *parent;
@@ -261,8 +240,11 @@ static void mark_reachable(struct commit *commit, unsigned long expire_limit)
261240
if (parse_commit(commit))
262241
continue;
263242
commit->object.flags |= REACHABLE;
264-
if (commit->date < expire_limit)
243+
if (commit->date < expire_limit) {
244+
commit_list_insert(commit, &leftover);
265245
continue;
246+
}
247+
commit->object.flags |= REACHABLE;
266248
parent = commit->parents;
267249
while (parent) {
268250
commit = parent->item;
@@ -272,6 +254,36 @@ static void mark_reachable(struct commit *commit, unsigned long expire_limit)
272254
commit_list_insert(commit, &pending);
273255
}
274256
}
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);
275287
}
276288

277289
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,
348360
cb.ref_commit = lookup_commit_reference_gently(sha1, 1);
349361
cb.ref = ref;
350362
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+
}
353369
for_each_reflog_ent(ref, expire_reflog_ent, &cb);
354370
if (cb.ref_commit)
355371
clear_commit_marks(cb.ref_commit, REACHABLE);

0 commit comments

Comments
 (0)