4 #include "object-store.h"
5 #include "repository.h"
12 #include "reachable.h"
15 static const char reflog_exists_usage
[] =
16 N_("git reflog exists <ref>");
18 static timestamp_t default_reflog_expire
;
19 static timestamp_t default_reflog_expire_unreachable
;
21 struct cmd_reflog_expire_cb
{
24 timestamp_t expire_total
;
25 timestamp_t expire_unreachable
;
29 struct expire_reflog_policy_cb
{
34 } unreachable_expire_kind
;
35 struct commit_list
*mark_list
;
36 unsigned long mark_limit
;
37 struct cmd_reflog_expire_cb cmd
;
38 struct commit
*tip_commit
;
39 struct commit_list
*tips
;
40 unsigned int dry_run
:1;
43 struct worktree_reflogs
{
44 struct worktree
*worktree
;
45 struct string_list reflogs
;
48 /* Remember to update object flag allocation in object.h */
49 #define INCOMPLETE (1u<<10)
50 #define STUDYING (1u<<11)
51 #define REACHABLE (1u<<12)
53 static int tree_is_complete(const struct object_id
*oid
)
55 struct tree_desc desc
;
56 struct name_entry entry
;
60 tree
= lookup_tree(the_repository
, oid
);
63 if (tree
->object
.flags
& SEEN
)
65 if (tree
->object
.flags
& INCOMPLETE
)
69 enum object_type type
;
71 void *data
= read_object_file(oid
, &type
, &size
);
73 tree
->object
.flags
|= INCOMPLETE
;
79 init_tree_desc(&desc
, tree
->buffer
, tree
->size
);
81 while (tree_entry(&desc
, &entry
)) {
82 if (!has_object_file(&entry
.oid
) ||
83 (S_ISDIR(entry
.mode
) && !tree_is_complete(&entry
.oid
))) {
84 tree
->object
.flags
|= INCOMPLETE
;
88 free_tree_buffer(tree
);
91 tree
->object
.flags
|= SEEN
;
95 static int commit_is_complete(struct commit
*commit
)
97 struct object_array study
;
98 struct object_array found
;
99 int is_incomplete
= 0;
103 if (commit
->object
.flags
& SEEN
)
105 if (commit
->object
.flags
& INCOMPLETE
)
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.
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
;
121 struct commit_list
*parent
;
123 c
= (struct commit
*)object_array_pop(&study
);
124 if (!c
->object
.parsed
&& !parse_object(the_repository
, &c
->object
.oid
))
125 c
->object
.flags
|= INCOMPLETE
;
127 if (c
->object
.flags
& INCOMPLETE
) {
131 else if (c
->object
.flags
& SEEN
)
133 for (parent
= c
->parents
; parent
; parent
= parent
->next
) {
134 struct commit
*p
= parent
->item
;
135 if (p
->object
.flags
& STUDYING
)
137 p
->object
.flags
|= STUDYING
;
138 add_object_array(&p
->object
, NULL
, &study
);
139 add_object_array(&p
->object
, NULL
, &found
);
142 if (!is_incomplete
) {
144 * make sure all commits in "found" array have all the
147 for (i
= 0; i
< found
.nr
; i
++) {
149 (struct commit
*)found
.objects
[i
].item
;
150 if (!tree_is_complete(get_commit_tree_oid(c
))) {
152 c
->object
.flags
|= INCOMPLETE
;
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
;
161 /* clear flags from the objects we traversed */
162 for (i
= 0; i
< found
.nr
; i
++)
163 found
.objects
[i
].item
->flags
&= ~STUDYING
;
165 commit
->object
.flags
|= INCOMPLETE
;
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.
175 for (i
= 0; i
< found
.nr
; i
++)
176 found
.objects
[i
].item
->flags
|= SEEN
;
178 /* free object arrays */
179 object_array_clear(&study
);
180 object_array_clear(&found
);
181 return !is_incomplete
;
184 static int keep_entry(struct commit
**it
, struct object_id
*oid
)
186 struct commit
*commit
;
188 if (is_null_oid(oid
))
190 commit
= lookup_commit_reference_gently(the_repository
, oid
, 1);
195 * Make sure everything in this commit exists.
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
202 if (!commit_is_complete(commit
))
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.
214 static void mark_reachable(struct expire_reflog_policy_cb
*cb
)
216 struct commit_list
*pending
;
217 timestamp_t expire_limit
= cb
->mark_limit
;
218 struct commit_list
*leftover
= NULL
;
220 for (pending
= cb
->mark_list
; pending
; pending
= pending
->next
)
221 pending
->item
->object
.flags
&= ~REACHABLE
;
223 pending
= cb
->mark_list
;
225 struct commit_list
*parent
;
226 struct commit
*commit
= pop_commit(&pending
);
227 if (commit
->object
.flags
& REACHABLE
)
229 if (parse_commit(commit
))
231 commit
->object
.flags
|= REACHABLE
;
232 if (commit
->date
< expire_limit
) {
233 commit_list_insert(commit
, &leftover
);
236 commit
->object
.flags
|= REACHABLE
;
237 parent
= commit
->parents
;
239 commit
= parent
->item
;
240 parent
= parent
->next
;
241 if (commit
->object
.flags
& REACHABLE
)
243 commit_list_insert(commit
, &pending
);
246 cb
->mark_list
= leftover
;
249 static int unreachable(struct expire_reflog_policy_cb
*cb
, struct commit
*commit
, struct object_id
*oid
)
252 * We may or may not have the commit yet - if not, look it
253 * up using the supplied sha1.
256 if (is_null_oid(oid
))
259 commit
= lookup_commit_reference_gently(the_repository
, oid
,
262 /* Not a commit -- keep it */
267 /* Reachable from the current ref? Don't prune. */
268 if (commit
->object
.flags
& REACHABLE
)
271 if (cb
->mark_list
&& cb
->mark_limit
) {
272 cb
->mark_limit
= 0; /* dig down to the root */
276 return !(commit
->object
.flags
& REACHABLE
);
280 * Return true iff the specified reflog entry should be expired.
282 static int should_expire_reflog_ent(struct object_id
*ooid
, struct object_id
*noid
,
283 const char *email
, timestamp_t timestamp
, int tz
,
284 const char *message
, void *cb_data
)
286 struct expire_reflog_policy_cb
*cb
= cb_data
;
287 struct commit
*old_commit
, *new_commit
;
289 if (timestamp
< cb
->cmd
.expire_total
)
292 old_commit
= new_commit
= NULL
;
293 if (cb
->cmd
.stalefix
&&
294 (!keep_entry(&old_commit
, ooid
) || !keep_entry(&new_commit
, noid
)))
297 if (timestamp
< cb
->cmd
.expire_unreachable
) {
298 switch (cb
->unreachable_expire_kind
) {
303 if (unreachable(cb
, old_commit
, ooid
) || unreachable(cb
, new_commit
, noid
))
309 if (cb
->cmd
.recno
&& --(cb
->cmd
.recno
) == 0)
315 static int should_expire_reflog_ent_verbose(struct object_id
*ooid
,
316 struct object_id
*noid
,
318 timestamp_t timestamp
, int tz
,
319 const char *message
, void *cb_data
)
321 struct expire_reflog_policy_cb
*cb
= cb_data
;
324 expire
= should_expire_reflog_ent(ooid
, noid
, email
, timestamp
, tz
,
328 printf("keep %s", message
);
329 else if (cb
->dry_run
)
330 printf("would prune %s", message
);
332 printf("prune %s", message
);
337 static int push_tip_to_list(const char *refname
, const struct object_id
*oid
,
338 int flags
, void *cb_data
)
340 struct commit_list
**list
= cb_data
;
341 struct commit
*tip_commit
;
342 if (flags
& REF_ISSYMREF
)
344 tip_commit
= lookup_commit_reference_gently(the_repository
, oid
, 1);
347 commit_list_insert(tip_commit
, list
);
351 static int is_head(const char *refname
)
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
);
362 return !strcmp(refname
, "HEAD");
365 static void reflog_expiry_prepare(const char *refname
,
366 const struct object_id
*oid
,
369 struct expire_reflog_policy_cb
*cb
= cb_data
;
370 struct commit_list
*elem
;
371 struct commit
*commit
= NULL
;
373 if (!cb
->cmd
.expire_unreachable
|| is_head(refname
)) {
374 cb
->unreachable_expire_kind
= UE_HEAD
;
376 commit
= lookup_commit(the_repository
, oid
);
377 cb
->unreachable_expire_kind
= commit
? UE_NORMAL
: UE_ALWAYS
;
380 if (cb
->cmd
.expire_unreachable
<= cb
->cmd
.expire_total
)
381 cb
->unreachable_expire_kind
= UE_ALWAYS
;
383 switch (cb
->unreachable_expire_kind
) {
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
);
392 commit_list_insert(commit
, &cb
->mark_list
);
393 /* For reflog_expiry_cleanup() below */
394 cb
->tip_commit
= commit
;
396 cb
->mark_limit
= cb
->cmd
.expire_total
;
400 static void reflog_expiry_cleanup(void *cb_data
)
402 struct expire_reflog_policy_cb
*cb
= cb_data
;
403 struct commit_list
*elem
;
405 switch (cb
->unreachable_expire_kind
) {
409 for (elem
= cb
->tips
; elem
; elem
= elem
->next
)
410 clear_commit_marks(elem
->item
, REACHABLE
);
411 free_commit_list(cb
->tips
);
414 clear_commit_marks(cb
->tip_commit
, REACHABLE
);
419 static int collect_reflog(const char *ref
, const struct object_id
*oid
, int unused
, void *cb_data
)
421 struct worktree_reflogs
*cb
= cb_data
;
422 struct worktree
*worktree
= cb
->worktree
;
423 struct strbuf newref
= STRBUF_INIT
;
426 * Avoid collecting the same shared ref multiple times because
427 * they are available via all worktrees.
429 if (!worktree
->is_current
&& ref_type(ref
) == REF_TYPE_NORMAL
)
432 strbuf_worktree_ref(worktree
, &newref
, ref
);
433 string_list_append_nodup(&cb
->reflogs
, strbuf_detach(&newref
, NULL
));
438 static struct reflog_expire_cfg
{
439 struct reflog_expire_cfg
*next
;
440 timestamp_t expire_total
;
441 timestamp_t expire_unreachable
;
442 char pattern
[FLEX_ARRAY
];
443 } *reflog_expire_cfg
, **reflog_expire_cfg_tail
;
445 static struct reflog_expire_cfg
*find_cfg_ent(const char *pattern
, size_t len
)
447 struct reflog_expire_cfg
*ent
;
449 if (!reflog_expire_cfg_tail
)
450 reflog_expire_cfg_tail
= &reflog_expire_cfg
;
452 for (ent
= reflog_expire_cfg
; ent
; ent
= ent
->next
)
453 if (!strncmp(ent
->pattern
, pattern
, len
) &&
454 ent
->pattern
[len
] == '\0')
457 FLEX_ALLOC_MEM(ent
, pattern
, pattern
, len
);
458 *reflog_expire_cfg_tail
= ent
;
459 reflog_expire_cfg_tail
= &(ent
->next
);
463 /* expiry timer slot */
464 #define EXPIRE_TOTAL 01
465 #define EXPIRE_UNREACH 02
467 static int reflog_expire_config(const char *var
, const char *value
, void *cb
)
469 const char *pattern
, *key
;
473 struct reflog_expire_cfg
*ent
;
475 if (parse_config_key(var
, "gc", &pattern
, &pattern_len
, &key
) < 0)
476 return git_default_config(var
, value
, cb
);
478 if (!strcmp(key
, "reflogexpire")) {
480 if (git_config_expiry_date(&expire
, var
, value
))
482 } else if (!strcmp(key
, "reflogexpireunreachable")) {
483 slot
= EXPIRE_UNREACH
;
484 if (git_config_expiry_date(&expire
, var
, value
))
487 return git_default_config(var
, value
, cb
);
492 default_reflog_expire
= expire
;
495 default_reflog_expire_unreachable
= expire
;
501 ent
= find_cfg_ent(pattern
, pattern_len
);
506 ent
->expire_total
= expire
;
509 ent
->expire_unreachable
= expire
;
515 static void set_reflog_expiry_param(struct cmd_reflog_expire_cb
*cb
, const char *ref
)
517 struct reflog_expire_cfg
*ent
;
519 if (cb
->explicit_expiry
== (EXPIRE_TOTAL
|EXPIRE_UNREACH
))
520 return; /* both given explicitly -- nothing to tweak */
522 for (ent
= reflog_expire_cfg
; ent
; ent
= ent
->next
) {
523 if (!wildmatch(ent
->pattern
, ref
, 0)) {
524 if (!(cb
->explicit_expiry
& EXPIRE_TOTAL
))
525 cb
->expire_total
= ent
->expire_total
;
526 if (!(cb
->explicit_expiry
& EXPIRE_UNREACH
))
527 cb
->expire_unreachable
= ent
->expire_unreachable
;
533 * If unconfigured, make stash never expire
535 if (!strcmp(ref
, "refs/stash")) {
536 if (!(cb
->explicit_expiry
& EXPIRE_TOTAL
))
537 cb
->expire_total
= 0;
538 if (!(cb
->explicit_expiry
& EXPIRE_UNREACH
))
539 cb
->expire_unreachable
= 0;
543 /* Nothing matched -- use the default value */
544 if (!(cb
->explicit_expiry
& EXPIRE_TOTAL
))
545 cb
->expire_total
= default_reflog_expire
;
546 if (!(cb
->explicit_expiry
& EXPIRE_UNREACH
))
547 cb
->expire_unreachable
= default_reflog_expire_unreachable
;
550 static 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>..."),
558 static int expire_unreachable_callback(const struct option
*opt
,
562 struct cmd_reflog_expire_cb
*cmd
= opt
->value
;
564 if (parse_expiry_date(arg
, &cmd
->expire_unreachable
))
565 die(_("invalid timestamp '%s' given to '--%s'"),
566 arg
, opt
->long_name
);
568 cmd
->explicit_expiry
|= EXPIRE_UNREACH
;
572 static int expire_total_callback(const struct option
*opt
,
576 struct cmd_reflog_expire_cb
*cmd
= opt
->value
;
578 if (parse_expiry_date(arg
, &cmd
->expire_total
))
579 die(_("invalid timestamp '%s' given to '--%s'"),
580 arg
, opt
->long_name
);
582 cmd
->explicit_expiry
|= EXPIRE_TOTAL
;
586 static int cmd_reflog_expire(int argc
, const char **argv
, const char *prefix
)
588 struct cmd_reflog_expire_cb cmd
= { 0 };
589 timestamp_t now
= time(NULL
);
590 int i
, status
, do_all
, all_worktrees
= 1;
591 unsigned int flags
= 0;
593 reflog_expiry_should_prune_fn
*should_prune_fn
= should_expire_reflog_ent
;
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"),
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"),
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.")),
620 default_reflog_expire_unreachable
= now
- 30 * 24 * 3600;
621 default_reflog_expire
= now
- 90 * 24 * 3600;
622 git_config(reflog_expire_config
, NULL
);
624 save_commit_buffer
= 0;
627 cmd
.explicit_expiry
= 0;
628 cmd
.expire_total
= default_reflog_expire
;
629 cmd
.expire_unreachable
= default_reflog_expire_unreachable
;
631 argc
= parse_options(argc
, argv
, prefix
, options
, reflog_expire_usage
, 0);
634 should_prune_fn
= should_expire_reflog_ent_verbose
;
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.
642 struct rev_info revs
;
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;
649 printf(_("Marking reachable objects..."));
650 mark_reachable_objects(&revs
, 0, 0, NULL
);
656 struct worktree_reflogs collected
= {
657 .reflogs
= STRING_LIST_INIT_DUP
,
659 struct string_list_item
*item
;
660 struct worktree
**worktrees
, **p
;
662 worktrees
= get_worktrees();
663 for (p
= worktrees
; *p
; p
++) {
664 if (!all_worktrees
&& !(*p
)->is_current
)
666 collected
.worktree
= *p
;
667 refs_for_each_reflog(get_worktree_ref_store(*p
),
668 collect_reflog
, &collected
);
670 free_worktrees(worktrees
);
672 for_each_string_list_item(item
, &collected
.reflogs
) {
673 struct expire_reflog_policy_cb cb
= {
675 .dry_run
= !!(flags
& EXPIRE_REFLOGS_DRY_RUN
),
678 set_reflog_expiry_param(&cb
.cmd
, item
->string
);
679 status
|= reflog_expire(item
->string
, flags
,
680 reflog_expiry_prepare
,
682 reflog_expiry_cleanup
,
685 string_list_clear(&collected
.reflogs
, 0);
688 for (i
= 0; i
< argc
; i
++) {
690 struct expire_reflog_policy_cb cb
= { .cmd
= cmd
};
692 if (!dwim_log(argv
[i
], strlen(argv
[i
]), NULL
, &ref
)) {
693 status
|= error(_("%s points nowhere!"), argv
[i
]);
696 set_reflog_expiry_param(&cb
.cmd
, ref
);
697 status
|= reflog_expire(ref
, flags
,
698 reflog_expiry_prepare
,
700 reflog_expiry_cleanup
,
707 static int count_reflog_ent(struct object_id
*ooid
, struct object_id
*noid
,
708 const char *email
, timestamp_t timestamp
, int tz
,
709 const char *message
, void *cb_data
)
711 struct cmd_reflog_expire_cb
*cb
= cb_data
;
712 if (!cb
->expire_total
|| timestamp
< cb
->expire_total
)
717 static const char * reflog_delete_usage
[] = {
718 N_("git reflog delete [--rewrite] [--updateref] "
719 "[--dry-run | -n] [--verbose] <refs>..."),
723 static int cmd_reflog_delete(int argc
, const char **argv
, const char *prefix
)
725 struct cmd_reflog_expire_cb cmd
= { 0 };
727 unsigned int flags
= 0;
729 reflog_expiry_should_prune_fn
*should_prune_fn
= should_expire_reflog_ent
;
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.")),
743 argc
= parse_options(argc
, argv
, prefix
, options
, reflog_delete_usage
, 0);
746 should_prune_fn
= should_expire_reflog_ent_verbose
;
749 return error(_("no reflog specified to delete"));
751 for (i
= 0; i
< argc
; i
++) {
752 const char *spec
= strstr(argv
[i
], "@{");
755 struct expire_reflog_policy_cb cb
= {
756 .dry_run
= !!(flags
& EXPIRE_REFLOGS_DRY_RUN
),
760 status
|= error(_("not a reflog: %s"), argv
[i
]);
764 if (!dwim_log(argv
[i
], spec
- argv
[i
], NULL
, &ref
)) {
765 status
|= error(_("no reflog for '%s'"), argv
[i
]);
769 recno
= strtoul(spec
+ 2, &ep
, 10);
772 for_each_reflog_ent(ref
, count_reflog_ent
, &cmd
);
774 cmd
.expire_total
= approxidate(spec
+ 2);
775 for_each_reflog_ent(ref
, count_reflog_ent
, &cmd
);
776 cmd
.expire_total
= 0;
780 status
|= reflog_expire(ref
, flags
,
781 reflog_expiry_prepare
,
783 reflog_expiry_cleanup
,
790 static int cmd_reflog_exists(int argc
, const char **argv
, const char *prefix
)
794 for (i
= 1; i
< argc
; i
++) {
795 const char *arg
= argv
[i
];
796 if (!strcmp(arg
, "--")) {
800 else if (arg
[0] == '-')
801 usage(_(reflog_exists_usage
));
808 if (argc
- start
!= 1)
809 usage(_(reflog_exists_usage
));
811 if (check_refname_format(argv
[start
], REFNAME_ALLOW_ONELEVEL
))
812 die(_("invalid ref format: %s"), argv
[start
]);
813 return !reflog_exists(argv
[start
]);
820 static const char reflog_usage
[] =
821 N_("git reflog [ show | expire | delete | exists ]");
823 int cmd_reflog(int argc
, const char **argv
, const char *prefix
)
825 if (argc
> 1 && !strcmp(argv
[1], "-h"))
826 usage(_(reflog_usage
));
828 /* With no command, we default to showing it. */
829 if (argc
< 2 || *argv
[1] == '-')
830 return cmd_log_reflog(argc
, argv
, prefix
);
832 if (!strcmp(argv
[1], "show"))
833 return cmd_log_reflog(argc
- 1, argv
+ 1, prefix
);
835 if (!strcmp(argv
[1], "expire"))
836 return cmd_reflog_expire(argc
- 1, argv
+ 1, prefix
);
838 if (!strcmp(argv
[1], "delete"))
839 return cmd_reflog_delete(argc
- 1, argv
+ 1, prefix
);
841 if (!strcmp(argv
[1], "exists"))
842 return cmd_reflog_exists(argc
- 1, argv
+ 1, prefix
);
844 return cmd_log_reflog(argc
, argv
, prefix
);