Quantcast

[PATCH] Correct singular form in diff summary line for human interaction

classic Classic list List threaded Threaded
32 messages Options
12
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH] Correct singular form in diff summary line for human interaction

Duy Nguyen
"git diff --stat" and "git apply --stat" now learn to print the line
"%d files changed, %d insertions(+), %d deletions(-)" in singular form
whenever applicable.

This change uncondtionally would upset scripts because scripts are not
nice. They simply hate changes. They can be very hostile when that
happens. So only adjust the line for human consumption.

Convenient function interactive_use() is added for this purpose. The
command thinks it's in human hands when:

 - GIT_SCRIPTING environment variable is not set
 - pager is on or
 - both stdout and stderr point to tty device

Signed-off-by: Nguyễn Thái Ngọc Duy <[hidden email]>
---
 The third attempt in the last couple months to remove three "s" in
 one line. I did not upset the test suite with this and hopefully
 won't upset any scripts around. Good start?

 builtin/apply.c |    3 ++-
 cache.h         |    1 +
 diff.c          |   33 ++++++++++++++++++++++++++++-----
 diff.h          |    3 +++
 pager.c         |    7 +++++++
 5 files changed, 41 insertions(+), 6 deletions(-)

diff --git a/builtin/apply.c b/builtin/apply.c
index c24dc54..389898f 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -14,6 +14,7 @@
 #include "builtin.h"
 #include "string-list.h"
 #include "dir.h"
+#include "diff.h"
 #include "parse-options.h"
 
 /*
@@ -3241,7 +3242,7 @@ static void stat_patch_list(struct patch *patch)
  show_stats(patch);
  }
 
- printf(" %d files changed, %d insertions(+), %d deletions(-)\n", files, adds, dels);
+ print_stat_summary(stdout, files, adds, dels);
 }
 
 static void numstat_patch_list(struct patch *patch)
diff --git a/cache.h b/cache.h
index 10afd71..7e0bb2b 100644
--- a/cache.h
+++ b/cache.h
@@ -1175,6 +1175,7 @@ extern void setup_pager(void);
 extern const char *pager_program;
 extern int pager_in_use(void);
 extern int pager_use_color;
+extern int interactive_use(void);
 
 extern const char *editor_program;
 extern const char *askpass_program;
diff --git a/diff.c b/diff.c
index 7e15426..2d63e9c 100644
--- a/diff.c
+++ b/diff.c
@@ -1322,6 +1322,32 @@ static void fill_print_name(struct diffstat_file *file)
  file->print_name = pname;
 }
 
+int print_stat_summary(FILE *fp, int files, int insertions, int deletions)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int ret;
+
+ if (!interactive_use())
+ return fprintf(fp, " %d files changed, %d insertions(+), %d deletions(-)\n",
+       files, insertions, deletions);
+
+ strbuf_addf(&sb,
+    ngettext(" %d file changed,", " %d files changed,",
+     files),
+    files);
+ strbuf_addf(&sb,
+    ngettext(" %d insertion(+),", " %d insertions(+),",
+     insertions),
+    insertions);
+ strbuf_addf(&sb,
+    ngettext(" %d deletion(-)\n", " %d deletions(-)\n",
+     deletions),
+    deletions);
+ ret = fputs(sb.buf, fp);
+ strbuf_release(&sb);
+ return ret;
+}
+
 static void show_stats(struct diffstat_t *data, struct diff_options *options)
 {
  int i, len, add, del, adds = 0, dels = 0;
@@ -1475,9 +1501,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
  extra_shown = 1;
  }
  fprintf(options->file, "%s", line_prefix);
- fprintf(options->file,
-       " %d files changed, %d insertions(+), %d deletions(-)\n",
-       total_files, adds, dels);
+ print_stat_summary(options->file, total_files, adds, dels);
 }
 
 static void show_shortstats(struct diffstat_t *data, struct diff_options *options)
@@ -1507,8 +1531,7 @@ static void show_shortstats(struct diffstat_t *data, struct diff_options *option
  options->output_prefix_data);
  fprintf(options->file, "%s", msg->buf);
  }
- fprintf(options->file, " %d files changed, %d insertions(+), %d deletions(-)\n",
-       total_files, adds, dels);
+ print_stat_summary(options->file, total_files, adds, dels);
 }
 
 static void show_numstat(struct diffstat_t *data, struct diff_options *options)
diff --git a/diff.h b/diff.h
index ae71f4c..7af5f1e 100644
--- a/diff.h
+++ b/diff.h
@@ -324,4 +324,7 @@ extern struct userdiff_driver *get_textconv(struct diff_filespec *one);
 
 extern int parse_rename_score(const char **cp_p);
 
+extern int print_stat_summary(FILE *fp, int files,
+      int insertions, int deletions);
+
 #endif /* DIFF_H */
diff --git a/pager.c b/pager.c
index 975955b..9a3d3d8 100644
--- a/pager.c
+++ b/pager.c
@@ -110,3 +110,10 @@ int pager_in_use(void)
  env = getenv("GIT_PAGER_IN_USE");
  return env ? git_config_bool("GIT_PAGER_IN_USE", env) : 0;
 }
+
+int interactive_use(void)
+{
+ const char *env;
+ env = getenv("GIT_SCRIPTING");
+ return !env && (pager_in_use() || (isatty(1) && isatty(2)));
+}
--
1.7.8.36.g69ee2

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH] Correct singular form in diff summary line for human interaction

Jonathan Nieder-2
Hi,

Nguyễn Thái Ngọc Duy wrote:

> Convenient function interactive_use() is added for this purpose. The
> command thinks it's in human hands when:

I admit I really dislike this, especially:

>  - GIT_SCRIPTING environment variable is not set

If my GUI app was parsing diffstats to convert them into a visual
representation, as a novice it may not be obvious to me where to find
the menu entry file to set this envvar in.

But maybe I'm not the right person to ask, since I'd be okay with
removing the "s"es (with an appropriate incubation time to discover
whether we are introducing a regression) unconditionally.

If there is an environment variable to say "I don't want to see
variations on strings intended for humans", can it be spelled as
LC_ALL=C?

Just my two cents,
Jonathan
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH] Correct singular form in diff summary line for human interaction

Junio C Hamano
Jonathan Nieder <[hidden email]> writes:

> Nguyễn Thái Ngọc Duy wrote:
>
>> Convenient function interactive_use() is added for this purpose. The
>> command thinks it's in human hands when:
>
> I admit I really dislike this, especially:
>
>>  - GIT_SCRIPTING environment variable is not set

I would have to agree that it is horrible.

> But maybe I'm not the right person to ask, since I'd be okay with
> removing the "s"es (with an appropriate incubation time to discover
> whether we are introducing a regression) unconditionally.
>
> If there is an environment variable to say "I don't want to see
> variations on strings intended for humans", can it be spelled as
> LC_ALL=C?

I have been wondering if we should even care, for two reasons.

 * We have had --numstat forever which is exactly what we added for scripts'
   use. "I've been parsing that output meant for humans" is not an excuse.

 * 'diffstat', at least the recent versions of it (it is hard to track
   down historical versions and I gave up [*1*]), gives output like these:

        1 file changed, 1 insertion(+)
        2 files changed, 3 insertions(+), 1 deletion(-)
        0 files changed

   The first one does not have anything but a one-line addition to a file,
   and we do not even see "0 deletions(-)". The second one is a more
   typical example. The third one is "diffstat </dev/null" [*2*].

If we were to touch this, I would prefer to do so unconditionally without
"hrm, can we reliably guess this is meant for humans?" and release it
unceremoniously, perhaps as part of the next release that will have a much
bigger user-visible UI correction to 'merge'.


[Footnote]

*1* I can guess from http://invisible-island.net/diffstat/CHANGES that the
source is probably kept in RCS, but I couldn't find development histories
beyond what is in that file.

*2* We mistakenly applied a patch to make "git apply --stat </dev/null" to
error out recently, which we might want to fix. But that is a separate
topic.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH] Correct singular form in diff summary line for human interaction

Duy Nguyen
On Wed, Feb 1, 2012 at 12:50 AM, Junio C Hamano <[hidden email]> wrote:

>> If there is an environment variable to say "I don't want to see
>> variations on strings intended for humans", can it be spelled as
>> LC_ALL=C?
>
>  ...
>
> If we were to touch this, I would prefer to do so unconditionally without
> "hrm, can we reliably guess this is meant for humans?" and release it
> unceremoniously, perhaps as part of the next release that will have a much
> bigger user-visible UI correction to 'merge'.

Unconditionally change is fine to me. There's another implication
that's not mentioned in the commit message, this change also allows
non-English translations. Any objections on i18n or we just keep this
line English only? Personally if scripts do not matter any more, I see
no reasons this line cannot be translated.
--
Duy
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH] Correct singular form in diff summary line for human interaction

Thomas Dickey
On Wed, Feb 01, 2012 at 08:32:43AM +0700, Nguyen Thai Ngoc Duy wrote:
> On Wed, Feb 1, 2012 at 12:50 AM, Junio C Hamano <[hidden email]> wrote:
> >> If there is an environment variable to say "I don't want to see
> >> variations on strings intended for humans", can it be spelled as
> >> LC_ALL=C?

I assume from Neider on the list that this is related to mawk, but I don't
have the email preceding this...

--
Thomas E. Dickey <[hidden email]>
http://invisible-island.net
ftp://invisible-island.net

signature.asc (204 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH] Correct singular form in diff summary line for human interaction

Thomas Dickey
In reply to this post by Duy Nguyen
On Wed, Feb 01, 2012 at 08:32:43AM +0700, Nguyen Thai Ngoc Duy wrote:
> On Wed, Feb 1, 2012 at 12:50 AM, Junio C Hamano <[hidden email]> wrote:
> >> If there is an environment variable to say "I don't want to see
> >> variations on strings intended for humans", can it be spelled as
> >> LC_ALL=C?
> >
> >  ...

... diffstat (google helped find context)

> > If we were to touch this, I would prefer to do so unconditionally without
> > "hrm, can we reliably guess this is meant for humans?" and release it
> > unceremoniously, perhaps as part of the next release that will have a much
> > bigger user-visible UI correction to 'merge'.
>
> Unconditionally change is fine to me. There's another implication
> that's not mentioned in the commit message, this change also allows
> non-English translations. Any objections on i18n or we just keep this
> line English only? Personally if scripts do not matter any more, I see
> no reasons this line cannot be translated.
I seem to recall that gettext does support plurals...

However, going that route means that even innocuous things like the
parentheses "(+)" can be mangled by translators (guaranteed to break
scripts ;-)

--
Thomas E. Dickey <[hidden email]>
http://invisible-island.net
ftp://invisible-island.net

signature.asc (204 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH] Correct singular form in diff summary line for human interaction

Duy Nguyen
On Wed, Feb 1, 2012 at 8:56 AM, Thomas Dickey <[hidden email]> wrote:

>> > If we were to touch this, I would prefer to do so unconditionally without
>> > "hrm, can we reliably guess this is meant for humans?" and release it
>> > unceremoniously, perhaps as part of the next release that will have a much
>> > bigger user-visible UI correction to 'merge'.
>>
>> Unconditionally change is fine to me. There's another implication
>> that's not mentioned in the commit message, this change also allows
>> non-English translations. Any objections on i18n or we just keep this
>> line English only? Personally if scripts do not matter any more, I see
>> no reasons this line cannot be translated.
>
> I seem to recall that gettext does support plurals...
>
> However, going that route means that even innocuous things like the
> parentheses "(+)" can be mangled by translators (guaranteed to break
> scripts ;-)

We disregard scripts at this point already, I think. "+" and "-"
should not be translated. We could either leave them out of
translatable text, or put a note to translators saying not to
translate them.
--
Duy
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH] Correct singular form in diff summary line for human interaction

Junio C Hamano
In reply to this post by Thomas Dickey
Thomas Dickey <[hidden email]> writes:

> On Wed, Feb 01, 2012 at 08:32:43AM +0700, Nguyen Thai Ngoc Duy wrote:
>> On Wed, Feb 1, 2012 at 12:50 AM, Junio C Hamano <[hidden email]> wrote:
>> >> If there is an environment variable to say "I don't want to see
>> >> variations on strings intended for humans", can it be spelled as
>> >> LC_ALL=C?
>> >
>> >  ...
>
> ... diffstat (google helped find context)

When we show diffstat from "git diff --stat" (or "git apply --stat"), we
currently do not do any singular/plural on the last line of the output
that summarizes the graph, ending up with:

        1 files changed, 1 insertions(+), 0 deletions(-)

when there is a single line insertion to a file and nothing else.

My recollection is that our behaviour originally came from our desire to
be as close as what "diffstat" produces, but that does not seem to be the
case.  I observed that the output from recent versions of "diffstat" is
much more human friendly.  We get these, depending on the input, from
"diffstat" version 1.53:

        1 file changed, 1 insertion(+)
        1 file changed, 1 deletion(-)
        0 files changed
        2 files changed, 3 insertions(+), 1 deletion(-)

Namely, it does singular/plural correctly, and omits unnecessary "0
deletions(-)" and "0 insertions(+)".

I was wondering if you remember what the behaviour of older versions of
"diffstat" was, and if it was changed to be more human friendly over
time. It is very possible that I am misremembering this and "diffstat" has
always done the singular/plural correctly and omitted useless "0 lines".

Somehow it seems hard to get hold of older versions of "diffstat", and I
was hoping that I could get that information straight out of the current
maintainer.

Thanks for responding and sorry for the lack of context of the original
message.

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH] Correct singular form in diff summary line for human interaction

Thomas Dickey
On Tue, Jan 31, 2012 at 07:04:15PM -0800, Junio C Hamano wrote:

> Thomas Dickey <[hidden email]> writes:
>
> > On Wed, Feb 01, 2012 at 08:32:43AM +0700, Nguyen Thai Ngoc Duy wrote:
> >> On Wed, Feb 1, 2012 at 12:50 AM, Junio C Hamano <[hidden email]> wrote:
> >> >> If there is an environment variable to say "I don't want to see
> >> >> variations on strings intended for humans", can it be spelled as
> >> >> LC_ALL=C?
> >> >
> >> >  ...
> >
> > ... diffstat (google helped find context)
>
> When we show diffstat from "git diff --stat" (or "git apply --stat"), we
> currently do not do any singular/plural on the last line of the output
> that summarizes the graph, ending up with:
>
> 1 files changed, 1 insertions(+), 0 deletions(-)
>
> when there is a single line insertion to a file and nothing else.
>
> My recollection is that our behaviour originally came from our desire to
> be as close as what "diffstat" produces, but that does not seem to be the
> case.  I observed that the output from recent versions of "diffstat" is
> much more human friendly.  We get these, depending on the input, from
> "diffstat" version 1.53:
I added the PLURAL() macro in 1.22, in 1996/3/16, which was a few months
before Tony Nugent commented that it was being used by other people.  Since
I'd been sending patches with diffstat's since mid-1994, it's possible
that there were a few copies using the form without plurals.  But it's
been quite a while.  Also, it was in 1998/1/17 that I modified the
copyright notice (1.26) at the request of someone in the Linux group, so
I'd assume that they would have started using the newer version.

Except for later applying PLURAL to the number of files changed (which Jean
Delvare pointed out in 2005), the message construction has not changed since
then.  The insert/delete/modify parts of the message were optional as you see in
my earliest version (1.3) from 1993/10/23:

        printf("%d files changed", num_files);
        if (total_ins) printf(", %d insertions", total_ins);
        if (total_del) printf(", %d deletions", total_del);
        if (total_mod) printf(", %d modifications", total_mod);
        printf("\n");
 

>         1 file changed, 1 insertion(+)
>         1 file changed, 1 deletion(-)
> 0 files changed
> 2 files changed, 3 insertions(+), 1 deletion(-)
>
> Namely, it does singular/plural correctly, and omits unnecessary "0
> deletions(-)" and "0 insertions(+)".
>
> I was wondering if you remember what the behaviour of older versions of
> "diffstat" was, and if it was changed to be more human friendly over
> time. It is very possible that I am misremembering this and "diffstat" has
> always done the singular/plural correctly and omitted useless "0 lines".
I have back to 1.3 in my archive. I use rcshist to look for things like this.
(also, for small things like this, I have a script that pulls all versions,
with proper timestamps to make it simpler to sort the files by date).
 
> Somehow it seems hard to get hold of older versions of "diffstat", and I
> was hoping that I could get that information straight out of the current
> maintainer.

I can provide the information.

Actually a couple of weeks ago I was experimenting with rcs-fast-export, but
found that would need more work to export diffstat (I use branches a lot)
I'm using "conflict" as a test-case for the changes that I'm making to support
exporting mawk.

> Thanks for responding and sorry for the lack of context of the original
> message.

no problem - google was helpful ;-)

--
Thomas E. Dickey <[hidden email]>
http://invisible-island.net
ftp://invisible-island.net

signature.asc (204 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH v2] Use correct grammar in diffstat summary line

Duy Nguyen
In reply to this post by Duy Nguyen
"git diff --stat" and "git apply --stat" now learn to print the line
"%d files changed, %d insertions(+), %d deletions(-)" in singular form
whenever applicable. "0 insertions" and "0 deletions" are also omitted
unless they are both zero.

Also make this line translatable.

Signed-off-by: Nguyễn Thái Ngọc Duy <[hidden email]>
---
 Second try. Make it unconditionally (I'd still rather have no changes
 when LANG=C). Also omit "0 operations", although I keep "%d files
 changed, 0 insertions(+), 0 deletions(-)" for binary diff.

 In Vietnamese, the summary line is "thay đổi 68 tập tin, thêm(+) 163,
 xoá(-) 116". Lovely. Perhaps I'll translate git into Vietnamese after
 all :)

 And this patch's diffstat looks just scary due to test suite's updates.

 builtin/apply.c                                    |    3 +-
 diff.c                                             |   53 ++++++++++++++++++--
 diff.h                                             |    3 +
 t/t0023-crlf-am.sh                                 |    2 +-
 t/t1200-tutorial.sh                                |    2 +-
 t/t3300-funny-names.sh                             |    2 +-
 t/t3508-cherry-pick-many-commits.sh                |   12 ++--
 t/t3903-stash.sh                                   |    4 +-
 ...ff-tree_--cc_--patch-with-stat_--summary_master |    2 +-
 ...diff-tree_--cc_--patch-with-stat_--summary_side |    2 +-
 .../diff.diff-tree_--cc_--patch-with-stat_master   |    2 +-
 .../diff.diff-tree_--cc_--stat_--summary_master    |    2 +-
 t/t4013/diff.diff-tree_--cc_--stat_--summary_side  |    2 +-
 t/t4013/diff.diff-tree_--cc_--stat_master          |    2 +-
 ...pretty=oneline_--root_--patch-with-stat_initial |    2 +-
 .../diff.diff-tree_--pretty_--patch-with-stat_side |    2 +-
 ...-tree_--pretty_--root_--patch-with-stat_initial |    2 +-
 ...f-tree_--pretty_--root_--stat_--summary_initial |    2 +-
 .../diff.diff-tree_--pretty_--root_--stat_initial  |    2 +-
 ...diff.diff-tree_--root_--patch-with-stat_initial |    2 +-
 t/t4013/diff.diff-tree_-c_--stat_--summary_master  |    2 +-
 t/t4013/diff.diff-tree_-c_--stat_--summary_side    |    2 +-
 t/t4013/diff.diff-tree_-c_--stat_master            |    2 +-
 .../diff.diff_--patch-with-stat_-r_initial..side   |    2 +-
 t/t4013/diff.diff_--patch-with-stat_initial..side  |    2 +-
 t/t4013/diff.diff_--stat_initial..side             |    2 +-
 t/t4013/diff.diff_-r_--stat_initial..side          |    2 +-
 ..._--attach_--stdout_--suffix=.diff_initial..side |    2 +-
 ....format-patch_--attach_--stdout_initial..master |    4 +-
 ...format-patch_--attach_--stdout_initial..master^ |    2 +-
 ...ff.format-patch_--attach_--stdout_initial..side |    2 +-
 ...nline_--stdout_--numbered-files_initial..master |    4 +-
 ...tdout_--subject-prefix=TESTCASE_initial..master |    4 +-
 ....format-patch_--inline_--stdout_initial..master |    4 +-
 ...format-patch_--inline_--stdout_initial..master^ |    2 +-
 ...ff.format-patch_--inline_--stdout_initial..side |    2 +-
 ...tch_--stdout_--cover-letter_-n_initial..master^ |    2 +-
 ...at-patch_--stdout_--no-numbered_initial..master |    4 +-
 ...ormat-patch_--stdout_--numbered_initial..master |    4 +-
 t/t4013/diff.format-patch_--stdout_initial..master |    4 +-
 .../diff.format-patch_--stdout_initial..master^    |    2 +-
 t/t4013/diff.format-patch_--stdout_initial..side   |    2 +-
 ....log_--patch-with-stat_--summary_master_--_dir_ |    6 +-
 t/t4013/diff.log_--patch-with-stat_master          |    4 +-
 t/t4013/diff.log_--patch-with-stat_master_--_dir_  |    6 +-
 ..._--root_--cc_--patch-with-stat_--summary_master |    8 ++--
 ...f.log_--root_--patch-with-stat_--summary_master |    6 +-
 t/t4013/diff.log_--root_--patch-with-stat_master   |    6 +-
 ...og_--root_-c_--patch-with-stat_--summary_master |    8 ++--
 t/t4013/diff.show_--patch-with-stat_--summary_side |    2 +-
 t/t4013/diff.show_--patch-with-stat_side           |    2 +-
 t/t4013/diff.show_--stat_--summary_side            |    2 +-
 t/t4013/diff.show_--stat_side                      |    2 +-
 ...nged_--patch-with-stat_--summary_master_--_dir_ |    6 +-
 t/t4013/diff.whatchanged_--patch-with-stat_master  |    4 +-
 ...ff.whatchanged_--patch-with-stat_master_--_dir_ |    6 +-
 ..._--root_--cc_--patch-with-stat_--summary_master |    8 ++--
 ...anged_--root_--patch-with-stat_--summary_master |    6 +-
 ...iff.whatchanged_--root_--patch-with-stat_master |    6 +-
 ...ed_--root_-c_--patch-with-stat_--summary_master |    8 ++--
 t/t4014-format-patch.sh                            |    2 +-
 t/t4030-diff-textconv.sh                           |    2 +-
 t/t4045-diff-relative.sh                           |    2 +-
 t/t4049-diff-stat-count.sh                         |    2 +-
 t/t4100/t-apply-8.expect                           |    2 +-
 t/t4100/t-apply-9.expect                           |    2 +-
 t/t5150-request-pull.sh                            |    2 +-
 t/t7602-merge-octopus-many.sh                      |    6 +-
 68 files changed, 163 insertions(+), 116 deletions(-)

diff --git a/builtin/apply.c b/builtin/apply.c
index c24dc54..389898f 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -14,6 +14,7 @@
 #include "builtin.h"
 #include "string-list.h"
 #include "dir.h"
+#include "diff.h"
 #include "parse-options.h"
 
 /*
@@ -3241,7 +3242,7 @@ static void stat_patch_list(struct patch *patch)
  show_stats(patch);
  }
 
- printf(" %d files changed, %d insertions(+), %d deletions(-)\n", files, adds, dels);
+ print_stat_summary(stdout, files, adds, dels);
 }
 
 static void numstat_patch_list(struct patch *patch)
diff --git a/diff.c b/diff.c
index 7e15426..5c31b36 100644
--- a/diff.c
+++ b/diff.c
@@ -1322,6 +1322,52 @@ static void fill_print_name(struct diffstat_file *file)
  file->print_name = pname;
 }
 
+int print_stat_summary(FILE *fp, int files, int insertions, int deletions)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int ret;
+
+ if (!files) {
+ assert(insertions == 0 && deletions == 0);
+ return fputs(_(" no changes\n"), fp);
+ }
+
+ strbuf_addf(&sb,
+    ngettext(" %d file changed", " %d files changed",
+     files),
+    files);
+
+ /*
+ * For binary diff, the caller may want to print "x files
+ * changed" with insertions == 0 && deletions == 0. Not
+ * omitting "0 insertions(+), 0 deletions(-)" in this case is
+ * probably less confusing (i.e skip over "2 files changed but
+ * nothing about added/removed lines? Is this a bug in
+ * git??").
+ */
+ if (insertions || deletions == 0) {
+ strbuf_addf(&sb,
+    /* TRANSLATORS: "+" in (+) is a line
+       addition marker, do not translate it */
+    ngettext(", %d insertion(+)", ", %d insertions(+)",
+     insertions),
+    insertions);
+ }
+
+ if (deletions || insertions == 0) {
+ strbuf_addf(&sb,
+    /* TRANSLATORS: "-" in (-) is a line
+       removal marker, do not translate it */
+    ngettext(", %d deletion(-)", ", %d deletions(-)",
+     deletions),
+    deletions);
+ }
+ strbuf_addch(&sb, '\n');
+ ret = fputs(sb.buf, fp);
+ strbuf_release(&sb);
+ return ret;
+}
+
 static void show_stats(struct diffstat_t *data, struct diff_options *options)
 {
  int i, len, add, del, adds = 0, dels = 0;
@@ -1475,9 +1521,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
  extra_shown = 1;
  }
  fprintf(options->file, "%s", line_prefix);
- fprintf(options->file,
-       " %d files changed, %d insertions(+), %d deletions(-)\n",
-       total_files, adds, dels);
+ print_stat_summary(options->file, total_files, adds, dels);
 }
 
 static void show_shortstats(struct diffstat_t *data, struct diff_options *options)
@@ -1507,8 +1551,7 @@ static void show_shortstats(struct diffstat_t *data, struct diff_options *option
  options->output_prefix_data);
  fprintf(options->file, "%s", msg->buf);
  }
- fprintf(options->file, " %d files changed, %d insertions(+), %d deletions(-)\n",
-       total_files, adds, dels);
+ print_stat_summary(options->file, total_files, adds, dels);
 }
 
 static void show_numstat(struct diffstat_t *data, struct diff_options *options)
diff --git a/diff.h b/diff.h
index ae71f4c..7af5f1e 100644
--- a/diff.h
+++ b/diff.h
@@ -324,4 +324,7 @@ extern struct userdiff_driver *get_textconv(struct diff_filespec *one);
 
 extern int parse_rename_score(const char **cp_p);
 
+extern int print_stat_summary(FILE *fp, int files,
+      int insertions, int deletions);
+
 #endif /* DIFF_H */
diff --git a/t/t0023-crlf-am.sh b/t/t0023-crlf-am.sh
index aaed725..18fe27b 100755
--- a/t/t0023-crlf-am.sh
+++ b/t/t0023-crlf-am.sh
@@ -12,7 +12,7 @@ Subject: test1
 
 ---
  foo |    1 +
- 1 files changed, 1 insertions(+), 0 deletions(-)
+ 1 file changed, 1 insertion(+)
  create mode 100644 foo
 
 diff --git a/foo b/foo
diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh
index 5e29e13..9356bea 100755
--- a/t/t1200-tutorial.sh
+++ b/t/t1200-tutorial.sh
@@ -156,7 +156,7 @@ Updating VARIABLE..VARIABLE
 FASTFORWARD (no commit created; -m option ignored)
  example |    1 +
  hello   |    1 +
- 2 files changed, 2 insertions(+), 0 deletions(-)
+ 2 files changed, 2 insertions(+)
 EOF
 
 test_expect_success 'git resolve' '
diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh
index 5e29a05..9f00ada 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -167,7 +167,7 @@ test_expect_success TABS_IN_FILENAMES 'git diff-tree delete with-funny' \
 test_expect_success TABS_IN_FILENAMES 'setup expect' '
 cat >expected <<\EOF
  "tabs\t,\" (dq) and spaces"
- 1 files changed, 0 insertions(+), 0 deletions(-)
+ 1 file changed, 0 insertions(+), 0 deletions(-)
 EOF
 '
 
diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh
index 8e09fd0..1b3a344 100755
--- a/t/t3508-cherry-pick-many-commits.sh
+++ b/t/t3508-cherry-pick-many-commits.sh
@@ -38,13 +38,13 @@ test_expect_success 'cherry-pick first..fourth works' '
  cat <<-\EOF >expected &&
  [master OBJID] second
  Author: A U Thor <[hidden email]>
- 1 files changed, 1 insertions(+), 0 deletions(-)
+ 1 file changed, 1 insertion(+)
  [master OBJID] third
  Author: A U Thor <[hidden email]>
- 1 files changed, 1 insertions(+), 0 deletions(-)
+ 1 file changed, 1 insertion(+)
  [master OBJID] fourth
  Author: A U Thor <[hidden email]>
- 1 files changed, 1 insertions(+), 0 deletions(-)
+ 1 file changed, 1 insertion(+)
  EOF
 
  git checkout -f master &&
@@ -64,15 +64,15 @@ test_expect_success 'cherry-pick --strategy resolve first..fourth works' '
  Trying simple merge.
  [master OBJID] second
  Author: A U Thor <[hidden email]>
- 1 files changed, 1 insertions(+), 0 deletions(-)
+ 1 file changed, 1 insertion(+)
  Trying simple merge.
  [master OBJID] third
  Author: A U Thor <[hidden email]>
- 1 files changed, 1 insertions(+), 0 deletions(-)
+ 1 file changed, 1 insertion(+)
  Trying simple merge.
  [master OBJID] fourth
  Author: A U Thor <[hidden email]>
- 1 files changed, 1 insertions(+), 0 deletions(-)
+ 1 file changed, 1 insertion(+)
  EOF
 
  git checkout -f master &&
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index dbe2ac1..663c60a 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -444,7 +444,7 @@ test_expect_success 'stash show - stashes on stack, stash-like argument' '
  git reset --hard &&
  cat >expected <<-EOF &&
  file |    1 +
- 1 files changed, 1 insertions(+), 0 deletions(-)
+ 1 file changed, 1 insertion(+)
  EOF
  git stash show ${STASH_ID} >actual &&
  test_cmp expected actual
@@ -482,7 +482,7 @@ test_expect_success 'stash show - no stashes on stack, stash-like argument' '
  git reset --hard &&
  cat >expected <<-EOF &&
  file |    1 +
- 1 files changed, 1 insertions(+), 0 deletions(-)
+ 1 file changed, 1 insertion(+)
  EOF
  git stash show ${STASH_ID} >actual &&
  test_cmp expected actual
diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master
index 3a9f78a..2f8560c 100644
--- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master
+++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master
@@ -2,7 +2,7 @@ $ git diff-tree --cc --patch-with-stat --summary master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --cc dir/sub
 index cead32e,7289e35..992913c
diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side
index a61ad8c..72e03c1 100644
--- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side
+++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side
@@ -3,7 +3,7 @@ c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master
index 49f23b9..8b357d9 100644
--- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master
+++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master
@@ -2,7 +2,7 @@ $ git diff-tree --cc --patch-with-stat master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --cc dir/sub
 index cead32e,7289e35..992913c
diff --git a/t/t4013/diff.diff-tree_--cc_--stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master
index cc6eb3b..e0568d6 100644
--- a/t/t4013/diff.diff-tree_--cc_--stat_--summary_master
+++ b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master
@@ -2,5 +2,5 @@ $ git diff-tree --cc --stat --summary master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 $
diff --git a/t/t4013/diff.diff-tree_--cc_--stat_--summary_side b/t/t4013/diff.diff-tree_--cc_--stat_--summary_side
index 50362be..5afc823 100644
--- a/t/t4013/diff.diff-tree_--cc_--stat_--summary_side
+++ b/t/t4013/diff.diff-tree_--cc_--stat_--summary_side
@@ -3,6 +3,6 @@ c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 $
diff --git a/t/t4013/diff.diff-tree_--cc_--stat_master b/t/t4013/diff.diff-tree_--cc_--stat_master
index fae7f33..f48367a 100644
--- a/t/t4013/diff.diff-tree_--cc_--stat_master
+++ b/t/t4013/diff.diff-tree_--cc_--stat_master
@@ -2,5 +2,5 @@ $ git diff-tree --cc --stat master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 $
diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial
index d5c333a..590864c 100644
--- a/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial
+++ b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial
@@ -3,7 +3,7 @@ $ git diff-tree --pretty=oneline --root --patch-with-stat initial
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 new file mode 100644
diff --git a/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side b/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side
index 4d30e7e..e05e778 100644
--- a/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side
+++ b/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial
index 7dfa6af..0e2c956 100644
--- a/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial
+++ b/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 new file mode 100644
diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial b/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial
index 43bfce2..384fa44 100644
--- a/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial
+++ b/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
  create mode 100644 file2
diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial b/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial
index 9154aa4..10384a8 100644
--- a/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial
+++ b/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial
@@ -8,5 +8,5 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
 $
diff --git a/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial
index 1562b62..f57062e 100644
--- a/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial
+++ b/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial
@@ -3,7 +3,7 @@ $ git diff-tree --root --patch-with-stat initial
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 new file mode 100644
diff --git a/t/t4013/diff.diff-tree_-c_--stat_--summary_master b/t/t4013/diff.diff-tree_-c_--stat_--summary_master
index ac9f641..7088683 100644
--- a/t/t4013/diff.diff-tree_-c_--stat_--summary_master
+++ b/t/t4013/diff.diff-tree_-c_--stat_--summary_master
@@ -2,5 +2,5 @@ $ git diff-tree -c --stat --summary master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 $
diff --git a/t/t4013/diff.diff-tree_-c_--stat_--summary_side b/t/t4013/diff.diff-tree_-c_--stat_--summary_side
index 2afcca1..ef216ab 100644
--- a/t/t4013/diff.diff-tree_-c_--stat_--summary_side
+++ b/t/t4013/diff.diff-tree_-c_--stat_--summary_side
@@ -3,6 +3,6 @@ c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 $
diff --git a/t/t4013/diff.diff-tree_-c_--stat_master b/t/t4013/diff.diff-tree_-c_--stat_master
index c2fe6a9..ad19f10 100644
--- a/t/t4013/diff.diff-tree_-c_--stat_master
+++ b/t/t4013/diff.diff-tree_-c_--stat_master
@@ -2,5 +2,5 @@ $ git diff-tree -c --stat master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 $
diff --git a/t/t4013/diff.diff_--patch-with-stat_-r_initial..side b/t/t4013/diff.diff_--patch-with-stat_-r_initial..side
index 9ed317a..ddad917 100644
--- a/t/t4013/diff.diff_--patch-with-stat_-r_initial..side
+++ b/t/t4013/diff.diff_--patch-with-stat_-r_initial..side
@@ -2,7 +2,7 @@ $ git diff --patch-with-stat -r initial..side
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
diff --git a/t/t4013/diff.diff_--patch-with-stat_initial..side b/t/t4013/diff.diff_--patch-with-stat_initial..side
index 8b50629..bdbd114 100644
--- a/t/t4013/diff.diff_--patch-with-stat_initial..side
+++ b/t/t4013/diff.diff_--patch-with-stat_initial..side
@@ -2,7 +2,7 @@ $ git diff --patch-with-stat initial..side
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
diff --git a/t/t4013/diff.diff_--stat_initial..side b/t/t4013/diff.diff_--stat_initial..side
index 0517b5d..6d08f3d 100644
--- a/t/t4013/diff.diff_--stat_initial..side
+++ b/t/t4013/diff.diff_--stat_initial..side
@@ -2,5 +2,5 @@ $ git diff --stat initial..side
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 $
diff --git a/t/t4013/diff.diff_-r_--stat_initial..side b/t/t4013/diff.diff_-r_--stat_initial..side
index 245220d..2ddb254 100644
--- a/t/t4013/diff.diff_-r_--stat_initial..side
+++ b/t/t4013/diff.diff_-r_--stat_initial..side
@@ -2,5 +2,5 @@ $ git diff -r --stat initial..side
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 $
diff --git a/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side b/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side
index 52116d3..3cab049 100644
--- a/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side
+++ b/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side
@@ -15,7 +15,7 @@ Content-Transfer-Encoding: 8bit
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 
diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master b/t/t4013/diff.format-patch_--attach_--stdout_initial..master
index ce49bd6..564a4d3 100644
--- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master
+++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master
@@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 
@@ -124,7 +124,7 @@ Content-Transfer-Encoding: 8bit
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 
diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^
index 5f1b238..4f28460 100644
--- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^
+++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^
@@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 
diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..side b/t/t4013/diff.format-patch_--attach_--stdout_initial..side
index 4a2364a..b10cc2e 100644
--- a/t/t4013/diff.format-patch_--attach_--stdout_initial..side
+++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..side
@@ -15,7 +15,7 @@ Content-Transfer-Encoding: 8bit
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 
diff --git a/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master
index 43b81eb..a976a8a 100644
--- a/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master
+++ b/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master
@@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 
@@ -124,7 +124,7 @@ Content-Transfer-Encoding: 8bit
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 
diff --git a/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master
index ca3f60b..b4fd664 100644
--- a/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master
+++ b/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master
@@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 
@@ -124,7 +124,7 @@ Content-Transfer-Encoding: 8bit
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 
diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_initial..master
index 08f2301..0d31036 100644
--- a/t/t4013/diff.format-patch_--inline_--stdout_initial..master
+++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master
@@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 
@@ -124,7 +124,7 @@ Content-Transfer-Encoding: 8bit
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 
diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^
index 07f1230..18d4714 100644
--- a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^
+++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^
@@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 
diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..side b/t/t4013/diff.format-patch_--inline_--stdout_initial..side
index 67633d4..3572f20 100644
--- a/t/t4013/diff.format-patch_--inline_--stdout_initial..side
+++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..side
@@ -15,7 +15,7 @@ Content-Transfer-Encoding: 8bit
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 
diff --git a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
index 3b4e113..54cdcda 100644
--- a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
+++ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
@@ -75,7 +75,7 @@ Subject: [DIFFERENT_PREFIX 2/2] Third
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
diff --git a/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master b/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master
index f7752eb..23194eb 100644
--- a/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master
+++ b/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master
@@ -53,7 +53,7 @@ Subject: [PATCH] Third
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -88,7 +88,7 @@ Subject: [PATCH] Side
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
diff --git a/t/t4013/diff.format-patch_--stdout_--numbered_initial..master b/t/t4013/diff.format-patch_--stdout_--numbered_initial..master
index 8e67dbf..78f1a80 100644
--- a/t/t4013/diff.format-patch_--stdout_--numbered_initial..master
+++ b/t/t4013/diff.format-patch_--stdout_--numbered_initial..master
@@ -53,7 +53,7 @@ Subject: [PATCH 2/3] Third
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -88,7 +88,7 @@ Subject: [PATCH 3/3] Side
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
diff --git a/t/t4013/diff.format-patch_--stdout_initial..master b/t/t4013/diff.format-patch_--stdout_initial..master
index 7b89978..a3dab7f 100644
--- a/t/t4013/diff.format-patch_--stdout_initial..master
+++ b/t/t4013/diff.format-patch_--stdout_initial..master
@@ -53,7 +53,7 @@ Subject: [PATCH 2/3] Third
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -88,7 +88,7 @@ Subject: [PATCH 3/3] Side
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
diff --git a/t/t4013/diff.format-patch_--stdout_initial..master^ b/t/t4013/diff.format-patch_--stdout_initial..master^
index b7f9725..39f4a3f 100644
--- a/t/t4013/diff.format-patch_--stdout_initial..master^
+++ b/t/t4013/diff.format-patch_--stdout_initial..master^
@@ -53,7 +53,7 @@ Subject: [PATCH 2/2] Third
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
diff --git a/t/t4013/diff.format-patch_--stdout_initial..side b/t/t4013/diff.format-patch_--stdout_initial..side
index e765088..8810920 100644
--- a/t/t4013/diff.format-patch_--stdout_initial..side
+++ b/t/t4013/diff.format-patch_--stdout_initial..side
@@ -8,7 +8,7 @@ Subject: [PATCH] Side
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
diff --git a/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_
index bd7f5c0..4085bbd 100644
--- a/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_
+++ b/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_
@@ -13,7 +13,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
     Side
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
@@ -32,7 +32,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
     Third
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 8422d40..cead32e 100644
@@ -54,7 +54,7 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     This is the second commit.
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..8422d40 100644
diff --git a/t/t4013/diff.log_--patch-with-stat_master b/t/t4013/diff.log_--patch-with-stat_master
index 14595a6..4586279 100644
--- a/t/t4013/diff.log_--patch-with-stat_master
+++ b/t/t4013/diff.log_--patch-with-stat_master
@@ -15,7 +15,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
@@ -56,7 +56,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 8422d40..cead32e 100644
diff --git a/t/t4013/diff.log_--patch-with-stat_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_master_--_dir_
index 5a4e727..6e172cf 100644
--- a/t/t4013/diff.log_--patch-with-stat_master_--_dir_
+++ b/t/t4013/diff.log_--patch-with-stat_master_--_dir_
@@ -13,7 +13,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
     Side
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
@@ -32,7 +32,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
     Third
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 8422d40..cead32e 100644
@@ -54,7 +54,7 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     This is the second commit.
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..8422d40 100644
diff --git a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master
index df0aaa9..48b0d4b 100644
--- a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master
+++ b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:04:00 2006 +0000
 
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --cc dir/sub
 index cead32e,7289e35..992913c
@@ -47,7 +47,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
@@ -89,7 +89,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -165,7 +165,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
  create mode 100644 file2
diff --git a/t/t4013/diff.log_--root_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--patch-with-stat_--summary_master
index c11b5f2c..f9dc512 100644
--- a/t/t4013/diff.log_--root_--patch-with-stat_--summary_master
+++ b/t/t4013/diff.log_--root_--patch-with-stat_--summary_master
@@ -15,7 +15,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
@@ -57,7 +57,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -133,7 +133,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
  create mode 100644 file2
diff --git a/t/t4013/diff.log_--root_--patch-with-stat_master b/t/t4013/diff.log_--root_--patch-with-stat_master
index 5f0c98f..0807ece 100644
--- a/t/t4013/diff.log_--root_--patch-with-stat_master
+++ b/t/t4013/diff.log_--root_--patch-with-stat_master
@@ -15,7 +15,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
@@ -56,7 +56,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 8422d40..cead32e 100644
@@ -130,7 +130,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 new file mode 100644
diff --git a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master
index e62c368..84f5ef6 100644
--- a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master
+++ b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:04:00 2006 +0000
 
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --combined dir/sub
 index cead32e,7289e35..992913c
@@ -47,7 +47,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
@@ -89,7 +89,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -165,7 +165,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
  create mode 100644 file2
diff --git a/t/t4013/diff.show_--patch-with-stat_--summary_side b/t/t4013/diff.show_--patch-with-stat_--summary_side
index 377f2b7..e60384d 100644
--- a/t/t4013/diff.show_--patch-with-stat_--summary_side
+++ b/t/t4013/diff.show_--patch-with-stat_--summary_side
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
diff --git a/t/t4013/diff.show_--patch-with-stat_side b/t/t4013/diff.show_--patch-with-stat_side
index fb14c53..a3a3255 100644
--- a/t/t4013/diff.show_--patch-with-stat_side
+++ b/t/t4013/diff.show_--patch-with-stat_side
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
diff --git a/t/t4013/diff.show_--stat_--summary_side b/t/t4013/diff.show_--stat_--summary_side
index 5bd5977..d16f464 100644
--- a/t/t4013/diff.show_--stat_--summary_side
+++ b/t/t4013/diff.show_--stat_--summary_side
@@ -8,6 +8,6 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 $
diff --git a/t/t4013/diff.show_--stat_side b/t/t4013/diff.show_--stat_side
index 3b22327..6300c05 100644
--- a/t/t4013/diff.show_--stat_side
+++ b/t/t4013/diff.show_--stat_side
@@ -8,5 +8,5 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 $
diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_
index 6a467cc..16ae543 100644
--- a/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_
+++ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_
@@ -6,7 +6,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
     Side
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
@@ -25,7 +25,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
     Third
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 8422d40..cead32e 100644
@@ -47,7 +47,7 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     This is the second commit.
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..8422d40 100644
diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master b/t/t4013/diff.whatchanged_--patch-with-stat_master
index 1e1bbe1..f3e45ec 100644
--- a/t/t4013/diff.whatchanged_--patch-with-stat_master
+++ b/t/t4013/diff.whatchanged_--patch-with-stat_master
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
@@ -49,7 +49,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 8422d40..cead32e 100644
diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_
index 13789f1..c77f0bc 100644
--- a/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_
+++ b/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_
@@ -6,7 +6,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
     Side
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
@@ -25,7 +25,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
     Third
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 8422d40..cead32e 100644
@@ -47,7 +47,7 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     This is the second commit.
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..8422d40 100644
diff --git a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master
index e96ff1f..8d03efe 100644
--- a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master
+++ b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:04:00 2006 +0000
 
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --cc dir/sub
 index cead32e,7289e35..992913c
@@ -47,7 +47,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
@@ -89,7 +89,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -165,7 +165,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
  create mode 100644 file2
diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master
index 0291153..1874d06 100644
--- a/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master
+++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
@@ -50,7 +50,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -126,7 +126,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
  create mode 100644 file2
diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_master
index 9b0349c..5211ff2 100644
--- a/t/t4013/diff.whatchanged_--root_--patch-with-stat_master
+++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_master
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
@@ -49,7 +49,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 8422d40..cead32e 100644
@@ -123,7 +123,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 new file mode 100644
diff --git a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master
index c0aff68..ad30245 100644
--- a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master
+++ b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:04:00 2006 +0000
 
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --combined dir/sub
 index cead32e,7289e35..992913c
@@ -47,7 +47,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
@@ -89,7 +89,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -165,7 +165,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
  create mode 100644 file2
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 6797512..7dfe716 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -520,7 +520,7 @@ test_expect_success 'shortlog of cover-letter wraps overly-long onelines' '
 cat > expect << EOF
 ---
  file |   16 ++++++++++++++++
- 1 files changed, 16 insertions(+), 0 deletions(-)
+ 1 file changed, 16 insertions(+)
 
 diff --git a/file b/file
 index 40f36c6..2dc5c23 100644
diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index 88c5619..4ac162c 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -86,7 +86,7 @@ test_expect_success 'status -v produces text' '
 
 cat >expect.stat <<'EOF'
  file |  Bin 2 -> 4 bytes
- 1 files changed, 0 insertions(+), 0 deletions(-)
+ 1 file changed, 0 insertions(+), 0 deletions(-)
 EOF
 test_expect_success 'diffstat does not run textconv' '
  echo file diff=fail >.gitattributes &&
diff --git a/t/t4045-diff-relative.sh b/t/t4045-diff-relative.sh
index 8a3c63b..bd119be 100755
--- a/t/t4045-diff-relative.sh
+++ b/t/t4045-diff-relative.sh
@@ -33,7 +33,7 @@ check_stat() {
 expect=$1; shift
 cat >expected <<EOF
  $expect |    1 +
- 1 files changed, 1 insertions(+), 0 deletions(-)
+ 1 file changed, 1 insertion(+)
 EOF
 test_expect_success "--stat $*" "
  git diff --stat $* HEAD^ >actual &&
diff --git a/t/t4049-diff-stat-count.sh b/t/t4049-diff-stat-count.sh
index 641e70d..a6d1887 100755
--- a/t/t4049-diff-stat-count.sh
+++ b/t/t4049-diff-stat-count.sh
@@ -16,7 +16,7 @@ test_expect_success setup '
  cat >expect <<-\EOF
  a |    1 +
  b |    1 +
- 2 files changed, 2 insertions(+), 0 deletions(-)
+ 2 files changed, 2 insertions(+)
  EOF
  git diff --stat --stat-count=2 >actual &&
  test_cmp expect actual
diff --git a/t/t4100/t-apply-8.expect b/t/t4100/t-apply-8.expect
index eef7f2e..55a55c3 100644
--- a/t/t4100/t-apply-8.expect
+++ b/t/t4100/t-apply-8.expect
@@ -1,2 +1,2 @@
  t/t4100-apply-stat.sh |    2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/t/t4100/t-apply-9.expect b/t/t4100/t-apply-9.expect
index eef7f2e..55a55c3 100644
--- a/t/t4100/t-apply-9.expect
+++ b/t/t4100/t-apply-9.expect
@@ -1,2 +1,2 @@
  t/t4100-apply-stat.sh |    2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/t/t5150-request-pull.sh b/t/t5150-request-pull.sh
index da25bc2..34c482f 100755
--- a/t/t5150-request-pull.sh
+++ b/t/t5150-request-pull.sh
@@ -95,7 +95,7 @@ test_expect_success 'setup: two scripts for reading pull requests' '
  b
  : diffstat
  n
- / [0-9]* files changed/ {
+ / [0-9]* files\? changed/ {
  a\\
  DIFFSTAT
  b
diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 61f36ba..5783ebf 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -57,7 +57,7 @@ Merge made by the 'octopus' strategy.
  c2.c |    1 +
  c3.c |    1 +
  c4.c |    1 +
- 3 files changed, 3 insertions(+), 0 deletions(-)
+ 3 files changed, 3 insertions(+)
  create mode 100644 c2.c
  create mode 100644 c3.c
  create mode 100644 c4.c
@@ -74,7 +74,7 @@ Already up-to-date with c4
 Trying simple merge with c5
 Merge made by the 'octopus' strategy.
  c5.c |    1 +
- 1 files changed, 1 insertions(+), 0 deletions(-)
+ 1 file changed, 1 insertion(+)
  create mode 100644 c5.c
 EOF
 
@@ -89,7 +89,7 @@ Trying simple merge with c2
 Merge made by the 'octopus' strategy.
  c1.c |    1 +
  c2.c |    1 +
- 2 files changed, 2 insertions(+), 0 deletions(-)
+ 2 files changed, 2 insertions(+)
  create mode 100644 c1.c
  create mode 100644 c2.c
 EOF
--
1.7.8.36.g69ee2

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2] Use correct grammar in diffstat summary line

Junio C Hamano
Nice.  Will queue with a minor update to the log message:

commit 3f29ab34372ee11946439da3bde307eb90ad9031
Author: Nguyễn Thái Ngọc Duy <[hidden email]>
Date:   Wed Feb 1 19:55:07 2012 +0700

    Use correct grammar in diffstat summary line
   
    "git diff --stat" and "git apply --stat" now learn to print the line
    "%d files changed, %d insertions(+), %d deletions(-)" in singular form
    whenever applicable. "0 insertions" and "0 deletions" are also omitted
    unless they are both zero.
   
    This matches how versions of "diffstat" that are not prehistoric produced
    their output, and also makes this line translatable.
   
    [jc: with help from Thomas Dickey in archaeology of "diffstat"]
   
    Signed-off-by: Nguyễn Thái Ngọc Duy <[hidden email]>
    Signed-off-by: Junio C Hamano <[hidden email]>

And also this bit on top:

diff --git a/diff.c b/diff.c
index 5c31b36..5f3ce97 100644
--- a/diff.c
+++ b/diff.c
@@ -1329,7 +1329,7 @@ int print_stat_summary(FILE *fp, int files, int insertions, int deletions)
 
  if (!files) {
  assert(insertions == 0 && deletions == 0);
- return fputs(_(" no changes\n"), fp);
+ return fputs(_(" 0 files changed\n"), fp);
  }
 
  strbuf_addf(&sb,
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2] Use correct grammar in diffstat summary line

Jonathan Nieder-2
In reply to this post by Duy Nguyen
(dropping Thomas from cc)
Nguyễn Thái Ngọc Duy wrote:

>  And this patch's diffstat looks just scary due to test suite's updates.

Not about this patch, but: let's see if we can chisel away at that.

Hidden below are also two minor bug reports about the patch.  See (*)
and (**) below.

> --- a/t/t0023-crlf-am.sh
> +++ b/t/t0023-crlf-am.sh
> @@ -12,7 +12,7 @@ Subject: test1
>  
>  ---
>   foo |    1 +
> - 1 files changed, 1 insertions(+), 0 deletions(-)
> + 1 file changed, 1 insertion(+)
>   create mode 100644 foo

This patchfile is sample input to "git am", and this patch hunk
changes it to match the modified format-patch output format.  But
don't we want "git am" to work with old patches, too?  So this hunk is
unnecessary.

[...]
> --- a/t/t1200-tutorial.sh
> +++ b/t/t1200-tutorial.sh
> @@ -156,7 +156,7 @@ Updating VARIABLE..VARIABLE
>  FASTFORWARD (no commit created; -m option ignored)
>   example |    1 +
>   hello   |    1 +
> - 2 files changed, 2 insertions(+), 0 deletions(-)
> + 2 files changed, 2 insertions(+)
>  EOF

Yes, this one's necessary.

(*) It's reminding us to update the gitcore-tutorial. :)

[...]

> --- a/t/t3300-funny-names.sh
> +++ b/t/t3300-funny-names.sh
> @@ -167,7 +167,7 @@ test_expect_success TABS_IN_FILENAMES 'git diff-tree delete with-funny' \
>  test_expect_success TABS_IN_FILENAMES 'setup expect' '
>  cat >expected <<\EOF
>   "tabs\t,\" (dq) and spaces"
> - 1 files changed, 0 insertions(+), 0 deletions(-)
> + 1 file changed, 0 insertions(+), 0 deletions(-)
>  EOF
>  '

I'm not sure why this and other tests in the same file use "git apply
--stat" to check their work.  The descriptions refer to diff-tree but
the tests themselves use diff-index | apply --stat.  Puzzling.

[...]

> --- a/t/t3508-cherry-pick-many-commits.sh
> +++ b/t/t3508-cherry-pick-many-commits.sh
> @@ -38,13 +38,13 @@ test_expect_success 'cherry-pick first..fourth works' '
>   cat <<-\EOF >expected &&
>   [master OBJID] second
>   Author: A U Thor <[hidden email]>
> - 1 files changed, 1 insertions(+), 0 deletions(-)
> + 1 file changed, 1 insertion(+)
>   [master OBJID] third
>   Author: A U Thor <[hidden email]>
> - 1 files changed, 1 insertions(+), 0 deletions(-)
> + 1 file changed, 1 insertion(+)
>   [master OBJID] fourth
>   Author: A U Thor <[hidden email]>
> - 1 files changed, 1 insertions(+), 0 deletions(-)
> + 1 file changed, 1 insertion(+)
>   EOF

Probably should be split out as a separate test so cherry-pick's
behavior and progress reporting can be tested separately.  Aside from
that detail, makes sense.

[...]
> --- a/t/t3903-stash.sh
> +++ b/t/t3903-stash.sh
> @@ -444,7 +444,7 @@ test_expect_success 'stash show - stashes on stack, stash-like argument' '
>   git reset --hard &&
>   cat >expected <<-EOF &&
>   file |    1 +
> - 1 files changed, 1 insertions(+), 0 deletions(-)
> + 1 file changed, 1 insertion(+)

Hm.  "git stash show" defaults to --stat, but these tests are not
really about that.  Maybe there should be one test that checks that
the default uses --stat and others could use --numstat or similar?

This will be a problem with GETTEXT_POISON (except your patch bypasses
poison so it got missed --- will send a relevant fix as a reply).

[...]
> +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master
> +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side
> +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master
> +++ b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master
[...]
> +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..side
> +++ b/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master
> +++ b/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master
[...]

Testing the --stat option.  Can't really be avoided.  (Though maybe
some more modular tests for these combinations can be made some day.)

[...]
> --- a/t/t4014-format-patch.sh
> +++ b/t/t4014-format-patch.sh
> @@ -520,7 +520,7 @@ test_expect_success 'shortlog of cover-letter wraps overly-long onelines' '
>  cat > expect << EOF
>  ---
>   file |   16 ++++++++++++++++
> - 1 files changed, 16 insertions(+), 0 deletions(-)
> + 1 file changed, 16 insertions(+)

Not relevant to the detail being tested, should probably be fuzzed
out.

[...]

> --- a/t/t4030-diff-textconv.sh
> +++ b/t/t4030-diff-textconv.sh
> @@ -86,7 +86,7 @@ test_expect_success 'status -v produces text' '
>  
>  cat >expect.stat <<'EOF'
>   file |  Bin 2 -> 4 bytes
> - 1 files changed, 0 insertions(+), 0 deletions(-)
> + 1 file changed, 0 insertions(+), 0 deletions(-)
>  EOF
>  test_expect_success 'diffstat does not run textconv' '
>   echo file diff=fail >.gitattributes &&

Testing diffstat.  Would be nice to have an accompanying test of
numstat.

[...]
> --- a/t/t4045-diff-relative.sh
> +++ b/t/t4045-diff-relative.sh
> @@ -33,7 +33,7 @@ check_stat() {
>  expect=$1; shift
>  cat >expected <<EOF
>   $expect |    1 +
> - 1 files changed, 1 insertions(+), 0 deletions(-)
> + 1 file changed, 1 insertion(+)
>  EOF

Not the detail being tested, so technically it would be nicer to
fuzz the last line out.

[...]

> --- a/t/t4049-diff-stat-count.sh
> +++ b/t/t4049-diff-stat-count.sh
> @@ -16,7 +16,7 @@ test_expect_success setup '
>   cat >expect <<-\EOF
>   a |    1 +
>   b |    1 +
> - 2 files changed, 2 insertions(+), 0 deletions(-)
> + 2 files changed, 2 insertions(+)
>   EOF
>   git diff --stat --stat-count=2 >actual &&
>   test_cmp expect actual

Testing diffstat.  Looks sane.

[...]
> +++ b/t/t4100/t-apply-8.expect
> @@ -1,2 +1,2 @@
>   t/t4100-apply-stat.sh |    2 +-
> - 1 files changed, 1 insertions(+), 1 deletions(-)
> + 1 file changed, 1 insertion(+), 1 deletion(-)
[...]
> +++ b/t/t4100/t-apply-9.expect
> @@ -1,2 +1,2 @@
>   t/t4100-apply-stat.sh |    2 +-
> - 1 files changed, 1 insertions(+), 1 deletions(-)
> + 1 file changed, 1 insertion(+), 1 deletion(-)

Testing apply --stat.  Tests of apply --numstat would be more
interesting, but then we'd still need some tests like these to make
sure --stat is consistent with it, so it still seems sane.

> --- a/t/t5150-request-pull.sh
> +++ b/t/t5150-request-pull.sh
> @@ -95,7 +95,7 @@ test_expect_success 'setup: two scripts for reading pull requests' '
>   b
>   : diffstat
>   n
> - / [0-9]* files changed/ {
> + / [0-9]* files\? changed/ {

Mimicking a human.

(**) Should probably use "*" instead of \? --- \? is a GNU extension,
not a BRE.

[...]

> +++ b/t/t7602-merge-octopus-many.sh
> @@ -57,7 +57,7 @@ Merge made by the 'octopus' strategy.
>   c2.c |    1 +
>   c3.c |    1 +
>   c4.c |    1 +
> - 3 files changed, 3 insertions(+), 0 deletions(-)
> + 3 files changed, 3 insertions(+)
>   create mode 100644 c2.c
>   create mode 100644 c3.c
>   create mode 100644 c4.c

Test is about the "Trying simple merge with" lines, not the final
diffstat summary.  Should probably be fuzzed out.

Thanks, that was interesting.

Jonathan
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[RFC/PATCH] i18n: do not define gettext/ngettext in NO_GETTEXT case

Jonathan Nieder-2
gettext.h is responsible for defining the _ and  Q_ helpers which are
either simple stubs (in the NO_GETTEXT case) or synonyms for the
libintl functions used to translated git output.  As an implementation
artifact, ever since the !NO_GETTEXT case was implemented
(v1.7.9-rc0~42^2, 2011-11-18), they have also defined gettext and
ngettext macros in the NO_GETTEXT case:

        #ifdef gettext
        # undef gettext
        #endif
        #define gettext(x) (x)

New readers looking at this header might be tempted to use gettext and
ngettext directly, since they are defined in all cases, instead of
using the _ and Q_ wrappers which look like shortcuts.

However gettext and ngettext bypass the GETTEXT_POISON feature.  So
any code using them directly will produce perfectly sensible English
output when run in the test suite with GETTEXT_POISON set, instead of
the poison markers that normally would make it easy to catch output
intended for machines that has been marked for translation by mistake.

Avoid the temptation by _not_ providing fallback definitions for
gettext and ngettext ourselves.  This way, the header is less
misleading and code that uses gettext et al directly will fail to
compile when NO_GETTEXT is set so we can catch it early.

We also take the opportunity to avoid a little ifdef-ery by splitting
the NO_GETTEXT and !NO_GETTEXT implementations into different headers.
Unfortunately this involves some duplication of code.

Signed-off-by: Jonathan Nieder <[hidden email]>
---
Jonathan Nieder wrote:

> This will be a problem with GETTEXT_POISON (except your patch bypasses
> poison so it got missed --- will send a relevant fix as a reply).

Here's a rough patch to make that kind of thing easier to catch.  It
might make more sense to do

        #ifdef NO_GETTEXT
        #define git_gettext_(x) (x)
        #define git_ngettext_(msgid, plu, n) ...
        #else
        #define git_gettext_(x) gettext(x)
        #define git_ngettext_(msgid, plu, n) ngettext(msgid, plu, n)
        #endif

        static inline const char *_(const char *msgid)
        {
                return poisoning() ? "poison!" : git_gettext_(msgid);
        }
        ...

but I didn't think of it until I had already written this patch.
Anyway, this way you get both approaches for easy comparison. ;-)

 Makefile          |    3 +++
 gettext-libintl.h |   26 ++++++++++++++++++++++++++
 gettext-noop.h    |   30 ++++++++++++++++++++++++++++++
 gettext.h         |   53 +++--------------------------------------------------
 git-compat-util.h |    6 ++++++
 5 files changed, 68 insertions(+), 50 deletions(-)
 create mode 100644 gettext-libintl.h
 create mode 100644 gettext-noop.h

diff --git a/Makefile b/Makefile
index c457c34f..83e8c0f1 100644
--- a/Makefile
+++ b/Makefile
@@ -1525,6 +1525,9 @@ endif
 ifdef NO_GETTEXT
  BASIC_CFLAGS += -DNO_GETTEXT
  USE_GETTEXT_SCHEME ?= fallthrough
+ LIB_H += gettext-noop.h
+else
+ LIB_H += gettext-libintl.h
 endif
 ifdef NO_STRCASESTR
  COMPAT_CFLAGS += -DNO_STRCASESTR
diff --git a/gettext-libintl.h b/gettext-libintl.h
new file mode 100644
index 00000000..c9199703
--- /dev/null
+++ b/gettext-libintl.h
@@ -0,0 +1,26 @@
+#ifndef GETTEXT_LIBINTL_H
+#define GETTEXT_LIBINTL_H
+
+#include <libintl.h>
+
+#define FORMAT_PRESERVING(n) __attribute__((format_arg(n)))
+
+extern void git_setup_gettext(void);
+
+static inline FORMAT_PRESERVING(1) const char *_(const char *msgid)
+{
+ return use_gettext_poison() ? "# GETTEXT POISON #" : gettext(msgid);
+}
+
+static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2)
+const char *Q_(const char *msgid, const char *plu, unsigned long n)
+{
+ if (use_gettext_poison())
+ return "# GETTEXT POISON #";
+ return ngettext(msgid, plu, n);
+}
+
+/* Mark msgid for translation but do not translate it. */
+#define N_(msgid) msgid
+
+#endif
diff --git a/gettext-noop.h b/gettext-noop.h
new file mode 100644
index 00000000..28843a61
--- /dev/null
+++ b/gettext-noop.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2010-2011 Ævar Arnfjörð Bjarmason
+ *
+ * This is a skeleton no-op implementation of gettext for Git.
+ */
+
+#ifndef GETTEXT_NOOP_H
+#define GETTEXT_NOOP_H
+
+#define FORMAT_PRESERVING(n) __attribute__((format_arg(n)))
+
+static inline void git_setup_gettext(void) { }
+
+static inline FORMAT_PRESERVING(1) const char *_(const char *msgid)
+{
+ return use_gettext_poison() ? "# GETTEXT POISON #" : msgid;
+}
+
+static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2)
+const char *Q_(const char *msgid, const char *plu, unsigned long n)
+{
+ if (use_gettext_poison())
+ return "# GETTEXT POISON #";
+ return n == 1 ? msgid : plu;
+}
+
+/* Mark msgid for translation but do not translate it. */
+#define N_(msgid) msgid
+
+#endif
diff --git a/gettext.h b/gettext.h
index 57ba8bb0..9bc67243 100644
--- a/gettext.h
+++ b/gettext.h
@@ -1,11 +1,3 @@
-/*
- * Copyright (c) 2010-2011 Ævar Arnfjörð Bjarmason
- *
- * This is a skeleton no-op implementation of gettext for Git.
- * You can replace it with something that uses libintl.h and wraps
- * gettext() to try out the translations.
- */
-
 #ifndef GETTEXT_H
 #define GETTEXT_H
 
@@ -13,49 +5,10 @@
 #error "namespace conflict: '_' or 'Q_' is pre-defined?"
 #endif
 
-#ifndef NO_GETTEXT
-# include <libintl.h>
+#ifdef NO_GETTEXT
+#include "gettext-noop.h"
 #else
-# ifdef gettext
-# undef gettext
-# endif
-# define gettext(s) (s)
-# ifdef ngettext
-# undef ngettext
-# endif
-# define ngettext(s, p, n) ((n == 1) ? (s) : (p))
+#include "gettext-libintl.h"
 #endif
 
-#define FORMAT_PRESERVING(n) __attribute__((format_arg(n)))
-
-#ifndef NO_GETTEXT
-extern void git_setup_gettext(void);
-#else
-static inline void git_setup_gettext(void)
-{
-}
-#endif
-
-#ifdef GETTEXT_POISON
-extern int use_gettext_poison(void);
-#else
-#define use_gettext_poison() 0
-#endif
-
-static inline FORMAT_PRESERVING(1) const char *_(const char *msgid)
-{
- return use_gettext_poison() ? "# GETTEXT POISON #" : gettext(msgid);
-}
-
-static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2)
-const char *Q_(const char *msgid, const char *plu, unsigned long n)
-{
- if (use_gettext_poison())
- return "# GETTEXT POISON #";
- return ngettext(msgid, plu, n);
-}
-
-/* Mark msgid for translation but do not translate it. */
-#define N_(msgid) msgid
-
 #endif
diff --git a/git-compat-util.h b/git-compat-util.h
index 8f3972cd..ca4a4f19 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -236,6 +236,12 @@ extern char *gitbasename(char *);
 #endif
 #endif
 
+#ifdef GETTEXT_POISON
+extern int use_gettext_poison(void);
+#else
+#define use_gettext_poison() 0
+#endif
+
 #include "compat/bswap.h"
 
 /* General helper functions */
--
1.7.9

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2] Use correct grammar in diffstat summary line

Jonathan Nieder-2
In reply to this post by Jonathan Nieder-2
Jonathan Nieder wrote:

> [...]
>> --- a/t/t1200-tutorial.sh
>> +++ b/t/t1200-tutorial.sh
>> @@ -156,7 +156,7 @@ Updating VARIABLE..VARIABLE
>>  FASTFORWARD (no commit created; -m option ignored)
>>   example |    1 +
>>   hello   |    1 +
>> - 2 files changed, 2 insertions(+), 0 deletions(-)
>> + 2 files changed, 2 insertions(+)
>>  EOF
>
> Yes, this one's necessary.
>
> (*) It's reminding us to update the gitcore-tutorial. :)

Patch for squashing (untested) below.

Signed-off-by: Jonathan Nieder <[hidden email]>
---
 Documentation/gitcore-tutorial.txt |    2 +-
 Documentation/gittutorial-2.txt    |    4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/gitcore-tutorial.txt b/Documentation/gitcore-tutorial.txt
index c27d086f..fb0d5692 100644
--- a/Documentation/gitcore-tutorial.txt
+++ b/Documentation/gitcore-tutorial.txt
@@ -1004,7 +1004,7 @@ Updating from ae3a2da... to a80b4aa....
 Fast-forward (no commit created; -m option ignored)
  example |    1 +
  hello   |    1 +
- 2 files changed, 2 insertions(+), 0 deletions(-)
+ 2 files changed, 2 insertions(+)
 ----------------
 
 Because your branch did not contain anything more than what had
diff --git a/Documentation/gittutorial-2.txt b/Documentation/gittutorial-2.txt
index f1e4422a..e00a4d21 100644
--- a/Documentation/gittutorial-2.txt
+++ b/Documentation/gittutorial-2.txt
@@ -34,12 +34,12 @@ $ echo 'hello world' > file.txt
 $ git add .
 $ git commit -a -m "initial commit"
 [master (root-commit) 54196cc] initial commit
- 1 files changed, 1 insertions(+), 0 deletions(-)
+ 1 file changed, 1 insertion(+)
  create mode 100644 file.txt
 $ echo 'hello world!' >file.txt
 $ git commit -a -m "add emphasis"
 [master c4d59f3] add emphasis
- 1 files changed, 1 insertions(+), 1 deletions(-)
+ 1 file changed, 1 insertion(+), 1 deletion(-)
 ------------------------------------------------
 
 What are the 7 digits of hex that git responded to the commit with?
--
1.7.9

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2] Use correct grammar in diffstat summary line

Jonathan Nieder-2
In reply to this post by Jonathan Nieder-2
Jonathan Nieder wrote:
> Nguyễn Thái Ngọc Duy wrote:

>> --- a/t/t5150-request-pull.sh
>> +++ b/t/t5150-request-pull.sh
>> @@ -95,7 +95,7 @@ test_expect_success 'setup: two scripts for reading pull requests' '
>>   b
>>   : diffstat
>>   n
>> - / [0-9]* files changed/ {
>> + / [0-9]* files\? changed/ {
>
> Mimicking a human.
>
> (**) Should probably use "*" instead of \? --- \? is a GNU extension,
> not a BRE.

... and here's a patch making that change for convenience (also untested).
---
 t/t5150-request-pull.sh |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/t/t5150-request-pull.sh b/t/t5150-request-pull.sh
index 34c482f1..ec5f7368 100755
--- a/t/t5150-request-pull.sh
+++ b/t/t5150-request-pull.sh
@@ -95,7 +95,7 @@ test_expect_success 'setup: two scripts for reading pull requests' '
  b
  : diffstat
  n
- / [0-9]* files\? changed/ {
+ / [0-9]* files* changed/ {
  a\\
  DIFFSTAT
  b
--
1.7.9

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2] Use correct grammar in diffstat summary line

Duy Nguyen
In reply to this post by Junio C Hamano
On Wed, Feb 01, 2012 at 01:26:43PM -0800, Junio C Hamano wrote:
> Nice.  Will queue

Please also squash this in (resend looks ugly and it's hard to point
out changes). It makes the code look less ugly, use Q_() for gettext
poisoning and revert am input text back as Jonathan suggested.

I take it --summary is un-i18n-able, should we introduce.. umm..
--nice-summary or something that can support i18n?

-- 8< --
diff --git a/diff.c b/diff.c
index 5f3ce97..07c94f2 100644
--- a/diff.c
+++ b/diff.c
@@ -1325,6 +1325,7 @@ static void fill_print_name(struct diffstat_file *file)
 int print_stat_summary(FILE *fp, int files, int insertions, int deletions)
 {
  struct strbuf sb = STRBUF_INIT;
+ const char *fmt;
  int ret;
 
  if (!files) {
@@ -1332,10 +1333,8 @@ int print_stat_summary(FILE *fp, int files, int insertions, int deletions)
  return fputs(_(" 0 files changed\n"), fp);
  }
 
- strbuf_addf(&sb,
-    ngettext(" %d file changed", " %d files changed",
-     files),
-    files);
+ fmt = Q_(" %d file changed", " %d files changed", files);
+ strbuf_addf(&sb, fmt, files);
 
  /*
  * For binary diff, the caller may want to print "x files
@@ -1346,25 +1345,17 @@ int print_stat_summary(FILE *fp, int files, int insertions, int deletions)
  * but nothing about added/removed lines? Is this a bug in Git?").
  */
  if (insertions || deletions == 0) {
- strbuf_addf(&sb,
-    /*
-     * TRANSLATORS: "+" in (+) is a line addition marker;
-     * do not translate it.
-     */
-    ngettext(", %d insertion(+)", ", %d insertions(+)",
-     insertions),
-    insertions);
+ /* TRANSLATORS: "+" in (+) is a line addition marker,
+   do not translate it */
+ fmt = Q_(", %d insertion(+)", ", %d insertions(+)", insertions);
+ strbuf_addf(&sb, fmt, insertions);
  }
 
  if (deletions || insertions == 0) {
- strbuf_addf(&sb,
-    /*
-     * TRANSLATORS: "-" in (-) is a line removal marker;
-     * do not translate it.
-     */
-    ngettext(", %d deletion(-)", ", %d deletions(-)",
-     deletions),
-    deletions);
+ /* TRANSLATORS: "-" in (-) is a line removal marker,
+   do not translate it */
+ fmt = Q_(", %d deletion(-)", ", %d deletions(-)", deletions);
+ strbuf_addf(&sb, fmt, deletions);
  }
  strbuf_addch(&sb, '\n');
  ret = fputs(sb.buf, fp);
diff --git a/t/t0023-crlf-am.sh b/t/t0023-crlf-am.sh
index 18fe27b..12a3d78 100755
--- a/t/t0023-crlf-am.sh
+++ b/t/t0023-crlf-am.sh
@@ -12,7 +12,7 @@ Subject: test1
 
 ---
  foo |    1 +
- 1 file changed, 1 insertion(+)
+ 1 files changed, 1 insertions(+)
  create mode 100644 foo
 
 diff --git a/foo b/foo
-- 8< --

--
Duy
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2] Use correct grammar in diffstat summary line

Junio C Hamano
Nguyen Thai Ngoc Duy <[hidden email]> writes:

> On Wed, Feb 01, 2012 at 01:26:43PM -0800, Junio C Hamano wrote:
>> Nice.  Will queue
>
> Please also squash this in (resend looks ugly and it's hard to point
> out changes). It makes the code look less ugly, use Q_() for gettext
> poisoning and revert am input text back as Jonathan suggested.
>
> I take it --summary is un-i18n-able,...

... because?
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2] Use correct grammar in diffstat summary line

Duy Nguyen
On Fri, Feb 3, 2012 at 1:24 AM, Junio C Hamano <[hidden email]> wrote:

> Nguyen Thai Ngoc Duy <[hidden email]> writes:
>
>> On Wed, Feb 01, 2012 at 01:26:43PM -0800, Junio C Hamano wrote:
>>> Nice.  Will queue
>>
>> Please also squash this in (resend looks ugly and it's hard to point
>> out changes). It makes the code look less ugly, use Q_() for gettext
>> poisoning and revert am input text back as Jonathan suggested.
>>
>> I take it --summary is un-i18n-able,...
>
> ... because?

.. of scripts? We have --numstat for scripts, but I see no alternative
to --summary. Does anybody parse --summary output?
--
Duy
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2] Use correct grammar in diffstat summary line

Junio C Hamano
Nguyen Thai Ngoc Duy <[hidden email]> writes:

> On Fri, Feb 3, 2012 at 1:24 AM, Junio C Hamano <[hidden email]> wrote:
>> Nguyen Thai Ngoc Duy <[hidden email]> writes:
>>
>>> I take it --summary is un-i18n-able,...
>>
>> ... because?
>
> .. of scripts? We have --numstat for scripts, but I see no alternative
> to --summary.

Ahh, you meant that --summary.  I somehow mixed that up with the "N files
added, M insersion(s),...".

I've always thought that "--summary" lines belong to the same category as
"new file mode M", "rename from A" and "similarity X%" that come at the
beginning of individual patches, and it probably would not make sense to
localize them.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2] Use correct grammar in diffstat summary line

Jeff King
In reply to this post by Duy Nguyen
On Fri, Feb 03, 2012 at 08:11:23AM +0700, Nguyen Thai Ngoc Duy wrote:

> >> I take it --summary is un-i18n-able,...
> >
> > ... because?
>
> .. of scripts? We have --numstat for scripts, but I see no alternative
> to --summary. Does anybody parse --summary output?

I would think it is spelled "--raw".

-Peff
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
12
Loading...