|
|
@ -36,6 +36,8 @@ struct expire_reflog_cb { |
|
|
|
FILE *newlog; |
|
|
|
FILE *newlog; |
|
|
|
const char *ref; |
|
|
|
const char *ref; |
|
|
|
struct commit *ref_commit; |
|
|
|
struct commit *ref_commit; |
|
|
|
|
|
|
|
struct commit_list *mark_list; |
|
|
|
|
|
|
|
unsigned long mark_limit; |
|
|
|
struct cmd_reflog_expire_cb *cmd; |
|
|
|
struct cmd_reflog_expire_cb *cmd; |
|
|
|
unsigned char last_kept_sha1[20]; |
|
|
|
unsigned char last_kept_sha1[20]; |
|
|
|
}; |
|
|
|
}; |
|
|
@ -210,46 +212,23 @@ static int keep_entry(struct commit **it, unsigned char *sha1) |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsigned char *sha1) |
|
|
|
/* |
|
|
|
|
|
|
|
* 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; |
|
|
|
* We may or may not have the commit yet - if not, look it |
|
|
|
struct commit_list *pending; |
|
|
|
* up using the supplied sha1. |
|
|
|
unsigned long expire_limit = cb->mark_limit; |
|
|
|
*/ |
|
|
|
struct commit_list *leftover = NULL; |
|
|
|
if (!commit) { |
|
|
|
|
|
|
|
if (is_null_sha1(sha1)) |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
commit = lookup_commit_reference_gently(sha1, 1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Not a commit -- keep it */ |
|
|
|
|
|
|
|
if (!commit) |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 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) |
|
|
|
for (pending = cb->mark_list; pending; pending = pending->next) |
|
|
|
{ |
|
|
|
pending->item->object.flags &= ~REACHABLE; |
|
|
|
/* |
|
|
|
|
|
|
|
* 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); |
|
|
|
pending = cb->mark_list; |
|
|
|
while (pending) { |
|
|
|
while (pending) { |
|
|
|
struct commit_list *entry = pending; |
|
|
|
struct commit_list *entry = pending; |
|
|
|
struct commit_list *parent; |
|
|
|
struct commit_list *parent; |
|
|
@ -261,8 +240,11 @@ static void mark_reachable(struct commit *commit, unsigned long expire_limit) |
|
|
|
if (parse_commit(commit)) |
|
|
|
if (parse_commit(commit)) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
commit->object.flags |= REACHABLE; |
|
|
|
commit->object.flags |= REACHABLE; |
|
|
|
if (commit->date < expire_limit) |
|
|
|
if (commit->date < expire_limit) { |
|
|
|
|
|
|
|
commit_list_insert(commit, &leftover); |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
commit->object.flags |= REACHABLE; |
|
|
|
parent = commit->parents; |
|
|
|
parent = commit->parents; |
|
|
|
while (parent) { |
|
|
|
while (parent) { |
|
|
|
commit = parent->item; |
|
|
|
commit = parent->item; |
|
|
@ -272,6 +254,36 @@ static void mark_reachable(struct commit *commit, unsigned long expire_limit) |
|
|
|
commit_list_insert(commit, &pending); |
|
|
|
commit_list_insert(commit, &pending); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
cb->mark_list = leftover; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsigned char *sha1) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
* We may or may not have the commit yet - if not, look it |
|
|
|
|
|
|
|
* up using the supplied sha1. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if (!commit) { |
|
|
|
|
|
|
|
if (is_null_sha1(sha1)) |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
commit = lookup_commit_reference_gently(sha1, 1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Not a commit -- keep it */ |
|
|
|
|
|
|
|
if (!commit) |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Reachable from the current ref? Don't prune. */ |
|
|
|
|
|
|
|
if (commit->object.flags & REACHABLE) |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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, |
|
|
|
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_commit = lookup_commit_reference_gently(sha1, 1); |
|
|
|
cb.ref = ref; |
|
|
|
cb.ref = ref; |
|
|
|
cb.cmd = cmd; |
|
|
|
cb.cmd = cmd; |
|
|
|
if (cb.ref_commit) |
|
|
|
if (cb.ref_commit) { |
|
|
|
mark_reachable(cb.ref_commit, cmd->expire_total); |
|
|
|
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); |
|
|
|
for_each_reflog_ent(ref, expire_reflog_ent, &cb); |
|
|
|
if (cb.ref_commit) |
|
|
|
if (cb.ref_commit) |
|
|
|
clear_commit_marks(cb.ref_commit, REACHABLE); |
|
|
|
clear_commit_marks(cb.ref_commit, REACHABLE); |
|
|
|