*/
static const char reflog_expire_usage[] =
-"git-reflog expire [--verbose] [--dry-run] [--fix-stale] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
+"git-reflog expire [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
static unsigned long default_reflog_expire;
static unsigned long default_reflog_expire_unreachable;
struct cmd_reflog_expire_cb *cmd;
};
+#define INCOMPLETE (1u<<10)
+#define STUDYING (1u<<11)
+
static int tree_is_complete(const unsigned char *sha1)
{
struct tree_desc desc;
- void *buf;
- char type[20];
+ struct name_entry entry;
+ int complete;
+ struct tree *tree;
- buf = read_sha1_file(sha1, type, &desc.size);
- if (!buf)
+ tree = lookup_tree(sha1);
+ if (!tree)
+ return 0;
+ if (tree->object.flags & SEEN)
+ return 1;
+ if (tree->object.flags & INCOMPLETE)
return 0;
- desc.buf = buf;
- while (desc.size) {
- const unsigned char *elem;
- const char *name;
- unsigned mode;
-
- elem = tree_entry_extract(&desc, &name, &mode);
- if (!has_sha1_file(elem) ||
- (S_ISDIR(mode) && !tree_is_complete(elem))) {
- free(buf);
+
+ desc.buf = tree->buffer;
+ desc.size = tree->size;
+ if (!desc.buf) {
+ char type[20];
+ void *data = read_sha1_file(sha1, type, &desc.size);
+ if (!data) {
+ tree->object.flags |= INCOMPLETE;
return 0;
}
- update_tree_entry(&desc);
+ desc.buf = data;
+ tree->buffer = data;
}
- free(buf);
- return 1;
-}
+ complete = 1;
+ while (tree_entry(&desc, &entry)) {
+ if (!has_sha1_file(entry.sha1) ||
+ (S_ISDIR(entry.mode) && !tree_is_complete(entry.sha1))) {
+ tree->object.flags |= INCOMPLETE;
+ complete = 0;
+ }
+ }
+ free(tree->buffer);
+ tree->buffer = NULL;
-#define INCOMPLETE (1u<<10)
-#define STUDYING (1u<<11)
+ if (complete)
+ tree->object.flags |= SEEN;
+ return complete;
+}
static int commit_is_complete(struct commit *commit)
{
}
}
if (!is_incomplete) {
- /* make sure all commits in found have all the
+ /*
+ * make sure all commits in "found" array have all the
* necessary objects.
*/
- for (i = 0; !is_incomplete && i < found.nr; i++) {
+ for (i = 0; i < found.nr; i++) {
struct commit *c =
(struct commit *)found.objects[i].item;
- if (!tree_is_complete(c->tree->object.sha1))
+ if (!tree_is_complete(c->tree->object.sha1)) {
is_incomplete = 1;
+ c->object.flags |= INCOMPLETE;
+ }
}
if (!is_incomplete) {
/* mark all found commits as complete, iow SEEN */
found.objects[i].item->flags &= ~STUDYING;
if (is_incomplete)
commit->object.flags |= INCOMPLETE;
+ else {
+ /*
+ * If we come here, we have (1) traversed the ancestry chain
+ * from the "commit" until we reach SEEN commits (which are
+ * known to be complete), and (2) made sure that the commits
+ * encountered during the above traversal refer to trees that
+ * are complete. Which means that we know *all* the commits
+ * we have seen during this process are complete.
+ */
+ for (i = 0; i < found.nr; i++)
+ found.objects[i].item->flags |= SEEN;
+ }
/* free object arrays */
free(study.objects);
free(found.objects);
{
struct commit *commit;
- *it = NULL;
if (is_null_sha1(sha1))
return 1;
commit = lookup_commit_reference_gently(sha1, 1);
}
static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
- char *data, void *cb_data)
+ const char *email, unsigned long timestamp, int tz,
+ const char *message, void *cb_data)
{
struct expire_reflog_cb *cb = cb_data;
- unsigned long timestamp;
- char *cp, *ep;
struct commit *old, *new;
- cp = strchr(data, '>');
- if (!cp || *++cp != ' ')
- goto prune;
- timestamp = strtoul(cp, &ep, 10);
- if (*ep != ' ')
- goto prune;
if (timestamp < cb->cmd->expire_total)
goto prune;
+ old = new = NULL;
if (cb->cmd->stalefix &&
(!keep_entry(&old, osha1) || !keep_entry(&new, nsha1)))
goto prune;
- if ((timestamp < cb->cmd->expire_unreachable) &&
- (!cb->ref_commit ||
- (old && !in_merge_bases(old, cb->ref_commit)) ||
- (new && !in_merge_bases(new, cb->ref_commit))))
- goto prune;
+ 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)) ||
+ (new && !in_merge_bases(new, cb->ref_commit)))
+ goto prune;
+ }
- if (cb->newlog)
- fprintf(cb->newlog, "%s %s %s",
- sha1_to_hex(osha1), sha1_to_hex(nsha1), data);
+ 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);
+ }
if (cb->cmd->verbose)
- printf("keep %s", data);
+ printf("keep %s", message);
return 0;
prune:
if (!cb->newlog || cb->cmd->verbose)
- printf("%sprune %s", cb->newlog ? "" : "would ", data);
+ printf("%sprune %s", cb->newlog ? "" : "would ", message);
return 0;
}
}
cb.ref_commit = lookup_commit_reference_gently(sha1, 1);
- if (!cb.ref_commit)
- fprintf(stderr,
- "warning: ref '%s' does not point at a commit\n", ref);
cb.ref = ref;
cb.cmd = cmd;
for_each_reflog_ent(ref, expire_reflog_ent, &cb);