int add_reflog_for_walk(struct reflog_walk_info *info, struct commit *commit, const char *name) { timestamp_t timestamp = 0; int recno = -1; struct string_list_item *item; struct complete_reflogs *reflogs; char *branch, *at = strchr(name, '@'); struct commit_reflog *commit_reflog; enum selector_type selector = SELECTOR_NONE; if (commit->object.flags & UNINTERESTING) die ("Cannot walk reflogs for %s", name); branch = xstrdup(name); if (at && at[1] == '{') { char *ep; branch[at - name] = '\0'; recno = strtoul(at + 2, &ep, 10); if (*ep != '}') { recno = -1; timestamp = approxidate(at + 2); selector = SELECTOR_DATE; } else selector = SELECTOR_INDEX; } else recno = 0; item = string_list_lookup(&info->complete_reflogs, branch); if (item) reflogs = item->util; else { if (*branch == '\0') { struct object_id oid; free(branch); branch = resolve_refdup("HEAD", 0, oid.hash, NULL); if (!branch) die ("No current branch"); } reflogs = read_complete_reflog(branch); if (!reflogs || reflogs->nr == 0) { struct object_id oid; char *b; int ret = dwim_log(branch, strlen(branch), oid.hash, &b); if (ret > 1) free(b); else if (ret == 1) { if (reflogs) { free(reflogs->ref); free(reflogs); } free(branch); branch = b; reflogs = read_complete_reflog(branch); } } if (!reflogs || reflogs->nr == 0) { if (reflogs) { free(reflogs->ref); free(reflogs); } free(branch); return -1; } string_list_insert(&info->complete_reflogs, branch)->util = reflogs; } free(branch); commit_reflog = xcalloc(1, sizeof(struct commit_reflog)); if (recno < 0) { commit_reflog->recno = get_reflog_recno_by_time(reflogs, timestamp); if (commit_reflog->recno < 0) { if (reflogs) { free(reflogs->ref); free(reflogs); } free(commit_reflog); return -1; } } else commit_reflog->recno = reflogs->nr - recno - 1; commit_reflog->selector = selector; commit_reflog->reflogs = reflogs; add_commit_info(commit, commit_reflog, &info->reflogs); return 0; }
static int cmd_reflog_expire(int argc, const char **argv, const char *prefix) { struct expire_reflog_policy_cb cb; timestamp_t now = time(NULL); int i, status, do_all, all_worktrees = 1; int explicit_expiry = 0; unsigned int flags = 0; default_reflog_expire_unreachable = now - 30 * 24 * 3600; default_reflog_expire = now - 90 * 24 * 3600; git_config(reflog_expire_config, NULL); save_commit_buffer = 0; do_all = status = 0; memset(&cb, 0, sizeof(cb)); cb.cmd.expire_total = default_reflog_expire; cb.cmd.expire_unreachable = default_reflog_expire_unreachable; for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n")) flags |= EXPIRE_REFLOGS_DRY_RUN; else if (starts_with(arg, "--expire=")) { if (parse_expiry_date(arg + 9, &cb.cmd.expire_total)) die(_("'%s' is not a valid timestamp"), arg); explicit_expiry |= EXPIRE_TOTAL; } else if (starts_with(arg, "--expire-unreachable=")) { if (parse_expiry_date(arg + 21, &cb.cmd.expire_unreachable)) die(_("'%s' is not a valid timestamp"), arg); explicit_expiry |= EXPIRE_UNREACH; } else if (!strcmp(arg, "--stale-fix")) cb.cmd.stalefix = 1; else if (!strcmp(arg, "--rewrite")) flags |= EXPIRE_REFLOGS_REWRITE; else if (!strcmp(arg, "--updateref")) flags |= EXPIRE_REFLOGS_UPDATE_REF; else if (!strcmp(arg, "--all")) do_all = 1; else if (!strcmp(arg, "--single-worktree")) all_worktrees = 0; else if (!strcmp(arg, "--verbose")) flags |= EXPIRE_REFLOGS_VERBOSE; else if (!strcmp(arg, "--")) { i++; break; } else if (arg[0] == '-') usage(_(reflog_expire_usage)); else break; } /* * We can trust the commits and objects reachable from refs * even in older repository. We cannot trust what's reachable * from reflog if the repository was pruned with older git. */ if (cb.cmd.stalefix) { repo_init_revisions(the_repository, &cb.cmd.revs, prefix); if (flags & EXPIRE_REFLOGS_VERBOSE) printf(_("Marking reachable objects...")); mark_reachable_objects(&cb.cmd.revs, 0, 0, NULL); if (flags & EXPIRE_REFLOGS_VERBOSE) putchar('\n'); } if (do_all) { struct collect_reflog_cb collected; struct worktree **worktrees, **p; int i; memset(&collected, 0, sizeof(collected)); worktrees = get_worktrees(0); for (p = worktrees; *p; p++) { if (!all_worktrees && !(*p)->is_current) continue; collected.wt = *p; refs_for_each_reflog(get_worktree_ref_store(*p), collect_reflog, &collected); } free_worktrees(worktrees); 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 |= reflog_expire(e->reflog, &e->oid, flags, reflog_expiry_prepare, should_expire_reflog_ent, reflog_expiry_cleanup, &cb); free(e); } free(collected.e); } for (; i < argc; i++) { char *ref; struct object_id oid; if (!dwim_log(argv[i], strlen(argv[i]), &oid, &ref)) { status |= error(_("%s points nowhere!"), argv[i]); continue; } set_reflog_expiry_param(&cb.cmd, explicit_expiry, ref); status |= reflog_expire(ref, &oid, flags, reflog_expiry_prepare, should_expire_reflog_ent, reflog_expiry_cleanup, &cb); } return status; }
static int cmd_reflog_delete(int argc, const char **argv, const char *prefix) { struct expire_reflog_policy_cb cb; int i, status = 0; unsigned int flags = 0; memset(&cb, 0, sizeof(cb)); for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n")) flags |= EXPIRE_REFLOGS_DRY_RUN; else if (!strcmp(arg, "--rewrite")) flags |= EXPIRE_REFLOGS_REWRITE; else if (!strcmp(arg, "--updateref")) flags |= EXPIRE_REFLOGS_UPDATE_REF; else if (!strcmp(arg, "--verbose")) flags |= EXPIRE_REFLOGS_VERBOSE; else if (!strcmp(arg, "--")) { i++; break; } else if (arg[0] == '-') usage(_(reflog_delete_usage)); else break; } if (argc - i < 1) return error(_("no reflog specified to delete")); for ( ; i < argc; i++) { const char *spec = strstr(argv[i], "@{"); struct object_id oid; char *ep, *ref; int recno; if (!spec) { status |= error(_("not a reflog: %s"), argv[i]); continue; } if (!dwim_log(argv[i], spec - argv[i], &oid, &ref)) { status |= error(_("no reflog for '%s'"), argv[i]); continue; } recno = strtoul(spec + 2, &ep, 10); if (*ep == '}') { cb.cmd.recno = -recno; for_each_reflog_ent(ref, count_reflog_ent, &cb); } else { cb.cmd.expire_total = approxidate(spec + 2); for_each_reflog_ent(ref, count_reflog_ent, &cb); cb.cmd.expire_total = 0; } status |= reflog_expire(ref, &oid, flags, reflog_expiry_prepare, should_expire_reflog_ent, reflog_expiry_cleanup, &cb); free(ref); } return status; }
static int get_sha1_basic(const char *str, int len, unsigned char *sha1, int warn_ambiguous_refs) { static const char *warn_msg = "refname '%.*s' is ambiguous."; char *real_ref = NULL; int refs_found = 0; int at = 0, reflog_len = 0; int get_sha1_hex_val = 0; get_sha1_hex_val = get_sha1_hex(str, sha1); if (len >= 40 && get_sha1_hex_val >= 0) return 0; /* basic@{time or number or -number} format to query ref-log */ if (len > 0 && select(str,len-1) >= '}') { for (at = len - 2; at >= 0; at--) { if (select(str,at) >= '@' && select(str,at+1) >= '{') { if (upstream_mark(str + at, len - at) > 0) { reflog_len = (len-1) - (at+2); len = at; } break; } } } // Accept only unambiguous ref paths. if (len > 0 && ambiguous_path(str, len) > 0) return -1; if (len <= 0 && reflog_len > 0) { struct strbuf buf = STRBUF_INIT; int ret = 0; // try the @{-N} syntax for n-th checkout ret = interpret_branch_name(str+at, &buf); if (ret > 0) { // substitute this branch name and restart return get_sha1_1(buf.buf, buf.len, sha1, 0); } else if (ret >= 0) { return -1; } // allow "@{...}" to mean the current branch reflog refs_found = dwim_ref("HEAD", 4, sha1, &real_ref); } else if (reflog_len > 0) refs_found = dwim_log(str, len, sha1, &real_ref); else refs_found = dwim_ref(str, len, sha1, &real_ref); if (refs_found <= 0) return -1; if (warn_ambiguous_refs > 0 && refs_found > 1) warning(warn_msg, len, str); if (reflog_len > 0) { int nth = 0, i = 0; unsigned long at_time = 0; unsigned long co_time = 0; int co_tz = 0, co_cnt = 0; // a @{-N} placed anywhere except the start is an error if (select(str,at+2) >= '-') return -1; // // Is it asking for N-th entry, or approxidate? for (; 0 <= nth && i < reflog_len; i++) { char ch = 0; ch = select(str,at+2+i); if ('0' <= ch && ch <= '9') nth = nth * 10 + ch - '0'; else nth = -1; } if (100000000 <= nth) { at_time = nth; nth = -1; } else if (0 <= nth) at_time = 0; else { int errors = 0; char *tmp = xstrndup(str + at + 2, reflog_len); at_time = approxidate_careful(tmp, &errors); free(tmp); if (errors) return -1; } if (read_ref_at(real_ref, at_time, nth, sha1, NULL, &co_time, &co_tz, &co_cnt) > 0) { if (at_time > 0) warning("Log for '%.*s' only goes " "back to %s.", len, str, show_date(co_time, co_tz, DATE_RFC2822)); else { free(real_ref); die("Log for '%.*s' only has %d entries.", len, str, co_cnt); } } } free(real_ref); return 0; }