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