From: Johannes Schindelin <Johannes.Schindelin@gmx.de>
To: git@vger.kernel.org
Subject: [WIP PATCH] Add 'git fast-export', the sister of 'git fast-import'
Date: Wed, 21 Nov 2007 03:40:37 +0000 (GMT) [thread overview]
Message-ID: <Pine.LNX.4.64.0711210336210.27959@racer.site> (raw)
[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
next reply other threads:[~2007-11-21 3:41 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-11-21 3:40 Johannes Schindelin [this message]
2007-11-21 7:44 ` [WIP PATCH] Add 'git fast-export', the sister of 'git fast-import' 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Pine.LNX.4.64.0711210336210.27959@racer.site \
--to=johannes.schindelin@gmx.de \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).