git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Commit ID in exported Tar Ball

From
René Scharfe <rene.scharfe@lsrfire.ath.cx>
Date
May 20, 2007, 11:20 UTC
Message-ID
<46502EFF.2080104@lsrfire.ath.cx>
In-Reply-To
<464F932D.6040509@lsrfire.ath.cx>

Turns out a matcher for the kind of pathspecs used in git-archive is much easier to write than I thought. :-)

This is just a progress note and not for inclusion, yet -- Shawn has a good point suggesting git-describe output to be used instead of bare commit IDs.

 Documentation/git-archive.txt |    4 +++
 archive-tar.c                 |    7 ++++++
 archive-zip.c                 |    7 ++++++
 archive.h                     |    1 +
 builtin-archive.c             |   44 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 63 insertions(+), 0 deletions(-)
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index 721e035..7016d1e 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -43,6 +43,10 @@ OPTIONS
 --prefix=<prefix>/::
 	Prepend <prefix>/ to each filename in the archive.
 
+--commit-id-file=<filename>::
+	Adds a file to the archive containing the commit ID.  This option
+	is can only be used if <tree-ish> references a commit or tag.
+
 <extra>::
 	This can be any options that the archiver backend understand.
 	See next section.
diff --git a/archive-tar.c b/archive-tar.c
index 33e7657..555850a 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -319,6 +319,13 @@ int write_tar_archive(struct archiver_args *args)
 	}
 	read_tree_recursive(args->tree, args->base, plen, 0,
 			    args->pathspec, write_tar_entry);
+	if (args->commit_sha1 && args->commit_sha1_file) {
+		unsigned char fake_sha1[20];
+		pretend_sha1_file(sha1_to_hex(args->commit_sha1), 40,
+		                  OBJ_BLOB, fake_sha1);
+		write_tar_entry(fake_sha1, args->base, plen,
+		                args->commit_sha1_file, 0100666, 0);
+	}
 	write_trailer();
 
 	return 0;
diff --git a/archive-zip.c b/archive-zip.c
index 3cbf6bb..88c5dfa 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -328,6 +328,13 @@ int write_zip_archive(struct archiver_args *args)
 	}
 	read_tree_recursive(args->tree, args->base, plen, 0,
 			    args->pathspec, write_zip_entry);
+	if (args->commit_sha1 && args->commit_sha1_file) {
+		unsigned char fake_sha1[20];
+		pretend_sha1_file(sha1_to_hex(args->commit_sha1), 40,
+		                  OBJ_BLOB, fake_sha1);
+		write_zip_entry(fake_sha1, args->base, plen,
+		                args->commit_sha1_file, 0100666, 0);
+	}
 	write_zip_trailer(args->commit_sha1);
 
 	free(zip_dir);
diff --git a/archive.h b/archive.h
index 6838dc7..020f82f 100644
--- a/archive.h
+++ b/archive.h
@@ -8,6 +8,7 @@ struct archiver_args {
 	const char *base;
 	struct tree *tree;
 	const unsigned char *commit_sha1;
+	const char *commit_sha1_file;
 	time_t time;
 	const char **pathspec;
 	unsigned int verbose : 1;
diff --git a/builtin-archive.c b/builtin-archive.c
index 7f4e409..1fe4d47 100644
--- a/builtin-archive.c
+++ b/builtin-archive.c
@@ -151,6 +151,7 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)
 	int extra_argc = 0;
 	const char *format = "tar";
 	const char *base = "";
+	const char *commit_sha1_file = NULL;
 	int verbose = 0;
 	int i;
 
@@ -174,6 +175,10 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)
 			base = arg + 9;
 			continue;
 		}
+		if (!prefixcmp(arg, "--commit-id-file=")) {
+			commit_sha1_file = arg + 17;
+			continue;
+		}
 		if (!strcmp(arg, "--")) {
 			i++;
 			break;
@@ -192,6 +197,11 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)
 		usage(archive_usage);
 	if (init_archiver(format, ar) < 0)
 		die("Unknown archive format '%s'", format);
+	if (commit_sha1_file) {
+		size_t namelen = strlen(commit_sha1_file);
+		if (namelen == 0 || commit_sha1_file[namelen - 1] == '/')
+			die("Invalid commit ID file name: %s", commit_sha1_file);
+	}
 
 	if (extra_argc) {
 		if (!ar->parse_extra)
@@ -201,6 +211,7 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)
 	}
 	ar->args.verbose = verbose;
 	ar->args.base = base;
+	ar->args.commit_sha1_file = commit_sha1_file;
 
 	return i;
 }
@@ -236,6 +247,32 @@ static const char *extract_remote_arg(int *ac, const char **av)
 	return remote;
 }
 
+static int is_path_in_spec(const struct archiver_args *args, const char *path)
+{
+	unsigned char sha1[20];
+	unsigned int mode;
+	const char *match;
+	const char **pathspec = args->pathspec;
+
+	if (get_tree_entry(args->tree->object.sha1, path, sha1, &mode))
+		return 0;
+	if (!pathspec)
+		return 1;
+	while ((match = *pathspec++) != NULL) {
+		size_t matchlen = strlen(match);
+		if (matchlen == 0)
+			return 1;
+		if (match[matchlen - 1] == '/') {
+			if (!prefixcmp(path, match))
+				return 1;
+		} else {
+			if (!strcmp(path, match))
+				return 1;
+		}
+	}
+	return 0;
+}
+
 int cmd_archive(int argc, const char **argv, const char *prefix)
 {
 	struct archiver ar;
@@ -257,5 +294,12 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
 	parse_treeish_arg(argv, &ar.args, prefix);
 	parse_pathspec_arg(argv + 1, &ar.args);
 
+	if (ar.args.commit_sha1_file) {
+		if (is_path_in_spec(&ar.args, ar.args.commit_sha1_file))
+			die("Commit ID file name already exists in archive.");
+		if (!ar.args.commit_sha1)
+			die("Need a commit to use --commit-id-file, and not a tree.");
+	}
+
 	return ar.write_archive(&ar.args);
 }
Previous: René ScharfeNext: Shawn O. Pearce
Message 13 of 38 in “Commit ID in exported Tar Ball”
  1. Thomas GlanzmannMay 17, 2007
  2. Johan HerlandMay 17, 2007
  3. Frank LichtenheldMay 17, 2007
  4. Thomas GlanzmannMay 17, 2007
  5. Johan HerlandMay 17, 2007
  6. git-archive: convert archive entries like checkouts doRené Scharfe, May 18, 2007
  7. Daniel BarkalowMay 18, 2007
  8. René ScharfeMay 18, 2007
  9. René ScharfeMay 19, 2007
  10. Junio C HamanoMay 19, 2007
  11. A Large Angry SCMMay 19, 2007
  12. René ScharfeMay 20, 2007
  13. René ScharfeMay 20, 2007
  14. Shawn O. PearceMay 20, 2007
  15. René ScharfeMay 20, 2007
  16. Shawn O. PearceMay 21, 2007
  17. Petr BaudisMay 21, 2007
  18. René ScharfeMay 21, 2007
  19. René ScharfeMay 22, 2007
  20. Junio C HamanoMay 22, 2007
  21. René ScharfeMay 22, 2007
  22. Shawn O. PearceMay 23, 2007
  23. René ScharfeMay 20, 2007
  24. Thomas GlanzmannMay 20, 2007
  25. Brian GernhardtMay 20, 2007
  26. Thomas GlanzmannMay 20, 2007
  27. Peter BaumannMay 21, 2007
  28. Thomas GlanzmannMay 21, 2007
  29. Shawn O. PearceMay 21, 2007
  30. Thomas GlanzmannMay 21, 2007
  31. Shawn O. PearceMay 21, 2007
  32. Thomas GlanzmannMay 21, 2007
  33. Brian GernhardtMay 21, 2007
  34. Thomas GlanzmannMay 21, 2007
  35. Frank LichtenheldMay 17, 2007
  36. Johan HerlandMay 17, 2007
  37. Kristian HøgsbergMay 17, 2007
  38. Thomas GlanzmannMay 17, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.