All of lore.kernel.org
 help / color / mirror / Atom feed
* [WIP PATCH] Add 'git fast-export', the sister of 'git fast-import'
@ 2007-11-21  3:40 Johannes Schindelin
  2007-11-21  7:44 ` Johannes Sixt
                   ` (3 more replies)
  0 siblings, 4 replies; 27+ messages in thread
From: Johannes Schindelin @ 2007-11-21  3:40 UTC (permalink / raw)
  To: git


[WIP: this does not handle tags yet, and it lacks a test script
 as well as documentation.]

This program dumps (parts of) a git repository in the format that
fast-import understands.

For clarity's sake, it does not use the 'inline' method of specifying
blobs in the commits, but builds the blobs before building the commits.B

---
	I am way too tired now to continue, but maybe someone else wants
	to pick up the ball.

	Oh, and it relies on "int" being castable to void * and vice 
	versa.  Is anybody aware of a platform where this can lead to
	problems?

	And yes, I will add a copyright when I woke up again.

 .gitignore            |    1 +
 Makefile              |    1 +
 builtin-fast-export.c |  202 +++++++++++++++++++++++++++++++++++++++++++++++++
 builtin.h             |    1 +
 git.c                 |    1 +
 5 files changed, 206 insertions(+), 0 deletions(-)
 create mode 100755 builtin-fast-export.c

diff --git a/.gitignore b/.gitignore
index 507e351..ef69e2f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,7 @@ git-diff-files
 git-diff-index
 git-diff-tree
 git-describe
+git-fast-export
 git-fast-import
 git-fetch
 git-fetch--tool
diff --git a/Makefile b/Makefile
index dd3ba6f..8784eff 100644
--- a/Makefile
+++ b/Makefile
@@ -336,6 +336,7 @@ BUILTIN_OBJS = \
 	builtin-diff-files.o \
 	builtin-diff-index.o \
 	builtin-diff-tree.o \
+	builtin-fast-export.o \
 	builtin-fetch.o \
 	builtin-fetch-pack.o \
 	builtin-fetch--tool.o \
diff --git a/builtin-fast-export.c b/builtin-fast-export.c
new file mode 100755
index 0000000..2e8e3dd
--- /dev/null
+++ b/builtin-fast-export.c
@@ -0,0 +1,202 @@
+#include "builtin.h"
+#include "cache.h"
+#include "commit.h"
+#include "object.h"
+#include "tag.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "log-tree.h"
+#include "revision.h"
+#include "decorate.h"
+#include "path-list.h"
+
+static struct decoration idnums;
+static uint32_t last_idnum;
+
+static const char *fast_export_usage = "git-fast-export [rev-list-opts]";
+
+static int has_unshown_parent(struct commit *commit)
+{
+	struct commit_list *parent;
+
+	for (parent = commit->parents; parent; parent = parent->next)
+		if (!(parent->item->object.flags & SHOWN))
+			return 1;
+	return 0;
+}
+
+static void handle_object(const unsigned char *sha1)
+{
+	unsigned long size;
+	enum object_type type;
+	char *buf;
+	struct object *object;
+
+	if (is_null_sha1(sha1))
+		return;
+
+	object = parse_object(sha1);
+	if (!object)
+		die ("Could not read blob %s", sha1_to_hex(sha1));
+
+	if (object->flags & SHOWN)
+		return;
+
+	buf = read_sha1_file(sha1, &type, &size);
+	if (!buf)
+		die ("Could not read blob %s", sha1_to_hex(sha1));
+
+	last_idnum++;
+	add_decoration(&idnums, object, (void *)last_idnum);
+
+	printf("blob\nmark :%d\ndata %lu\n", last_idnum, size);
+	if (fwrite(buf, size, 1, stdout) != 1)
+		die ("Could not write blob %s", sha1_to_hex(sha1));
+	printf("\n");
+
+	object->flags |= SHOWN;
+	free(buf);
+}
+
+static void show_filemodify(struct diff_queue_struct *q,
+		struct diff_options *options, void *data)
+{
+	int i;
+	for (i = 0; i < q->nr; i++) {
+		struct diff_filespec *spec = q->queue[i]->two;
+		if (is_null_sha1(spec->sha1))
+			printf("D %s\n", spec->path);
+		else {
+			struct object *object = lookup_object(spec->sha1);
+			printf("M 0%06o :%d %s\n", spec->mode,
+					(int)lookup_decoration(&idnums, object),
+					spec->path);
+		}
+	}
+}
+
+static void handle_commit(struct commit *commit, struct rev_info *rev)
+{
+	const char *author, *author_end, *committer, *committer_end, *message;
+	int saved_output_format = rev->diffopt.output_format;
+	int i;
+
+	rev->diffopt.output_format = DIFF_FORMAT_CALLBACK;
+
+	parse_commit(commit);
+	author = strstr(commit->buffer, "\nauthor ");
+	if (!author)
+		die ("Could not find author in commit %s",
+				sha1_to_hex(commit->object.sha1));
+	author++;
+	author_end = strchrnul(author, '\n');
+	committer = strstr(author_end, "\ncommitter ");
+	if (!committer)
+		die ("Could not find committer in commit %s",
+				sha1_to_hex(commit->object.sha1));
+	committer++;
+	committer_end = strchrnul(committer, '\n');
+	message = strstr(committer_end, "\n\n");
+	if (message)
+		message += 2;
+
+	if (commit->parents) {
+		parse_commit(commit->parents->item);
+		diff_tree_sha1(commit->parents->item->tree->object.sha1,
+				commit->tree->object.sha1, "", &rev->diffopt);
+	}
+	else
+		diff_root_tree_sha1(commit->tree->object.sha1,
+				"", &rev->diffopt);
+
+	for (i = 0; i < diff_queued_diff.nr; i++)
+		handle_object(diff_queued_diff.queue[i]->two->sha1);
+
+	last_idnum++;
+	add_decoration(&idnums, &commit->object, (void *)last_idnum);
+	printf("commit %s\nmark :%d\n%.*s\n%.*s\ndata %u\n%s",
+		(const char *)commit->util, last_idnum,
+		author_end - author, author,
+		committer_end - committer, committer,
+		message ? strlen(message) : 0, message ? message : "");
+
+	log_tree_diff_flush(rev);
+	rev->diffopt.output_format = saved_output_format;
+
+	printf("\n");
+}
+
+static void handle_tail(struct object_array *commits, struct rev_info *revs)
+{
+	struct commit *commit;
+	while (commits->nr) {
+		commit = (struct commit *)commits->objects[commits->nr - 1].item;
+		if (has_unshown_parent(commit))
+			return;
+		handle_commit(commit, revs);
+		commits->nr--;
+	}
+}
+
+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 commit *commit;
+	int i;
+
+	init_revisions(&revs, prefix);
+	argc = setup_revisions(argc, argv, &revs, NULL);
+	if (argc > 1)
+		usage (fast_export_usage);
+
+	for (i = 0; i < revs.pending.nr; i++) {
+		struct object_array_entry *e = revs.pending.objects + i;
+		unsigned char sha1[20];
+		char *full_name;
+
+		/* TODO: handle tags */
+		commit = (struct commit *)e->item;
+		if (dwim_ref(e->name, strlen(e->name), sha1, &full_name) != 1)
+			die ("Could not get a unique ref name for '%s'",
+				e->name);
+		if (commit->util)
+			/* more than one name for the same object */
+			path_list_insert(full_name, &extra_refs)->util = commit;
+		else
+			commit->util = full_name;
+	}
+
+	prepare_revision_walk(&revs);
+	revs.diffopt.format_callback = show_filemodify;
+	revs.diffopt.recursive = 1;
+	while ((commit = get_revision(&revs))) {
+		if (has_unshown_parent(commit)) {
+			struct commit_list *parent = commit->parents;
+			add_object_array(&commit->object, NULL, &commits);
+			for (; parent; parent = parent->next)
+				if (!parent->item->util)
+					parent->item->util = commit->util;
+		}
+		else {
+			handle_commit(commit, &revs);
+			handle_tail(&commits, &revs);
+		}
+	}
+
+	if (commits.nr)
+		die ("This should not happen: there were %d commits left!",
+			commits.nr);
+
+	for (i = 0; i < extra_refs.nr; i++) {
+		/* create refs pointing to already seen commits */
+		commit = extra_refs.items[i].util;
+		printf("reset %s\nfrom :%d\n\n",
+				extra_refs.items[i].path,
+				(int)lookup_decoration(&idnums,
+					&commit->object));
+	}
+
+	return 0;
+}
diff --git a/builtin.h b/builtin.h
index e76f5da..5723f9e 100644
--- a/builtin.h
+++ b/builtin.h
@@ -31,6 +31,7 @@ extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
 extern int cmd_diff_index(int argc, const char **argv, const char *prefix);
 extern int cmd_diff(int argc, const char **argv, const char *prefix);
 extern int cmd_diff_tree(int argc, const char **argv, const char *prefix);
+extern int cmd_fast_export(int argc, const char **argv, const char *prefix);
 extern int cmd_fetch(int argc, const char **argv, const char *prefix);
 extern int cmd_fetch_pack(int argc, const char **argv, const char *prefix);
 extern int cmd_fetch__tool(int argc, const char **argv, const char *prefix);
diff --git a/git.c b/git.c
index 0b6825e..deda6dd 100644
--- a/git.c
+++ b/git.c
@@ -301,6 +301,7 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "diff-files", cmd_diff_files },
 		{ "diff-index", cmd_diff_index, RUN_SETUP },
 		{ "diff-tree", cmd_diff_tree, RUN_SETUP },
+		{ "fast-export", cmd_fast_export, RUN_SETUP },
 		{ "fetch", cmd_fetch, RUN_SETUP },
 		{ "fetch-pack", cmd_fetch_pack, RUN_SETUP },
 		{ "fetch--tool", cmd_fetch__tool, RUN_SETUP },
-- 
1.5.3.5.1751.gf6fb4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2007-11-27 15:11 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-11-21  3:40 [WIP PATCH] Add 'git fast-export', the sister of 'git fast-import' Johannes Schindelin
2007-11-21  7:44 ` Johannes Sixt
2007-11-21  7:47   ` Shawn O. Pearce
2007-11-21 14:01   ` Johannes Schindelin
2007-11-21 15:09     ` Andreas Ericsson
2007-11-21 15:47       ` Johannes Schindelin
2007-11-21 15:53         ` Andreas Ericsson
2007-11-21 12:43 ` Geert Bosch
2007-11-21 14:42   ` Johannes Schindelin
2007-11-23  0:27 ` Han-Wen Nienhuys
2007-11-23  1:01   ` Johannes Schindelin
2007-11-23  1:23     ` Han-Wen Nienhuys
2007-11-23  2:11       ` Johannes Schindelin
2007-11-23 20:59         ` Shawn O. Pearce
2007-11-25 17:00           ` Karl Hasselström
2007-11-26 16:48             ` Johannes Schindelin
2007-11-27 10:16               ` Karl Hasselström
2007-11-27 11:25                 ` Johannes Schindelin
2007-11-27 14:51                   ` Karl Hasselström
2007-11-27 15:10                     ` Johannes Schindelin
2007-11-26 16:47           ` Johannes Schindelin
2007-11-23 12:31 ` Nguyen Thai Ngoc Duy
2007-11-23 14:31   ` Johannes Schindelin
2007-11-23 20:56     ` Shawn O. Pearce
2007-11-24 14:08     ` Nguyen Thai Ngoc Duy
2007-11-27 12:16       ` Johannes Schindelin
2007-11-27 14:17         ` Nguyen Thai Ngoc Duy

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.