reflog.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. #include "builtin.h"
  2. #include "config.h"
  3. #include "lockfile.h"
  4. #include "object-store.h"
  5. #include "repository.h"
  6. #include "commit.h"
  7. #include "refs.h"
  8. #include "dir.h"
  9. #include "tree-walk.h"
  10. #include "diff.h"
  11. #include "revision.h"
  12. #include "reachable.h"
  13. #include "worktree.h"
  14. /* NEEDSWORK: switch to using parse_options */
  15. static const char reflog_expire_usage[] =
  16. N_("git reflog expire [--expire=<time>] "
  17. "[--expire-unreachable=<time>] "
  18. "[--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] "
  19. "[--verbose] [--all] <refs>...");
  20. static const char reflog_delete_usage[] =
  21. N_("git reflog delete [--rewrite] [--updateref] "
  22. "[--dry-run | -n] [--verbose] <refs>...");
  23. static const char reflog_exists_usage[] =
  24. N_("git reflog exists <ref>");
  25. static timestamp_t default_reflog_expire;
  26. static timestamp_t default_reflog_expire_unreachable;
  27. struct cmd_reflog_expire_cb {
  28. struct rev_info revs;
  29. int stalefix;
  30. timestamp_t expire_total;
  31. timestamp_t expire_unreachable;
  32. int recno;
  33. };
  34. struct expire_reflog_policy_cb {
  35. enum {
  36. UE_NORMAL,
  37. UE_ALWAYS,
  38. UE_HEAD
  39. } unreachable_expire_kind;
  40. struct commit_list *mark_list;
  41. unsigned long mark_limit;
  42. struct cmd_reflog_expire_cb cmd;
  43. struct commit *tip_commit;
  44. struct commit_list *tips;
  45. };
  46. struct collected_reflog {
  47. struct object_id oid;
  48. char reflog[FLEX_ARRAY];
  49. };
  50. struct collect_reflog_cb {
  51. struct collected_reflog **e;
  52. int alloc;
  53. int nr;
  54. struct worktree *wt;
  55. };
  56. /* Remember to update object flag allocation in object.h */
  57. #define INCOMPLETE (1u<<10)
  58. #define STUDYING (1u<<11)
  59. #define REACHABLE (1u<<12)
  60. static int tree_is_complete(const struct object_id *oid)
  61. {
  62. struct tree_desc desc;
  63. struct name_entry entry;
  64. int complete;
  65. struct tree *tree;
  66. tree = lookup_tree(the_repository, oid);
  67. if (!tree)
  68. return 0;
  69. if (tree->object.flags & SEEN)
  70. return 1;
  71. if (tree->object.flags & INCOMPLETE)
  72. return 0;
  73. if (!tree->buffer) {
  74. enum object_type type;
  75. unsigned long size;
  76. void *data = read_object_file(oid, &type, &size);
  77. if (!data) {
  78. tree->object.flags |= INCOMPLETE;
  79. return 0;
  80. }
  81. tree->buffer = data;
  82. tree->size = size;
  83. }
  84. init_tree_desc(&desc, tree->buffer, tree->size);
  85. complete = 1;
  86. while (tree_entry(&desc, &entry)) {
  87. if (!has_object_file(&entry.oid) ||
  88. (S_ISDIR(entry.mode) && !tree_is_complete(&entry.oid))) {
  89. tree->object.flags |= INCOMPLETE;
  90. complete = 0;
  91. }
  92. }
  93. free_tree_buffer(tree);
  94. if (complete)
  95. tree->object.flags |= SEEN;
  96. return complete;
  97. }
  98. static int commit_is_complete(struct commit *commit)
  99. {
  100. struct object_array study;
  101. struct object_array found;
  102. int is_incomplete = 0;
  103. int i;
  104. /* early return */
  105. if (commit->object.flags & SEEN)
  106. return 1;
  107. if (commit->object.flags & INCOMPLETE)
  108. return 0;
  109. /*
  110. * Find all commits that are reachable and are not marked as
  111. * SEEN. Then make sure the trees and blobs contained are
  112. * complete. After that, mark these commits also as SEEN.
  113. * If some of the objects that are needed to complete this
  114. * commit are missing, mark this commit as INCOMPLETE.
  115. */
  116. memset(&study, 0, sizeof(study));
  117. memset(&found, 0, sizeof(found));
  118. add_object_array(&commit->object, NULL, &study);
  119. add_object_array(&commit->object, NULL, &found);
  120. commit->object.flags |= STUDYING;
  121. while (study.nr) {
  122. struct commit *c;
  123. struct commit_list *parent;
  124. c = (struct commit *)object_array_pop(&study);
  125. if (!c->object.parsed && !parse_object(the_repository, &c->object.oid))
  126. c->object.flags |= INCOMPLETE;
  127. if (c->object.flags & INCOMPLETE) {
  128. is_incomplete = 1;
  129. break;
  130. }
  131. else if (c->object.flags & SEEN)
  132. continue;
  133. for (parent = c->parents; parent; parent = parent->next) {
  134. struct commit *p = parent->item;
  135. if (p->object.flags & STUDYING)
  136. continue;
  137. p->object.flags |= STUDYING;
  138. add_object_array(&p->object, NULL, &study);
  139. add_object_array(&p->object, NULL, &found);
  140. }
  141. }
  142. if (!is_incomplete) {
  143. /*
  144. * make sure all commits in "found" array have all the
  145. * necessary objects.
  146. */
  147. for (i = 0; i < found.nr; i++) {
  148. struct commit *c =
  149. (struct commit *)found.objects[i].item;
  150. if (!tree_is_complete(get_commit_tree_oid(c))) {
  151. is_incomplete = 1;
  152. c->object.flags |= INCOMPLETE;
  153. }
  154. }
  155. if (!is_incomplete) {
  156. /* mark all found commits as complete, iow SEEN */
  157. for (i = 0; i < found.nr; i++)
  158. found.objects[i].item->flags |= SEEN;
  159. }
  160. }
  161. /* clear flags from the objects we traversed */
  162. for (i = 0; i < found.nr; i++)
  163. found.objects[i].item->flags &= ~STUDYING;
  164. if (is_incomplete)
  165. commit->object.flags |= INCOMPLETE;
  166. else {
  167. /*
  168. * If we come here, we have (1) traversed the ancestry chain
  169. * from the "commit" until we reach SEEN commits (which are
  170. * known to be complete), and (2) made sure that the commits
  171. * encountered during the above traversal refer to trees that
  172. * are complete. Which means that we know *all* the commits
  173. * we have seen during this process are complete.
  174. */
  175. for (i = 0; i < found.nr; i++)
  176. found.objects[i].item->flags |= SEEN;
  177. }
  178. /* free object arrays */
  179. object_array_clear(&study);
  180. object_array_clear(&found);
  181. return !is_incomplete;
  182. }
  183. static int keep_entry(struct commit **it, struct object_id *oid)
  184. {
  185. struct commit *commit;
  186. if (is_null_oid(oid))
  187. return 1;
  188. commit = lookup_commit_reference_gently(the_repository, oid, 1);
  189. if (!commit)
  190. return 0;
  191. /*
  192. * Make sure everything in this commit exists.
  193. *
  194. * We have walked all the objects reachable from the refs
  195. * and cache earlier. The commits reachable by this commit
  196. * must meet SEEN commits -- and then we should mark them as
  197. * SEEN as well.
  198. */
  199. if (!commit_is_complete(commit))
  200. return 0;
  201. *it = commit;
  202. return 1;
  203. }
  204. /*
  205. * Starting from commits in the cb->mark_list, mark commits that are
  206. * reachable from them. Stop the traversal at commits older than
  207. * the expire_limit and queue them back, so that the caller can call
  208. * us again to restart the traversal with longer expire_limit.
  209. */
  210. static void mark_reachable(struct expire_reflog_policy_cb *cb)
  211. {
  212. struct commit_list *pending;
  213. timestamp_t expire_limit = cb->mark_limit;
  214. struct commit_list *leftover = NULL;
  215. for (pending = cb->mark_list; pending; pending = pending->next)
  216. pending->item->object.flags &= ~REACHABLE;
  217. pending = cb->mark_list;
  218. while (pending) {
  219. struct commit_list *parent;
  220. struct commit *commit = pop_commit(&pending);
  221. if (commit->object.flags & REACHABLE)
  222. continue;
  223. if (parse_commit(commit))
  224. continue;
  225. commit->object.flags |= REACHABLE;
  226. if (commit->date < expire_limit) {
  227. commit_list_insert(commit, &leftover);
  228. continue;
  229. }
  230. commit->object.flags |= REACHABLE;
  231. parent = commit->parents;
  232. while (parent) {
  233. commit = parent->item;
  234. parent = parent->next;
  235. if (commit->object.flags & REACHABLE)
  236. continue;
  237. commit_list_insert(commit, &pending);
  238. }
  239. }
  240. cb->mark_list = leftover;
  241. }
  242. static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, struct object_id *oid)
  243. {
  244. /*
  245. * We may or may not have the commit yet - if not, look it
  246. * up using the supplied sha1.
  247. */
  248. if (!commit) {
  249. if (is_null_oid(oid))
  250. return 0;
  251. commit = lookup_commit_reference_gently(the_repository, oid,
  252. 1);
  253. /* Not a commit -- keep it */
  254. if (!commit)
  255. return 0;
  256. }
  257. /* Reachable from the current ref? Don't prune. */
  258. if (commit->object.flags & REACHABLE)
  259. return 0;
  260. if (cb->mark_list && cb->mark_limit) {
  261. cb->mark_limit = 0; /* dig down to the root */
  262. mark_reachable(cb);
  263. }
  264. return !(commit->object.flags & REACHABLE);
  265. }
  266. /*
  267. * Return true iff the specified reflog entry should be expired.
  268. */
  269. static int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
  270. const char *email, timestamp_t timestamp, int tz,
  271. const char *message, void *cb_data)
  272. {
  273. struct expire_reflog_policy_cb *cb = cb_data;
  274. struct commit *old_commit, *new_commit;
  275. if (timestamp < cb->cmd.expire_total)
  276. return 1;
  277. old_commit = new_commit = NULL;
  278. if (cb->cmd.stalefix &&
  279. (!keep_entry(&old_commit, ooid) || !keep_entry(&new_commit, noid)))
  280. return 1;
  281. if (timestamp < cb->cmd.expire_unreachable) {
  282. if (cb->unreachable_expire_kind == UE_ALWAYS)
  283. return 1;
  284. if (unreachable(cb, old_commit, ooid) || unreachable(cb, new_commit, noid))
  285. return 1;
  286. }
  287. if (cb->cmd.recno && --(cb->cmd.recno) == 0)
  288. return 1;
  289. return 0;
  290. }
  291. static int push_tip_to_list(const char *refname, const struct object_id *oid,
  292. int flags, void *cb_data)
  293. {
  294. struct commit_list **list = cb_data;
  295. struct commit *tip_commit;
  296. if (flags & REF_ISSYMREF)
  297. return 0;
  298. tip_commit = lookup_commit_reference_gently(the_repository, oid, 1);
  299. if (!tip_commit)
  300. return 0;
  301. commit_list_insert(tip_commit, list);
  302. return 0;
  303. }
  304. static int is_head(const char *refname)
  305. {
  306. switch (ref_type(refname)) {
  307. case REF_TYPE_OTHER_PSEUDOREF:
  308. case REF_TYPE_MAIN_PSEUDOREF:
  309. if (parse_worktree_ref(refname, NULL, NULL, &refname))
  310. BUG("not a worktree ref: %s", refname);
  311. break;
  312. default:
  313. break;
  314. }
  315. return !strcmp(refname, "HEAD");
  316. }
  317. static void reflog_expiry_prepare(const char *refname,
  318. const struct object_id *oid,
  319. void *cb_data)
  320. {
  321. struct expire_reflog_policy_cb *cb = cb_data;
  322. if (!cb->cmd.expire_unreachable || is_head(refname)) {
  323. cb->tip_commit = NULL;
  324. cb->unreachable_expire_kind = UE_HEAD;
  325. } else {
  326. cb->tip_commit = lookup_commit_reference_gently(the_repository,
  327. oid, 1);
  328. if (!cb->tip_commit)
  329. cb->unreachable_expire_kind = UE_ALWAYS;
  330. else
  331. cb->unreachable_expire_kind = UE_NORMAL;
  332. }
  333. if (cb->cmd.expire_unreachable <= cb->cmd.expire_total)
  334. cb->unreachable_expire_kind = UE_ALWAYS;
  335. cb->mark_list = NULL;
  336. cb->tips = NULL;
  337. if (cb->unreachable_expire_kind != UE_ALWAYS) {
  338. if (cb->unreachable_expire_kind == UE_HEAD) {
  339. struct commit_list *elem;
  340. for_each_ref(push_tip_to_list, &cb->tips);
  341. for (elem = cb->tips; elem; elem = elem->next)
  342. commit_list_insert(elem->item, &cb->mark_list);
  343. } else {
  344. commit_list_insert(cb->tip_commit, &cb->mark_list);
  345. }
  346. cb->mark_limit = cb->cmd.expire_total;
  347. mark_reachable(cb);
  348. }
  349. }
  350. static void reflog_expiry_cleanup(void *cb_data)
  351. {
  352. struct expire_reflog_policy_cb *cb = cb_data;
  353. if (cb->unreachable_expire_kind != UE_ALWAYS) {
  354. if (cb->unreachable_expire_kind == UE_HEAD) {
  355. struct commit_list *elem;
  356. for (elem = cb->tips; elem; elem = elem->next)
  357. clear_commit_marks(elem->item, REACHABLE);
  358. free_commit_list(cb->tips);
  359. } else {
  360. clear_commit_marks(cb->tip_commit, REACHABLE);
  361. }
  362. }
  363. }
  364. static int collect_reflog(const char *ref, const struct object_id *oid, int unused, void *cb_data)
  365. {
  366. struct collected_reflog *e;
  367. struct collect_reflog_cb *cb = cb_data;
  368. struct strbuf newref = STRBUF_INIT;
  369. /*
  370. * Avoid collecting the same shared ref multiple times because
  371. * they are available via all worktrees.
  372. */
  373. if (!cb->wt->is_current && ref_type(ref) == REF_TYPE_NORMAL)
  374. return 0;
  375. strbuf_worktree_ref(cb->wt, &newref, ref);
  376. FLEX_ALLOC_STR(e, reflog, newref.buf);
  377. strbuf_release(&newref);
  378. oidcpy(&e->oid, oid);
  379. ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);
  380. cb->e[cb->nr++] = e;
  381. return 0;
  382. }
  383. static struct reflog_expire_cfg {
  384. struct reflog_expire_cfg *next;
  385. timestamp_t expire_total;
  386. timestamp_t expire_unreachable;
  387. char pattern[FLEX_ARRAY];
  388. } *reflog_expire_cfg, **reflog_expire_cfg_tail;
  389. static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)
  390. {
  391. struct reflog_expire_cfg *ent;
  392. if (!reflog_expire_cfg_tail)
  393. reflog_expire_cfg_tail = &reflog_expire_cfg;
  394. for (ent = reflog_expire_cfg; ent; ent = ent->next)
  395. if (!strncmp(ent->pattern, pattern, len) &&
  396. ent->pattern[len] == '\0')
  397. return ent;
  398. FLEX_ALLOC_MEM(ent, pattern, pattern, len);
  399. *reflog_expire_cfg_tail = ent;
  400. reflog_expire_cfg_tail = &(ent->next);
  401. return ent;
  402. }
  403. /* expiry timer slot */
  404. #define EXPIRE_TOTAL 01
  405. #define EXPIRE_UNREACH 02
  406. static int reflog_expire_config(const char *var, const char *value, void *cb)
  407. {
  408. const char *pattern, *key;
  409. size_t pattern_len;
  410. timestamp_t expire;
  411. int slot;
  412. struct reflog_expire_cfg *ent;
  413. if (parse_config_key(var, "gc", &pattern, &pattern_len, &key) < 0)
  414. return git_default_config(var, value, cb);
  415. if (!strcmp(key, "reflogexpire")) {
  416. slot = EXPIRE_TOTAL;
  417. if (git_config_expiry_date(&expire, var, value))
  418. return -1;
  419. } else if (!strcmp(key, "reflogexpireunreachable")) {
  420. slot = EXPIRE_UNREACH;
  421. if (git_config_expiry_date(&expire, var, value))
  422. return -1;
  423. } else
  424. return git_default_config(var, value, cb);
  425. if (!pattern) {
  426. switch (slot) {
  427. case EXPIRE_TOTAL:
  428. default_reflog_expire = expire;
  429. break;
  430. case EXPIRE_UNREACH:
  431. default_reflog_expire_unreachable = expire;
  432. break;
  433. }
  434. return 0;
  435. }
  436. ent = find_cfg_ent(pattern, pattern_len);
  437. if (!ent)
  438. return -1;
  439. switch (slot) {
  440. case EXPIRE_TOTAL:
  441. ent->expire_total = expire;
  442. break;
  443. case EXPIRE_UNREACH:
  444. ent->expire_unreachable = expire;
  445. break;
  446. }
  447. return 0;
  448. }
  449. static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, const char *ref)
  450. {
  451. struct reflog_expire_cfg *ent;
  452. if (slot == (EXPIRE_TOTAL|EXPIRE_UNREACH))
  453. return; /* both given explicitly -- nothing to tweak */
  454. for (ent = reflog_expire_cfg; ent; ent = ent->next) {
  455. if (!wildmatch(ent->pattern, ref, 0)) {
  456. if (!(slot & EXPIRE_TOTAL))
  457. cb->expire_total = ent->expire_total;
  458. if (!(slot & EXPIRE_UNREACH))
  459. cb->expire_unreachable = ent->expire_unreachable;
  460. return;
  461. }
  462. }
  463. /*
  464. * If unconfigured, make stash never expire
  465. */
  466. if (!strcmp(ref, "refs/stash")) {
  467. if (!(slot & EXPIRE_TOTAL))
  468. cb->expire_total = 0;
  469. if (!(slot & EXPIRE_UNREACH))
  470. cb->expire_unreachable = 0;
  471. return;
  472. }
  473. /* Nothing matched -- use the default value */
  474. if (!(slot & EXPIRE_TOTAL))
  475. cb->expire_total = default_reflog_expire;
  476. if (!(slot & EXPIRE_UNREACH))
  477. cb->expire_unreachable = default_reflog_expire_unreachable;
  478. }
  479. static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
  480. {
  481. struct expire_reflog_policy_cb cb;
  482. timestamp_t now = time(NULL);
  483. int i, status, do_all, all_worktrees = 1;
  484. int explicit_expiry = 0;
  485. unsigned int flags = 0;
  486. default_reflog_expire_unreachable = now - 30 * 24 * 3600;
  487. default_reflog_expire = now - 90 * 24 * 3600;
  488. git_config(reflog_expire_config, NULL);
  489. save_commit_buffer = 0;
  490. do_all = status = 0;
  491. memset(&cb, 0, sizeof(cb));
  492. cb.cmd.expire_total = default_reflog_expire;
  493. cb.cmd.expire_unreachable = default_reflog_expire_unreachable;
  494. for (i = 1; i < argc; i++) {
  495. const char *arg = argv[i];
  496. if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
  497. flags |= EXPIRE_REFLOGS_DRY_RUN;
  498. else if (skip_prefix(arg, "--expire=", &arg)) {
  499. if (parse_expiry_date(arg, &cb.cmd.expire_total))
  500. die(_("'%s' is not a valid timestamp"), arg);
  501. explicit_expiry |= EXPIRE_TOTAL;
  502. }
  503. else if (skip_prefix(arg, "--expire-unreachable=", &arg)) {
  504. if (parse_expiry_date(arg, &cb.cmd.expire_unreachable))
  505. die(_("'%s' is not a valid timestamp"), arg);
  506. explicit_expiry |= EXPIRE_UNREACH;
  507. }
  508. else if (!strcmp(arg, "--stale-fix"))
  509. cb.cmd.stalefix = 1;
  510. else if (!strcmp(arg, "--rewrite"))
  511. flags |= EXPIRE_REFLOGS_REWRITE;
  512. else if (!strcmp(arg, "--updateref"))
  513. flags |= EXPIRE_REFLOGS_UPDATE_REF;
  514. else if (!strcmp(arg, "--all"))
  515. do_all = 1;
  516. else if (!strcmp(arg, "--single-worktree"))
  517. all_worktrees = 0;
  518. else if (!strcmp(arg, "--verbose"))
  519. flags |= EXPIRE_REFLOGS_VERBOSE;
  520. else if (!strcmp(arg, "--")) {
  521. i++;
  522. break;
  523. }
  524. else if (arg[0] == '-')
  525. usage(_(reflog_expire_usage));
  526. else
  527. break;
  528. }
  529. /*
  530. * We can trust the commits and objects reachable from refs
  531. * even in older repository. We cannot trust what's reachable
  532. * from reflog if the repository was pruned with older git.
  533. */
  534. if (cb.cmd.stalefix) {
  535. repo_init_revisions(the_repository, &cb.cmd.revs, prefix);
  536. if (flags & EXPIRE_REFLOGS_VERBOSE)
  537. printf(_("Marking reachable objects..."));
  538. mark_reachable_objects(&cb.cmd.revs, 0, 0, NULL);
  539. if (flags & EXPIRE_REFLOGS_VERBOSE)
  540. putchar('\n');
  541. }
  542. if (do_all) {
  543. struct collect_reflog_cb collected;
  544. struct worktree **worktrees, **p;
  545. int i;
  546. memset(&collected, 0, sizeof(collected));
  547. worktrees = get_worktrees();
  548. for (p = worktrees; *p; p++) {
  549. if (!all_worktrees && !(*p)->is_current)
  550. continue;
  551. collected.wt = *p;
  552. refs_for_each_reflog(get_worktree_ref_store(*p),
  553. collect_reflog, &collected);
  554. }
  555. free_worktrees(worktrees);
  556. for (i = 0; i < collected.nr; i++) {
  557. struct collected_reflog *e = collected.e[i];
  558. set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog);
  559. status |= reflog_expire(e->reflog, &e->oid, flags,
  560. reflog_expiry_prepare,
  561. should_expire_reflog_ent,
  562. reflog_expiry_cleanup,
  563. &cb);
  564. free(e);
  565. }
  566. free(collected.e);
  567. }
  568. for (; i < argc; i++) {
  569. char *ref;
  570. struct object_id oid;
  571. if (!dwim_log(argv[i], strlen(argv[i]), &oid, &ref)) {
  572. status |= error(_("%s points nowhere!"), argv[i]);
  573. continue;
  574. }
  575. set_reflog_expiry_param(&cb.cmd, explicit_expiry, ref);
  576. status |= reflog_expire(ref, &oid, flags,
  577. reflog_expiry_prepare,
  578. should_expire_reflog_ent,
  579. reflog_expiry_cleanup,
  580. &cb);
  581. }
  582. return status;
  583. }
  584. static int count_reflog_ent(struct object_id *ooid, struct object_id *noid,
  585. const char *email, timestamp_t timestamp, int tz,
  586. const char *message, void *cb_data)
  587. {
  588. struct expire_reflog_policy_cb *cb = cb_data;
  589. if (!cb->cmd.expire_total || timestamp < cb->cmd.expire_total)
  590. cb->cmd.recno++;
  591. return 0;
  592. }
  593. static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
  594. {
  595. struct expire_reflog_policy_cb cb;
  596. int i, status = 0;
  597. unsigned int flags = 0;
  598. memset(&cb, 0, sizeof(cb));
  599. for (i = 1; i < argc; i++) {
  600. const char *arg = argv[i];
  601. if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
  602. flags |= EXPIRE_REFLOGS_DRY_RUN;
  603. else if (!strcmp(arg, "--rewrite"))
  604. flags |= EXPIRE_REFLOGS_REWRITE;
  605. else if (!strcmp(arg, "--updateref"))
  606. flags |= EXPIRE_REFLOGS_UPDATE_REF;
  607. else if (!strcmp(arg, "--verbose"))
  608. flags |= EXPIRE_REFLOGS_VERBOSE;
  609. else if (!strcmp(arg, "--")) {
  610. i++;
  611. break;
  612. }
  613. else if (arg[0] == '-')
  614. usage(_(reflog_delete_usage));
  615. else
  616. break;
  617. }
  618. if (argc - i < 1)
  619. return error(_("no reflog specified to delete"));
  620. for ( ; i < argc; i++) {
  621. const char *spec = strstr(argv[i], "@{");
  622. struct object_id oid;
  623. char *ep, *ref;
  624. int recno;
  625. if (!spec) {
  626. status |= error(_("not a reflog: %s"), argv[i]);
  627. continue;
  628. }
  629. if (!dwim_log(argv[i], spec - argv[i], &oid, &ref)) {
  630. status |= error(_("no reflog for '%s'"), argv[i]);
  631. continue;
  632. }
  633. recno = strtoul(spec + 2, &ep, 10);
  634. if (*ep == '}') {
  635. cb.cmd.recno = -recno;
  636. for_each_reflog_ent(ref, count_reflog_ent, &cb);
  637. } else {
  638. cb.cmd.expire_total = approxidate(spec + 2);
  639. for_each_reflog_ent(ref, count_reflog_ent, &cb);
  640. cb.cmd.expire_total = 0;
  641. }
  642. status |= reflog_expire(ref, &oid, flags,
  643. reflog_expiry_prepare,
  644. should_expire_reflog_ent,
  645. reflog_expiry_cleanup,
  646. &cb);
  647. free(ref);
  648. }
  649. return status;
  650. }
  651. static int cmd_reflog_exists(int argc, const char **argv, const char *prefix)
  652. {
  653. int i, start = 0;
  654. for (i = 1; i < argc; i++) {
  655. const char *arg = argv[i];
  656. if (!strcmp(arg, "--")) {
  657. i++;
  658. break;
  659. }
  660. else if (arg[0] == '-')
  661. usage(_(reflog_exists_usage));
  662. else
  663. break;
  664. }
  665. start = i;
  666. if (argc - start != 1)
  667. usage(_(reflog_exists_usage));
  668. if (check_refname_format(argv[start], REFNAME_ALLOW_ONELEVEL))
  669. die(_("invalid ref format: %s"), argv[start]);
  670. return !reflog_exists(argv[start]);
  671. }
  672. /*
  673. * main "reflog"
  674. */
  675. static const char reflog_usage[] =
  676. N_("git reflog [ show | expire | delete | exists ]");
  677. int cmd_reflog(int argc, const char **argv, const char *prefix)
  678. {
  679. if (argc > 1 && !strcmp(argv[1], "-h"))
  680. usage(_(reflog_usage));
  681. /* With no command, we default to showing it. */
  682. if (argc < 2 || *argv[1] == '-')
  683. return cmd_log_reflog(argc, argv, prefix);
  684. if (!strcmp(argv[1], "show"))
  685. return cmd_log_reflog(argc - 1, argv + 1, prefix);
  686. if (!strcmp(argv[1], "expire"))
  687. return cmd_reflog_expire(argc - 1, argv + 1, prefix);
  688. if (!strcmp(argv[1], "delete"))
  689. return cmd_reflog_delete(argc - 1, argv + 1, prefix);
  690. if (!strcmp(argv[1], "exists"))
  691. return cmd_reflog_exists(argc - 1, argv + 1, prefix);
  692. return cmd_log_reflog(argc, argv, prefix);
  693. }