aboutsummaryrefslogtreecommitdiff
path: root/builtin-fast-export.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin-fast-export.c')
-rw-r--r--builtin-fast-export.c166
1 files changed, 144 insertions, 22 deletions
diff --git a/builtin-fast-export.c b/builtin-fast-export.c
index d0a462ff8..070971616 100644
--- a/builtin-fast-export.c
+++ b/builtin-fast-export.c
@@ -13,12 +13,12 @@
#include "log-tree.h"
#include "revision.h"
#include "decorate.h"
-#include "path-list.h"
+#include "string-list.h"
#include "utf8.h"
#include "parse-options.h"
static const char *fast_export_usage[] = {
- "git-fast-export [rev-list-opts]",
+ "git fast-export [rev-list-opts]",
NULL
};
@@ -56,10 +56,24 @@ static int has_unshown_parent(struct commit *commit)
}
/* Since intptr_t is C99, we do not use it here */
-static void mark_object(struct object *object)
+static inline uint32_t *mark_to_ptr(uint32_t mark)
{
- last_idnum++;
- add_decoration(&idnums, object, ((uint32_t *)NULL) + last_idnum);
+ return ((uint32_t *)NULL) + mark;
+}
+
+static inline uint32_t ptr_to_mark(void * mark)
+{
+ return (uint32_t *)mark - (uint32_t *)NULL;
+}
+
+static inline void mark_object(struct object *object, uint32_t mark)
+{
+ add_decoration(&idnums, object, mark_to_ptr(mark));
+}
+
+static inline void mark_next_object(struct object *object)
+{
+ mark_object(object, ++last_idnum);
}
static int get_object_mark(struct object *object)
@@ -67,7 +81,7 @@ static int get_object_mark(struct object *object)
void *decoration = lookup_decoration(&idnums, object);
if (!decoration)
return 0;
- return (uint32_t *)decoration - (uint32_t *)NULL;
+ return ptr_to_mark(decoration);
}
static void show_progress(void)
@@ -100,9 +114,9 @@ static void handle_object(const unsigned char *sha1)
if (!buf)
die ("Could not read blob %s", sha1_to_hex(sha1));
- mark_object(object);
+ mark_next_object(object);
- printf("blob\nmark :%d\ndata %lu\n", last_idnum, size);
+ printf("blob\nmark :%"PRIu32"\ndata %lu\n", last_idnum, size);
if (size && fwrite(buf, size, 1, stdout) != 1)
die ("Could not write blob %s", sha1_to_hex(sha1));
printf("\n");
@@ -118,13 +132,46 @@ static void show_filemodify(struct diff_queue_struct *q,
{
int i;
for (i = 0; i < q->nr; i++) {
+ struct diff_filespec *ospec = q->queue[i]->one;
struct diff_filespec *spec = q->queue[i]->two;
- if (is_null_sha1(spec->sha1))
+
+ switch (q->queue[i]->status) {
+ case DIFF_STATUS_DELETED:
printf("D %s\n", spec->path);
- else {
- struct object *object = lookup_object(spec->sha1);
- printf("M %06o :%d %s\n", spec->mode,
- get_object_mark(object), spec->path);
+ break;
+
+ case DIFF_STATUS_COPIED:
+ case DIFF_STATUS_RENAMED:
+ printf("%c \"%s\" \"%s\"\n", q->queue[i]->status,
+ ospec->path, spec->path);
+
+ if (!hashcmp(ospec->sha1, spec->sha1) &&
+ ospec->mode == spec->mode)
+ break;
+ /* fallthrough */
+
+ case DIFF_STATUS_TYPE_CHANGED:
+ case DIFF_STATUS_MODIFIED:
+ case DIFF_STATUS_ADDED:
+ /*
+ * Links refer to objects in another repositories;
+ * output the SHA-1 verbatim.
+ */
+ if (S_ISGITLINK(spec->mode))
+ printf("M %06o %s %s\n", spec->mode,
+ sha1_to_hex(spec->sha1), spec->path);
+ else {
+ struct object *object = lookup_object(spec->sha1);
+ printf("M %06o :%d %s\n", spec->mode,
+ get_object_mark(object), spec->path);
+ }
+ break;
+
+ default:
+ die("Unexpected comparison status '%c' for %s, %s",
+ q->queue[i]->status,
+ ospec->path ? ospec->path : "none",
+ spec->path ? spec->path : "none");
}
}
}
@@ -182,15 +229,17 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
diff_root_tree_sha1(commit->tree->object.sha1,
"", &rev->diffopt);
+ /* Export the referenced blobs, and remember the marks. */
for (i = 0; i < diff_queued_diff.nr; i++)
- handle_object(diff_queued_diff.queue[i]->two->sha1);
+ if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode))
+ handle_object(diff_queued_diff.queue[i]->two->sha1);
- mark_object(&commit->object);
+ mark_next_object(&commit->object);
if (!is_encoding_utf8(encoding))
reencoded = reencode_string(message, "UTF-8", encoding);
if (!commit->parents)
printf("reset %s\n", (const char*)commit->util);
- printf("commit %s\nmark :%d\n%.*s\n%.*s\ndata %u\n%s",
+ printf("commit %s\nmark :%"PRIu32"\n%.*s\n%.*s\ndata %u\n%s",
(const char *)commit->util, last_idnum,
(int)(author_end - author), author,
(int)(committer_end - committer), committer,
@@ -284,7 +333,7 @@ static void handle_tag(const char *name, struct tag *tag)
}
static void get_tags_and_duplicates(struct object_array *pending,
- struct path_list *extra_refs)
+ struct string_list *extra_refs)
{
struct tag *tag;
int i;
@@ -305,7 +354,7 @@ static void get_tags_and_duplicates(struct object_array *pending,
case OBJ_TAG:
tag = (struct tag *)e->item;
while (tag && tag->object.type == OBJ_TAG) {
- path_list_insert(full_name, extra_refs)->util = tag;
+ string_list_insert(full_name, extra_refs)->util = tag;
tag = (struct tag *)tag->tagged;
}
if (!tag)
@@ -325,19 +374,19 @@ static void get_tags_and_duplicates(struct object_array *pending,
}
if (commit->util)
/* more than one name for the same object */
- path_list_insert(full_name, extra_refs)->util = commit;
+ string_list_insert(full_name, extra_refs)->util = commit;
else
commit->util = full_name;
}
}
-static void handle_tags_and_duplicates(struct path_list *extra_refs)
+static void handle_tags_and_duplicates(struct string_list *extra_refs)
{
struct commit *commit;
int i;
for (i = extra_refs->nr - 1; i >= 0; i--) {
- const char *name = extra_refs->items[i].path;
+ const char *name = extra_refs->items[i].string;
struct object *object = extra_refs->items[i].util;
switch (object->type) {
case OBJ_TAG:
@@ -354,18 +403,85 @@ static void handle_tags_and_duplicates(struct path_list *extra_refs)
}
}
+static void export_marks(char *file)
+{
+ unsigned int i;
+ uint32_t mark;
+ struct object_decoration *deco = idnums.hash;
+ FILE *f;
+
+ f = fopen(file, "w");
+ if (!f)
+ error("Unable to open marks file %s for writing", file);
+
+ for (i = 0; i < idnums.size; i++) {
+ if (deco->base && deco->base->type == 1) {
+ mark = ptr_to_mark(deco->decoration);
+ fprintf(f, ":%u %s\n", mark, sha1_to_hex(deco->base->sha1));
+ }
+ deco++;
+ }
+
+ if (ferror(f) || fclose(f))
+ error("Unable to write marks file %s.", file);
+}
+
+static void import_marks(char *input_file)
+{
+ char line[512];
+ FILE *f = fopen(input_file, "r");
+ if (!f)
+ die("cannot read %s: %s", input_file, strerror(errno));
+
+ while (fgets(line, sizeof(line), f)) {
+ uint32_t mark;
+ char *line_end, *mark_end;
+ unsigned char sha1[20];
+ struct object *object;
+
+ line_end = strchr(line, '\n');
+ if (line[0] != ':' || !line_end)
+ die("corrupt mark line: %s", line);
+ *line_end = '\0';
+
+ mark = strtoumax(line + 1, &mark_end, 10);
+ if (!mark || mark_end == line + 1
+ || *mark_end != ' ' || get_sha1(mark_end + 1, sha1))
+ die("corrupt mark line: %s", line);
+
+ object = parse_object(sha1);
+ if (!object)
+ die ("Could not read blob %s", sha1_to_hex(sha1));
+
+ if (object->flags & SHOWN)
+ error("Object %s already has a mark", sha1);
+
+ mark_object(object, mark);
+ if (last_idnum < mark)
+ last_idnum = mark;
+
+ object->flags |= SHOWN;
+ }
+ fclose(f);
+}
+
int cmd_fast_export(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
struct object_array commits = { 0, 0, NULL };
- struct path_list extra_refs = { NULL, 0, 0, 0 };
+ struct string_list extra_refs = { NULL, 0, 0, 0 };
struct commit *commit;
+ char *export_filename = NULL, *import_filename = NULL;
struct option options[] = {
OPT_INTEGER(0, "progress", &progress,
"show progress after <n> objects"),
OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, "mode",
"select handling of signed tags",
parse_opt_signed_tag_mode),
+ OPT_STRING(0, "export-marks", &export_filename, "FILE",
+ "Dump marks to this file"),
+ OPT_STRING(0, "import-marks", &import_filename, "FILE",
+ "Import marks from this file"),
OPT_END()
};
@@ -378,6 +494,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
if (argc > 1)
usage_with_options (fast_export_usage, options);
+ if (import_filename)
+ import_marks(import_filename);
+
get_tags_and_duplicates(&revs.pending, &extra_refs);
if (prepare_revision_walk(&revs))
@@ -400,5 +519,8 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
handle_tags_and_duplicates(&extra_refs);
+ if (export_filename)
+ export_marks(export_filename);
+
return 0;
}