Interested in helping open source friends on HP-UX?
[git/mjg.git] / builtin / fast-export.c
blobb8182c241dad4fd7221432cb5b40674f76789be4
1 /*
2 * "git fast-export" builtin command
4 * Copyright (C) 2007 Johannes E. Schindelin
5 */
6 #include "builtin.h"
7 #include "cache.h"
8 #include "commit.h"
9 #include "object.h"
10 #include "tag.h"
11 #include "diff.h"
12 #include "diffcore.h"
13 #include "log-tree.h"
14 #include "revision.h"
15 #include "decorate.h"
16 #include "string-list.h"
17 #include "utf8.h"
18 #include "parse-options.h"
19 #include "quote.h"
20 #include "remote.h"
21 #include "blob.h"
23 static const char *fast_export_usage[] = {
24 N_("git fast-export [rev-list-opts]"),
25 NULL
28 static int progress;
29 static enum { ABORT, VERBATIM, WARN, WARN_STRIP, STRIP } signed_tag_mode = ABORT;
30 static enum { ERROR, DROP, REWRITE } tag_of_filtered_mode = ERROR;
31 static int fake_missing_tagger;
32 static int use_done_feature;
33 static int no_data;
34 static int full_tree;
35 static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
36 static struct refspec *refspecs;
37 static int refspecs_nr;
38 static int anonymize;
40 static int parse_opt_signed_tag_mode(const struct option *opt,
41 const char *arg, int unset)
43 if (unset || !strcmp(arg, "abort"))
44 signed_tag_mode = ABORT;
45 else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore"))
46 signed_tag_mode = VERBATIM;
47 else if (!strcmp(arg, "warn"))
48 signed_tag_mode = WARN;
49 else if (!strcmp(arg, "warn-strip"))
50 signed_tag_mode = WARN_STRIP;
51 else if (!strcmp(arg, "strip"))
52 signed_tag_mode = STRIP;
53 else
54 return error("Unknown signed-tags mode: %s", arg);
55 return 0;
58 static int parse_opt_tag_of_filtered_mode(const struct option *opt,
59 const char *arg, int unset)
61 if (unset || !strcmp(arg, "abort"))
62 tag_of_filtered_mode = ERROR;
63 else if (!strcmp(arg, "drop"))
64 tag_of_filtered_mode = DROP;
65 else if (!strcmp(arg, "rewrite"))
66 tag_of_filtered_mode = REWRITE;
67 else
68 return error("Unknown tag-of-filtered mode: %s", arg);
69 return 0;
72 static struct decoration idnums;
73 static uint32_t last_idnum;
75 static int has_unshown_parent(struct commit *commit)
77 struct commit_list *parent;
79 for (parent = commit->parents; parent; parent = parent->next)
80 if (!(parent->item->object.flags & SHOWN) &&
81 !(parent->item->object.flags & UNINTERESTING))
82 return 1;
83 return 0;
86 struct anonymized_entry {
87 struct hashmap_entry hash;
88 const char *orig;
89 size_t orig_len;
90 const char *anon;
91 size_t anon_len;
94 static int anonymized_entry_cmp(const void *va, const void *vb,
95 const void *data)
97 const struct anonymized_entry *a = va, *b = vb;
98 return a->orig_len != b->orig_len ||
99 memcmp(a->orig, b->orig, a->orig_len);
103 * Basically keep a cache of X->Y so that we can repeatedly replace
104 * the same anonymized string with another. The actual generation
105 * is farmed out to the generate function.
107 static const void *anonymize_mem(struct hashmap *map,
108 void *(*generate)(const void *, size_t *),
109 const void *orig, size_t *len)
111 struct anonymized_entry key, *ret;
113 if (!map->cmpfn)
114 hashmap_init(map, anonymized_entry_cmp, 0);
116 hashmap_entry_init(&key, memhash(orig, *len));
117 key.orig = orig;
118 key.orig_len = *len;
119 ret = hashmap_get(map, &key, NULL);
121 if (!ret) {
122 ret = xmalloc(sizeof(*ret));
123 hashmap_entry_init(&ret->hash, key.hash.hash);
124 ret->orig = xstrdup(orig);
125 ret->orig_len = *len;
126 ret->anon = generate(orig, len);
127 ret->anon_len = *len;
128 hashmap_put(map, ret);
131 *len = ret->anon_len;
132 return ret->anon;
136 * We anonymize each component of a path individually,
137 * so that paths a/b and a/c will share a common root.
138 * The paths are cached via anonymize_mem so that repeated
139 * lookups for "a" will yield the same value.
141 static void anonymize_path(struct strbuf *out, const char *path,
142 struct hashmap *map,
143 void *(*generate)(const void *, size_t *))
145 while (*path) {
146 const char *end_of_component = strchrnul(path, '/');
147 size_t len = end_of_component - path;
148 const char *c = anonymize_mem(map, generate, path, &len);
149 strbuf_add(out, c, len);
150 path = end_of_component;
151 if (*path)
152 strbuf_addch(out, *path++);
156 /* Since intptr_t is C99, we do not use it here */
157 static inline uint32_t *mark_to_ptr(uint32_t mark)
159 return ((uint32_t *)NULL) + mark;
162 static inline uint32_t ptr_to_mark(void * mark)
164 return (uint32_t *)mark - (uint32_t *)NULL;
167 static inline void mark_object(struct object *object, uint32_t mark)
169 add_decoration(&idnums, object, mark_to_ptr(mark));
172 static inline void mark_next_object(struct object *object)
174 mark_object(object, ++last_idnum);
177 static int get_object_mark(struct object *object)
179 void *decoration = lookup_decoration(&idnums, object);
180 if (!decoration)
181 return 0;
182 return ptr_to_mark(decoration);
185 static void show_progress(void)
187 static int counter = 0;
188 if (!progress)
189 return;
190 if ((++counter % progress) == 0)
191 printf("progress %d objects\n", counter);
195 * Ideally we would want some transformation of the blob data here
196 * that is unreversible, but would still be the same size and have
197 * the same data relationship to other blobs (so that we get the same
198 * delta and packing behavior as the original). But the first and last
199 * requirements there are probably mutually exclusive, so let's take
200 * the easy way out for now, and just generate arbitrary content.
202 * There's no need to cache this result with anonymize_mem, since
203 * we already handle blob content caching with marks.
205 static char *anonymize_blob(unsigned long *size)
207 static int counter;
208 struct strbuf out = STRBUF_INIT;
209 strbuf_addf(&out, "anonymous blob %d", counter++);
210 *size = out.len;
211 return strbuf_detach(&out, NULL);
214 static void export_blob(const unsigned char *sha1)
216 unsigned long size;
217 enum object_type type;
218 char *buf;
219 struct object *object;
220 int eaten;
222 if (no_data)
223 return;
225 if (is_null_sha1(sha1))
226 return;
228 object = lookup_object(sha1);
229 if (object && object->flags & SHOWN)
230 return;
232 if (anonymize) {
233 buf = anonymize_blob(&size);
234 object = (struct object *)lookup_blob(sha1);
235 eaten = 0;
236 } else {
237 buf = read_sha1_file(sha1, &type, &size);
238 if (!buf)
239 die ("Could not read blob %s", sha1_to_hex(sha1));
240 if (check_sha1_signature(sha1, buf, size, typename(type)) < 0)
241 die("sha1 mismatch in blob %s", sha1_to_hex(sha1));
242 object = parse_object_buffer(sha1, type, size, buf, &eaten);
245 if (!object)
246 die("Could not read blob %s", sha1_to_hex(sha1));
248 mark_next_object(object);
250 printf("blob\nmark :%"PRIu32"\ndata %lu\n", last_idnum, size);
251 if (size && fwrite(buf, size, 1, stdout) != 1)
252 die_errno ("Could not write blob '%s'", sha1_to_hex(sha1));
253 printf("\n");
255 show_progress();
257 object->flags |= SHOWN;
258 if (!eaten)
259 free(buf);
262 static int depth_first(const void *a_, const void *b_)
264 const struct diff_filepair *a = *((const struct diff_filepair **)a_);
265 const struct diff_filepair *b = *((const struct diff_filepair **)b_);
266 const char *name_a, *name_b;
267 int len_a, len_b, len;
268 int cmp;
270 name_a = a->one ? a->one->path : a->two->path;
271 name_b = b->one ? b->one->path : b->two->path;
273 len_a = strlen(name_a);
274 len_b = strlen(name_b);
275 len = (len_a < len_b) ? len_a : len_b;
277 /* strcmp will sort 'd' before 'd/e', we want 'd/e' before 'd' */
278 cmp = memcmp(name_a, name_b, len);
279 if (cmp)
280 return cmp;
281 cmp = len_b - len_a;
282 if (cmp)
283 return cmp;
285 * Move 'R'ename entries last so that all references of the file
286 * appear in the output before it is renamed (e.g., when a file
287 * was copied and renamed in the same commit).
289 return (a->status == 'R') - (b->status == 'R');
292 static void print_path_1(const char *path)
294 int need_quote = quote_c_style(path, NULL, NULL, 0);
295 if (need_quote)
296 quote_c_style(path, NULL, stdout, 0);
297 else if (strchr(path, ' '))
298 printf("\"%s\"", path);
299 else
300 printf("%s", path);
303 static void *anonymize_path_component(const void *path, size_t *len)
305 static int counter;
306 struct strbuf out = STRBUF_INIT;
307 strbuf_addf(&out, "path%d", counter++);
308 return strbuf_detach(&out, len);
311 static void print_path(const char *path)
313 if (!anonymize)
314 print_path_1(path);
315 else {
316 static struct hashmap paths;
317 static struct strbuf anon = STRBUF_INIT;
319 anonymize_path(&anon, path, &paths, anonymize_path_component);
320 print_path_1(anon.buf);
321 strbuf_reset(&anon);
325 static void *generate_fake_sha1(const void *old, size_t *len)
327 static uint32_t counter = 1; /* avoid null sha1 */
328 unsigned char *out = xcalloc(20, 1);
329 put_be32(out + 16, counter++);
330 return out;
333 static const unsigned char *anonymize_sha1(const unsigned char *sha1)
335 static struct hashmap sha1s;
336 size_t len = 20;
337 return anonymize_mem(&sha1s, generate_fake_sha1, sha1, &len);
340 static void show_filemodify(struct diff_queue_struct *q,
341 struct diff_options *options, void *data)
343 int i;
346 * Handle files below a directory first, in case they are all deleted
347 * and the directory changes to a file or symlink.
349 qsort(q->queue, q->nr, sizeof(q->queue[0]), depth_first);
351 for (i = 0; i < q->nr; i++) {
352 struct diff_filespec *ospec = q->queue[i]->one;
353 struct diff_filespec *spec = q->queue[i]->two;
355 switch (q->queue[i]->status) {
356 case DIFF_STATUS_DELETED:
357 printf("D ");
358 print_path(spec->path);
359 putchar('\n');
360 break;
362 case DIFF_STATUS_COPIED:
363 case DIFF_STATUS_RENAMED:
364 printf("%c ", q->queue[i]->status);
365 print_path(ospec->path);
366 putchar(' ');
367 print_path(spec->path);
368 putchar('\n');
370 if (!hashcmp(ospec->sha1, spec->sha1) &&
371 ospec->mode == spec->mode)
372 break;
373 /* fallthrough */
375 case DIFF_STATUS_TYPE_CHANGED:
376 case DIFF_STATUS_MODIFIED:
377 case DIFF_STATUS_ADDED:
379 * Links refer to objects in another repositories;
380 * output the SHA-1 verbatim.
382 if (no_data || S_ISGITLINK(spec->mode))
383 printf("M %06o %s ", spec->mode,
384 sha1_to_hex(anonymize ?
385 anonymize_sha1(spec->sha1) :
386 spec->sha1));
387 else {
388 struct object *object = lookup_object(spec->sha1);
389 printf("M %06o :%d ", spec->mode,
390 get_object_mark(object));
392 print_path(spec->path);
393 putchar('\n');
394 break;
396 default:
397 die("Unexpected comparison status '%c' for %s, %s",
398 q->queue[i]->status,
399 ospec->path ? ospec->path : "none",
400 spec->path ? spec->path : "none");
405 static const char *find_encoding(const char *begin, const char *end)
407 const char *needle = "\nencoding ";
408 char *bol, *eol;
410 bol = memmem(begin, end ? end - begin : strlen(begin),
411 needle, strlen(needle));
412 if (!bol)
413 return git_commit_encoding;
414 bol += strlen(needle);
415 eol = strchrnul(bol, '\n');
416 *eol = '\0';
417 return bol;
420 static void *anonymize_ref_component(const void *old, size_t *len)
422 static int counter;
423 struct strbuf out = STRBUF_INIT;
424 strbuf_addf(&out, "ref%d", counter++);
425 return strbuf_detach(&out, len);
428 static const char *anonymize_refname(const char *refname)
431 * If any of these prefixes is found, we will leave it intact
432 * so that tags remain tags and so forth.
434 static const char *prefixes[] = {
435 "refs/heads/",
436 "refs/tags/",
437 "refs/remotes/",
438 "refs/"
440 static struct hashmap refs;
441 static struct strbuf anon = STRBUF_INIT;
442 int i;
445 * We also leave "master" as a special case, since it does not reveal
446 * anything interesting.
448 if (!strcmp(refname, "refs/heads/master"))
449 return refname;
451 strbuf_reset(&anon);
452 for (i = 0; i < ARRAY_SIZE(prefixes); i++) {
453 if (skip_prefix(refname, prefixes[i], &refname)) {
454 strbuf_addstr(&anon, prefixes[i]);
455 break;
459 anonymize_path(&anon, refname, &refs, anonymize_ref_component);
460 return anon.buf;
464 * We do not even bother to cache commit messages, as they are unlikely
465 * to be repeated verbatim, and it is not that interesting when they are.
467 static char *anonymize_commit_message(const char *old)
469 static int counter;
470 return xstrfmt("subject %d\n\nbody\n", counter++);
473 static struct hashmap idents;
474 static void *anonymize_ident(const void *old, size_t *len)
476 static int counter;
477 struct strbuf out = STRBUF_INIT;
478 strbuf_addf(&out, "User %d <user%d@example.com>", counter, counter);
479 counter++;
480 return strbuf_detach(&out, len);
484 * Our strategy here is to anonymize the names and email addresses,
485 * but keep timestamps intact, as they influence things like traversal
486 * order (and by themselves should not be too revealing).
488 static void anonymize_ident_line(const char **beg, const char **end)
490 static struct strbuf buffers[] = { STRBUF_INIT, STRBUF_INIT };
491 static unsigned which_buffer;
493 struct strbuf *out;
494 struct ident_split split;
495 const char *end_of_header;
497 out = &buffers[which_buffer++];
498 which_buffer %= ARRAY_SIZE(buffers);
499 strbuf_reset(out);
501 /* skip "committer", "author", "tagger", etc */
502 end_of_header = strchr(*beg, ' ');
503 if (!end_of_header)
504 die("BUG: malformed line fed to anonymize_ident_line: %.*s",
505 (int)(*end - *beg), *beg);
506 end_of_header++;
507 strbuf_add(out, *beg, end_of_header - *beg);
509 if (!split_ident_line(&split, end_of_header, *end - end_of_header) &&
510 split.date_begin) {
511 const char *ident;
512 size_t len;
514 len = split.mail_end - split.name_begin;
515 ident = anonymize_mem(&idents, anonymize_ident,
516 split.name_begin, &len);
517 strbuf_add(out, ident, len);
518 strbuf_addch(out, ' ');
519 strbuf_add(out, split.date_begin, split.tz_end - split.date_begin);
520 } else {
521 strbuf_addstr(out, "Malformed Ident <malformed@example.com> 0 -0000");
524 *beg = out->buf;
525 *end = out->buf + out->len;
528 static void handle_commit(struct commit *commit, struct rev_info *rev)
530 int saved_output_format = rev->diffopt.output_format;
531 const char *commit_buffer;
532 const char *author, *author_end, *committer, *committer_end;
533 const char *encoding, *message;
534 char *reencoded = NULL;
535 struct commit_list *p;
536 const char *refname;
537 int i;
539 rev->diffopt.output_format = DIFF_FORMAT_CALLBACK;
541 parse_commit_or_die(commit);
542 commit_buffer = get_commit_buffer(commit, NULL);
543 author = strstr(commit_buffer, "\nauthor ");
544 if (!author)
545 die ("Could not find author in commit %s",
546 sha1_to_hex(commit->object.sha1));
547 author++;
548 author_end = strchrnul(author, '\n');
549 committer = strstr(author_end, "\ncommitter ");
550 if (!committer)
551 die ("Could not find committer in commit %s",
552 sha1_to_hex(commit->object.sha1));
553 committer++;
554 committer_end = strchrnul(committer, '\n');
555 message = strstr(committer_end, "\n\n");
556 encoding = find_encoding(committer_end, message);
557 if (message)
558 message += 2;
560 if (commit->parents &&
561 get_object_mark(&commit->parents->item->object) != 0 &&
562 !full_tree) {
563 parse_commit_or_die(commit->parents->item);
564 diff_tree_sha1(commit->parents->item->tree->object.sha1,
565 commit->tree->object.sha1, "", &rev->diffopt);
567 else
568 diff_root_tree_sha1(commit->tree->object.sha1,
569 "", &rev->diffopt);
571 /* Export the referenced blobs, and remember the marks. */
572 for (i = 0; i < diff_queued_diff.nr; i++)
573 if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode))
574 export_blob(diff_queued_diff.queue[i]->two->sha1);
576 refname = commit->util;
577 if (anonymize) {
578 refname = anonymize_refname(refname);
579 anonymize_ident_line(&committer, &committer_end);
580 anonymize_ident_line(&author, &author_end);
583 mark_next_object(&commit->object);
584 if (anonymize)
585 reencoded = anonymize_commit_message(message);
586 else if (!is_encoding_utf8(encoding))
587 reencoded = reencode_string(message, "UTF-8", encoding);
588 if (!commit->parents)
589 printf("reset %s\n", refname);
590 printf("commit %s\nmark :%"PRIu32"\n%.*s\n%.*s\ndata %u\n%s",
591 refname, last_idnum,
592 (int)(author_end - author), author,
593 (int)(committer_end - committer), committer,
594 (unsigned)(reencoded
595 ? strlen(reencoded) : message
596 ? strlen(message) : 0),
597 reencoded ? reencoded : message ? message : "");
598 free(reencoded);
599 unuse_commit_buffer(commit, commit_buffer);
601 for (i = 0, p = commit->parents; p; p = p->next) {
602 int mark = get_object_mark(&p->item->object);
603 if (!mark)
604 continue;
605 if (i == 0)
606 printf("from :%d\n", mark);
607 else
608 printf("merge :%d\n", mark);
609 i++;
612 if (full_tree)
613 printf("deleteall\n");
614 log_tree_diff_flush(rev);
615 rev->diffopt.output_format = saved_output_format;
617 printf("\n");
619 show_progress();
622 static void *anonymize_tag(const void *old, size_t *len)
624 static int counter;
625 struct strbuf out = STRBUF_INIT;
626 strbuf_addf(&out, "tag message %d", counter++);
627 return strbuf_detach(&out, len);
630 static void handle_tail(struct object_array *commits, struct rev_info *revs)
632 struct commit *commit;
633 while (commits->nr) {
634 commit = (struct commit *)commits->objects[commits->nr - 1].item;
635 if (has_unshown_parent(commit))
636 return;
637 handle_commit(commit, revs);
638 commits->nr--;
642 static void handle_tag(const char *name, struct tag *tag)
644 unsigned long size;
645 enum object_type type;
646 char *buf;
647 const char *tagger, *tagger_end, *message;
648 size_t message_size = 0;
649 struct object *tagged;
650 int tagged_mark;
651 struct commit *p;
653 /* Trees have no identifier in fast-export output, thus we have no way
654 * to output tags of trees, tags of tags of trees, etc. Simply omit
655 * such tags.
657 tagged = tag->tagged;
658 while (tagged->type == OBJ_TAG) {
659 tagged = ((struct tag *)tagged)->tagged;
661 if (tagged->type == OBJ_TREE) {
662 warning("Omitting tag %s,\nsince tags of trees (or tags of tags of trees, etc.) are not supported.",
663 sha1_to_hex(tag->object.sha1));
664 return;
667 buf = read_sha1_file(tag->object.sha1, &type, &size);
668 if (!buf)
669 die ("Could not read tag %s", sha1_to_hex(tag->object.sha1));
670 message = memmem(buf, size, "\n\n", 2);
671 if (message) {
672 message += 2;
673 message_size = strlen(message);
675 tagger = memmem(buf, message ? message - buf : size, "\ntagger ", 8);
676 if (!tagger) {
677 if (fake_missing_tagger)
678 tagger = "tagger Unspecified Tagger "
679 "<unspecified-tagger> 0 +0000";
680 else
681 tagger = "";
682 tagger_end = tagger + strlen(tagger);
683 } else {
684 tagger++;
685 tagger_end = strchrnul(tagger, '\n');
686 if (anonymize)
687 anonymize_ident_line(&tagger, &tagger_end);
690 if (anonymize) {
691 name = anonymize_refname(name);
692 if (message) {
693 static struct hashmap tags;
694 message = anonymize_mem(&tags, anonymize_tag,
695 message, &message_size);
699 /* handle signed tags */
700 if (message) {
701 const char *signature = strstr(message,
702 "\n-----BEGIN PGP SIGNATURE-----\n");
703 if (signature)
704 switch(signed_tag_mode) {
705 case ABORT:
706 die ("Encountered signed tag %s; use "
707 "--signed-tags=<mode> to handle it.",
708 sha1_to_hex(tag->object.sha1));
709 case WARN:
710 warning ("Exporting signed tag %s",
711 sha1_to_hex(tag->object.sha1));
712 /* fallthru */
713 case VERBATIM:
714 break;
715 case WARN_STRIP:
716 warning ("Stripping signature from tag %s",
717 sha1_to_hex(tag->object.sha1));
718 /* fallthru */
719 case STRIP:
720 message_size = signature + 1 - message;
721 break;
725 /* handle tag->tagged having been filtered out due to paths specified */
726 tagged = tag->tagged;
727 tagged_mark = get_object_mark(tagged);
728 if (!tagged_mark) {
729 switch(tag_of_filtered_mode) {
730 case ABORT:
731 die ("Tag %s tags unexported object; use "
732 "--tag-of-filtered-object=<mode> to handle it.",
733 sha1_to_hex(tag->object.sha1));
734 case DROP:
735 /* Ignore this tag altogether */
736 return;
737 case REWRITE:
738 if (tagged->type != OBJ_COMMIT) {
739 die ("Tag %s tags unexported %s!",
740 sha1_to_hex(tag->object.sha1),
741 typename(tagged->type));
743 p = (struct commit *)tagged;
744 for (;;) {
745 if (p->parents && p->parents->next)
746 break;
747 if (p->object.flags & UNINTERESTING)
748 break;
749 if (!(p->object.flags & TREESAME))
750 break;
751 if (!p->parents)
752 die ("Can't find replacement commit for tag %s\n",
753 sha1_to_hex(tag->object.sha1));
754 p = p->parents->item;
756 tagged_mark = get_object_mark(&p->object);
760 if (starts_with(name, "refs/tags/"))
761 name += 10;
762 printf("tag %s\nfrom :%d\n%.*s%sdata %d\n%.*s\n",
763 name, tagged_mark,
764 (int)(tagger_end - tagger), tagger,
765 tagger == tagger_end ? "" : "\n",
766 (int)message_size, (int)message_size, message ? message : "");
769 static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
771 switch (e->item->type) {
772 case OBJ_COMMIT:
773 return (struct commit *)e->item;
774 case OBJ_TAG: {
775 struct tag *tag = (struct tag *)e->item;
777 /* handle nested tags */
778 while (tag && tag->object.type == OBJ_TAG) {
779 parse_object(tag->object.sha1);
780 string_list_append(&extra_refs, full_name)->util = tag;
781 tag = (struct tag *)tag->tagged;
783 if (!tag)
784 die("Tag %s points nowhere?", e->name);
785 return (struct commit *)tag;
786 break;
788 default:
789 return NULL;
793 static void get_tags_and_duplicates(struct rev_cmdline_info *info)
795 int i;
797 for (i = 0; i < info->nr; i++) {
798 struct rev_cmdline_entry *e = info->rev + i;
799 unsigned char sha1[20];
800 struct commit *commit;
801 char *full_name;
803 if (e->flags & UNINTERESTING)
804 continue;
806 if (dwim_ref(e->name, strlen(e->name), sha1, &full_name) != 1)
807 continue;
809 if (refspecs) {
810 char *private;
811 private = apply_refspecs(refspecs, refspecs_nr, full_name);
812 if (private) {
813 free(full_name);
814 full_name = private;
818 commit = get_commit(e, full_name);
819 if (!commit) {
820 warning("%s: Unexpected object of type %s, skipping.",
821 e->name,
822 typename(e->item->type));
823 continue;
826 switch(commit->object.type) {
827 case OBJ_COMMIT:
828 break;
829 case OBJ_BLOB:
830 export_blob(commit->object.sha1);
831 continue;
832 default: /* OBJ_TAG (nested tags) is already handled */
833 warning("Tag points to object of unexpected type %s, skipping.",
834 typename(commit->object.type));
835 continue;
839 * This ref will not be updated through a commit, lets make
840 * sure it gets properly updated eventually.
842 if (commit->util || commit->object.flags & SHOWN)
843 string_list_append(&extra_refs, full_name)->util = commit;
844 if (!commit->util)
845 commit->util = full_name;
849 static void handle_tags_and_duplicates(void)
851 struct commit *commit;
852 int i;
854 for (i = extra_refs.nr - 1; i >= 0; i--) {
855 const char *name = extra_refs.items[i].string;
856 struct object *object = extra_refs.items[i].util;
857 switch (object->type) {
858 case OBJ_TAG:
859 handle_tag(name, (struct tag *)object);
860 break;
861 case OBJ_COMMIT:
862 if (anonymize)
863 name = anonymize_refname(name);
864 /* create refs pointing to already seen commits */
865 commit = (struct commit *)object;
866 printf("reset %s\nfrom :%d\n\n", name,
867 get_object_mark(&commit->object));
868 show_progress();
869 break;
874 static void export_marks(char *file)
876 unsigned int i;
877 uint32_t mark;
878 struct object_decoration *deco = idnums.hash;
879 FILE *f;
880 int e = 0;
882 f = fopen(file, "w");
883 if (!f)
884 die_errno("Unable to open marks file %s for writing.", file);
886 for (i = 0; i < idnums.size; i++) {
887 if (deco->base && deco->base->type == 1) {
888 mark = ptr_to_mark(deco->decoration);
889 if (fprintf(f, ":%"PRIu32" %s\n", mark,
890 sha1_to_hex(deco->base->sha1)) < 0) {
891 e = 1;
892 break;
895 deco++;
898 e |= ferror(f);
899 e |= fclose(f);
900 if (e)
901 error("Unable to write marks file %s.", file);
904 static void import_marks(char *input_file)
906 char line[512];
907 FILE *f = fopen(input_file, "r");
908 if (!f)
909 die_errno("cannot read '%s'", input_file);
911 while (fgets(line, sizeof(line), f)) {
912 uint32_t mark;
913 char *line_end, *mark_end;
914 unsigned char sha1[20];
915 struct object *object;
916 struct commit *commit;
917 enum object_type type;
919 line_end = strchr(line, '\n');
920 if (line[0] != ':' || !line_end)
921 die("corrupt mark line: %s", line);
922 *line_end = '\0';
924 mark = strtoumax(line + 1, &mark_end, 10);
925 if (!mark || mark_end == line + 1
926 || *mark_end != ' ' || get_sha1_hex(mark_end + 1, sha1))
927 die("corrupt mark line: %s", line);
929 if (last_idnum < mark)
930 last_idnum = mark;
932 type = sha1_object_info(sha1, NULL);
933 if (type < 0)
934 die("object not found: %s", sha1_to_hex(sha1));
936 if (type != OBJ_COMMIT)
937 /* only commits */
938 continue;
940 commit = lookup_commit(sha1);
941 if (!commit)
942 die("not a commit? can't happen: %s", sha1_to_hex(sha1));
944 object = &commit->object;
946 if (object->flags & SHOWN)
947 error("Object %s already has a mark", sha1_to_hex(sha1));
949 mark_object(object, mark);
951 object->flags |= SHOWN;
953 fclose(f);
956 static void handle_deletes(void)
958 int i;
959 for (i = 0; i < refspecs_nr; i++) {
960 struct refspec *refspec = &refspecs[i];
961 if (*refspec->src)
962 continue;
964 printf("reset %s\nfrom %s\n\n",
965 refspec->dst, sha1_to_hex(null_sha1));
969 int cmd_fast_export(int argc, const char **argv, const char *prefix)
971 struct rev_info revs;
972 struct object_array commits = OBJECT_ARRAY_INIT;
973 struct commit *commit;
974 char *export_filename = NULL, *import_filename = NULL;
975 uint32_t lastimportid;
976 struct string_list refspecs_list = STRING_LIST_INIT_NODUP;
977 struct option options[] = {
978 OPT_INTEGER(0, "progress", &progress,
979 N_("show progress after <n> objects")),
980 OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, N_("mode"),
981 N_("select handling of signed tags"),
982 parse_opt_signed_tag_mode),
983 OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, N_("mode"),
984 N_("select handling of tags that tag filtered objects"),
985 parse_opt_tag_of_filtered_mode),
986 OPT_STRING(0, "export-marks", &export_filename, N_("file"),
987 N_("Dump marks to this file")),
988 OPT_STRING(0, "import-marks", &import_filename, N_("file"),
989 N_("Import marks from this file")),
990 OPT_BOOL(0, "fake-missing-tagger", &fake_missing_tagger,
991 N_("Fake a tagger when tags lack one")),
992 OPT_BOOL(0, "full-tree", &full_tree,
993 N_("Output full tree for each commit")),
994 OPT_BOOL(0, "use-done-feature", &use_done_feature,
995 N_("Use the done feature to terminate the stream")),
996 OPT_BOOL(0, "no-data", &no_data, N_("Skip output of blob data")),
997 OPT_STRING_LIST(0, "refspec", &refspecs_list, N_("refspec"),
998 N_("Apply refspec to exported refs")),
999 OPT_BOOL(0, "anonymize", &anonymize, N_("anonymize output")),
1000 OPT_END()
1003 if (argc == 1)
1004 usage_with_options (fast_export_usage, options);
1006 /* we handle encodings */
1007 git_config(git_default_config, NULL);
1009 init_revisions(&revs, prefix);
1010 revs.topo_order = 1;
1011 revs.show_source = 1;
1012 revs.rewrite_parents = 1;
1013 argc = parse_options(argc, argv, prefix, options, fast_export_usage,
1014 PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN);
1015 argc = setup_revisions(argc, argv, &revs, NULL);
1016 if (argc > 1)
1017 usage_with_options (fast_export_usage, options);
1019 if (refspecs_list.nr) {
1020 const char **refspecs_str;
1021 int i;
1023 refspecs_str = xmalloc(sizeof(*refspecs_str) * refspecs_list.nr);
1024 for (i = 0; i < refspecs_list.nr; i++)
1025 refspecs_str[i] = refspecs_list.items[i].string;
1027 refspecs_nr = refspecs_list.nr;
1028 refspecs = parse_fetch_refspec(refspecs_nr, refspecs_str);
1030 string_list_clear(&refspecs_list, 1);
1031 free(refspecs_str);
1034 if (use_done_feature)
1035 printf("feature done\n");
1037 if (import_filename)
1038 import_marks(import_filename);
1039 lastimportid = last_idnum;
1041 if (import_filename && revs.prune_data.nr)
1042 full_tree = 1;
1044 get_tags_and_duplicates(&revs.cmdline);
1046 if (prepare_revision_walk(&revs))
1047 die("revision walk setup failed");
1048 revs.diffopt.format_callback = show_filemodify;
1049 DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
1050 while ((commit = get_revision(&revs))) {
1051 if (has_unshown_parent(commit)) {
1052 add_object_array(&commit->object, NULL, &commits);
1054 else {
1055 handle_commit(commit, &revs);
1056 handle_tail(&commits, &revs);
1060 handle_tags_and_duplicates();
1061 handle_deletes();
1063 if (export_filename && lastimportid != last_idnum)
1064 export_marks(export_filename);
1066 if (use_done_feature)
1067 printf("done\n");
1069 free_refspec(refspecs_nr, refspecs);
1071 return 0;