static unsigned long default_reflog_expire;
static unsigned long default_reflog_expire_unreachable;
+enum expire_reflog_flags {
+ EXPIRE_REFLOGS_DRY_RUN = 1 << 0,
+ EXPIRE_REFLOGS_UPDATE_REF = 1 << 1
+};
+
struct cmd_reflog_expire_cb {
struct rev_info revs;
- int dry_run;
int stalefix;
int rewrite;
- int updateref;
int verbose;
unsigned long expire_total;
unsigned long expire_unreachable;
int recno;
};
-struct expire_reflog_cb {
+struct expire_reflog_policy_cb {
FILE *newlog;
enum {
UE_NORMAL,
unsigned long mark_limit;
struct cmd_reflog_expire_cb *cmd;
unsigned char last_kept_sha1[20];
+ struct commit *tip_commit;
+ struct commit_list *tips;
+};
+
+struct expire_reflog_cb {
+ unsigned int flags;
+ void *policy_cb;
};
struct collected_reflog {
unsigned char sha1[20];
char reflog[FLEX_ARRAY];
};
+
struct collect_reflog_cb {
struct collected_reflog **e;
int alloc;
* 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)
+static void mark_reachable(struct expire_reflog_policy_cb *cb)
{
struct commit *commit;
struct commit_list *pending;
cb->mark_list = leftover;
}
-static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsigned char *sha1)
+static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, unsigned char *sha1)
{
/*
* We may or may not have the commit yet - if not, look it
const char *email, unsigned long timestamp, int tz,
const char *message, void *cb_data)
{
- struct expire_reflog_cb *cb = cb_data;
+ struct expire_reflog_policy_cb *cb = cb_data;
struct commit *old, *new;
if (timestamp < cb->cmd->expire_total)
const char *message, void *cb_data)
{
struct expire_reflog_cb *cb = cb_data;
+ struct expire_reflog_policy_cb *policy_cb = cb->policy_cb;
- if (cb->cmd->rewrite)
- osha1 = cb->last_kept_sha1;
+ if (policy_cb->cmd->rewrite)
+ osha1 = policy_cb->last_kept_sha1;
if (should_expire_reflog_ent(osha1, nsha1, email, timestamp, tz,
- message, cb_data)) {
- if (!cb->newlog)
+ message, policy_cb)) {
+ if (!policy_cb->newlog)
printf("would prune %s", message);
- else if (cb->cmd->verbose)
+ else if (policy_cb->cmd->verbose)
printf("prune %s", message);
} else {
- if (cb->newlog) {
+ if (policy_cb->newlog) {
char sign = (tz < 0) ? '-' : '+';
int zone = (tz < 0) ? (-tz) : tz;
- fprintf(cb->newlog, "%s %s %s %lu %c%04d\t%s",
+ fprintf(policy_cb->newlog, "%s %s %s %lu %c%04d\t%s",
sha1_to_hex(osha1), sha1_to_hex(nsha1),
email, timestamp, sign, zone,
message);
- hashcpy(cb->last_kept_sha1, nsha1);
+ hashcpy(policy_cb->last_kept_sha1, nsha1);
}
- if (cb->cmd->verbose)
+ if (policy_cb->cmd->verbose)
printf("keep %s", message);
}
return 0;
}
-static int push_tip_to_list(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
+static int push_tip_to_list(const char *refname, const unsigned char *sha1,
+ int flags, void *cb_data)
{
struct commit_list **list = cb_data;
struct commit *tip_commit;
return 0;
}
+static void reflog_expiry_prepare(const char *refname,
+ const unsigned char *sha1,
+ struct expire_reflog_policy_cb *cb)
+{
+ if (!cb->cmd->expire_unreachable || !strcmp(refname, "HEAD")) {
+ cb->tip_commit = NULL;
+ cb->unreachable_expire_kind = UE_HEAD;
+ } else {
+ cb->tip_commit = lookup_commit_reference_gently(sha1, 1);
+ if (!cb->tip_commit)
+ cb->unreachable_expire_kind = UE_ALWAYS;
+ else
+ cb->unreachable_expire_kind = UE_NORMAL;
+ }
+
+ if (cb->cmd->expire_unreachable <= cb->cmd->expire_total)
+ cb->unreachable_expire_kind = UE_ALWAYS;
+
+ cb->mark_list = NULL;
+ cb->tips = NULL;
+ if (cb->unreachable_expire_kind != UE_ALWAYS) {
+ if (cb->unreachable_expire_kind == UE_HEAD) {
+ struct commit_list *elem;
+ for_each_ref(push_tip_to_list, &cb->tips);
+ for (elem = cb->tips; elem; elem = elem->next)
+ commit_list_insert(elem->item, &cb->mark_list);
+ } else {
+ commit_list_insert(cb->tip_commit, &cb->mark_list);
+ }
+ cb->mark_limit = cb->cmd->expire_total;
+ mark_reachable(cb);
+ }
+}
+
+static void reflog_expiry_cleanup(struct expire_reflog_policy_cb *cb)
+{
+ if (cb->unreachable_expire_kind != UE_ALWAYS) {
+ if (cb->unreachable_expire_kind == UE_HEAD) {
+ struct commit_list *elem;
+ for (elem = cb->tips; elem; elem = elem->next)
+ clear_commit_marks(elem->item, REACHABLE);
+ free_commit_list(cb->tips);
+ } else {
+ clear_commit_marks(cb->tip_commit, REACHABLE);
+ }
+ }
+}
+
static int expire_reflog(const char *refname, const unsigned char *sha1,
- struct cmd_reflog_expire_cb *cmd)
+ unsigned int flags, struct cmd_reflog_expire_cb *cmd)
{
static struct lock_file reflog_lock;
struct expire_reflog_cb cb;
+ struct expire_reflog_policy_cb policy_cb;
struct ref_lock *lock;
char *log_file;
- struct commit *tip_commit;
- struct commit_list *tips;
int status = 0;
memset(&cb, 0, sizeof(cb));
+ memset(&policy_cb, 0, sizeof(policy_cb));
+ cb.flags = flags;
+ cb.policy_cb = &policy_cb;
/*
* The reflog file is locked by holding the lock on the
}
log_file = git_pathdup("logs/%s", refname);
- if (!cmd->dry_run) {
+ if (!(flags & EXPIRE_REFLOGS_DRY_RUN)) {
/*
* Even though holding $GIT_DIR/logs/$reflog.lock has
* no locking implications, we use the lock_file
strbuf_release(&err);
goto failure;
}
- cb.newlog = fdopen_lock_file(&reflog_lock, "w");
- if (!cb.newlog) {
+ policy_cb.newlog = fdopen_lock_file(&reflog_lock, "w");
+ if (!policy_cb.newlog) {
error("cannot fdopen %s (%s)",
reflog_lock.filename.buf, strerror(errno));
goto failure;
}
}
- cb.cmd = cmd;
-
- if (!cmd->expire_unreachable || !strcmp(refname, "HEAD")) {
- tip_commit = NULL;
- cb.unreachable_expire_kind = UE_HEAD;
- } else {
- tip_commit = lookup_commit_reference_gently(sha1, 1);
- if (!tip_commit)
- cb.unreachable_expire_kind = UE_ALWAYS;
- else
- cb.unreachable_expire_kind = UE_NORMAL;
- }
-
- if (cmd->expire_unreachable <= cmd->expire_total)
- cb.unreachable_expire_kind = UE_ALWAYS;
-
- cb.mark_list = NULL;
- tips = NULL;
- if (cb.unreachable_expire_kind != UE_ALWAYS) {
- if (cb.unreachable_expire_kind == UE_HEAD) {
- struct commit_list *elem;
- for_each_ref(push_tip_to_list, &tips);
- for (elem = tips; elem; elem = elem->next)
- commit_list_insert(elem->item, &cb.mark_list);
- } else {
- commit_list_insert(tip_commit, &cb.mark_list);
- }
- cb.mark_limit = cmd->expire_total;
- mark_reachable(&cb);
- }
+ policy_cb.cmd = cmd;
+ reflog_expiry_prepare(refname, sha1, &policy_cb);
for_each_reflog_ent(refname, expire_reflog_ent, &cb);
+ reflog_expiry_cleanup(&policy_cb);
- if (cb.unreachable_expire_kind != UE_ALWAYS) {
- if (cb.unreachable_expire_kind == UE_HEAD) {
- struct commit_list *elem;
- for (elem = tips; elem; elem = elem->next)
- clear_commit_marks(elem->item, REACHABLE);
- free_commit_list(tips);
- } else {
- clear_commit_marks(tip_commit, REACHABLE);
- }
- }
-
- if (cb.newlog) {
+ if (!(flags & EXPIRE_REFLOGS_DRY_RUN)) {
if (close_lock_file(&reflog_lock)) {
status |= error("couldn't write %s: %s", log_file,
strerror(errno));
- } else if (cmd->updateref &&
+ } else if ((flags & EXPIRE_REFLOGS_UPDATE_REF) &&
(write_in_full(lock->lock_fd,
- sha1_to_hex(cb.last_kept_sha1), 40) != 40 ||
+ sha1_to_hex(policy_cb.last_kept_sha1), 40) != 40 ||
write_str_in_full(lock->lock_fd, "\n") != 1 ||
close_ref(lock) < 0)) {
status |= error("couldn't write %s",
} else if (commit_lock_file(&reflog_lock)) {
status |= error("unable to commit reflog '%s' (%s)",
log_file, strerror(errno));
- } else if (cmd->updateref && commit_ref(lock)) {
+ } else if ((flags & EXPIRE_REFLOGS_UPDATE_REF) && commit_ref(lock)) {
status |= error("couldn't set %s", lock->ref_name);
}
}
unsigned long now = time(NULL);
int i, status, do_all;
int explicit_expiry = 0;
+ unsigned int flags = 0;
default_reflog_expire_unreachable = now - 30 * 24 * 3600;
default_reflog_expire = now - 90 * 24 * 3600;
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
- cb.dry_run = 1;
+ flags |= EXPIRE_REFLOGS_DRY_RUN;
else if (starts_with(arg, "--expire=")) {
if (parse_expiry_date(arg + 9, &cb.expire_total))
die(_("'%s' is not a valid timestamp"), arg);
else if (!strcmp(arg, "--rewrite"))
cb.rewrite = 1;
else if (!strcmp(arg, "--updateref"))
- cb.updateref = 1;
+ flags |= EXPIRE_REFLOGS_UPDATE_REF;
else if (!strcmp(arg, "--all"))
do_all = 1;
else if (!strcmp(arg, "--verbose"))
for (i = 0; i < collected.nr; i++) {
struct collected_reflog *e = collected.e[i];
set_reflog_expiry_param(&cb, explicit_expiry, e->reflog);
- status |= expire_reflog(e->reflog, e->sha1, &cb);
+ status |= expire_reflog(e->reflog, e->sha1, flags, &cb);
free(e);
}
free(collected.e);
continue;
}
set_reflog_expiry_param(&cb, explicit_expiry, ref);
- status |= expire_reflog(ref, sha1, &cb);
+ status |= expire_reflog(ref, sha1, flags, &cb);
}
return status;
}
{
struct cmd_reflog_expire_cb cb;
int i, status = 0;
+ unsigned int flags = 0;
memset(&cb, 0, sizeof(cb));
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
- cb.dry_run = 1;
+ flags |= EXPIRE_REFLOGS_DRY_RUN;
else if (!strcmp(arg, "--rewrite"))
cb.rewrite = 1;
else if (!strcmp(arg, "--updateref"))
- cb.updateref = 1;
+ flags |= EXPIRE_REFLOGS_UPDATE_REF;
else if (!strcmp(arg, "--verbose"))
cb.verbose = 1;
else if (!strcmp(arg, "--")) {
cb.expire_total = 0;
}
- status |= expire_reflog(ref, sha1, &cb);
+ status |= expire_reflog(ref, sha1, flags, &cb);
free(ref);
}
return status;