#include "revision.h"
#include "reachable.h"
-/*
- * reflog expire
- */
-
+/* NEEDSWORK: switch to using parse_options */
static const char reflog_expire_usage[] =
-"git reflog expire [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
+"git reflog expire [--expire=<time>] [--expire-unreachable=<time>] [--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] [--verbose] [--all] <refs>...";
static const char reflog_delete_usage[] =
-"git reflog delete [--verbose] [--dry-run] [--rewrite] [--updateref] <refs>...";
+"git reflog delete [--rewrite] [--updateref] [--dry-run | -n] [--verbose] <refs>...";
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,
- EXPIRE_REFLOGS_VERBOSE = 1 << 2,
- EXPIRE_REFLOGS_REWRITE = 1 << 3
-};
-
struct cmd_reflog_expire_cb {
struct rev_info revs;
int stalefix;
struct commit_list *tips;
};
-struct expire_reflog_cb {
- unsigned int flags;
- void *policy_cb;
- FILE *newlog;
- unsigned char last_kept_sha1[20];
-};
-
struct collected_reflog {
unsigned char sha1[20];
char reflog[FLEX_ARRAY];
return 0;
}
-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)
-{
- struct expire_reflog_cb *cb = cb_data;
- struct expire_reflog_policy_cb *policy_cb = cb->policy_cb;
-
- if (cb->flags & EXPIRE_REFLOGS_REWRITE)
- osha1 = cb->last_kept_sha1;
-
- if (should_expire_reflog_ent(osha1, nsha1, email, timestamp, tz,
- message, policy_cb)) {
- if (!cb->newlog)
- printf("would prune %s", message);
- else if (cb->flags & EXPIRE_REFLOGS_VERBOSE)
- printf("prune %s", message);
- } else {
- if (cb->newlog) {
- char sign = (tz < 0) ? '-' : '+';
- int zone = (tz < 0) ? (-tz) : tz;
- fprintf(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);
- }
- if (cb->flags & EXPIRE_REFLOGS_VERBOSE)
- printf("keep %s", message);
- }
- return 0;
-}
-
-static int push_tip_to_list(const char *refname, const unsigned char *sha1,
+static int push_tip_to_list(const char *refname, const struct object_id *oid,
int flags, void *cb_data)
{
struct commit_list **list = cb_data;
struct commit *tip_commit;
if (flags & REF_ISSYMREF)
return 0;
- tip_commit = lookup_commit_reference_gently(sha1, 1);
+ tip_commit = lookup_commit_reference_gently(oid->hash, 1);
if (!tip_commit)
return 0;
commit_list_insert(tip_commit, list);
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);
}
}
-static int expire_reflog(const char *refname, const unsigned char *sha1,
- unsigned int flags, void *policy_cb_data)
-{
- static struct lock_file reflog_lock;
- struct expire_reflog_cb cb;
- struct ref_lock *lock;
- char *log_file;
- int status = 0;
-
- memset(&cb, 0, sizeof(cb));
- cb.flags = flags;
- cb.policy_cb = policy_cb_data;
-
- /*
- * The reflog file is locked by holding the lock on the
- * reference itself, plus we might need to update the
- * reference if --updateref was specified:
- */
- lock = lock_any_ref_for_update(refname, sha1, 0, NULL);
- if (!lock)
- return error("cannot lock ref '%s'", refname);
- if (!reflog_exists(refname)) {
- unlock_ref(lock);
- return 0;
- }
-
- log_file = git_pathdup("logs/%s", refname);
- if (!(flags & EXPIRE_REFLOGS_DRY_RUN)) {
- /*
- * Even though holding $GIT_DIR/logs/$reflog.lock has
- * no locking implications, we use the lock_file
- * machinery here anyway because it does a lot of the
- * work we need, including cleaning up if the program
- * exits unexpectedly.
- */
- if (hold_lock_file_for_update(&reflog_lock, log_file, 0) < 0) {
- struct strbuf err = STRBUF_INIT;
- unable_to_lock_message(log_file, errno, &err);
- error("%s", err.buf);
- strbuf_release(&err);
- goto failure;
- }
- cb.newlog = fdopen_lock_file(&reflog_lock, "w");
- if (!cb.newlog) {
- error("cannot fdopen %s (%s)",
- reflog_lock.filename.buf, strerror(errno));
- goto failure;
- }
- }
-
- reflog_expiry_prepare(refname, sha1, cb.policy_cb);
- for_each_reflog_ent(refname, expire_reflog_ent, &cb);
- reflog_expiry_cleanup(cb.policy_cb);
-
- 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 ((flags & EXPIRE_REFLOGS_UPDATE_REF) &&
- (write_in_full(lock->lock_fd,
- sha1_to_hex(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",
- lock->lk->filename.buf);
- rollback_lock_file(&reflog_lock);
- } else if (commit_lock_file(&reflog_lock)) {
- status |= error("unable to commit reflog '%s' (%s)",
- log_file, strerror(errno));
- } else if ((flags & EXPIRE_REFLOGS_UPDATE_REF) && commit_ref(lock)) {
- status |= error("couldn't set %s", lock->ref_name);
- }
- }
- free(log_file);
- unlock_ref(lock);
- return status;
-
- failure:
- rollback_lock_file(&reflog_lock);
- free(log_file);
- unlock_ref(lock);
- return -1;
-}
-
-static int collect_reflog(const char *ref, const unsigned char *sha1, int unused, void *cb_data)
+static int collect_reflog(const char *ref, const struct object_id *oid, int unused, void *cb_data)
{
struct collected_reflog *e;
struct collect_reflog_cb *cb = cb_data;
size_t namelen = strlen(ref);
e = xmalloc(sizeof(*e) + namelen + 1);
- hashcpy(e->sha1, sha1);
+ hashcpy(e->sha1, oid->hash);
memcpy(e->reflog, ref, namelen + 1);
ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);
cb->e[cb->nr++] = e;
for (i = 0; i < collected.nr; i++) {
struct collected_reflog *e = collected.e[i];
set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog);
- status |= expire_reflog(e->reflog, e->sha1, flags, &cb);
+ status |= reflog_expire(e->reflog, e->sha1, flags,
+ reflog_expiry_prepare,
+ should_expire_reflog_ent,
+ reflog_expiry_cleanup,
+ &cb);
free(e);
}
free(collected.e);
continue;
}
set_reflog_expiry_param(&cb.cmd, explicit_expiry, ref);
- status |= expire_reflog(ref, sha1, flags, &cb);
+ status |= reflog_expire(ref, sha1, flags,
+ reflog_expiry_prepare,
+ should_expire_reflog_ent,
+ reflog_expiry_cleanup,
+ &cb);
}
return status;
}
cb.cmd.expire_total = 0;
}
- status |= expire_reflog(ref, sha1, flags, &cb);
+ status |= reflog_expire(ref, sha1, flags,
+ reflog_expiry_prepare,
+ should_expire_reflog_ent,
+ reflog_expiry_cleanup,
+ &cb);
free(ref);
}
return status;