{"thread":{"id":"4061","subject":"[PATCH] Teach fmt-patch to write individual files.","startedAt":"2006-05-04T23:16:40Z","lastAt":"2006-05-05T00:56:16Z","messageCount":3,"participants":["Johannes Schindelin","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"19531","messageId":"Pine.LNX.4.63.0605050115440.12795@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"4061","inReplyTo":null,"subject":"[PATCH] Teach fmt-patch to write individual files.","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-05-04T23:16:40Z","receivedAt":"2006-05-04T23:16:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nWhen called with \"--stdout\", it still writes to standard output.\n\nNotable differences to git-format-patch:\n\n\t- since fmt-patch uses the standardized logging machinery, it is\n\t  no longer \"From nobody\", but \"From <commit_sha1>\",\n\n\t- the empty lines before and after the \"---\" just before the\n\t  diffstat are no longer there,\n\n\t- git-format-patch outputs the commit_sha1 just before the first\n\t  diff, which fmt-patch does not,\n\n\t- the file names are no longer output to stdout, but to stderr\n\t  (since stdout is freopen()ed all the time), and\n\n\t- \"git fmt-patch HEAD^\" does not work as expected: it outputs\n\t  *all* commits reachable from HEAD^!\n\nThe last one is possibly a showstopper. At least I used to call that\ncommand quite often...\n\nSigned-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n---\n\n\tI forgot to \"git-update-index builtin-log.c\"...\n\n builtin-log.c |   72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n 1 files changed, 71 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin-log.c b/builtin-log.c\nindex a39aed6..576703c 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -69,12 +69,65 @@ int cmd_log(int argc, const char **argv,\n \treturn cmd_log_wc(argc, argv, envp, &rev);\n }\n \n+static int istitlechar(char c)\n+{\n+\treturn (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||\n+\t\t(c >= '0' && c <= '9') || c == '.' || c == '_';\n+}\n+\n+static void reopen_stdout(struct commit *commit, int nr)\n+{\n+\tchar filename[1024];\n+\tchar *sol;\n+\tint len;\n+\n+\n+\tsprintf(filename, \"%04d\", nr);\n+\tlen = strlen(filename);\n+\n+\tsol = strstr(commit->buffer, \"\\n\\n\");\n+\tif (sol) {\n+\t\tint j, space = 1;\n+\n+\t\tsol += 2;\n+\t\t/* strip [PATCH] or [PATCH blabla] */\n+\t\tif (!strncmp(sol, \"[PATCH\", 6)) {\n+\t\t\tchar *eos = strchr(sol + 6, ']');\n+\t\t\tif (eos) {\n+\t\t\t\twhile (isspace(*eos))\n+\t\t\t\t\teos++;\n+\t\t\t\tsol = eos;\n+\t\t\t}\n+\t\t}\n+\n+\t\tfor (j = 0; len < 1024 - 6 && sol[j] && sol[j] != '\\n'; j++) {\n+\t\t\tif (istitlechar(sol[j])) {\n+\t\t\t\tif (space) {\n+\t\t\t\t\tfilename[len++] = '-';\n+\t\t\t\t\tspace = 0;\n+\t\t\t\t}\n+\t\t\t\tfilename[len++] = sol[j];\n+\t\t\t\tif (sol[j] == '.')\n+\t\t\t\t\twhile (sol[j + 1] == '.')\n+\t\t\t\t\t\tj++;\n+\t\t\t} else\n+\t\t\t\tspace = 1;\n+\t\t}\n+\t\twhile (filename[len - 1] == '.' || filename[len - 1] == '-')\n+\t\t\tlen--;\n+\t}\n+\tstrcpy(filename + len, \".txt\");\n+\tfprintf(stderr, \"%s\\n\", filename);\n+\tfreopen(filename, \"w\", stdout);\n+}\n+\n int cmd_format_patch(int argc, const char **argv, char **envp)\n {\n \tstruct commit *commit;\n \tstruct commit **list = NULL;\n \tstruct rev_info rev;\n-\tint nr = 0;\n+\tint nr = 0, total;\n+\tint use_stdout = 0;\n \n \tinit_revisions(&rev);\n \trev.commit_format = CMIT_FMT_EMAIL;\n@@ -87,20 +140,37 @@ int cmd_format_patch(int argc, const cha\n \trev.diffopt.output_format = DIFF_FORMAT_PATCH;\n \targc = setup_revisions(argc, argv, &rev, \"HEAD\");\n \n+\twhile (argc > 1) {\n+\t\tif (!strcmp(argv[1], \"--stdout\"))\n+\t\t\tuse_stdout = 1;\n+\t\telse\n+\t\t\tdie (\"unrecognized argument: %s\", argv[1]);\n+\t\targc--;\n+\t\targv++;\n+\t}\n+\n \tprepare_revision_walk(&rev);\n \twhile ((commit = get_revision(&rev)) != NULL) {\n+\t\t/* ignore merges */\n+\t\tif (commit->parents && commit->parents->next)\n+\t\t\tcontinue;\n \t\tnr++;\n \t\tlist = realloc(list, nr * sizeof(list[0]));\n \t\tlist[nr - 1] = commit;\n \t}\n+\ttotal = nr;\n \twhile (0 <= --nr) {\n \t\tint shown;\n \t\tcommit = list[nr];\n+\t\tif (!use_stdout)\n+\t\t\treopen_stdout(commit, total - nr);\n \t\tshown = log_tree_commit(&rev, commit);\n \t\tfree(commit->buffer);\n \t\tcommit->buffer = NULL;\n \t\tif (shown)\n \t\t\tprintf(\"-- \\n%s\\n\\n\", git_version_string);\n+\t\tif (!use_stdout)\n+\t\t\tfclose(stdout);\n \t}\n \tfree(list);\n \treturn 0;\n-- \n1.3.1.g42859-dirty\n"},{"id":"19534","messageId":"7vhd452uzn.fsf@assigned-by-dhcp.cox.net","threadId":"4061","inReplyTo":"Pine.LNX.4.63.0605050115440.12795@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH] Teach fmt-patch to write individual files.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-05-05T00:09:00Z","receivedAt":"2006-05-05T00:09:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> When called with \"--stdout\", it still writes to standard output.\n>\n> Notable differences to git-format-patch:\n>\n> \t- since fmt-patch uses the standardized logging machinery, it is\n> \t  no longer \"From nobody\", but \"From <commit_sha1>\",\n\nYes, and the date on that UNIX-From line has been updated ;-).\n\n> \t- the empty lines before and after the \"---\" just before the\n> \t  diffstat are no longer there,\n\nPersonally, I find this the most annoying myself.  I am not\ncomplaining to you because as you know you inherited this\nbehaviour from my code.\n\n> \t- git-format-patch outputs the commit_sha1 just before the first\n> \t  diff, which fmt-patch does not,\n\nWhich should be fine.\n\n> \t- the file names are no longer output to stdout, but to stderr\n> \t  (since stdout is freopen()ed all the time), and\n\nWhich might be a bigger deal; I suspect people capture that while\ndumping patches into individual files, and do their\npostprocessing using the list of filenames.\n\n> \t- \"git fmt-patch HEAD^\" does not work as expected: it outputs\n> \t  *all* commits reachable from HEAD^!\n\nIf we really wanted to handle this, you could do something like\nwhat builtin-diff does before letting the revision machinery\nstart walking the revision tree.  Look at pending objects, and\nif you find only one UNINTERESTING commit, add_object the\ncurrent HEAD there as well.  Personally I do not think it is\nworth it; rather we would probably want to standardize on rev-list\nsyntax.\n\nTwo major differences you forgot to mention.\n\nOne is that it does not do the \"git cherry\" filtering.  It is\nnot a big deal for me personally, but some people may be\ndepending on it.  I dunno.\n\nAnother is -o outdir, which should be trivial to add once you\nhave implemented output switching with freopen().\n\nAnyhow, thanks for starting this.\n"},{"id":"19537","messageId":"Pine.LNX.4.63.0605050249050.25249@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"4061","inReplyTo":"7vhd452uzn.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Teach fmt-patch to write individual files.","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-05-05T00:56:16Z","receivedAt":"2006-05-05T00:56:16Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 4 May 2006, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > When called with \"--stdout\", it still writes to standard output.\n> >\n> > Notable differences to git-format-patch:\n> >\n> > \t- since fmt-patch uses the standardized logging machinery, it is\n> > \t  no longer \"From nobody\", but \"From <commit_sha1>\",\n> \n> Yes, and the date on that UNIX-From line has been updated ;-).\n\nRight.\n\n> > \t- the empty lines before and after the \"---\" just before the\n> > \t  diffstat are no longer there,\n> \n> Personally, I find this the most annoying myself.  I am not\n> complaining to you because as you know you inherited this\n> behaviour from my code.\n\nHow about this?\n\n-- snip --\ndiff --git a/log-tree.c b/log-tree.c\nindex d92abaf..6379d43 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -86,7 +86,7 @@ int log_tree_diff_flush(struct rev_info \n \t}\n \n \tif (opt->loginfo && !opt->no_commit_id)\n-\t\tshow_log(opt, opt->loginfo, opt->diffopt.with_stat ? \"---\\n\" : \"\\n\");\n+\t\tshow_log(opt, opt->loginfo, opt->diffopt.with_stat ? \"\\n---\\n\\n\" : \"\\n\");\n \tdiff_flush(&opt->diffopt);\n \treturn 1;\n }\n-- snap --\n\n> > \t- git-format-patch outputs the commit_sha1 just before the first\n> > \t  diff, which fmt-patch does not,\n> \n> Which should be fine.\n\nYeah, I just wanted to mention it in case people rely on it.\n\n> > \t- the file names are no longer output to stdout, but to stderr\n> > \t  (since stdout is freopen()ed all the time), and\n> \n> Which might be a bigger deal; I suspect people capture that while\n> dumping patches into individual files, and do their\n> postprocessing using the list of filenames.\n\nI hoped it is not necessary to \"FILE *realstdout = fdopen(dup(1));\" but I \ncan do it if this is wanted.\n\n> > \t- \"git fmt-patch HEAD^\" does not work as expected: it outputs\n> > \t  *all* commits reachable from HEAD^!\n> \n> If we really wanted to handle this, you could do something like\n> what builtin-diff does before letting the revision machinery\n> start walking the revision tree.  Look at pending objects, and\n> if you find only one UNINTERESTING commit, add_object the\n> current HEAD there as well.  Personally I do not think it is\n> worth it; rather we would probably want to standardize on rev-list\n> syntax.\n\nWell, I have to get used to add \"..\" after HEAD^, but that is probably not \nvery difficult. I would like fmt-patch to error out without a range, \nthough.\n\n> Two major differences you forgot to mention.\n> \n> One is that it does not do the \"git cherry\" filtering.  It is\n> not a big deal for me personally, but some people may be\n> depending on it.  I dunno.\n\nOops. I really did not think of that.\n\n> Another is -o outdir, which should be trivial to add once you\n> have implemented output switching with freopen().\n\nYes, this becomes easy now. I'll do that next.\n\nCiao,\nDscho\n"}]}