#include "builtin.h" #include "config.h" #include "revision.h" #include "reachable.h" #include "worktree.h" #include "reflog.h" static const char reflog_exists_usage[] = N_("git reflog exists "); static timestamp_t default_reflog_expire; static timestamp_t default_reflog_expire_unreachable; struct worktree_reflogs { struct worktree *worktree; struct string_list reflogs; }; static int collect_reflog(const char *ref, const struct object_id *oid, int unused, void *cb_data) { struct worktree_reflogs *cb = cb_data; struct worktree *worktree = cb->worktree; struct strbuf newref = STRBUF_INIT; /* * Avoid collecting the same shared ref multiple times because * they are available via all worktrees. */ if (!worktree->is_current && ref_type(ref) == REF_TYPE_NORMAL) return 0; strbuf_worktree_ref(worktree, &newref, ref); string_list_append_nodup(&cb->reflogs, strbuf_detach(&newref, NULL)); return 0; } static struct reflog_expire_cfg { struct reflog_expire_cfg *next; timestamp_t expire_total; timestamp_t expire_unreachable; char pattern[FLEX_ARRAY]; } *reflog_expire_cfg, **reflog_expire_cfg_tail; static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len) { struct reflog_expire_cfg *ent; if (!reflog_expire_cfg_tail) reflog_expire_cfg_tail = &reflog_expire_cfg; for (ent = reflog_expire_cfg; ent; ent = ent->next) if (!strncmp(ent->pattern, pattern, len) && ent->pattern[len] == '\0') return ent; FLEX_ALLOC_MEM(ent, pattern, pattern, len); *reflog_expire_cfg_tail = ent; reflog_expire_cfg_tail = &(ent->next); return ent; } /* expiry timer slot */ #define EXPIRE_TOTAL 01 #define EXPIRE_UNREACH 02 static int reflog_expire_config(const char *var, const char *value, void *cb) { const char *pattern, *key; size_t pattern_len; timestamp_t expire; int slot; struct reflog_expire_cfg *ent; if (parse_config_key(var, "gc", &pattern, &pattern_len, &key) < 0) return git_default_config(var, value, cb); if (!strcmp(key, "reflogexpire")) { slot = EXPIRE_TOTAL; if (git_config_expiry_date(&expire, var, value)) return -1; } else if (!strcmp(key, "reflogexpireunreachable")) { slot = EXPIRE_UNREACH; if (git_config_expiry_date(&expire, var, value)) return -1; } else return git_default_config(var, value, cb); if (!pattern) { switch (slot) { case EXPIRE_TOTAL: default_reflog_expire = expire; break; case EXPIRE_UNREACH: default_reflog_expire_unreachable = expire; break; } return 0; } ent = find_cfg_ent(pattern, pattern_len); if (!ent) return -1; switch (slot) { case EXPIRE_TOTAL: ent->expire_total = expire; break; case EXPIRE_UNREACH: ent->expire_unreachable = expire; break; } return 0; } static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, const char *ref) { struct reflog_expire_cfg *ent; if (cb->explicit_expiry == (EXPIRE_TOTAL|EXPIRE_UNREACH)) return; /* both given explicitly -- nothing to tweak */ for (ent = reflog_expire_cfg; ent; ent = ent->next) { if (!wildmatch(ent->pattern, ref, 0)) { if (!(cb->explicit_expiry & EXPIRE_TOTAL)) cb->expire_total = ent->expire_total; if (!(cb->explicit_expiry & EXPIRE_UNREACH)) cb->expire_unreachable = ent->expire_unreachable; return; } } /* * If unconfigured, make stash never expire */ if (!strcmp(ref, "refs/stash")) { if (!(cb->explicit_expiry & EXPIRE_TOTAL)) cb->expire_total = 0; if (!(cb->explicit_expiry & EXPIRE_UNREACH)) cb->expire_unreachable = 0; return; } /* Nothing matched -- use the default value */ if (!(cb->explicit_expiry & EXPIRE_TOTAL)) cb->expire_total = default_reflog_expire; if (!(cb->explicit_expiry & EXPIRE_UNREACH)) cb->expire_unreachable = default_reflog_expire_unreachable; } static const char * reflog_expire_usage[] = { N_("git reflog expire [--expire=