Teach fmt-patch to write individual files.
authorJohannes Schindelin <Johannes.Schindelin@gmx.de>
Thu, 4 May 2006 23:16:40 +0000 (01:16 +0200)
committerJunio C Hamano <junkio@cox.net>
Fri, 5 May 2006 20:55:45 +0000 (13:55 -0700)
When called with "--stdout", it still writes to standard output.

Notable differences to git-format-patch:

- since fmt-patch uses the standardized logging machinery, it is
  no longer "From nobody", but "From <commit_sha1>",

- the empty lines before and after the "---" just before the
  diffstat are no longer there,

- git-format-patch outputs the commit_sha1 just before the first
  diff, which fmt-patch does not,

- the file names are no longer output to stdout, but to stderr
  (since stdout is freopen()ed all the time), and

- "git fmt-patch HEAD^" does not work as expected: it outputs
  *all* commits reachable from HEAD^!

The last one is possibly a showstopper. At least I used to call that
command quite often...

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
builtin-log.c

index a39aed6..576703c 100644 (file)
@@ -69,12 +69,65 @@ int cmd_log(int argc, const char **argv, char **envp)
        return cmd_log_wc(argc, argv, envp, &rev);
 }
 
+static int istitlechar(char c)
+{
+       return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+               (c >= '0' && c <= '9') || c == '.' || c == '_';
+}
+
+static void reopen_stdout(struct commit *commit, int nr)
+{
+       char filename[1024];
+       char *sol;
+       int len;
+
+
+       sprintf(filename, "%04d", nr);
+       len = strlen(filename);
+
+       sol = strstr(commit->buffer, "\n\n");
+       if (sol) {
+               int j, space = 1;
+
+               sol += 2;
+               /* strip [PATCH] or [PATCH blabla] */
+               if (!strncmp(sol, "[PATCH", 6)) {
+                       char *eos = strchr(sol + 6, ']');
+                       if (eos) {
+                               while (isspace(*eos))
+                                       eos++;
+                               sol = eos;
+                       }
+               }
+
+               for (j = 0; len < 1024 - 6 && sol[j] && sol[j] != '\n'; j++) {
+                       if (istitlechar(sol[j])) {
+                               if (space) {
+                                       filename[len++] = '-';
+                                       space = 0;
+                               }
+                               filename[len++] = sol[j];
+                               if (sol[j] == '.')
+                                       while (sol[j + 1] == '.')
+                                               j++;
+                       } else
+                               space = 1;
+               }
+               while (filename[len - 1] == '.' || filename[len - 1] == '-')
+                       len--;
+       }
+       strcpy(filename + len, ".txt");
+       fprintf(stderr, "%s\n", filename);
+       freopen(filename, "w", stdout);
+}
+
 int cmd_format_patch(int argc, const char **argv, char **envp)
 {
        struct commit *commit;
        struct commit **list = NULL;
        struct rev_info rev;
-       int nr = 0;
+       int nr = 0, total;
+       int use_stdout = 0;
 
        init_revisions(&rev);
        rev.commit_format = CMIT_FMT_EMAIL;
@@ -87,20 +140,37 @@ int cmd_format_patch(int argc, const char **argv, char **envp)
        rev.diffopt.output_format = DIFF_FORMAT_PATCH;
        argc = setup_revisions(argc, argv, &rev, "HEAD");
 
+       while (argc > 1) {
+               if (!strcmp(argv[1], "--stdout"))
+                       use_stdout = 1;
+               else
+                       die ("unrecognized argument: %s", argv[1]);
+               argc--;
+               argv++;
+       }
+
        prepare_revision_walk(&rev);
        while ((commit = get_revision(&rev)) != NULL) {
+               /* ignore merges */
+               if (commit->parents && commit->parents->next)
+                       continue;
                nr++;
                list = realloc(list, nr * sizeof(list[0]));
                list[nr - 1] = commit;
        }
+       total = nr;
        while (0 <= --nr) {
                int shown;
                commit = list[nr];
+               if (!use_stdout)
+                       reopen_stdout(commit, total - nr);
                shown = log_tree_commit(&rev, commit);
                free(commit->buffer);
                commit->buffer = NULL;
                if (shown)
                        printf("-- \n%s\n\n", git_version_string);
+               if (!use_stdout)
+                       fclose(stdout);
        }
        free(list);
        return 0;