This outputs the log in GNU ChangeLog format. Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> --- commit.c | 18 +++++++++++--- commit.h | 1 + diff.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff.h | 1 + log-tree.c | 17 ++++++++++++- revision.c | 6 ++++ 6 files changed, 115 insertions(+), 5 deletions(-) diff --git a/commit.c b/commit.c index fb75ae5..64ddb56 100644 --- a/commit.c +++ b/commit.c @@ -38,6 +38,7 @@ struct cmt_fmt_map { { "fuller", 5, CMIT_FMT_FULLER }, { "oneline", 1, CMIT_FMT_ONELINE }, { "format:", 7, CMIT_FMT_USERFORMAT}, + { "changelog", 9, CMIT_FMT_CHANGELOG} }; static char *user_format; @@ -563,6 +564,8 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, ret += namelen - display_name_length; buf[ret++] = '\n'; } + else if (fmt == CMIT_FMT_CHANGELOG) + ret = 0; else { ret = sprintf(buf, "%s: %.*s%.*s\n", what, (fmt == CMIT_FMT_FULLER) ? 4 : 0, @@ -581,6 +584,11 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, ret += sprintf(buf + ret, "%sDate: %s\n", what, show_date(time, tz, relative_date)); break; + case CMIT_FMT_CHANGELOG: + ret += sprintf(buf + ret, "%s %.*s\n", + show_date(time, tz, DATE_SHORT), + namelen, line); + break; default: /* notin' */ break; @@ -603,7 +611,7 @@ static int add_merge_info(enum cmit_fmt fmt, char *buf, const struct commit *com int offset; if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) || - !parent || !parent->next) + fmt == CMIT_FMT_CHANGELOG || !parent || !parent->next) return 0; offset = sprintf(buf, "Merge:"); @@ -931,7 +939,8 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, if (reencoded) msg = reencoded; - if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) + if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL || + fmt == CMIT_FMT_CHANGELOG) indent = 0; /* After-subject is used to pass in Content-Type: multipart @@ -982,7 +991,8 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, if (hdr) { if (linelen == 1) { hdr = 0; - if ((fmt != CMIT_FMT_ONELINE) && !subject) + if (fmt != CMIT_FMT_ONELINE && + fmt != CMIT_FMT_CHANGELOG && !subject) buf[offset++] = '\n'; continue; } @@ -1052,7 +1062,7 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, offset += linelen + indent; } buf[offset++] = '\n'; - if (fmt == CMIT_FMT_ONELINE) + if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_CHANGELOG) break; if (subject && plain_non_ascii) { int sz; diff --git a/commit.h b/commit.h index 83507a0..9d59e0f 100644 --- a/commit.h +++ b/commit.h @@ -48,6 +48,7 @@ enum cmit_fmt { CMIT_FMT_ONELINE, CMIT_FMT_EMAIL, CMIT_FMT_USERFORMAT, + CMIT_FMT_CHANGELOG, CMIT_FMT_UNSPECIFIED, }; diff --git a/diff.c b/diff.c index 5651152..aed5388 100644 --- a/diff.c +++ b/diff.c @@ -8,6 +8,7 @@ #include "delta.h" #include "xdiff-interface.h" #include "color.h" +#include "utf8.h" #ifdef NO_FAST_WORKING_DIRECTORY #define FAST_WORKING_DIRECTORY 0 @@ -1845,6 +1846,59 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o) builtin_checkdiff(name, other, p->one, p->two, o); } +#define CHANGELOG_TAB_SIZE 8 +#define CHANGELOG_WIDTH 76 + +struct changelog_t { + int offset, seen_first; +}; + +static void run_changelog(struct diff_filepair *p, struct diff_options *o, + struct changelog_t *changelog) +{ + const char *name; + const char *other; + static char buffer[1024]; + + if (DIFF_PAIR_UNMERGED(p)) { + /* unmerged */ + return; + } + + if (changelog->seen_first) + buffer[0] = ','; + else { + buffer[0] = '*'; + changelog->offset = -CHANGELOG_TAB_SIZE; + changelog->seen_first = 1; + } + + name = p->one->path; + other = p->two->path; + + if (!name) { + if (!other) + return; + snprintf(buffer + 1, sizeof(buffer) - 1, " %s", other); + } else if (!other || !strcmp(name, other)) + snprintf(buffer + 1, sizeof(buffer) - 1, " %s", name); + else + snprintf(buffer + 1, sizeof(buffer) - 1, " %s => %s", + name, other); + changelog->offset = print_wrapped_text(buffer, -changelog->offset, + CHANGELOG_TAB_SIZE + 2, CHANGELOG_WIDTH); +} + +static void finalize_changelog(struct diff_options *options, + struct changelog_t *changelog) +{ + changelog->offset = print_wrapped_text(": ", -changelog->offset, + CHANGELOG_TAB_SIZE + 2, CHANGELOG_WIDTH); + changelog->offset = print_wrapped_text(options->stat_sep, + -changelog->offset, + CHANGELOG_TAB_SIZE + 2, CHANGELOG_WIDTH); +} + void diff_setup(struct diff_options *options) { memset(options, 0, sizeof(*options)); @@ -2366,6 +2420,19 @@ static void diff_flush_checkdiff(struct diff_filepair *p, run_checkdiff(p, o); } +static void diff_flush_changelog(struct diff_filepair *p, + struct diff_options *o, struct changelog_t *changelog) +{ + if (diff_unmodified_pair(p)) + return; + + if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) || + (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode))) + return; /* no tree diffs in patch format */ + + run_changelog(p, o, changelog); +} + int diff_queue_is_empty(void) { struct diff_queue_struct *q = &diff_queued_diff; @@ -2752,6 +2819,16 @@ void diff_flush(struct diff_options *options) separator++; } + if (output_format & DIFF_FORMAT_CHANGELOG) { + struct changelog_t changelog; + memset(&changelog, 0, sizeof(struct changelog_t)); + for (i = 0; i < q->nr; i++) { + struct diff_filepair *p = q->queue[i]; + if (check_pair_status(p)) + diff_flush_changelog(p, options, &changelog); + } + finalize_changelog(options, &changelog); + } if (output_format & (DIFF_FORMAT_DIFFSTAT|DIFF_FORMAT_SHORTSTAT|DIFF_FORMAT_NUMSTAT)) { struct diffstat_t diffstat; diff --git a/diff.h b/diff.h index 4043cec..df3b512 100644 --- a/diff.h +++ b/diff.h @@ -30,6 +30,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, #define DIFF_FORMAT_SUMMARY 0x0008 #define DIFF_FORMAT_PATCH 0x0010 #define DIFF_FORMAT_SHORTSTAT 0x0020 +#define DIFF_FORMAT_CHANGELOG 0x0040 /* These override all above */ #define DIFF_FORMAT_NAME 0x0100 diff --git a/log-tree.c b/log-tree.c index 6ce239d..b7006bf 100644 --- a/log-tree.c +++ b/log-tree.c @@ -211,7 +211,8 @@ void show_log(struct rev_info *opt, const char *sep) sha1, sha1); opt->diffopt.stat_sep = buffer; } - } else if (opt->commit_format != CMIT_FMT_USERFORMAT) { + } else if (opt->commit_format != CMIT_FMT_USERFORMAT && + opt->commit_format != CMIT_FMT_CHANGELOG) { fputs(diff_get_color(opt->diffopt.color_diff, DIFF_COMMIT), stdout); if (opt->commit_format != CMIT_FMT_ONELINE) @@ -253,6 +254,20 @@ void show_log(struct rev_info *opt, const char *sep) sizeof(this_header), abbrev, subject, extra_headers, opt->relative_date); + if (opt->commit_format == CMIT_FMT_CHANGELOG) { + static char *oneline = NULL; + char *eol = strchr(this_header, '\n'); + + if (oneline) + free(oneline); + if (eol) { + oneline = xstrdup(eol + 1); + eol[1] = '\0'; + } else + oneline = NULL; + opt->diffopt.stat_sep = oneline; + } + if (opt->add_signoff) len = append_signoff(this_header, sizeof(this_header), len, opt->add_signoff); diff --git a/revision.c b/revision.c index 823bbd1..5bdc1fc 100644 --- a/revision.c +++ b/revision.c @@ -1119,6 +1119,12 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch if (revs->dense_combined_merges && !revs->diffopt.output_format) revs->diffopt.output_format = DIFF_FORMAT_PATCH; } + if (revs->commit_format == CMIT_FMT_CHANGELOG) { + revs->diffopt.output_format |= DIFF_FORMAT_CHANGELOG; + revs->diff = 1; + revs->diffopt.recursive = 1; + revs->no_merges = 1; + } revs->diffopt.abbrev = revs->abbrev; if (diff_setup_done(&revs->diffopt) < 0) die("diff_setup_done failed"); -- 1.5.0.2.2410.g737b - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html