Subject: [WIP/PATCH] Teach fast-import to print the id of each imported commit

From: Jonathan Nieder <[email-masked]>
Date: Thu, 1 Jul 2010 00:48:49 -0500

For the svn importer, it would be useful to have a map from
subversion revision numbers to git commits.  This is particularly
relevant because the subversion api sometimes represents as "copy
this directory from this revision", and the importer needs to be
able to access the corresponding trees.  So (optionally) print
each commit id when the corresponding object is written.

Unfortunately when each commit object is written, it is not yet
accessible to the caller.  The corresponding pack index
and header are not written until the next checkpoint finishes.

Should fast-import accept lines of the form

 M 100644 <commit id>:<path> <path>

and

 M 040000 <commit id>:<path> <path>

to allow the caller to use commits before they are accessible
through the git object database?

Signed-off-by: Jonathan Nieder <[email-masked]>
but definitely not ready for inclusion
---
 fast-import.c          |   18 ++++++++++++++++++
 t/t9300-fast-import.sh |   45 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/fast-import.c b/fast-import.c
index ad6843a..869da7f 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -361,6 +361,9 @@ static uintmax_t next_mark;
 static struct strbuf new_data = STRBUF_INIT;
 static int seen_data_command;
 
+/* Where to report commits */
+static int commits_fd = -1;
+
 static void parse_argv(void);
 
 static void write_branch_report(FILE *rpt, struct branch *b)
@@ -2563,6 +2566,11 @@ static void parse_new_commit(void)
 
 	if (!store_object(OBJ_COMMIT, &new_data, NULL, b->sha1, next_mark))
 		b->pack_id = pack_id;
+	if (commits_fd != -1) {
+		char *buf = sha1_to_hex(b->sha1);
+		buf[40] = '\n';
+		write_or_die(commits_fd, buf, 41);
+	}
 	b->last_commit = object_count_by_type[OBJ_COMMIT];
 }
 
@@ -2747,6 +2755,14 @@ static void option_export_marks(const char *marks)
 	safe_create_leading_directories_const(export_marks_file);
 }
 
+static void option_print_commits(const char *fd)
+{
+	unsigned long n = strtoul(fd, NULL, 0);
+	if (n > (unsigned long) INT_MAX)
+		die("--print-commits cannot exceed %d", INT_MAX);
+	commits_fd = (int) n;
+}
+
 static void option_export_pack_edges(const char *edges)
 {
 	if (pack_edges)
@@ -2800,6 +2816,8 @@ static int parse_one_feature(const char *feature, int from_stream)
 		option_import_marks(feature + 13, from_stream);
 	} else if (!prefixcmp(feature, "export-marks=")) {
 		option_export_marks(feature + 13);
+	} else if (!prefixcmp(feature, "print-commits=")) {
+		option_print_commits(feature + strlen("print-commits="));
 	} else if (!prefixcmp(feature, "relative-marks")) {
 		relative_marks_paths = 1;
 	} else if (!prefixcmp(feature, "no-relative-marks")) {
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 50d5913..5cb949f 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -1555,6 +1555,51 @@ test_expect_success 'R: feature no-relative-marks should be honoured' '
     test_cmp marks.new non-relative.out
 '
 
+test_expect_success 'R: print-commits magic' '
+	mkfifo commits &&
+	cat >caller <<-\CALLER_END
+		#!/bin/sh
+		cat <<EOF &&
+		feature print-commits=3
+		commit refs/heads/printed
+		committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+		data <<COMMIT
+		to be printed
+		COMMIT
+
+		from refs/heads/master
+		D file3
+
+		EOF
+
+		read cid <&3 &&
+		! git rev-parse $cid: >/dev/null &&
+		echo checkpoint &&
+		sleep 1 &&
+		tree=$(git rev-parse $cid:) &&
+		cat <<EOF
+		commit refs/heads/printed
+		committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+		data <<COMMIT
+		to be printed
+		COMMIT
+
+		from refs/heads/printed^0
+		M 040000 $tree old
+
+		EOF
+		sleep 1
+	CALLER_END
+	chmod +x caller &&
+	{
+		sh caller 3<commits ||
+		echo fail
+	} |
+	git fast-import 3>commits &&
+	git rev-parse printed^ printed &&
+	git show printed:
+'
+
 cat >input << EOF
 option git quiet
 blob
-- 
1.7.1.1