mirror of
https://github.com/git/git
synced 2024-10-30 14:03:28 +00:00
Merge branch 'jc/maint-reflog-expire-unreachable'
* jc/maint-reflog-expire-unreachable: reflog --expire-unreachable: avoid merge-base computation
This commit is contained in:
commit
a9eb304129
1 changed files with 58 additions and 42 deletions
100
builtin/reflog.c
100
builtin/reflog.c
|
@ -36,6 +36,8 @@ struct expire_reflog_cb {
|
|||
FILE *newlog;
|
||||
const char *ref;
|
||||
struct commit *ref_commit;
|
||||
struct commit_list *mark_list;
|
||||
unsigned long mark_limit;
|
||||
struct cmd_reflog_expire_cb *cmd;
|
||||
unsigned char last_kept_sha1[20];
|
||||
};
|
||||
|
@ -210,6 +212,51 @@ static int keep_entry(struct commit **it, unsigned char *sha1)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Starting from commits in the cb->mark_list, mark commits that are
|
||||
* reachable from them. Stop the traversal at commits older than
|
||||
* the expire_limit and queue them back, so that the caller can call
|
||||
* us again to restart the traversal with longer expire_limit.
|
||||
*/
|
||||
static void mark_reachable(struct expire_reflog_cb *cb)
|
||||
{
|
||||
struct commit *commit;
|
||||
struct commit_list *pending;
|
||||
unsigned long expire_limit = cb->mark_limit;
|
||||
struct commit_list *leftover = NULL;
|
||||
|
||||
for (pending = cb->mark_list; pending; pending = pending->next)
|
||||
pending->item->object.flags &= ~REACHABLE;
|
||||
|
||||
pending = cb->mark_list;
|
||||
while (pending) {
|
||||
struct commit_list *entry = pending;
|
||||
struct commit_list *parent;
|
||||
pending = entry->next;
|
||||
commit = entry->item;
|
||||
free(entry);
|
||||
if (commit->object.flags & REACHABLE)
|
||||
continue;
|
||||
if (parse_commit(commit))
|
||||
continue;
|
||||
commit->object.flags |= REACHABLE;
|
||||
if (commit->date < expire_limit) {
|
||||
commit_list_insert(commit, &leftover);
|
||||
continue;
|
||||
}
|
||||
commit->object.flags |= REACHABLE;
|
||||
parent = commit->parents;
|
||||
while (parent) {
|
||||
commit = parent->item;
|
||||
parent = parent->next;
|
||||
if (commit->object.flags & REACHABLE)
|
||||
continue;
|
||||
commit_list_insert(commit, &pending);
|
||||
}
|
||||
}
|
||||
cb->mark_list = leftover;
|
||||
}
|
||||
|
||||
static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsigned char *sha1)
|
||||
{
|
||||
/*
|
||||
|
@ -230,48 +277,13 @@ static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsig
|
|||
/* Reachable from the current ref? Don't prune. */
|
||||
if (commit->object.flags & REACHABLE)
|
||||
return 0;
|
||||
if (in_merge_bases(commit, &cb->ref_commit, 1))
|
||||
return 0;
|
||||
|
||||
/* We can't reach it - prune it. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void mark_reachable(struct commit *commit, unsigned long expire_limit)
|
||||
{
|
||||
/*
|
||||
* We need to compute whether the commit on either side of a reflog
|
||||
* entry is reachable from the tip of the ref for all entries.
|
||||
* Mark commits that are reachable from the tip down to the
|
||||
* time threshold first; we know a commit marked thusly is
|
||||
* reachable from the tip without running in_merge_bases()
|
||||
* at all.
|
||||
*/
|
||||
struct commit_list *pending = NULL;
|
||||
|
||||
commit_list_insert(commit, &pending);
|
||||
while (pending) {
|
||||
struct commit_list *entry = pending;
|
||||
struct commit_list *parent;
|
||||
pending = entry->next;
|
||||
commit = entry->item;
|
||||
free(entry);
|
||||
if (commit->object.flags & REACHABLE)
|
||||
continue;
|
||||
if (parse_commit(commit))
|
||||
continue;
|
||||
commit->object.flags |= REACHABLE;
|
||||
if (commit->date < expire_limit)
|
||||
continue;
|
||||
parent = commit->parents;
|
||||
while (parent) {
|
||||
commit = parent->item;
|
||||
parent = parent->next;
|
||||
if (commit->object.flags & REACHABLE)
|
||||
continue;
|
||||
commit_list_insert(commit, &pending);
|
||||
}
|
||||
if (cb->mark_list && cb->mark_limit) {
|
||||
cb->mark_limit = 0; /* dig down to the root */
|
||||
mark_reachable(cb);
|
||||
}
|
||||
|
||||
return !(commit->object.flags & REACHABLE);
|
||||
}
|
||||
|
||||
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,
|
|||
cb.ref_commit = lookup_commit_reference_gently(sha1, 1);
|
||||
cb.ref = ref;
|
||||
cb.cmd = cmd;
|
||||
if (cb.ref_commit)
|
||||
mark_reachable(cb.ref_commit, cmd->expire_total);
|
||||
if (cb.ref_commit) {
|
||||
cb.mark_list = NULL;
|
||||
commit_list_insert(cb.ref_commit, &cb.mark_list);
|
||||
cb.mark_limit = cmd->expire_total;
|
||||
mark_reachable(&cb);
|
||||
}
|
||||
for_each_reflog_ent(ref, expire_reflog_ent, &cb);
|
||||
if (cb.ref_commit)
|
||||
clear_commit_marks(cb.ref_commit, REACHABLE);
|
||||
|
|
Loading…
Reference in a new issue