{"thread":{"id":"8191","subject":"Commit ID in exported Tar Ball","startedAt":"2007-05-17T16:38:03Z","lastAt":"2007-05-23T05:22:20Z","messageCount":38,"participants":["Thomas Glanzmann","Johan Herland","Kristian Høgsberg","Frank Lichtenheld","René Scharfe","Daniel Barkalow","Junio C Hamano","A Large Angry SCM","Shawn O. Pearce","Brian Gernhardt","Peter Baumann","Petr Baudis"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"42412","messageId":"20070517163803.GE4095@cip.informatik.uni-erlangen.de","threadId":"8191","inReplyTo":null,"subject":"Commit ID in exported Tar Ball","fromName":"Thomas Glanzmann","fromEmail":"thomas@glanzmann.de","sentAt":"2007-05-17T16:38:03Z","receivedAt":"2007-05-17T16:38:03Z","isPatch":false,"sender":{"key":"thomas@glanzmann.de","avatar":null},"body":"Hello,\nMichae, a friend of mine, is in the phase of migrating from git to cvs.\nHe releases tar balls of his software project using gitweb. He would\nlove to have a way to have the commit-id of HEAD of the export contained\nin one of the files he exported that way. Is there infrastructure in git\nthat makes that already possible or does he need to some kind of\ngerneration tool by himself? Maybe it would be helpful if the\ngit-tar-tree would generate a file .commitid or something like that in\nthe generated tar tree.\n\n        Thomas\n"},{"id":"42413","messageId":"200705171857.22891.johan@herland.net","threadId":"8191","inReplyTo":"20070517163803.GE4095@cip.informatik.uni-erlangen.de","subject":"Re: Commit ID in exported Tar Ball","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2007-05-17T16:57:22Z","receivedAt":"2007-05-17T16:57:22Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Thursday 17 May 2007, Thomas Glanzmann wrote:\n> Hello,\n> Michae, a friend of mine, is in the phase of migrating from git to cvs.\n                                                         ^^^^^^^^^^^^^^^\nMan... You are _definitely_ on the wrong list. ;)\n\n> He releases tar balls of his software project using gitweb. He would\n> love to have a way to have the commit-id of HEAD of the export contained\n> in one of the files he exported that way. Is there infrastructure in git\n> that makes that already possible or does he need to some kind of\n> gerneration tool by himself? Maybe it would be helpful if the\n> git-tar-tree would generate a file .commitid or something like that in\n> the generated tar tree.\n\nHmm, doesn't seem like git-tar-tree (or git-archive for that matter) \nsupports this out of the box. Maybe it's possible to achieve in combination \nwith the $Id$ construct?\n\nI guess it depends on whether git-tar-tree/git-archive actually does a \ncheckout from the repo from which the archive is made. If so, it should \nbe possible to store \"$Id$\" in .commitid, and check it in, and it should \nautomagically appear with the correct commit-id in your archive.\n\nOf course, it all depends on whether the $Id$ conversion is triggered by \ngit-archive...\n\n\nHave fun!\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"42414","messageId":"59ad55d30705171002m503feb17l64fea9ffe2cf2297@mail.gmail.com","threadId":"8191","inReplyTo":"20070517163803.GE4095@cip.informatik.uni-erlangen.de","subject":"Re: Commit ID in exported Tar Ball","fromName":"Kristian Høgsberg","fromEmail":"krh@bitplanet.net","sentAt":"2007-05-17T17:02:26Z","receivedAt":"2007-05-17T17:02:26Z","isPatch":false,"sender":{"key":"krh@bitplanet.net","avatar":"https://gravatar.com/avatar/6ba3f320dfeafb6821e9824d11122fe7157e39c443476c4cf35d6dd830052d1d?d=mp&s=160"},"body":"On 5/17/07, Thomas Glanzmann <thomas@glanzmann.de> wrote:\n> Hello,\n> Michae, a friend of mine, is in the phase of migrating from git to cvs.\n> He releases tar balls of his software project using gitweb. He would\n> love to have a way to have the commit-id of HEAD of the export contained\n> in one of the files he exported that way. Is there infrastructure in git\n> that makes that already possible or does he need to some kind of\n> gerneration tool by himself? Maybe it would be helpful if the\n> git-tar-tree would generate a file .commitid or something like that in\n> the generated tar tree.\n\nUse git-get-tar-commit-id:\n\n  $ gzip -cd snapshot.tar.gz | git-get-tar-commit-id\n\ncheers,\nKristian\n"},{"id":"42415","messageId":"20070517171150.GL5272@planck.djpig.de","threadId":"8191","inReplyTo":"200705171857.22891.johan@herland.net","subject":"Re: Commit ID in exported Tar Ball","fromName":"Frank Lichtenheld","fromEmail":"frank@lichtenheld.de","sentAt":"2007-05-17T17:11:50Z","receivedAt":"2007-05-17T17:11:50Z","isPatch":false,"sender":{"key":"frank@lichtenheld.de","avatar":"https://gravatar.com/avatar/b9f1d4b120e138f157c9e480d0818197c474628923786adb98f30017cdb99c3c?d=mp&s=160"},"body":"On Thu, May 17, 2007 at 06:57:22PM +0200, Johan Herland wrote:\n> Of course, it all depends on whether the $Id$ conversion is triggered by \n> git-archive...\n\nAnother possibility might be to add a commandline switch to git-archive\nso you can decide whether the commit id should be added as a header to\nthe tar file (which it already supports) or as a ordinary file (which\nshould be reasonable trivial to implement). The question if whether\nit would be worth to add that feature. Don't know if there are many\nother users out there that need it.\n\nGruesse,\n-- \nFrank Lichtenheld <frank@lichtenheld.de>\nwww: http://www.djpig.de/\n"},{"id":"42416","messageId":"20070517171340.GF4095@cip.informatik.uni-erlangen.de","threadId":"8191","inReplyTo":"59ad55d30705171002m503feb17l64fea9ffe2cf2297@mail.gmail.com","subject":"Re: Commit ID in exported Tar Ball","fromName":"Thomas Glanzmann","fromEmail":"thomas@glanzmann.de","sentAt":"2007-05-17T17:13:40Z","receivedAt":"2007-05-17T17:13:40Z","isPatch":false,"sender":{"key":"thomas@glanzmann.de","avatar":null},"body":"Hello,\n\n>  $ gzip -cd snapshot.tar.gz | git-get-tar-commit-id\n\nnot good enough. What he wants is:\n\n        - user loads tar tree down from gitweb via the 'snapshot'\n          button.\n\n        - user extracts the tarball and types make\n\n        - The output of the produced binary contains a unique\n          identifier.\n\n        Thomas\n"},{"id":"42417","messageId":"20070517171457.GG4095@cip.informatik.uni-erlangen.de","threadId":"8191","inReplyTo":"20070517171150.GL5272@planck.djpig.de","subject":"Re: Commit ID in exported Tar Ball","fromName":"Thomas Glanzmann","fromEmail":"thomas@glanzmann.de","sentAt":"2007-05-17T17:14:57Z","receivedAt":"2007-05-17T17:14:57Z","isPatch":false,"sender":{"key":"thomas@glanzmann.de","avatar":null},"body":"Hello,\n\n> Another possibility might be to add a commandline switch to\n> git-archive so you can decide whether the commit id should be added as\n> a header to the tar file (which it already supports) or as a ordinary\n> file (which should be reasonable trivial to implement). The question\n> if whether it would be worth to add that feature. Don't know if there\n> are many other users out there that need it.\n\nthat would be very good aproach I guess. At least from my point of view.\nBecause it doesn't break diffs, it concentrates on what matters and if\nyou don't like it you don't use it.\n\n        Thomas\n"},{"id":"42418","messageId":"200705171928.34927.johan@herland.net","threadId":"8191","inReplyTo":"20070517171150.GL5272@planck.djpig.de","subject":"Re: Commit ID in exported Tar Ball","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2007-05-17T17:28:34Z","receivedAt":"2007-05-17T17:28:34Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Thursday 17 May 2007, Frank Lichtenheld wrote:\n> On Thu, May 17, 2007 at 06:57:22PM +0200, Johan Herland wrote:\n> > Of course, it all depends on whether the $Id$ conversion is triggered by \n> > git-archive...\n> \n> Another possibility might be to add a commandline switch to git-archive\n> so you can decide whether the commit id should be added as a header to\n> the tar file (which it already supports) or as a ordinary file (which\n> should be reasonable trivial to implement). The question if whether\n> it would be worth to add that feature. Don't know if there are many\n> other users out there that need it.\n\nAlthough this efficiently solves Michael's problem, I still think the ideal \nsolution would be for git-archive to do the same conversions/filters as a \nregular checkout would. Otherwise, we'll easily get into situations where \na git-archive tree is different enough from a \"regular\" working tree to \ncause annoying differences in behaviour.\n\n\nHave fun!\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"42421","messageId":"20070517174807.GM5272@planck.djpig.de","threadId":"8191","inReplyTo":"200705171857.22891.johan@herland.net","subject":"Re: Commit ID in exported Tar Ball","fromName":"Frank Lichtenheld","fromEmail":"frank@lichtenheld.de","sentAt":"2007-05-17T17:48:07Z","receivedAt":"2007-05-17T17:48:07Z","isPatch":false,"sender":{"key":"frank@lichtenheld.de","avatar":"https://gravatar.com/avatar/b9f1d4b120e138f157c9e480d0818197c474628923786adb98f30017cdb99c3c?d=mp&s=160"},"body":"On Thu, May 17, 2007 at 06:57:22PM +0200, Johan Herland wrote:\n> Hmm, doesn't seem like git-tar-tree (or git-archive for that matter) \n> supports this out of the box. Maybe it's possible to achieve in combination \n> with the $Id$ construct?\n\n$Id$ contains the blob id, not the commit id.\n\nGruesse,\n-- \nFrank Lichtenheld <frank@lichtenheld.de>\nwww: http://www.djpig.de/\n"},{"id":"42422","messageId":"200705172005.14196.johan@herland.net","threadId":"8191","inReplyTo":"20070517174807.GM5272@planck.djpig.de","subject":"Re: Commit ID in exported Tar Ball","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2007-05-17T18:05:14Z","receivedAt":"2007-05-17T18:05:14Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Thursday 17 May 2007, Frank Lichtenheld wrote:\n> On Thu, May 17, 2007 at 06:57:22PM +0200, Johan Herland wrote:\n> > Hmm, doesn't seem like git-tar-tree (or git-archive for that matter) \n> > supports this out of the box. Maybe it's possible to achieve in combination \n> > with the $Id$ construct?\n> \n> $Id$ contains the blob id, not the commit id.\n\nOops. My bad. In that case, your solution (to add another commandline switch \nto git-archive) is definitely what Michael needs.\n\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"42541","messageId":"464E2425.2030904@lsrfire.ath.cx","threadId":"8191","inReplyTo":"200705171928.34927.johan@herland.net","subject":"[PATCH] git-archive: convert archive entries like checkouts do","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2007-05-18T22:09:41Z","receivedAt":"2007-05-18T22:09:41Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"As noted by Johan Herland, git-archive is a kind of checkout and needs\nto apply any checkout filters that might be configured.\n\nThis patch adds the convenience function convert_sha1_file which returns\na buffer containing the object's contents, after converting, if necessary\n(i.e. it's a combination of read_sha1_file and convert_to_working_tree).\nDirect calls to read_sha1_file in git-archive are then replaced by calls\nto convert_sha1_file.\n\nSince convert_sha1_file expects its path argument to be NUL-terminated --\na convention it inherits from convert_to_working_tree -- the patch also\nchanges the path handling in archive-tar.c to always NUL-terminate the\nstring.  It used to solely rely on the len field of struct strbuf before.\n\narchive-zip.c already NUL-terminates the path and thus needs no such\nchange.\n\nSigned-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>\n\n---\n archive-tar.c |   12 +++++++-----\n archive-zip.c |    2 +-\n cache.h       |    1 +\n convert.c     |   15 +++++++++++++++\n 4 files changed, 24 insertions(+), 6 deletions(-)\n\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 56ff356..eb0abc7 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -83,11 +83,12 @@ static void strbuf_append_string(struct strbuf *sb, const char *s)\n \tint slen = strlen(s);\n \tint total = sb->len + slen;\n \tif (total > sb->alloc) {\n-\t\tsb->buf = xrealloc(sb->buf, total);\n-\t\tsb->alloc = total;\n+\t\tsb->buf = xrealloc(sb->buf, total + 1);\n+\t\tsb->alloc = total + 1;\n \t}\n \tmemcpy(sb->buf + sb->len, s, slen);\n \tsb->len = total;\n+\tsb->buf[total] = '\\0';\n }\n \n /*\n@@ -272,18 +273,19 @@ static int write_tar_entry(const unsigned char *sha1,\n \t}\n \tif (path.alloc < baselen + filenamelen) {\n \t\tfree(path.buf);\n-\t\tpath.buf = xmalloc(baselen + filenamelen);\n-\t\tpath.alloc = baselen + filenamelen;\n+\t\tpath.buf = xmalloc(baselen + filenamelen + 1);\n+\t\tpath.alloc = baselen + filenamelen + 1;\n \t}\n \tmemcpy(path.buf, base, baselen);\n \tmemcpy(path.buf + baselen, filename, filenamelen);\n \tpath.len = baselen + filenamelen;\n+\tpath.buf[path.len] = '\\0';\n \tif (S_ISDIR(mode) || S_ISDIRLNK(mode)) {\n \t\tstrbuf_append_string(&path, \"/\");\n \t\tbuffer = NULL;\n \t\tsize = 0;\n \t} else {\n-\t\tbuffer = read_sha1_file(sha1, &type, &size);\n+\t\tbuffer = convert_sha1_file(path.buf, sha1, mode, &type, &size);\n \t\tif (!buffer)\n \t\t\tdie(\"cannot read %s\", sha1_to_hex(sha1));\n \t}\ndiff --git a/archive-zip.c b/archive-zip.c\nindex 1eaf262..3cbf6bb 100644\n--- a/archive-zip.c\n+++ b/archive-zip.c\n@@ -195,7 +195,7 @@ static int write_zip_entry(const unsigned char *sha1,\n \t\tif (S_ISREG(mode) && zlib_compression_level != 0)\n \t\t\tmethod = 8;\n \t\tresult = 0;\n-\t\tbuffer = read_sha1_file(sha1, &type, &size);\n+\t\tbuffer = convert_sha1_file(path, sha1, mode, &type, &size);\n \t\tif (!buffer)\n \t\t\tdie(\"cannot read %s\", sha1_to_hex(sha1));\n \t\tcrc = crc32(crc, buffer, size);\ndiff --git a/cache.h b/cache.h\nindex aaeb04a..4204bc1 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -548,6 +548,7 @@ extern void trace_argv_printf(const char **argv, int count, const char *format,\n /* convert.c */\n extern char *convert_to_git(const char *path, const char *src, unsigned long *sizep);\n extern char *convert_to_working_tree(const char *path, const char *src, unsigned long *sizep);\n+extern void *convert_sha1_file(const char *path, const unsigned char *sha1, unsigned int mode, enum object_type *type, unsigned long *size);\n \n /* match-trees.c */\n void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, int);\ndiff --git a/convert.c b/convert.c\nindex 12abdaf..c64880b 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -652,3 +652,18 @@ char *convert_to_working_tree(const char *path, const char *src, unsigned long *\n \n \treturn buf;\n }\n+\n+void *convert_sha1_file(const char *path, const unsigned char *sha1,\n+                        unsigned int mode, enum object_type *type,\n+                        unsigned long *size)\n+{\n+\tvoid *buffer = read_sha1_file(sha1, type, size);\n+\tif (S_ISREG(mode) && buffer) {\n+\t\tvoid *converted = convert_to_working_tree(path, buffer, size);\n+\t\tif (converted) {\n+\t\t\tfree(buffer);\n+\t\t\tbuffer = converted;\n+\t\t}\n+\t}\n+\treturn buffer;\n+}\n"},{"id":"42544","messageId":"Pine.LNX.4.64.0705181826220.18541@iabervon.org","threadId":"8191","inReplyTo":"464E2425.2030904@lsrfire.ath.cx","subject":"Re: [PATCH] git-archive: convert archive entries like checkouts do","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2007-05-18T22:27:49Z","receivedAt":"2007-05-18T22:27:49Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Sat, 19 May 2007, René Scharfe wrote:\n\n> diff --git a/archive-tar.c b/archive-tar.c\n> index 56ff356..eb0abc7 100644\n> --- a/archive-tar.c\n> +++ b/archive-tar.c\n> @@ -83,11 +83,12 @@ static void strbuf_append_string(struct strbuf *sb, const char *s)\n>  \tint slen = strlen(s);\n>  \tint total = sb->len + slen;\n>  \tif (total > sb->alloc) {\n> -\t\tsb->buf = xrealloc(sb->buf, total);\n> -\t\tsb->alloc = total;\n> +\t\tsb->buf = xrealloc(sb->buf, total + 1);\n> +\t\tsb->alloc = total + 1;\n\nConditional needs a \"+ 1\", too.\n\n>  \t}\n>  \tmemcpy(sb->buf + sb->len, s, slen);\n>  \tsb->len = total;\n> +\tsb->buf[total] = '\\0';\n>  }\n>  \n>  /*\n> @@ -272,18 +273,19 @@ static int write_tar_entry(const unsigned char *sha1,\n>  \t}\n>  \tif (path.alloc < baselen + filenamelen) {\n>  \t\tfree(path.buf);\n> -\t\tpath.buf = xmalloc(baselen + filenamelen);\n> -\t\tpath.alloc = baselen + filenamelen;\n> +\t\tpath.buf = xmalloc(baselen + filenamelen + 1);\n> +\t\tpath.alloc = baselen + filenamelen + 1;\n\nSame here.\n\n\t-Daniel\n*This .sig left intentionally blank*"},{"id":"42551","messageId":"464E2F82.7090309@lsrfire.ath.cx","threadId":"8191","inReplyTo":"Pine.LNX.4.64.0705181826220.18541@iabervon.org","subject":"Re: [PATCH] git-archive: convert archive entries like checkouts do","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2007-05-18T22:58:10Z","receivedAt":"2007-05-18T22:58:10Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Daniel Barkalow schrieb:\n> Conditional needs a \"+ 1\", too.\n[...]\n> Same here.\n\nThank you for spotting this.  Fix-up patch below.\n\nSigned-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>\n\n---\nEmbarrassing.  I'm off to go to sleep now.\n\n archive-tar.c |    4 ++--\n 1 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/archive-tar.c b/archive-tar.c\nindex eb0abc7..33e7657 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -82,7 +82,7 @@ static void strbuf_append_string(struct strbuf *sb, const char *s)\n {\n \tint slen = strlen(s);\n \tint total = sb->len + slen;\n-\tif (total > sb->alloc) {\n+\tif (total + 1 > sb->alloc) {\n \t\tsb->buf = xrealloc(sb->buf, total + 1);\n \t\tsb->alloc = total + 1;\n \t}\n@@ -271,7 +271,7 @@ static int write_tar_entry(const unsigned char *sha1,\n \t\tpath.alloc = PATH_MAX;\n \t\tpath.len = path.eof = 0;\n \t}\n-\tif (path.alloc < baselen + filenamelen) {\n+\tif (path.alloc < baselen + filenamelen + 1) {\n \t\tfree(path.buf);\n \t\tpath.buf = xmalloc(baselen + filenamelen + 1);\n \t\tpath.alloc = baselen + filenamelen + 1;\n"},{"id":"42647","messageId":"464F5CA2.3070809@lsrfire.ath.cx","threadId":"8191","inReplyTo":"20070517171150.GL5272@planck.djpig.de","subject":"Re: Commit ID in exported Tar Ball","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2007-05-19T20:22:58Z","receivedAt":"2007-05-19T20:22:58Z","isPatch":false,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Frank Lichtenheld schrieb:\n> On Thu, May 17, 2007 at 06:57:22PM +0200, Johan Herland wrote:\n>> Of course, it all depends on whether the $Id$ conversion is triggered by \n>> git-archive...\n> \n> Another possibility might be to add a commandline switch to git-archive\n> so you can decide whether the commit id should be added as a header to\n> the tar file (which it already supports) or as a ordinary file (which\n> should be reasonable trivial to implement). The question if whether\n> it would be worth to add that feature. Don't know if there are many\n> other users out there that need it.\n\nSomething like the following patch?  Since we're already embedding the\ncommit ID in a comment, we might as well offer creating a synthetic file\nfor it, too, if that solves a user's problem that might be difficult to\nwork around otherwise.\n\nRené\n\n\n Documentation/git-archive.txt |    4 ++++\n archive-tar.c                 |    7 +++++++\n archive-zip.c                 |    7 +++++++\n archive.h                     |    1 +\n builtin-archive.c             |   11 +++++++++++\n 5 files changed, 30 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt\nindex 721e035..ac31aac 100644\n--- a/Documentation/git-archive.txt\n+++ b/Documentation/git-archive.txt\n@@ -43,6 +43,10 @@ OPTIONS\n --prefix=<prefix>/::\n \tPrepend <prefix>/ to each filename in the archive.\n \n+--commit-id-file=<filename>::\n+\tAdds a file to the archive containing the commit ID.  This option\n+\tis ignored if <tree-ish> references a tree instead of a commit.\n+\n <extra>::\n \tThis can be any options that the archiver backend understand.\n \tSee next section.\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 33e7657..555850a 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -319,6 +319,13 @@ int write_tar_archive(struct archiver_args *args)\n \t}\n \tread_tree_recursive(args->tree, args->base, plen, 0,\n \t\t\t    args->pathspec, write_tar_entry);\n+\tif (args->commit_sha1 && args->commit_sha1_file) {\n+\t\tunsigned char fake_sha1[20];\n+\t\tpretend_sha1_file(sha1_to_hex(args->commit_sha1), 40,\n+\t\t                  OBJ_BLOB, fake_sha1);\n+\t\twrite_tar_entry(fake_sha1, args->base, plen,\n+\t\t                args->commit_sha1_file, 0100666, 0);\n+\t}\n \twrite_trailer();\n \n \treturn 0;\ndiff --git a/archive-zip.c b/archive-zip.c\nindex 3cbf6bb..88c5dfa 100644\n--- a/archive-zip.c\n+++ b/archive-zip.c\n@@ -328,6 +328,13 @@ int write_zip_archive(struct archiver_args *args)\n \t}\n \tread_tree_recursive(args->tree, args->base, plen, 0,\n \t\t\t    args->pathspec, write_zip_entry);\n+\tif (args->commit_sha1 && args->commit_sha1_file) {\n+\t\tunsigned char fake_sha1[20];\n+\t\tpretend_sha1_file(sha1_to_hex(args->commit_sha1), 40,\n+\t\t                  OBJ_BLOB, fake_sha1);\n+\t\twrite_zip_entry(fake_sha1, args->base, plen,\n+\t\t                args->commit_sha1_file, 0100666, 0);\n+\t}\n \twrite_zip_trailer(args->commit_sha1);\n \n \tfree(zip_dir);\ndiff --git a/archive.h b/archive.h\nindex 6838dc7..020f82f 100644\n--- a/archive.h\n+++ b/archive.h\n@@ -8,6 +8,7 @@ struct archiver_args {\n \tconst char *base;\n \tstruct tree *tree;\n \tconst unsigned char *commit_sha1;\n+\tconst char *commit_sha1_file;\n \ttime_t time;\n \tconst char **pathspec;\n \tunsigned int verbose : 1;\ndiff --git a/builtin-archive.c b/builtin-archive.c\nindex 7f4e409..e58ea16 100644\n--- a/builtin-archive.c\n+++ b/builtin-archive.c\n@@ -151,6 +151,7 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)\n \tint extra_argc = 0;\n \tconst char *format = \"tar\";\n \tconst char *base = \"\";\n+\tconst char *commit_sha1_file = NULL;\n \tint verbose = 0;\n \tint i;\n \n@@ -174,6 +175,10 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)\n \t\t\tbase = arg + 9;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!prefixcmp(arg, \"--commit-id-file=\")) {\n+\t\t\tcommit_sha1_file = arg + 17;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"--\")) {\n \t\t\ti++;\n \t\t\tbreak;\n@@ -192,6 +197,11 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)\n \t\tusage(archive_usage);\n \tif (init_archiver(format, ar) < 0)\n \t\tdie(\"Unknown archive format '%s'\", format);\n+\tif (commit_sha1_file) {\n+\t\tsize_t namelen = strlen(commit_sha1_file);\n+\t\tif (namelen == 0 || commit_sha1_file[namelen - 1] == '/')\n+\t\t\tdie(\"Invalid commit ID file name: %s\", commit_sha1_file);\n+\t}\n \n \tif (extra_argc) {\n \t\tif (!ar->parse_extra)\n@@ -201,6 +211,7 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)\n \t}\n \tar->args.verbose = verbose;\n \tar->args.base = base;\n+\tar->args.commit_sha1_file = commit_sha1_file;\n \n \treturn i;\n }\n"},{"id":"42650","messageId":"7vd50wv88t.fsf@assigned-by-dhcp.cox.net","threadId":"8191","inReplyTo":"464F5CA2.3070809@lsrfire.ath.cx","subject":"Re: Commit ID in exported Tar Ball","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-05-19T21:00:50Z","receivedAt":"2007-05-19T21:00:50Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"René Scharfe <rene.scharfe@lsrfire.ath.cx> writes:\n\n> Something like the following patch?  Since we're already embedding the\n> commit ID in a comment, we might as well offer creating a synthetic file\n> for it, too, if that solves a user's problem that might be difficult to\n> work around otherwise.\n\nAre you detecting and erroring out if the named file already\nexists in the tree being archived?\n\nShould we?  Maybe we should just replace with warning?\n\nAlso should we silently ignore the request if the tree-ish is\nnot a commit-ish, or error out?\n"},{"id":"42652","messageId":"464F6E9C.4070506@gmail.com","threadId":"8191","inReplyTo":"7vd50wv88t.fsf@assigned-by-dhcp.cox.net","subject":"Re: Commit ID in exported Tar Ball","fromName":"A Large Angry SCM","fromEmail":"gitzilla@gmail.com","sentAt":"2007-05-19T21:39:40Z","receivedAt":"2007-05-19T21:39:40Z","isPatch":false,"sender":{"key":"gitzilla@gmail.com","avatar":"https://gravatar.com/avatar/354625c442439908ff3dd99757dee330e29e9df7847472384faf7a00add247fb?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> René Scharfe <rene.scharfe@lsrfire.ath.cx> writes:\n> \n>> Something like the following patch?  Since we're already embedding the\n>> commit ID in a comment, we might as well offer creating a synthetic file\n>> for it, too, if that solves a user's problem that might be difficult to\n>> work around otherwise.\n> \n> Are you detecting and erroring out if the named file already\n> exists in the tree being archived?\n> \n> Should we?  Maybe we should just replace with warning?\n> \n> Also should we silently ignore the request if the tree-ish is\n> not a commit-ish, or error out?\n\nSilently ignoring conflicting command arguments is (almost always) a \nbug; either in the implementation or the design.\n"},{"id":"42661","messageId":"464F932D.6040509@lsrfire.ath.cx","threadId":"8191","inReplyTo":"7vd50wv88t.fsf@assigned-by-dhcp.cox.net","subject":"Re: Commit ID in exported Tar Ball","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2007-05-20T00:15:41Z","receivedAt":"2007-05-20T00:15:41Z","isPatch":false,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Junio C Hamano schrieb:\n> René Scharfe <rene.scharfe@lsrfire.ath.cx> writes:\n> \n>> Something like the following patch?  Since we're already embedding\n>> the commit ID in a comment, we might as well offer creating a\n>> synthetic file for it, too, if that solves a user's problem that\n>> might be difficult to work around otherwise.\n> \n> Are you detecting and erroring out if the named file already exists\n> in the tree being archived?\n> \n> Should we?  Maybe we should just replace with warning?\n\nCurrently the commit ID file is appended to the archive, so if there is\na name conflict, we keep both files.  unzip offers a choice between\nrenaming, overwriting and keeping the first extracted version when the\nsecond one is about to be extracted.  tar has a -k option: with -k you\nget the first version, without -k you get the second one.\n\nTo avoid confusion, we should disallow a name that already comes from\nthe tree.  Only I can't see an easy way to implement this.  Perhaps a\ncheck using get_tree_entry is enough -- it doesn't take pathspecs into\naccount, though.  That means we would disallow all names in the tree,\neven if a pathspec excludes the chosen commit ID file name.\n\nBefore I roll my own path existence checker with pathspec support, is\nthere something like that already implemented?  I suspect it's hiding in\nthe diff code, but I don't dare go near it. ;-)\n\n> Also should we silently ignore the request if the tree-ish is not a\n> commit-ish, or error out?\n\nAs Angry said, erroring out is better.  It's also easy to do.\n\n Documentation/git-archive.txt |    4 ++++\n archive-tar.c                 |    7 +++++++\n archive-zip.c                 |    7 +++++++\n archive.h                     |    1 +\n builtin-archive.c             |   32 ++++++++++++++++++++++++++++++++\n 5 files changed, 51 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt\nindex 721e035..7016d1e 100644\n--- a/Documentation/git-archive.txt\n+++ b/Documentation/git-archive.txt\n@@ -43,6 +43,10 @@ OPTIONS\n --prefix=<prefix>/::\n \tPrepend <prefix>/ to each filename in the archive.\n \n+--commit-id-file=<filename>::\n+\tAdds a file to the archive containing the commit ID.  This option\n+\tis can only be used if <tree-ish> references a commit or tag.\n+\n <extra>::\n \tThis can be any options that the archiver backend understand.\n \tSee next section.\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 33e7657..555850a 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -319,6 +319,13 @@ int write_tar_archive(struct archiver_args *args)\n \t}\n \tread_tree_recursive(args->tree, args->base, plen, 0,\n \t\t\t    args->pathspec, write_tar_entry);\n+\tif (args->commit_sha1 && args->commit_sha1_file) {\n+\t\tunsigned char fake_sha1[20];\n+\t\tpretend_sha1_file(sha1_to_hex(args->commit_sha1), 40,\n+\t\t                  OBJ_BLOB, fake_sha1);\n+\t\twrite_tar_entry(fake_sha1, args->base, plen,\n+\t\t                args->commit_sha1_file, 0100666, 0);\n+\t}\n \twrite_trailer();\n \n \treturn 0;\ndiff --git a/archive-zip.c b/archive-zip.c\nindex 3cbf6bb..88c5dfa 100644\n--- a/archive-zip.c\n+++ b/archive-zip.c\n@@ -328,6 +328,13 @@ int write_zip_archive(struct archiver_args *args)\n \t}\n \tread_tree_recursive(args->tree, args->base, plen, 0,\n \t\t\t    args->pathspec, write_zip_entry);\n+\tif (args->commit_sha1 && args->commit_sha1_file) {\n+\t\tunsigned char fake_sha1[20];\n+\t\tpretend_sha1_file(sha1_to_hex(args->commit_sha1), 40,\n+\t\t                  OBJ_BLOB, fake_sha1);\n+\t\twrite_zip_entry(fake_sha1, args->base, plen,\n+\t\t                args->commit_sha1_file, 0100666, 0);\n+\t}\n \twrite_zip_trailer(args->commit_sha1);\n \n \tfree(zip_dir);\ndiff --git a/archive.h b/archive.h\nindex 6838dc7..020f82f 100644\n--- a/archive.h\n+++ b/archive.h\n@@ -8,6 +8,7 @@ struct archiver_args {\n \tconst char *base;\n \tstruct tree *tree;\n \tconst unsigned char *commit_sha1;\n+\tconst char *commit_sha1_file;\n \ttime_t time;\n \tconst char **pathspec;\n \tunsigned int verbose : 1;\ndiff --git a/builtin-archive.c b/builtin-archive.c\nindex 7f4e409..6bb0781 100644\n--- a/builtin-archive.c\n+++ b/builtin-archive.c\n@@ -151,6 +151,7 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)\n \tint extra_argc = 0;\n \tconst char *format = \"tar\";\n \tconst char *base = \"\";\n+\tconst char *commit_sha1_file = NULL;\n \tint verbose = 0;\n \tint i;\n \n@@ -174,6 +175,10 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)\n \t\t\tbase = arg + 9;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!prefixcmp(arg, \"--commit-id-file=\")) {\n+\t\t\tcommit_sha1_file = arg + 17;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"--\")) {\n \t\t\ti++;\n \t\t\tbreak;\n@@ -192,6 +197,11 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)\n \t\tusage(archive_usage);\n \tif (init_archiver(format, ar) < 0)\n \t\tdie(\"Unknown archive format '%s'\", format);\n+\tif (commit_sha1_file) {\n+\t\tsize_t namelen = strlen(commit_sha1_file);\n+\t\tif (namelen == 0 || commit_sha1_file[namelen - 1] == '/')\n+\t\t\tdie(\"Invalid commit ID file name: %s\", commit_sha1_file);\n+\t}\n \n \tif (extra_argc) {\n \t\tif (!ar->parse_extra)\n@@ -201,6 +211,7 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)\n \t}\n \tar->args.verbose = verbose;\n \tar->args.base = base;\n+\tar->args.commit_sha1_file = commit_sha1_file;\n \n \treturn i;\n }\n@@ -236,6 +247,20 @@ static const char *extract_remote_arg(int *ac, const char **av)\n \treturn remote;\n }\n \n+static int is_path_in_spec(struct tree *tree, const char **pathspec,\n+                           const char *path)\n+{\n+\tunsigned char sha1[20];\n+\tunsigned int mode;\n+\n+\tif (get_tree_entry(tree->object.sha1, path, sha1, &mode))\n+\t\treturn 0;\n+\tif (!pathspec)\n+\t\treturn 1;\n+\t/* TODO: the actual pathspec check */\n+\treturn 1;\n+}\n+\n int cmd_archive(int argc, const char **argv, const char *prefix)\n {\n \tstruct archiver ar;\n@@ -257,5 +282,12 @@ int cmd_archive(int argc, const char **argv, const char *prefix)\n \tparse_treeish_arg(argv, &ar.args, prefix);\n \tparse_pathspec_arg(argv + 1, &ar.args);\n \n+\tif (ar.args.commit_sha1_file) {\n+\t\tif (is_path_in_spec(ar.args.tree, ar.args.pathspec, ar.args.commit_sha1_file))\n+\t\t\tdie(\"Commit ID file name already exists in archive.\");\n+\t\tif (!ar.args.commit_sha1)\n+\t\t\tdie(\"Need a commit to use --commit-id-file, and not a tree.\");\n+\t}\n+\n \treturn ar.write_archive(&ar.args);\n }\n"},{"id":"42670","messageId":"20070520035752.GG3141@spearce.org","threadId":"8191","inReplyTo":"7vd50wv88t.fsf@assigned-by-dhcp.cox.net","subject":"Re: Commit ID in exported Tar Ball","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-05-20T03:57:52Z","receivedAt":"2007-05-20T03:57:52Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Junio C Hamano <junkio@cox.net> wrote:\n> René Scharfe <rene.scharfe@lsrfire.ath.cx> writes:\n> \n> > Something like the following patch?  Since we're already embedding the\n> > commit ID in a comment, we might as well offer creating a synthetic file\n> > for it, too, if that solves a user's problem that might be difficult to\n> > work around otherwise.\n\nWhat about being able to get the output of git-describe embedded\ninto an archive file?  Doesn't git.git do that in its Makefile?  ;-)\n\ngit-describe is more human-friendly than a SHA-1...\n\n-- \nShawn.\n"},{"id":"42703","messageId":"46502EF7.6000708@lsrfire.ath.cx","threadId":"8191","inReplyTo":"20070520035752.GG3141@spearce.org","subject":"Re: Commit ID in exported Tar Ball","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2007-05-20T11:20:23Z","receivedAt":"2007-05-20T11:20:23Z","isPatch":false,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Shawn O. Pearce schrieb:\n> Junio C Hamano <junkio@cox.net> wrote:\n>> René Scharfe <rene.scharfe@lsrfire.ath.cx> writes:\n>>\n>>> Something like the following patch?  Since we're already embedding the\n>>> commit ID in a comment, we might as well offer creating a synthetic file\n>>> for it, too, if that solves a user's problem that might be difficult to\n>>> work around otherwise.\n> \n> What about being able to get the output of git-describe embedded\n> into an archive file?  Doesn't git.git do that in its Makefile?  ;-)\n> \n> git-describe is more human-friendly than a SHA-1...\n\nYes, and the Makefile does even more than that: it adds a version file,\na spec file and another version file for git-gui.\n\nThe first two are probably useful for most projects that actually do\nversioned releases.  We could have a simple parser that reads a\ntemplate, replaces @@VERSION@@ with a git-describe output string and\nadds the result as a synthetic file to the archive.  It's not exactly\ntrivial -- e.g., how to specify git-describe options, template file and\nsynthetic name, all in one command line parameter? -- but it's doable.\n\nI'm not sure how the git-gui version file fits in.  I guess it's just a\nspecial case and doesn't need git-archive support?\n\nRené\n"},{"id":"42702","messageId":"46502EFF.2080104@lsrfire.ath.cx","threadId":"8191","inReplyTo":"464F932D.6040509@lsrfire.ath.cx","subject":"Re: Commit ID in exported Tar Ball","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2007-05-20T11:20:31Z","receivedAt":"2007-05-20T11:20:31Z","isPatch":false,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Turns out a matcher for the kind of pathspecs used in git-archive\nis much easier to write than I thought. :-)\n\nThis is just a progress note and not for inclusion, yet -- Shawn has\na good point suggesting git-describe output to be used instead of\nbare commit IDs.\n\n Documentation/git-archive.txt |    4 +++\n archive-tar.c                 |    7 ++++++\n archive-zip.c                 |    7 ++++++\n archive.h                     |    1 +\n builtin-archive.c             |   44 +++++++++++++++++++++++++++++++++++++++++\n 5 files changed, 63 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt\nindex 721e035..7016d1e 100644\n--- a/Documentation/git-archive.txt\n+++ b/Documentation/git-archive.txt\n@@ -43,6 +43,10 @@ OPTIONS\n --prefix=<prefix>/::\n \tPrepend <prefix>/ to each filename in the archive.\n \n+--commit-id-file=<filename>::\n+\tAdds a file to the archive containing the commit ID.  This option\n+\tis can only be used if <tree-ish> references a commit or tag.\n+\n <extra>::\n \tThis can be any options that the archiver backend understand.\n \tSee next section.\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 33e7657..555850a 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -319,6 +319,13 @@ int write_tar_archive(struct archiver_args *args)\n \t}\n \tread_tree_recursive(args->tree, args->base, plen, 0,\n \t\t\t    args->pathspec, write_tar_entry);\n+\tif (args->commit_sha1 && args->commit_sha1_file) {\n+\t\tunsigned char fake_sha1[20];\n+\t\tpretend_sha1_file(sha1_to_hex(args->commit_sha1), 40,\n+\t\t                  OBJ_BLOB, fake_sha1);\n+\t\twrite_tar_entry(fake_sha1, args->base, plen,\n+\t\t                args->commit_sha1_file, 0100666, 0);\n+\t}\n \twrite_trailer();\n \n \treturn 0;\ndiff --git a/archive-zip.c b/archive-zip.c\nindex 3cbf6bb..88c5dfa 100644\n--- a/archive-zip.c\n+++ b/archive-zip.c\n@@ -328,6 +328,13 @@ int write_zip_archive(struct archiver_args *args)\n \t}\n \tread_tree_recursive(args->tree, args->base, plen, 0,\n \t\t\t    args->pathspec, write_zip_entry);\n+\tif (args->commit_sha1 && args->commit_sha1_file) {\n+\t\tunsigned char fake_sha1[20];\n+\t\tpretend_sha1_file(sha1_to_hex(args->commit_sha1), 40,\n+\t\t                  OBJ_BLOB, fake_sha1);\n+\t\twrite_zip_entry(fake_sha1, args->base, plen,\n+\t\t                args->commit_sha1_file, 0100666, 0);\n+\t}\n \twrite_zip_trailer(args->commit_sha1);\n \n \tfree(zip_dir);\ndiff --git a/archive.h b/archive.h\nindex 6838dc7..020f82f 100644\n--- a/archive.h\n+++ b/archive.h\n@@ -8,6 +8,7 @@ struct archiver_args {\n \tconst char *base;\n \tstruct tree *tree;\n \tconst unsigned char *commit_sha1;\n+\tconst char *commit_sha1_file;\n \ttime_t time;\n \tconst char **pathspec;\n \tunsigned int verbose : 1;\ndiff --git a/builtin-archive.c b/builtin-archive.c\nindex 7f4e409..1fe4d47 100644\n--- a/builtin-archive.c\n+++ b/builtin-archive.c\n@@ -151,6 +151,7 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)\n \tint extra_argc = 0;\n \tconst char *format = \"tar\";\n \tconst char *base = \"\";\n+\tconst char *commit_sha1_file = NULL;\n \tint verbose = 0;\n \tint i;\n \n@@ -174,6 +175,10 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)\n \t\t\tbase = arg + 9;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!prefixcmp(arg, \"--commit-id-file=\")) {\n+\t\t\tcommit_sha1_file = arg + 17;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"--\")) {\n \t\t\ti++;\n \t\t\tbreak;\n@@ -192,6 +197,11 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)\n \t\tusage(archive_usage);\n \tif (init_archiver(format, ar) < 0)\n \t\tdie(\"Unknown archive format '%s'\", format);\n+\tif (commit_sha1_file) {\n+\t\tsize_t namelen = strlen(commit_sha1_file);\n+\t\tif (namelen == 0 || commit_sha1_file[namelen - 1] == '/')\n+\t\t\tdie(\"Invalid commit ID file name: %s\", commit_sha1_file);\n+\t}\n \n \tif (extra_argc) {\n \t\tif (!ar->parse_extra)\n@@ -201,6 +211,7 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)\n \t}\n \tar->args.verbose = verbose;\n \tar->args.base = base;\n+\tar->args.commit_sha1_file = commit_sha1_file;\n \n \treturn i;\n }\n@@ -236,6 +247,32 @@ static const char *extract_remote_arg(int *ac, const char **av)\n \treturn remote;\n }\n \n+static int is_path_in_spec(const struct archiver_args *args, const char *path)\n+{\n+\tunsigned char sha1[20];\n+\tunsigned int mode;\n+\tconst char *match;\n+\tconst char **pathspec = args->pathspec;\n+\n+\tif (get_tree_entry(args->tree->object.sha1, path, sha1, &mode))\n+\t\treturn 0;\n+\tif (!pathspec)\n+\t\treturn 1;\n+\twhile ((match = *pathspec++) != NULL) {\n+\t\tsize_t matchlen = strlen(match);\n+\t\tif (matchlen == 0)\n+\t\t\treturn 1;\n+\t\tif (match[matchlen - 1] == '/') {\n+\t\t\tif (!prefixcmp(path, match))\n+\t\t\t\treturn 1;\n+\t\t} else {\n+\t\t\tif (!strcmp(path, match))\n+\t\t\t\treturn 1;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n int cmd_archive(int argc, const char **argv, const char *prefix)\n {\n \tstruct archiver ar;\n@@ -257,5 +294,12 @@ int cmd_archive(int argc, const char **argv, const char *prefix)\n \tparse_treeish_arg(argv, &ar.args, prefix);\n \tparse_pathspec_arg(argv + 1, &ar.args);\n \n+\tif (ar.args.commit_sha1_file) {\n+\t\tif (is_path_in_spec(&ar.args, ar.args.commit_sha1_file))\n+\t\t\tdie(\"Commit ID file name already exists in archive.\");\n+\t\tif (!ar.args.commit_sha1)\n+\t\t\tdie(\"Need a commit to use --commit-id-file, and not a tree.\");\n+\t}\n+\n \treturn ar.write_archive(&ar.args);\n }\n"},{"id":"42701","messageId":"46502F04.9050307@lsrfire.ath.cx","threadId":"8191","inReplyTo":"20070520035752.GG3141@spearce.org","subject":"Re: Commit ID in exported Tar Ball","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2007-05-20T11:20:36Z","receivedAt":"2007-05-20T11:20:36Z","isPatch":false,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Shawn O. Pearce schrieb:\n> Junio C Hamano <junkio@cox.net> wrote:\n>> René Scharfe <rene.scharfe@lsrfire.ath.cx> writes:\n>>\n>>> Something like the following patch?  Since we're already embedding the\n>>> commit ID in a comment, we might as well offer creating a synthetic file\n>>> for it, too, if that solves a user's problem that might be difficult to\n>>> work around otherwise.\n> \n> What about being able to get the output of git-describe embedded\n> into an archive file?  Doesn't git.git do that in its Makefile?  ;-)\n> \n> git-describe is more human-friendly than a SHA-1...\n\nYes, and the Makefile does even more than that: it adds a version file,\na spec file and another version file for git-gui.\n\nThe first two are probably useful for most projects that actually do\nversioned releases.  We could have a simple parser that reads a\ntemplate, replaces @@VERSION@@ with a git-describe output string and\nadds the result as a synthetic file to the archive.  It's not exactly\ntrivial -- e.g., how to specify git-describe options, template file and\nsynthetic name, all in one command line parameter? -- but it's doable.\n\nI'm not sure how the git-gui version file fits in.  I guess it's just a\nspecial case and doesn't need git-archive support?\n\nRené\n"},{"id":"42725","messageId":"20070520161048.GI5015@cip.informatik.uni-erlangen.de","threadId":"8191","inReplyTo":"20070520035752.GG3141@spearce.org","subject":"Re: Commit ID in exported Tar Ball","fromName":"Thomas Glanzmann","fromEmail":"thomas@glanzmann.de","sentAt":"2007-05-20T16:10:48Z","receivedAt":"2007-05-20T16:10:48Z","isPatch":false,"sender":{"key":"thomas@glanzmann.de","avatar":null},"body":"Hello,\n\n> git-describe is more human-friendly than a SHA-1...\n\nFor me git-describe does the following:\n\n        (thinkpad) [~/work/slides] git-describe --all HEAD\n        heads/master\n\nI don't see how Michael is able to tell from this output what version\nhis users is using. Do I miss something? I really do like the patch Rene\nhas submitted. And it is exactly what is missing. A unique identifier\nwhich tells the exact version of the tree the user is using.\n\n        Thomas\n"},{"id":"42729","messageId":"817CD103-261C-4D40-9C8F-00B2E14130BE@silverinsanity.com","threadId":"8191","inReplyTo":"20070520161048.GI5015@cip.informatik.uni-erlangen.de","subject":"Re: Commit ID in exported Tar Ball","fromName":"Brian Gernhardt","fromEmail":"benji@silverinsanity.com","sentAt":"2007-05-20T16:28:53Z","receivedAt":"2007-05-20T16:28:53Z","isPatch":false,"sender":{"key":"benji@silverinsanity.com","avatar":"https://gravatar.com/avatar/e06c101dbc25c68114d859b4a9ec7cf8a2c52fd2b0270ef0eac0e2e63ff22311?d=mp&s=160"},"body":"\nOn May 20, 2007, at 12:10 PM, Thomas Glanzmann wrote:\n\n> Hello,\n>\n>> git-describe is more human-friendly than a SHA-1...\n>\n> For me git-describe does the following:\n>\n>         (thinkpad) [~/work/slides] git-describe --all HEAD\n>         heads/master\n>\n> I don't see how Michael is able to tell from this output what version\n> his users is using. Do I miss something? I really do like the patch  \n> Rene\n> has submitted. And it is exactly what is missing. A unique identifier\n> which tells the exact version of the tree the user is using.\n\nFor version information it is far more useful to use --tags or no  \noptions (annotated tags only) instead of --all.\n\n# On git.git's master this morning:\n$ git describe HEAD\nv1.5.2\n$ git describe HEAD^^\nv1.5.2-rc3-97-g03f6db0\n\n~~ Brian\n"},{"id":"42730","messageId":"20070520163026.GA7387@cip.informatik.uni-erlangen.de","threadId":"8191","inReplyTo":"817CD103-261C-4D40-9C8F-00B2E14130BE@silverinsanity.com","subject":"Re: Commit ID in exported Tar Ball","fromName":"Thomas Glanzmann","fromEmail":"thomas@glanzmann.de","sentAt":"2007-05-20T16:30:26Z","receivedAt":"2007-05-20T16:30:26Z","isPatch":false,"sender":{"key":"thomas@glanzmann.de","avatar":null},"body":"Hello,\n\n> For version information it is far more useful to use --tags or no options \n> (annotated tags only) instead of --all.\n\nso this output is useless if you don't have tagged the commit which\nisn't the case. But thanks for the awareness.\n\n        Thomas\n"},{"id":"42841","messageId":"20070521060231.GI3141@spearce.org","threadId":"8191","inReplyTo":"46502EF7.6000708@lsrfire.ath.cx","subject":"Re: Commit ID in exported Tar Ball","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-05-21T06:02:32Z","receivedAt":"2007-05-21T06:02:32Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Ren?? Scharfe <rene.scharfe@lsrfire.ath.cx> wrote:\n> Shawn O. Pearce schrieb:\n> > \n> > git-describe is more human-friendly than a SHA-1...\n> \n> Yes, and the Makefile does even more than that: it adds a version file,\n> a spec file and another version file for git-gui.\n> \n> The first two are probably useful for most projects that actually do\n> versioned releases.  We could have a simple parser that reads a\n> template, replaces @@VERSION@@ with a git-describe output string and\n> adds the result as a synthetic file to the archive.  It's not exactly\n> trivial -- e.g., how to specify git-describe options, template file and\n> synthetic name, all in one command line parameter? -- but it's doable.\n\nMaybe something just as simple as allowing the user to specify a\nshell script in-tree that we unpack and run for them?  That script\nprints to stdout the content of the file to include.\n \n> I'm not sure how the git-gui version file fits in.  I guess it's just a\n> special case and doesn't need git-archive support?\n\nWell, if you look at git-gui's own version script it really just\nwants to do `git-describe` like git.git's script, but it cannot as\nwhen its hosted in git.git `git-describe` gives us back Git's version\nnumber, not git-gui's version number.  So we get cute and look for\nthe merge commit, and take the second parent, and describe that.\nThat's (by convention of how Junio works) always a true git-gui\ncommit.\n\nIn other words, git-gui.git gets a little whacky when Junio\ndistributes it in git.git.  git-gui really needs to become\na subproject.  When that happens its git-describe will become\nmuch easier.\n\nSo now we're also really talking about, what should git-archive\ndo for a subproject?  Sometimes you really do want to repackage\nand redistribute the subproject as part of the superproject's\ntarball. Sometimes you don't.  I think in the case of git.git and\ngit-gui.git we want to include the subproject.  ;-)\n\n-- \nShawn.\n"},{"id":"42845","messageId":"20070521061954.GB8605@xp.machine.xx","threadId":"8191","inReplyTo":"20070520163026.GA7387@cip.informatik.uni-erlangen.de","subject":"Re: Commit ID in exported Tar Ball","fromName":"Peter Baumann","fromEmail":"waste.manager@gmx.de","sentAt":"2007-05-21T06:19:54Z","receivedAt":"2007-05-21T06:19:54Z","isPatch":false,"sender":{"key":"waste.manager@gmx.de","avatar":null},"body":"On Sun, May 20, 2007 at 06:30:26PM +0200, Thomas Glanzmann wrote:\n> Hello,\n> \n> > For version information it is far more useful to use --tags or no options \n> > (annotated tags only) instead of --all.\n> \n> so this output is useless if you don't have tagged the commit which\n> isn't the case. But thanks for the awareness.\n> \n\nNo. Just _ONE_ tagged commit should be enough. In a project of mine I\ntagged the root commit and as I am the only committer and this project\nis so simple that I don't have to do a lot of branching/merging, I get a\nsingle line of history\n\n\tt - o1 - o2 - o3 - o4 <- master\n\t^\n\t|- tagged root commit\n\nThis gives me very nicely enumerated commits like tag-1-g<sha1-abbrev> for\nthe commit o1 and tag-2-g<sha1-abbrev> for o2 ... you get the idea.\n\n-Peter\n"},{"id":"42844","messageId":"20070521062406.GA23350@cip.informatik.uni-erlangen.de","threadId":"8191","inReplyTo":"20070521061954.GB8605@xp.machine.xx","subject":"Re: Commit ID in exported Tar Ball","fromName":"Thomas Glanzmann","fromEmail":"thomas@glanzmann.de","sentAt":"2007-05-21T06:24:06Z","receivedAt":"2007-05-21T06:24:06Z","isPatch":false,"sender":{"key":"thomas@glanzmann.de","avatar":null},"body":"Hello,\n\n> This gives me very nicely enumerated commits like tag-1-g<sha1-abbrev> for\n> the commit o1 and tag-2-g<sha1-abbrev> for o2 ... you get the idea.\n\nI get the idea but I don't like it very much. From my point of view the\ncommit id makes much more sense. The output is cut&pasted anyway.\n\n        Thomas\n"},{"id":"42846","messageId":"20070521062953.GL3141@spearce.org","threadId":"8191","inReplyTo":"20070520163026.GA7387@cip.informatik.uni-erlangen.de","subject":"Re: Commit ID in exported Tar Ball","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-05-21T06:29:53Z","receivedAt":"2007-05-21T06:29:53Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Thomas Glanzmann <thomas@glanzmann.de> wrote:\n> so this output is useless if you don't have tagged the commit which\n> isn't the case. But thanks for the awareness.\n\nThanks for not quoting Brian's reply.  Because I had to go and\nquote it manually, so I can say its *NOT* useless...\n\n> Brian Gernhardt <benji@silverinsanity.com> wrote:\n> > For version information it is far more useful to use --tags or no\n> > options (annotated tags only) instead of --all.\n> > \n> > # On git.git's master this morning:\n> > $ git describe HEAD\n> > v1.5.2\n\nHere whatever HEAD's commit is is exactly the commit that the tag\nv1.5.2 points at.  This commit is definately v1.5.2.\n\n> > $ git describe HEAD^^\n> > v1.5.2-rc3-97-g03f6db0\n\nHere whatever commit is 2 commits earlier than HEAD is 97 commits\n*after* v1.5.2-rc3 was tagged.  That's a good deal of information\nright there.  I know its v1.5.2-rc3 plus a bunch of additional\ncommits (97 to be exact).  Add another commit and that 97 will\ngo to 98.  Wow, look, an automatic version counter!  No user\nintervention required!\n\nSometimes I don't even bother tagging git-gui fixes, for exactly\nthat reason.  The output of git-describe is giving me a count along\nmy maint branch, or my master branch.\n\nNow that g03f6db0 suffix is also very useful, it means its the\ncommit whose SHA- starts with 03f6db0.  That abbreviated SHA-1\nis unique at the time that git-describe ran.  At 8 hex digits it\nwill probably also stay unique for quite some time, even in large\nprojects like the kernel.\n\nAnd even if that isn't unique later on, I doubt there will be another\ncommit with the same leading hex digits that is also 97 commits\nafter v1.5.2, as counted by `git-rev-list v1.5.2..$it | wc -l`.\nSo even in the case of a later duplicate, we can get back a full\nSHA-1.\n\nAnd did you know that Git knows how to parse those, and can checkout\nthat commit?\n\n  $ git checkout v1.5.2-rc3-97-g03f6db0\n  Note: moving to \"v1.5.2-rc3-97-g03f6db0\" which isn't a local branch\n  If you want to create a new branch from this checkout, you may do so\n  (now or later) by using -b with the checkout command again. Example:\n    git checkout -b <new_branch_name>\n  HEAD is now at 03f6db0... Merge branch 'maint' to synchronize with 1.5.1.6\n\nWow.  Magic!  Not useless!\n\n-- \nShawn.\n"},{"id":"42847","messageId":"20070521063752.GB23350@cip.informatik.uni-erlangen.de","threadId":"8191","inReplyTo":"20070521062953.GL3141@spearce.org","subject":"Re: Commit ID in exported Tar Ball","fromName":"Thomas Glanzmann","fromEmail":"thomas@glanzmann.de","sentAt":"2007-05-21T06:37:52Z","receivedAt":"2007-05-21T06:37:52Z","isPatch":false,"sender":{"key":"thomas@glanzmann.de","avatar":null},"body":"Hello,\nso maybe it isn't that useless as I thought it initial is. But my point\nstill stands. I want the commit id of the HEAD in a _file within_ the\ntarball and I definitively don't want to tag my project before I get a\nunique identifier.\n\n        Thomas\n"},{"id":"42850","messageId":"20070521065355.GN3141@spearce.org","threadId":"8191","inReplyTo":"20070521063752.GB23350@cip.informatik.uni-erlangen.de","subject":"Re: Commit ID in exported Tar Ball","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-05-21T06:53:55Z","receivedAt":"2007-05-21T06:53:55Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Thomas Glanzmann <thomas@glanzmann.de> wrote:\n> so maybe it isn't that useless as I thought it initial is. But my point\n> still stands. I want the commit id of the HEAD in a _file within_ the\n> tarball and I definitively don't want to tag my project before I get a\n> unique identifier.\n\nSo what, a magic flag to git-describe like:\n\n\tgit-describe --untagged HEAD\n\t1a8213...\n\nWhere --untagged just means \"give me back the raw commit SHA-1 if\nthe input ref(s) aren't tagged\"?\n\n-- \nShawn.\n"},{"id":"42851","messageId":"74FC1AD6-199E-4A01-BB9F-AD030659AE29@silverinsanity.com","threadId":"8191","inReplyTo":"20070521063752.GB23350@cip.informatik.uni-erlangen.de","subject":"Re: Commit ID in exported Tar Ball","fromName":"Brian Gernhardt","fromEmail":"benji@silverinsanity.com","sentAt":"2007-05-21T06:56:34Z","receivedAt":"2007-05-21T06:56:34Z","isPatch":false,"sender":{"key":"benji@silverinsanity.com","avatar":"https://gravatar.com/avatar/e06c101dbc25c68114d859b4a9ec7cf8a2c52fd2b0270ef0eac0e2e63ff22311?d=mp&s=160"},"body":"\nOn May 21, 2007, at 2:37 AM, Thomas Glanzmann wrote:\n\n> so maybe it isn't that useless as I thought it initial is. But my  \n> point\n> still stands. I want the commit id of the HEAD in a _file within_ the\n> tarball and I definitively don't want to tag my project before I get a\n> unique identifier.\n\nIf you haven't tagged anything, then git can't give you anything  \nbetter than the SHA-1.  Giving a reference relative to a branch isn't  \nuseful, as the branch can change.  If the branch doesn't change, it's  \nreally a tag and you should mark it as such.\n\nHopefully the patch for the \"in a file\" flag for git-archive will go  \nin soon (or something like it).  I don't think we should make it any  \nmore complex than just the hash, myself.  If you want something more  \ncomplex a Makefile rule like\n\ndist:\n\tgit archive HEAD > dist.tar\n\tgit describe HEAD > version-file\n\ttar rf dist.tar version-file\n\tgzip dist.tar\n\nshould do the trick.  (And you can replace \"git describe\" with \"git  \nparse-rev\" for a bare hash if you'd like.)\n\n~~ Brian\n"},{"id":"42853","messageId":"20070521070042.GE23350@cip.informatik.uni-erlangen.de","threadId":"8191","inReplyTo":"20070521065355.GN3141@spearce.org","subject":"Re: Commit ID in exported Tar Ball","fromName":"Thomas Glanzmann","fromEmail":"thomas@glanzmann.de","sentAt":"2007-05-21T07:00:42Z","receivedAt":"2007-05-21T07:00:42Z","isPatch":false,"sender":{"key":"thomas@glanzmann.de","avatar":null},"body":"Hello,\n\n> So what, a magic flag to git-describe like:\n\n> \tgit-describe --untagged HEAD\n> \t1a8213...\n\n> Where --untagged just means \"give me back the raw commit SHA-1 if\n> the input ref(s) aren't tagged\"?\n\nthat is something I would love to live with. But it should also get the\nprimary objective done which is: Get the commit-id in the tar archive.\n\n        Thomas\n"},{"id":"42854","messageId":"20070521070216.GF23350@cip.informatik.uni-erlangen.de","threadId":"8191","inReplyTo":"74FC1AD6-199E-4A01-BB9F-AD030659AE29@silverinsanity.com","subject":"Re: Commit ID in exported Tar Ball","fromName":"Thomas Glanzmann","fromEmail":"thomas@glanzmann.de","sentAt":"2007-05-21T07:02:16Z","receivedAt":"2007-05-21T07:02:16Z","isPatch":false,"sender":{"key":"thomas@glanzmann.de","avatar":null},"body":"Hello Brian,\n\n> dist:\n> \tgit archive HEAD > dist.tar\n> \tgit describe HEAD > version-file\n> \ttar rf dist.tar version-file\n> \tgzip dist.tar\n\nto be precise that was my first idea when I started the whole\ndiscussion. But I like the patch from Rene much more than that. Because\nI want to use it with gitweb and it is definitevly easier to use realize\nthat with Renes patch.\n\n        Thomas\n"},{"id":"42888","messageId":"20070521120920.GF4489@pasky.or.cz","threadId":"8191","inReplyTo":"20070521060231.GI3141@spearce.org","subject":"Re: Commit ID in exported Tar Ball","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2007-05-21T12:09:20Z","receivedAt":"2007-05-21T12:09:20Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"On Mon, May 21, 2007 at 08:02:32AM CEST, Shawn O. Pearce wrote:\n> Ren?? Scharfe <rene.scharfe@lsrfire.ath.cx> wrote:\n> > Shawn O. Pearce schrieb:\n> > > \n> > > git-describe is more human-friendly than a SHA-1...\n> > \n> > Yes, and the Makefile does even more than that: it adds a version file,\n> > a spec file and another version file for git-gui.\n> > \n> > The first two are probably useful for most projects that actually do\n> > versioned releases.  We could have a simple parser that reads a\n> > template, replaces @@VERSION@@ with a git-describe output string and\n> > adds the result as a synthetic file to the archive.  It's not exactly\n> > trivial -- e.g., how to specify git-describe options, template file and\n> > synthetic name, all in one command line parameter? -- but it's doable.\n> \n> Maybe something just as simple as allowing the user to specify a\n> shell script in-tree that we unpack and run for them?  That script\n> prints to stdout the content of the file to include.\n\nSpecify how? At the point of git-archive execution? At that point you\nusually can append the file to the archive as well.\n\nAnd if you make it somehow a \"project default\", that becomes a huge\nsecurity risk, since anyone who clones the project and runs git-archive\nwill execute aribtrary code on his account.\n\nBesides, the original motivation for this were snapshots from gitweb.\nGitweb frequently does not run with the uid of the project owner, so\nthis becomes a security problem as well.\n\nMaybe some kind of format-string in .git/config...\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nEver try. Ever fail. No matter. // Try again. Fail again. Fail better.\n\t\t-- Samuel Beckett\n"},{"id":"42919","messageId":"4651F908.2000608@lsrfire.ath.cx","threadId":"8191","inReplyTo":"20070521060231.GI3141@spearce.org","subject":"Re: Commit ID in exported Tar Ball","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2007-05-21T19:54:48Z","receivedAt":"2007-05-21T19:54:48Z","isPatch":false,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Shawn O. Pearce schrieb:\n> Ren?? Scharfe <rene.scharfe@lsrfire.ath.cx> wrote:\n>> Shawn O. Pearce schrieb:\n>>> git-describe is more human-friendly than a SHA-1...\n>> Yes, and the Makefile does even more than that: it adds a version file,\n>> a spec file and another version file for git-gui.\n>>\n>> The first two are probably useful for most projects that actually do\n>> versioned releases.  We could have a simple parser that reads a\n>> template, replaces @@VERSION@@ with a git-describe output string and\n>> adds the result as a synthetic file to the archive.  It's not exactly\n>> trivial -- e.g., how to specify git-describe options, template file and\n>> synthetic name, all in one command line parameter? -- but it's doable.\n> \n> Maybe something just as simple as allowing the user to specify a\n> shell script in-tree that we unpack and run for them?  That script\n> prints to stdout the content of the file to include.\n\nI doubt executing a shell script is simple. :-D  You'd possibly get\ndifferent results on different platforms (dare I mention Windows?).\n\nThe template system I mentioned would be a kind of scripting language\nitself, but in this case we define its syntax and can guarantee\nconsistency everywhere git runs.  And since it would only have four\ntypes of tokens (@@VERSION@@, @@COMMITID@@, @@@@ and string literals) it\ncould be fast and simple.\n\nWe could implement it as a checkout converter, preferably one that is\nonly applied by git-archive.  Then we'd rename git.spec.in to git.spec,\nassign the \"specfile\" attribute to it and let git-archive replace the\nstring @@VERSION@@ with git-describe's output.  git-checkout would not\nexpand the special strings, so you can simply edit and version the file\nas you can do with git.spec.in now.  Michael would have a file\ncontaining only @@COMMITID@@ to solve his original problem.  Make sense?\n\n> So now we're also really talking about, what should git-archive\n> do for a subproject?  Sometimes you really do want to repackage\n> and redistribute the subproject as part of the superproject's\n> tarball. Sometimes you don't.  I think in the case of git.git and\n> git-gui.git we want to include the subproject.  ;-)\n\nOh, yes, subprojects.  git-archive currently exports them as empty\ndirectories.  Using tar's append command you could simply build the\nproject+subproject archive in the Makefile.  That wouldn't work well\nwith gitweb, though.  Perhaps a --include-subproject=<path> option is\nneeded?\n\nRené\n"},{"id":"43004","messageId":"46536E32.6000202@lsrfire.ath.cx","threadId":"8191","inReplyTo":"4651F908.2000608@lsrfire.ath.cx","subject":"Re: Commit ID in exported Tar Ball","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2007-05-22T22:26:58Z","receivedAt":"2007-05-22T22:26:58Z","isPatch":false,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"[I'm quoting myself in full because I somehow sent my reply to everyone\nbut Shawn.  A patch can be found at the end.]\n\nRené Scharfe schrieb:\n> Shawn O. Pearce schrieb:\n>> Ren?? Scharfe <rene.scharfe@lsrfire.ath.cx> wrote:\n>>> Shawn O. Pearce schrieb:\n>>>> git-describe is more human-friendly than a SHA-1...\n>>> Yes, and the Makefile does even more than that: it adds a version\n>>> file, a spec file and another version file for git-gui.\n>>> \n>>> The first two are probably useful for most projects that actually\n>>> do versioned releases.  We could have a simple parser that reads\n>>> a template, replaces @@VERSION@@ with a git-describe output\n>>> string and adds the result as a synthetic file to the archive.\n>>> It's not exactly trivial -- e.g., how to specify git-describe\n>>> options, template file and synthetic name, all in one command\n>>> line parameter? -- but it's doable.\n>> Maybe something just as simple as allowing the user to specify a \n>> shell script in-tree that we unpack and run for them?  That script \n>> prints to stdout the content of the file to include.\n> \n> I doubt executing a shell script is simple. :-D  You'd possibly get \n> different results on different platforms (dare I mention Windows?).\n> \n> The template system I mentioned would be a kind of scripting language\n>  itself, but in this case we define its syntax and can guarantee \n> consistency everywhere git runs.  And since it would only have four \n> types of tokens (@@VERSION@@, @@COMMITID@@, @@@@ and string literals)\n> it could be fast and simple.\n> \n> We could implement it as a checkout converter, preferably one that is\n> only applied by git-archive.  Then we'd rename git.spec.in to\n> git.spec, assign the \"specfile\" attribute to it and let git-archive\n> replace the string @@VERSION@@ with git-describe's output.\n> git-checkout would not expand the special strings, so you can simply\n> edit and version the file as you can do with git.spec.in now.\n> Michael would have a file containing only @@COMMITID@@ to solve his\n> original problem.  Make sense?\n> \n>> So now we're also really talking about, what should git-archive do\n>> for a subproject?  Sometimes you really do want to repackage and\n>> redistribute the subproject as part of the superproject's tarball.\n>> Sometimes you don't.  I think in the case of git.git and \n>> git-gui.git we want to include the subproject.  ;-)\n> \n> Oh, yes, subprojects.  git-archive currently exports them as empty \n> directories.  Using tar's append command you could simply build the \n> project+subproject archive in the Makefile.  That wouldn't work well \n> with gitweb, though.  Perhaps a --include-subproject=<path> option is\n>  needed?\n\nOK, so here's a first shot at the mentioned parser.  It only understands\n@@COMMITID@@ and @@@@, but it's easily extendible.  The internals of\ngit-describe would need to be converted to library functions, preferably\noffering every piece of version info separately (see thread \"[PATCH]\nMake sure an autogenerated version has at least four parts\" for why).\n\nBefore doing that, we should determine if this is the way to, though.\n\nRené\n\n\n Documentation/gitattributes.txt |   19 ++++++-\n archive-tar.c                   |    5 ++-\n archive-zip.c                   |    5 ++-\n cache.h                         |    1 +\n convert.c                       |  112 +++++++++++++++++++++++++++++++++++++++\n 5 files changed, 139 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex d3ac9c7..84c414c 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -72,7 +72,7 @@ EFFECTS\n -------\n \n Certain operations by git can be influenced by assigning\n-particular attributes to a path.  Currently, three operations\n+particular attributes to a path.  Currently, four operations\n are attributes-aware.\n \n Checking-out and checking-in\n@@ -374,6 +374,23 @@ frotz\tunspecified\n ----------------------------------------------------------------\n \n \n+Creating an archive\n+~~~~~~~~~~~~~~~~~~~\n+\n+\n+`specfile`\n+^^^^^^^^^^\n+\n+If the attribute `specfile` is set for a file then git will expand\n+several placeholders when adding this file to an archive.  The\n+expansion depends on the availability of a commit ID, i.e. if\n+`git-archive` has been given a tree instead of a commit or a tag\n+then no replacement will be done.\n+\n+`@@COMMITID@@`:: is replaced by the commit hash.\n+`@@@@`:: is replaced by `@@`.\n+\n+\n GIT\n ---\n Part of the gitlink:git[7] suite\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 66fe3e3..eba24cb 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -17,6 +17,7 @@ static unsigned long offset;\n static time_t archive_time;\n static int tar_umask = 002;\n static int verbose;\n+static const unsigned char *commit_sha1;\n \n /* writes out the whole block, but only if it is full */\n static void write_if_needed(void)\n@@ -285,7 +286,8 @@ static int write_tar_entry(const unsigned char *sha1,\n \t\tbuffer = NULL;\n \t\tsize = 0;\n \t} else {\n-\t\tbuffer = convert_sha1_file(path.buf, sha1, mode, &type, &size);\n+\t\tbuffer = sha1_file_to_archive(path.buf, sha1, mode, &type,\n+\t\t                              &size, commit_sha1);\n \t\tif (!buffer)\n \t\t\tdie(\"cannot read %s\", sha1_to_hex(sha1));\n \t}\n@@ -304,6 +306,7 @@ int write_tar_archive(struct archiver_args *args)\n \n \tarchive_time = args->time;\n \tverbose = args->verbose;\n+\tcommit_sha1 = args->commit_sha1;\n \n \tif (args->commit_sha1)\n \t\twrite_global_extended_header(args->commit_sha1);\ndiff --git a/archive-zip.c b/archive-zip.c\nindex 444e162..93a5ab3 100644\n--- a/archive-zip.c\n+++ b/archive-zip.c\n@@ -12,6 +12,7 @@\n static int verbose;\n static int zip_date;\n static int zip_time;\n+static const unsigned char *commit_sha1;\n \n static unsigned char *zip_dir;\n static unsigned int zip_dir_size;\n@@ -195,7 +196,8 @@ static int write_zip_entry(const unsigned char *sha1,\n \t\tif (S_ISREG(mode) && zlib_compression_level != 0)\n \t\t\tmethod = 8;\n \t\tresult = 0;\n-\t\tbuffer = convert_sha1_file(path, sha1, mode, &type, &size);\n+\t\tbuffer = sha1_file_to_archive(path, sha1, mode, &type, &size,\n+\t\t                              commit_sha1);\n \t\tif (!buffer)\n \t\t\tdie(\"cannot read %s\", sha1_to_hex(sha1));\n \t\tcrc = crc32(crc, buffer, size);\n@@ -316,6 +318,7 @@ int write_zip_archive(struct archiver_args *args)\n \tzip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE);\n \tzip_dir_size = ZIP_DIRECTORY_MIN_SIZE;\n \tverbose = args->verbose;\n+\tcommit_sha1 = args->commit_sha1;\n \n \tif (args->base && plen > 0 && args->base[plen - 1] == '/') {\n \t\tchar *base = xstrdup(args->base);\ndiff --git a/cache.h b/cache.h\nindex cd875bc..0484904 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -550,6 +550,7 @@ extern void trace_argv_printf(const char **argv, int count, const char *format,\n extern char *convert_to_git(const char *path, const char *src, unsigned long *sizep);\n extern char *convert_to_working_tree(const char *path, const char *src, unsigned long *sizep);\n extern void *convert_sha1_file(const char *path, const unsigned char *sha1, unsigned int mode, enum object_type *type, unsigned long *size);\n+extern void *sha1_file_to_archive(const char *path, const unsigned char *sha1, unsigned int mode, enum object_type *type, unsigned long *size, const unsigned char *commit_sha1);\n \n /* match-trees.c */\n void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, int);\ndiff --git a/convert.c b/convert.c\nindex 4b26b1a..1cdaec5 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"attr.h\"\n #include \"run-command.h\"\n+#include \"strbuf.h\"\n \n /*\n  * convert.c - convert a file when checking it out and checking it in.\n@@ -667,3 +668,114 @@ void *convert_sha1_file(const char *path, const unsigned char *sha1,\n \t}\n \treturn buffer;\n }\n+\n+static void strbuf_append(struct strbuf *sb, const void *s, size_t len)\n+{\n+\tif (sb->alloc < sb->len + len) {\n+\t\tsb->alloc = (sb->len + len) * 3 / 2 + 16;\n+\t\tsb->buf = xrealloc(sb->buf, sb->alloc);\n+\t}\n+\tmemcpy(sb->buf + sb->len, s, len);\n+\tsb->len += len;\n+}\n+\n+static unsigned int match_keyword(const char *data, unsigned int datalen,\n+                                  const char *keyword)\n+{\n+\tunsigned int keylen = strlen(keyword);\n+\tif (keylen > datalen)\n+\t\treturn 0;\n+\tif (memcmp(data, keyword, keylen))\n+\t\treturn 0;\n+\treturn keylen;\n+}\n+\n+static void *convert_to_archive(const char *path, const void *src,\n+                                unsigned long *sizep,\n+                                const unsigned char *commit_sha1)\n+{\n+\tstatic struct git_attr *attr_specfile;\n+\tstruct git_attr_check check[1];\n+\tconst char *p = src;\n+\tunsigned long srcsize = *sizep;\n+\tint at_signs = 0;\n+\tstruct strbuf dst;\n+\tunsigned int match;\n+\tint replaced_something = 0;\n+\n+\tif (!commit_sha1)\n+\t\treturn NULL;\n+\n+        if (!attr_specfile)\n+                attr_specfile = git_attr(\"specfile\", 8);\n+\n+\tcheck[0].attr = attr_specfile;\n+\tif (git_checkattr(path, ARRAY_SIZE(check), check))\n+\t\treturn NULL;\n+\tif (!ATTR_TRUE(check[0].value))\n+\t\treturn NULL;\n+\n+\tdst.alloc = srcsize + 128;\n+\tdst.buf = xmalloc(dst.alloc);\n+\tdst.len = dst.eof = 0;\n+\n+\twhile (srcsize > 0) {\n+\t\tif ((at_signs == 0 || at_signs == 1) && *p == '@') {\n+\t\t\tat_signs++;\n+\t\t\tp++;\n+\t\t\tsrcsize--;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (at_signs == 1) {\n+\t\t\tat_signs = 0;\n+\t\t\tstrbuf_append(&dst, \"@\", 1);\n+\t\t}\n+\t\tif (at_signs == 0) {\n+\t\t\tstrbuf_append(&dst, p, 1);\n+\t\t\tp++;\n+\t\t\tsrcsize--;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif ((match = match_keyword(p, srcsize, \"@@\")))\n+\t\t\tstrbuf_append(&dst, \"@@\", 2);\n+\t\telse if ((match = match_keyword(p, srcsize, \"COMMITID@@\")))\n+\t\t\tstrbuf_append(&dst, sha1_to_hex(commit_sha1), 40);\n+\t\telse\n+\t\t\tstrbuf_append(&dst, \"@@\", 2);\n+\t\tat_signs = 0;\n+\t\tp += match;\n+\t\tsrcsize -= match;\n+\t\treplaced_something = 1;\n+\t}\n+\n+\tif (!replaced_something) {\n+\t\tfree(dst.buf);\n+\t\treturn NULL;\n+\t}\n+\n+\t*sizep = dst.len;\n+\treturn dst.buf;\n+}\n+\n+void *sha1_file_to_archive(const char *path, const unsigned char *sha1,\n+                           unsigned int mode, enum object_type *type,\n+                           unsigned long *size,\n+                           const unsigned char *commit_sha1)\n+{\n+\tvoid *buffer = read_sha1_file(sha1, type, size);\n+\tif (S_ISREG(mode) && buffer) {\n+\t\tvoid *converted = convert_to_working_tree(path, buffer, size);\n+\t\tif (converted) {\n+\t\t\tfree(buffer);\n+\t\t\tbuffer = converted;\n+\t\t}\n+\n+\t\tconverted = convert_to_archive(path, buffer, size, commit_sha1);\n+\t\tif (converted) {\n+\t\t\tfree(buffer);\n+\t\t\tbuffer = converted;\n+\t\t}\n+\t}\n+\treturn buffer;\n+}\n"},{"id":"43005","messageId":"7vd50s79lg.fsf@assigned-by-dhcp.cox.net","threadId":"8191","inReplyTo":"46536E32.6000202@lsrfire.ath.cx","subject":"Re: Commit ID in exported Tar Ball","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-05-22T22:54:35Z","receivedAt":"2007-05-22T22:54:35Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"René Scharfe <rene.scharfe@lsrfire.ath.cx> writes:\n\n> OK, so here's a first shot at the mentioned parser.  It only understands\n> @@COMMITID@@ and @@@@, but it's easily extendible.  The internals of\n> git-describe would need to be converted to library functions, preferably\n> offering every piece of version info separately (see thread \"[PATCH]\n> Make sure an autogenerated version has at least four parts\" for why).\n>\n> Before doing that, we should determine if this is the way to, though.\n>\n> René\n\nHmmm.  I am torn.\n\nIt almost feels as if we'd better bite the bullet and do more\ninsane things in ident substitution, instead of introducing this\napparent syntax inconsistency between \"$id$\" and \"@@COMMITID@@\".\n\nThat is, we could (I am not seriously proposing to do this, as I\nexpect this will lead to a lot of insanity at the end):\n\n (1) introduce \"const unsigned char commit_in_focus[20]\",\n     globally available to git suite, and clear it at the\n     beginning of main();\n\n (2) teach ident substitution to expand \"$commit$\" to\n     sprintf(\"$commit: %40s $\", sha1_to_hex(commit_in_focus[])),\n     and unexpand \"$commit: .* $\".\n\n (3) have git-archive set commit_in_focus[] before letting the\n     convert_to_working_tree do its work.\n\n (4) later, we _might_ teach a single tree read-tree to also set\n     up commit_in_focus[], so that:\n\n\t$ rm -f .git/index\n        $ git checkout -f HEAD\n\n     would expand \"$commit$\" in blobs.\n\nThis obviously have a lot of problems once we start adding the\ncommit_in_focus[] to more random programs.  Even two-tree\nread-tree case would behave in an unexpected way for an\nuninitiated person, if you do something like:\n\n\t$ git checkout master\n        $ git checkout next\n\nI am CC'ing Linus because he would literally hate me suggesting\nthe above.\n"},{"id":"43008","messageId":"46538065.9080705@lsrfire.ath.cx","threadId":"8191","inReplyTo":"7vd50s79lg.fsf@assigned-by-dhcp.cox.net","subject":"Re: Commit ID in exported Tar Ball","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2007-05-22T23:44:37Z","receivedAt":"2007-05-22T23:44:37Z","isPatch":false,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Junio C Hamano schrieb:\n> René Scharfe <rene.scharfe@lsrfire.ath.cx> writes:\n> \n>> OK, so here's a first shot at the mentioned parser.  It only understands\n>> @@COMMITID@@ and @@@@, but it's easily extendible.  The internals of\n>> git-describe would need to be converted to library functions, preferably\n>> offering every piece of version info separately (see thread \"[PATCH]\n>> Make sure an autogenerated version has at least four parts\" for why).\n>>\n>> Before doing that, we should determine if this is the way to, though.\n>>\n>> René\n> \n> Hmmm.  I am torn.\n> \n> It almost feels as if we'd better bite the bullet and do more\n> insane things in ident substitution, instead of introducing this\n> apparent syntax inconsistency between \"$id$\" and \"@@COMMITID@@\".\n\n$Id$ (and $commit$) is reversible, @@COMMITID@@ is not.  That means you\ncan create a synthetic file byte for byte with @@COMMITID@@ (and its not\nyet implemented brethren), but you can't do that with $Id$ -- it's\nimpossible to get rid of the dollar signs.\n\nI'm not attached to any particular syntax.  It all started with\n@@VERSION@@ from git.spec.in, which should not be implemented 1:1 anyway\n(we'd need to be able to use arbitrary separators between version parts\nto support different ways of ordering version numbers).\n\nWe could use $ to indicate reversible substitutions as before and @\n(instead of @@) for one-way substitutions.  I can't think of any other\nuse than in archives, though.  It sure would be very confusing to have\nsuch a conversion happen on checkout -- you'd need to use git-cat-file\nto see the real file contents.\n\n> That is, we could (I am not seriously proposing to do this, as I\n> expect this will lead to a lot of insanity at the end):\n> \n>  (1) introduce \"const unsigned char commit_in_focus[20]\",\n>      globally available to git suite, and clear it at the\n>      beginning of main();\n\nUgh.  Requiring another global variable doesn't smell like good design.\n\nBy the way, we already have a similar, but very different syntax: the\none format_commit_message in commit.c.  It's a one-way conversion, too.\n Maybe we should copy the relevant pieces like %H and %h from there..\n\nDo we want git-archive specific one-way conversions that are capable of\ncreating files like git.spec?  Or is this just a shiny toy hypnotizing\nme? 8-)\n\nRené\n"},{"id":"43015","messageId":"20070523052220.GC28023@spearce.org","threadId":"8191","inReplyTo":"46538065.9080705@lsrfire.ath.cx","subject":"Re: Commit ID in exported Tar Ball","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-05-23T05:22:20Z","receivedAt":"2007-05-23T05:22:20Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Ren?? Scharfe <rene.scharfe@lsrfire.ath.cx> wrote:\n> $Id$ (and $commit$) is reversible, @@COMMITID@@ is not.  That means you\n> can create a synthetic file byte for byte with @@COMMITID@@ (and its not\n> yet implemented brethren), but you can't do that with $Id$ -- it's\n> impossible to get rid of the dollar signs.\n\nYes, and that's one of the big problems with the $Id$ syntax so\ncommonly used by versioning systems.  Most files you want to insert\nthat automatic id into want a clean id string, not something that\nstarts with $Id: and ends with $...\n\nSince we are apparently supporting $Foo: ...$ to collapse back to\n$Foo$ reusing that syntax for git-archive is actually probably a\nbad idea.  We should support the checkout filters in git-archive (as\nmuch as possible anyway) but what this thread has been going on is\nsomething quite different...  so we probably want a different syntax.\nWhich is why I'm also in favor of the @@COMMITID@@ syntax...\n \n> >  (1) introduce \"const unsigned char commit_in_focus[20]\",\n> >      globally available to git suite, and clear it at the\n> >      beginning of main();\n> \n> Ugh.  Requiring another global variable doesn't smell like good design.\n\nI agree.  We already have a lot of globals.  We need another one like\nwe need a hole in the head.  Especially a global like this one... ;-)\n \n> Do we want git-archive specific one-way conversions that are capable of\n> creating files like git.spec?  Or is this just a shiny toy hypnotizing\n> me? 8-)\n\nBut aren't shiny toys fun?  ;-)\n\n-- \nShawn.\n"}]}