Git development
 help / color / mirror / Atom feed
* Re: git-subtree Ready #2
From: David A. Greene @ 2012-02-21  5:37 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git, Avery Pennarun
In-Reply-To: <7vd399jdwc.fsf@alter.siamese.dyndns.org>

Junio C Hamano <gitster@pobox.com> writes:

> Jeff King <peff@peff.net> writes:
>
> It sounds like the simplest and cleanest would be to treat it as if its
> current version came as a patch submission, cook it just like any other
> topic in 'pu' down to 'next' down to eventually 'master', with the usual
> review cycle of pointing out what is wrong and needs fixing followed by a
> series of re-rolls.

Ok, but we will preserve the history via the subtree merge, yes?

> The total amount of change does not look too bad, either:

Yes, it's a fairly small tool.

> It does look like it needs to start its life in contrib/ if we were to put
> this in git.git. 

That sounds good to me.  It should get a good shakedown before graduating.

> I haven't looked at the script fully, but it has an issue from its
> first line, which is marked with "#!/bin/bash".  It is unclear if it
> is infested by bash-isms beyond repair (in which case "#!/bin/bash" is
> fine), or it was written portably but was marked with "#!/bin/bash"
> just by inertia.  A patch that corresponds to the above diffstat
> immediately shows many style issues including trailing eye-sore
> whitespaces.

Ok.

> It seems that it is even capable of installing from contrib/subtree, so
> keeping it in contrib/ while many issues it may have gets fixed would not
> hurt the original goal of giving the script more visibility.

Right, I intentially designed it that way.

> The change to t/test-lib.sh should be made independent of this topic, I
> would think.

Ok, I'll propose those changes separately.  They are a prerequisite for
a git-subtree that is easily testable while in contrib.

> ----------------------------------------------------------------
> diff --git a/t/test-lib.sh b/t/test-lib.sh
> index e28d5fd..c877a91 100644
> --- a/t/test-lib.sh
> +++ b/t/test-lib.sh
> @@ -55,6 +55,7 @@ unset $(perl -e '
>  		.*_TEST
>  		PROVE
>  		VALGRIND
> +                BUILD_DIR
>  	));
>  	my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
>  	print join("\n", @vars);
> @@ -924,7 +925,15 @@ then
>  	# itself.
>  	TEST_DIRECTORY=$(pwd)
>  fi
> -GIT_BUILD_DIR="$TEST_DIRECTORY"/..
> +
> +if test -z "$GIT_BUILD_DIR"
> +then
> +    echo Here
> +	# We allow tests to override this, in case they want to run tests
> +	# outside of t/, e.g. for running tests on the test library
> +	# itself.
> +        GIT_BUILD_DIR="$TEST_DIRECTORY"/..
> +fi
>  
>  if test -n "$valgrind"
>  then
> ----------------------------------------------------------------
> This change deserves its own justification.

I'll put a patch together with a more extensive explanation.  Basically,
tests run outside of the top-level t/ directory don't work because there
are all sort of assumptions in test-lib.sh about where they live.  There
are comments in test-lib.sh indicating that it should support tests in
other directories but I could not make it work out of the box.

> After looking at the history of subtree branch there, however, I agree
> that it would not help anybody to have its history in my tree with log
> messages like these (excerpt from shortlog output):
>
>       update todo
>       Some todo items reported by pmccurdy
>       todo
>       Docs: when pushing to github, the repo path needs to end in .git
>       todo
>       todo^
>       todo
>       todo: idea for a 'git subtree grafts' command

Ok, these are Avery's commits.  I don't know that I have enough context
to improve the logs but I will look throught revisions and try to figure
things out.  Avery, could you be of any help here?  It sounds like we
need more descriptive log messages.

                               -Dave

^ permalink raw reply

* Re: git-subtree Ready #2
From: David A. Greene @ 2012-02-21  5:31 UTC (permalink / raw)
  To: Jeff King; +Cc: git, Avery Pennarun
In-Reply-To: <20120220205346.GA6335@sigill.intra.peff.net>

Jeff King <peff@peff.net> writes:

> Of course there's no real reason we can't take it slow by putting it in
> contrib, and then graduating from there. It just seems like an
> unnecessary and complicated interim step. Either way, I do think it's
> worth saving the commit history by doing a real merge.

I have no problem starting off in contrib.  I was asking more about the
logistics of getting there.

> As a non-user, I am totally fine with it. I think the burden is not that
> high, and you have already promised to deal with ongoing maintenance
> issues.

Indeed, I'm more than happy to help with maintenance.  I have one or two
fixes/enhancements on my list, in fact.

                              -Dave

^ permalink raw reply

* Re: [PATCH] Ignore SIGPIPE when running a filter driver
From: Jonathan Nieder @ 2012-02-21  3:01 UTC (permalink / raw)
  To: Jehan Bing; +Cc: git, gitster, j.sixt, peff
In-Reply-To: <1329771217-9088-1-git-send-email-jehan@orb.com>

Hi,

Jehan Bing wrote:

> If a filter is not defined or if it fails, git behaves as if the filter
> is a no-op passthru. However, if the filter exits before reading all
> the content, and depending on the timing git, could be kill with
> SIGPIPE instead.
>
> Ignore SIGPIPE while processing the filter to detect when it exits
> early and fallback to using the unfiltered content.
>
> Signed-off-by: Jehan Bing <jehan@orb.com>

For the benefit of the uninitiated ("how would ignoring an error help
me detect an error?"): setting the SIGPIPE handler to SIG_IGN does not
actually ignore the broken pipe condition but causes it to be reported
as an I/O error, errno == EPIPE.  That means instead of being killed
by SIGPIPE, git gets to fall back to passthrough and report the
filter's mistake:

	error: cannot feed the input to external filter <foo>
	error: external filter <foo> failed

[...]
> +++ b/convert.c
[...]
> @@ -360,12 +361,16 @@ static int filter_buffer(int in, int out, void *data)
>  	if (start_command(&child_process))
>  		return error("cannot fork to run external filter %s", params->cmd);
>  
> +	sigchain_push(SIGPIPE, SIG_IGN);

Setting the signal disposition after launching the external filter
which would otherwise inherit it, so the filter does not have to cope
with unfamiliar SIGPIPE handling[*].  Phew.

> +
>  	write_err = (write_in_full(child_process.in, params->src, params->size) < 0);
>  	if (close(child_process.in))
>  		write_err = 1;
>  	if (write_err)
>  		error("cannot feed the input to external filter %s", params->cmd);
>  
> +	sigchain_pop(SIGPIPE);
> +

This happens in an async procedure.  SIGPIPE is ignored in the
following block in the other thread:

	if (strbuf_read(&nbuf, async.out, len) < 0) {
		error("read from external filter %s failed", cmd);
		ret = 0;
	}
	if (close(async.out)) {
		error("read from external filter %s failed", cmd);
		ret = 0;
	}
	if (finish_async(&async)) {

That implies a tiny behavior change: if there is an I/O error reading
from async.out at the right moment and stderr is going to a closed
pipe, inability to report the error can result in the error flag being
set on stderr instead of the process being killed.  I don't think
anyone will notice.

So at least on POSIX-y platforms, this patch looks good to me.  Thanks
for writing it.

Sincerely,
Jonathan

[*] See http://bugs.python.org/issue1652 for some stories about what
we are narrowly escaping here. :)

^ permalink raw reply

* [PATCH] contrib: added git-diffall
From: Tim Henigan @ 2012-02-21  0:59 UTC (permalink / raw)
  To: git, gitster; +Cc: tim.henigan

This script adds directory diff support to git.  It launches a single
instance of the user-configured external diff tool and performs a
directory diff between the specified revisions. The before/after files
are copied to a tmp directory to do this.  Either 'diff.tool' or
'merge.tool' must be set before running the script.

The existing 'git difftool' command already allows the user to view diffs
using an external tool.  However if multiple files have changed, a
separate instance of the tool is launched for each one.  This can be
tedious when many files are involved.

Signed-off-by: Tim Henigan <tim.henigan@gmail.com>
---

This script has been hosted on GitHub [1] since April 2010. Enough people
have found it useful that I hope it will be considered for inclusion in
the standard git install, either in contrib or as a new core command.

[1]: https://github.com/thenigan/git-diffall

 contrib/diffall/README      |   18 +++
 contrib/diffall/git-diffall |  275 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 293 insertions(+)
 create mode 100644 contrib/diffall/README
 create mode 100755 contrib/diffall/git-diffall

diff --git a/contrib/diffall/README b/contrib/diffall/README
new file mode 100644
index 0000000..12881d2
--- /dev/null
+++ b/contrib/diffall/README
@@ -0,0 +1,18 @@
+The git-diffall script provides a directory based diff mechanism
+for git.  The script relies on the diff.tool configuration option
+to determine what diff viewer is used.
+
+This script is compatible with all the forms used to specify a
+range of revisions to diff:
+
+  1. git diffall: shows diff between working tree and staged changes
+  2. git diffall --cached [<commit>]: shows diff between staged changes and HEAD (or other named commit)
+  3. git diffall <commit>: shows diff between working tree and named commit
+  4. git diffall <commit> <commit>: show diff between two named commits
+  5. git diffall <commit>..<commit>: same as above
+  6. git diffall <commit>...<commit>: show the changes on the branch containing and up to the second , starting at a common ancestor of both <commit>
+
+Note: all forms take an optional path limiter [--] [<path>*]
+
+This script is based on an example provided by Thomas Rast on the Git list [1]:
+[1] http://thread.gmane.org/gmane.comp.version-control.git/124807
diff --git a/contrib/diffall/git-diffall b/contrib/diffall/git-diffall
new file mode 100755
index 0000000..ef01eda
--- /dev/null
+++ b/contrib/diffall/git-diffall
@@ -0,0 +1,275 @@
+#!/bin/bash -e
+# Copyright 2010 - 2012, Tim Henigan <tim.henigan@gmail.com>
+#
+# Perform a directory diff between commits in the repository using
+# the external diff or merge tool specified in the user's config.
+
+USAGE='[--cached] [--copy-back] [-x|--extcmd=<command>] <commit>{0,2} -- <path>*
+
+    --cached     Compare to the index rather than the working tree.
+
+    --copy-back  Copy files back to the working tree when the diff
+                 tool exits (in case they were modified by the
+                 user).  This option is only valid if the diff
+                 compared with the working tree.
+
+    -x=<command>
+    --extcmd=<command>  Specify a custom command for viewing diffs.
+                 git-diffall ignores the configured defaults and
+                 runs $command $LOCAL $REMOTE when this option is
+                 specified. Additionally, $BASE is set in the
+                 environment.
+'
+
+SUBDIRECTORY_OK=1
+. "$(git --exec-path)/git-sh-setup"
+
+TOOL_MODE=diff
+. "$(git --exec-path)/git-mergetool--lib"
+
+merge_tool="$(get_merge_tool)"
+if test -z "$merge_tool"
+then
+	echo "Error: Either the 'diff.tool' or 'merge.tool' option must be set."
+	usage
+fi
+
+start_dir=$(pwd)
+
+# needed to access tar utility
+cdup=$(git rev-parse --show-cdup) &&
+cd "$cdup" || {
+	echo >&2 "Cannot chdir to $cdup, the toplevel of the working tree"
+	exit 1
+}
+
+# mktemp is not available on all platforms (missing from msysgit)
+# Use a hard-coded tmp dir if it is not available
+if test -z $(which mktemp 2>/dev/null)
+then
+	tmp=/tmp/git-diffall-tmp
+else
+	tmp="$(mktemp -d -t tmp.XXXXXX)"
+fi
+mkdir -p "$tmp"
+
+left=
+right=
+paths=
+path_sep=
+compare_staged=
+common_ancestor=
+left_dir=
+right_dir=
+diff_tool=
+copy_back=
+
+while test $# != 0
+do
+	case "$1" in
+	-h|--h|--he|--hel|--help)
+		usage
+		;;
+	--cached)
+		compare_staged=1
+		;;
+	--copy-back)
+		copy_back=1
+		;;
+	-x|--e|--ex|--ext|--extc|--extcm|--extcmd)
+		diff_tool=$2
+		shift
+		;;
+	--)
+		path_sep=1
+		;;
+	-*)
+		echo Invalid option: "$1"
+		usage
+		;;
+	*)
+		# could be commit, commit range or path limiter
+		case "$1" in
+		*...*)
+			left=${1%...*}
+			right=${1#*...}
+			common_ancestor=1
+			;;
+		*..*)
+			left=${1%..*}
+			right=${1#*..}
+			;;
+		*)
+			if test -n "$path_sep"
+			then
+				if test -z "$paths"
+				then
+					paths=$1
+				else
+					paths="$paths $1"
+				fi
+			elif test -z "$left"
+			then
+				left=$1
+			elif test -z "$right"
+			then
+				right=$1
+			else
+				if test -z "$paths"
+				then
+					paths=$1
+				else
+					paths="$paths $1"
+				fi
+			fi
+			;;
+		esac
+		;;
+	esac
+	shift
+done
+
+# Determine the set of files which changed
+if test -n "$left" && test -n "$right"
+then
+	left_dir="cmt-$(git rev-parse --short $left)"
+	right_dir="cmt-$(git rev-parse --short $right)"
+
+	if test -n "$compare_staged"
+	then
+		usage
+	elif test -n "$common_ancestor"
+	then
+		git diff --name-only "$left"..."$right" -- $paths > "$tmp"/filelist
+	else
+		git diff --name-only "$left" "$right" -- $paths > "$tmp"/filelist
+	fi
+elif test -n "$left"
+then
+	left_dir="cmt-$(git rev-parse --short $left)"
+
+	if test -n "$compare_staged"
+	then
+		right_dir="staged"
+		git diff --name-only --cached "$left" -- $paths > "$tmp"/filelist
+	else
+		right_dir="working_tree"
+		git diff --name-only "$left" -- $paths > "$tmp"/filelist
+	fi
+else
+	left_dir="HEAD"
+
+	if test -n "$compare_staged"
+	then
+		right_dir="staged"
+		git diff --name-only --cached -- $paths > "$tmp"/filelist
+	else
+		right_dir="working_tree"
+		git diff --name-only -- $paths > "$tmp"/filelist
+	fi
+fi
+
+# Exit immediately if there are no diffs
+if test ! -s "$tmp"/filelist
+then
+	exit 0
+fi
+
+if test -n "$copy_back" && test "$right_dir" != "working_tree"
+then
+	echo "--copy-back is only valid when diff includes the working tree."
+	exit 1
+fi
+
+# Create the named tmp directories that will hold the files to be compared
+mkdir -p "$tmp"/"$left_dir" "$tmp"/"$right_dir"
+
+# Populate the tmp/right_dir directory with the files to be compared
+if test -n "$right"
+then
+	while read name
+	do
+		ls_list=$(git ls-tree $right $name)
+		if test -n "$ls_list"
+	then
+			mkdir -p "$tmp"/"$right_dir"/"$(dirname "$name")"
+			git show "$right":"$name" > "$tmp"/"$right_dir"/"$name" || true
+		fi
+	done < "$tmp"/filelist
+elif test -n "$compare_staged"
+then
+	while read name
+	do
+		ls_list=$(git ls-files -- $name)
+		if test -n "$ls_list"
+	then
+			mkdir -p "$tmp"/"$right_dir"/"$(dirname "$name")"
+			git show :"$name" > "$tmp"/"$right_dir"/"$name"
+		fi
+	done < "$tmp"/filelist
+else
+	if test -n "$(which gnutar 2>/dev/null)"
+	then
+		gnutar --ignore-failed-read -c -T "$tmp"/filelist | (cd "$tmp"/"$right_dir" && gnutar -x)
+	else
+		tar --ignore-failed-read -c -T "$tmp"/filelist | (cd "$tmp"/"$right_dir" && tar -x)
+	fi
+fi
+
+# Populate the tmp/left_dir directory with the files to be compared
+while read name
+do
+	if test -n "$left"
+	then
+		ls_list=$(git ls-tree $left $name)
+		if test -n "$ls_list"
+		then
+			mkdir -p "$tmp"/"$left_dir"/"$(dirname "$name")"
+			git show "$left":"$name" > "$tmp"/"$left_dir"/"$name" || true
+		fi
+	else
+		if test -n "$compare_staged"
+		then
+			ls_list=$(git ls-tree HEAD $name)
+			if test -n "$ls_list"
+			then
+				mkdir -p "$tmp"/"$left_dir"/"$(dirname "$name")"
+				git show HEAD:"$name" > "$tmp"/"$left_dir"/"$name"
+				fi
+			else
+				mkdir -p "$tmp"/"$left_dir"/"$(dirname "$name")"
+				git show :"$name" > "$tmp"/"$left_dir"/"$name"
+		fi
+	fi
+done < "$tmp"/filelist
+
+cd "$tmp"
+LOCAL="$left_dir"
+REMOTE="$right_dir"
+
+if test -n "$diff_tool"
+then
+	export BASE
+	eval $diff_tool '"$LOCAL"' '"$REMOTE"'
+else
+	run_merge_tool "$merge_tool" false
+fi
+
+# This function is called on exit
+cleanup () {
+	cd "$start_dir"
+
+	# Copy files back to the working dir, if requested
+	if test -n "$copy_back" && test "$right_dir" = "working_tree"
+	then
+		git_top_dir=$(git rev-parse --show-toplevel)
+		find "$tmp/$right_dir" -type f|while read file; do
+			cp "$file" "$git_top_dir/${file#$tmp/$right_dir/}"
+		done
+	fi
+
+	# Remove the tmp directory
+	rm -rf "$tmp"
+}
+
+trap cleanup EXIT
-- 
1.7.9.GIT

^ permalink raw reply related

* Re: [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream
From: Johan Herland @ 2012-02-21  0:03 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, jnareb, philipoakley
In-Reply-To: <7vobstjfcs.fsf@alter.siamese.dyndns.org>

On Mon, Feb 20, 2012 at 23:43, Junio C Hamano <gitster@pobox.com> wrote:
> Johan Herland <johan@herland.net> writes:
>> Teach the pre-rebase sample hook to refuse rewriting commits on a branch
>> that are present in that branch's @{upstream}. This is to prevent users
>> from rewriting commits that have already been published.
>
> If the user has configured an option to always create @{u} when creating a
> branch from somewhere else, transplanting $n good commits from his master
> that is forked from the shared master onto his maint would be done like
> this:
>
>        $ git checkout -b copy master
>        $ git rebase -i --onto maint HEAD~$n
>
> If these good commits have been published to 'master', because the
> upstream of 'copy' is set to the local 'master', would the new mechanism
> hinder this attempt to backport good fixes?  Perhaps it is safer to
> trigger only when @{u} exists and it is not local?

Ah, you're talking about setting branch.autosetupmerge = always. I
didn't know about that until I looked it up, just now. My first
impression is "who would want to use that?", but since it's there, we
should not break it. So, yes, we should probably apply the check when
@{u} exists, and refers to a remote-tracking branch. (One could argue
that this is also unsafe, since the current repo is a perfectly valid
remote, but if you do that, I'd be inclined to let you shoot yourself
in the foot.)

Also, if this check becomes part of core git, we obviously want some
config option to en/disable it. Preferably at multiple levels, as
discussed earlier in this thread:

  core.rewriteUpstream = refuse/false, warn, allow/true
(en/disables the check for the entire repo, but may be overridden by:)

  remote.<name>.rewriteUpstream = refuse/false, warn, allow/true
(en/disables the check for branches whose upstream is the given
remote, but may be overridden by:)

  branch.<name>.rewriteUpstream = refuse/false, warn, allow/true
(en/disables the check for the given local branch)

This allows fine-grained control of which branches/remotes you
consider 'public', and which are ok to rewrite.

> But because you wanted to discuss more about the issues than the
> implementation, let me think aloud a bit, reviewing what I usually do.
>
> I keep things simpler by sticking to a very simple rule. I allow myself to
> rebase only what is not yet in 'next', so the logic becomes a simple "am I
> creating a new commit based on what is already in 'next'?"
>
> During the course of integration testing with 'next', however, I often
> find a topic or two that I have merged to it is less than ideal, and of
> course, the whole point of doing integration testing with 'next' is to
> find such problematic topics before pushing 'next' out.  I rewind 'next',
> rebuild the problematic topics, and then rebuild 'next', and all of these
> happen before 'next' is pushed out.  The step that rewinds 'next' that
> acquired problematic versions of the topics makes the topics eligible for
> rebase.
>
> That would mean that a configuration variable "rebase.bottomLimit = next"
> is sufficient to implement such a check for me.  No per-branch bottom is
> needed, because everything is merged to 'next' and tested to see if they
> do not need further rebases for fixing them up before they are published.

What  you are describing here may be a common workflow, but
"rebase.bottomLimit" is still very specific to that kind of workflow.
What I'm after is a much more workflow-agnostic concept of:

  "If I have pushed something, I should probably not rebase it"

I believe this rule is sufficiently common in most workflows to
warrant the addition of this safety-check to Git. (And making the
safety-check configurable caters to those that don't need/want it.)

> Perhaps "I mistakenly rebased something that I have already published" is
> a mere symptom a bigger problem.  The issue may not be that we do not give
> them a good tool to help them to be more careful with less effort on their
> part before they rebase.  It may instead be that it is too easy to publish
> branches that are not ready to be pushed out, and that is the real cause
> of the "I realized I need to fix the topic and I fixed it, but I did not
> realize that it was too late and I shouldn't have rebased" problem.
>
> I wonder if it would be a more direct solution to the issue you are
> raising to give them a good tool to help them to be more careful with less
> effort on their part before they publish (not before they rebase).

Yes, in many cases, the user will probably agree that the rewrite
should ideally have happened _before_ the branch was first published.
However, I'm not sure how we can help the user _not_ publish the
branch until it's ready. We could throw in a warning (or even a stupid
"Are  you really sure you want to publish?") before pushing a branch,
but I don't think it would help at all.

I think the following decribes what often happens for many users:

 1. User A pushes the branch to a public repo.
 2. User B points out a simple mistake in the branch.
 3. User A makes a fix
 4. User A squashes the fix into the (already-published) history.
 5. User A attempts to push the "fixed" history (but is rejected by
the public repo because of non-fast-forward).

At this point, the damage is already done, since often neither of the
following alternatives are desirable:

 6a. (safe) User A realizes the error and undoes the history-rewrite
(this is not easy for novice users), leaving the fix on top of the
already-published history, and re-pushes a fast-forwarding history.
OR
 6b. (dangerous) User A reattempts the push with --force. User B (and
user C, D, ...) is left to clean up the mess.

You could say that User A should be more careful and push to a "less
public" repo in step #1 (thus allowing the fix to be squashed before
pushing to a "more public" repo in step #5), but how "public" is
"public" enough to have someone point out the bug, but still
"unpublic" enough to allow rebase?

In general, I really cannot see any opportunity before step #4 where
we can stop (or warn) the user from what is about to happen. And I
think that refusing rewrites of commits that are already present in
the @{upstream} remote-tracking branch is good enough to help most
users avoid steps #4 through #6 (in a push-based workflow[1]). In
fact, from a pedagogical POV, I think step #4 is probably the best
spot for novice users to learn exactly the distinction between
acceptable and unacceptable history rewrites (instead of having it
explained to them as a consequence of the step #5).


Thanks for your insight,

...Johan


[1]: For non-push-based workflows (such as send-email, sharing
bundles, pulls from local repo, etc.) we will need other methods for
determining which commits have been published. This have been
discussed earlier in the thread, but is outside the scope of what I
want to accomplish for now.

-- 
Johan Herland, <johan@herland.net>
www.herland.net

^ permalink raw reply

* Re: [PATCH 0/8 v6] diff --stat: use the full terminal width
From: Zbigniew Jędrzejewski-Szmek @ 2012-02-21  0:26 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Michael J Gruber, pclouds, j.sixt
In-Reply-To: <7v4nuljcnk.fsf@alter.siamese.dyndns.org>

On 02/21/2012 12:41 AM, Junio C Hamano wrote:
> Zbigniew Jędrzejewski-Szmek<zbyszek@in.waw.pl>  writes:
>
>> JC:
>>> Perhaps the maximum for garph_width should be raised to something like
>>> "min(80, stat_width) - name_width"?
>> I think that a graph like
>> a | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>> b |    1 -
>> is not very readable. I like the consistency forced by the 40-column limit.
>> But I guess that this is very subjective.
>
> The above makes it very obvious that there is a huge amount of change made
> to 'a' and a bit of deletion to 'b', compared to a mini-graph that is
> truncated to half the screen width.
Yes. But the same graph with 40 columns tells me exactly the same thing.
OTOH, if the filenames+graph fill the whole 80 columns, everything is 
nicely aligned wrt. to text above and below. Maybe it should be 
configurable after all?

> Besides, the above is what you would get without your patch on 80-column
> terminal, no?
Yes.

Zbyszek

^ permalink raw reply

* [ANNOUNCE] git-link -- builds repository browser links
From: Georgi Valkov @ 2012-02-21  0:06 UTC (permalink / raw)
  To: git

Hi all,

If you find yourselves sending out a ton of gitweb, cgit or github links 
every day, git-link is a sub-command that can speed things up for you by 
eliminating pointy-clicky time that you would spend in a browser.

Example:
 > $ git config --add link.url http://git.kernel.org/?p=git/git.git
 > $ git config --add link.browser gitweb

 > $ git link v1.7.9~^{tree}
 > 
http://git.kernel.org/?p=git/git.git;a=tree;h=903db0d86a809b1f84415654369a3cf6dff5f4d5

 > $ git link --clipboard fsck.c
 > 
http://git.kernel.org/?p=git/git.git;a=blob;h=6c855f84f01c19678399d85181da1094bd61b371;f=fsck.c

Links:
  - https://github.com/gvalkov/git-link
  - http://pypi.python.org/pypi/gitlink

Best,
G.

^ permalink raw reply

* Re: [PATCH 0/8 v6] diff --stat: use the full terminal width
From: Junio C Hamano @ 2012-02-20 23:41 UTC (permalink / raw)
  To: Zbigniew Jędrzejewski-Szmek; +Cc: git, Michael J Gruber, pclouds, j.sixt
In-Reply-To: <1329775034-21551-1-git-send-email-zbyszek@in.waw.pl>

Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> writes:

> JC:
>> Perhaps the maximum for garph_width should be raised to something like
>> "min(80, stat_width) - name_width"?
> I think that a graph like
> a | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> b |    1 -
> is not very readable. I like the consistency forced by the 40-column limit.
> But I guess that this is very subjective.

The above makes it very obvious that there is a huge amount of change made
to 'a' and a bit of deletion to 'b', compared to a mini-graph that is
truncated to half the screen width.

Besides, the above is what you would get without your patch on 80-column
terminal, no?

^ permalink raw reply

* Re: git status: small difference between stating whole repository and small subdirectory
From: Junio C Hamano @ 2012-02-20 23:31 UTC (permalink / raw)
  To: Jeff King
  Cc: Thomas Rast, Nguyen Thai Ngoc Duy, Piotr Krukowiecki,
	Git Mailing List
In-Reply-To: <20120220224140.GA7116@sigill.intra.peff.net>

Jeff King <peff@peff.net> writes:

> I still think replaying real-world test cases is going to be more likely
> to find issues in invalidation.

Yes, but it depends on what kind of replaying you have in mind.  It is
very hard to come up with "replaying real-world test case".

For example, randomly picking commit pair <$A,$B> from the kernel
repository and running

	git reset --hard $A
        git checkout $B
        T0=$(git write-tree)
        drop-cache-tree
        T1=$(git write-tree)
        test "$T0" = "$T1" && test "$T0" = $(git rev-parse $B^{tree})

is necessary but I do not think that is sufficient.  We also want to do
something like:

	git reset --hard $A
        ... modify paths that do not change between $A and $B
        ... git add these paths
        git write-tree
        git checkout $B

with and without the "git write-tree" to see the part of the cache-tree
smudged by the modification behaves sanely.  The codepath that is used
to deal with the case where the index does not match $A but matches $B is
also different, so the "modify path and git add" step would have to be
crafted carefully to touch all bases.

^ permalink raw reply

* Re: git-subtree Ready #2
From: Junio C Hamano @ 2012-02-20 23:14 UTC (permalink / raw)
  To: Jeff King; +Cc: David A. Greene, git, Avery Pennarun
In-Reply-To: <20120220205346.GA6335@sigill.intra.peff.net>

Jeff King <peff@peff.net> writes:

> On Wed, Feb 15, 2012 at 10:07:16PM -0600, David A. Greene wrote:
> ...
> Of course there's no real reason we can't take it slow by putting it in
> contrib, and then graduating from there. It just seems like an
> unnecessary and complicated interim step. Either way, I do think it's
> worth saving the commit history by doing a real merge.
>
> I dunno. It is really up to Junio, I guess.

It sounds like the simplest and cleanest would be to treat it as if its
current version came as a patch submission, cook it just like any other
topic in 'pu' down to 'next' down to eventually 'master', with the usual
review cycle of pointing out what is wrong and needs fixing followed by a
series of re-rolls.

The total amount of change does not look too bad, either:

    $ git diff --stat master...origin/subtree
     contrib/subtree/.gitignore         |    5 +
     contrib/subtree/COPYING            |  339 +++++++++++++++++
     contrib/subtree/Makefile           |   45 +++
     contrib/subtree/README             |    8 +
     contrib/subtree/git-subtree.sh     |  712 ++++++++++++++++++++++++++++++++++++
     contrib/subtree/git-subtree.txt    |  366 ++++++++++++++++++
     contrib/subtree/t/Makefile         |   71 ++++
     contrib/subtree/t/t7900-subtree.sh |  508 +++++++++++++++++++++++++
     contrib/subtree/todo               |   50 +++
     t/test-lib.sh                      |   11 +-
     10 files changed, 2114 insertions(+), 1 deletion(-)

It does look like it needs to start its life in contrib/ if we were to put
this in git.git. I haven't looked at the script fully, but it has an issue
from its first line, which is marked with "#!/bin/bash".  It is unclear if
it is infested by bash-isms beyond repair (in which case "#!/bin/bash" is
fine), or it was written portably but was marked with "#!/bin/bash" just
by inertia.  A patch that corresponds to the above diffstat immediately
shows many style issues including trailing eye-sore whitespaces.

It seems that it is even capable of installing from contrib/subtree, so
keeping it in contrib/ while many issues it may have gets fixed would not
hurt the original goal of giving the script more visibility.

The change to t/test-lib.sh should be made independent of this topic, I
would think.

----------------------------------------------------------------
diff --git a/t/test-lib.sh b/t/test-lib.sh
index e28d5fd..c877a91 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -55,6 +55,7 @@ unset $(perl -e '
 		.*_TEST
 		PROVE
 		VALGRIND
+                BUILD_DIR
 	));
 	my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
 	print join("\n", @vars);
@@ -924,7 +925,15 @@ then
 	# itself.
 	TEST_DIRECTORY=$(pwd)
 fi
-GIT_BUILD_DIR="$TEST_DIRECTORY"/..
+
+if test -z "$GIT_BUILD_DIR"
+then
+    echo Here
+	# We allow tests to override this, in case they want to run tests
+	# outside of t/, e.g. for running tests on the test library
+	# itself.
+        GIT_BUILD_DIR="$TEST_DIRECTORY"/..
+fi
 
 if test -n "$valgrind"
 then
----------------------------------------------------------------
This change deserves its own justification.

After looking at the history of subtree branch there, however, I agree
that it would not help anybody to have its history in my tree with log
messages like these (excerpt from shortlog output):

      update todo
      Some todo items reported by pmccurdy
      todo
      Docs: when pushing to github, the repo path needs to end in .git
      todo
      todo^
      todo
      todo: idea for a 'git subtree grafts' command

^ permalink raw reply related

* Re: [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream
From: Junio C Hamano @ 2012-02-20 22:43 UTC (permalink / raw)
  To: Johan Herland; +Cc: git, jnareb, philipoakley
In-Reply-To: <1329772071-11301-1-git-send-email-johan@herland.net>

Johan Herland <johan@herland.net> writes:

> Teach the pre-rebase sample hook to refuse rewriting commits on a branch
> that are present in that branch's @{upstream}. This is to prevent users
> from rewriting commits that have already been published.

If the user has configured an option to always create @{u} when creating a
branch from somewhere else, transplanting $n good commits from his master
that is forked from the shared master onto his maint would be done like
this:

	$ git checkout -b copy master
        $ git rebase -i --onto maint HEAD~$n

If these good commits have been published to 'master', because the
upstream of 'copy' is set to the local 'master', would the new mechanism
hinder this attempt to backport good fixes?  Perhaps it is safer to
trigger only when @{u} exists and it is not local?

But because you wanted to discuss more about the issues than the
implementation, let me think aloud a bit, reviewing what I usually do.

I keep things simpler by sticking to a very simple rule. I allow myself to
rebase only what is not yet in 'next', so the logic becomes a simple "am I
creating a new commit based on what is already in 'next'?"

During the course of integration testing with 'next', however, I often
find a topic or two that I have merged to it is less than ideal, and of
course, the whole point of doing integration testing with 'next' is to
find such problematic topics before pushing 'next' out.  I rewind 'next',
rebuild the problematic topics, and then rebuild 'next', and all of these
happen before 'next' is pushed out.  The step that rewinds 'next' that
acquired problematic versions of the topics makes the topics eligible for
rebase.

That would mean that a configuration variable "rebase.bottomLimit = next"
is sufficient to implement such a check for me.  No per-branch bottom is
needed, because everything is merged to 'next' and tested to see if they
do not need further rebases for fixing them up before they are published.

Perhaps "I mistakenly rebased something that I have already published" is
a mere symptom a bigger problem.  The issue may not be that we do not give
them a good tool to help them to be more careful with less effort on their
part before they rebase.  It may instead be that it is too easy to publish
branches that are not ready to be pushed out, and that is the real cause
of the "I realized I need to fix the topic and I fixed it, but I did not
realize that it was too late and I shouldn't have rebased" problem.

I wonder if it would be a more direct solution to the issue you are
raising to give them a good tool to help them to be more careful with less
effort on their part before they publish (not before they rebase).

^ permalink raw reply

* Re: git status: small difference between stating whole repository and small subdirectory
From: Jeff King @ 2012-02-20 22:41 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Thomas Rast, Nguyen Thai Ngoc Duy, Piotr Krukowiecki,
	Git Mailing List
In-Reply-To: <7v1uppkvpx.fsf@alter.siamese.dyndns.org>

On Mon, Feb 20, 2012 at 02:04:26PM -0800, Junio C Hamano wrote:

> > ... Things may have changed since then, of course, but I at
> > least know that they were sufficient in 34110cd^.
> 
> Looking at where cache_tree_free() is called, I think back then the
> two-way merge was deemed OK, but we did not trust three-way merge or
> merge-recursive at all.

Thanks, I'll take a look more closely at those cases.

> It is OK to check that we do not over-invalidate for performance, but it
> is a lot more important to make sure we do not under-invalidate for
> correctness.  I am a bit worried that you seem to be putting more stress
> on the former.

I think it is just selection bias of the specific parts of his tests
that I was responding to. I completely agree that correctness is way
more important, and I'm also trying to come up with tests to validate
correctness. I just wasn't talking about them there.

I still think replaying real-world test cases is going to be more likely
to find issues in invalidation. I can come up with lots of simple
test-cases, but they're not likely to find anything we wouldn't find in
the code with trivial inspection. I think a combination of careful
analysis and real-world validation is going to be more helpful in the
long run than the kind of simplistic tests that are in t0090.

-Peff

^ permalink raw reply

* Re: [PATCH] Ignore SIGPIPE when running a filter driver
From: Junio C Hamano @ 2012-02-20 22:11 UTC (permalink / raw)
  To: Jehan Bing; +Cc: git, j.sixt, peff, jrnieder
In-Reply-To: <1329771217-9088-1-git-send-email-jehan@orb.com>

Jehan Bing <jehan@orb.com> writes:

> diff --git a/convert.c b/convert.c
> index c06309f..5d312cb 100644
> --- a/convert.c
> +++ b/convert.c
> @@ -2,6 +2,7 @@
>  #include "attr.h"
>  #include "run-command.h"
>  #include "quote.h"
> +#include "sigchain.h"
>  
>  /*
>   * convert.c - convert a file when checking it out and checking it in.
> @@ -360,12 +361,16 @@ static int filter_buffer(int in, int out, void *data)
>  	if (start_command(&child_process))
>  		return error("cannot fork to run external filter %s", params->cmd);
>  
> +	sigchain_push(SIGPIPE, SIG_IGN);
> +
>  	write_err = (write_in_full(child_process.in, params->src, params->size) < 0);
>  	if (close(child_process.in))
>  		write_err = 1;
>  	if (write_err)
>  		error("cannot feed the input to external filter %s", params->cmd);
>  
> +	sigchain_pop(SIGPIPE);
> +

Thanks.

I think this is OK on a POSIX system where this function is run by
start_async() which is implemented with a forked child process.

I do not now if it poses a issue on Windows, though.  Johannes, any
comments?

^ permalink raw reply

* Re: [PATCH 0/5] diff --ignore-case
From: Chris Leong @ 2012-02-20 22:10 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Thomas Rast, Johannes Sixt, git
In-Reply-To: <7vvcn1l21d.fsf@alter.siamese.dyndns.org>

It was about not worrying about the exact case of matches.

On Tue, Feb 21, 2012 at 6:47 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Want to try and see how well it works?
>

^ permalink raw reply

* [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream
From: Johan Herland @ 2012-02-20 21:07 UTC (permalink / raw)
  To: git; +Cc: Johan Herland, gitster, jnareb, philipoakley
In-Reply-To: <201202111445.33260.jnareb@gmail.com>

Teach the pre-rebase sample hook to refuse rewriting commits on a branch
that are present in that branch's @{upstream}. This is to prevent users
from rewriting commits that have already been published.

If the branch has no @{upstream}, or the commits-to-be-rebased are not
reachable from the upstream (hence assumed to be unpublished), the rebase
is not refused.

This patch is not an ideal solution to the problem, for at least the
following reasons:

 - There is no way for the user to override this check, except skipping
   the pre-rebase hook entirely with --no-verify.

 - The check only works for branches with a configured upstream. If the
   user's workflow does not rely on upstream branches, or uses some other
   method of publishing commits, the check will produce false negatives
   (i.e. allow rebases that should have been refused).

 - The check only applies to rebase. I wanted to add the same check
   on 'commit --amend', but there's no obvious way to detect --amend
   from within the pre-commit hook.

 - There may be other rewrite scenarios where we want to do this check,
   such as 'git reset'. Maybe a pre-rewrite hook should be added?

 - Some (including myself) want this check to be performed by default,
   since it's mostly targeted at newbies that are less likely to enable
   the pre-rebase (pre-rewrite) hook, so maybe the check should be added
   to core git instead.

Discussed-with: Jakub Narebski <jnareb@gmail.com>
Signed-off-by: Johan Herland <johan@herland.net>
---
 templates/hooks--pre-rebase.sample |   14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/templates/hooks--pre-rebase.sample b/templates/hooks--pre-rebase.sample
index 053f111..4c28b27 100755
--- a/templates/hooks--pre-rebase.sample
+++ b/templates/hooks--pre-rebase.sample
@@ -25,6 +25,20 @@ else
 	exit 0 ;# we do not interrupt rebasing detached HEAD
 fi
 
+# Are we rewriting upstreamed commits?
+upstream=`git rev-parse --verify "${topic#refs/heads/}@{u}" 2>/dev/null`
+if test -n "$upstream"
+then
+	# See if any of the commits to be rebased are reachable from upstream.
+	basecommit=`git rev-parse --verify "$basebranch"`
+	mergebase=`git merge-base "$basecommit" "$upstream"`
+	if test "$basecommit" != "$upstream" -a "$basecommit" = "$mergebase"
+	then
+		echo >&2 "Cannot rebase commits that are in $topic's upstream"
+		exit 1
+	fi
+fi
+
 case "$topic" in
 refs/heads/??/*)
 	;;
-- 
1.7.9.1.314.ga9004

^ permalink raw reply related

* Re: rfe: git-config: lack of color reset option
From: Junio C Hamano @ 2012-02-20 22:05 UTC (permalink / raw)
  To: Jeff King; +Cc: Jan Engelhardt, git
In-Reply-To: <20120220212006.GB6335@sigill.intra.peff.net>

Jeff King <peff@peff.net> writes:

> This is an artifact of the way the ANSI colorizing works. Git says "turn
> on bold white and a blue background", then it outputs some content, then
> it says "turn on green", and so forth. At the end we issue a "reset" to
> turn everything back to normal. We should perhaps issue a reset before
> outputting the decoration, as we are moving from one colorized bit to
> the other, and we don't know what we are inheriting.

Yeah, I agree with the diagnosis and the proposed solution. It sounds
both simple and correct thing to do.

^ permalink raw reply

* Re: git status: small difference between stating whole repository and small subdirectory
From: Junio C Hamano @ 2012-02-20 22:04 UTC (permalink / raw)
  To: Jeff King
  Cc: Thomas Rast, Nguyen Thai Ngoc Duy, Piotr Krukowiecki,
	Git Mailing List
In-Reply-To: <20120220203540.GA5966@sigill.intra.peff.net>

Jeff King <peff@peff.net> writes:

> ... Things may have changed since then, of course, but I at
> least know that they were sufficient in 34110cd^.

Looking at where cache_tree_free() is called, I think back then the
two-way merge was deemed OK, but we did not trust three-way merge or
merge-recursive at all.

> I think you can construct two tests that will both work in the "ideal"
> case. In the first one, you move to a tree that updates "foo", and
> therefore the root cache-tree is invalidated.

I have to warn you that under-invalidation of cache-tree is extremely hard
to find.  The only way I know, which I had to resort to when dealing with
a handful of instances of under-invalidation bugs, is to run write-tree
with potentially corrupt cache-tree and then using the same index but with
the cache-tree purged, run another write-tree and check to see if two
trees match.

> In general, t0090 could benefit from using a larger tree. For example,
> the add test does "git add foo" and checks that the root cache-tree was
> invalidated. But it should _also_ check that the cache-tree for a
> subdirectory is _not_ invalidated (and it isn't; git-add does the right
> thing).

It is OK to check that we do not over-invalidate for performance, but it
is a lot more important to make sure we do not under-invalidate for
correctness.  I am a bit worried that you seem to be putting more stress
on the former.

^ permalink raw reply

* [PATCH 8/8 v6] diff --stat: use less columns for change counts
From: Zbigniew Jędrzejewski-Szmek @ 2012-02-20 21:57 UTC (permalink / raw)
  To: git, gitster
  Cc: Michael J Gruber, pclouds, j.sixt,
	Zbigniew Jędrzejewski-Szmek
In-Reply-To: <1329775034-21551-1-git-send-email-zbyszek@in.waw.pl>

Number of columns required for change counts is computed based on the
maximum number of changed lines. This means that usually a few more
columns will be available for the filenames and the graph.

The graph width logic is also modified to include enough space for
"Bin XXX -> YYY bytes".

If changes to binary files are mixed with changes to text files,
change counts are padded to take at least three columns. And the other
way around, if change counts require more than three columns, then
"Bin"s are padded to align with the change count. This way, the +-
part starts in the same column as "XXX -> YYY" part for binary files.
This makes the graph easier to parse visually thanks to the empty
column. This mimics the layout of diff --stat before this change.

Tests and the tutorial are updated to reflect the new --stat output.
This means either the removal of extra padding and/or the addition of
up to three extra characters to truncated filenames. One test is added
to check the graph alignment when a binary file change and text file
change of more than 999 lines are committed together.

Signed-off-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
---
 Documentation/gitcore-tutorial.txt                 |  4 +-
 diff.c                                             | 44 ++++++++++++++----
 t/t0023-crlf-am.sh                                 |  2 +-
 t/t1200-tutorial.sh                                |  4 +-
 t/t3404-rebase-interactive.sh                      |  2 +-
 t/t3903-stash.sh                                   |  4 +-
 t/t4012-diff-binary.sh                             | 19 ++++++++
 ...ff-tree_--cc_--patch-with-stat_--summary_master |  4 +-
 ...diff-tree_--cc_--patch-with-stat_--summary_side |  6 +--
 .../diff.diff-tree_--cc_--patch-with-stat_master   |  4 +-
 .../diff.diff-tree_--cc_--stat_--summary_master    |  4 +-
 t/t4013/diff.diff-tree_--cc_--stat_--summary_side  |  6 +--
 t/t4013/diff.diff-tree_--cc_--stat_master          |  4 +-
 ...pretty=oneline_--root_--patch-with-stat_initial |  6 +--
 .../diff.diff-tree_--pretty_--patch-with-stat_side |  6 +--
 ...-tree_--pretty_--root_--patch-with-stat_initial |  6 +--
 ...f-tree_--pretty_--root_--stat_--summary_initial |  6 +--
 .../diff.diff-tree_--pretty_--root_--stat_initial  |  6 +--
 ...diff.diff-tree_--root_--patch-with-stat_initial |  6 +--
 t/t4013/diff.diff-tree_-c_--stat_--summary_master  |  4 +-
 t/t4013/diff.diff-tree_-c_--stat_--summary_side    |  6 +--
 t/t4013/diff.diff-tree_-c_--stat_master            |  4 +-
 .../diff.diff_--patch-with-stat_-r_initial..side   |  6 +--
 t/t4013/diff.diff_--patch-with-stat_initial..side  |  6 +--
 t/t4013/diff.diff_--stat_initial..side             |  6 +--
 t/t4013/diff.diff_-r_--stat_initial..side          |  6 +--
 ..._--attach_--stdout_--suffix=.diff_initial..side |  6 +--
 ....format-patch_--attach_--stdout_initial..master | 16 +++----
 ...format-patch_--attach_--stdout_initial..master^ | 10 ++--
 ...ff.format-patch_--attach_--stdout_initial..side |  6 +--
 ...nline_--stdout_--numbered-files_initial..master | 16 +++----
 ...tdout_--subject-prefix=TESTCASE_initial..master | 16 +++----
 ....format-patch_--inline_--stdout_initial..master | 16 +++----
 ...format-patch_--inline_--stdout_initial..master^ | 10 ++--
 ...ormat-patch_--inline_--stdout_initial..master^^ |  6 +--
 ...ff.format-patch_--inline_--stdout_initial..side |  6 +--
 ...tch_--stdout_--cover-letter_-n_initial..master^ | 18 ++++----
 ...at-patch_--stdout_--no-numbered_initial..master | 16 +++----
 ...ormat-patch_--stdout_--numbered_initial..master | 16 +++----
 t/t4013/diff.format-patch_--stdout_initial..master | 16 +++----
 .../diff.format-patch_--stdout_initial..master^    | 10 ++--
 t/t4013/diff.format-patch_--stdout_initial..side   |  6 +--
 ....log_--patch-with-stat_--summary_master_--_dir_ |  6 +--
 t/t4013/diff.log_--patch-with-stat_master          | 16 +++----
 t/t4013/diff.log_--patch-with-stat_master_--_dir_  |  6 +--
 ..._--root_--cc_--patch-with-stat_--summary_master | 26 +++++------
 ...f.log_--root_--patch-with-stat_--summary_master | 22 ++++-----
 t/t4013/diff.log_--root_--patch-with-stat_master   | 22 ++++-----
 ...og_--root_-c_--patch-with-stat_--summary_master | 26 +++++------
 t/t4013/diff.show_--patch-with-stat_--summary_side |  6 +--
 t/t4013/diff.show_--patch-with-stat_side           |  6 +--
 t/t4013/diff.show_--stat_--summary_side            |  6 +--
 t/t4013/diff.show_--stat_side                      |  6 +--
 ...nged_--patch-with-stat_--summary_master_--_dir_ |  6 +--
 t/t4013/diff.whatchanged_--patch-with-stat_master  | 16 +++----
 ...ff.whatchanged_--patch-with-stat_master_--_dir_ |  6 +--
 ..._--root_--cc_--patch-with-stat_--summary_master | 26 +++++------
 ...anged_--root_--patch-with-stat_--summary_master | 22 ++++-----
 ...iff.whatchanged_--root_--patch-with-stat_master | 22 ++++-----
 ...ed_--root_-c_--patch-with-stat_--summary_master | 26 +++++------
 t/t4014-format-patch.sh                            |  2 +-
 t/t4016-diff-quote.sh                              | 14 +++---
 t/t4030-diff-textconv.sh                           |  2 +-
 t/t4043-diff-rename-binary.sh                      |  4 +-
 t/t4045-diff-relative.sh                           |  2 +-
 t/t4047-diff-dirstat.sh                            | 54 +++++++++++-----------
 t/t4049-diff-stat-count.sh                         |  4 +-
 t/t4052-stat-output.sh                             |  8 ++--
 t/t5100/patch0001                                  |  2 +-
 t/t5100/patch0002                                  |  2 +-
 t/t5100/patch0003                                  |  2 +-
 t/t5100/patch0005                                  |  4 +-
 t/t5100/patch0006                                  |  2 +-
 t/t5100/patch0010                                  |  2 +-
 t/t5100/patch0011                                  |  2 +-
 t/t5100/patch0014                                  |  2 +-
 t/t5100/patch0014--scissors                        |  2 +-
 t/t5100/sample.mbox                                | 18 ++++----
 t/t7602-merge-octopus-many.sh                      | 12 ++---
 79 files changed, 415 insertions(+), 368 deletions(-)

diff --git Documentation/gitcore-tutorial.txt Documentation/gitcore-tutorial.txt
index fb0d569..5b5d5a4 100644
--- Documentation/gitcore-tutorial.txt
+++ Documentation/gitcore-tutorial.txt
@@ -1002,8 +1002,8 @@ would be different)
 ----------------
 Updating from ae3a2da... to a80b4aa....
 Fast-forward (no commit created; -m option ignored)
- example |    1 +
- hello   |    1 +
+ example | 1 +
+ hello   | 1 +
  2 files changed, 2 insertions(+)
 ----------------
 
diff --git diff.c diff.c
index 8a9a387..b4b35d6 100644
--- diff.c
+++ diff.c
@@ -1374,8 +1374,8 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 {
 	int i, len, add, del, adds = 0, dels = 0;
 	uintmax_t max_change = 0, max_len = 0;
-	int total_files = data->nr;
-	int width, name_width, graph_width, number_width = 4, count;
+	int total_files = data->nr, count;
+	int width, name_width, graph_width, number_width = 0, bin_width = 0;
 	const char *reset, *add_c, *del_c;
 	const char *line_prefix = "";
 	int extra_shown = 0;
@@ -1411,8 +1411,21 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 		if (max_len < len)
 			max_len = len;
 
-		if (file->is_binary || file->is_unmerged)
+		if (file->is_unmerged) {
+			/* "Unmerged" is 8 characters */
+			bin_width = bin_width < 8 ? 8 : bin_width;
 			continue;
+		}
+		if (file->is_binary) {
+			/* "Bin XXX -> YYY bytes" */
+			int w = 14 + decimal_width(file->added)
+				+ decimal_width(file->deleted);
+			bin_width = bin_width < w ? w : bin_width;
+			/* Display change counts aligned with "Bin" */
+			number_width = 3;
+			continue;
+		}
+
 		if (max_change < change)
 			max_change = change;
 	}
@@ -1437,12 +1450,22 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 	 * stat_name_width fixes the maximum width of the filename,
 	 * and is also used to divide available columns if there
 	 * aren't enough.
+	 *
+	 * Binary files are displayed with "Bin XXX -> YYY bytes"
+	 * instead of the change count and graph. This part is treated
+	 * similarly to the graph part, except that it is not
+	 * "scaled". If total width is too small to accomodate the
+	 * guaranteed minimum width of the filename part and the
+	 * separators and this message, this message will "overflow"
+	 * making the line longer than the maximum width.
 	 */
 
 	if (options->stat_width == -1)
 		width = term_columns();
 	else
 		width = options->stat_width ? options->stat_width : 80;
+	number_width = decimal_width(max_change) > number_width ?
+		decimal_width(max_change) : number_width;
 
 	/*
 	 * Guarantee 3/8*16==6 for the graph part
@@ -1453,8 +1476,12 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 
 	/*
 	 * First assign sizes that are wanted, ignoring available width.
+	 * strlen("Bin XXX -> YYY bytes") == bin_width, and the part
+	 * starting from "XXX" should fit in graph_width.
 	 */
-	graph_width = max_change < 40 ? max_change : 40;
+	graph_width = max_change + 4 > bin_width ? max_change : bin_width - 4;
+	if (graph_width > 40)
+		graph_width = 40;
 	name_width = (options->stat_name_width > 0 &&
 		      options->stat_name_width < max_len) ?
 		options->stat_name_width : max_len;
@@ -1508,7 +1535,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 		if (data->files[i]->is_binary) {
 			fprintf(options->file, "%s", line_prefix);
 			show_name(options->file, prefix, name, len);
-			fprintf(options->file, "  Bin ");
+			fprintf(options->file, " %*s ", number_width, "Bin");
 			fprintf(options->file, "%s%"PRIuMAX"%s",
 				del_c, deleted, reset);
 			fprintf(options->file, " -> ");
@@ -1521,7 +1548,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 		else if (data->files[i]->is_unmerged) {
 			fprintf(options->file, "%s", line_prefix);
 			show_name(options->file, prefix, name, len);
-			fprintf(options->file, "  Unmerged\n");
+			fprintf(options->file, " Unmerged\n");
 			continue;
 		}
 
@@ -1550,8 +1577,9 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 		}
 		fprintf(options->file, "%s", line_prefix);
 		show_name(options->file, prefix, name, len);
-		fprintf(options->file, "%5"PRIuMAX"%s", added + deleted,
-				added + deleted ? " " : "");
+		fprintf(options->file, " %*"PRIuMAX"%s",
+			number_width, added + deleted,
+			added + deleted ? " " : "");
 		show_graph(options->file, '+', add, add_c, reset);
 		show_graph(options->file, '-', del, del_c, reset);
 		fprintf(options->file, "\n");
diff --git t/t0023-crlf-am.sh t/t0023-crlf-am.sh
index aaed725..f9bbb91 100755
--- t/t0023-crlf-am.sh
+++ t/t0023-crlf-am.sh
@@ -11,7 +11,7 @@ Date: Thu, 23 Aug 2007 13:00:00 +0200
 Subject: test1
 
 ---
- foo |    1 +
+ foo | 1 +
  1 files changed, 1 insertions(+), 0 deletions(-)
  create mode 100644 foo
 
diff --git t/t1200-tutorial.sh t/t1200-tutorial.sh
index 9356bea..397ccb6 100755
--- t/t1200-tutorial.sh
+++ t/t1200-tutorial.sh
@@ -154,8 +154,8 @@ test_expect_success 'git show-branch' '
 cat > resolve.expect << EOF
 Updating VARIABLE..VARIABLE
 FASTFORWARD (no commit created; -m option ignored)
- example |    1 +
- hello   |    1 +
+ example | 1 +
+ hello   | 1 +
  2 files changed, 2 insertions(+)
 EOF
 
diff --git t/t3404-rebase-interactive.sh t/t3404-rebase-interactive.sh
index b981572..c8fe1a9 100755
--- t/t3404-rebase-interactive.sh
+++ t/t3404-rebase-interactive.sh
@@ -323,7 +323,7 @@ test_expect_success 'verbose flag is heeded, even after --continue' '
 	echo resolved > file1 &&
 	git add file1 &&
 	git rebase --continue > output &&
-	grep "^ file1 |    2 +-$" output
+	grep "^ file1 | 2 +-$" output
 '
 
 test_expect_success 'multi-squash only fires up editor once' '
diff --git t/t3903-stash.sh t/t3903-stash.sh
index 663c60a..9b83c28 100755
--- t/t3903-stash.sh
+++ t/t3903-stash.sh
@@ -443,7 +443,7 @@ test_expect_success 'stash show - stashes on stack, stash-like argument' '
 	STASH_ID=$(git stash create) &&
 	git reset --hard &&
 	cat >expected <<-EOF &&
-	 file |    1 +
+	 file | 1 +
 	 1 file changed, 1 insertion(+)
 	EOF
 	git stash show ${STASH_ID} >actual &&
@@ -481,7 +481,7 @@ test_expect_success 'stash show - no stashes on stack, stash-like argument' '
 	STASH_ID=$(git stash create) &&
 	git reset --hard &&
 	cat >expected <<-EOF &&
-	 file |    1 +
+	 file | 1 +
 	 1 file changed, 1 insertion(+)
 	EOF
 	git stash show ${STASH_ID} >actual &&
diff --git t/t4012-diff-binary.sh t/t4012-diff-binary.sh
index 2d9f9a0..9dd48bb 100755
--- t/t4012-diff-binary.sh
+++ t/t4012-diff-binary.sh
@@ -90,4 +90,23 @@ test_expect_success 'diff --no-index with binary creation' '
 	test_cmp expected actual
 '
 
+cat >expect <<EOF
+ binfile  |   Bin 0 -> 1026 bytes
+ textfile | 10000 ++++++++++++++++++++++++++++++++++++++++
+EOF
+
+test_expect_success 'diff --stat with binary files and big change count' '
+	echo X | dd of=binfile bs=1k seek=1 &&
+	git add binfile &&
+	i=0 &&
+	while test $i -lt 10000; do
+		echo $i &&
+		i=$(($i + 1))
+	done >textfile &&
+	git add textfile &&
+	git diff --cached --stat binfile textfile >output &&
+	grep " | " output >actual &&
+	test_cmp expect actual
+'
+
 test_done
diff --git t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master
index 2f8560c..9951e36 100644
--- t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master
+++ t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master
@@ -1,7 +1,7 @@
 $ git diff-tree --cc --patch-with-stat --summary master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
- dir/sub |    2 ++
- file0   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
  2 files changed, 5 insertions(+)
 
 diff --cc dir/sub
diff --git t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side
index 72e03c1..cec33fa 100644
--- t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side
+++ t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side
@@ -1,8 +1,8 @@
 $ git diff-tree --cc --patch-with-stat --summary side
 c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
diff --git t/t4013/diff.diff-tree_--cc_--patch-with-stat_master t/t4013/diff.diff-tree_--cc_--patch-with-stat_master
index 8b357d9..db3c0a7 100644
--- t/t4013/diff.diff-tree_--cc_--patch-with-stat_master
+++ t/t4013/diff.diff-tree_--cc_--patch-with-stat_master
@@ -1,7 +1,7 @@
 $ git diff-tree --cc --patch-with-stat master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
- dir/sub |    2 ++
- file0   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
  2 files changed, 5 insertions(+)
 
 diff --cc dir/sub
diff --git t/t4013/diff.diff-tree_--cc_--stat_--summary_master t/t4013/diff.diff-tree_--cc_--stat_--summary_master
index e0568d6..d019867 100644
--- t/t4013/diff.diff-tree_--cc_--stat_--summary_master
+++ t/t4013/diff.diff-tree_--cc_--stat_--summary_master
@@ -1,6 +1,6 @@
 $ git diff-tree --cc --stat --summary master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
- dir/sub |    2 ++
- file0   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
  2 files changed, 5 insertions(+)
 $
diff --git t/t4013/diff.diff-tree_--cc_--stat_--summary_side t/t4013/diff.diff-tree_--cc_--stat_--summary_side
index 5afc823..12b2eee 100644
--- t/t4013/diff.diff-tree_--cc_--stat_--summary_side
+++ t/t4013/diff.diff-tree_--cc_--stat_--summary_side
@@ -1,8 +1,8 @@
 $ git diff-tree --cc --stat --summary side
 c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 $
diff --git t/t4013/diff.diff-tree_--cc_--stat_master t/t4013/diff.diff-tree_--cc_--stat_master
index f48367a..40b9179 100644
--- t/t4013/diff.diff-tree_--cc_--stat_master
+++ t/t4013/diff.diff-tree_--cc_--stat_master
@@ -1,6 +1,6 @@
 $ git diff-tree --cc --stat master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
- dir/sub |    2 ++
- file0   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
  2 files changed, 5 insertions(+)
 $
diff --git t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial
index 590864c..817ed06 100644
--- t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial
+++ t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial
@@ -1,8 +1,8 @@
 $ git diff-tree --pretty=oneline --root --patch-with-stat initial
 444ac553ac7612cc88969031b02b3767fb8a353a Initial
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 +++
  3 files changed, 8 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
diff --git t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side
index e05e778..fe3f6b7 100644
--- t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side
+++ t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side
@@ -5,9 +5,9 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
diff --git t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial
index 0e2c956..06eb77e 100644
--- t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial
+++ t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial
@@ -5,9 +5,9 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
 
     Initial
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 +++
  3 files changed, 8 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
diff --git t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial
index 384fa44..680eab5 100644
--- t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial
+++ t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial
@@ -5,9 +5,9 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
 
     Initial
 
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 +++
  3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
diff --git t/t4013/diff.diff-tree_--pretty_--root_--stat_initial t/t4013/diff.diff-tree_--pretty_--root_--stat_initial
index 10384a8..9722d1b 100644
--- t/t4013/diff.diff-tree_--pretty_--root_--stat_initial
+++ t/t4013/diff.diff-tree_--pretty_--root_--stat_initial
@@ -5,8 +5,8 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
 
     Initial
 
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 +++
  3 files changed, 8 insertions(+)
 $
diff --git t/t4013/diff.diff-tree_--root_--patch-with-stat_initial t/t4013/diff.diff-tree_--root_--patch-with-stat_initial
index f57062e..ad69ffe 100644
--- t/t4013/diff.diff-tree_--root_--patch-with-stat_initial
+++ t/t4013/diff.diff-tree_--root_--patch-with-stat_initial
@@ -1,8 +1,8 @@
 $ git diff-tree --root --patch-with-stat initial
 444ac553ac7612cc88969031b02b3767fb8a353a
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 +++
  3 files changed, 8 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
diff --git t/t4013/diff.diff-tree_-c_--stat_--summary_master t/t4013/diff.diff-tree_-c_--stat_--summary_master
index 7088683..81c3021 100644
--- t/t4013/diff.diff-tree_-c_--stat_--summary_master
+++ t/t4013/diff.diff-tree_-c_--stat_--summary_master
@@ -1,6 +1,6 @@
 $ git diff-tree -c --stat --summary master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
- dir/sub |    2 ++
- file0   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
  2 files changed, 5 insertions(+)
 $
diff --git t/t4013/diff.diff-tree_-c_--stat_--summary_side t/t4013/diff.diff-tree_-c_--stat_--summary_side
index ef216ab..e8dc12b 100644
--- t/t4013/diff.diff-tree_-c_--stat_--summary_side
+++ t/t4013/diff.diff-tree_-c_--stat_--summary_side
@@ -1,8 +1,8 @@
 $ git diff-tree -c --stat --summary side
 c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 $
diff --git t/t4013/diff.diff-tree_-c_--stat_master t/t4013/diff.diff-tree_-c_--stat_master
index ad19f10..89d59b1 100644
--- t/t4013/diff.diff-tree_-c_--stat_master
+++ t/t4013/diff.diff-tree_-c_--stat_master
@@ -1,6 +1,6 @@
 $ git diff-tree -c --stat master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
- dir/sub |    2 ++
- file0   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
  2 files changed, 5 insertions(+)
 $
diff --git t/t4013/diff.diff_--patch-with-stat_-r_initial..side t/t4013/diff.diff_--patch-with-stat_-r_initial..side
index ddad917..be8d1ea 100644
--- t/t4013/diff.diff_--patch-with-stat_-r_initial..side
+++ t/t4013/diff.diff_--patch-with-stat_-r_initial..side
@@ -1,7 +1,7 @@
 $ git diff --patch-with-stat -r initial..side
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
diff --git t/t4013/diff.diff_--patch-with-stat_initial..side t/t4013/diff.diff_--patch-with-stat_initial..side
index bdbd114..5424e6d 100644
--- t/t4013/diff.diff_--patch-with-stat_initial..side
+++ t/t4013/diff.diff_--patch-with-stat_initial..side
@@ -1,7 +1,7 @@
 $ git diff --patch-with-stat initial..side
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
diff --git t/t4013/diff.diff_--stat_initial..side t/t4013/diff.diff_--stat_initial..side
index 6d08f3d..b7741e2 100644
--- t/t4013/diff.diff_--stat_initial..side
+++ t/t4013/diff.diff_--stat_initial..side
@@ -1,6 +1,6 @@
 $ git diff --stat initial..side
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
 $
diff --git t/t4013/diff.diff_-r_--stat_initial..side t/t4013/diff.diff_-r_--stat_initial..side
index 2ddb254..5d514f5 100644
--- t/t4013/diff.diff_-r_--stat_initial..side
+++ t/t4013/diff.diff_-r_--stat_initial..side
@@ -1,6 +1,6 @@
 $ git diff -r --stat initial..side
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
 $
diff --git t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side
index 3cab049..547ca06 100644
--- t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side
+++ t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side
@@ -12,9 +12,9 @@ Content-Type: text/plain; charset=UTF-8; format=fixed
 Content-Transfer-Encoding: 8bit
 
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
diff --git t/t4013/diff.format-patch_--attach_--stdout_initial..master t/t4013/diff.format-patch_--attach_--stdout_initial..master
index 564a4d3..52fedc1 100644
--- t/t4013/diff.format-patch_--attach_--stdout_initial..master
+++ t/t4013/diff.format-patch_--attach_--stdout_initial..master
@@ -14,9 +14,9 @@ Content-Transfer-Encoding: 8bit
 
 This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -73,8 +73,8 @@ Content-Type: text/plain; charset=UTF-8; format=fixed
 Content-Transfer-Encoding: 8bit
 
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
@@ -121,9 +121,9 @@ Content-Type: text/plain; charset=UTF-8; format=fixed
 Content-Transfer-Encoding: 8bit
 
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
diff --git t/t4013/diff.format-patch_--attach_--stdout_initial..master^ t/t4013/diff.format-patch_--attach_--stdout_initial..master^
index 4f28460..1c3cde2 100644
--- t/t4013/diff.format-patch_--attach_--stdout_initial..master^
+++ t/t4013/diff.format-patch_--attach_--stdout_initial..master^
@@ -14,9 +14,9 @@ Content-Transfer-Encoding: 8bit
 
 This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -73,8 +73,8 @@ Content-Type: text/plain; charset=UTF-8; format=fixed
 Content-Transfer-Encoding: 8bit
 
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
diff --git t/t4013/diff.format-patch_--attach_--stdout_initial..side t/t4013/diff.format-patch_--attach_--stdout_initial..side
index b10cc2e..4717bd8 100644
--- t/t4013/diff.format-patch_--attach_--stdout_initial..side
+++ t/t4013/diff.format-patch_--attach_--stdout_initial..side
@@ -12,9 +12,9 @@ Content-Type: text/plain; charset=UTF-8; format=fixed
 Content-Transfer-Encoding: 8bit
 
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
diff --git t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master
index a976a8a..02c4db7 100644
--- t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master
+++ t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master
@@ -14,9 +14,9 @@ Content-Transfer-Encoding: 8bit
 
 This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -73,8 +73,8 @@ Content-Type: text/plain; charset=UTF-8; format=fixed
 Content-Transfer-Encoding: 8bit
 
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
@@ -121,9 +121,9 @@ Content-Type: text/plain; charset=UTF-8; format=fixed
 Content-Transfer-Encoding: 8bit
 
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
diff --git t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master
index b4fd664..c7677c5 100644
--- t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master
+++ t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master
@@ -14,9 +14,9 @@ Content-Transfer-Encoding: 8bit
 
 This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -73,8 +73,8 @@ Content-Type: text/plain; charset=UTF-8; format=fixed
 Content-Transfer-Encoding: 8bit
 
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
@@ -121,9 +121,9 @@ Content-Type: text/plain; charset=UTF-8; format=fixed
 Content-Transfer-Encoding: 8bit
 
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
diff --git t/t4013/diff.format-patch_--inline_--stdout_initial..master t/t4013/diff.format-patch_--inline_--stdout_initial..master
index 0d31036..5b3e34e 100644
--- t/t4013/diff.format-patch_--inline_--stdout_initial..master
+++ t/t4013/diff.format-patch_--inline_--stdout_initial..master
@@ -14,9 +14,9 @@ Content-Transfer-Encoding: 8bit
 
 This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -73,8 +73,8 @@ Content-Type: text/plain; charset=UTF-8; format=fixed
 Content-Transfer-Encoding: 8bit
 
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
@@ -121,9 +121,9 @@ Content-Type: text/plain; charset=UTF-8; format=fixed
 Content-Transfer-Encoding: 8bit
 
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
diff --git t/t4013/diff.format-patch_--inline_--stdout_initial..master^ t/t4013/diff.format-patch_--inline_--stdout_initial..master^
index 18d4714..d13f8a8 100644
--- t/t4013/diff.format-patch_--inline_--stdout_initial..master^
+++ t/t4013/diff.format-patch_--inline_--stdout_initial..master^
@@ -14,9 +14,9 @@ Content-Transfer-Encoding: 8bit
 
 This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -73,8 +73,8 @@ Content-Type: text/plain; charset=UTF-8; format=fixed
 Content-Transfer-Encoding: 8bit
 
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
diff --git t/t4013/diff.format-patch_--inline_--stdout_initial..master^^ t/t4013/diff.format-patch_--inline_--stdout_initial..master^^
index 29e00ab..caec553 100644
--- t/t4013/diff.format-patch_--inline_--stdout_initial..master^^
+++ t/t4013/diff.format-patch_--inline_--stdout_initial..master^^
@@ -14,9 +14,9 @@ Content-Transfer-Encoding: 8bit
 
 This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
diff --git t/t4013/diff.format-patch_--inline_--stdout_initial..side t/t4013/diff.format-patch_--inline_--stdout_initial..side
index 3572f20..d3a6762 100644
--- t/t4013/diff.format-patch_--inline_--stdout_initial..side
+++ t/t4013/diff.format-patch_--inline_--stdout_initial..side
@@ -12,9 +12,9 @@ Content-Type: text/plain; charset=UTF-8; format=fixed
 Content-Transfer-Encoding: 8bit
 
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
diff --git t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
index 54cdcda..244d964 100644
--- t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
+++ t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
@@ -10,10 +10,10 @@ A U Thor (2):
   Second
   Third
 
- dir/sub |    4 ++++
- file0   |    3 +++
- file1   |    3 +++
- file2   |    3 ---
+ dir/sub | 4 ++++
+ file0   | 3 +++
+ file1   | 3 +++
+ file2   | 3 ---
  4 files changed, 10 insertions(+), 3 deletions(-)
  create mode 100644 file1
  delete mode 100644 file2
@@ -28,9 +28,9 @@ Subject: [DIFFERENT_PREFIX 1/2] Second
 
 This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -73,8 +73,8 @@ Date: Mon, 26 Jun 2006 00:02:00 +0000
 Subject: [DIFFERENT_PREFIX 2/2] Third
 
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
diff --git t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master
index 23194eb..bfc287a 100644
--- t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master
+++ t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master
@@ -6,9 +6,9 @@ Subject: [PATCH] Second
 
 This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -51,8 +51,8 @@ Date: Mon, 26 Jun 2006 00:02:00 +0000
 Subject: [PATCH] Third
 
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
@@ -85,9 +85,9 @@ Date: Mon, 26 Jun 2006 00:03:00 +0000
 Subject: [PATCH] Side
 
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
diff --git t/t4013/diff.format-patch_--stdout_--numbered_initial..master t/t4013/diff.format-patch_--stdout_--numbered_initial..master
index 78f1a80..568f6f5 100644
--- t/t4013/diff.format-patch_--stdout_--numbered_initial..master
+++ t/t4013/diff.format-patch_--stdout_--numbered_initial..master
@@ -6,9 +6,9 @@ Subject: [PATCH 1/3] Second
 
 This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -51,8 +51,8 @@ Date: Mon, 26 Jun 2006 00:02:00 +0000
 Subject: [PATCH 2/3] Third
 
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
@@ -85,9 +85,9 @@ Date: Mon, 26 Jun 2006 00:03:00 +0000
 Subject: [PATCH 3/3] Side
 
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
diff --git t/t4013/diff.format-patch_--stdout_initial..master t/t4013/diff.format-patch_--stdout_initial..master
index a3dab7f..5f0352f 100644
--- t/t4013/diff.format-patch_--stdout_initial..master
+++ t/t4013/diff.format-patch_--stdout_initial..master
@@ -6,9 +6,9 @@ Subject: [PATCH 1/3] Second
 
 This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -51,8 +51,8 @@ Date: Mon, 26 Jun 2006 00:02:00 +0000
 Subject: [PATCH 2/3] Third
 
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
@@ -85,9 +85,9 @@ Date: Mon, 26 Jun 2006 00:03:00 +0000
 Subject: [PATCH 3/3] Side
 
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
diff --git t/t4013/diff.format-patch_--stdout_initial..master^ t/t4013/diff.format-patch_--stdout_initial..master^
index 39f4a3f..2ae454d 100644
--- t/t4013/diff.format-patch_--stdout_initial..master^
+++ t/t4013/diff.format-patch_--stdout_initial..master^
@@ -6,9 +6,9 @@ Subject: [PATCH 1/2] Second
 
 This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -51,8 +51,8 @@ Date: Mon, 26 Jun 2006 00:02:00 +0000
 Subject: [PATCH 2/2] Third
 
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
diff --git t/t4013/diff.format-patch_--stdout_initial..side t/t4013/diff.format-patch_--stdout_initial..side
index 8810920..a7d52fb 100644
--- t/t4013/diff.format-patch_--stdout_initial..side
+++ t/t4013/diff.format-patch_--stdout_initial..side
@@ -5,9 +5,9 @@ Date: Mon, 26 Jun 2006 00:03:00 +0000
 Subject: [PATCH] Side
 
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
diff --git t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_
index 4085bbd..a18f147 100644
--- t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_
+++ t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_
@@ -12,7 +12,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
+ dir/sub | 2 ++
  1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
@@ -31,7 +31,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 
     Third
 ---
- dir/sub |    2 ++
+ dir/sub | 2 ++
  1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
@@ -53,7 +53,7 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     
     This is the second commit.
 ---
- dir/sub |    2 ++
+ dir/sub | 2 ++
  1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
diff --git t/t4013/diff.log_--patch-with-stat_master t/t4013/diff.log_--patch-with-stat_master
index 4586279..ae425c4 100644
--- t/t4013/diff.log_--patch-with-stat_master
+++ t/t4013/diff.log_--patch-with-stat_master
@@ -12,9 +12,9 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
@@ -54,8 +54,8 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 
     Third
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
@@ -86,9 +86,9 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     
     This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
 
 diff --git a/dir/sub b/dir/sub
diff --git t/t4013/diff.log_--patch-with-stat_master_--_dir_ t/t4013/diff.log_--patch-with-stat_master_--_dir_
index 6e172cf..d5207ca 100644
--- t/t4013/diff.log_--patch-with-stat_master_--_dir_
+++ t/t4013/diff.log_--patch-with-stat_master_--_dir_
@@ -12,7 +12,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
+ dir/sub | 2 ++
  1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
@@ -31,7 +31,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 
     Third
 ---
- dir/sub |    2 ++
+ dir/sub | 2 ++
  1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
@@ -53,7 +53,7 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     
     This is the second commit.
 ---
- dir/sub |    2 ++
+ dir/sub | 2 ++
  1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
diff --git t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master
index 48b0d4b..0fc1e8c 100644
--- t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master
+++ t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master
@@ -6,8 +6,8 @@ Date:   Mon Jun 26 00:04:00 2006 +0000
 
     Merge branch 'side'
 
- dir/sub |    2 ++
- file0   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
  2 files changed, 5 insertions(+)
 
 diff --cc dir/sub
@@ -44,9 +44,9 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
@@ -87,8 +87,8 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 
     Third
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
@@ -120,9 +120,9 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     
     This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -162,9 +162,9 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
 
     Initial
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 +++
  3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
diff --git t/t4013/diff.log_--root_--patch-with-stat_--summary_master t/t4013/diff.log_--root_--patch-with-stat_--summary_master
index f9dc512..dffc09d 100644
--- t/t4013/diff.log_--root_--patch-with-stat_--summary_master
+++ t/t4013/diff.log_--root_--patch-with-stat_--summary_master
@@ -12,9 +12,9 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
@@ -55,8 +55,8 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 
     Third
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
@@ -88,9 +88,9 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     
     This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -130,9 +130,9 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
 
     Initial
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 +++
  3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
diff --git t/t4013/diff.log_--root_--patch-with-stat_master t/t4013/diff.log_--root_--patch-with-stat_master
index 0807ece..55aa980 100644
--- t/t4013/diff.log_--root_--patch-with-stat_master
+++ t/t4013/diff.log_--root_--patch-with-stat_master
@@ -12,9 +12,9 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
@@ -54,8 +54,8 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 
     Third
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
@@ -86,9 +86,9 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     
     This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
 
 diff --git a/dir/sub b/dir/sub
@@ -127,9 +127,9 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
 
     Initial
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 +++
  3 files changed, 8 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
diff --git t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master
index 84f5ef6..019d85f 100644
--- t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master
+++ t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master
@@ -6,8 +6,8 @@ Date:   Mon Jun 26 00:04:00 2006 +0000
 
     Merge branch 'side'
 
- dir/sub |    2 ++
- file0   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
  2 files changed, 5 insertions(+)
 
 diff --combined dir/sub
@@ -44,9 +44,9 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
@@ -87,8 +87,8 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 
     Third
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
@@ -120,9 +120,9 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     
     This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -162,9 +162,9 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
 
     Initial
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 +++
  3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
diff --git t/t4013/diff.show_--patch-with-stat_--summary_side t/t4013/diff.show_--patch-with-stat_--summary_side
index e60384d..95a474e 100644
--- t/t4013/diff.show_--patch-with-stat_--summary_side
+++ t/t4013/diff.show_--patch-with-stat_--summary_side
@@ -5,9 +5,9 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
diff --git t/t4013/diff.show_--patch-with-stat_side t/t4013/diff.show_--patch-with-stat_side
index a3a3255..974e99b 100644
--- t/t4013/diff.show_--patch-with-stat_side
+++ t/t4013/diff.show_--patch-with-stat_side
@@ -5,9 +5,9 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
diff --git t/t4013/diff.show_--stat_--summary_side t/t4013/diff.show_--stat_--summary_side
index d16f464..a71492f 100644
--- t/t4013/diff.show_--stat_--summary_side
+++ t/t4013/diff.show_--stat_--summary_side
@@ -5,9 +5,9 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 $
diff --git t/t4013/diff.show_--stat_side t/t4013/diff.show_--stat_side
index 6300c05..9be7124 100644
--- t/t4013/diff.show_--stat_side
+++ t/t4013/diff.show_--stat_side
@@ -5,8 +5,8 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
 $
diff --git t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_
index 16ae543..c8b6af2 100644
--- t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_
+++ t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_
@@ -5,7 +5,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
+ dir/sub | 2 ++
  1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
@@ -24,7 +24,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 
     Third
 ---
- dir/sub |    2 ++
+ dir/sub | 2 ++
  1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
@@ -46,7 +46,7 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     
     This is the second commit.
 ---
- dir/sub |    2 ++
+ dir/sub | 2 ++
  1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
diff --git t/t4013/diff.whatchanged_--patch-with-stat_master t/t4013/diff.whatchanged_--patch-with-stat_master
index f3e45ec..1ac431b 100644
--- t/t4013/diff.whatchanged_--patch-with-stat_master
+++ t/t4013/diff.whatchanged_--patch-with-stat_master
@@ -5,9 +5,9 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
@@ -47,8 +47,8 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 
     Third
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
@@ -79,9 +79,9 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     
     This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
 
 diff --git a/dir/sub b/dir/sub
diff --git t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_
index c77f0bc..b30c285 100644
--- t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_
+++ t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_
@@ -5,7 +5,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
+ dir/sub | 2 ++
  1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
@@ -24,7 +24,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 
     Third
 ---
- dir/sub |    2 ++
+ dir/sub | 2 ++
  1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
@@ -46,7 +46,7 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     
     This is the second commit.
 ---
- dir/sub |    2 ++
+ dir/sub | 2 ++
  1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
diff --git t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master
index 8d03efe..30aae78 100644
--- t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master
+++ t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master
@@ -6,8 +6,8 @@ Date:   Mon Jun 26 00:04:00 2006 +0000
 
     Merge branch 'side'
 
- dir/sub |    2 ++
- file0   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
  2 files changed, 5 insertions(+)
 
 diff --cc dir/sub
@@ -44,9 +44,9 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
@@ -87,8 +87,8 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 
     Third
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
@@ -120,9 +120,9 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     
     This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -162,9 +162,9 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
 
     Initial
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 +++
  3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
diff --git t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master
index 1874d06..db90e51 100644
--- t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master
+++ t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master
@@ -5,9 +5,9 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
@@ -48,8 +48,8 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 
     Third
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
@@ -81,9 +81,9 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     
     This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -123,9 +123,9 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
 
     Initial
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 +++
  3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
diff --git t/t4013/diff.whatchanged_--root_--patch-with-stat_master t/t4013/diff.whatchanged_--root_--patch-with-stat_master
index 5211ff2..9a6cc92 100644
--- t/t4013/diff.whatchanged_--root_--patch-with-stat_master
+++ t/t4013/diff.whatchanged_--root_--patch-with-stat_master
@@ -5,9 +5,9 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
@@ -47,8 +47,8 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 
     Third
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
@@ -79,9 +79,9 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     
     This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
 
 diff --git a/dir/sub b/dir/sub
@@ -120,9 +120,9 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
 
     Initial
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 +++
  3 files changed, 8 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
diff --git t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master
index ad30245..d1d32bd 100644
--- t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master
+++ t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master
@@ -6,8 +6,8 @@ Date:   Mon Jun 26 00:04:00 2006 +0000
 
     Merge branch 'side'
 
- dir/sub |    2 ++
- file0   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
  2 files changed, 5 insertions(+)
 
 diff --combined dir/sub
@@ -44,9 +44,9 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
 
     Side
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file3   |    4 ++++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file3   | 4 ++++
  3 files changed, 9 insertions(+)
  create mode 100644 file3
 
@@ -87,8 +87,8 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 
     Third
 ---
- dir/sub |    2 ++
- file1   |    3 +++
+ dir/sub | 2 ++
+ file1   | 3 +++
  2 files changed, 5 insertions(+)
  create mode 100644 file1
 
@@ -120,9 +120,9 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     
     This is the second commit.
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 ---
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 ---
  3 files changed, 5 insertions(+), 3 deletions(-)
  delete mode 100644 file2
 
@@ -162,9 +162,9 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
 
     Initial
 ---
- dir/sub |    2 ++
- file0   |    3 +++
- file2   |    3 +++
+ dir/sub | 2 ++
+ file0   | 3 +++
+ file2   | 3 +++
  3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
diff --git t/t4014-format-patch.sh t/t4014-format-patch.sh
index 7dfe716..3cfa960 100755
--- t/t4014-format-patch.sh
+++ t/t4014-format-patch.sh
@@ -519,7 +519,7 @@ test_expect_success 'shortlog of cover-letter wraps overly-long onelines' '
 
 cat > expect << EOF
 ---
- file |   16 ++++++++++++++++
+ file | 16 ++++++++++++++++
  1 file changed, 16 insertions(+)
 
 diff --git a/file b/file
diff --git t/t4016-diff-quote.sh t/t4016-diff-quote.sh
index ab0c2f0..e451f2a 100755
--- t/t4016-diff-quote.sh
+++ t/t4016-diff-quote.sh
@@ -59,13 +59,13 @@ test_expect_success TABS_IN_FILENAMES 'git diff --summary -M HEAD' '
 
 test_expect_success TABS_IN_FILENAMES 'setup expected files' '
 cat >expect <<\EOF
- pathname.1 => "Rpathname\twith HT.0"            |    0
- pathname.3 => "Rpathname\nwith LF.0"            |    0
- "pathname\twith HT.3" => "Rpathname\nwith LF.1" |    0
- pathname.2 => Rpathname with SP.0               |    0
- "pathname\twith HT.2" => Rpathname with SP.1    |    0
- pathname.0 => Rpathname.0                       |    0
- "pathname\twith HT.0" => Rpathname.1            |    0
+ pathname.1 => "Rpathname\twith HT.0"            | 0
+ pathname.3 => "Rpathname\nwith LF.0"            | 0
+ "pathname\twith HT.3" => "Rpathname\nwith LF.1" | 0
+ pathname.2 => Rpathname with SP.0               | 0
+ "pathname\twith HT.2" => Rpathname with SP.1    | 0
+ pathname.0 => Rpathname.0                       | 0
+ "pathname\twith HT.0" => Rpathname.1            | 0
  7 files changed, 0 insertions(+), 0 deletions(-)
 EOF
 '
diff --git t/t4030-diff-textconv.sh t/t4030-diff-textconv.sh
index 4ac162c..bd95f93 100755
--- t/t4030-diff-textconv.sh
+++ t/t4030-diff-textconv.sh
@@ -85,7 +85,7 @@ test_expect_success 'status -v produces text' '
 '
 
 cat >expect.stat <<'EOF'
- file |  Bin 2 -> 4 bytes
+ file | Bin 2 -> 4 bytes
  1 file changed, 0 insertions(+), 0 deletions(-)
 EOF
 test_expect_success 'diffstat does not run textconv' '
diff --git t/t4043-diff-rename-binary.sh t/t4043-diff-rename-binary.sh
index 0601281..ad0b2da 100755
--- t/t4043-diff-rename-binary.sh
+++ t/t4043-diff-rename-binary.sh
@@ -23,8 +23,8 @@ test_expect_success 'move the files into a "sub" directory' '
 '
 
 cat > expected <<\EOF
- bar => sub/bar |  Bin 5 -> 5 bytes
- foo => sub/foo |    0
+ bar => sub/bar | Bin 5 -> 5 bytes
+ foo => sub/foo |   0
  2 files changed, 0 insertions(+), 0 deletions(-)
 
 diff --git a/bar b/sub/bar
diff --git t/t4045-diff-relative.sh t/t4045-diff-relative.sh
index bd119be..ba33578 100755
--- t/t4045-diff-relative.sh
+++ t/t4045-diff-relative.sh
@@ -32,7 +32,7 @@ test_expect_success "-p $*" "
 check_stat() {
 expect=$1; shift
 cat >expected <<EOF
- $expect |    1 +
+ $expect | 1 +
  1 file changed, 1 insertion(+)
 EOF
 test_expect_success "--stat $*" "
diff --git t/t4047-diff-dirstat.sh t/t4047-diff-dirstat.sh
index 29e80a5..75eaf16 100755
--- t/t4047-diff-dirstat.sh
+++ t/t4047-diff-dirstat.sh
@@ -252,41 +252,41 @@ EOF
 '
 
 cat <<EOF >expect_diff_stat
- changed/text             |    2 +-
- dst/copy/changed/text    |   10 ++++++++++
- dst/copy/rearranged/text |   10 ++++++++++
- dst/copy/unchanged/text  |   10 ++++++++++
- dst/move/changed/text    |   10 ++++++++++
- dst/move/rearranged/text |   10 ++++++++++
- dst/move/unchanged/text  |   10 ++++++++++
- rearranged/text          |    2 +-
- src/move/changed/text    |   10 ----------
- src/move/rearranged/text |   10 ----------
- src/move/unchanged/text  |   10 ----------
+ changed/text             |  2 +-
+ dst/copy/changed/text    | 10 ++++++++++
+ dst/copy/rearranged/text | 10 ++++++++++
+ dst/copy/unchanged/text  | 10 ++++++++++
+ dst/move/changed/text    | 10 ++++++++++
+ dst/move/rearranged/text | 10 ++++++++++
+ dst/move/unchanged/text  | 10 ++++++++++
+ rearranged/text          |  2 +-
+ src/move/changed/text    | 10 ----------
+ src/move/rearranged/text | 10 ----------
+ src/move/unchanged/text  | 10 ----------
  11 files changed, 62 insertions(+), 32 deletions(-)
 EOF
 
 cat <<EOF >expect_diff_stat_M
- changed/text                      |    2 +-
- dst/copy/changed/text             |   10 ++++++++++
- dst/copy/rearranged/text          |   10 ++++++++++
- dst/copy/unchanged/text           |   10 ++++++++++
- {src => dst}/move/changed/text    |    2 +-
- {src => dst}/move/rearranged/text |    2 +-
- {src => dst}/move/unchanged/text  |    0
- rearranged/text                   |    2 +-
+ changed/text                      |  2 +-
+ dst/copy/changed/text             | 10 ++++++++++
+ dst/copy/rearranged/text          | 10 ++++++++++
+ dst/copy/unchanged/text           | 10 ++++++++++
+ {src => dst}/move/changed/text    |  2 +-
+ {src => dst}/move/rearranged/text |  2 +-
+ {src => dst}/move/unchanged/text  |  0
+ rearranged/text                   |  2 +-
  8 files changed, 34 insertions(+), 4 deletions(-)
 EOF
 
 cat <<EOF >expect_diff_stat_CC
- changed/text                      |    2 +-
- {src => dst}/copy/changed/text    |    2 +-
- {src => dst}/copy/rearranged/text |    2 +-
- {src => dst}/copy/unchanged/text  |    0
- {src => dst}/move/changed/text    |    2 +-
- {src => dst}/move/rearranged/text |    2 +-
- {src => dst}/move/unchanged/text  |    0
- rearranged/text                   |    2 +-
+ changed/text                      | 2 +-
+ {src => dst}/copy/changed/text    | 2 +-
+ {src => dst}/copy/rearranged/text | 2 +-
+ {src => dst}/copy/unchanged/text  | 0
+ {src => dst}/move/changed/text    | 2 +-
+ {src => dst}/move/rearranged/text | 2 +-
+ {src => dst}/move/unchanged/text  | 0
+ rearranged/text                   | 2 +-
  8 files changed, 6 insertions(+), 6 deletions(-)
 EOF
 
diff --git t/t4049-diff-stat-count.sh t/t4049-diff-stat-count.sh
index a6d1887..d7231ee 100755
--- t/t4049-diff-stat-count.sh
+++ t/t4049-diff-stat-count.sh
@@ -14,8 +14,8 @@ test_expect_success setup '
 	echo a >a &&
 	echo b >b &&
 	cat >expect <<-\EOF
-	 a |    1 +
-	 b |    1 +
+	 a | 1 +
+	 b | 1 +
 	 2 files changed, 2 insertions(+)
 	EOF
 	git diff --stat --stat-count=2 >actual &&
diff --git t/t4052-stat-output.sh t/t4052-stat-output.sh
index 1b237b7..d670bb0 100755
--- t/t4052-stat-output.sh
+++ t/t4052-stat-output.sh
@@ -19,11 +19,11 @@ test_expect_success 'preparation' '
 	git commit -m message "$name"
 '
 cat >expect80 <<'EOF'
- ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |    1 +
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
 EOF
 
 cat >expect40 <<-'EOF'
- ...aaaaaaaaaaaaaaaaaaaaaaaaaa |    1 +
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
 EOF
 
 while read cmd args
@@ -47,13 +47,13 @@ do
 	'
 
 	test_expect_success "$cmd --stat=...,name-width with long name" '
-		git $cmd $args --stat=60,29 >output &&
+		git $cmd $args --stat=60,32 >output &&
 		grep " | " output >actual &&
 		test_cmp expect40 actual
 	'
 
 	test_expect_success "$cmd --stat-name-width with long name" '
-		git $cmd $args --stat-name-width=29 >output &&
+		git $cmd $args --stat-name-width=32 >output &&
 		grep " | " output >actual &&
 		test_cmp expect40 actual
 	'
diff --git t/t5100/patch0001 t/t5100/patch0001
index 8ce1551..02c9774 100644
--- t/t5100/patch0001
+++ t/t5100/patch0001
@@ -1,5 +1,5 @@
 ---
- foo |    2 +-
+ foo | 2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)
 
 diff --git a/foo b/foo
diff --git t/t5100/patch0002 t/t5100/patch0002
index 8ce1551..02c9774 100644
--- t/t5100/patch0002
+++ t/t5100/patch0002
@@ -1,5 +1,5 @@
 ---
- foo |    2 +-
+ foo | 2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)
 
 diff --git a/foo b/foo
diff --git t/t5100/patch0003 t/t5100/patch0003
index 8ce1551..02c9774 100644
--- t/t5100/patch0003
+++ t/t5100/patch0003
@@ -1,5 +1,5 @@
 ---
- foo |    2 +-
+ foo | 2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)
 
 diff --git a/foo b/foo
diff --git t/t5100/patch0005 t/t5100/patch0005
index 7d24b24..ab7a383 100644
--- t/t5100/patch0005
+++ t/t5100/patch0005
@@ -1,7 +1,7 @@
 ---
 
- Documentation/git-cvsimport-script.txt |    9 ++++++++-
- git-cvsimport-script                   |    4 ++--
+ Documentation/git-cvsimport-script.txt | 9 ++++++++-
+ git-cvsimport-script                   | 4 ++--
  2 files changed, 10 insertions(+), 3 deletions(-)
 
 50452f9c0c2df1f04d83a26266ba704b13861632
diff --git t/t5100/patch0006 t/t5100/patch0006
index 8ce1551..02c9774 100644
--- t/t5100/patch0006
+++ t/t5100/patch0006
@@ -1,5 +1,5 @@
 ---
- foo |    2 +-
+ foo | 2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)
 
 diff --git a/foo b/foo
diff --git t/t5100/patch0010 t/t5100/patch0010
index f055481..436821c 100644
--- t/t5100/patch0010
+++ t/t5100/patch0010
@@ -1,5 +1,5 @@
 ---
- builtin-mailinfo.c |    2 +-
+ builtin-mailinfo.c | 2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)
 
 diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
diff --git t/t5100/patch0011 t/t5100/patch0011
index 8841d3c..0988713 100644
--- t/t5100/patch0011
+++ t/t5100/patch0011
@@ -1,5 +1,5 @@
 ---
- builtin-mailinfo.c  |    4 ++--
+ builtin-mailinfo.c  | 4 ++--
 
 diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
 index 3e5fe51..aabfe5c 100644
diff --git t/t5100/patch0014 t/t5100/patch0014
index 124efd2..3f3825f 100644
--- t/t5100/patch0014
+++ t/t5100/patch0014
@@ -1,5 +1,5 @@
 ---
- builtin-mailinfo.c |   37 ++++++++++++++++++++++++++++++++++++-
+ builtin-mailinfo.c | 37 ++++++++++++++++++++++++++++++++++++-
  1 files changed, 36 insertions(+), 1 deletions(-)
 
 diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
diff --git t/t5100/patch0014--scissors t/t5100/patch0014--scissors
index 124efd2..3f3825f 100644
--- t/t5100/patch0014--scissors
+++ t/t5100/patch0014--scissors
@@ -1,5 +1,5 @@
 ---
- builtin-mailinfo.c |   37 ++++++++++++++++++++++++++++++++++++-
+ builtin-mailinfo.c | 37 ++++++++++++++++++++++++++++++++++++-
  1 files changed, 36 insertions(+), 1 deletions(-)
 
 diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
diff --git t/t5100/sample.mbox t/t5100/sample.mbox
index de10312..34a09a0 100644
--- t/t5100/sample.mbox
+++ t/t5100/sample.mbox
@@ -12,7 +12,7 @@ Subject: [PATCH] a commit.
 Here is a patch from A U Thor.
 
 ---
- foo |    2 +-
+ foo | 2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)
 
 diff --git a/foo b/foo
@@ -52,7 +52,7 @@ two truly blank and another full of spaces in between.
 Hope this helps.
 
 ---
- foo |    2 +-
+ foo | 2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)
 
 diff --git a/foo b/foo
@@ -83,7 +83,7 @@ Message-Id: <nitpicker.12121212@example.net>
 Hopefully this would fix the problem stated there.
 
 ---
- foo |    2 +-
+ foo | 2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)
 
 diff --git a/foo b/foo
@@ -249,8 +249,8 @@ actual flags.
 Signed-off-by: David K=E5gedal <davidk@lysator.liu.se>
 ---
 
- Documentation/git-cvsimport-script.txt |    9 ++++++++-
- git-cvsimport-script                   |    4 ++--
+ Documentation/git-cvsimport-script.txt | 9 ++++++++-
+ git-cvsimport-script                   | 4 ++--
  2 files changed, 10 insertions(+), 3 deletions(-)
 
 50452f9c0c2df1f04d83a26266ba704b13861632
@@ -379,7 +379,7 @@ Subject: [PATCH] a commit.
 Here is a patch from A U Thor.
 
 ---
- foo |    2 +-
+ foo | 2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)
 
 diff --git a/foo b/foo
@@ -449,7 +449,7 @@ memcmp("Subject: ", header[i], 7) will never match.
 Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>
 Signed-off-by: Junio C Hamano <gitster@pobox.com>
 ---
- builtin-mailinfo.c |    2 +-
+ builtin-mailinfo.c | 2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)
 
 diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
@@ -482,7 +482,7 @@ Content-Transfer-Encoding: quoted-printable
 Here comes a commit log message, and
 its second line is here.
 ---
- builtin-mailinfo.c  |    4 ++--
+ builtin-mailinfo.c  | 4 ++--
 
 diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
 index 3e5fe51..aabfe5c 100644
@@ -587,7 +587,7 @@ everything before it in the message body.
 
 Signed-off-by: Junio C Hamano <gitster@pobox.com>
 ---
- builtin-mailinfo.c |   37 ++++++++++++++++++++++++++++++++++++-
+ builtin-mailinfo.c | 37 ++++++++++++++++++++++++++++++++++++-
  1 files changed, 36 insertions(+), 1 deletions(-)
 
 diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
diff --git t/t7602-merge-octopus-many.sh t/t7602-merge-octopus-many.sh
index 5783ebf..1479b8f 100755
--- t/t7602-merge-octopus-many.sh
+++ t/t7602-merge-octopus-many.sh
@@ -54,9 +54,9 @@ Trying simple merge with c2
 Trying simple merge with c3
 Trying simple merge with c4
 Merge made by the 'octopus' strategy.
- c2.c |    1 +
- c3.c |    1 +
- c4.c |    1 +
+ c2.c | 1 +
+ c3.c | 1 +
+ c4.c | 1 +
  3 files changed, 3 insertions(+)
  create mode 100644 c2.c
  create mode 100644 c3.c
@@ -73,7 +73,7 @@ cat >expected <<\EOF
 Already up-to-date with c4
 Trying simple merge with c5
 Merge made by the 'octopus' strategy.
- c5.c |    1 +
+ c5.c | 1 +
  1 file changed, 1 insertion(+)
  create mode 100644 c5.c
 EOF
@@ -87,8 +87,8 @@ cat >expected <<\EOF
 Fast-forwarding to: c1
 Trying simple merge with c2
 Merge made by the 'octopus' strategy.
- c1.c |    1 +
- c2.c |    1 +
+ c1.c | 1 +
+ c2.c | 1 +
  2 files changed, 2 insertions(+)
  create mode 100644 c1.c
  create mode 100644 c2.c
-- 
1.7.9.1.353.g684b4

^ permalink raw reply related

* [PATCH 5/8 v6] log --stat: use the full terminal width
From: Zbigniew Jędrzejewski-Szmek @ 2012-02-20 21:57 UTC (permalink / raw)
  To: git, gitster
  Cc: Michael J Gruber, pclouds, j.sixt,
	Zbigniew Jędrzejewski-Szmek
In-Reply-To: <1329775034-21551-1-git-send-email-zbyszek@in.waw.pl>

Make log --stat behave like diff --stat and use the full terminal
width.

Signed-off-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
---
 builtin/log.c          | 1 +
 t/t4052-stat-output.sh | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git builtin/log.c builtin/log.c
index d37ae26..075a427 100644
--- builtin/log.c
+++ builtin/log.c
@@ -77,6 +77,7 @@ static void cmd_log_init_defaults(struct rev_info *rev)
 		get_commit_format(fmt_pretty, rev);
 	rev->verbose_header = 1;
 	DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
+	rev->diffopt.stat_width = -1; /* use full terminal width */
 	rev->abbrev_commit = default_abbrev_commit;
 	rev->show_root_diff = default_show_root;
 	rev->subject_prefix = fmt_patch_subject_prefix;
diff --git t/t4052-stat-output.sh t/t4052-stat-output.sh
index 91c4ba8..acc54cd 100755
--- t/t4052-stat-output.sh
+++ t/t4052-stat-output.sh
@@ -96,7 +96,7 @@ done <<\EOF
 ignores expect80 format-patch -1 --stdout
 respects expect200 diff HEAD^ HEAD --stat
 respects expect200 show --stat
-ignores expect80 log -1 --stat
+respects expect200 log -1 --stat
 EOF
 
 cat >expect <<'EOF'
@@ -164,7 +164,7 @@ done <<\EOF
 ignores expect80 format-patch -1 --stdout
 respects expect200 diff HEAD^ HEAD --stat
 respects expect200 show --stat
-ignores expect80 log -1 --stat
+respects expect200 log -1 --stat
 EOF
 
 cat >expect <<'EOF'
-- 
1.7.9.1.353.g684b4

^ permalink raw reply related

* [PATCH 2/8 v6] diff --stat: tests for long filenames and big change counts
From: Zbigniew Jędrzejewski-Szmek @ 2012-02-20 21:57 UTC (permalink / raw)
  To: git, gitster
  Cc: Michael J Gruber, pclouds, j.sixt,
	Zbigniew Jędrzejewski-Szmek
In-Reply-To: <1329775034-21551-1-git-send-email-zbyszek@in.waw.pl>

In preparation for updates to the "diff --stat" that updates the logic
to split the allotted columns into the name part and the graph part to
make the output more readable, add a handful of tests to document the
corner case behaviour in which long filenames and big changes are shown.

When a pathname is so long that it cannot fit on the column, the current
code truncates it to make sure that the graph part has enough room to show
a meaningful graph.  If the actual change is small (e.g. only one line
changed), this results in the final output that is shorter than the width
we aim for.  A couple of new tests marked with test_expect_failure
demonstrate this bug.

Signed-off-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
---
 t/t4052-stat-output.sh | 182 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 182 insertions(+)
 create mode 100755 t/t4052-stat-output.sh

diff --git t/t4052-stat-output.sh t/t4052-stat-output.sh
new file mode 100755
index 0000000..031107b
--- /dev/null
+++ t/t4052-stat-output.sh
@@ -0,0 +1,182 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Zbigniew Jędrzejewski-Szmek
+#
+
+test_description='test --stat output of various commands'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
+
+# 120 character name
+name=aaaaaaaaaa
+name=$name$name$name$name$name$name$name$name$name$name$name$name
+test_expect_success 'preparation' '
+	>"$name" &&
+	git add "$name" &&
+	git commit -m message &&
+	echo a >"$name" &&
+	git commit -m message "$name"
+'
+cat >expect80 <<'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |    1 +
+EOF
+
+cat >expect40 <<-'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaa |    1 +
+EOF
+
+while read cmd args
+do
+	test_expect_failure "$cmd graph width defaults to 80 columns" '
+		git $cmd $args >output &&
+		grep " | " output >actual &&
+		test_cmp expect80 actual
+	'
+
+	test_expect_failure "$cmd --stat=width with long name" '
+		git $cmd $args --stat=40 >output &&
+		grep " | " output >actual &&
+		test_cmp expect40 actual
+	'
+
+	test_expect_failure "$cmd --stat-width=width with long name" '
+		git $cmd $args --stat-width=40 >output &&
+		grep " | " output >actual &&
+		test_cmp expect40 actual
+	'
+
+	test_expect_success "$cmd --stat=...,name-width with long name" '
+		git $cmd $args --stat=60,29 >output &&
+		grep " | " output >actual &&
+		test_cmp expect40 actual
+	'
+
+	test_expect_success "$cmd --stat-name-width with long name" '
+		git $cmd $args --stat-name-width=29 >output &&
+		grep " | " output >actual &&
+		test_cmp expect40 actual
+	'
+done <<\EOF
+format-patch -1 --stdout
+diff HEAD^ HEAD --stat
+show --stat
+log -1 --stat
+EOF
+
+
+test_expect_success 'preparation for big change tests' '
+	>abcd &&
+	git add abcd &&
+	git commit -m message &&
+	i=0 &&
+	while test $i -lt 1000
+	do
+		echo $i && i=$(($i + 1))
+	done >abcd &&
+	git commit -m message abcd
+'
+
+cat >expect80 <<'EOF'
+ abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+EOF
+
+while read verb expect cmd args
+do
+	test_expect_success "$cmd $verb COLUMNS (big change)" '
+		COLUMNS=200 git $cmd $args >output
+		grep " | " output >actual &&
+		test_cmp "$expect" actual
+	'
+done <<\EOF
+ignores expect80 format-patch -1 --stdout
+ignores expect80 diff HEAD^ HEAD --stat
+ignores expect80 show --stat
+ignores expect80 log -1 --stat
+EOF
+
+cat >expect <<'EOF'
+ abcd | 1000 ++++++++++++++++++++++++++
+EOF
+
+while read cmd args
+do
+	test_expect_success "$cmd --stat=width with big change" '
+		git $cmd $args --stat=40 >output
+		grep " | " output >actual &&
+		test_cmp expect actual
+	'
+
+	test_expect_success "$cmd --stat-width=width with big change" '
+		git $cmd $args --stat-width=40 >output
+		grep " | " output >actual &&
+		test_cmp expect actual
+	'
+done <<\EOF
+format-patch -1 --stdout
+diff HEAD^ HEAD --stat
+show --stat
+log -1 --stat
+EOF
+
+test_expect_success 'preparation for long filename tests' '
+	cp abcd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
+	git add aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
+	git commit -m message
+'
+
+cat >expect <<'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++
+EOF
+
+while read cmd args
+do
+	test_expect_success "$cmd --stat=width with big change and long name" '
+		git $cmd $args --stat-width=60 >output &&
+		grep " | " output >actual &&
+		test_cmp expect actual
+	'
+done <<\EOF
+format-patch -1 --stdout
+diff HEAD^ HEAD --stat
+show --stat
+log -1 --stat
+EOF
+
+cat >expect80 <<'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++
+EOF
+while read verb expect cmd args
+do
+	test_expect_success "$cmd $verb COLUMNS (long filename)" '
+		COLUMNS=200 git $cmd $args >output
+		grep " | " output >actual &&
+		test_cmp "$expect" actual
+	'
+done <<\EOF
+ignores expect80 format-patch -1 --stdout
+ignores expect80 diff HEAD^ HEAD --stat
+ignores expect80 show --stat
+ignores expect80 log -1 --stat
+EOF
+
+cat >expect <<'EOF'
+ abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+EOF
+test_expect_success 'merge --stat ignores COLUMNS (big change)' '
+	git checkout -b branch HEAD^^ &&
+	COLUMNS=100 git merge --stat --no-ff master^ >output &&
+	grep " | " output >actual
+	test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++
+EOF
+test_expect_success 'merge --stat ignores COLUMNS (long filename)' '
+	COLUMNS=100 git merge --stat --no-ff master >output &&
+	grep " | " output >actual
+	test_cmp expect actual
+'
+
+test_done
-- 
1.7.9.1.353.g684b4

^ permalink raw reply related

* [PATCH 7/8 v6] diff --stat: limit graph part to 40 columns
From: Zbigniew Jędrzejewski-Szmek @ 2012-02-20 21:57 UTC (permalink / raw)
  To: git, gitster
  Cc: Michael J Gruber, pclouds, j.sixt,
	Zbigniew Jędrzejewski-Szmek
In-Reply-To: <1329775034-21551-1-git-send-email-zbyszek@in.waw.pl>

The way that available columns are divided between the filename part
and the graph part is modified to use as many columns as necessary for
the filenames and up to 40 columns for the graph.

If commits changing a lot of lines are displayed in a wide terminal
window (200 or more columns), and the +- graph would use the full
width, the output would look bad. Messages wrapped to about 80 columns
would be interspersed with very long +- lines. It makes sense to limit
the width of the graph part to a fixed value, even if more columns are
available. This fixed value is subjectively hard-coded to be 40
columns, which seems to work well for git.git and linux-2.6.git and
some other repositories.

If there isn't enough columns to print both the filename and the
graph, at least 5/8 of available space is devoted to filenames. On a
standard 80 column terminal, or if not connected to a terminal and
using the default of 80 columns, this gives the same partition as
before.

The effect of this change is visible in the patch to t4052 that fixes a
few tests marked with test_expect_failure, and the change to shorten the
maximum graph width to 40 columns. Since limiting the graph part to
40 columns makes COLUMNS=200 stop influencing diff --stat behaviour,
because it isn't wide enough now, a new test with COLUMNS=40 is added
to check that the environment variable influences diff, show, log, but not
format-patch. The old test with COLUMNS=200 is added to check for
regressions.

Signed-off-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
---
 Documentation/diff-options.txt | 14 +++---
 diff.c                         | 94 +++++++++++++++++++++++++++-------------
 t/t4052-stat-output.sh         | 45 ++++++++++++-------
 3 files changed, 102 insertions(+), 51 deletions(-)

diff --git Documentation/diff-options.txt Documentation/diff-options.txt
index 9ed78c9..e4d0e3e 100644
--- Documentation/diff-options.txt
+++ Documentation/diff-options.txt
@@ -53,13 +53,15 @@ endif::git-format-patch[]
 	Generate a diff using the "patience diff" algorithm.
 
 --stat[=<width>[,<name-width>[,<count>]]]::
-	Generate a diffstat.  You can override the default
-	output width for 80-column terminal by `--stat=<width>`.
-	The width of the filename part can be controlled by
-	giving another width to it separated by a comma.
+	Generate a diffstat. By default, as much space as necessary
+	will be used for the filename part, and up to 40 columns for
+	the graph part. Maximum width defaults to terminal width,
+	or 80 columns if not connected to a terminal, and can be
+	overriden by `<width>`. The width of the filename part can be
+	limited by giving another width `<name-width>` after a comma.
 	By giving a third parameter `<count>`, you can limit the
-	output to the first `<count>` lines, followed by
-	`...` if there are more.
+	output to the first `<count>` lines, followed by `...` if
+	there are more.
 +
 These parameters can also be set individually with `--stat-width=<width>`,
 `--stat-name-width=<name-width>` and `--stat-count=<count>`.
diff --git diff.c diff.c
index 1db46a4..8a9a387 100644
--- diff.c
+++ diff.c
@@ -1375,7 +1375,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 	int i, len, add, del, adds = 0, dels = 0;
 	uintmax_t max_change = 0, max_len = 0;
 	int total_files = data->nr;
-	int width, name_width, count;
+	int width, name_width, graph_width, number_width = 4, count;
 	const char *reset, *add_c, *del_c;
 	const char *line_prefix = "";
 	int extra_shown = 0;
@@ -1389,28 +1389,15 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 		line_prefix = msg->buf;
 	}
 
-	if (options->stat_width == -1)
-		width = term_columns();
-	else
-		width = options->stat_width ? options->stat_width : 80;
-	name_width = options->stat_name_width ? options->stat_name_width : 50;
 	count = options->stat_count ? options->stat_count : data->nr;
 
-	/* Sanity: give at least 5 columns to the graph,
-	 * but leave at least 10 columns for the name.
-	 */
-	if (width < 25)
-		width = 25;
-	if (name_width < 10)
-		name_width = 10;
-	else if (width < name_width + 15)
-		name_width = width - 15;
-
-	/* Find the longest filename and max number of changes */
 	reset = diff_get_color_opt(options, DIFF_RESET);
 	add_c = diff_get_color_opt(options, DIFF_FILE_NEW);
 	del_c = diff_get_color_opt(options, DIFF_FILE_OLD);
 
+	/*
+	 * Find the longest filename and max number of changes
+	 */
 	for (i = 0; (i < count) && (i < data->nr); i++) {
 		struct diffstat_file *file = data->files[i];
 		uintmax_t change = file->added + file->deleted;
@@ -1431,19 +1418,66 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 	}
 	count = i; /* min(count, data->nr) */
 
-	/* Compute the width of the graph part;
-	 * 10 is for one blank at the beginning of the line plus
-	 * " | count " between the name and the graph.
+	/*
+	 * We have width = stat_width or term_columns() columns total.
+	 * We want a maximum of min(max_len, stat_name_width) for the name part.
+	 * We want a maximum of min(max_change, 40) for the +- part.
+	 * We also need 1 for " " and 4 + decimal_width(max_change)
+	 * for " | NNNN " and one the empty column at the end, altogether
+	 * 6 + decimal_width(max_change).
+	 *
+	 * If there's not enough space, we will use the smaller of
+	 * stat_name_width (if set) and 5/8*width for the filename,
+	 * and the rest for constant elements + graph part, but no more
+	 * than 40 for the graph part.
+	 * (5/8 gives 50 for filename and 30 for the constant parts + graph
+	 * for the standard terminal size).
 	 *
-	 * From here on, name_width is the width of the name area,
-	 * and width is the width of the graph area.
+	 * In other words: stat_width limits the maximum width, and
+	 * stat_name_width fixes the maximum width of the filename,
+	 * and is also used to divide available columns if there
+	 * aren't enough.
 	 */
-	name_width = (name_width < max_len) ? name_width : max_len;
-	if (width < (name_width + 10) + max_change)
-		width = width - (name_width + 10);
+
+	if (options->stat_width == -1)
+		width = term_columns();
 	else
-		width = max_change;
+		width = options->stat_width ? options->stat_width : 80;
 
+	/*
+	 * Guarantee 3/8*16==6 for the graph part
+	 * and 5/8*16==10 for the filename part
+	 */
+	if (width < 16 + 6 + number_width)
+		width = 16 + 6 + number_width;
+
+	/*
+	 * First assign sizes that are wanted, ignoring available width.
+	 */
+	graph_width = max_change < 40 ? max_change : 40;
+	name_width = (options->stat_name_width > 0 &&
+		      options->stat_name_width < max_len) ?
+		options->stat_name_width : max_len;
+
+	/*
+	 * Adjust adjustable widths not to exceed maximum width
+	 */
+	if (name_width + number_width + 6 + graph_width > width) {
+		if (graph_width > width * 3/8 - number_width - 6)
+			graph_width = width * 3/8 - number_width - 6;
+		if (graph_width > 40)
+			graph_width =  40;
+		if (name_width > width - number_width - 6 - graph_width)
+			name_width = width - number_width - 6 - graph_width;
+		else
+			graph_width = width - number_width - 6 - name_width;
+	}
+
+	/*
+	 * From here name_width is the width of the name area,
+	 * and graph_width is the width of the graph area.
+	 * max_change is used to scale graph properly.
+	 */
 	for (i = 0; i < count; i++) {
 		const char *prefix = "";
 		char *name = data->files[i]->print_name;
@@ -1499,18 +1533,18 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 		adds += add;
 		dels += del;
 
-		if (width <= max_change) {
+		if (graph_width <= max_change) {
 			int total = add + del;
 
-			total = scale_linear(add + del, width, max_change);
+			total = scale_linear(add + del, graph_width, max_change);
 			if (total < 2 && add && del)
 				/* width >= 2 due to the sanity check */
 				total = 2;
 			if (add < del) {
-				add = scale_linear(add, width, max_change);
+				add = scale_linear(add, graph_width, max_change);
 				del = total - add;
 			} else {
-				del = scale_linear(del, width, max_change);
+				del = scale_linear(del, graph_width, max_change);
 				add = total - del;
 			}
 		}
diff --git t/t4052-stat-output.sh t/t4052-stat-output.sh
index 2b4510c..1b237b7 100755
--- t/t4052-stat-output.sh
+++ t/t4052-stat-output.sh
@@ -28,19 +28,19 @@ EOF
 
 while read cmd args
 do
-	test_expect_failure "$cmd graph width defaults to 80 columns" '
+	test_expect_success "$cmd graph width defaults to 80 columns" '
 		git $cmd $args >output &&
 		grep " | " output >actual &&
 		test_cmp expect80 actual
 	'
 
-	test_expect_failure "$cmd --stat=width with long name" '
+	test_expect_success "$cmd --stat=width with long name" '
 		git $cmd $args --stat=40 >output &&
 		grep " | " output >actual &&
 		test_cmp expect40 actual
 	'
 
-	test_expect_failure "$cmd --stat-width=width with long name" '
+	test_expect_success "$cmd --stat-width=width with long name" '
 		git $cmd $args --stat-width=40 >output &&
 		grep " | " output >actual &&
 		test_cmp expect40 actual
@@ -78,27 +78,42 @@ test_expect_success 'preparation for big change tests' '
 '
 
 cat >expect80 <<'EOF'
- abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ abcd | 1000 ++++++++++++++++++++++++++++++++++++++++
 EOF
 
-cat >expect200 <<'EOF'
- abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+while read verb expect cmd args
+do
+	test_expect_success "$cmd $verb too many COLUMNS (big change)" '
+		COLUMNS=200 git $cmd $args >output
+		grep " | " output >actual &&
+		test_cmp "$expect" actual
+	'
+done <<\EOF
+ignores expect80 format-patch -1 --stdout
+respects expect80 diff HEAD^ HEAD --stat
+respects expect80 show --stat
+respects expect80 log -1 --stat
+EOF
+
+cat >expect40 <<'EOF'
+ abcd | 1000 ++++++++++++++++++++++++++
 EOF
 
 while read verb expect cmd args
 do
-	test_expect_success "$cmd $verb COLUMNS (big change)" '
-		COLUMNS=200 git $cmd $args >output
+	test_expect_success "$cmd $verb not enough COLUMNS (big change)" '
+		COLUMNS=40 git $cmd $args >output
 		grep " | " output >actual &&
 		test_cmp "$expect" actual
 	'
 done <<\EOF
 ignores expect80 format-patch -1 --stdout
-respects expect200 diff HEAD^ HEAD --stat
-respects expect200 show --stat
-respects expect200 log -1 --stat
+respects expect40 diff HEAD^ HEAD --stat
+respects expect40 show --stat
+respects expect40 log -1 --stat
 EOF
 
+
 cat >expect <<'EOF'
  abcd | 1000 ++++++++++++++++++++++++++
 EOF
@@ -130,7 +145,7 @@ test_expect_success 'preparation for long filename tests' '
 '
 
 cat >expect <<'EOF'
- ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++
 EOF
 
 while read cmd args
@@ -151,7 +166,7 @@ cat >expect80 <<'EOF'
  ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++
 EOF
 cat >expect200 <<'EOF'
- ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++++++++++++++++++++++
 EOF
 while read verb expect cmd args
 do
@@ -168,7 +183,7 @@ respects expect200 log -1 --stat
 EOF
 
 cat >expect <<'EOF'
- abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ abcd | 1000 ++++++++++++++++++++++++++++++++++++++++
 EOF
 test_expect_success 'merge --stat respects COLUMNS (big change)' '
 	git checkout -b branch HEAD^^ &&
@@ -178,7 +193,7 @@ test_expect_success 'merge --stat respects COLUMNS (big change)' '
 '
 
 cat >expect <<'EOF'
- ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++++++++++++++++++++++
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++
 EOF
 test_expect_success 'merge --stat respects COLUMNS (long filename)' '
 	COLUMNS=100 git merge --stat --no-ff master >output &&
-- 
1.7.9.1.353.g684b4

^ permalink raw reply related

* [PATCH 6/8 v6] merge --stat: use the full terminal width
From: Zbigniew Jędrzejewski-Szmek @ 2012-02-20 21:57 UTC (permalink / raw)
  To: git, gitster
  Cc: Michael J Gruber, pclouds, j.sixt,
	Zbigniew Jędrzejewski-Szmek
In-Reply-To: <1329775034-21551-1-git-send-email-zbyszek@in.waw.pl>

Make merge --stat behave like diff --stat and use the full terminal
width.

Signed-off-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
---
 builtin/merge.c        | 1 +
 t/t4052-stat-output.sh | 8 ++++----
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git builtin/merge.c builtin/merge.c
index ed0f959..7b368e7 100644
--- builtin/merge.c
+++ builtin/merge.c
@@ -399,6 +399,7 @@ static void finish(struct commit *head_commit,
 	if (new_head && show_diffstat) {
 		struct diff_options opts;
 		diff_setup(&opts);
+		opts.stat_width = -1; /* use full terminal width */
 		opts.output_format |=
 			DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
 		opts.detect_rename = DIFF_DETECT_RENAME;
diff --git t/t4052-stat-output.sh t/t4052-stat-output.sh
index acc54cd..2b4510c 100755
--- t/t4052-stat-output.sh
+++ t/t4052-stat-output.sh
@@ -168,9 +168,9 @@ respects expect200 log -1 --stat
 EOF
 
 cat >expect <<'EOF'
- abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 EOF
-test_expect_success 'merge --stat ignores COLUMNS (big change)' '
+test_expect_success 'merge --stat respects COLUMNS (big change)' '
 	git checkout -b branch HEAD^^ &&
 	COLUMNS=100 git merge --stat --no-ff master^ >output &&
 	grep " | " output >actual
@@ -178,9 +178,9 @@ test_expect_success 'merge --stat ignores COLUMNS (big change)' '
 '
 
 cat >expect <<'EOF'
- ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++++++++++++++++++++++
 EOF
-test_expect_success 'merge --stat ignores COLUMNS (long filename)' '
+test_expect_success 'merge --stat respects COLUMNS (long filename)' '
 	COLUMNS=100 git merge --stat --no-ff master >output &&
 	grep " | " output >actual
 	test_cmp expect actual
-- 
1.7.9.1.353.g684b4

^ permalink raw reply related

* [PATCH 4/8 v6] show --stat: use the full terminal width
From: Zbigniew Jędrzejewski-Szmek @ 2012-02-20 21:57 UTC (permalink / raw)
  To: git, gitster
  Cc: Michael J Gruber, pclouds, j.sixt,
	Zbigniew Jędrzejewski-Szmek
In-Reply-To: <1329775034-21551-1-git-send-email-zbyszek@in.waw.pl>

Make show --stat behave like diff --stat and use the full terminal
width.

Signed-off-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
---
 builtin/log.c          | 2 ++
 t/t4052-stat-output.sh | 4 ++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git builtin/log.c builtin/log.c
index 7d1f6f8..d37ae26 100644
--- builtin/log.c
+++ builtin/log.c
@@ -447,6 +447,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 	rev.diff = 1;
 	rev.always_show_header = 1;
 	rev.no_walk = 1;
+	rev.diffopt.stat_width = -1; 	/* Scale to real terminal size */
+
 	memset(&opt, 0, sizeof(opt));
 	opt.def = "HEAD";
 	opt.tweak = show_rev_tweak_rev;
diff --git t/t4052-stat-output.sh t/t4052-stat-output.sh
index 4bfd6a5..91c4ba8 100755
--- t/t4052-stat-output.sh
+++ t/t4052-stat-output.sh
@@ -95,7 +95,7 @@ do
 done <<\EOF
 ignores expect80 format-patch -1 --stdout
 respects expect200 diff HEAD^ HEAD --stat
-ignores expect80 show --stat
+respects expect200 show --stat
 ignores expect80 log -1 --stat
 EOF
 
@@ -163,7 +163,7 @@ do
 done <<\EOF
 ignores expect80 format-patch -1 --stdout
 respects expect200 diff HEAD^ HEAD --stat
-ignores expect80 show --stat
+respects expect200 show --stat
 ignores expect80 log -1 --stat
 EOF
 
-- 
1.7.9.1.353.g684b4

^ permalink raw reply related

* [PATCH 3/8 v6] diff --stat: use the full terminal width
From: Zbigniew Jędrzejewski-Szmek @ 2012-02-20 21:57 UTC (permalink / raw)
  To: git, gitster
  Cc: Michael J Gruber, pclouds, j.sixt,
	Zbigniew Jędrzejewski-Szmek
In-Reply-To: <1329775034-21551-1-git-send-email-zbyszek@in.waw.pl>

Default to the real terminal width for diff --stat output, instead
of the hard-coded 80 columns.

Some projects (especially in Java), have long filename paths, with
nested directories or long individual filenames. When files are
renamed, the filename part in stat output can be almost useless. If
the middle part between { and } is long (because the file was moved to
a completely different directory), then most of the path would be
truncated.

It makes sense to detect and use the full terminal width and display
full filenames if possible.

The are commands like diff, show, and log, which can adapt the output
to the terminal width. There are also commands like format-patch,
whose output should be independent of the terminal width. Since it is
safer to use the 80-column default, the real terminal width is only
used if requested by the calling code by setting diffopts.stat_width=-1.
Normally this value is 0, and can be set by the user only to a
non-negative value, so -1 is safe to use internally.

This patch only changes the diff builtin to use the full terminal width.

Signed-off-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
---
 builtin/diff.c         |  3 +++
 diff.c                 |  5 ++++-
 t/t4052-stat-output.sh | 11 +++++++++--
 3 files changed, 16 insertions(+), 3 deletions(-)

diff --git builtin/diff.c builtin/diff.c
index 387afa7..81b6bae 100644
--- builtin/diff.c
+++ builtin/diff.c
@@ -285,6 +285,9 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
 	/* Otherwise, we are doing the usual "git" diff */
 	rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
 
+	/* Scale to real terminal size */
+	rev.diffopt.stat_width = -1;
+
 	/* Default to let external and textconv be used */
 	DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
 	DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);
diff --git diff.c diff.c
index 01c15da..1db46a4 100644
--- diff.c
+++ diff.c
@@ -1389,7 +1389,10 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 		line_prefix = msg->buf;
 	}
 
-	width = options->stat_width ? options->stat_width : 80;
+	if (options->stat_width == -1)
+		width = term_columns();
+	else
+		width = options->stat_width ? options->stat_width : 80;
 	name_width = options->stat_name_width ? options->stat_name_width : 50;
 	count = options->stat_count ? options->stat_count : data->nr;
 
diff --git t/t4052-stat-output.sh t/t4052-stat-output.sh
index 031107b..4bfd6a5 100755
--- t/t4052-stat-output.sh
+++ t/t4052-stat-output.sh
@@ -81,6 +81,10 @@ cat >expect80 <<'EOF'
  abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 EOF
 
+cat >expect200 <<'EOF'
+ abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+EOF
+
 while read verb expect cmd args
 do
 	test_expect_success "$cmd $verb COLUMNS (big change)" '
@@ -90,7 +94,7 @@ do
 	'
 done <<\EOF
 ignores expect80 format-patch -1 --stdout
-ignores expect80 diff HEAD^ HEAD --stat
+respects expect200 diff HEAD^ HEAD --stat
 ignores expect80 show --stat
 ignores expect80 log -1 --stat
 EOF
@@ -146,6 +150,9 @@ EOF
 cat >expect80 <<'EOF'
  ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++
 EOF
+cat >expect200 <<'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+EOF
 while read verb expect cmd args
 do
 	test_expect_success "$cmd $verb COLUMNS (long filename)" '
@@ -155,7 +162,7 @@ do
 	'
 done <<\EOF
 ignores expect80 format-patch -1 --stdout
-ignores expect80 diff HEAD^ HEAD --stat
+respects expect200 diff HEAD^ HEAD --stat
 ignores expect80 show --stat
 ignores expect80 log -1 --stat
 EOF
-- 
1.7.9.1.353.g684b4

^ permalink raw reply related

* [PATCH 1/8 v6] make lineno_width() from blame reusable for others
From: Zbigniew Jędrzejewski-Szmek @ 2012-02-20 21:57 UTC (permalink / raw)
  To: git, gitster
  Cc: Michael J Gruber, pclouds, j.sixt,
	Zbigniew Jędrzejewski-Szmek
In-Reply-To: <1329775034-21551-1-git-send-email-zbyszek@in.waw.pl>

builtin/blame.c has a helper function to compute how many columns we
need to show a line-number, whose implementation is reusable as a more
generic helper function to count the number of columns necessary to
show any cardinal number.

Rename it to decimal_width(), move it to pager.c and export it for use
by future callers.

Signed-off-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
---
 builtin/blame.c | 18 +++---------------
 cache.h         |  1 +
 pager.c         | 13 +++++++++++++
 3 files changed, 17 insertions(+), 15 deletions(-)

diff --git builtin/blame.c builtin/blame.c
index 01956c8..b35bd62 100644
--- builtin/blame.c
+++ builtin/blame.c
@@ -1829,18 +1829,6 @@ static int read_ancestry(const char *graft_file)
 }
 
 /*
- * How many columns do we need to show line numbers in decimal?
- */
-static int lineno_width(int lines)
-{
-	int i, width;
-
-	for (width = 1, i = 10; i <= lines; width++)
-		i *= 10;
-	return width;
-}
-
-/*
  * How many columns do we need to show line numbers, authors,
  * and filenames?
  */
@@ -1880,9 +1868,9 @@ static void find_alignment(struct scoreboard *sb, int *option)
 		if (largest_score < ent_score(sb, e))
 			largest_score = ent_score(sb, e);
 	}
-	max_orig_digits = lineno_width(longest_src_lines);
-	max_digits = lineno_width(longest_dst_lines);
-	max_score_digits = lineno_width(largest_score);
+	max_orig_digits = decimal_width(longest_src_lines);
+	max_digits = decimal_width(longest_dst_lines);
+	max_score_digits = decimal_width(largest_score);
 }
 
 /*
diff --git cache.h cache.h
index 9ecdf76..980d95d 100644
--- cache.h
+++ cache.h
@@ -1198,6 +1198,7 @@ extern const char *pager_program;
 extern int pager_in_use(void);
 extern int pager_use_color;
 extern int term_columns(void);
+extern int decimal_width(uintmax_t number);
 
 extern const char *editor_program;
 extern const char *askpass_program;
diff --git pager.c pager.c
index b790967..60be7bb 100644
--- pager.c
+++ pager.c
@@ -147,3 +147,16 @@ int term_columns(void)
 
 	return term_columns_at_startup;
 }
+
+/*
+ * How many columns do we need to show this number in decimal?
+ */
+int decimal_width(uintmax_t number)
+{
+	int width;
+	uintmax_t i;
+
+	for (width = 1, i = 10; i <= number; width++)
+		i *= 10;
+	return width;
+}
-- 
1.7.9.1.353.g684b4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox