]> git.ipfire.org Git - thirdparty/git.git/blame - builtin/reflog.c
Merge branch 'en/fetch-negotiation-default-fix'
[thirdparty/git.git] / builtin / reflog.c
CommitLineData
4264dc15 1#include "builtin.h"
b2141fc1 2#include "config.h"
697cc8ef 3#include "lockfile.h"
cbd53a21 4#include "object-store.h"
109cd76d 5#include "repository.h"
4264dc15
JH
6#include "commit.h"
7#include "refs.h"
8#include "dir.h"
8d8b9f62 9#include "tree-walk.h"
1389d9dd
JH
10#include "diff.h"
11#include "revision.h"
12#include "reachable.h"
c9ef0d95 13#include "worktree.h"
1389d9dd 14
afcb2e7a 15static const char reflog_exists_usage[] =
dd509db3 16N_("git reflog exists <ref>");
4264dc15 17
dddbad72
JS
18static timestamp_t default_reflog_expire;
19static timestamp_t default_reflog_expire_unreachable;
4aec56d1 20
1389d9dd 21struct cmd_reflog_expire_cb {
1389d9dd 22 int stalefix;
33d7bdd6 23 int explicit_expiry;
dddbad72
JS
24 timestamp_t expire_total;
25 timestamp_t expire_unreachable;
552cecc2 26 int recno;
1389d9dd
JH
27};
28
ea7b4f6d 29struct expire_reflog_policy_cb {
03cb91b1
JH
30 enum {
31 UE_NORMAL,
32 UE_ALWAYS,
33 UE_HEAD
34 } unreachable_expire_kind;
b4ca1db9
JH
35 struct commit_list *mark_list;
36 unsigned long mark_limit;
b729effb 37 struct cmd_reflog_expire_cb cmd;
c48a1635
MH
38 struct commit *tip_commit;
39 struct commit_list *tips;
fcd2c3d9 40 unsigned int dry_run:1;
4264dc15
JH
41};
42
f2919bae
ÆAB
43struct worktree_reflogs {
44 struct worktree *worktree;
45 struct string_list reflogs;
bda3a31c
JH
46};
47
95308d64 48/* Remember to update object flag allocation in object.h */
cd1f9c36
JH
49#define INCOMPLETE (1u<<10)
50#define STUDYING (1u<<11)
494fbfe8 51#define REACHABLE (1u<<12)
cd1f9c36 52
49a09e74 53static int tree_is_complete(const struct object_id *oid)
8d8b9f62
JH
54{
55 struct tree_desc desc;
cd1f9c36
JH
56 struct name_entry entry;
57 int complete;
58 struct tree *tree;
8d8b9f62 59
f86bcc7b 60 tree = lookup_tree(the_repository, oid);
cd1f9c36 61 if (!tree)
8d8b9f62 62 return 0;
cd1f9c36
JH
63 if (tree->object.flags & SEEN)
64 return 1;
65 if (tree->object.flags & INCOMPLETE)
66 return 0;
67
6fda5e51 68 if (!tree->buffer) {
21666f1a 69 enum object_type type;
6fda5e51 70 unsigned long size;
b4f5aca4 71 void *data = read_object_file(oid, &type, &size);
cd1f9c36
JH
72 if (!data) {
73 tree->object.flags |= INCOMPLETE;
8d8b9f62
JH
74 return 0;
75 }
cd1f9c36 76 tree->buffer = data;
6fda5e51 77 tree->size = size;
8d8b9f62 78 }
6fda5e51 79 init_tree_desc(&desc, tree->buffer, tree->size);
cd1f9c36
JH
80 complete = 1;
81 while (tree_entry(&desc, &entry)) {
cba595ab 82 if (!has_object_file(&entry.oid) ||
ea82b2a0 83 (S_ISDIR(entry.mode) && !tree_is_complete(&entry.oid))) {
cd1f9c36
JH
84 tree->object.flags |= INCOMPLETE;
85 complete = 0;
86 }
87 }
6e454b9a 88 free_tree_buffer(tree);
8d8b9f62 89
cd1f9c36
JH
90 if (complete)
91 tree->object.flags |= SEEN;
92 return complete;
93}
1389d9dd
JH
94
95static int commit_is_complete(struct commit *commit)
96{
97 struct object_array study;
98 struct object_array found;
99 int is_incomplete = 0;
100 int i;
101
102 /* early return */
103 if (commit->object.flags & SEEN)
104 return 1;
105 if (commit->object.flags & INCOMPLETE)
106 return 0;
107 /*
108 * Find all commits that are reachable and are not marked as
109 * SEEN. Then make sure the trees and blobs contained are
110 * complete. After that, mark these commits also as SEEN.
111 * If some of the objects that are needed to complete this
112 * commit are missing, mark this commit as INCOMPLETE.
113 */
114 memset(&study, 0, sizeof(study));
115 memset(&found, 0, sizeof(found));
116 add_object_array(&commit->object, NULL, &study);
117 add_object_array(&commit->object, NULL, &found);
118 commit->object.flags |= STUDYING;
119 while (study.nr) {
120 struct commit *c;
121 struct commit_list *parent;
122
71992039 123 c = (struct commit *)object_array_pop(&study);
109cd76d 124 if (!c->object.parsed && !parse_object(the_repository, &c->object.oid))
1389d9dd
JH
125 c->object.flags |= INCOMPLETE;
126
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) {
cd1f9c36
JH
143 /*
144 * make sure all commits in "found" array have all the
1389d9dd
JH
145 * necessary objects.
146 */
cd1f9c36 147 for (i = 0; i < found.nr; i++) {
1389d9dd
JH
148 struct commit *c =
149 (struct commit *)found.objects[i].item;
2e27bd77 150 if (!tree_is_complete(get_commit_tree_oid(c))) {
1389d9dd 151 is_incomplete = 1;
cd1f9c36
JH
152 c->object.flags |= INCOMPLETE;
153 }
1389d9dd
JH
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;
cd1f9c36
JH
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 }
1389d9dd 178 /* free object arrays */
dcb572ab
179 object_array_clear(&study);
180 object_array_clear(&found);
1389d9dd
JH
181 return !is_incomplete;
182}
183
4322478a 184static int keep_entry(struct commit **it, struct object_id *oid)
4264dc15 185{
8d8b9f62
JH
186 struct commit *commit;
187
4322478a 188 if (is_null_oid(oid))
4264dc15 189 return 1;
21e1ee8f 190 commit = lookup_commit_reference_gently(the_repository, oid, 1);
8d8b9f62
JH
191 if (!commit)
192 return 0;
193
1389d9dd
JH
194 /*
195 * Make sure everything in this commit exists.
196 *
197 * We have walked all the objects reachable from the refs
198 * and cache earlier. The commits reachable by this commit
199 * must meet SEEN commits -- and then we should mark them as
200 * SEEN as well.
201 */
202 if (!commit_is_complete(commit))
8d8b9f62
JH
203 return 0;
204 *it = commit;
205 return 1;
4264dc15
JH
206}
207
b4ca1db9
JH
208/*
209 * Starting from commits in the cb->mark_list, mark commits that are
210 * reachable from them. Stop the traversal at commits older than
211 * the expire_limit and queue them back, so that the caller can call
212 * us again to restart the traversal with longer expire_limit.
213 */
ea7b4f6d 214static void mark_reachable(struct expire_reflog_policy_cb *cb)
666e07e6 215{
b4ca1db9 216 struct commit_list *pending;
dddbad72 217 timestamp_t expire_limit = cb->mark_limit;
b4ca1db9 218 struct commit_list *leftover = NULL;
666e07e6 219
b4ca1db9
JH
220 for (pending = cb->mark_list; pending; pending = pending->next)
221 pending->item->object.flags &= ~REACHABLE;
494fbfe8 222
b4ca1db9 223 pending = cb->mark_list;
494fbfe8 224 while (pending) {
494fbfe8 225 struct commit_list *parent;
e510ab89 226 struct commit *commit = pop_commit(&pending);
494fbfe8
JH
227 if (commit->object.flags & REACHABLE)
228 continue;
229 if (parse_commit(commit))
230 continue;
231 commit->object.flags |= REACHABLE;
b4ca1db9
JH
232 if (commit->date < expire_limit) {
233 commit_list_insert(commit, &leftover);
494fbfe8 234 continue;
b4ca1db9
JH
235 }
236 commit->object.flags |= REACHABLE;
494fbfe8
JH
237 parent = commit->parents;
238 while (parent) {
239 commit = parent->item;
240 parent = parent->next;
241 if (commit->object.flags & REACHABLE)
242 continue;
243 commit_list_insert(commit, &pending);
244 }
245 }
b4ca1db9
JH
246 cb->mark_list = leftover;
247}
248
4322478a 249static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, struct object_id *oid)
b4ca1db9
JH
250{
251 /*
252 * We may or may not have the commit yet - if not, look it
253 * up using the supplied sha1.
254 */
255 if (!commit) {
4322478a 256 if (is_null_oid(oid))
b4ca1db9
JH
257 return 0;
258
21e1ee8f
SB
259 commit = lookup_commit_reference_gently(the_repository, oid,
260 1);
b4ca1db9
JH
261
262 /* Not a commit -- keep it */
263 if (!commit)
264 return 0;
265 }
266
267 /* Reachable from the current ref? Don't prune. */
268 if (commit->object.flags & REACHABLE)
269 return 0;
270
271 if (cb->mark_list && cb->mark_limit) {
272 cb->mark_limit = 0; /* dig down to the root */
273 mark_reachable(cb);
274 }
275
276 return !(commit->object.flags & REACHABLE);
494fbfe8
JH
277}
278
60cc3c40
MH
279/*
280 * Return true iff the specified reflog entry should be expired.
281 */
4322478a 282static int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
dddbad72 283 const char *email, timestamp_t timestamp, int tz,
60cc3c40 284 const char *message, void *cb_data)
4264dc15 285{
ea7b4f6d 286 struct expire_reflog_policy_cb *cb = cb_data;
dfa5990d 287 struct commit *old_commit, *new_commit;
4264dc15 288
b729effb 289 if (timestamp < cb->cmd.expire_total)
60cc3c40 290 return 1;
2b81fab2 291
dfa5990d 292 old_commit = new_commit = NULL;
b729effb 293 if (cb->cmd.stalefix &&
dfa5990d 294 (!keep_entry(&old_commit, ooid) || !keep_entry(&new_commit, noid)))
60cc3c40 295 return 1;
4264dc15 296
b729effb 297 if (timestamp < cb->cmd.expire_unreachable) {
20d6b686
ÆAB
298 switch (cb->unreachable_expire_kind) {
299 case UE_ALWAYS:
60cc3c40 300 return 1;
20d6b686
ÆAB
301 case UE_NORMAL:
302 case UE_HEAD:
303 if (unreachable(cb, old_commit, ooid) || unreachable(cb, new_commit, noid))
304 return 1;
305 break;
306 }
9bbaa6cc 307 }
4264dc15 308
b729effb 309 if (cb->cmd.recno && --(cb->cmd.recno) == 0)
60cc3c40
MH
310 return 1;
311
4264dc15 312 return 0;
60cc3c40
MH
313}
314
fcd2c3d9
ÆAB
315static int should_expire_reflog_ent_verbose(struct object_id *ooid,
316 struct object_id *noid,
317 const char *email,
318 timestamp_t timestamp, int tz,
319 const char *message, void *cb_data)
320{
321 struct expire_reflog_policy_cb *cb = cb_data;
322 int expire;
323
324 expire = should_expire_reflog_ent(ooid, noid, email, timestamp, tz,
325 message, cb);
326
327 if (!expire)
328 printf("keep %s", message);
329 else if (cb->dry_run)
330 printf("would prune %s", message);
331 else
332 printf("prune %s", message);
333
334 return expire;
335}
336
5bcad1bc 337static int push_tip_to_list(const char *refname, const struct object_id *oid,
ea7b4f6d 338 int flags, void *cb_data)
03cb91b1
JH
339{
340 struct commit_list **list = cb_data;
341 struct commit *tip_commit;
342 if (flags & REF_ISSYMREF)
343 return 0;
21e1ee8f 344 tip_commit = lookup_commit_reference_gently(the_repository, oid, 1);
03cb91b1
JH
345 if (!tip_commit)
346 return 0;
347 commit_list_insert(tip_commit, list);
348 return 0;
349}
350
c9ef0d95
NTND
351static int is_head(const char *refname)
352{
353 switch (ref_type(refname)) {
354 case REF_TYPE_OTHER_PSEUDOREF:
355 case REF_TYPE_MAIN_PSEUDOREF:
356 if (parse_worktree_ref(refname, NULL, NULL, &refname))
357 BUG("not a worktree ref: %s", refname);
358 break;
359 default:
360 break;
361 }
362 return !strcmp(refname, "HEAD");
363}
364
c48a1635 365static void reflog_expiry_prepare(const char *refname,
4322478a 366 const struct object_id *oid,
b729effb 367 void *cb_data)
c48a1635 368{
b729effb 369 struct expire_reflog_policy_cb *cb = cb_data;
20d6b686 370 struct commit_list *elem;
07815e2d 371 struct commit *commit = NULL;
b729effb 372
c9ef0d95 373 if (!cb->cmd.expire_unreachable || is_head(refname)) {
c48a1635
MH
374 cb->unreachable_expire_kind = UE_HEAD;
375 } else {
daf1d828 376 commit = lookup_commit(the_repository, oid);
07815e2d 377 cb->unreachable_expire_kind = commit ? UE_NORMAL : UE_ALWAYS;
c48a1635
MH
378 }
379
b729effb 380 if (cb->cmd.expire_unreachable <= cb->cmd.expire_total)
c48a1635
MH
381 cb->unreachable_expire_kind = UE_ALWAYS;
382
20d6b686
ÆAB
383 switch (cb->unreachable_expire_kind) {
384 case UE_ALWAYS:
385 return;
386 case UE_HEAD:
387 for_each_ref(push_tip_to_list, &cb->tips);
388 for (elem = cb->tips; elem; elem = elem->next)
389 commit_list_insert(elem->item, &cb->mark_list);
390 break;
391 case UE_NORMAL:
07815e2d
ÆAB
392 commit_list_insert(commit, &cb->mark_list);
393 /* For reflog_expiry_cleanup() below */
394 cb->tip_commit = commit;
c48a1635 395 }
20d6b686
ÆAB
396 cb->mark_limit = cb->cmd.expire_total;
397 mark_reachable(cb);
c48a1635
MH
398}
399
b729effb 400static void reflog_expiry_cleanup(void *cb_data)
c48a1635 401{
b729effb 402 struct expire_reflog_policy_cb *cb = cb_data;
20d6b686
ÆAB
403 struct commit_list *elem;
404
405 switch (cb->unreachable_expire_kind) {
406 case UE_ALWAYS:
407 return;
408 case UE_HEAD:
409 for (elem = cb->tips; elem; elem = elem->next)
410 clear_commit_marks(elem->item, REACHABLE);
411 free_commit_list(cb->tips);
412 break;
413 case UE_NORMAL:
414 clear_commit_marks(cb->tip_commit, REACHABLE);
415 break;
c48a1635
MH
416 }
417}
418
5bcad1bc 419static int collect_reflog(const char *ref, const struct object_id *oid, int unused, void *cb_data)
bda3a31c 420{
f2919bae
ÆAB
421 struct worktree_reflogs *cb = cb_data;
422 struct worktree *worktree = cb->worktree;
c9ef0d95
NTND
423 struct strbuf newref = STRBUF_INIT;
424
425 /*
426 * Avoid collecting the same shared ref multiple times because
427 * they are available via all worktrees.
428 */
f2919bae 429 if (!worktree->is_current && ref_type(ref) == REF_TYPE_NORMAL)
c9ef0d95
NTND
430 return 0;
431
f2919bae
ÆAB
432 strbuf_worktree_ref(worktree, &newref, ref);
433 string_list_append_nodup(&cb->reflogs, strbuf_detach(&newref, NULL));
bda3a31c 434
bda3a31c
JH
435 return 0;
436}
437
3cb22b8e
JH
438static struct reflog_expire_cfg {
439 struct reflog_expire_cfg *next;
dddbad72
JS
440 timestamp_t expire_total;
441 timestamp_t expire_unreachable;
3cb22b8e
JH
442 char pattern[FLEX_ARRAY];
443} *reflog_expire_cfg, **reflog_expire_cfg_tail;
444
445static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)
4aec56d1 446{
3cb22b8e
JH
447 struct reflog_expire_cfg *ent;
448
449 if (!reflog_expire_cfg_tail)
450 reflog_expire_cfg_tail = &reflog_expire_cfg;
451
452 for (ent = reflog_expire_cfg; ent; ent = ent->next)
c3a700fb
JK
453 if (!strncmp(ent->pattern, pattern, len) &&
454 ent->pattern[len] == '\0')
3cb22b8e
JH
455 return ent;
456
96ffc06f 457 FLEX_ALLOC_MEM(ent, pattern, pattern, len);
3cb22b8e
JH
458 *reflog_expire_cfg_tail = ent;
459 reflog_expire_cfg_tail = &(ent->next);
460 return ent;
461}
462
3cb22b8e
JH
463/* expiry timer slot */
464#define EXPIRE_TOTAL 01
465#define EXPIRE_UNREACH 02
466
467static int reflog_expire_config(const char *var, const char *value, void *cb)
468{
b3873c33 469 const char *pattern, *key;
f5914f4b 470 size_t pattern_len;
dddbad72 471 timestamp_t expire;
3cb22b8e
JH
472 int slot;
473 struct reflog_expire_cfg *ent;
474
b3873c33 475 if (parse_config_key(var, "gc", &pattern, &pattern_len, &key) < 0)
3cb22b8e
JH
476 return git_default_config(var, value, cb);
477
b3873c33 478 if (!strcmp(key, "reflogexpire")) {
3cb22b8e 479 slot = EXPIRE_TOTAL;
5f967424 480 if (git_config_expiry_date(&expire, var, value))
3cb22b8e 481 return -1;
b3873c33 482 } else if (!strcmp(key, "reflogexpireunreachable")) {
3cb22b8e 483 slot = EXPIRE_UNREACH;
5f967424 484 if (git_config_expiry_date(&expire, var, value))
3cb22b8e
JH
485 return -1;
486 } else
487 return git_default_config(var, value, cb);
488
b3873c33 489 if (!pattern) {
3cb22b8e
JH
490 switch (slot) {
491 case EXPIRE_TOTAL:
492 default_reflog_expire = expire;
493 break;
494 case EXPIRE_UNREACH:
495 default_reflog_expire_unreachable = expire;
496 break;
497 }
4f342b96
JH
498 return 0;
499 }
3cb22b8e 500
b3873c33 501 ent = find_cfg_ent(pattern, pattern_len);
3cb22b8e
JH
502 if (!ent)
503 return -1;
504 switch (slot) {
505 case EXPIRE_TOTAL:
506 ent->expire_total = expire;
507 break;
508 case EXPIRE_UNREACH:
509 ent->expire_unreachable = expire;
510 break;
511 }
512 return 0;
513}
514
33d7bdd6 515static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, const char *ref)
3cb22b8e
JH
516{
517 struct reflog_expire_cfg *ent;
518
33d7bdd6 519 if (cb->explicit_expiry == (EXPIRE_TOTAL|EXPIRE_UNREACH))
3cb22b8e
JH
520 return; /* both given explicitly -- nothing to tweak */
521
522 for (ent = reflog_expire_cfg; ent; ent = ent->next) {
55d34269 523 if (!wildmatch(ent->pattern, ref, 0)) {
33d7bdd6 524 if (!(cb->explicit_expiry & EXPIRE_TOTAL))
3cb22b8e 525 cb->expire_total = ent->expire_total;
33d7bdd6 526 if (!(cb->explicit_expiry & EXPIRE_UNREACH))
3cb22b8e
JH
527 cb->expire_unreachable = ent->expire_unreachable;
528 return;
529 }
530 }
531
60bce2bb
JH
532 /*
533 * If unconfigured, make stash never expire
534 */
535 if (!strcmp(ref, "refs/stash")) {
33d7bdd6 536 if (!(cb->explicit_expiry & EXPIRE_TOTAL))
60bce2bb 537 cb->expire_total = 0;
33d7bdd6 538 if (!(cb->explicit_expiry & EXPIRE_UNREACH))
60bce2bb
JH
539 cb->expire_unreachable = 0;
540 return;
541 }
542
3cb22b8e 543 /* Nothing matched -- use the default value */
33d7bdd6 544 if (!(cb->explicit_expiry & EXPIRE_TOTAL))
3cb22b8e 545 cb->expire_total = default_reflog_expire;
33d7bdd6 546 if (!(cb->explicit_expiry & EXPIRE_UNREACH))
3cb22b8e 547 cb->expire_unreachable = default_reflog_expire_unreachable;
4aec56d1
JH
548}
549
33d7bdd6
JC
550static const char * reflog_expire_usage[] = {
551 N_("git reflog expire [--expire=<time>] "
552 "[--expire-unreachable=<time>] "
553 "[--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] "
554 "[--verbose] [--all] <refs>..."),
555 NULL
556};
557
558static int expire_unreachable_callback(const struct option *opt,
559 const char *arg,
560 int unset)
561{
562 struct cmd_reflog_expire_cb *cmd = opt->value;
563
564 if (parse_expiry_date(arg, &cmd->expire_unreachable))
565 die(_("invalid timestamp '%s' given to '--%s'"),
566 arg, opt->long_name);
567
568 cmd->explicit_expiry |= EXPIRE_UNREACH;
569 return 0;
570}
571
572static int expire_total_callback(const struct option *opt,
573 const char *arg,
574 int unset)
575{
576 struct cmd_reflog_expire_cb *cmd = opt->value;
577
578 if (parse_expiry_date(arg, &cmd->expire_total))
579 die(_("invalid timestamp '%s' given to '--%s'"),
580 arg, opt->long_name);
581
582 cmd->explicit_expiry |= EXPIRE_TOTAL;
583 return 0;
584}
585
4264dc15
JH
586static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
587{
46fbe418 588 struct cmd_reflog_expire_cb cmd = { 0 };
dddbad72 589 timestamp_t now = time(NULL);
c9ef0d95 590 int i, status, do_all, all_worktrees = 1;
aba56c89 591 unsigned int flags = 0;
fcd2c3d9
ÆAB
592 int verbose = 0;
593 reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
33d7bdd6
JC
594 const struct option options[] = {
595 OPT_BIT(0, "dry-run", &flags, N_("do not actually prune any entries"),
596 EXPIRE_REFLOGS_DRY_RUN),
597 OPT_BIT(0, "rewrite", &flags,
598 N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
599 EXPIRE_REFLOGS_REWRITE),
600 OPT_BIT(0, "updateref", &flags,
601 N_("update the reference to the value of the top reflog entry"),
602 EXPIRE_REFLOGS_UPDATE_REF),
603 OPT_BOOL(0, "verbose", &verbose, N_("print extra information on screen.")),
604 OPT_CALLBACK_F(0, "expire", &cmd, N_("timestamp"),
605 N_("prune entries older than the specified time"),
606 PARSE_OPT_NONEG,
607 expire_total_callback),
608 OPT_CALLBACK_F(0, "expire-unreachable", &cmd, N_("timestamp"),
609 N_("prune entries older than <time> that are not reachable from the current tip of the branch"),
610 PARSE_OPT_NONEG,
611 expire_unreachable_callback),
612 OPT_BOOL(0, "stale-fix", &cmd.stalefix,
613 N_("prune any reflog entries that point to broken commits")),
614 OPT_BOOL(0, "all", &do_all, N_("process the reflogs of all references")),
615 OPT_BOOL(1, "single-worktree", &all_worktrees,
616 N_("limits processing to reflogs from the current worktree only.")),
617 OPT_END()
618 };
4264dc15 619
4a9f4394
AS
620 default_reflog_expire_unreachable = now - 30 * 24 * 3600;
621 default_reflog_expire = now - 90 * 24 * 3600;
ef90d6d4 622 git_config(reflog_expire_config, NULL);
4aec56d1 623
4264dc15
JH
624 save_commit_buffer = 0;
625 do_all = status = 0;
4aec56d1 626
33d7bdd6 627 cmd.explicit_expiry = 0;
46fbe418
ÆAB
628 cmd.expire_total = default_reflog_expire;
629 cmd.expire_unreachable = default_reflog_expire_unreachable;
4264dc15 630
33d7bdd6 631 argc = parse_options(argc, argv, prefix, options, reflog_expire_usage, 0);
3cb22b8e 632
fcd2c3d9
ÆAB
633 if (verbose)
634 should_prune_fn = should_expire_reflog_ent_verbose;
635
3cb22b8e
JH
636 /*
637 * We can trust the commits and objects reachable from refs
638 * even in older repository. We cannot trust what's reachable
639 * from reflog if the repository was pruned with older git.
640 */
46fbe418 641 if (cmd.stalefix) {
994b328f
ÆAB
642 struct rev_info revs;
643
644 repo_init_revisions(the_repository, &revs, prefix);
645 revs.do_not_die_on_missing_tree = 1;
646 revs.ignore_missing = 1;
647 revs.ignore_missing_links = 1;
fcd2c3d9 648 if (verbose)
dd509db3 649 printf(_("Marking reachable objects..."));
994b328f 650 mark_reachable_objects(&revs, 0, 0, NULL);
fcd2c3d9 651 if (verbose)
1389d9dd
JH
652 putchar('\n');
653 }
654
bda3a31c 655 if (do_all) {
f2919bae
ÆAB
656 struct worktree_reflogs collected = {
657 .reflogs = STRING_LIST_INIT_DUP,
658 };
659 struct string_list_item *item;
c9ef0d95 660 struct worktree **worktrees, **p;
bda3a31c 661
03f2465b 662 worktrees = get_worktrees();
c9ef0d95
NTND
663 for (p = worktrees; *p; p++) {
664 if (!all_worktrees && !(*p)->is_current)
665 continue;
f2919bae 666 collected.worktree = *p;
c9ef0d95
NTND
667 refs_for_each_reflog(get_worktree_ref_store(*p),
668 collect_reflog, &collected);
669 }
670 free_worktrees(worktrees);
f2919bae
ÆAB
671
672 for_each_string_list_item(item, &collected.reflogs) {
fcd2c3d9
ÆAB
673 struct expire_reflog_policy_cb cb = {
674 .cmd = cmd,
675 .dry_run = !!(flags & EXPIRE_REFLOGS_DRY_RUN),
676 };
ae35e16c 677
33d7bdd6 678 set_reflog_expiry_param(&cb.cmd, item->string);
f2919bae 679 status |= reflog_expire(item->string, flags,
fa5b1830 680 reflog_expiry_prepare,
fcd2c3d9 681 should_prune_fn,
fa5b1830
MH
682 reflog_expiry_cleanup,
683 &cb);
bda3a31c 684 }
f2919bae 685 string_list_clear(&collected.reflogs, 0);
bda3a31c
JH
686 }
687
33d7bdd6 688 for (i = 0; i < argc; i++) {
90fb46ec 689 char *ref;
46fbe418
ÆAB
690 struct expire_reflog_policy_cb cb = { .cmd = cmd };
691
ae35e16c 692 if (!dwim_log(argv[i], strlen(argv[i]), NULL, &ref)) {
dd509db3 693 status |= error(_("%s points nowhere!"), argv[i]);
4264dc15
JH
694 continue;
695 }
33d7bdd6 696 set_reflog_expiry_param(&cb.cmd, ref);
cc40b5ce 697 status |= reflog_expire(ref, flags,
fa5b1830 698 reflog_expiry_prepare,
fcd2c3d9 699 should_prune_fn,
fa5b1830
MH
700 reflog_expiry_cleanup,
701 &cb);
3c815049 702 free(ref);
4264dc15
JH
703 }
704 return status;
705}
706
9461d272 707static int count_reflog_ent(struct object_id *ooid, struct object_id *noid,
dddbad72 708 const char *email, timestamp_t timestamp, int tz,
552cecc2
JS
709 const char *message, void *cb_data)
710{
4a0339b3
ÆAB
711 struct cmd_reflog_expire_cb *cb = cb_data;
712 if (!cb->expire_total || timestamp < cb->expire_total)
713 cb->recno++;
552cecc2
JS
714 return 0;
715}
716
33d7bdd6
JC
717static const char * reflog_delete_usage[] = {
718 N_("git reflog delete [--rewrite] [--updateref] "
719 "[--dry-run | -n] [--verbose] <refs>..."),
720 NULL
721};
722
552cecc2
JS
723static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
724{
4a0339b3 725 struct cmd_reflog_expire_cb cmd = { 0 };
552cecc2 726 int i, status = 0;
aba56c89 727 unsigned int flags = 0;
fcd2c3d9
ÆAB
728 int verbose = 0;
729 reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
33d7bdd6
JC
730 const struct option options[] = {
731 OPT_BIT(0, "dry-run", &flags, N_("do not actually prune any entries"),
732 EXPIRE_REFLOGS_DRY_RUN),
733 OPT_BIT(0, "rewrite", &flags,
734 N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
735 EXPIRE_REFLOGS_REWRITE),
736 OPT_BIT(0, "updateref", &flags,
737 N_("update the reference to the value of the top reflog entry"),
738 EXPIRE_REFLOGS_UPDATE_REF),
739 OPT_BOOL(0, "verbose", &verbose, N_("print extra information on screen.")),
740 OPT_END()
741 };
742
743 argc = parse_options(argc, argv, prefix, options, reflog_delete_usage, 0);
3c386aa3 744
fcd2c3d9
ÆAB
745 if (verbose)
746 should_prune_fn = should_expire_reflog_ent_verbose;
747
33d7bdd6 748 if (argc < 1)
dd509db3 749 return error(_("no reflog specified to delete"));
3c386aa3 750
33d7bdd6 751 for (i = 0; i < argc; i++) {
552cecc2 752 const char *spec = strstr(argv[i], "@{");
552cecc2
JS
753 char *ep, *ref;
754 int recno;
fcd2c3d9
ÆAB
755 struct expire_reflog_policy_cb cb = {
756 .dry_run = !!(flags & EXPIRE_REFLOGS_DRY_RUN),
757 };
552cecc2
JS
758
759 if (!spec) {
dd509db3 760 status |= error(_("not a reflog: %s"), argv[i]);
552cecc2
JS
761 continue;
762 }
763
ae35e16c 764 if (!dwim_log(argv[i], spec - argv[i], NULL, &ref)) {
dd509db3 765 status |= error(_("no reflog for '%s'"), argv[i]);
552cecc2
JS
766 continue;
767 }
768
769 recno = strtoul(spec + 2, &ep, 10);
770 if (*ep == '}') {
4a0339b3
ÆAB
771 cmd.recno = -recno;
772 for_each_reflog_ent(ref, count_reflog_ent, &cmd);
552cecc2 773 } else {
4a0339b3
ÆAB
774 cmd.expire_total = approxidate(spec + 2);
775 for_each_reflog_ent(ref, count_reflog_ent, &cmd);
776 cmd.expire_total = 0;
552cecc2
JS
777 }
778
4a0339b3 779 cb.cmd = cmd;
cc40b5ce 780 status |= reflog_expire(ref, flags,
fa5b1830 781 reflog_expiry_prepare,
fcd2c3d9 782 should_prune_fn,
fa5b1830
MH
783 reflog_expiry_cleanup,
784 &cb);
552cecc2
JS
785 free(ref);
786 }
787 return status;
788}
789
afcb2e7a
DT
790static int cmd_reflog_exists(int argc, const char **argv, const char *prefix)
791{
792 int i, start = 0;
793
794 for (i = 1; i < argc; i++) {
795 const char *arg = argv[i];
796 if (!strcmp(arg, "--")) {
797 i++;
798 break;
799 }
800 else if (arg[0] == '-')
dd509db3 801 usage(_(reflog_exists_usage));
afcb2e7a
DT
802 else
803 break;
804 }
805
806 start = i;
807
808 if (argc - start != 1)
dd509db3 809 usage(_(reflog_exists_usage));
afcb2e7a
DT
810
811 if (check_refname_format(argv[start], REFNAME_ALLOW_ONELEVEL))
dd509db3 812 die(_("invalid ref format: %s"), argv[start]);
afcb2e7a
DT
813 return !reflog_exists(argv[start]);
814}
815
1389d9dd
JH
816/*
817 * main "reflog"
818 */
819
4264dc15 820static const char reflog_usage[] =
dd509db3 821N_("git reflog [ show | expire | delete | exists ]");
4264dc15
JH
822
823int cmd_reflog(int argc, const char **argv, const char *prefix)
824{
99caeed0 825 if (argc > 1 && !strcmp(argv[1], "-h"))
dd509db3 826 usage(_(reflog_usage));
99caeed0 827
cf39f54e
LT
828 /* With no command, we default to showing it. */
829 if (argc < 2 || *argv[1] == '-')
830 return cmd_log_reflog(argc, argv, prefix);
831
832 if (!strcmp(argv[1], "show"))
833 return cmd_log_reflog(argc - 1, argv + 1, prefix);
834
835 if (!strcmp(argv[1], "expire"))
4264dc15 836 return cmd_reflog_expire(argc - 1, argv + 1, prefix);
cf39f54e 837
552cecc2
JS
838 if (!strcmp(argv[1], "delete"))
839 return cmd_reflog_delete(argc - 1, argv + 1, prefix);
840
afcb2e7a
DT
841 if (!strcmp(argv[1], "exists"))
842 return cmd_reflog_exists(argc - 1, argv + 1, prefix);
843
bf01d4a3 844 return cmd_log_reflog(argc, argv, prefix);
4264dc15 845}