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