int verbose;
unsigned long expire_total;
unsigned long expire_unreachable;
+ int recno;
};
struct expire_reflog_cb {
struct cmd_reflog_expire_cb *cmd;
};
+struct collected_reflog {
+ unsigned char sha1[20];
+ char reflog[FLEX_ARRAY];
+};
+struct collect_reflog_cb {
+ struct collected_reflog **e;
+ int alloc;
+ int nr;
+};
+
#define INCOMPLETE (1u<<10)
#define STUDYING (1u<<11)
goto prune;
}
+ if (cb->cmd->recno && --(cb->cmd->recno) == 0)
+ goto prune;
+
if (cb->newlog) {
char sign = (tz < 0) ? '-' : '+';
int zone = (tz < 0) ? (-tz) : tz;
for_each_reflog_ent(ref, expire_reflog_ent, &cb);
finish:
if (cb.newlog) {
- if (fclose(cb.newlog))
+ if (fclose(cb.newlog)) {
status |= error("%s: %s", strerror(errno),
newlog_path);
- if (rename(newlog_path, log_file)) {
+ unlink(newlog_path);
+ } else if (rename(newlog_path, log_file)) {
status |= error("cannot rename %s to %s",
newlog_path, log_file);
unlink(newlog_path);
return status;
}
+static int collect_reflog(const char *ref, const unsigned char *sha1, 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);
+ memcpy(e->reflog, ref, namelen + 1);
+ ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);
+ cb->e[cb->nr++] = e;
+ return 0;
+}
+
static int reflog_expire_config(const char *var, const char *value)
{
- if (!strcmp(var, "gc.reflogexpire"))
+ if (!strcmp(var, "gc.reflogexpire")) {
+ if (!value)
+ config_error_nonbool(var);
default_reflog_expire = approxidate(value);
- else if (!strcmp(var, "gc.reflogexpireunreachable"))
+ return 0;
+ }
+ if (!strcmp(var, "gc.reflogexpireunreachable")) {
+ if (!value)
+ config_error_nonbool(var);
default_reflog_expire_unreachable = approxidate(value);
- else
- return git_default_config(var, value);
- return 0;
+ return 0;
+ }
+ return git_default_config(var, value);
}
static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
putchar('\n');
}
- if (do_all)
- status |= for_each_reflog(expire_reflog, &cb);
+ if (do_all) {
+ struct collect_reflog_cb collected;
+ int i;
+
+ memset(&collected, 0, sizeof(collected));
+ for_each_reflog(collect_reflog, &collected);
+ for (i = 0; i < collected.nr; i++) {
+ struct collected_reflog *e = collected.e[i];
+ status |= expire_reflog(e->reflog, e->sha1, 0, &cb);
+ free(e);
+ }
+ free(collected.e);
+ }
+
while (i < argc) {
const char *ref = argv[i++];
unsigned char sha1[20];
return status;
}
+static int count_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
+ const char *email, unsigned long timestamp, int tz,
+ const char *message, void *cb_data)
+{
+ struct cmd_reflog_expire_cb *cb = cb_data;
+ if (!cb->expire_total || timestamp < cb->expire_total)
+ cb->recno++;
+ return 0;
+}
+
+static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
+{
+ struct cmd_reflog_expire_cb cb;
+ int i, status = 0;
+
+ if (argc < 2)
+ return error("Nothing to delete?");
+
+ memset(&cb, 0, sizeof(cb));
+
+ for (i = 1; i < argc; i++) {
+ const char *spec = strstr(argv[i], "@{");
+ unsigned char sha1[20];
+ char *ep, *ref;
+ int recno;
+
+ if (!spec) {
+ status |= error("Not a reflog: %s", argv[i]);
+ continue;
+ }
+
+ if (!dwim_ref(argv[i], spec - argv[i], sha1, &ref)) {
+ status |= error("%s points nowhere!", argv[i]);
+ continue;
+ }
+
+ recno = strtoul(spec + 2, &ep, 10);
+ if (*ep == '}') {
+ cb.recno = -recno;
+ for_each_reflog_ent(ref, count_reflog_ent, &cb);
+ } else {
+ cb.expire_total = approxidate(spec + 2);
+ for_each_reflog_ent(ref, count_reflog_ent, &cb);
+ cb.expire_total = 0;
+ }
+
+ status |= expire_reflog(ref, sha1, 0, &cb);
+ free(ref);
+ }
+ return status;
+}
+
/*
* main "reflog"
*/
if (!strcmp(argv[1], "expire"))
return cmd_reflog_expire(argc - 1, argv + 1, prefix);
+ if (!strcmp(argv[1], "delete"))
+ return cmd_reflog_delete(argc - 1, argv + 1, prefix);
+
/* Not a recognized reflog command..*/
usage(reflog_usage);
}