Added a description for my extensions (README-my-extensions.html).
[parsecvs/imz-RCS2git-use-cases.git] / parsecvs.c
blob30180edcd56dc284cc15a9a669c6955aef2c94cf
1 /*
2 * Copyright © 2006 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or (at
7 * your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
18 #include "cvs.h"
19 #include <unistd.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <errno.h>
23 #include <getopt.h>
25 #ifndef MAXPATHLEN
26 #define MAXPATHLEN 10240
27 #endif
29 cvs_file *this_file;
31 rev_execution_mode rev_mode = ExecuteGit;
33 int elide = 0;
34 int difffiles = 0;
35 int allfiles = 1;
37 const char *log_command;
39 void
40 dump_number_file (FILE *f, char *name, cvs_number *number)
42 int i;
43 fprintf (f, "%s ", name);
44 if (number) {
45 for (i = 0; i < number->c; i++) {
46 fprintf (f, "%d", number->n[i]);
47 if (i < number->c - 1) fprintf (f, ".");
52 void
53 dump_number (char *name, cvs_number *number)
55 dump_number_file (stdout, name, number);
58 void
59 dump_symbols (char *name, cvs_symbol *symbols)
61 printf ("%s\n", name);
62 while (symbols) {
63 printf ("\t");
64 dump_number (symbols->name, &symbols->number);
65 printf ("\n");
66 symbols = symbols->next;
70 void
71 dump_branches (char *name, cvs_branch *branches)
73 printf ("%s", name);
74 while (branches) {
75 dump_number (" ", &branches->number);
76 branches = branches->next;
78 printf ("\n");
81 void
82 dump_versions (char *name, cvs_version *versions)
84 printf ("%s\n", name);
85 while (versions) {
86 dump_number ("\tnumber:", &versions->number); printf ("\n");
87 printf ("\t\tdate: %s", ctime (&versions->date));
88 printf ("\t\tauthor: %s\n", versions->author);
89 dump_branches("\t\tbranches:", versions->branches);
90 dump_number ("\t\tparent: ", &versions->parent); printf ("\n");
91 if (versions->commitid)
92 printf ("\t\tcommitid: %s\n", versions->commitid);
93 printf ("\n");
94 versions = versions->next;
98 void
99 dump_patches (char *name, cvs_patch *patches)
101 printf ("%s\n", name);
102 while (patches) {
103 dump_number ("\tnumber: ", &patches->number); printf ("\n");
104 printf ("\t\tlog: %d bytes\n", (int)strlen (patches->log));
105 printf ("\t\ttext: %d bytes\n", (int)strlen (patches->text));
106 patches = patches->next;
110 void
111 dump_file (cvs_file *file)
113 dump_number ("head", &file->head); printf ("\n");
114 dump_number ("branch", &file->branch); printf ("\n");
115 dump_symbols ("symbols", file->symbols);
116 dump_versions ("versions", file->versions);
117 dump_patches ("patches", file->patches);
120 void
121 dump_log (FILE *f, char *log)
123 int j;
124 for (j = 0; j < 48; j++) {
125 if (log[j] == '\0')
126 break;
127 if (log[j] == '\n') {
128 if (j > 5) break;
129 continue;
131 if (log[j] & 0x80)
132 continue;
133 if (log[j] < ' ')
134 continue;
135 if (log[j] == '(' || log[j] == ')' ||
136 log[j] == '[' || log[j] == ']' ||
137 log[j] == '{' || log[j] == '}')
138 continue;
139 if (log[j] == '"')
140 putc ('\\', f);
141 putc (log[j], f);
142 if (log[j] == '.' && isspace (log[j+1]))
143 break;
147 void
148 dump_commit_graph (rev_commit *c, rev_ref *branch)
150 rev_file *f;
151 int i, j;
153 printf ("\"");
154 if (branch)
155 dump_ref_name (stdout, branch);
156 // if (c->tail)
157 // printf ("*** TAIL");
158 printf ("\\n");
159 printf ("%s\\n", ctime_nonl (&c->date));
160 dump_log (stdout, c->log);
161 printf ("\\n");
162 if (difffiles) {
163 rev_diff *diff = rev_commit_diff (c->parent, c);
164 rev_file_list *fl;
166 for (fl = diff->add; fl; fl = fl->next) {
167 if (!rev_file_list_has_filename (diff->del, fl->file->name)) {
168 printf ("+");
169 dump_number (fl->file->name, &fl->file->number);
170 printf ("\\n");
173 for (fl = diff->add; fl; fl = fl->next) {
174 if (rev_file_list_has_filename (diff->del, fl->file->name)) {
175 printf ("|");
176 dump_number (fl->file->name, &fl->file->number);
177 printf ("\\n");
180 for (fl = diff->del; fl; fl = fl->next) {
181 if (!rev_file_list_has_filename (diff->add, fl->file->name)) {
182 printf ("-");
183 dump_number (fl->file->name, &fl->file->number);
184 printf ("\\n");
187 rev_diff_free (diff);
188 } else {
189 if (!allfiles) {
190 dump_number (c->file->name, &c->file->number);
191 printf ("\\n");
192 } else {
193 for (i = 0; i < c->ndirs; i++) {
194 rev_dir *dir = c->dirs[i];
195 for (j = 0; j < dir->nfiles; j++) {
196 f = dir->files[j];
197 dump_number (f->name, &f->number);
198 printf ("\\n");
203 printf ("%p", c);
204 printf ("\"");
207 void
208 dump_ref_name (FILE *f, rev_ref *ref)
210 if (ref->parent) {
211 dump_ref_name (f, ref->parent);
212 fprintf (f, " > ");
214 fprintf (f, "%s", ref->name);
217 static void dump_tag_name(FILE *f, Tag *tag)
219 if (tag->parent) {
220 dump_ref_name (f, tag->parent);
221 fprintf (f, " > ");
223 fprintf (f, "%s", tag->name);
226 static
227 rev_ref *
228 dump_find_branch (rev_list *rl, rev_commit *commit)
230 rev_ref *h;
231 rev_commit *c;
233 for (h = rl->heads; h; h = h->next)
235 if (h->tail)
236 continue;
237 for (c = h->commit; c; c = c->parent)
239 if (c == commit)
240 return h;
241 if (c->tail)
242 break;
245 return NULL;
248 void
249 dump_refs (rev_list *rl, rev_ref *refs, char *title, char *shape)
251 rev_ref *r, *o;
252 int n;
254 for (r = refs; r; r = r->next) {
255 if (!r->shown) {
256 printf ("\t");
257 printf ("\"");
258 if (title)
259 printf ("%s\\n", title);
260 if (r->tail)
261 printf ("TAIL\\n");
262 n = 0;
263 for (o = r; o; o = o->next)
264 if (!o->shown && o->commit == r->commit)
266 o->shown = 1;
267 if (n)
268 printf ("\\n");
269 dump_ref_name (stdout, o);
270 printf (" (%d)", o->degree);
271 n++;
273 printf ("\" [fontsize=6,fixedsize=false,shape=%s];\n", shape);
276 for (r = refs; r; r = r->next)
277 r->shown = 0;
278 for (r = refs; r; r = r->next) {
279 if (!r->shown) {
280 printf ("\t");
281 printf ("\"");
282 if (title)
283 printf ("%s\\n", title);
284 if (r->tail)
285 printf ("TAIL\\n");
286 n = 0;
287 for (o = r; o; o = o->next)
288 if (!o->shown && o->commit == r->commit)
290 o->shown = 1;
291 if (n)
292 printf ("\\n");
293 dump_ref_name (stdout, o);
294 printf (" (%d)", o->degree);
295 n++;
297 printf ("\"");
298 printf (" -> ");
299 if (r->commit)
300 dump_commit_graph (r->commit, dump_find_branch (rl,
301 r->commit));
302 else
303 printf ("LOST");
304 printf (" [weight=%d];\n", !r->tail ? 100 : 3);
307 for (r = refs; r; r = r->next)
308 r->shown = 0;
311 static void dump_tags(rev_list *rl, char *title, char *shape)
313 Tag *r;
314 int n;
315 int i, count;
316 struct {
317 int alias;
318 Tag *t;
319 } *v;
321 for (r = all_tags, count = 0; r; r = r->next, count++)
324 v = calloc(count, sizeof(*v));
326 for (r = all_tags, i = 0; r; r = r->next)
327 v[i++].t = r;
329 for (i = 0; i < count; i++) {
330 if (v[i].alias)
331 continue;
332 r = v[i].t;
333 printf ("\t\"");
334 if (title)
335 printf ("%s\\n", title);
336 dump_tag_name(stdout, r);
337 for (n = i + 1; n < count; n++) {
338 if (v[n].t->commit == r->commit) {
339 v[n].alias = 1;
340 printf ("\\n");
341 dump_tag_name(stdout, v[n].t);
344 printf ("\" [fontsize=6,fixedsize=false,shape=%s];\n", shape);
346 for (i = 0; i < count; i++) {
347 if (v[i].alias)
348 continue;
349 r = v[i].t;
350 printf ("\t\"");
351 if (title)
352 printf ("%s\\n", title);
353 dump_tag_name(stdout, r);
354 for (n = i + 1; n < count; n++) {
355 if (v[n].alias && v[n].t->commit == r->commit) {
356 printf ("\\n");
357 dump_tag_name(stdout, v[n].t);
360 printf ("\" -> ");
361 if (r->commit)
362 dump_commit_graph (r->commit, dump_find_branch (rl, r->commit));
363 else
364 printf ("LOST");
365 printf (" [weight=3];\n");
367 free(v);
370 static rev_commit *
371 dump_get_rev_parent (rev_commit *c)
373 int seen = c->seen;
375 c = c->parent;
376 while (elide && c && c->seen == seen && !c->tail && !c->tagged)
377 c = c->parent;
378 return c;
381 void
382 dump_rev_graph_nodes (rev_list *rl, char *title)
384 rev_ref *h;
385 rev_commit *c, *p;
386 int tail;
388 printf ("nodesep=0.1;\n");
389 printf ("ranksep=0.1;\n");
390 printf ("edge [dir=none];\n");
391 printf ("node [shape=box,fontsize=6];\n");
392 dump_refs (rl, rl->heads, title, "ellipse");
393 dump_tags (rl, title, "diamond");
394 for (h = rl->heads; h; h = h->next) {
395 if (h->tail)
396 continue;
397 for (c = h->commit; c; c = p) {
398 p = dump_get_rev_parent (c);
399 tail = c->tail;
400 if (!p)
401 break;
402 printf ("\t");
403 dump_commit_graph (c, h);
404 printf (" -> ");
405 dump_commit_graph (p, tail ? h->parent : h);
406 if (!tail)
407 printf (" [weight=10];");
408 printf ("\n");
409 if (tail)
410 break;
415 void
416 dump_rev_graph_begin ()
418 printf ("digraph G {\n");
421 void
422 dump_rev_graph_end ()
424 printf ("}\n");
427 void
428 dump_rev_graph (rev_list *rl, char *title)
430 dump_rev_graph_begin ();
431 dump_rev_graph_nodes (rl, title);
432 dump_rev_graph_end ();
435 void
436 dump_rev_commit (rev_commit *c)
438 rev_file *f;
439 int i, j;
441 for (i = 0; i < c->ndirs; i++) {
442 rev_dir *dir = c->dirs[i];
444 for (j = 0; j < dir->nfiles; j++) {
445 f = dir->files[j];
446 dump_number (f->name, &f->number);
447 printf (" ");
450 printf ("\n");
453 void
454 dump_rev_head (rev_ref *h)
456 rev_commit *c;
457 for (c = h->commit; c; c = c->parent) {
458 dump_rev_commit (c);
459 if (c->tail)
460 break;
464 void
465 dump_rev_list (rev_list *rl)
467 rev_ref *h;
469 for (h = rl->heads; h; h = h->next) {
470 if (h->tail)
471 continue;
472 dump_rev_head (h);
476 extern FILE *yyin;
477 static int err = 0;
478 char *yyfilename;
479 extern int yylineno;
481 static rev_list *
482 rev_list_file (char *name, int *nversions)
484 rev_list *rl;
485 struct stat buf;
487 yyin = fopen (name, "r");
488 if (!yyin) {
489 perror (name);
490 ++err;
492 yyfilename = name;
493 yylineno = 0;
494 this_file = calloc (1, sizeof (cvs_file));
495 this_file->name = name;
496 if (yyin)
497 assert (fstat (fileno (yyin), &buf) == 0);
498 this_file->mode = buf.st_mode;
499 yyparse ();
500 fclose (yyin);
501 yyfilename = 0;
502 rl = rev_list_cvs (this_file);
504 *nversions = this_file->nversions;
505 cvs_file_free (this_file);
506 return rl;
509 typedef struct _rev_split {
510 struct _rev_split *next;
511 rev_commit *childa, *childb;
512 rev_commit *parent;
513 rev_commit *topa, *topb;
514 } rev_split;
516 char *
517 ctime_nonl (time_t *date)
519 char *d = ctime (date);
521 d[strlen(d)-1] = '\0';
522 return d;
525 void
526 dump_splits (rev_list *rl)
528 #if 0
529 rev_split *splits = NULL, *s;
530 rev_ref *head;
531 rev_commit *c, *a, *b;
532 int ai, bi;
533 rev_file *af, *bf;
534 char *which;
536 /* Find tails and mark splits */
537 for (head = rl->heads; head; head = head->next) {
538 if (head->tail)
539 continue;
540 for (c = head->commit; c; c = c->parent)
541 if (c->tail) {
542 for (s = splits; s; s = s->next)
543 if (s->parent == c->parent)
544 break;
545 if (!s) {
546 s = calloc (1, sizeof (rev_split));
547 s->parent = c->parent;
548 s->childa = c;
549 s->topa = head->commit;
550 s->next = splits;
551 splits = s;
555 /* Find join points */
556 for (s = splits; s; s = s->next) {
557 for (head = rl->heads; head; head = head->next) {
558 if (head->tail)
559 continue;
560 for (c = head->commit; c; c = c->parent) {
561 if (c->parent == s->parent && c != s->childa) {
562 s->childb = c;
563 s->topb = head->commit;
568 for (s = splits; s; s = s->next) {
569 if (s->parent && s->childa && s->childb) {
570 for (head = rl->heads; head; head = head->next) {
571 if (head->commit == s->topa)
572 fprintf (stderr, "%s ", head->name);
574 fprintf (stderr, "->");
575 for (head = rl->heads; head; head = head->next) {
576 if (head->commit == s->topb)
577 fprintf (stderr, "%s ", head->name);
579 fprintf (stderr, "\n");
580 a = s->childa;
581 b = s->childb;
582 ai = bi = 0;
583 while (ai < a->nfiles && bi < b->nfiles) {
584 af = a->files[ai];
585 bf = b->files[bi];
586 if (af != bf) {
587 if (rev_file_later (af, bf)) {
588 fprintf (stderr, "a : %s ", ctime_nonl (&af->date));
589 dump_number_file (stderr, af->name, &af->number);
590 ai++;
591 } else {
592 fprintf (stderr, " b: %s ", ctime_nonl (&bf->date));
593 dump_number_file (stderr, bf->name, &bf->number);
594 bi++;
596 fprintf (stderr, "\n");
597 } else {
598 // fprintf (stderr, "ab: %s ", ctime_nonl (&af->date));
599 // dump_number_file (stderr, af->name, &af->number);
600 // fprintf (stderr, "\n");
601 ai++;
602 bi++;
605 which = "a ";
606 if (ai >= a->nfiles) {
607 a = b;
608 ai = bi;
609 which = " b";
611 while (ai < a->nfiles) {
612 af = a->files[ai];
613 fprintf (stderr, "%s: ", which);
614 dump_number_file (stderr, af->name, &af->number);
615 fprintf (stderr, "\n");
616 ai++;
620 #endif
623 void
624 dump_rev_tree (rev_list *rl)
626 rev_ref *h;
627 rev_ref *oh;
628 rev_commit *c, *p;
629 int tail;
631 printf ("rev_list {\n");
633 for (h = rl->heads; h; h = h->next) {
634 if (h->tail)
635 continue;
636 for (oh = rl->heads; oh; oh = oh->next) {
637 if (h->commit == oh->commit)
638 printf ("%s:\n", oh->name);
640 printf ("\t{\n");
641 tail = h->tail;
642 for (c = h->commit; c; c = p) {
643 printf ("\t\t%p ", c);
644 dump_log (stdout, c->log);
645 if (tail) {
646 printf ("\n\t\t...\n");
647 break;
649 printf (" {\n");
651 p = c->parent;
652 #if 0
653 if (p && c->nfiles > 16) {
654 rev_file *ef, *pf;
655 int ei, pi;
656 ei = pi = 0;
657 while (ei < c->nfiles && pi < p->nfiles) {
658 ef = c->files[ei];
659 pf = p->files[pi];
660 if (ef != pf) {
661 if (rev_file_later (ef, pf)) {
662 fprintf (stdout, "+ ");
663 dump_number_file (stdout, ef->name, &ef->number);
664 ei++;
665 } else {
666 fprintf (stdout, "- ");
667 dump_number_file (stdout, pf->name, &pf->number);
668 pi++;
670 fprintf (stdout, "\n");
671 } else {
672 ei++;
673 pi++;
676 while (ei < c->nfiles) {
677 ef = c->files[ei];
678 fprintf (stdout, "+ ");
679 dump_number_file (stdout, ef->name, &ef->number);
680 ei++;
681 fprintf (stdout, "\n");
683 while (pi < p->nfiles) {
684 pf = p->files[pi];
685 fprintf (stdout, "- ");
686 dump_number_file (stdout, pf->name, &pf->number);
687 pi++;
688 fprintf (stdout, "\n");
690 } else {
691 for (i = 0; i < c->nfiles; i++) {
692 printf ("\t\t\t");
693 dump_number (c->files[i]->name, &c->files[i]->number);
694 printf ("\n");
697 #endif
698 printf ("\t\t}\n");
699 tail = c->tail;
700 #if 0
701 if (time_compare (c->date, 1079499163) <= 0) {
702 printf ("\t\t...\n");
703 break;
705 #endif
707 printf ("\t}\n");
709 printf ("}\n");
712 time_t time_now;
714 static int
715 strcommon (char *a, char *b)
717 int c = 0;
719 while (*a == *b) {
720 if (!*a)
721 break;
722 a++;
723 b++;
724 c++;
726 return c;
729 typedef struct _rev_filename {
730 struct _rev_filename *next;
731 char *file;
732 } rev_filename;
734 #define STATUS stdout
735 #define PROGRESS_LEN 20
736 static int load_current_file, load_total_files;
738 static void load_status (char *name)
740 int spot = load_current_file * PROGRESS_LEN / load_total_files;
741 int s;
742 int l;
744 if (rev_mode == ExecuteGraph)
745 return;
746 l = strlen (name);
747 if (l > 35) name += l - 35;
749 fprintf (STATUS, "Load: %35.35s ", name);
750 for (s = 0; s < PROGRESS_LEN + 1; s++)
751 putc (s == spot ? '*' : '.', STATUS);
752 fprintf (STATUS, " %5d of %5d\n", load_current_file, load_total_files);
753 fflush (STATUS);
756 static void load_status_next (void)
758 if (rev_mode == ExecuteGraph)
759 return;
760 fprintf (STATUS, "\n");
761 fflush (STATUS);
764 int commit_time_window = 60;
765 static int obj_pack_time = 0;
768 main (int argc, char **argv)
770 rev_filename *fn_head, **fn_tail = &fn_head, *fn;
771 rev_list *head, **tail = &head;
772 rev_list *rl;
773 int j = 1;
774 char name[10240], *last = NULL;
775 int strip = -1;
776 int c;
777 char *file;
778 int nfile = 0;
779 rev_list *pack_start = NULL;
780 int pack_objcount = 0;
782 while (1) {
783 static struct option options[] = {
784 { "help", 0, 0, 'h' },
785 { "version", 0, 0, 'V' },
786 { "commit-time-window", 1, 0, 'w' },
787 { "log-command", 1, 0, 'l' },
788 { "autopack", 1, 0, 'p' },
790 int c = getopt_long(argc, argv, "+hVw:l:p:", options, NULL);
791 if (c < 0)
792 break;
793 switch (c) {
794 case 'h':
795 printf("Usage: parsecvs [OPTIONS] [FILE]...\n"
796 "Parse RCS files and populate git repository.\n\n"
797 "Mandatory arguments to long options are mandatory for short options too.\n"
798 " -h --help This help\n"
799 " -l --log-command=COMMAND Call COMMAND to handle changelogs\n"
800 " -p --autopack=NUM Auto-pack for every NUM objects. 0 disables.\n"
802 " -v --version Print version\n"
803 " -w --commit-time-window=WINDOW Time window for commits\n\n"
804 "Example: find -name '*,v' | parsecvs -l edit-change-log -p 1024\n");
805 return 0;
806 case 'l':
807 log_command = strdup (optarg);
808 break;
809 case 'p':
810 obj_pack_time = atoi (optarg);
811 break;
812 case 'V':
813 printf("parsecvs version 0.1\n"
814 "\n"
815 "Copyright (c) 2006 Keith Packard <keithp@keithp.com>.\n"
816 "This is free software; see the source for copying conditions. There is NO\n"
817 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
818 return 0;
819 case 'w':
820 commit_time_window = atoi (optarg);
821 break;
822 default: /* error message already emitted */
823 fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
824 return 1;
828 argv[optind-1] = argv[0];
829 argv += optind-1;
830 argc -= optind-1;
832 /* force times using mktime to be interpreted in UTC */
833 setenv ("TZ", "UTC", 1);
834 time_now = time (NULL);
835 for (;;)
837 if (argc < 2) {
838 int l;
839 if (fgets (name, sizeof (name) - 1, stdin) == NULL)
840 break;
841 l = strlen (name);
842 if (name[l-1] == '\n')
843 name[l-1] = '\0';
844 file = name;
845 } else {
846 file = argv[j++];
847 if (!file)
848 break;
850 fn = calloc (1, sizeof (rev_filename));
851 fn->file = atom (file);
852 *fn_tail = fn;
853 fn_tail = &fn->next;
854 if (strip > 0) {
855 c = strcommon (fn->file, last);
856 if (c < strip)
857 strip = c;
858 } else if (strip < 0) {
859 int i;
861 strip = 0;
862 for (i = 0; i < strlen (fn->file); i++)
863 if (fn->file[i] == '/')
864 strip = i + 1;
866 last = fn->file;
867 nfile++;
869 if (git_system ("git init --shared") != 0)
870 exit (1);
871 load_total_files = nfile;
872 load_current_file = 0;
873 while (fn_head) {
874 int nversions;
876 fn = fn_head;
877 fn_head = fn_head->next;
878 ++load_current_file;
879 load_status (fn->file + strip);
880 rl = rev_list_file (fn->file, &nversions);
881 if (rl->watch)
882 dump_rev_tree (rl);
883 *tail = rl;
884 tail = &rl->next;
886 if (rev_mode == ExecuteGit && obj_pack_time)
889 * Pack objects on occasion to reduce .git directory
890 * cost
892 if (!pack_start)
893 pack_start = rl;
894 pack_objcount += nversions;
895 if (pack_objcount > obj_pack_time)
897 git_rev_list_pack (pack_start, strip);
898 pack_start = NULL;
899 pack_objcount = 0;
903 free(fn);
905 if (rev_mode == ExecuteGit && pack_objcount && obj_pack_time)
906 git_rev_list_pack (pack_start, strip);
907 load_status_next ();
908 init_tree(strip);
909 rl = rev_list_merge (head);
910 if (rl) {
911 switch (rev_mode) {
912 case ExecuteGraph:
913 dump_rev_graph (rl, NULL);
914 break;
915 case ExecuteSplits:
916 dump_splits (rl);
917 break;
918 case ExecuteGit:
919 git_rev_list_commit (rl, strip);
920 break;
923 if (rl)
924 rev_list_free (rl, 0);
925 while (head) {
926 rl = head;
927 head = head->next;
928 rev_list_free (rl, 1);
930 discard_atoms ();
931 discard_tags ();
932 discard_tree ();
933 rev_free_dirs ();
934 rev_commit_cleanup ();
935 git_free_author_map ();
936 return err;