Instead of saving human readable rename information in the 'name' field when diffstat info is generated, do it when writing --stat output. Change --numstat output to be machine friendly. This makes result of git-diff --numstat more suitable for machines also when renames are involved, by using format similar to the one for renames in the raw diff format, instead of the format more suited for humans. The numstat format for rename is now added deleted TAB path for "src" TAB path for "dst" LF or if -z option is used added deleted TAB path for "src" NUL NUL path for "dst" NUL When -z option is not used, ", TAB, LF, and backslash characters in pathnames are represented as \", \t, \n, and \\, respectively. If any character needs to be quoted then pathnames are enclosed in double quotes. Signed-off-by: Jakub Narebski <jnareb@xxxxxxxxx> --- This change increases memory footprint a bit, as struct diffstat_file is wider by sizeof(char *) wide field, which is NULL except for renames. I have thought about storing it using one pointer to fragment of memory of the form "dst name \0 src name \0", but this trades a little memory for CPU time. The goal of this change is to make it possible to generate HTML diffstat against first parent for merge commits in gitweb. The current notation for renames, which looks for example like below: t/{t6030-bisect-run.sh => t6030-bisect-porcelain.sh} is not easy to parse by machines (note that filename may contain "=>"), but easy to understand _usually_ by humans. P.S. By the way, what is the difference between quote_one and quote_c_style, i.e. when one calls one and when the other? diff.c | 22 ++++++++++++++++++---- 1 files changed, 18 insertions(+), 4 deletions(-) diff --git a/diff.c b/diff.c index 7bbe759..568c59b 100644 --- a/diff.c +++ b/diff.c @@ -703,6 +703,7 @@ struct diffstat_t { int alloc; struct diffstat_file { char *name; + char *from_name; unsigned is_unmerged:1; unsigned is_binary:1; unsigned is_renamed:1; @@ -722,12 +723,13 @@ static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat, diffstat->alloc * sizeof(x)); } diffstat->files[diffstat->nr++] = x; + x->name = xstrdup(name_a); if (name_b) { - x->name = pprint_rename(name_a, name_b); + x->from_name = xstrdup(name_b); x->is_renamed = 1; } else - x->name = xstrdup(name_a); + x->from_name = NULL; return x; } @@ -805,7 +807,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) struct diffstat_file *file = data->files[i]; int change = file->added + file->deleted; - if (!file->is_renamed) { /* renames are already quoted by pprint_rename */ + if (!file->is_renamed) { /* renames are quoted by pprint_rename */ len = quote_c_style(file->name, NULL, NULL, 0); if (len) { char *qname = xmalloc(len + 1); @@ -813,6 +815,10 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) free(file->name); file->name = qname; } + } else { + char *qname = pprint_rename(file->name, file->from_name); + free(file->name); + file->name = qname; } len = strlen(file->name); @@ -949,11 +955,19 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options) printf("-\t-\t"); else printf("%d\t%d\t", file->added, file->deleted); - if (options->line_termination && !file->is_renamed && + if (options->line_termination && quote_c_style(file->name, NULL, NULL, 0)) quote_c_style(file->name, NULL, stdout, 0); else fputs(file->name, stdout); + if (file->is_renamed) { + printf("%s", options->line_termination ? "\t" : "\0\0"); + if (options->line_termination && + quote_c_style(file->from_name, NULL, NULL, 0)) + quote_c_style(file->from_name, NULL, stdout, 0); + else + fputs(file->from_name, stdout); + } putchar(options->line_termination); } } -- 1.5.1.3 - 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