15 static const char reflog_expire_usage[] =
16 "git reflog expire [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
17 static const char reflog_delete_usage[] =
18 "git reflog delete [--verbose] [--dry-run] [--rewrite] [--updateref] <refs>...";
20 static unsigned long default_reflog_expire;
21 static unsigned long default_reflog_expire_unreachable;
23 enum expire_reflog_flags {
24 EXPIRE_REFLOGS_DRY_RUN = 1 << 0
27 struct cmd_reflog_expire_cb {
33 unsigned long expire_total;
34 unsigned long expire_unreachable;
38 struct expire_reflog_cb {
44 } unreachable_expire_kind;
45 struct commit_list *mark_list;
46 unsigned long mark_limit;
47 struct cmd_reflog_expire_cb *cmd;
48 unsigned char last_kept_sha1[20];
49 struct commit *tip_commit;
50 struct commit_list *tips;
53 struct collected_reflog {
54 unsigned char sha1[20];
55 char reflog[FLEX_ARRAY];
57 struct collect_reflog_cb {
58 struct collected_reflog **e;
63 #define INCOMPLETE (1u<<10)
64 #define STUDYING (1u<<11)
65 #define REACHABLE (1u<<12)
67 static int tree_is_complete(const unsigned char *sha1)
69 struct tree_desc desc;
70 struct name_entry entry;
74 tree = lookup_tree(sha1);
77 if (tree->object.flags & SEEN)
79 if (tree->object.flags & INCOMPLETE)
83 enum object_type type;
85 void *data = read_sha1_file(sha1, &type, &size);
87 tree->object.flags |= INCOMPLETE;
93 init_tree_desc(&desc, tree->buffer, tree->size);
95 while (tree_entry(&desc, &entry)) {
96 if (!has_sha1_file(entry.sha1) ||
97 (S_ISDIR(entry.mode) && !tree_is_complete(entry.sha1))) {
98 tree->object.flags |= INCOMPLETE;
102 free_tree_buffer(tree);
105 tree->object.flags |= SEEN;
109 static int commit_is_complete(struct commit *commit)
111 struct object_array study;
112 struct object_array found;
113 int is_incomplete = 0;
117 if (commit->object.flags & SEEN)
119 if (commit->object.flags & INCOMPLETE)
122 * Find all commits that are reachable and are not marked as
123 * SEEN. Then make sure the trees and blobs contained are
124 * complete. After that, mark these commits also as SEEN.
125 * If some of the objects that are needed to complete this
126 * commit are missing, mark this commit as INCOMPLETE.
128 memset(&study, 0, sizeof(study));
129 memset(&found, 0, sizeof(found));
130 add_object_array(&commit->object, NULL, &study);
131 add_object_array(&commit->object, NULL, &found);
132 commit->object.flags |= STUDYING;
135 struct commit_list *parent;
137 c = (struct commit *)study.objects[--study.nr].item;
138 if (!c->object.parsed && !parse_object(c->object.sha1))
139 c->object.flags |= INCOMPLETE;
141 if (c->object.flags & INCOMPLETE) {
145 else if (c->object.flags & SEEN)
147 for (parent = c->parents; parent; parent = parent->next) {
148 struct commit *p = parent->item;
149 if (p->object.flags & STUDYING)
151 p->object.flags |= STUDYING;
152 add_object_array(&p->object, NULL, &study);
153 add_object_array(&p->object, NULL, &found);
156 if (!is_incomplete) {
158 * make sure all commits in "found" array have all the
161 for (i = 0; i < found.nr; i++) {
163 (struct commit *)found.objects[i].item;
164 if (!tree_is_complete(c->tree->object.sha1)) {
166 c->object.flags |= INCOMPLETE;
169 if (!is_incomplete) {
170 /* mark all found commits as complete, iow SEEN */
171 for (i = 0; i < found.nr; i++)
172 found.objects[i].item->flags |= SEEN;
175 /* clear flags from the objects we traversed */
176 for (i = 0; i < found.nr; i++)
177 found.objects[i].item->flags &= ~STUDYING;
179 commit->object.flags |= INCOMPLETE;
182 * If we come here, we have (1) traversed the ancestry chain
183 * from the "commit" until we reach SEEN commits (which are
184 * known to be complete), and (2) made sure that the commits
185 * encountered during the above traversal refer to trees that
186 * are complete. Which means that we know *all* the commits
187 * we have seen during this process are complete.
189 for (i = 0; i < found.nr; i++)
190 found.objects[i].item->flags |= SEEN;
192 /* free object arrays */
195 return !is_incomplete;
198 static int keep_entry(struct commit **it, unsigned char *sha1)
200 struct commit *commit;
202 if (is_null_sha1(sha1))
204 commit = lookup_commit_reference_gently(sha1, 1);
209 * Make sure everything in this commit exists.
211 * We have walked all the objects reachable from the refs
212 * and cache earlier. The commits reachable by this commit
213 * must meet SEEN commits -- and then we should mark them as
216 if (!commit_is_complete(commit))
223 * Starting from commits in the cb->mark_list, mark commits that are
224 * reachable from them. Stop the traversal at commits older than
225 * the expire_limit and queue them back, so that the caller can call
226 * us again to restart the traversal with longer expire_limit.
228 static void mark_reachable(struct expire_reflog_cb *cb)
230 struct commit *commit;
231 struct commit_list *pending;
232 unsigned long expire_limit = cb->mark_limit;
233 struct commit_list *leftover = NULL;
235 for (pending = cb->mark_list; pending; pending = pending->next)
236 pending->item->object.flags &= ~REACHABLE;
238 pending = cb->mark_list;
240 struct commit_list *entry = pending;
241 struct commit_list *parent;
242 pending = entry->next;
243 commit = entry->item;
245 if (commit->object.flags & REACHABLE)
247 if (parse_commit(commit))
249 commit->object.flags |= REACHABLE;
250 if (commit->date < expire_limit) {
251 commit_list_insert(commit, &leftover);
254 commit->object.flags |= REACHABLE;
255 parent = commit->parents;
257 commit = parent->item;
258 parent = parent->next;
259 if (commit->object.flags & REACHABLE)
261 commit_list_insert(commit, &pending);
264 cb->mark_list = leftover;
267 static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsigned char *sha1)
270 * We may or may not have the commit yet - if not, look it
271 * up using the supplied sha1.
274 if (is_null_sha1(sha1))
277 commit = lookup_commit_reference_gently(sha1, 1);
279 /* Not a commit -- keep it */
284 /* Reachable from the current ref? Don't prune. */
285 if (commit->object.flags & REACHABLE)
288 if (cb->mark_list && cb->mark_limit) {
289 cb->mark_limit = 0; /* dig down to the root */
293 return !(commit->object.flags & REACHABLE);
297 * Return true iff the specified reflog entry should be expired.
299 static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
300 const char *email, unsigned long timestamp, int tz,
301 const char *message, void *cb_data)
303 struct expire_reflog_cb *cb = cb_data;
304 struct commit *old, *new;
306 if (timestamp < cb->cmd->expire_total)
310 if (cb->cmd->stalefix &&
311 (!keep_entry(&old, osha1) || !keep_entry(&new, nsha1)))
314 if (timestamp < cb->cmd->expire_unreachable) {
315 if (cb->unreachable_expire_kind == UE_ALWAYS)
317 if (unreachable(cb, old, osha1) || unreachable(cb, new, nsha1))
321 if (cb->cmd->recno && --(cb->cmd->recno) == 0)
327 static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
328 const char *email, unsigned long timestamp, int tz,
329 const char *message, void *cb_data)
331 struct expire_reflog_cb *cb = cb_data;
333 if (cb->cmd->rewrite)
334 osha1 = cb->last_kept_sha1;
336 if (should_expire_reflog_ent(osha1, nsha1, email, timestamp, tz,
339 printf("would prune %s", message);
340 else if (cb->cmd->verbose)
341 printf("prune %s", message);
344 char sign = (tz < 0) ? '-' : '+';
345 int zone = (tz < 0) ? (-tz) : tz;
346 fprintf(cb->newlog, "%s %s %s %lu %c%04d\t%s",
347 sha1_to_hex(osha1), sha1_to_hex(nsha1),
348 email, timestamp, sign, zone,
350 hashcpy(cb->last_kept_sha1, nsha1);
352 if (cb->cmd->verbose)
353 printf("keep %s", message);
358 static int push_tip_to_list(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
360 struct commit_list **list = cb_data;
361 struct commit *tip_commit;
362 if (flags & REF_ISSYMREF)
364 tip_commit = lookup_commit_reference_gently(sha1, 1);
367 commit_list_insert(tip_commit, list);
371 static void reflog_expiry_prepare(const char *refname,
372 const unsigned char *sha1,
373 struct expire_reflog_cb *cb)
375 if (!cb->cmd->expire_unreachable || !strcmp(refname, "HEAD")) {
376 cb->tip_commit = NULL;
377 cb->unreachable_expire_kind = UE_HEAD;
379 cb->tip_commit = lookup_commit_reference_gently(sha1, 1);
381 cb->unreachable_expire_kind = UE_ALWAYS;
383 cb->unreachable_expire_kind = UE_NORMAL;
386 if (cb->cmd->expire_unreachable <= cb->cmd->expire_total)
387 cb->unreachable_expire_kind = UE_ALWAYS;
389 cb->mark_list = NULL;
391 if (cb->unreachable_expire_kind != UE_ALWAYS) {
392 if (cb->unreachable_expire_kind == UE_HEAD) {
393 struct commit_list *elem;
394 for_each_ref(push_tip_to_list, &cb->tips);
395 for (elem = cb->tips; elem; elem = elem->next)
396 commit_list_insert(elem->item, &cb->mark_list);
398 commit_list_insert(cb->tip_commit, &cb->mark_list);
400 cb->mark_limit = cb->cmd->expire_total;
405 static void reflog_expiry_cleanup(struct expire_reflog_cb *cb)
407 if (cb->unreachable_expire_kind != UE_ALWAYS) {
408 if (cb->unreachable_expire_kind == UE_HEAD) {
409 struct commit_list *elem;
410 for (elem = cb->tips; elem; elem = elem->next)
411 clear_commit_marks(elem->item, REACHABLE);
412 free_commit_list(cb->tips);
414 clear_commit_marks(cb->tip_commit, REACHABLE);
419 static int expire_reflog(const char *refname, const unsigned char *sha1,
420 unsigned int flags, struct cmd_reflog_expire_cb *cmd)
422 static struct lock_file reflog_lock;
423 struct expire_reflog_cb cb;
424 struct ref_lock *lock;
428 memset(&cb, 0, sizeof(cb));
431 * The reflog file is locked by holding the lock on the
432 * reference itself, plus we might need to update the
433 * reference if --updateref was specified:
435 lock = lock_any_ref_for_update(refname, sha1, 0, NULL);
437 return error("cannot lock ref '%s'", refname);
438 if (!reflog_exists(refname)) {
443 log_file = git_pathdup("logs/%s", refname);
444 if (!(flags & EXPIRE_REFLOGS_DRY_RUN)) {
446 * Even though holding $GIT_DIR/logs/$reflog.lock has
447 * no locking implications, we use the lock_file
448 * machinery here anyway because it does a lot of the
449 * work we need, including cleaning up if the program
450 * exits unexpectedly.
452 if (hold_lock_file_for_update(&reflog_lock, log_file, 0) < 0) {
453 struct strbuf err = STRBUF_INIT;
454 unable_to_lock_message(log_file, errno, &err);
455 error("%s", err.buf);
456 strbuf_release(&err);
459 cb.newlog = fdopen_lock_file(&reflog_lock, "w");
461 error("cannot fdopen %s (%s)",
462 reflog_lock.filename.buf, strerror(errno));
469 reflog_expiry_prepare(refname, sha1, &cb);
470 for_each_reflog_ent(refname, expire_reflog_ent, &cb);
471 reflog_expiry_cleanup(&cb);
473 if (!(flags & EXPIRE_REFLOGS_DRY_RUN)) {
474 if (close_lock_file(&reflog_lock)) {
475 status |= error("couldn't write %s: %s", log_file,
477 } else if (cmd->updateref &&
478 (write_in_full(lock->lock_fd,
479 sha1_to_hex(cb.last_kept_sha1), 40) != 40 ||
480 write_str_in_full(lock->lock_fd, "\n") != 1 ||
481 close_ref(lock) < 0)) {
482 status |= error("couldn't write %s",
483 lock->lk->filename.buf);
484 rollback_lock_file(&reflog_lock);
485 } else if (commit_lock_file(&reflog_lock)) {
486 status |= error("unable to commit reflog '%s' (%s)",
487 log_file, strerror(errno));
488 } else if (cmd->updateref && commit_ref(lock)) {
489 status |= error("couldn't set %s", lock->ref_name);
497 rollback_lock_file(&reflog_lock);
503 static int collect_reflog(const char *ref, const unsigned char *sha1, int unused, void *cb_data)
505 struct collected_reflog *e;
506 struct collect_reflog_cb *cb = cb_data;
507 size_t namelen = strlen(ref);
509 e = xmalloc(sizeof(*e) + namelen + 1);
510 hashcpy(e->sha1, sha1);
511 memcpy(e->reflog, ref, namelen + 1);
512 ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);
517 static struct reflog_expire_cfg {
518 struct reflog_expire_cfg *next;
519 unsigned long expire_total;
520 unsigned long expire_unreachable;
522 char pattern[FLEX_ARRAY];
523 } *reflog_expire_cfg, **reflog_expire_cfg_tail;
525 static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)
527 struct reflog_expire_cfg *ent;
529 if (!reflog_expire_cfg_tail)
530 reflog_expire_cfg_tail = &reflog_expire_cfg;
532 for (ent = reflog_expire_cfg; ent; ent = ent->next)
533 if (ent->len == len &&
534 !memcmp(ent->pattern, pattern, len))
537 ent = xcalloc(1, (sizeof(*ent) + len));
538 memcpy(ent->pattern, pattern, len);
540 *reflog_expire_cfg_tail = ent;
541 reflog_expire_cfg_tail = &(ent->next);
545 static int parse_expire_cfg_value(const char *var, const char *value, unsigned long *expire)
548 return config_error_nonbool(var);
549 if (parse_expiry_date(value, expire))
550 return error(_("%s' for '%s' is not a valid timestamp"),
555 /* expiry timer slot */
556 #define EXPIRE_TOTAL 01
557 #define EXPIRE_UNREACH 02
559 static int reflog_expire_config(const char *var, const char *value, void *cb)
561 const char *pattern, *key;
563 unsigned long expire;
565 struct reflog_expire_cfg *ent;
567 if (parse_config_key(var, "gc", &pattern, &pattern_len, &key) < 0)
568 return git_default_config(var, value, cb);
570 if (!strcmp(key, "reflogexpire")) {
572 if (parse_expire_cfg_value(var, value, &expire))
574 } else if (!strcmp(key, "reflogexpireunreachable")) {
575 slot = EXPIRE_UNREACH;
576 if (parse_expire_cfg_value(var, value, &expire))
579 return git_default_config(var, value, cb);
584 default_reflog_expire = expire;
587 default_reflog_expire_unreachable = expire;
593 ent = find_cfg_ent(pattern, pattern_len);
598 ent->expire_total = expire;
601 ent->expire_unreachable = expire;
607 static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, const char *ref)
609 struct reflog_expire_cfg *ent;
611 if (slot == (EXPIRE_TOTAL|EXPIRE_UNREACH))
612 return; /* both given explicitly -- nothing to tweak */
614 for (ent = reflog_expire_cfg; ent; ent = ent->next) {
615 if (!wildmatch(ent->pattern, ref, 0, NULL)) {
616 if (!(slot & EXPIRE_TOTAL))
617 cb->expire_total = ent->expire_total;
618 if (!(slot & EXPIRE_UNREACH))
619 cb->expire_unreachable = ent->expire_unreachable;
625 * If unconfigured, make stash never expire
627 if (!strcmp(ref, "refs/stash")) {
628 if (!(slot & EXPIRE_TOTAL))
629 cb->expire_total = 0;
630 if (!(slot & EXPIRE_UNREACH))
631 cb->expire_unreachable = 0;
635 /* Nothing matched -- use the default value */
636 if (!(slot & EXPIRE_TOTAL))
637 cb->expire_total = default_reflog_expire;
638 if (!(slot & EXPIRE_UNREACH))
639 cb->expire_unreachable = default_reflog_expire_unreachable;
642 static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
644 struct cmd_reflog_expire_cb cb;
645 unsigned long now = time(NULL);
646 int i, status, do_all;
647 int explicit_expiry = 0;
648 unsigned int flags = 0;
650 default_reflog_expire_unreachable = now - 30 * 24 * 3600;
651 default_reflog_expire = now - 90 * 24 * 3600;
652 git_config(reflog_expire_config, NULL);
654 save_commit_buffer = 0;
656 memset(&cb, 0, sizeof(cb));
658 cb.expire_total = default_reflog_expire;
659 cb.expire_unreachable = default_reflog_expire_unreachable;
661 for (i = 1; i < argc; i++) {
662 const char *arg = argv[i];
663 if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
664 flags |= EXPIRE_REFLOGS_DRY_RUN;
665 else if (starts_with(arg, "--expire=")) {
666 if (parse_expiry_date(arg + 9, &cb.expire_total))
667 die(_("'%s' is not a valid timestamp"), arg);
668 explicit_expiry |= EXPIRE_TOTAL;
670 else if (starts_with(arg, "--expire-unreachable=")) {
671 if (parse_expiry_date(arg + 21, &cb.expire_unreachable))
672 die(_("'%s' is not a valid timestamp"), arg);
673 explicit_expiry |= EXPIRE_UNREACH;
675 else if (!strcmp(arg, "--stale-fix"))
677 else if (!strcmp(arg, "--rewrite"))
679 else if (!strcmp(arg, "--updateref"))
681 else if (!strcmp(arg, "--all"))
683 else if (!strcmp(arg, "--verbose"))
685 else if (!strcmp(arg, "--")) {
689 else if (arg[0] == '-')
690 usage(reflog_expire_usage);
696 * We can trust the commits and objects reachable from refs
697 * even in older repository. We cannot trust what's reachable
698 * from reflog if the repository was pruned with older git.
701 init_revisions(&cb.revs, prefix);
703 printf("Marking reachable objects...");
704 mark_reachable_objects(&cb.revs, 0, 0, NULL);
710 struct collect_reflog_cb collected;
713 memset(&collected, 0, sizeof(collected));
714 for_each_reflog(collect_reflog, &collected);
715 for (i = 0; i < collected.nr; i++) {
716 struct collected_reflog *e = collected.e[i];
717 set_reflog_expiry_param(&cb, explicit_expiry, e->reflog);
718 status |= expire_reflog(e->reflog, e->sha1, flags, &cb);
724 for (; i < argc; i++) {
726 unsigned char sha1[20];
727 if (!dwim_log(argv[i], strlen(argv[i]), sha1, &ref)) {
728 status |= error("%s points nowhere!", argv[i]);
731 set_reflog_expiry_param(&cb, explicit_expiry, ref);
732 status |= expire_reflog(ref, sha1, flags, &cb);
737 static int count_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
738 const char *email, unsigned long timestamp, int tz,
739 const char *message, void *cb_data)
741 struct cmd_reflog_expire_cb *cb = cb_data;
742 if (!cb->expire_total || timestamp < cb->expire_total)
747 static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
749 struct cmd_reflog_expire_cb cb;
751 unsigned int flags = 0;
753 memset(&cb, 0, sizeof(cb));
755 for (i = 1; i < argc; i++) {
756 const char *arg = argv[i];
757 if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
758 flags |= EXPIRE_REFLOGS_DRY_RUN;
759 else if (!strcmp(arg, "--rewrite"))
761 else if (!strcmp(arg, "--updateref"))
763 else if (!strcmp(arg, "--verbose"))
765 else if (!strcmp(arg, "--")) {
769 else if (arg[0] == '-')
770 usage(reflog_delete_usage);
776 return error("Nothing to delete?");
778 for ( ; i < argc; i++) {
779 const char *spec = strstr(argv[i], "@{");
780 unsigned char sha1[20];
785 status |= error("Not a reflog: %s", argv[i]);
789 if (!dwim_log(argv[i], spec - argv[i], sha1, &ref)) {
790 status |= error("no reflog for '%s'", argv[i]);
794 recno = strtoul(spec + 2, &ep, 10);
797 for_each_reflog_ent(ref, count_reflog_ent, &cb);
799 cb.expire_total = approxidate(spec + 2);
800 for_each_reflog_ent(ref, count_reflog_ent, &cb);
804 status |= expire_reflog(ref, sha1, flags, &cb);
814 static const char reflog_usage[] =
815 "git reflog [ show | expire | delete ]";
817 int cmd_reflog(int argc, const char **argv, const char *prefix)
819 if (argc > 1 && !strcmp(argv[1], "-h"))
822 /* With no command, we default to showing it. */
823 if (argc < 2 || *argv[1] == '-')
824 return cmd_log_reflog(argc, argv, prefix);
826 if (!strcmp(argv[1], "show"))
827 return cmd_log_reflog(argc - 1, argv + 1, prefix);
829 if (!strcmp(argv[1], "expire"))
830 return cmd_reflog_expire(argc - 1, argv + 1, prefix);
832 if (!strcmp(argv[1], "delete"))
833 return cmd_reflog_delete(argc - 1, argv + 1, prefix);
835 return cmd_log_reflog(argc, argv, prefix);