|
|
|
@ -52,6 +52,7 @@ struct collect_reflog_cb {
@@ -52,6 +52,7 @@ struct collect_reflog_cb {
|
|
|
|
|
|
|
|
|
|
#define INCOMPLETE (1u<<10) |
|
|
|
|
#define STUDYING (1u<<11) |
|
|
|
|
#define REACHABLE (1u<<12) |
|
|
|
|
|
|
|
|
|
static int tree_is_complete(const unsigned char *sha1) |
|
|
|
|
{ |
|
|
|
@ -209,6 +210,70 @@ static int keep_entry(struct commit **it, unsigned char *sha1)
@@ -209,6 +210,70 @@ static int keep_entry(struct commit **it, unsigned char *sha1)
|
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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 (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 if commit on either side of an 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 threashold 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); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1, |
|
|
|
|
const char *email, unsigned long timestamp, int tz, |
|
|
|
|
const char *message, void *cb_data) |
|
|
|
@ -230,12 +295,7 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
@@ -230,12 +295,7 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
|
|
|
|
|
if (timestamp < cb->cmd->expire_unreachable) { |
|
|
|
|
if (!cb->ref_commit) |
|
|
|
|
goto prune; |
|
|
|
|
if (!old && !is_null_sha1(osha1)) |
|
|
|
|
old = lookup_commit_reference_gently(osha1, 1); |
|
|
|
|
if (!new && !is_null_sha1(nsha1)) |
|
|
|
|
new = lookup_commit_reference_gently(nsha1, 1); |
|
|
|
|
if ((old && !in_merge_bases(old, &cb->ref_commit, 1)) || |
|
|
|
|
(new && !in_merge_bases(new, &cb->ref_commit, 1))) |
|
|
|
|
if (unreachable(cb, old, osha1) || unreachable(cb, new, nsha1)) |
|
|
|
|
goto prune; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -288,7 +348,11 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
@@ -288,7 +348,11 @@ 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); |
|
|
|
|
for_each_reflog_ent(ref, expire_reflog_ent, &cb); |
|
|
|
|
if (cb.ref_commit) |
|
|
|
|
clear_commit_marks(cb.ref_commit, REACHABLE); |
|
|
|
|
finish: |
|
|
|
|
if (cb.newlog) { |
|
|
|
|
if (fclose(cb.newlog)) { |
|
|
|
|