summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Documentation/config.txt6
-rw-r--r--Documentation/git-instaweb.txt84
-rw-r--r--Makefile29
-rw-r--r--builtin-diff-files.c3
-rw-r--r--builtin-diff-index.c3
-rw-r--r--builtin-diff-stages.c3
-rw-r--r--builtin-diff-tree.c3
-rw-r--r--builtin-diff.c56
-rw-r--r--builtin-fmt-merge-msg.c355
-rw-r--r--builtin-grep.c36
-rw-r--r--builtin-log.c39
-rw-r--r--builtin.h1
-rw-r--r--cache.h7
-rw-r--r--combine-diff.c68
-rw-r--r--config.c14
-rw-r--r--connect.c35
-rw-r--r--contrib/emacs/vc-git.el13
-rwxr-xr-xcontrib/git-svn/git-svn.perl2
-rw-r--r--csum-file.c2
-rw-r--r--diff.c223
-rw-r--r--diff.h28
-rw-r--r--environment.c1
-rwxr-xr-xgit-annotate.perl197
-rwxr-xr-xgit-fmt-merge-msg.perl173
-rwxr-xr-xgit-instaweb.sh235
-rwxr-xr-xgit-reset.sh6
-rwxr-xr-xgit-send-email.perl18
-rw-r--r--git.c3
-rwxr-xr-xgitweb/gitweb.cgi66
-rw-r--r--http-push.c2
-rw-r--r--log-tree.c23
-rw-r--r--log-tree.h2
-rw-r--r--peek-remote.c28
-rw-r--r--ppc/sha1ppc.S351
-rw-r--r--revision.c3
-rw-r--r--send-pack.c2
-rw-r--r--sha1_file.c4
-rwxr-xr-xt/t4013-diff-various.sh247
-rw-r--r--t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master34
-rw-r--r--t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side39
-rw-r--r--t/t4013/diff.diff-tree_--cc_--patch-with-stat_master34
-rw-r--r--t/t4013/diff.diff-tree_--cc_--stat_--summary_master6
-rw-r--r--t/t4013/diff.diff-tree_--cc_--stat_--summary_side8
-rw-r--r--t/t4013/diff.diff-tree_--cc_--stat_master6
-rw-r--r--t/t4013/diff.diff-tree_--cc_master30
-rw-r--r--t/t4013/diff.diff-tree_--patch-with-raw_initial2
-rw-r--r--t/t4013/diff.diff-tree_--patch-with-stat_initial2
-rw-r--r--t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-raw_initial2
-rw-r--r--t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-stat_initial2
-rw-r--r--t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-raw_initial33
-rw-r--r--t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial34
-rw-r--r--t/t4013/diff.diff-tree_--pretty=oneline_--root_-p_initial29
-rw-r--r--t/t4013/diff.diff-tree_--pretty=oneline_--root_initial6
-rw-r--r--t/t4013/diff.diff-tree_--pretty=oneline_-p_initial2
-rw-r--r--t/t4013/diff.diff-tree_--pretty=oneline_initial2
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--patch-with-raw_initial2
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--patch-with-stat_initial2
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side43
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--root_--patch-with-raw_initial38
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial39
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial15
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--root_--stat_initial12
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--root_--summary_-r_initial11
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--root_--summary_initial11
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--root_-p_initial34
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--root_initial11
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--stat_--summary_initial2
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--stat_initial2
-rw-r--r--t/t4013/diff.diff-tree_--pretty_--summary_initial2
-rw-r--r--t/t4013/diff.diff-tree_--pretty_-p_initial2
-rw-r--r--t/t4013/diff.diff-tree_--pretty_-p_side38
-rw-r--r--t/t4013/diff.diff-tree_--pretty_initial2
-rw-r--r--t/t4013/diff.diff-tree_--pretty_side11
-rw-r--r--t/t4013/diff.diff-tree_--root_--abbrev_initial6
-rw-r--r--t/t4013/diff.diff-tree_--root_--patch-with-raw_initial33
-rw-r--r--t/t4013/diff.diff-tree_--root_--patch-with-stat_initial34
-rw-r--r--t/t4013/diff.diff-tree_--root_-p_initial29
-rw-r--r--t/t4013/diff.diff-tree_--root_-r_--abbrev=4_initial6
-rw-r--r--t/t4013/diff.diff-tree_--root_-r_--abbrev_initial6
-rw-r--r--t/t4013/diff.diff-tree_--root_-r_initial6
-rw-r--r--t/t4013/diff.diff-tree_--root_initial6
-rw-r--r--t/t4013/diff.diff-tree_-c_--abbrev_master5
-rw-r--r--t/t4013/diff.diff-tree_-c_--stat_--summary_master6
-rw-r--r--t/t4013/diff.diff-tree_-c_--stat_--summary_side8
-rw-r--r--t/t4013/diff.diff-tree_-c_--stat_master6
-rw-r--r--t/t4013/diff.diff-tree_-c_master5
-rw-r--r--t/t4013/diff.diff-tree_-p_-m_master80
-rw-r--r--t/t4013/diff.diff-tree_-p_initial2
-rw-r--r--t/t4013/diff.diff-tree_-p_master2
-rw-r--r--t/t4013/diff.diff-tree_-r_--abbrev=4_initial2
-rw-r--r--t/t4013/diff.diff-tree_-r_--abbrev_initial2
-rw-r--r--t/t4013/diff.diff-tree_-r_initial2
-rw-r--r--t/t4013/diff.diff-tree_initial2
-rw-r--r--t/t4013/diff.diff-tree_master2
-rw-r--r--t/t4013/diff.diff_--abbrev_initial..side32
-rw-r--r--t/t4013/diff.diff_--patch-with-raw_-r_initial..side36
-rw-r--r--t/t4013/diff.diff_--patch-with-raw_initial..side36
-rw-r--r--t/t4013/diff.diff_--patch-with-stat_-r_initial..side37
-rw-r--r--t/t4013/diff.diff_--patch-with-stat_initial..side37
-rw-r--r--t/t4013/diff.diff_--stat_initial..side6
-rw-r--r--t/t4013/diff.diff_-r_--stat_initial..side6
-rw-r--r--t/t4013/diff.diff_-r_initial..side32
-rw-r--r--t/t4013/diff.diff_initial..side32
-rw-r--r--t/t4013/diff.format-patch_--attach_--stdout_initial..master165
-rw-r--r--t/t4013/diff.format-patch_--attach_--stdout_initial..master^106
-rw-r--r--t/t4013/diff.format-patch_--attach_--stdout_initial..side60
-rw-r--r--t/t4013/diff.format-patch_--stdout_initial..master120
-rw-r--r--t/t4013/diff.format-patch_--stdout_initial..master^76
-rw-r--r--t/t4013/diff.format-patch_--stdout_initial..side45
-rw-r--r--t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_72
-rw-r--r--t/t4013/diff.log_--patch-with-stat_master127
-rw-r--r--t/t4013/diff.log_--patch-with-stat_master_--_dir_72
-rw-r--r--t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master197
-rw-r--r--t/t4013/diff.log_--root_--patch-with-stat_--summary_master165
-rw-r--r--t/t4013/diff.log_--root_--patch-with-stat_master159
-rw-r--r--t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master197
-rw-r--r--t/t4013/diff.log_--root_-p_master140
-rw-r--r--t/t4013/diff.log_--root_master32
-rw-r--r--t/t4013/diff.log_-SF_-p_master18
-rw-r--r--t/t4013/diff.log_-SF_master8
-rw-r--r--t/t4013/diff.log_-p_master113
-rw-r--r--t/t4013/diff.log_master32
-rw-r--r--t/t4013/diff.show_--patch-with-raw_side42
-rw-r--r--t/t4013/diff.show_--patch-with-stat_--summary_side44
-rw-r--r--t/t4013/diff.show_--patch-with-stat_side43
-rw-r--r--t/t4013/diff.show_--root_initial34
-rw-r--r--t/t4013/diff.show_--stat_--summary_side13
-rw-r--r--t/t4013/diff.show_--stat_side12
-rw-r--r--t/t4013/diff.show_initial7
-rw-r--r--t/t4013/diff.show_master36
-rw-r--r--t/t4013/diff.show_side38
-rw-r--r--t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_59
-rw-r--r--t/t4013/diff.whatchanged_--patch-with-stat_master114
-rw-r--r--t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_59
-rw-r--r--t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master197
-rw-r--r--t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master158
-rw-r--r--t/t4013/diff.whatchanged_--root_--patch-with-stat_master152
-rw-r--r--t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master197
-rw-r--r--t/t4013/diff.whatchanged_--root_-p_master133
-rw-r--r--t/t4013/diff.whatchanged_--root_master40
-rw-r--r--t/t4013/diff.whatchanged_-SF_-p_master18
-rw-r--r--t/t4013/diff.whatchanged_-SF_master9
-rw-r--r--t/t4013/diff.whatchanged_-p_master100
-rw-r--r--t/t4013/diff.whatchanged_master30
-rwxr-xr-xt/t6200-fmt-merge-msg.sh163
-rwxr-xr-xt/t8001-annotate.sh6
-rwxr-xr-xt/t9001-send-email.sh11
-rw-r--r--test-sha1.c47
-rwxr-xr-xtest-sha1.sh83
150 files changed, 6498 insertions, 675 deletions
diff --git a/.gitignore b/.gitignore
index 7b954d5..2bcc604 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,6 +46,7 @@ git-http-push
git-imap-send
git-index-pack
git-init-db
+git-instaweb
git-local-fetch
git-log
git-lost-found
diff --git a/Documentation/config.txt b/Documentation/config.txt
index a04c5ad..f075f19 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -91,6 +91,12 @@ core.warnAmbiguousRefs::
If true, git will warn you if the ref name you passed it is ambiguous
and might match multiple refs in the .git/refs/ tree. True by default.
+core.compression::
+ An integer -1..9, indicating the compression level for objects that
+ are not in a pack file. -1 is the zlib and git default. 0 means no
+ compression, and 1..9 are various speed/size tradeoffs, 9 being
+ slowest.
+
alias.*::
Command aliases for the gitlink:git[1] command wrapper - e.g.
after defining "alias.last = cat-file commit HEAD", the invocation
diff --git a/Documentation/git-instaweb.txt b/Documentation/git-instaweb.txt
new file mode 100644
index 0000000..7dd393b
--- /dev/null
+++ b/Documentation/git-instaweb.txt
@@ -0,0 +1,84 @@
+git-instaweb(1)
+===============
+
+NAME
+----
+git-instaweb - instantly browse your working repository in gitweb
+
+SYNOPSIS
+--------
+'git-instaweb' [--local] [--httpd=<httpd>] [--port=<port>] [--browser=<browser>]
+
+'git-instaweb' [--start] [--stop] [--restart]
+
+DESCRIPTION
+-----------
+A simple script to setup gitweb and a web server for browsing the local
+repository.
+
+OPTIONS
+-------
+
+-l|--local::
+ Only bind the web server to the local IP (127.0.0.1).
+
+-d|--httpd::
+ The HTTP daemon command-line that will be executed.
+ Command-line options may be specified here, and the
+ configuration file will be added at the end of the command-line.
+ Currently, lighttpd and apache2 are the only supported servers.
+ (Default: lighttpd)
+
+-m|--module-path::
+ The module path (only needed if httpd is Apache).
+ (Default: /usr/lib/apache2/modules)
+
+-p|--port::
+ The port number to bind the httpd to. (Default: 1234)
+
+-b|--browser::
+
+ The web browser command-line to execute to view the gitweb page.
+ If blank, the URL of the gitweb instance will be printed to
+ stdout. (Default: 'firefox')
+
+--start::
+ Start the httpd instance and exit. This does not generate
+ any of the configuration files for spawning a new instance.
+
+--stop::
+ Stop the httpd instance and exit. This does not generate
+ any of the configuration files for spawning a new instance,
+ nor does it close the browser.
+
+--restart::
+ Restart the httpd instance and exit. This does not generate
+ any of the configuration files for spawning a new instance.
+
+CONFIGURATION
+-------------
+
+You may specify configuration in your .git/config
+
+-----------------------------------------------------------------------
+[instaweb]
+ local = true
+ httpd = apache2 -f
+ port = 4321
+ browser = konqueror
+ modulepath = /usr/lib/apache2/modules
+
+-----------------------------------------------------------------------
+
+Author
+------
+Written by Eric Wong <normalperson@yhbt.net>
+
+Documentation
+--------------
+Documentation by Eric Wong <normalperson@yhbt.net>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
+
diff --git a/Makefile b/Makefile
index 76abcc4..202f261 100644
--- a/Makefile
+++ b/Makefile
@@ -131,7 +131,7 @@ SCRIPT_SH = \
SCRIPT_PERL = \
git-archimport.perl git-cvsimport.perl git-relink.perl \
- git-shortlog.perl git-fmt-merge-msg.perl git-rerere.perl \
+ git-shortlog.perl git-rerere.perl \
git-annotate.perl git-cvsserver.perl \
git-svnimport.perl git-mv.perl git-cvsexportcommit.perl \
git-send-email.perl
@@ -142,7 +142,7 @@ SCRIPT_PYTHON = \
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
$(patsubst %.py,%,$(SCRIPT_PYTHON)) \
- git-cherry-pick git-status
+ git-cherry-pick git-status git-instaweb
# The ones that do not have to link with lcrypto, lz nor xdiff.
SIMPLE_PROGRAMS = \
@@ -173,7 +173,8 @@ BUILT_INS = git-log$X git-whatchanged$X git-show$X git-update-ref$X \
git-ls-files$X git-ls-tree$X git-get-tar-commit-id$X \
git-read-tree$X git-commit-tree$X git-write-tree$X \
git-apply$X git-show-branch$X git-diff-files$X git-update-index$X \
- git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X
+ git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X \
+ git-fmt-merge-msg$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -229,7 +230,7 @@ BUILTIN_OBJS = \
builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \
- builtin-update-ref.o
+ builtin-update-ref.o builtin-fmt-merge-msg.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
@@ -545,6 +546,20 @@ git-status: git-commit
cp $< $@+
mv $@+ $@
+git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
+ rm -f $@ $@+
+ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
+ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
+ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
+ -e 's/@@NO_PYTHON@@/$(NO_PYTHON)/g' \
+ -e '/@@GITWEB_CGI@@/rgitweb/gitweb.cgi' \
+ -e '/@@GITWEB_CGI@@/d' \
+ -e '/@@GITWEB_CSS@@/rgitweb/gitweb.css' \
+ -e '/@@GITWEB_CSS@@/d' \
+ $@.sh > $@+
+ chmod +x $@+
+ mv $@+ $@
+
# These can record GIT_VERSION
git$X git.spec \
$(patsubst %.sh,%,$(SCRIPT_SH)) \
@@ -650,6 +665,12 @@ test-delta$X: test-delta.c diff-delta.o patch-delta.o
test-dump-cache-tree$X: dump-cache-tree.o $(GITLIBS)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
+test-sha1$X: test-sha1.o $(GITLIBS)
+ $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
+
+check-sha1:: test-sha1$X
+ ./test-sha1.sh
+
check:
for i in *.c; do sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; done
diff --git a/builtin-diff-files.c b/builtin-diff-files.c
index 5afc1d7..a655eea 100644
--- a/builtin-diff-files.c
+++ b/builtin-diff-files.c
@@ -36,6 +36,9 @@ int cmd_diff_files(int argc, const char **argv, char **envp)
usage(diff_files_usage);
argv++; argc--;
}
+ if (!rev.diffopt.output_format)
+ rev.diffopt.output_format = DIFF_FORMAT_RAW;
+
/*
* Make sure there are NO revision (i.e. pending object) parameter,
* rev.max_count is reasonable (0 <= n <= 3),
diff --git a/builtin-diff-index.c b/builtin-diff-index.c
index c42ef9a..b37c9e8 100644
--- a/builtin-diff-index.c
+++ b/builtin-diff-index.c
@@ -28,6 +28,9 @@ int cmd_diff_index(int argc, const char **argv, char **envp)
else
usage(diff_cache_usage);
}
+ if (!rev.diffopt.output_format)
+ rev.diffopt.output_format = DIFF_FORMAT_RAW;
+
/*
* Make sure there is one revision (i.e. pending object),
* and there is no revision filtering parameters.
diff --git a/builtin-diff-stages.c b/builtin-diff-stages.c
index 7c157ca..30931fe 100644
--- a/builtin-diff-stages.c
+++ b/builtin-diff-stages.c
@@ -85,6 +85,9 @@ int cmd_diff_stages(int ac, const char **av, char **envp)
ac--; av++;
}
+ if (!diff_options.output_format)
+ diff_options.output_format = DIFF_FORMAT_RAW;
+
if (ac < 3 ||
sscanf(av[1], "%d", &stage1) != 1 ||
! (0 <= stage1 && stage1 <= 3) ||
diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c
index 3409a39..ae1cde9 100644
--- a/builtin-diff-tree.c
+++ b/builtin-diff-tree.c
@@ -84,6 +84,9 @@ int cmd_diff_tree(int argc, const char **argv, char **envp)
usage(diff_tree_usage);
}
+ if (!opt->diffopt.output_format)
+ opt->diffopt.output_format = DIFF_FORMAT_RAW;
+
/*
* NOTE! We expect "a ^b" to be equal to "a..b", so we
* reverse the order of the objects if the second one
diff --git a/builtin-diff.c b/builtin-diff.c
index 99a2f76..d520c7c 100644
--- a/builtin-diff.c
+++ b/builtin-diff.c
@@ -39,8 +39,6 @@ static int builtin_diff_files(struct rev_info *revs,
revs->max_count = 3;
else if (!strcmp(arg, "-q"))
silent = 1;
- else if (!strcmp(arg, "--raw"))
- revs->diffopt.output_format = DIFF_FORMAT_RAW;
else
usage(builtin_diff_usage);
argv++; argc--;
@@ -56,7 +54,7 @@ static int builtin_diff_files(struct rev_info *revs,
3 < revs->max_count)
usage(builtin_diff_usage);
if (revs->max_count < 0 &&
- (revs->diffopt.output_format == DIFF_FORMAT_PATCH))
+ (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
revs->combine_merges = revs->dense_combined_merges = 1;
/*
* Backward compatibility wart - "diff-files -s" used to
@@ -107,14 +105,9 @@ static int builtin_diff_b_f(struct rev_info *revs,
/* Blob vs file in the working tree*/
struct stat st;
- while (1 < argc) {
- const char *arg = argv[1];
- if (!strcmp(arg, "--raw"))
- revs->diffopt.output_format = DIFF_FORMAT_RAW;
- else
- usage(builtin_diff_usage);
- argv++; argc--;
- }
+ if (argc > 1)
+ usage(builtin_diff_usage);
+
if (lstat(path, &st))
die("'%s': %s", path, strerror(errno));
if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
@@ -137,14 +130,9 @@ static int builtin_diff_blobs(struct rev_info *revs,
*/
unsigned mode = canon_mode(S_IFREG | 0644);
- while (1 < argc) {
- const char *arg = argv[1];
- if (!strcmp(arg, "--raw"))
- revs->diffopt.output_format = DIFF_FORMAT_RAW;
- else
- usage(builtin_diff_usage);
- argv++; argc--;
- }
+ if (argc > 1)
+ usage(builtin_diff_usage);
+
stuff_change(&revs->diffopt,
mode, mode,
blob[1].sha1, blob[0].sha1,
@@ -162,8 +150,6 @@ static int builtin_diff_index(struct rev_info *revs,
const char *arg = argv[1];
if (!strcmp(arg, "--cached"))
cached = 1;
- else if (!strcmp(arg, "--raw"))
- revs->diffopt.output_format = DIFF_FORMAT_RAW;
else
usage(builtin_diff_usage);
argv++; argc--;
@@ -185,14 +171,9 @@ static int builtin_diff_tree(struct rev_info *revs,
{
const unsigned char *(sha1[2]);
int swap = 0;
- while (1 < argc) {
- const char *arg = argv[1];
- if (!strcmp(arg, "--raw"))
- revs->diffopt.output_format = DIFF_FORMAT_RAW;
- else
- usage(builtin_diff_usage);
- argv++; argc--;
- }
+
+ if (argc > 1)
+ usage(builtin_diff_usage);
/* We saw two trees, ent[0] and ent[1].
* if ent[1] is unintesting, they are swapped
@@ -214,14 +195,9 @@ static int builtin_diff_combined(struct rev_info *revs,
const unsigned char (*parent)[20];
int i;
- while (1 < argc) {
- const char *arg = argv[1];
- if (!strcmp(arg, "--raw"))
- revs->diffopt.output_format = DIFF_FORMAT_RAW;
- else
- usage(builtin_diff_usage);
- argv++; argc--;
- }
+ if (argc > 1)
+ usage(builtin_diff_usage);
+
if (!revs->dense_combined_merges && !revs->combine_merges)
revs->dense_combined_merges = revs->combine_merges = 1;
parent = xmalloc(ents * sizeof(*parent));
@@ -276,9 +252,13 @@ int cmd_diff(int argc, const char **argv, char **envp)
git_config(git_diff_config);
init_revisions(&rev);
- rev.diffopt.output_format = DIFF_FORMAT_PATCH;
argc = setup_revisions(argc, argv, &rev, NULL);
+ if (!rev.diffopt.output_format) {
+ rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+ diff_setup_done(&rev.diffopt);
+ }
+
/* Do we have --cached and not have a pending object, then
* default to HEAD by hand. Eek.
*/
diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c
new file mode 100644
index 0000000..6527482
--- /dev/null
+++ b/builtin-fmt-merge-msg.c
@@ -0,0 +1,355 @@
+#include "cache.h"
+#include "commit.h"
+#include "diff.h"
+#include "revision.h"
+#include "tag.h"
+
+static const char *fmt_merge_msg_usage =
+ "git-fmt-merge-msg [--summary] [--no-summary] [--file <file>]";
+
+static int merge_summary = 0;
+
+static int fmt_merge_msg_config(const char *key, const char *value)
+{
+ if (!strcmp("merge.summary", key))
+ merge_summary = git_config_bool(key, value);
+ return 0;
+}
+
+struct list {
+ char **list;
+ void **payload;
+ unsigned nr, alloc;
+};
+
+static void append_to_list(struct list *list, char *value, void *payload)
+{
+ if (list->nr == list->alloc) {
+ list->alloc += 32;
+ list->list = realloc(list->list, sizeof(char *) * list->alloc);
+ list->payload = realloc(list->payload,
+ sizeof(char *) * list->alloc);
+ }
+ list->payload[list->nr] = payload;
+ list->list[list->nr++] = value;
+}
+
+static int find_in_list(struct list *list, char *value)
+{
+ int i;
+
+ for (i = 0; i < list->nr; i++)
+ if (!strcmp(list->list[i], value))
+ return i;
+
+ return -1;
+}
+
+static void free_list(struct list *list)
+{
+ int i;
+
+ if (list->alloc == 0)
+ return;
+
+ for (i = 0; i < list->nr; i++) {
+ free(list->list[i]);
+ if (list->payload[i])
+ free(list->payload[i]);
+ }
+ free(list->list);
+ free(list->payload);
+ list->nr = list->alloc = 0;
+}
+
+struct src_data {
+ struct list branch, tag, r_branch, generic;
+ int head_status;
+};
+
+static struct list srcs = { NULL, NULL, 0, 0};
+static struct list origins = { NULL, NULL, 0, 0};
+
+static int handle_line(char *line)
+{
+ int i, len = strlen(line);
+ unsigned char *sha1;
+ char *src, *origin;
+ struct src_data *src_data;
+
+ if (len < 43 || line[40] != '\t')
+ return 1;
+
+ if (!strncmp(line + 41, "not-for-merge", 13))
+ return 0;
+
+ if (line[41] != '\t')
+ return 2;
+
+ line[40] = 0;
+ sha1 = xmalloc(20);
+ i = get_sha1(line, sha1);
+ line[40] = '\t';
+ if (i)
+ return 3;
+
+ if (line[len - 1] == '\n')
+ line[len - 1] = 0;
+ line += 42;
+
+ src = strstr(line, " of ");
+ if (src) {
+ *src = 0;
+ src += 4;
+ } else
+ src = "HEAD";
+
+ i = find_in_list(&srcs, src);
+ if (i < 0) {
+ i = srcs.nr;
+ append_to_list(&srcs, strdup(src),
+ xcalloc(1, sizeof(struct src_data)));
+ }
+ src_data = srcs.payload[i];
+
+ if (!strncmp(line, "branch ", 7)) {
+ origin = strdup(line + 7);
+ append_to_list(&src_data->branch, origin, NULL);
+ src_data->head_status |= 2;
+ } else if (!strncmp(line, "tag ", 4)) {
+ origin = line;
+ append_to_list(&src_data->tag, strdup(origin + 4), NULL);
+ src_data->head_status |= 2;
+ } else if (!strncmp(line, "remote branch ", 14)) {
+ origin = strdup(line + 14);
+ append_to_list(&src_data->r_branch, origin, NULL);
+ src_data->head_status |= 2;
+ } else if (!strcmp(line, "HEAD")) {
+ origin = strdup(src);
+ src_data->head_status |= 1;
+ } else {
+ origin = strdup(src);
+ append_to_list(&src_data->generic, strdup(line), NULL);
+ src_data->head_status |= 2;
+ }
+
+ if (!strcmp(".", src) || !strcmp(src, origin)) {
+ int len = strlen(origin);
+ if (origin[0] == '\'' && origin[len - 1] == '\'') {
+ char *new_origin = malloc(len - 1);
+ memcpy(new_origin, origin + 1, len - 2);
+ new_origin[len - 1] = 0;
+ origin = new_origin;
+ } else
+ origin = strdup(origin);
+ } else {
+ char *new_origin = malloc(strlen(origin) + strlen(src) + 5);
+ sprintf(new_origin, "%s of %s", origin, src);
+ origin = new_origin;
+ }
+ append_to_list(&origins, origin, sha1);
+ return 0;
+}
+
+static void print_joined(const char *singular, const char *plural,
+ struct list *list)
+{
+ if (list->nr == 0)
+ return;
+ if (list->nr == 1) {
+ printf("%s%s", singular, list->list[0]);
+ } else {
+ int i;
+ printf("%s", plural);
+ for (i = 0; i < list->nr - 1; i++)
+ printf("%s%s", i > 0 ? ", " : "", list->list[i]);
+ printf(" and %s", list->list[list->nr - 1]);
+ }
+}
+
+static void shortlog(const char *name, unsigned char *sha1,
+ struct commit *head, struct rev_info *rev, int limit)
+{
+ int i, count = 0;
+ struct commit *commit;
+ struct object *branch;
+ struct list subjects = { NULL, NULL, 0, 0 };
+ int flags = UNINTERESTING | TREECHANGE | SEEN | SHOWN | ADDED;
+
+ branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
+ if (!branch || branch->type != TYPE_COMMIT)
+ return;
+
+ setup_revisions(0, NULL, rev, NULL);
+ rev->ignore_merges = 1;
+ add_pending_object(rev, branch, name);
+ add_pending_object(rev, &head->object, "^HEAD");
+ head->object.flags |= UNINTERESTING;
+ prepare_revision_walk(rev);
+ while ((commit = get_revision(rev)) != NULL) {
+ char *oneline, *bol, *eol;
+
+ /* ignore merges */
+ if (commit->parents && commit->parents->next)
+ continue;
+
+ count++;
+ if (subjects.nr > limit)
+ continue;
+
+ bol = strstr(commit->buffer, "\n\n");
+ if (!bol) {
+ append_to_list(&subjects, strdup(sha1_to_hex(
+ commit->object.sha1)),
+ NULL);
+ continue;
+ }
+
+ bol += 2;
+ eol = strchr(bol, '\n');
+
+ if (eol) {
+ int len = eol - bol;
+ oneline = malloc(len + 1);
+ memcpy(oneline, bol, len);
+ oneline[len] = 0;
+ } else
+ oneline = strdup(bol);
+ append_to_list(&subjects, oneline, NULL);
+ }
+
+ if (count > limit)
+ printf("\n* %s: (%d commits)\n", name, count);
+ else
+ printf("\n* %s:\n", name);
+
+ for (i = 0; i < subjects.nr; i++)
+ if (i >= limit)
+ printf(" ...\n");
+ else
+ printf(" %s\n", subjects.list[i]);
+
+ clear_commit_marks((struct commit *)branch, flags);
+ clear_commit_marks(head, flags);
+ free_commit_list(rev->commits);
+ rev->commits = NULL;
+ rev->pending.nr = 0;
+
+ free_list(&subjects);
+}
+
+int cmd_fmt_merge_msg(int argc, char **argv, char **envp)
+{
+ int limit = 20, i = 0;
+ char line[1024];
+ FILE *in = stdin;
+ const char *sep = "";
+ unsigned char head_sha1[20];
+ const char *head, *current_branch;
+
+ git_config(fmt_merge_msg_config);
+
+ while (argc > 1) {
+ if (!strcmp(argv[1], "--summary"))
+ merge_summary = 1;
+ else if (!strcmp(argv[1], "--no-summary"))
+ merge_summary = 0;
+ else if (!strcmp(argv[1], "-F") || !strcmp(argv[1], "--file")) {
+ if (argc < 2)
+ die ("Which file?");
+ if (!strcmp(argv[2], "-"))
+ in = stdin;
+ else {
+ fclose(in);
+ in = fopen(argv[2], "r");
+ }
+ argc--; argv++;
+ } else
+ break;
+ argc--; argv++;
+ }
+
+ if (argc > 1)
+ usage(fmt_merge_msg_usage);
+
+ /* get current branch */
+ head = strdup(git_path("HEAD"));
+ current_branch = resolve_ref(head, head_sha1, 1);
+ current_branch += strlen(head) - 4;
+ free((char *)head);
+ if (!strncmp(current_branch, "refs/heads/", 11))
+ current_branch += 11;
+
+ while (fgets(line, sizeof(line), in)) {
+ i++;
+ if (line[0] == 0)
+ continue;
+ if (handle_line(line))
+ die ("Error in line %d: %s", i, line);
+ }
+
+ printf("Merge ");
+ for (i = 0; i < srcs.nr; i++) {
+ struct src_data *src_data = srcs.payload[i];
+ const char *subsep = "";
+
+ printf(sep);
+ sep = "; ";
+
+ if (src_data->head_status == 1) {
+ printf(srcs.list[i]);
+ continue;
+ }
+ if (src_data->head_status == 3) {
+ subsep = ", ";
+ printf("HEAD");
+ }
+ if (src_data->branch.nr) {
+ printf(subsep);
+ subsep = ", ";
+ print_joined("branch ", "branches ", &src_data->branch);
+ }
+ if (src_data->r_branch.nr) {
+ printf(subsep);
+ subsep = ", ";
+ print_joined("remote branch ", "remote branches ",
+ &src_data->r_branch);
+ }
+ if (src_data->tag.nr) {
+ printf(subsep);
+ subsep = ", ";
+ print_joined("tag ", "tags ", &src_data->tag);
+ }
+ if (src_data->generic.nr) {
+ printf(subsep);
+ print_joined("commit ", "commits ", &src_data->generic);
+ }
+ if (strcmp(".", srcs.list[i]))
+ printf(" of %s", srcs.list[i]);
+ }
+
+ if (!strcmp("master", current_branch))
+ putchar('\n');
+ else
+ printf(" into %s\n", current_branch);
+
+ if (merge_summary) {
+ struct commit *head;
+ struct rev_info rev;
+
+ head = lookup_commit(head_sha1);
+ init_revisions(&rev);
+ rev.commit_format = CMIT_FMT_ONELINE;
+ rev.ignore_merges = 1;
+ rev.limited = 1;
+
+ for (i = 0; i < origins.nr; i++)
+ shortlog(origins.list[i], origins.payload[i],
+ head, &rev, limit);
+ }
+
+ /* No cleanup yet; is standalone anyway */
+
+ return 0;
+}
+
diff --git a/builtin-grep.c b/builtin-grep.c
index 2e7986c..6973c66 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -446,7 +446,7 @@ static int exec_grep(int argc, const char **argv)
static int external_grep(struct grep_opt *opt, const char **paths, int cached)
{
- int i, nr, argc, hit, len;
+ int i, nr, argc, hit, len, status;
const char *argv[MAXARGS+1];
char randarg[ARGBUF];
char *argptr = randarg;
@@ -536,12 +536,17 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
argv[argc++] = name;
if (argc < MAXARGS)
continue;
- hit += exec_grep(argc, argv);
+ status = exec_grep(argc, argv);
+ if (0 < status)
+ hit = 1;
argc = nr;
}
- if (argc > nr)
- hit += exec_grep(argc, argv);
- return 0;
+ if (argc > nr) {
+ status = exec_grep(argc, argv);
+ if (0 < status)
+ hit = 1;
+ }
+ return hit;
}
static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
@@ -652,6 +657,13 @@ static int grep_object(struct grep_opt *opt, const char **paths,
static const char builtin_grep_usage[] =
"git-grep <option>* <rev>* [-e] <pattern> [<path>...]";
+static const char emsg_invalid_context_len[] =
+"%s: invalid context length argument";
+static const char emsg_missing_context_len[] =
+"missing context length argument";
+static const char emsg_missing_argument[] =
+"option requires an argument -%s";
+
int cmd_grep(int argc, const char **argv, char **envp)
{
int hit = 0;
@@ -759,7 +771,7 @@ int cmd_grep(int argc, const char **argv, char **envp)
case 'A': case 'B': case 'C':
if (!arg[2]) {
if (argc <= 1)
- usage(builtin_grep_usage);
+ die(emsg_missing_context_len);
scan = *++argv;
argc--;
}
@@ -771,7 +783,7 @@ int cmd_grep(int argc, const char **argv, char **envp)
break;
}
if (sscanf(scan, "%u", &num) != 1)
- usage(builtin_grep_usage);
+ die(emsg_invalid_context_len, scan);
switch (arg[1]) {
case 'A':
opt.post_context = num;
@@ -790,7 +802,7 @@ int cmd_grep(int argc, const char **argv, char **envp)
int lno = 0;
char buf[1024];
if (argc <= 1)
- usage(builtin_grep_usage);
+ die(emsg_missing_argument, arg);
patterns = fopen(argv[1], "r");
if (!patterns)
die("'%s': %s", argv[1], strerror(errno));
@@ -815,10 +827,14 @@ int cmd_grep(int argc, const char **argv, char **envp)
argc--;
continue;
}
- usage(builtin_grep_usage);
+ die(emsg_missing_argument, arg);
}
- if (!strcmp("--", arg))
+ if (!strcmp("--", arg)) {
+ /* later processing wants to have this at argv[1] */
+ argv--;
+ argc++;
break;
+ }
if (*arg == '-')
usage(builtin_grep_usage);
diff --git a/builtin-log.c b/builtin-log.c
index f9515a8..864c6cd 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -14,25 +14,22 @@
/* this is in builtin-diff.c */
void add_head(struct rev_info *revs);
-static int cmd_log_wc(int argc, const char **argv, char **envp,
+static void cmd_log_init(int argc, const char **argv, char **envp,
struct rev_info *rev)
{
- struct commit *commit;
-
rev->abbrev = DEFAULT_ABBREV;
rev->commit_format = CMIT_FMT_DEFAULT;
rev->verbose_header = 1;
argc = setup_revisions(argc, argv, rev, "HEAD");
- if (rev->always_show_header) {
- if (rev->diffopt.pickaxe || rev->diffopt.filter) {
- rev->always_show_header = 0;
- if (rev->diffopt.output_format == DIFF_FORMAT_RAW)
- rev->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT;
- }
- }
-
+ if (rev->diffopt.pickaxe || rev->diffopt.filter)
+ rev->always_show_header = 0;
if (argc > 1)
die("unrecognized argument: %s", argv[1]);
+}
+
+static int cmd_log_walk(struct rev_info *rev)
+{
+ struct commit *commit;
prepare_revision_walk(rev);
setup_pager();
@@ -54,7 +51,10 @@ int cmd_whatchanged(int argc, const char **argv, char **envp)
rev.diff = 1;
rev.diffopt.recursive = 1;
rev.simplify_history = 0;
- return cmd_log_wc(argc, argv, envp, &rev);
+ cmd_log_init(argc, argv, envp, &rev);
+ if (!rev.diffopt.output_format)
+ rev.diffopt.output_format = DIFF_FORMAT_RAW;
+ return cmd_log_walk(&rev);
}
int cmd_show(int argc, const char **argv, char **envp)
@@ -69,7 +69,8 @@ int cmd_show(int argc, const char **argv, char **envp)
rev.always_show_header = 1;
rev.ignore_merges = 0;
rev.no_walk = 1;
- return cmd_log_wc(argc, argv, envp, &rev);
+ cmd_log_init(argc, argv, envp, &rev);
+ return cmd_log_walk(&rev);
}
int cmd_log(int argc, const char **argv, char **envp)
@@ -78,8 +79,8 @@ int cmd_log(int argc, const char **argv, char **envp)
init_revisions(&rev);
rev.always_show_header = 1;
- rev.diffopt.recursive = 1;
- return cmd_log_wc(argc, argv, envp, &rev);
+ cmd_log_init(argc, argv, envp, &rev);
+ return cmd_log_walk(&rev);
}
static int istitlechar(char c)
@@ -237,11 +238,10 @@ int cmd_format_patch(int argc, const char **argv, char **envp)
rev.commit_format = CMIT_FMT_EMAIL;
rev.verbose_header = 1;
rev.diff = 1;
- rev.diffopt.with_raw = 0;
- rev.diffopt.with_stat = 1;
rev.combine_merges = 0;
rev.ignore_merges = 1;
- rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+ rev.diffopt.msg_sep = "";
+ rev.diffopt.recursive = 1;
git_config(git_format_config);
rev.extra_headers = extra_headers;
@@ -312,6 +312,9 @@ int cmd_format_patch(int argc, const char **argv, char **envp)
if (argc > 1)
die ("unrecognized argument: %s", argv[1]);
+ if (!rev.diffopt.output_format)
+ rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH;
+
if (output_directory) {
if (use_stdout)
die("standard output, or directory, which one?");
diff --git a/builtin.h b/builtin.h
index f12d5e6..d9e5483 100644
--- a/builtin.h
+++ b/builtin.h
@@ -49,6 +49,7 @@ extern int cmd_cat_file(int argc, const char **argv, char **envp);
extern int cmd_rev_parse(int argc, const char **argv, char **envp);
extern int cmd_update_index(int argc, const char **argv, char **envp);
extern int cmd_update_ref(int argc, const char **argv, char **envp);
+extern int cmd_fmt_merge_msg(int argc, const char **argv, char **envp);
extern int cmd_write_tree(int argc, const char **argv, char **envp);
extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
diff --git a/cache.h b/cache.h
index 8719939..7b5c91c 100644
--- a/cache.h
+++ b/cache.h
@@ -183,6 +183,7 @@ extern int log_all_ref_updates;
extern int warn_ambiguous_refs;
extern int shared_repository;
extern const char *apply_default_whitespace;
+extern int zlib_compression_level;
#define GIT_REPO_VERSION 0
extern int repository_format_version;
@@ -321,13 +322,17 @@ struct ref {
char name[FLEX_ARRAY]; /* more */
};
+#define REF_NORMAL (1u << 0)
+#define REF_HEADS (1u << 1)
+#define REF_TAGS (1u << 2)
+
extern int git_connect(int fd[2], char *url, const char *prog);
extern int finish_connect(pid_t pid);
extern int path_match(const char *path, int nr, char **match);
extern int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
int nr_refspec, char **refspec, int all);
extern int get_ack(int fd, unsigned char *result_sha1);
-extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, int ignore_funny);
+extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags);
extern int server_supports(const char *feature);
extern struct packed_git *parse_pack_index(unsigned char *sha1);
diff --git a/combine-diff.c b/combine-diff.c
index 2254221..caffb92 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -702,7 +702,7 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
const char *abb;
if (rev->loginfo)
- show_log(rev, rev->loginfo, "\n");
+ show_log(rev, opt->msg_sep);
dump_quoted_path(dense ? "diff --cc " : "diff --combined ", elem->path);
printf("index ");
for (i = 0; i < num_parent; i++) {
@@ -770,9 +770,9 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re
inter_name_termination = 0;
if (rev->loginfo)
- show_log(rev, rev->loginfo, "\n");
+ show_log(rev, opt->msg_sep);
- if (opt->output_format == DIFF_FORMAT_RAW) {
+ if (opt->output_format & DIFF_FORMAT_RAW) {
offset = strlen(COLONS) - num_parent;
if (offset < 0)
offset = 0;
@@ -792,8 +792,7 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re
printf(" %s ", diff_unique_abbrev(p->sha1, opt->abbrev));
}
- if (opt->output_format == DIFF_FORMAT_RAW ||
- opt->output_format == DIFF_FORMAT_NAME_STATUS) {
+ if (opt->output_format & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS)) {
for (i = 0; i < num_parent; i++)
putchar(p->parent[i].status);
putchar(inter_name_termination);
@@ -819,17 +818,12 @@ void show_combined_diff(struct combine_diff_path *p,
struct diff_options *opt = &rev->diffopt;
if (!p->len)
return;
- switch (opt->output_format) {
- case DIFF_FORMAT_RAW:
- case DIFF_FORMAT_NAME_STATUS:
- case DIFF_FORMAT_NAME:
+ if (opt->output_format & (DIFF_FORMAT_RAW |
+ DIFF_FORMAT_NAME |
+ DIFF_FORMAT_NAME_STATUS)) {
show_raw_diff(p, num_parent, rev);
- return;
- case DIFF_FORMAT_PATCH:
+ } else if (opt->output_format & DIFF_FORMAT_PATCH) {
show_patch_diff(p, num_parent, dense, rev);
- return;
- default:
- return;
}
}
@@ -842,22 +836,20 @@ void diff_tree_combined(const unsigned char *sha1,
struct diff_options *opt = &rev->diffopt;
struct diff_options diffopts;
struct combine_diff_path *p, *paths = NULL;
- int i, num_paths;
- int do_diffstat;
+ int i, num_paths, needsep, show_log_first;
- do_diffstat = (opt->output_format == DIFF_FORMAT_DIFFSTAT ||
- opt->with_stat);
diffopts = *opt;
- diffopts.with_raw = 0;
- diffopts.with_stat = 0;
+ diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
diffopts.recursive = 1;
+ show_log_first = !!rev->loginfo;
+ needsep = 0;
/* find set of paths that everybody touches */
for (i = 0; i < num_parent; i++) {
/* show stat against the first parent even
* when doing combined diff.
*/
- if (i == 0 && do_diffstat)
+ if (i == 0 && opt->output_format & DIFF_FORMAT_DIFFSTAT)
diffopts.output_format = DIFF_FORMAT_DIFFSTAT;
else
diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
@@ -865,12 +857,12 @@ void diff_tree_combined(const unsigned char *sha1,
diffcore_std(&diffopts);
paths = intersect_paths(paths, i, num_parent);
- if (do_diffstat && rev->loginfo)
- show_log(rev, rev->loginfo,
- opt->with_stat ? "---\n" : "\n");
+ if (show_log_first && i == 0) {
+ show_log(rev, opt->msg_sep);
+ if (rev->verbose_header && opt->output_format)
+ putchar(opt->line_termination);
+ }
diff_flush(&diffopts);
- if (opt->with_stat)
- putchar('\n');
}
/* find out surviving paths */
@@ -879,17 +871,25 @@ void diff_tree_combined(const unsigned char *sha1,
num_paths++;
}
if (num_paths) {
- if (opt->with_raw) {
- int saved_format = opt->output_format;
- opt->output_format = DIFF_FORMAT_RAW;
+ if (opt->output_format & (DIFF_FORMAT_RAW |
+ DIFF_FORMAT_NAME |
+ DIFF_FORMAT_NAME_STATUS)) {
for (p = paths; p; p = p->next) {
- show_combined_diff(p, num_parent, dense, rev);
+ if (p->len)
+ show_raw_diff(p, num_parent, rev);
}
- opt->output_format = saved_format;
- putchar(opt->line_termination);
+ needsep = 1;
}
- for (p = paths; p; p = p->next) {
- show_combined_diff(p, num_parent, dense, rev);
+ else if (opt->output_format & DIFF_FORMAT_DIFFSTAT)
+ needsep = 1;
+ if (opt->output_format & DIFF_FORMAT_PATCH) {
+ if (needsep)
+ putchar(opt->line_termination);
+ for (p = paths; p; p = p->next) {
+ if (p->len)
+ show_patch_diff(p, num_parent, dense,
+ rev);
+ }
}
}
diff --git a/config.c b/config.c
index ec44827..8445f7d 100644
--- a/config.c
+++ b/config.c
@@ -244,9 +244,9 @@ int git_config_bool(const char *name, const char *value)
return 1;
if (!*value)
return 0;
- if (!strcasecmp(value, "true"))
+ if (!strcasecmp(value, "true") || !strcasecmp(value, "yes"))
return 1;
- if (!strcasecmp(value, "false"))
+ if (!strcasecmp(value, "false") || !strcasecmp(value, "no"))
return 0;
return git_config_int(name, value) != 0;
}
@@ -279,6 +279,16 @@ int git_default_config(const char *var, const char *value)
return 0;
}
+ if (!strcmp(var, "core.compression")) {
+ int level = git_config_int(var, value);
+ if (level == -1)
+ level = Z_DEFAULT_COMPRESSION;
+ else if (level < 0 || level > Z_BEST_COMPRESSION)
+ die("bad zlib compression level %d", level);
+ zlib_compression_level = level;
+ return 0;
+ }
+
if (!strcmp(var, "user.name")) {
strlcpy(git_default_name, value, sizeof(git_default_name));
return 0;
diff --git a/connect.c b/connect.c
index 9a87bd9..4422a0d 100644
--- a/connect.c
+++ b/connect.c
@@ -12,11 +12,40 @@
static char *server_capabilities = NULL;
+static int check_ref(const char *name, int len, unsigned int flags)
+{
+ if (!flags)
+ return 1;
+
+ if (len > 45 || memcmp(name, "refs/", 5))
+ return 0;
+
+ /* Skip the "refs/" part */
+ name += 5;
+ len -= 5;
+
+ /* REF_NORMAL means that we don't want the magic fake tag refs */
+ if ((flags & REF_NORMAL) && check_ref_format(name) < 0)
+ return 0;
+
+ /* REF_HEADS means that we want regular branch heads */
+ if ((flags & REF_HEADS) && !memcmp(name, "heads/", 6))
+ return 1;
+
+ /* REF_TAGS means that we want tags */
+ if ((flags & REF_TAGS) && !memcmp(name, "tags/", 5))
+ return 1;
+
+ /* All type bits clear means that we are ok with anything */
+ return !(flags & ~REF_NORMAL);
+}
+
/*
* Read all the refs from the other end
*/
struct ref **get_remote_heads(int in, struct ref **list,
- int nr_match, char **match, int ignore_funny)
+ int nr_match, char **match,
+ unsigned int flags)
{
*list = NULL;
for (;;) {
@@ -43,10 +72,8 @@ struct ref **get_remote_heads(int in, struct ref **list,
server_capabilities = strdup(name + name_len + 1);
}
- if (ignore_funny && 45 < len && !memcmp(name, "refs/", 5) &&
- check_ref_format(name + 5))
+ if (!check_ref(name, name_len, flags))
continue;
-
if (nr_match && !path_match(name, nr_match, match))
continue;
ref = xcalloc(1, sizeof(*ref) + len - 40);
diff --git a/contrib/emacs/vc-git.el b/contrib/emacs/vc-git.el
index 2453cdc..3f6ed69 100644
--- a/contrib/emacs/vc-git.el
+++ b/contrib/emacs/vc-git.el
@@ -95,16 +95,17 @@
"Register FILE into the git version-control system."
(vc-git--run-command file "update-index" "--add" "--"))
-(defun vc-git-print-log (file)
+(defun vc-git-print-log (file &optional buffer)
(let ((name (file-relative-name file))
(coding-system-for-read git-commits-coding-system))
- (vc-do-command nil 'async "git" name "rev-list" "--pretty" "HEAD" "--")))
+ (vc-do-command buffer 'async "git" name "rev-list" "--pretty" "HEAD" "--")))
-(defun vc-git-diff (file &optional rev1 rev2)
- (let ((name (file-relative-name file)))
+(defun vc-git-diff (file &optional rev1 rev2 buffer)
+ (let ((name (file-relative-name file))
+ (buf (or buffer "*vc-diff*")))
(if (and rev1 rev2)
- (vc-do-command "*vc-diff*" 0 "git" name "diff-tree" "-p" rev1 rev2 "--")
- (vc-do-command "*vc-diff*" 0 "git" name "diff-index" "-p" (or rev1 "HEAD") "--"))
+ (vc-do-command buf 0 "git" name "diff-tree" "-p" rev1 rev2 "--")
+ (vc-do-command buf 0 "git" name "diff-index" "-p" (or rev1 "HEAD") "--"))
; git-diff-index doesn't set exit status like diff does
(if (vc-git-workfile-unchanged-p file) 0 1)))
diff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl
index 1e19aa1..8bc4188 100755
--- a/contrib/git-svn/git-svn.perl
+++ b/contrib/git-svn/git-svn.perl
@@ -2617,7 +2617,7 @@ sub libsvn_connect {
sub libsvn_get_file {
my ($gui, $f, $rev) = @_;
my $p = $f;
- return unless ($p =~ s#^\Q$SVN_PATH\E/?##);
+ return unless ($p =~ s#^\Q$SVN_PATH\E/##);
my ($hash, $pid, $in, $out);
my $pool = SVN::Pool->new;
diff --git a/csum-file.c b/csum-file.c
index ebaad03..6a7b40f 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -122,7 +122,7 @@ int sha1write_compressed(struct sha1file *f, void *in, unsigned int size)
void *out;
memset(&stream, 0, sizeof(stream));
- deflateInit(&stream, Z_DEFAULT_COMPRESSION);
+ deflateInit(&stream, zlib_compression_level);
maxsize = deflateBound(&stream, size);
out = xmalloc(maxsize);
diff --git a/diff.c b/diff.c
index 5a71489..507e401 100644
--- a/diff.c
+++ b/diff.c
@@ -583,7 +583,7 @@ static unsigned char *deflate_it(char *data,
z_stream stream;
memset(&stream, 0, sizeof(stream));
- deflateInit(&stream, Z_BEST_COMPRESSION);
+ deflateInit(&stream, zlib_compression_level);
bound = deflateBound(&stream, size);
deflated = xmalloc(bound);
stream.next_out = deflated;
@@ -1420,11 +1420,11 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)
void diff_setup(struct diff_options *options)
{
memset(options, 0, sizeof(*options));
- options->output_format = DIFF_FORMAT_RAW;
options->line_termination = '\n';
options->break_opt = -1;
options->rename_limit = -1;
options->context = 3;
+ options->msg_sep = "";
options->change = diff_change;
options->add_remove = diff_addremove;
@@ -1438,22 +1438,28 @@ int diff_setup_done(struct diff_options *options)
(0 <= options->rename_limit && !options->detect_rename))
return -1;
+ if (options->output_format & (DIFF_FORMAT_NAME |
+ DIFF_FORMAT_NAME_STATUS |
+ DIFF_FORMAT_CHECKDIFF |
+ DIFF_FORMAT_NO_OUTPUT))
+ options->output_format &= ~(DIFF_FORMAT_RAW |
+ DIFF_FORMAT_DIFFSTAT |
+ DIFF_FORMAT_SUMMARY |
+ DIFF_FORMAT_PATCH);
+
/*
* These cases always need recursive; we do not drop caller-supplied
* recursive bits for other formats here.
*/
- if ((options->output_format == DIFF_FORMAT_PATCH) ||
- (options->output_format == DIFF_FORMAT_DIFFSTAT) ||
- (options->output_format == DIFF_FORMAT_CHECKDIFF))
+ if (options->output_format & (DIFF_FORMAT_PATCH |
+ DIFF_FORMAT_DIFFSTAT |
+ DIFF_FORMAT_CHECKDIFF))
options->recursive = 1;
-
/*
- * These combinations do not make sense.
+ * Also pickaxe would not work very well if you do not say recursive
*/
- if (options->output_format == DIFF_FORMAT_RAW)
- options->with_raw = 0;
- if (options->output_format == DIFF_FORMAT_DIFFSTAT)
- options->with_stat = 0;
+ if (options->pickaxe)
+ options->recursive = 1;
if (options->detect_rename && options->rename_limit < 0)
options->rename_limit = diff_rename_limit_default;
@@ -1526,22 +1532,22 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
{
const char *arg = av[0];
if (!strcmp(arg, "-p") || !strcmp(arg, "-u"))
- options->output_format = DIFF_FORMAT_PATCH;
+ options->output_format |= DIFF_FORMAT_PATCH;
else if (opt_arg(arg, 'U', "unified", &options->context))
- options->output_format = DIFF_FORMAT_PATCH;
+ options->output_format |= DIFF_FORMAT_PATCH;
+ else if (!strcmp(arg, "--raw"))
+ options->output_format |= DIFF_FORMAT_RAW;
else if (!strcmp(arg, "--patch-with-raw")) {
- options->output_format = DIFF_FORMAT_PATCH;
- options->with_raw = 1;
+ options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_RAW;
}
else if (!strcmp(arg, "--stat"))
- options->output_format = DIFF_FORMAT_DIFFSTAT;
+ options->output_format |= DIFF_FORMAT_DIFFSTAT;
else if (!strcmp(arg, "--check"))
- options->output_format = DIFF_FORMAT_CHECKDIFF;
+ options->output_format |= DIFF_FORMAT_CHECKDIFF;
else if (!strcmp(arg, "--summary"))
- options->summary = 1;
+ options->output_format |= DIFF_FORMAT_SUMMARY;
else if (!strcmp(arg, "--patch-with-stat")) {
- options->output_format = DIFF_FORMAT_PATCH;
- options->with_stat = 1;
+ options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_DIFFSTAT;
}
else if (!strcmp(arg, "-z"))
options->line_termination = 0;
@@ -1550,19 +1556,20 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
else if (!strcmp(arg, "--full-index"))
options->full_index = 1;
else if (!strcmp(arg, "--binary")) {
- options->output_format = DIFF_FORMAT_PATCH;
+ options->output_format |= DIFF_FORMAT_PATCH;
options->full_index = options->binary = 1;
}
else if (!strcmp(arg, "--name-only"))
- options->output_format = DIFF_FORMAT_NAME;
+ options->output_format |= DIFF_FORMAT_NAME;
else if (!strcmp(arg, "--name-status"))
- options->output_format = DIFF_FORMAT_NAME_STATUS;
+ options->output_format |= DIFF_FORMAT_NAME_STATUS;
else if (!strcmp(arg, "-R"))
options->reverse_diff = 1;
else if (!strncmp(arg, "-S", 2))
options->pickaxe = arg + 2;
- else if (!strcmp(arg, "-s"))
- options->output_format = DIFF_FORMAT_NO_OUTPUT;
+ else if (!strcmp(arg, "-s")) {
+ options->output_format |= DIFF_FORMAT_NO_OUTPUT;
+ }
else if (!strncmp(arg, "-O", 2))
options->orderfile = arg + 2;
else if (!strncmp(arg, "--diff-filter=", 14))
@@ -1737,15 +1744,17 @@ const char *diff_unique_abbrev(const unsigned char *sha1, int len)
}
static void diff_flush_raw(struct diff_filepair *p,
- int line_termination,
- int inter_name_termination,
- struct diff_options *options,
- int output_format)
+ struct diff_options *options)
{
int two_paths;
char status[10];
int abbrev = options->abbrev;
const char *path_one, *path_two;
+ int inter_name_termination = '\t';
+ int line_termination = options->line_termination;
+
+ if (!line_termination)
+ inter_name_termination = 0;
path_one = p->one->path;
path_two = p->two->path;
@@ -1774,7 +1783,7 @@ static void diff_flush_raw(struct diff_filepair *p,
two_paths = 0;
break;
}
- if (output_format != DIFF_FORMAT_NAME_STATUS) {
+ if (!(options->output_format & DIFF_FORMAT_NAME_STATUS)) {
printf(":%06o %06o %s ",
p->one->mode, p->two->mode,
diff_unique_abbrev(p->one->sha1, abbrev));
@@ -1983,48 +1992,30 @@ static void diff_resolve_rename_copy(void)
diff_debug_queue("resolve-rename-copy done", q);
}
-static void flush_one_pair(struct diff_filepair *p,
- int diff_output_format,
- struct diff_options *options,
- struct diffstat_t *diffstat)
+static int check_pair_status(struct diff_filepair *p)
{
- int inter_name_termination = '\t';
- int line_termination = options->line_termination;
- if (!line_termination)
- inter_name_termination = 0;
-
switch (p->status) {
case DIFF_STATUS_UNKNOWN:
- break;
+ return 0;
case 0:
die("internal error in diff-resolve-rename-copy");
- break;
default:
- switch (diff_output_format) {
- case DIFF_FORMAT_DIFFSTAT:
- diff_flush_stat(p, options, diffstat);
- break;
- case DIFF_FORMAT_CHECKDIFF:
- diff_flush_checkdiff(p, options);
- break;
- case DIFF_FORMAT_PATCH:
- diff_flush_patch(p, options);
- break;
- case DIFF_FORMAT_RAW:
- case DIFF_FORMAT_NAME_STATUS:
- diff_flush_raw(p, line_termination,
- inter_name_termination,
- options, diff_output_format);
- break;
- case DIFF_FORMAT_NAME:
- diff_flush_name(p, line_termination);
- break;
- case DIFF_FORMAT_NO_OUTPUT:
- break;
- }
+ return 1;
}
}
+static void flush_one_pair(struct diff_filepair *p, struct diff_options *opt)
+{
+ int fmt = opt->output_format;
+
+ if (fmt & DIFF_FORMAT_CHECKDIFF)
+ diff_flush_checkdiff(p, opt);
+ else if (fmt & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS))
+ diff_flush_raw(p, opt);
+ else if (fmt & DIFF_FORMAT_NAME)
+ diff_flush_name(p, opt->line_termination);
+}
+
static void show_file_mode_name(const char *newdelete, struct diff_filespec *fs)
{
if (fs->mode)
@@ -2243,58 +2234,96 @@ int diff_flush_patch_id(struct diff_options *options, unsigned char *sha1)
return result;
}
-void diff_flush(struct diff_options *options)
+static int is_summary_empty(const struct diff_queue_struct *q)
{
- struct diff_queue_struct *q = &diff_queued_diff;
int i;
- int diff_output_format = options->output_format;
- struct diffstat_t *diffstat = NULL;
- if (diff_output_format == DIFF_FORMAT_DIFFSTAT || options->with_stat) {
- diffstat = xcalloc(sizeof (struct diffstat_t), 1);
- diffstat->xm.consume = diffstat_consume;
+ for (i = 0; i < q->nr; i++) {
+ const struct diff_filepair *p = q->queue[i];
+
+ switch (p->status) {
+ case DIFF_STATUS_DELETED:
+ case DIFF_STATUS_ADDED:
+ case DIFF_STATUS_COPIED:
+ case DIFF_STATUS_RENAMED:
+ return 0;
+ default:
+ if (p->score)
+ return 0;
+ if (p->one->mode && p->two->mode &&
+ p->one->mode != p->two->mode)
+ return 0;
+ break;
+ }
}
+ return 1;
+}
- if (options->with_raw) {
+void diff_flush(struct diff_options *options)
+{
+ struct diff_queue_struct *q = &diff_queued_diff;
+ int i, output_format = options->output_format;
+ int separator = 0;
+
+ /*
+ * Order: raw, stat, summary, patch
+ * or: name/name-status/checkdiff (other bits clear)
+ */
+ if (!q->nr)
+ goto free_queue;
+
+ if (output_format & (DIFF_FORMAT_RAW |
+ DIFF_FORMAT_NAME |
+ DIFF_FORMAT_NAME_STATUS |
+ DIFF_FORMAT_CHECKDIFF)) {
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
- flush_one_pair(p, DIFF_FORMAT_RAW, options, NULL);
+ if (check_pair_status(p))
+ flush_one_pair(p, options);
}
- putchar(options->line_termination);
+ separator++;
}
- if (options->with_stat) {
+
+ if (output_format & DIFF_FORMAT_DIFFSTAT) {
+ struct diffstat_t diffstat;
+
+ memset(&diffstat, 0, sizeof(struct diffstat_t));
+ diffstat.xm.consume = diffstat_consume;
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
- flush_one_pair(p, DIFF_FORMAT_DIFFSTAT, options,
- diffstat);
+ if (check_pair_status(p))
+ diff_flush_stat(p, options, &diffstat);
}
- show_stats(diffstat);
- free(diffstat);
- diffstat = NULL;
- if (options->summary)
- for (i = 0; i < q->nr; i++)
- diff_summary(q->queue[i]);
- if (options->stat_sep)
- fputs(options->stat_sep, stdout);
- else
- putchar(options->line_termination);
- }
- for (i = 0; i < q->nr; i++) {
- struct diff_filepair *p = q->queue[i];
- flush_one_pair(p, diff_output_format, options, diffstat);
+ show_stats(&diffstat);
+ separator++;
}
- if (diffstat) {
- show_stats(diffstat);
- free(diffstat);
+ if (output_format & DIFF_FORMAT_SUMMARY && !is_summary_empty(q)) {
+ for (i = 0; i < q->nr; i++)
+ diff_summary(q->queue[i]);
+ separator++;
}
- for (i = 0; i < q->nr; i++) {
- if (diffstat && options->summary)
- diff_summary(q->queue[i]);
- diff_free_filepair(q->queue[i]);
+ if (output_format & DIFF_FORMAT_PATCH) {
+ if (separator) {
+ if (options->stat_sep) {
+ /* attach patch instead of inline */
+ fputs(options->stat_sep, stdout);
+ } else {
+ putchar(options->line_termination);
+ }
+ }
+
+ for (i = 0; i < q->nr; i++) {
+ struct diff_filepair *p = q->queue[i];
+ if (check_pair_status(p))
+ diff_flush_patch(p, options);
+ }
}
+ for (i = 0; i < q->nr; i++)
+ diff_free_filepair(q->queue[i]);
+free_queue:
free(q->queue);
q->queue = NULL;
q->nr = q->alloc = 0;
diff --git a/diff.h b/diff.h
index d5068af..d557394 100644
--- a/diff.h
+++ b/diff.h
@@ -20,19 +20,31 @@ typedef void (*add_remove_fn_t)(struct diff_options *options,
const unsigned char *sha1,
const char *base, const char *path);
+#define DIFF_FORMAT_RAW 0x0001
+#define DIFF_FORMAT_DIFFSTAT 0x0002
+#define DIFF_FORMAT_SUMMARY 0x0004
+#define DIFF_FORMAT_PATCH 0x0008
+
+/* These override all above */
+#define DIFF_FORMAT_NAME 0x0010
+#define DIFF_FORMAT_NAME_STATUS 0x0020
+#define DIFF_FORMAT_CHECKDIFF 0x0040
+
+/* Same as output_format = 0 but we know that -s flag was given
+ * and we should not give default value to output_format.
+ */
+#define DIFF_FORMAT_NO_OUTPUT 0x0080
+
struct diff_options {
const char *filter;
const char *orderfile;
const char *pickaxe;
unsigned recursive:1,
- with_raw:1,
- with_stat:1,
tree_in_recursive:1,
binary:1,
full_index:1,
silent_on_remove:1,
find_copies_harder:1,
- summary:1,
color_diff:1;
int context;
int break_opt;
@@ -45,6 +57,7 @@ struct diff_options {
int rename_limit;
int setup;
int abbrev;
+ const char *msg_sep;
const char *stat_sep;
long xdl_opts;
@@ -151,15 +164,6 @@ extern void diffcore_std_no_resolve(struct diff_options *);
" show all files diff when -S is used and hit is found.\n"
extern int diff_queue_is_empty(void);
-
-#define DIFF_FORMAT_RAW 1
-#define DIFF_FORMAT_PATCH 2
-#define DIFF_FORMAT_NO_OUTPUT 3
-#define DIFF_FORMAT_NAME 4
-#define DIFF_FORMAT_NAME_STATUS 5
-#define DIFF_FORMAT_DIFFSTAT 6
-#define DIFF_FORMAT_CHECKDIFF 7
-
extern void diff_flush(struct diff_options*);
/* diff-raw status letters */
diff --git a/environment.c b/environment.c
index 3de8eb3..43823ff 100644
--- a/environment.c
+++ b/environment.c
@@ -20,6 +20,7 @@ int repository_format_version = 0;
char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
int shared_repository = PERM_UMASK;
const char *apply_default_whitespace = NULL;
+int zlib_compression_level = Z_DEFAULT_COMPRESSION;
static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
*git_graft_file;
diff --git a/git-annotate.perl b/git-annotate.perl
index a6a7a48..6db2f48 100755
--- a/git-annotate.perl
+++ b/git-annotate.perl
@@ -102,10 +102,10 @@ while (my $bound = pop @stack) {
push @revqueue, $head;
init_claim( defined $starting_rev ? $head : 'dirty');
unless (defined $starting_rev) {
- my $diff = open_pipe("git","diff","-R", "HEAD", "--",$filename)
+ my $diff = open_pipe("git","diff","HEAD", "--",$filename)
or die "Failed to call git diff to check for dirty state: $!";
- _git_diff_parse($diff, $head, "dirty", (
+ _git_diff_parse($diff, [$head], "dirty", (
'author' => gitvar_name("GIT_AUTHOR_IDENT"),
'author_date' => sprintf("%s +0000",time()),
)
@@ -154,14 +154,13 @@ sub handle_rev {
my %revinfo = git_commit_info($rev);
- foreach my $p (@{$revs{$rev}{'parents'}}) {
-
- git_diff_parse($p, $rev, %revinfo);
- push @revqueue, $p;
- }
+ if (exists $revs{$rev}{parents} &&
+ scalar @{$revs{$rev}{parents}} != 0) {
+ git_diff_parse($revs{$rev}{'parents'}, $rev, %revinfo);
+ push @revqueue, @{$revs{$rev}{'parents'}};
- if (scalar @{$revs{$rev}{parents}} == 0) {
+ } else {
# We must be at the initial rev here, so claim everything that is left.
for (my $i = 0; $i < @{$revs{$rev}{lines}}; $i++) {
if (ref ${$revs{$rev}{lines}}[$i] eq '' || ${$revs{$rev}{lines}}[$i][1] eq '') {
@@ -252,89 +251,171 @@ sub git_find_parent {
# Get a diff between the current revision and a parent.
# Record the commit information that results.
sub git_diff_parse {
- my ($parent, $rev, %revinfo) = @_;
+ my ($parents, $rev, %revinfo) = @_;
- my $diff = open_pipe("git-diff-tree","-M","-p",$rev,$parent,"--",
- $revs{$rev}{'filename'}, $revs{$parent}{'filename'})
+ my @filenames = ( $revs{$rev}{'filename'} );
+ foreach my $parent (@$parents) {
+ push @filenames, $revs{$parent}{'filename'};
+ }
+
+ my $diff = open_pipe("git-diff-tree","-M","-p","-c",$rev,"--",
+ @filenames )
or die "Failed to call git-diff for annotation: $!";
- _git_diff_parse($diff, $parent, $rev, %revinfo);
+ _git_diff_parse($diff, $parents, $rev, %revinfo);
close($diff);
}
sub _git_diff_parse {
- my ($diff, $parent, $rev, %revinfo) = @_;
+ my ($diff, $parents, $rev, %revinfo) = @_;
+
+ my $ri = 0;
- my ($ri, $pi) = (0,0);
my $slines = $revs{$rev}{'lines'};
- my @plines;
+ my (%plines, %pi);
my $gotheader = 0;
my ($remstart);
- my ($hunk_start, $hunk_index);
+ my $parent_count = @$parents;
+
+ my $diff_header_regexp = "^@";
+ $diff_header_regexp .= "@" x @$parents;
+ $diff_header_regexp .= ' -\d+,\d+' x @$parents;
+ $diff_header_regexp .= ' \+(\d+),\d+';
+
+ my %claim_regexps;
+ my $allparentplus = '^' . '\\+' x @$parents . '(.*)$';
+
+ {
+ my $i = 0;
+ foreach my $parent (@$parents) {
+
+ $pi{$parent} = 0;
+ my $r = '^' . '.' x @$parents . '(.*)$';
+ my $p = $r;
+ substr($p,$i+1, 1) = '\\+';
+
+ my $m = $r;
+ substr($m,$i+1, 1) = '-';
+
+ $claim_regexps{$parent}{plus} = $p;
+ $claim_regexps{$parent}{minus} = $m;
+
+ $plines{$parent} = [];
+
+ $i++;
+ }
+ }
+
+ DIFF:
while(<$diff>) {
chomp;
- if (m/^@@ -(\d+),(\d+) \+(\d+),(\d+)/) {
- $remstart = $1;
- # Adjust for 0-based arrays
- $remstart--;
- # Reinit hunk tracking.
- $hunk_start = $remstart;
- $hunk_index = 0;
+ if (m/$diff_header_regexp/) {
+ $remstart = $1 - 1;
+ # (0-based arrays)
+
$gotheader = 1;
- for (my $i = $ri; $i < $remstart; $i++) {
- $plines[$pi++] = $slines->[$i];
- $ri++;
+ printf("Copying from %d to %d\n", $ri, $remstart);
+ foreach my $parent (@$parents) {
+ for (my $i = $ri; $i < $remstart; $i++) {
+ $plines{$parent}[$pi{$parent}++] = $slines->[$i];
+ }
}
- next;
- } elsif (!$gotheader) {
- next;
- }
+ $ri = $remstart;
- if (m/^\+(.*)$/) {
- my $line = $1;
- $plines[$pi++] = [ $line, '', '', '', 0 ];
- next;
+ next DIFF;
- } elsif (m/^-(.*)$/) {
- my $line = $1;
- if (get_line($slines, $ri) eq $line) {
- # Found a match, claim
- claim_line($ri, $rev, $slines, %revinfo);
- } else {
- die sprintf("Sync error: %d/%d\n|%s\n|%s\n%s => %s\n",
- $ri, $hunk_start + $hunk_index,
- $line,
- get_line($slines, $ri),
- $rev, $parent);
- }
- $ri++;
+ } elsif (!$gotheader) {
+ # Skip over the leadin.
+ next DIFF;
+ }
- } elsif (m/^\\/) {
+ if (m/^\\/) {
;
# Skip \No newline at end of file.
# But this can be internationalized, so only look
# for an initial \
} else {
- if (substr($_,1) ne get_line($slines,$ri) ) {
- die sprintf("Line %d (%d) does not match:\n|%s\n|%s\n%s => %s\n",
- $hunk_start + $hunk_index, $ri,
- substr($_,1),
- get_line($slines,$ri),
- $rev, $parent);
+ my %claims = ();
+ my $negclaim = 0;
+ my $allclaimed = 0;
+ my $line;
+
+ if (m/$allparentplus/) {
+ claim_line($ri, $rev, $slines, %revinfo);
+ $allclaimed = 1;
+
+ }
+
+ PARENT:
+ foreach my $parent (keys %claim_regexps) {
+ my $m = $claim_regexps{$parent}{minus};
+ my $p = $claim_regexps{$parent}{plus};
+
+ if (m/$m/) {
+ $line = $1;
+ $plines{$parent}[$pi{$parent}++] = [ $line, '', '', '', 0 ];
+ $negclaim++;
+
+ } elsif (m/$p/) {
+ $line = $1;
+ if (get_line($slines, $ri) eq $line) {
+ # Found a match, claim
+ $claims{$parent}++;
+
+ } else {
+ die sprintf("Sync error: %d\n|%s\n|%s\n%s => %s\n",
+ $ri, $line,
+ get_line($slines, $ri),
+ $rev, $parent);
+ }
+ }
+ }
+
+ if (%claims) {
+ foreach my $parent (@$parents) {
+ next if $claims{$parent} || $allclaimed;
+ $plines{$parent}[$pi{$parent}++] = $slines->[$ri];
+ #[ $line, '', '', '', 0 ];
+ }
+ $ri++;
+
+ } elsif ($negclaim) {
+ next DIFF;
+
+ } else {
+ if (substr($_,scalar @$parents) ne get_line($slines,$ri) ) {
+ foreach my $parent (@$parents) {
+ printf("parent %s is on line %d\n", $parent, $pi{$parent});
+ }
+
+ die sprintf("Line %d, does not match:\n|%s|\n|%s|\n%s\n",
+ $ri,
+ substr($_,scalar @$parents),
+ get_line($slines,$ri), $rev);
+ }
+ foreach my $parent (@$parents) {
+ $plines{$parent}[$pi{$parent}++] = $slines->[$ri];
+ }
+ $ri++;
}
- $plines[$pi++] = $slines->[$ri++];
}
- $hunk_index++;
}
+
for (my $i = $ri; $i < @{$slines} ; $i++) {
- push @plines, $slines->[$ri++];
+ foreach my $parent (@$parents) {
+ push @{$plines{$parent}}, $slines->[$ri];
+ }
+ $ri++;
+ }
+
+ foreach my $parent (@$parents) {
+ $revs{$parent}{lines} = $plines{$parent};
}
- $revs{$parent}{lines} = \@plines;
return;
}
diff --git a/git-fmt-merge-msg.perl b/git-fmt-merge-msg.perl
deleted file mode 100755
index 5986e54..0000000
--- a/git-fmt-merge-msg.perl
+++ /dev/null
@@ -1,173 +0,0 @@
-#!/usr/bin/perl -w
-#
-# Copyright (c) 2005 Junio C Hamano
-#
-# Read .git/FETCH_HEAD and make a human readable merge message
-# by grouping branches and tags together to form a single line.
-
-use strict;
-
-my @src;
-my %src;
-sub andjoin {
- my ($label, $labels, $stuff) = @_;
- my $l = scalar @$stuff;
- my $m = '';
- if ($l == 0) {
- return ();
- }
- if ($l == 1) {
- $m = "$label$stuff->[0]";
- }
- else {
- $m = ("$labels" .
- join (', ', @{$stuff}[0..$l-2]) .
- " and $stuff->[-1]");
- }
- return ($m);
-}
-
-sub repoconfig {
- my ($val) = qx{git-repo-config --get merge.summary};
- return $val;
-}
-
-sub current_branch {
- my ($bra) = qx{git-symbolic-ref HEAD};
- chomp($bra);
- $bra =~ s|^refs/heads/||;
- if ($bra ne 'master') {
- $bra = " into $bra";
- } else {
- $bra = "";
- }
- return $bra;
-}
-
-sub shortlog {
- my ($tip) = @_;
- my @result;
- foreach ( qx{git-log --no-merges --topo-order --pretty=oneline $tip ^HEAD} ) {
- s/^[0-9a-f]{40}\s+//;
- push @result, $_;
- }
- die "git-log failed\n" if $?;
- return @result;
-}
-
-my @origin = ();
-while (<>) {
- my ($bname, $tname, $gname, $src, $sha1, $origin);
- chomp;
- s/^([0-9a-f]*) //;
- $sha1 = $1;
- next if (/^not-for-merge/);
- s/^ //;
- if (s/ of (.*)$//) {
- $src = $1;
- } else {
- # Pulling HEAD
- $src = $_;
- $_ = 'HEAD';
- }
- if (! exists $src{$src}) {
- push @src, $src;
- $src{$src} = {
- BRANCH => [],
- TAG => [],
- R_BRANCH => [],
- GENERIC => [],
- # &1 == has HEAD.
- # &2 == has others.
- HEAD_STATUS => 0,
- };
- }
- if (/^branch (.*)$/) {
- $origin = $1;
- push @{$src{$src}{BRANCH}}, $1;
- $src{$src}{HEAD_STATUS} |= 2;
- }
- elsif (/^tag (.*)$/) {
- $origin = $_;
- push @{$src{$src}{TAG}}, $1;
- $src{$src}{HEAD_STATUS} |= 2;
- }
- elsif (/^remote branch (.*)$/) {
- $origin = $1;
- push @{$src{$src}{R_BRANCH}}, $1;
- $src{$src}{HEAD_STATUS} |= 2;
- }
- elsif (/^HEAD$/) {
- $origin = $src;
- $src{$src}{HEAD_STATUS} |= 1;
- }
- else {
- push @{$src{$src}{GENERIC}}, $_;
- $src{$src}{HEAD_STATUS} |= 2;
- $origin = $src;
- }
- if ($src eq '.' || $src eq $origin) {
- $origin =~ s/^'(.*)'$/$1/;
- push @origin, [$sha1, "$origin"];
- }
- else {
- push @origin, [$sha1, "$origin of $src"];
- }
-}
-
-my @msg;
-for my $src (@src) {
- if ($src{$src}{HEAD_STATUS} == 1) {
- # Only HEAD is fetched, nothing else.
- push @msg, $src;
- next;
- }
- my @this;
- if ($src{$src}{HEAD_STATUS} == 3) {
- # HEAD is fetched among others.
- push @this, andjoin('', '', ['HEAD']);
- }
- push @this, andjoin("branch ", "branches ",
- $src{$src}{BRANCH});
- push @this, andjoin("remote branch ", "remote branches ",
- $src{$src}{R_BRANCH});
- push @this, andjoin("tag ", "tags ",
- $src{$src}{TAG});
- push @this, andjoin("commit ", "commits ",
- $src{$src}{GENERIC});
- my $this = join(', ', @this);
- if ($src ne '.') {
- $this .= " of $src";
- }
- push @msg, $this;
-}
-
-my $into = current_branch();
-
-print "Merge ", join("; ", @msg), $into, "\n";
-
-if (!repoconfig) {
- exit(0);
-}
-
-# We limit the merge message to the latst 20 or so per each branch.
-my $limit = 20;
-
-for (@origin) {
- my ($sha1, $name) = @$_;
- my @log = shortlog($sha1);
- if ($limit + 1 <= @log) {
- print "\n* $name: (" . scalar(@log) . " commits)\n";
- }
- else {
- print "\n* $name:\n";
- }
- my $cnt = 0;
- for my $log (@log) {
- if ($limit < ++$cnt) {
- print " ...\n";
- last;
- }
- print " $log";
- }
-}
diff --git a/git-instaweb.sh b/git-instaweb.sh
new file mode 100755
index 0000000..69aef3c
--- /dev/null
+++ b/git-instaweb.sh
@@ -0,0 +1,235 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Eric Wong
+#
+USAGE='[--start] [--stop] [--restart]
+ [--local] [--httpd=<httpd>] [--port=<port>] [--browser=<browser>]
+ [--module-path=<path> (for Apache2 only)]'
+
+. git-sh-setup
+
+case "$GIT_DIR" in
+/*)
+ fqgitdir="$GIT_DIR" ;;
+*)
+ fqgitdir="$PWD/$GIT_DIR" ;;
+esac
+
+local="`git repo-config --bool --get instaweb.local`"
+httpd="`git repo-config --get instaweb.httpd`"
+browser="`git repo-config --get instaweb.browser`"
+port=`git repo-config --get instaweb.port`
+module_path="`git repo-config --get instaweb.modulepath`"
+
+conf=$GIT_DIR/gitweb/httpd.conf
+
+# Defaults:
+
+# if installed, it doens't need further configuration (module_path)
+test -z "$httpd" && httpd='lighttpd -f'
+
+# probably the most popular browser among gitweb users
+test -z "$browser" && browser='firefox'
+
+# any untaken local port will do...
+test -z "$port" && port=1234
+
+start_httpd () {
+ httpd_only="`echo $httpd | cut -f1 -d' '`"
+ if test "`expr index $httpd_only /`" -eq '1' || \
+ which $httpd_only >/dev/null
+ then
+ $httpd $fqgitdir/gitweb/httpd.conf
+ else
+ # many httpds are installed in /usr/sbin or /usr/local/sbin
+ # these days and those are not in most users $PATHs
+ for i in /usr/local/sbin /usr/sbin
+ do
+ if test -x "$i/$httpd_only"
+ then
+ # don't quote $httpd, there can be
+ # arguments to it (-f)
+ $i/$httpd "$fqgitdir/gitweb/httpd.conf"
+ return
+ fi
+ done
+ fi
+}
+
+stop_httpd () {
+ test -f "$fqgitdir/pid" && kill `cat "$fqgitdir/pid"`
+}
+
+while case "$#" in 0) break ;; esac
+do
+ case "$1" in
+ --stop|stop)
+ stop_httpd
+ exit 0
+ ;;
+ --start|start)
+ start_httpd
+ exit 0
+ ;;
+ --restart|restart)
+ stop_httpd
+ start_httpd
+ exit 0
+ ;;
+ --local|-l)
+ local=true
+ ;;
+ -d|--httpd|--httpd=*)
+ case "$#,$1" in
+ *,*=*)
+ httpd=`expr "$1" : '-[^=]*=\(.*\)'` ;;
+ 1,*)
+ usage ;;
+ *)
+ httpd="$2"
+ shift ;;
+ esac
+ ;;
+ -b|--browser|--browser=*)
+ case "$#,$1" in
+ *,*=*)
+ browser=`expr "$1" : '-[^=]*=\(.*\)'` ;;
+ 1,*)
+ usage ;;
+ *)
+ browser="$2"
+ shift ;;
+ esac
+ ;;
+ -p|--port|--port=*)
+ case "$#,$1" in
+ *,*=*)
+ port=`expr "$1" : '-[^=]*=\(.*\)'` ;;
+ 1,*)
+ usage ;;
+ *)
+ port="$2"
+ shift ;;
+ esac
+ ;;
+ -m|--module-path=*|--module-path)
+ case "$#,$1" in
+ *,*=*)
+ module_path=`expr "$1" : '-[^=]*=\(.*\)'` ;;
+ 1,*)
+ usage ;;
+ *)
+ module_path="$2"
+ shift ;;
+ esac
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ shift
+done
+
+mkdir -p "$GIT_DIR/gitweb/tmp"
+GIT_EXEC_PATH="`git --exec-path`"
+GIT_DIR="$fqgitdir"
+export GIT_EXEC_PATH GIT_DIR
+
+
+lighttpd_conf () {
+ cat > "$conf" <<EOF
+server.document-root = "$fqgitdir/gitweb"
+server.port = $port
+server.modules = ( "mod_cgi" )
+server.indexfiles = ( "gitweb.cgi" )
+server.pid-file = "$fqgitdir/pid"
+cgi.assign = ( ".cgi" => "" )
+mimetype.assign = ( ".css" => "text/css" )
+EOF
+ test "$local" = true && echo 'server.bind = "127.0.0.1"' >> "$conf"
+}
+
+apache2_conf () {
+ test -z "$module_path" && module_path=/usr/lib/apache2/modules
+ mkdir -p "$GIT_DIR/gitweb/logs"
+ bind=
+ test "$local" = true && bind='127.0.0.1:'
+ echo 'text/css css' > $fqgitdir/mime.types
+ cat > "$conf" <<EOF
+ServerRoot "$fqgitdir/gitweb"
+DocumentRoot "$fqgitdir/gitweb"
+PidFile "$fqgitdir/pid"
+Listen $bind$port
+TypesConfig $fqgitdir/mime.types
+DirectoryIndex gitweb.cgi
+EOF
+
+ # check to see if Dennis Stosberg's mod_perl compatibility patch
+ # (<20060621130708.Gcbc6e5c@leonov.stosberg.net>) has been applied
+ if test -f "$module_path/mod_perl.so" && grep '^our $gitbin' \
+ "$GIT_DIR/gitweb/gitweb.cgi" >/dev/null
+ then
+ # favor mod_perl if available
+ cat >> "$conf" <<EOF
+LoadModule perl_module $module_path/mod_perl.so
+PerlPassEnv GIT_DIR
+PerlPassEnv GIT_EXEC_DIR
+<Location /gitweb.cgi>
+ SetHandler perl-script
+ PerlResponseHandler ModPerl::Registry
+ PerlOptions +ParseHeaders
+ Options +ExecCGI
+</Location>
+EOF
+ else
+ # plain-old CGI
+ cat >> "$conf" <<EOF
+LoadModule cgi_module $module_path/mod_cgi.so
+AddHandler cgi-script .cgi
+<Location /gitweb.cgi>
+ Options +ExecCGI
+</Location>
+EOF
+ fi
+}
+
+script='
+s#^\(my\|our\) $projectroot =.*#\1 $projectroot = "'`dirname $fqgitdir`'";#
+s#\(my\|our\) $gitbin =.*#\1 $gitbin = "'$GIT_EXEC_PATH'";#
+s#\(my\|our\) $projects_list =.*#\1 $projects_list = $projectroot;#
+s#\(my\|our\) $git_temp =.*#\1 $git_temp = "'$fqgitdir/gitweb/tmp'";#'
+
+gitweb_cgi () {
+ cat > "$1.tmp" <<\EOFGITWEB
+@@GITWEB_CGI@@
+EOFGITWEB
+ sed "$script" "$1.tmp" > "$1"
+ chmod +x "$1"
+ rm -f "$1.tmp"
+}
+
+gitweb_css () {
+ cat > "$1" <<\EOFGITWEB
+@@GITWEB_CSS@@
+EOFGITWEB
+}
+
+gitweb_cgi $GIT_DIR/gitweb/gitweb.cgi
+gitweb_css $GIT_DIR/gitweb/gitweb.css
+
+case "$httpd" in
+*lighttpd*)
+ lighttpd_conf
+ ;;
+*apache2*)
+ apache2_conf
+ ;;
+*)
+ echo "Unknown httpd specified: $httpd"
+ exit 1
+ ;;
+esac
+
+start_httpd
+test -z "$browser" && browser=echo
+$browser http://127.0.0.1:$port
diff --git a/git-reset.sh b/git-reset.sh
index 46451d0..5c02240 100755
--- a/git-reset.sh
+++ b/git-reset.sh
@@ -17,7 +17,11 @@ case "$1" in
usage ;;
esac
-rev=$(git-rev-parse --verify --default HEAD "$@") || exit
+case $# in
+0) rev=HEAD ;;
+1) rev=$(git-rev-parse --verify "$1") || exit ;;
+*) usage ;;
+esac
rev=$(git-rev-parse --verify $rev^0) || exit
# We need to remember the set of paths that _could_ be left
diff --git a/git-send-email.perl b/git-send-email.perl
index c5d9e73..b04b8f4 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -22,6 +22,17 @@ use Term::ReadLine;
use Getopt::Long;
use Data::Dumper;
+package FakeTerm;
+sub new {
+ my ($class, $reason) = @_;
+ return bless \$reason, shift;
+}
+sub readline {
+ my $self = shift;
+ die "Cannot use readline on FakeTerm: $$self";
+}
+package main;
+
# most mail servers generate the Date: header, but not all...
$ENV{LC_ALL} = 'C';
use POSIX qw/strftime/;
@@ -46,7 +57,12 @@ my $smtp_server;
# Example reply to:
#$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
-my $term = new Term::ReadLine 'git-send-email';
+my $term = eval {
+ new Term::ReadLine 'git-send-email';
+};
+if ($@) {
+ $term = new FakeTerm "$@: going non-interactive";
+}
# Begin by accumulating all the variables (defined above), that we will end up
# needing, first, from the command line:
diff --git a/git.c b/git.c
index ca8961f..2567301 100644
--- a/git.c
+++ b/git.c
@@ -187,7 +187,8 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
{ "mailinfo", cmd_mailinfo },
{ "stripspace", cmd_stripspace },
{ "update-index", cmd_update_index },
- { "update-ref", cmd_update_ref }
+ { "update-ref", cmd_update_ref },
+ { "fmt-merge-msg", cmd_fmt_merge_msg }
};
int i;
diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 035e76d..3e2790c 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -16,21 +16,21 @@ use Encode;
use Fcntl ':mode';
binmode STDOUT, ':utf8';
-my $cgi = new CGI;
-my $version = "267";
-my $my_url = $cgi->url();
-my $my_uri = $cgi->url(-absolute => 1);
-my $rss_link = "";
+our $cgi = new CGI;
+our $version = "267";
+our $my_url = $cgi->url();
+our $my_uri = $cgi->url(-absolute => 1);
+our $rss_link = "";
# location of the git-core binaries
-my $gitbin = "/usr/bin";
+our $gitbin = "/usr/bin";
# absolute fs-path which will be prepended to the project path
-#my $projectroot = "/pub/scm";
-my $projectroot = "/home/kay/public_html/pub/scm";
+#our $projectroot = "/pub/scm";
+our $projectroot = "/home/kay/public_html/pub/scm";
# version of the git-core binaries
-my $git_version = qx($gitbin/git --version);
+our $git_version = qx($gitbin/git --version);
if ($git_version =~ m/git version (.*)$/) {
$git_version = $1;
} else {
@@ -38,32 +38,31 @@ if ($git_version =~ m/git version (.*)$/) {
}
# location for temporary files needed for diffs
-my $git_temp = "/tmp/gitweb";
+our $git_temp = "/tmp/gitweb";
# target of the home link on top of all pages
-my $home_link = $my_uri;
+our $home_link = $my_uri;
# html text to include at home page
-my $home_text = "indextext.html";
+our $home_text = "indextext.html";
# URI of default stylesheet
-my $stylesheet = "gitweb.css";
+our $stylesheet = "gitweb.css";
# source of projects list
-#my $projects_list = $projectroot;
-my $projects_list = "index/index.aux";
+#our $projects_list = $projectroot;
+our $projects_list = "index/index.aux";
# default blob_plain mimetype and default charset for text/plain blob
-my $default_blob_plain_mimetype = 'text/plain';
-my $default_text_plain_charset = undef;
+our $default_blob_plain_mimetype = 'text/plain';
+our $default_text_plain_charset = undef;
# file to use for guessing MIME types before trying /etc/mime.types
# (relative to the current git repository)
-my $mimetypes_file = undef;
-
+our $mimetypes_file = undef;
# input validation and dispatch
-my $action = $cgi->param('a');
+our $action = $cgi->param('a');
if (defined $action) {
if ($action =~ m/[^0-9a-zA-Z\.\-_]/) {
undef $action;
@@ -78,7 +77,7 @@ if (defined $action) {
}
}
-my $order = $cgi->param('o');
+our $order = $cgi->param('o');
if (defined $order) {
if ($order =~ m/[^0-9a-zA-Z_]/) {
undef $order;
@@ -86,7 +85,7 @@ if (defined $order) {
}
}
-my $project = ($cgi->param('p') || $ENV{'PATH_INFO'});
+our $project = ($cgi->param('p') || $ENV{'PATH_INFO'});
if (defined $project) {
$project =~ s|^/||; $project =~ s|/$||;
$project = validate_input($project);
@@ -109,7 +108,7 @@ if (defined $project) {
exit;
}
-my $file_name = $cgi->param('f');
+our $file_name = $cgi->param('f');
if (defined $file_name) {
$file_name = validate_input($file_name);
if (!defined($file_name)) {
@@ -117,7 +116,7 @@ if (defined $file_name) {
}
}
-my $hash = $cgi->param('h');
+our $hash = $cgi->param('h');
if (defined $hash) {
$hash = validate_input($hash);
if (!defined($hash)) {
@@ -125,7 +124,7 @@ if (defined $hash) {
}
}
-my $hash_parent = $cgi->param('hp');
+our $hash_parent = $cgi->param('hp');
if (defined $hash_parent) {
$hash_parent = validate_input($hash_parent);
if (!defined($hash_parent)) {
@@ -133,7 +132,7 @@ if (defined $hash_parent) {
}
}
-my $hash_base = $cgi->param('hb');
+our $hash_base = $cgi->param('hb');
if (defined $hash_base) {
$hash_base = validate_input($hash_base);
if (!defined($hash_base)) {
@@ -141,7 +140,7 @@ if (defined $hash_base) {
}
}
-my $page = $cgi->param('pg');
+our $page = $cgi->param('pg');
if (defined $page) {
if ($page =~ m/[^0-9]$/) {
undef $page;
@@ -149,7 +148,7 @@ if (defined $page) {
}
}
-my $searchtext = $cgi->param('s');
+our $searchtext = $cgi->param('s');
if (defined $searchtext) {
if ($searchtext =~ m/[^a-zA-Z0-9_\.\/\-\+\:\@ ]/) {
undef $searchtext;
@@ -1676,6 +1675,7 @@ sub git_tree {
"</td>\n" .
"<td class=\"link\">" .
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$t_hash$base_key;f=$base$t_name")}, "tree") .
+ " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=history;h=$hash_base;f=$base$t_name")}, "history") .
"</td>\n";
}
print "</tr>\n";
@@ -2295,16 +2295,13 @@ sub git_history {
"</div>\n";
print "<div class=\"page_path\"><b>/" . esc_html($file_name) . "</b><br/></div>\n";
- open my $fd, "-|", "$gitbin/git-rev-list $hash | $gitbin/git-diff-tree -r --stdin -- \'$file_name\'";
- my $commit;
+ open my $fd, "-|",
+ "$gitbin/git-rev-list --full-history $hash -- \'$file_name\'";
print "<table cellspacing=\"0\">\n";
my $alternate = 0;
while (my $line = <$fd>) {
if ($line =~ m/^([0-9a-fA-F]{40})/){
- $commit = $1;
- next;
- }
- if ($line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)\t(.*)$/ && (defined $commit)) {
+ my $commit = $1;
my %co = git_read_commit($commit);
if (!%co) {
next;
@@ -2336,7 +2333,6 @@ sub git_history {
}
print "</td>\n" .
"</tr>\n";
- undef $commit;
}
}
print "</table>\n";
diff --git a/http-push.c b/http-push.c
index e281f70..f761584 100644
--- a/http-push.c
+++ b/http-push.c
@@ -492,7 +492,7 @@ static void start_put(struct transfer_request *request)
/* Set it up */
memset(&stream, 0, sizeof(stream));
- deflateInit(&stream, Z_BEST_COMPRESSION);
+ deflateInit(&stream, zlib_compression_level);
size = deflateBound(&stream, len + hdrlen);
request->buffer.buffer = xmalloc(size);
diff --git a/log-tree.c b/log-tree.c
index ebb49f2..9d8d46f 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -43,9 +43,10 @@ static int append_signoff(char *buf, int buf_sz, int at, const char *signoff)
return at;
}
-void show_log(struct rev_info *opt, struct log_info *log, const char *sep)
+void show_log(struct rev_info *opt, const char *sep)
{
static char this_header[16384];
+ struct log_info *log = opt->loginfo;
struct commit *commit = log->commit, *parent = log->parent;
int abbrev = opt->diffopt.abbrev;
int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40;
@@ -163,8 +164,22 @@ int log_tree_diff_flush(struct rev_info *opt)
return 0;
}
- if (opt->loginfo && !opt->no_commit_id)
- show_log(opt, opt->loginfo, opt->diffopt.with_stat ? "---\n" : "\n");
+ if (opt->loginfo && !opt->no_commit_id) {
+ /* When showing a verbose header (i.e. log message),
+ * and not in --pretty=oneline format, we would want
+ * an extra newline between the end of log and the
+ * output for readability.
+ */
+ show_log(opt, opt->diffopt.msg_sep);
+ if (opt->verbose_header &&
+ opt->commit_format != CMIT_FMT_ONELINE) {
+ int pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH;
+ if ((pch & opt->diffopt.output_format) == pch)
+ printf("---%c", opt->diffopt.line_termination);
+ else
+ putchar(opt->diffopt.line_termination);
+ }
+ }
diff_flush(&opt->diffopt);
return 1;
}
@@ -261,7 +276,7 @@ int log_tree_commit(struct rev_info *opt, struct commit *commit)
shown = log_tree_diff(opt, commit, &log);
if (!shown && opt->loginfo && opt->always_show_header) {
log.parent = NULL;
- show_log(opt, opt->loginfo, "");
+ show_log(opt, "");
shown = 1;
}
opt->loginfo = NULL;
diff --git a/log-tree.h b/log-tree.h
index a26e484..e82b56a 100644
--- a/log-tree.h
+++ b/log-tree.h
@@ -11,6 +11,6 @@ void init_log_tree_opt(struct rev_info *);
int log_tree_diff_flush(struct rev_info *);
int log_tree_commit(struct rev_info *, struct commit *);
int log_tree_opt_parse(struct rev_info *, const char **, int);
-void show_log(struct rev_info *opt, struct log_info *log, const char *sep);
+void show_log(struct rev_info *opt, const char *sep);
#endif
diff --git a/peek-remote.c b/peek-remote.c
index a90cf22..2b30980 100644
--- a/peek-remote.c
+++ b/peek-remote.c
@@ -7,11 +7,11 @@ static const char peek_remote_usage[] =
"git-peek-remote [--exec=upload-pack] [host:]directory";
static const char *exec = "git-upload-pack";
-static int peek_remote(int fd[2])
+static int peek_remote(int fd[2], unsigned flags)
{
struct ref *ref;
- get_remote_heads(fd[0], &ref, 0, NULL, 0);
+ get_remote_heads(fd[0], &ref, 0, NULL, flags);
packet_flush(fd[1]);
while (ref) {
@@ -28,6 +28,7 @@ int main(int argc, char **argv)
int fd[2];
pid_t pid;
int nongit = 0;
+ unsigned flags = 0;
setup_git_directory_gently(&nongit);
@@ -35,22 +36,35 @@ int main(int argc, char **argv)
char *arg = argv[i];
if (*arg == '-') {
- if (!strncmp("--exec=", arg, 7))
+ if (!strncmp("--exec=", arg, 7)) {
exec = arg + 7;
- else
- usage(peek_remote_usage);
- continue;
+ continue;
+ }
+ if (!strcmp("--tags", arg)) {
+ flags |= REF_TAGS;
+ continue;
+ }
+ if (!strcmp("--heads", arg)) {
+ flags |= REF_HEADS;
+ continue;
+ }
+ if (!strcmp("--refs", arg)) {
+ flags |= REF_NORMAL;
+ continue;
+ }
+ usage(peek_remote_usage);
}
dest = arg;
break;
}
+
if (!dest || i != argc - 1)
usage(peek_remote_usage);
pid = git_connect(fd, dest, exec);
if (pid < 0)
return 1;
- ret = peek_remote(fd);
+ ret = peek_remote(fd, flags);
close(fd[0]);
close(fd[1]);
finish_connect(pid);
diff --git a/ppc/sha1ppc.S b/ppc/sha1ppc.S
index e85611a..f591d98 100644
--- a/ppc/sha1ppc.S
+++ b/ppc/sha1ppc.S
@@ -3,183 +3,222 @@
*
* Copyright (C) 2005 Paul Mackerras <paulus@samba.org>
*/
-#define FS 80
/*
- * We roll the registers for T, A, B, C, D, E around on each
- * iteration; T on iteration t is A on iteration t+1, and so on.
- * We use registers 7 - 12 for this.
+ * PowerPC calling convention:
+ * %r0 - volatile temp
+ * %r1 - stack pointer.
+ * %r2 - reserved
+ * %r3-%r12 - Incoming arguments & return values; volatile.
+ * %r13-%r31 - Callee-save registers
+ * %lr - Return address, volatile
+ * %ctr - volatile
+ *
+ * Register usage in this routine:
+ * %r0 - temp
+ * %r3 - argument (pointer to 5 words of SHA state)
+ * %r4 - argument (pointer to data to hash)
+ * %r5 - Contant K in SHA round (initially number of blocks to hash)
+ * %r6-%r10 - Working copies of SHA variables A..E (actually E..A order)
+ * %r11-%r26 - Data being hashed W[].
+ * %r27-%r31 - Previous copies of A..E, for final add back.
+ * %ctr - loop count
+ */
+
+
+/*
+ * We roll the registers for A, B, C, D, E around on each
+ * iteration; E on iteration t is D on iteration t+1, and so on.
+ * We use registers 6 - 10 for this. (Registers 27 - 31 hold
+ * the previous values.)
*/
-#define RT(t) ((((t)+5)%6)+7)
-#define RA(t) ((((t)+4)%6)+7)
-#define RB(t) ((((t)+3)%6)+7)
-#define RC(t) ((((t)+2)%6)+7)
-#define RD(t) ((((t)+1)%6)+7)
-#define RE(t) ((((t)+0)%6)+7)
-
-/* We use registers 16 - 31 for the W values */
-#define W(t) (((t)%16)+16)
-
-#define STEPD0(t) \
- and %r6,RB(t),RC(t); \
- andc %r0,RD(t),RB(t); \
- rotlwi RT(t),RA(t),5; \
- rotlwi RB(t),RB(t),30; \
- or %r6,%r6,%r0; \
- add %r0,RE(t),%r15; \
- add RT(t),RT(t),%r6; \
- add %r0,%r0,W(t); \
- add RT(t),RT(t),%r0
-
-#define STEPD1(t) \
- xor %r6,RB(t),RC(t); \
- rotlwi RT(t),RA(t),5; \
- rotlwi RB(t),RB(t),30; \
- xor %r6,%r6,RD(t); \
- add %r0,RE(t),%r15; \
- add RT(t),RT(t),%r6; \
- add %r0,%r0,W(t); \
- add RT(t),RT(t),%r0
-
-#define STEPD2(t) \
- and %r6,RB(t),RC(t); \
- and %r0,RB(t),RD(t); \
- rotlwi RT(t),RA(t),5; \
- rotlwi RB(t),RB(t),30; \
- or %r6,%r6,%r0; \
- and %r0,RC(t),RD(t); \
- or %r6,%r6,%r0; \
- add %r0,RE(t),%r15; \
- add RT(t),RT(t),%r6; \
- add %r0,%r0,W(t); \
- add RT(t),RT(t),%r0
-
-#define LOADW(t) \
- lwz W(t),(t)*4(%r4)
-
-#define UPDATEW(t) \
- xor %r0,W((t)-3),W((t)-8); \
- xor W(t),W((t)-16),W((t)-14); \
- xor W(t),W(t),%r0; \
- rotlwi W(t),W(t),1
-
-#define STEP0LD4(t) \
- STEPD0(t); LOADW((t)+4); \
- STEPD0((t)+1); LOADW((t)+5); \
- STEPD0((t)+2); LOADW((t)+6); \
- STEPD0((t)+3); LOADW((t)+7)
-
-#define STEPUP4(t, fn) \
- STEP##fn(t); UPDATEW((t)+4); \
- STEP##fn((t)+1); UPDATEW((t)+5); \
- STEP##fn((t)+2); UPDATEW((t)+6); \
- STEP##fn((t)+3); UPDATEW((t)+7)
-
-#define STEPUP20(t, fn) \
- STEPUP4(t, fn); \
- STEPUP4((t)+4, fn); \
- STEPUP4((t)+8, fn); \
- STEPUP4((t)+12, fn); \
- STEPUP4((t)+16, fn)
+#define RA(t) (((t)+4)%5+6)
+#define RB(t) (((t)+3)%5+6)
+#define RC(t) (((t)+2)%5+6)
+#define RD(t) (((t)+1)%5+6)
+#define RE(t) (((t)+0)%5+6)
+
+/* We use registers 11 - 26 for the W values */
+#define W(t) ((t)%16+11)
+
+/* Register 5 is used for the constant k */
+
+/*
+ * The basic SHA-1 round function is:
+ * E += ROTL(A,5) + F(B,C,D) + W[i] + K; B = ROTL(B,30)
+ * Then the variables are renamed: (A,B,C,D,E) = (E,A,B,C,D).
+ *
+ * Every 20 rounds, the function F() and the contant K changes:
+ * - 20 rounds of f0(b,c,d) = "bit wise b ? c : d" = (^b & d) + (b & c)
+ * - 20 rounds of f1(b,c,d) = b^c^d = (b^d)^c
+ * - 20 rounds of f2(b,c,d) = majority(b,c,d) = (b&d) + ((b^d)&c)
+ * - 20 more rounds of f1(b,c,d)
+ *
+ * These are all scheduled for near-optimal performance on a G4.
+ * The G4 is a 3-issue out-of-order machine with 3 ALUs, but it can only
+ * *consider* starting the oldest 3 instructions per cycle. So to get
+ * maximum performace out of it, you have to treat it as an in-order
+ * machine. Which means interleaving the computation round t with the
+ * computation of W[t+4].
+ *
+ * The first 16 rounds use W values loaded directly from memory, while the
+ * remianing 64 use values computed from those first 16. We preload
+ * 4 values before starting, so there are three kinds of rounds:
+ * - The first 12 (all f0) also load the W values from memory.
+ * - The next 64 compute W(i+4) in parallel. 8*f0, 20*f1, 20*f2, 16*f1.
+ * - The last 4 (all f1) do not do anything with W.
+ *
+ * Therefore, we have 6 different round functions:
+ * STEPD0_LOAD(t,s) - Perform round t and load W(s). s < 16
+ * STEPD0_UPDATE(t,s) - Perform round t and compute W(s). s >= 16.
+ * STEPD1_UPDATE(t,s)
+ * STEPD2_UPDATE(t,s)
+ * STEPD1(t) - Perform round t with no load or update.
+ *
+ * The G5 is more fully out-of-order, and can find the parallelism
+ * by itself. The big limit is that it has a 2-cycle ALU latency, so
+ * even though it's 2-way, the code has to be scheduled as if it's
+ * 4-way, which can be a limit. To help it, we try to schedule the
+ * read of RA(t) as late as possible so it doesn't stall waiting for
+ * the previous round's RE(t-1), and we try to rotate RB(t) as early
+ * as possible while reading RC(t) (= RB(t-1)) as late as possible.
+ */
+
+/* the initial loads. */
+#define LOADW(s) \
+ lwz W(s),(s)*4(%r4)
+
+/*
+ * Perform a step with F0, and load W(s). Uses W(s) as a temporary
+ * before loading it.
+ * This is actually 10 instructions, which is an awkward fit.
+ * It can execute grouped as listed, or delayed one instruction.
+ * (If delayed two instructions, there is a stall before the start of the
+ * second line.) Thus, two iterations take 7 cycles, 3.5 cycles per round.
+ */
+#define STEPD0_LOAD(t,s) \
+add RE(t),RE(t),W(t); andc %r0,RD(t),RB(t); and W(s),RC(t),RB(t); \
+add RE(t),RE(t),%r0; rotlwi %r0,RA(t),5; rotlwi RB(t),RB(t),30; \
+add RE(t),RE(t),W(s); add %r0,%r0,%r5; lwz W(s),(s)*4(%r4); \
+add RE(t),RE(t),%r0
+
+/*
+ * This is likewise awkward, 13 instructions. However, it can also
+ * execute starting with 2 out of 3 possible moduli, so it does 2 rounds
+ * in 9 cycles, 4.5 cycles/round.
+ */
+#define STEPD0_UPDATE(t,s,loadk...) \
+add RE(t),RE(t),W(t); andc %r0,RD(t),RB(t); xor W(s),W((s)-16),W((s)-3); \
+add RE(t),RE(t),%r0; and %r0,RC(t),RB(t); xor W(s),W(s),W((s)-8); \
+add RE(t),RE(t),%r0; rotlwi %r0,RA(t),5; xor W(s),W(s),W((s)-14); \
+add RE(t),RE(t),%r5; loadk; rotlwi RB(t),RB(t),30; rotlwi W(s),W(s),1; \
+add RE(t),RE(t),%r0
+
+/* Nicely optimal. Conveniently, also the most common. */
+#define STEPD1_UPDATE(t,s,loadk...) \
+add RE(t),RE(t),W(t); xor %r0,RD(t),RB(t); xor W(s),W((s)-16),W((s)-3); \
+add RE(t),RE(t),%r5; loadk; xor %r0,%r0,RC(t); xor W(s),W(s),W((s)-8); \
+add RE(t),RE(t),%r0; rotlwi %r0,RA(t),5; xor W(s),W(s),W((s)-14); \
+add RE(t),RE(t),%r0; rotlwi RB(t),RB(t),30; rotlwi W(s),W(s),1
+
+/*
+ * The naked version, no UPDATE, for the last 4 rounds. 3 cycles per.
+ * We could use W(s) as a temp register, but we don't need it.
+ */
+#define STEPD1(t) \
+ add RE(t),RE(t),W(t); xor %r0,RD(t),RB(t); \
+rotlwi RB(t),RB(t),30; add RE(t),RE(t),%r5; xor %r0,%r0,RC(t); \
+add RE(t),RE(t),%r0; rotlwi %r0,RA(t),5; /* spare slot */ \
+add RE(t),RE(t),%r0
+
+/*
+ * 14 instructions, 5 cycles per. The majority function is a bit
+ * awkward to compute. This can execute with a 1-instruction delay,
+ * but it causes a 2-instruction delay, which triggers a stall.
+ */
+#define STEPD2_UPDATE(t,s,loadk...) \
+add RE(t),RE(t),W(t); and %r0,RD(t),RB(t); xor W(s),W((s)-16),W((s)-3); \
+add RE(t),RE(t),%r0; xor %r0,RD(t),RB(t); xor W(s),W(s),W((s)-8); \
+add RE(t),RE(t),%r5; loadk; and %r0,%r0,RC(t); xor W(s),W(s),W((s)-14); \
+add RE(t),RE(t),%r0; rotlwi %r0,RA(t),5; rotlwi W(s),W(s),1; \
+add RE(t),RE(t),%r0; rotlwi RB(t),RB(t),30
+
+#define STEP0_LOAD4(t,s) \
+ STEPD0_LOAD(t,s); \
+ STEPD0_LOAD((t+1),(s)+1); \
+ STEPD0_LOAD((t)+2,(s)+2); \
+ STEPD0_LOAD((t)+3,(s)+3)
+
+#define STEPUP4(fn, t, s, loadk...) \
+ STEP##fn##_UPDATE(t,s,); \
+ STEP##fn##_UPDATE((t)+1,(s)+1,); \
+ STEP##fn##_UPDATE((t)+2,(s)+2,); \
+ STEP##fn##_UPDATE((t)+3,(s)+3,loadk)
+
+#define STEPUP20(fn, t, s, loadk...) \
+ STEPUP4(fn, t, s,); \
+ STEPUP4(fn, (t)+4, (s)+4,); \
+ STEPUP4(fn, (t)+8, (s)+8,); \
+ STEPUP4(fn, (t)+12, (s)+12,); \
+ STEPUP4(fn, (t)+16, (s)+16, loadk)
.globl sha1_core
sha1_core:
- stwu %r1,-FS(%r1)
- stw %r15,FS-68(%r1)
- stw %r16,FS-64(%r1)
- stw %r17,FS-60(%r1)
- stw %r18,FS-56(%r1)
- stw %r19,FS-52(%r1)
- stw %r20,FS-48(%r1)
- stw %r21,FS-44(%r1)
- stw %r22,FS-40(%r1)
- stw %r23,FS-36(%r1)
- stw %r24,FS-32(%r1)
- stw %r25,FS-28(%r1)
- stw %r26,FS-24(%r1)
- stw %r27,FS-20(%r1)
- stw %r28,FS-16(%r1)
- stw %r29,FS-12(%r1)
- stw %r30,FS-8(%r1)
- stw %r31,FS-4(%r1)
+ stwu %r1,-80(%r1)
+ stmw %r13,4(%r1)
/* Load up A - E */
- lwz RA(0),0(%r3) /* A */
- lwz RB(0),4(%r3) /* B */
- lwz RC(0),8(%r3) /* C */
- lwz RD(0),12(%r3) /* D */
- lwz RE(0),16(%r3) /* E */
+ lmw %r27,0(%r3)
mtctr %r5
-1: LOADW(0)
+1:
+ LOADW(0)
+ lis %r5,0x5a82
+ mr RE(0),%r31
LOADW(1)
+ mr RD(0),%r30
+ mr RC(0),%r29
LOADW(2)
+ ori %r5,%r5,0x7999 /* K0-19 */
+ mr RB(0),%r28
LOADW(3)
+ mr RA(0),%r27
+
+ STEP0_LOAD4(0, 4)
+ STEP0_LOAD4(4, 8)
+ STEP0_LOAD4(8, 12)
+ STEPUP4(D0, 12, 16,)
+ STEPUP4(D0, 16, 20, lis %r5,0x6ed9)
- lis %r15,0x5a82 /* K0-19 */
- ori %r15,%r15,0x7999
- STEP0LD4(0)
- STEP0LD4(4)
- STEP0LD4(8)
- STEPUP4(12, D0)
- STEPUP4(16, D0)
-
- lis %r15,0x6ed9 /* K20-39 */
- ori %r15,%r15,0xeba1
- STEPUP20(20, D1)
-
- lis %r15,0x8f1b /* K40-59 */
- ori %r15,%r15,0xbcdc
- STEPUP20(40, D2)
-
- lis %r15,0xca62 /* K60-79 */
- ori %r15,%r15,0xc1d6
- STEPUP4(60, D1)
- STEPUP4(64, D1)
- STEPUP4(68, D1)
- STEPUP4(72, D1)
+ ori %r5,%r5,0xeba1 /* K20-39 */
+ STEPUP20(D1, 20, 24, lis %r5,0x8f1b)
+
+ ori %r5,%r5,0xbcdc /* K40-59 */
+ STEPUP20(D2, 40, 44, lis %r5,0xca62)
+
+ ori %r5,%r5,0xc1d6 /* K60-79 */
+ STEPUP4(D1, 60, 64,)
+ STEPUP4(D1, 64, 68,)
+ STEPUP4(D1, 68, 72,)
+ STEPUP4(D1, 72, 76,)
+ addi %r4,%r4,64
STEPD1(76)
STEPD1(77)
STEPD1(78)
STEPD1(79)
- lwz %r20,16(%r3)
- lwz %r19,12(%r3)
- lwz %r18,8(%r3)
- lwz %r17,4(%r3)
- lwz %r16,0(%r3)
- add %r20,RE(80),%r20
- add RD(0),RD(80),%r19
- add RC(0),RC(80),%r18
- add RB(0),RB(80),%r17
- add RA(0),RA(80),%r16
- mr RE(0),%r20
- stw RA(0),0(%r3)
- stw RB(0),4(%r3)
- stw RC(0),8(%r3)
- stw RD(0),12(%r3)
- stw RE(0),16(%r3)
+ /* Add results to original values */
+ add %r31,%r31,RE(0)
+ add %r30,%r30,RD(0)
+ add %r29,%r29,RC(0)
+ add %r28,%r28,RB(0)
+ add %r27,%r27,RA(0)
- addi %r4,%r4,64
bdnz 1b
- lwz %r15,FS-68(%r1)
- lwz %r16,FS-64(%r1)
- lwz %r17,FS-60(%r1)
- lwz %r18,FS-56(%r1)
- lwz %r19,FS-52(%r1)
- lwz %r20,FS-48(%r1)
- lwz %r21,FS-44(%r1)
- lwz %r22,FS-40(%r1)
- lwz %r23,FS-36(%r1)
- lwz %r24,FS-32(%r1)
- lwz %r25,FS-28(%r1)
- lwz %r26,FS-24(%r1)
- lwz %r27,FS-20(%r1)
- lwz %r28,FS-16(%r1)
- lwz %r29,FS-12(%r1)
- lwz %r30,FS-8(%r1)
- lwz %r31,FS-4(%r1)
- addi %r1,%r1,FS
+ /* Save final hash, restore registers, and return */
+ stmw %r27,0(%r3)
+ lmw %r13,4(%r1)
+ addi %r1,%r1,80
blr
diff --git a/revision.c b/revision.c
index b4157cb..a7750e6 100644
--- a/revision.c
+++ b/revision.c
@@ -883,8 +883,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
}
if (revs->combine_merges) {
revs->ignore_merges = 0;
- if (revs->dense_combined_merges &&
- (revs->diffopt.output_format != DIFF_FORMAT_DIFFSTAT))
+ if (revs->dense_combined_merges && !revs->diffopt.output_format)
revs->diffopt.output_format = DIFF_FORMAT_PATCH;
}
revs->diffopt.abbrev = revs->abbrev;
diff --git a/send-pack.c b/send-pack.c
index af93b11..4019a4b 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -239,7 +239,7 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec)
int expect_status_report = 0;
/* No funny business with the matcher */
- remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, 1);
+ remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL);
get_local_heads();
/* Does the other end support the reporting? */
diff --git a/sha1_file.c b/sha1_file.c
index 8179630..bc35808 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1458,7 +1458,7 @@ int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned cha
/* Set it up */
memset(&stream, 0, sizeof(stream));
- deflateInit(&stream, Z_BEST_COMPRESSION);
+ deflateInit(&stream, zlib_compression_level);
size = deflateBound(&stream, len+hdrlen);
compressed = xmalloc(size);
@@ -1511,7 +1511,7 @@ static void *repack_object(const unsigned char *sha1, unsigned long *objsize)
/* Set it up */
memset(&stream, 0, sizeof(stream));
- deflateInit(&stream, Z_BEST_COMPRESSION);
+ deflateInit(&stream, zlib_compression_level);
size = deflateBound(&stream, len + hdrlen);
buf = xmalloc(size);
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
new file mode 100755
index 0000000..06837d1
--- /dev/null
+++ b/t/t4013-diff-various.sh
@@ -0,0 +1,247 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Junio C Hamano
+#
+
+test_description='Various diff formatting options'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+ GIT_AUTHOR_DATE="2006-06-26 00:00:00 +0000" &&
+ GIT_COMMITTER_DATE="2006-06-26 00:00:00 +0000" &&
+ export GIT_AUTHOR_DATE GIT_COMMITTER_DATE &&
+
+ mkdir dir &&
+ for i in 1 2 3; do echo $i; done >file0 &&
+ for i in A B; do echo $i; done >dir/sub &&
+ cat file0 >file2 &&
+ git add file0 file2 dir/sub &&
+ git commit -m Initial &&
+
+ git branch initial &&
+ git branch side &&
+
+ GIT_AUTHOR_DATE="2006-06-26 00:01:00 +0000" &&
+ GIT_COMMITTER_DATE="2006-06-26 00:01:00 +0000" &&
+ export GIT_AUTHOR_DATE GIT_COMMITTER_DATE &&
+
+ for i in 4 5 6; do echo $i; done >>file0 &&
+ for i in C D; do echo $i; done >>dir/sub &&
+ rm -f file2 &&
+ git update-index --remove file0 file2 dir/sub &&
+ git commit -m Second &&
+
+ GIT_AUTHOR_DATE="2006-06-26 00:02:00 +0000" &&
+ GIT_COMMITTER_DATE="2006-06-26 00:02:00 +0000" &&
+ export GIT_AUTHOR_DATE GIT_COMMITTER_DATE &&
+
+ for i in A B C; do echo $i; done >file1 &&
+ git add file1 &&
+ for i in E F; do echo $i; done >>dir/sub &&
+ git update-index dir/sub &&
+ git commit -m Third &&
+
+ GIT_AUTHOR_DATE="2006-06-26 00:03:00 +0000" &&
+ GIT_COMMITTER_DATE="2006-06-26 00:03:00 +0000" &&
+ export GIT_AUTHOR_DATE GIT_COMMITTER_DATE &&
+
+ git checkout side &&
+ for i in A B C; do echo $i; done >>file0 &&
+ for i in 1 2; do echo $i; done >>dir/sub &&
+ cat dir/sub >file3 &&
+ git add file3 &&
+ git update-index file0 dir/sub &&
+ git commit -m Side &&
+
+ GIT_AUTHOR_DATE="2006-06-26 00:04:00 +0000" &&
+ GIT_COMMITTER_DATE="2006-06-26 00:04:00 +0000" &&
+ export GIT_AUTHOR_DATE GIT_COMMITTER_DATE &&
+
+ git checkout master &&
+ git pull -s ours . side &&
+
+ GIT_AUTHOR_DATE="2006-06-26 00:05:00 +0000" &&
+ GIT_COMMITTER_DATE="2006-06-26 00:05:00 +0000" &&
+ export GIT_AUTHOR_DATE GIT_COMMITTER_DATE &&
+
+ for i in A B C; do echo $i; done >>file0 &&
+ for i in 1 2; do echo $i; done >>dir/sub &&
+ git update-index file0 dir/sub &&
+
+ EDITOR=: VISUAL=: git commit --amend &&
+ git show-branch
+'
+
+: <<\EOF
+! [initial] Initial
+ * [master] Merge branch 'side'
+ ! [side] Side
+---
+ - [master] Merge branch 'side'
+ *+ [side] Side
+ * [master^] Second
++*+ [initial] Initial
+EOF
+
+V=`git version | sed -e 's/^git version //'`
+while read cmd
+do
+ case "$cmd" in
+ '' | '#'*) continue ;;
+ esac
+ test=`echo "$cmd" | sed -e 's|[/ ][/ ]*|_|g'`
+ cnt=`expr $test_count + 1`
+ pfx=`printf "%04d" $cnt`
+ expect="../t4013/diff.$test"
+ actual="$pfx-diff.$test"
+
+ test_expect_success "git $cmd" '
+ {
+ echo "\$ git $cmd"
+ git $cmd | sed -e "s/$V/g-i-t--v-e-r-s-i-o-n/"
+ echo "\$"
+ } >"$actual" &&
+ if test -f "$expect"
+ then
+ diff -u "$expect" "$actual" &&
+ rm -f "$actual"
+ else
+ # this is to help developing new tests.
+ cp "$actual" "$expect"
+ false
+ fi
+ '
+done <<\EOF
+diff-tree initial
+diff-tree -r initial
+diff-tree -r --abbrev initial
+diff-tree -r --abbrev=4 initial
+diff-tree --root initial
+diff-tree --root --abbrev initial
+diff-tree --root -r initial
+diff-tree --root -r --abbrev initial
+diff-tree --root -r --abbrev=4 initial
+diff-tree -p initial
+diff-tree --root -p initial
+diff-tree --patch-with-stat initial
+diff-tree --root --patch-with-stat initial
+diff-tree --patch-with-raw initial
+diff-tree --root --patch-with-raw initial
+
+diff-tree --pretty initial
+diff-tree --pretty --root initial
+diff-tree --pretty -p initial
+diff-tree --pretty --stat initial
+diff-tree --pretty --summary initial
+diff-tree --pretty --stat --summary initial
+diff-tree --pretty --root -p initial
+diff-tree --pretty --root --stat initial
+# improved by Timo's patch
+diff-tree --pretty --root --summary initial
+# improved by Timo's patch
+diff-tree --pretty --root --summary -r initial
+diff-tree --pretty --root --stat --summary initial
+diff-tree --pretty --patch-with-stat initial
+diff-tree --pretty --root --patch-with-stat initial
+diff-tree --pretty --patch-with-raw initial
+diff-tree --pretty --root --patch-with-raw initial
+
+diff-tree --pretty=oneline initial
+diff-tree --pretty=oneline --root initial
+diff-tree --pretty=oneline -p initial
+diff-tree --pretty=oneline --root -p initial
+diff-tree --pretty=oneline --patch-with-stat initial
+# improved by Timo's patch
+diff-tree --pretty=oneline --root --patch-with-stat initial
+diff-tree --pretty=oneline --patch-with-raw initial
+diff-tree --pretty=oneline --root --patch-with-raw initial
+
+diff-tree --pretty side
+diff-tree --pretty -p side
+diff-tree --pretty --patch-with-stat side
+
+diff-tree master
+diff-tree -p master
+diff-tree -p -m master
+diff-tree -c master
+diff-tree -c --abbrev master
+diff-tree --cc master
+# stat only should show the diffstat with the first parent
+diff-tree -c --stat master
+diff-tree --cc --stat master
+diff-tree -c --stat --summary master
+diff-tree --cc --stat --summary master
+# stat summary should show the diffstat and summary with the first parent
+diff-tree -c --stat --summary side
+diff-tree --cc --stat --summary side
+# improved by Timo's patch
+diff-tree --cc --patch-with-stat master
+# improved by Timo's patch
+diff-tree --cc --patch-with-stat --summary master
+# this is correct
+diff-tree --cc --patch-with-stat --summary side
+
+log master
+log -p master
+log --root master
+log --root -p master
+log --patch-with-stat master
+log --root --patch-with-stat master
+log --root --patch-with-stat --summary master
+# improved by Timo's patch
+log --root -c --patch-with-stat --summary master
+# improved by Timo's patch
+log --root --cc --patch-with-stat --summary master
+log -SF master
+log -SF -p master
+
+whatchanged master
+whatchanged -p master
+whatchanged --root master
+whatchanged --root -p master
+whatchanged --patch-with-stat master
+whatchanged --root --patch-with-stat master
+whatchanged --root --patch-with-stat --summary master
+# improved by Timo's patch
+whatchanged --root -c --patch-with-stat --summary master
+# improved by Timo's patch
+whatchanged --root --cc --patch-with-stat --summary master
+whatchanged -SF master
+whatchanged -SF -p master
+
+log --patch-with-stat master -- dir/
+whatchanged --patch-with-stat master -- dir/
+log --patch-with-stat --summary master -- dir/
+whatchanged --patch-with-stat --summary master -- dir/
+
+show initial
+show --root initial
+show side
+show master
+show --stat side
+show --stat --summary side
+show --patch-with-stat side
+show --patch-with-raw side
+show --patch-with-stat --summary side
+
+format-patch --stdout initial..side
+format-patch --stdout initial..master^
+format-patch --stdout initial..master
+format-patch --attach --stdout initial..side
+format-patch --attach --stdout initial..master^
+format-patch --attach --stdout initial..master
+
+diff --abbrev initial..side
+diff -r initial..side
+diff --stat initial..side
+diff -r --stat initial..side
+diff initial..side
+diff --patch-with-stat initial..side
+diff --patch-with-raw initial..side
+diff --patch-with-stat -r initial..side
+diff --patch-with-raw -r initial..side
+EOF
+
+test_done
diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master
new file mode 100644
index 0000000..0ac9800
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master
@@ -0,0 +1,34 @@
+$ git diff-tree --cc --patch-with-stat --summary master
+176b998f5d647cbd77a9d8acf4531e930754d16d
+ dir/sub | 2 ++
+ file0 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --cc dir/sub
+index cead32e,7289e35..992913c
+--- a/dir/sub
++++ b/dir/sub
+@@@ -1,6 -1,4 +1,8 @@@
+ A
+ B
+ +C
+ +D
+ +E
+ +F
++ 1
++ 2
+diff --cc file0
+index b414108,f4615da..10a8a9f
+--- a/file0
++++ b/file0
+@@@ -1,6 -1,6 +1,9 @@@
+ 1
+ 2
+ 3
+ +4
+ +5
+ +6
++ A
++ B
++ C
+$
diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side
new file mode 100644
index 0000000..a61ad8c
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side
@@ -0,0 +1,39 @@
+$ git diff-tree --cc --patch-with-stat --summary side
+c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+ create mode 100644 file3
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+$
diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master
new file mode 100644
index 0000000..f6ecf76
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master
@@ -0,0 +1,34 @@
+$ git diff-tree --cc --patch-with-stat master
+176b998f5d647cbd77a9d8acf4531e930754d16d
+ dir/sub | 2 ++
+ file0 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --cc dir/sub
+index cead32e,7289e35..992913c
+--- a/dir/sub
++++ b/dir/sub
+@@@ -1,6 -1,4 +1,8 @@@
+ A
+ B
+ +C
+ +D
+ +E
+ +F
++ 1
++ 2
+diff --cc file0
+index b414108,f4615da..10a8a9f
+--- a/file0
++++ b/file0
+@@@ -1,6 -1,6 +1,9 @@@
+ 1
+ 2
+ 3
+ +4
+ +5
+ +6
++ A
++ B
++ C
+$
diff --git a/t/t4013/diff.diff-tree_--cc_--stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master
new file mode 100644
index 0000000..712ffd2
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master
@@ -0,0 +1,6 @@
+$ git diff-tree --cc --stat --summary master
+176b998f5d647cbd77a9d8acf4531e930754d16d
+ dir/sub | 2 ++
+ file0 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+$
diff --git a/t/t4013/diff.diff-tree_--cc_--stat_--summary_side b/t/t4013/diff.diff-tree_--cc_--stat_--summary_side
new file mode 100644
index 0000000..50362be
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--cc_--stat_--summary_side
@@ -0,0 +1,8 @@
+$ git diff-tree --cc --stat --summary side
+c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+ create mode 100644 file3
+$
diff --git a/t/t4013/diff.diff-tree_--cc_--stat_master b/t/t4013/diff.diff-tree_--cc_--stat_master
new file mode 100644
index 0000000..8d5bdc9
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--cc_--stat_master
@@ -0,0 +1,6 @@
+$ git diff-tree --cc --stat master
+176b998f5d647cbd77a9d8acf4531e930754d16d
+ dir/sub | 2 ++
+ file0 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+$
diff --git a/t/t4013/diff.diff-tree_--cc_master b/t/t4013/diff.diff-tree_--cc_master
new file mode 100644
index 0000000..e57d943
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--cc_master
@@ -0,0 +1,30 @@
+$ git diff-tree --cc master
+176b998f5d647cbd77a9d8acf4531e930754d16d
+diff --cc dir/sub
+index cead32e,7289e35..992913c
+--- a/dir/sub
++++ b/dir/sub
+@@@ -1,6 -1,4 +1,8 @@@
+ A
+ B
+ +C
+ +D
+ +E
+ +F
++ 1
++ 2
+diff --cc file0
+index b414108,f4615da..10a8a9f
+--- a/file0
++++ b/file0
+@@@ -1,6 -1,6 +1,9 @@@
+ 1
+ 2
+ 3
+ +4
+ +5
+ +6
++ A
++ B
++ C
+$
diff --git a/t/t4013/diff.diff-tree_--patch-with-raw_initial b/t/t4013/diff.diff-tree_--patch-with-raw_initial
new file mode 100644
index 0000000..fc177ab
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--patch-with-raw_initial
@@ -0,0 +1,2 @@
+$ git diff-tree --patch-with-raw initial
+$
diff --git a/t/t4013/diff.diff-tree_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--patch-with-stat_initial
new file mode 100644
index 0000000..bd905b1
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--patch-with-stat_initial
@@ -0,0 +1,2 @@
+$ git diff-tree --patch-with-stat initial
+$
diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-raw_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-raw_initial
new file mode 100644
index 0000000..7bb8b45
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-raw_initial
@@ -0,0 +1,2 @@
+$ git diff-tree --pretty=oneline --patch-with-raw initial
+$
diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-stat_initial
new file mode 100644
index 0000000..cbdde4f
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-stat_initial
@@ -0,0 +1,2 @@
+$ git diff-tree --pretty=oneline --patch-with-stat initial
+$
diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-raw_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-raw_initial
new file mode 100644
index 0000000..cd79f1a
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-raw_initial
@@ -0,0 +1,33 @@
+$ git diff-tree --pretty=oneline --root --patch-with-raw initial
+444ac553ac7612cc88969031b02b3767fb8a353a Initial
+:000000 100644 0000000000000000000000000000000000000000 35d242ba79ae89ac695e26b3d4c27a8e6f028f9e A dir/sub
+:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file0
+:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file2
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial
new file mode 100644
index 0000000..d5c333a
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial
@@ -0,0 +1,34 @@
+$ git diff-tree --pretty=oneline --root --patch-with-stat initial
+444ac553ac7612cc88969031b02b3767fb8a353a Initial
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 +++
+ 3 files changed, 8 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--root_-p_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--root_-p_initial
new file mode 100644
index 0000000..3c5092c
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty=oneline_--root_-p_initial
@@ -0,0 +1,29 @@
+$ git diff-tree --pretty=oneline --root -p initial
+444ac553ac7612cc88969031b02b3767fb8a353a Initial
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--root_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--root_initial
new file mode 100644
index 0000000..08920ac
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty=oneline_--root_initial
@@ -0,0 +1,6 @@
+$ git diff-tree --pretty=oneline --root initial
+444ac553ac7612cc88969031b02b3767fb8a353a Initial
+:000000 040000 0000000000000000000000000000000000000000 da7a33fa77d8066d6698643940ce5860fe2d7fb3 A dir
+:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file0
+:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file2
+$
diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_-p_initial b/t/t4013/diff.diff-tree_--pretty=oneline_-p_initial
new file mode 100644
index 0000000..94b76bf
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty=oneline_-p_initial
@@ -0,0 +1,2 @@
+$ git diff-tree --pretty=oneline -p initial
+$
diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_initial b/t/t4013/diff.diff-tree_--pretty=oneline_initial
new file mode 100644
index 0000000..d50970d
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty=oneline_initial
@@ -0,0 +1,2 @@
+$ git diff-tree --pretty=oneline initial
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_--patch-with-raw_initial b/t/t4013/diff.diff-tree_--pretty_--patch-with-raw_initial
new file mode 100644
index 0000000..3a85316
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_--patch-with-raw_initial
@@ -0,0 +1,2 @@
+$ git diff-tree --pretty --patch-with-raw initial
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_initial
new file mode 100644
index 0000000..2e08239
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_initial
@@ -0,0 +1,2 @@
+$ git diff-tree --pretty --patch-with-stat initial
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side b/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side
new file mode 100644
index 0000000..4d30e7e
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side
@@ -0,0 +1,43 @@
+$ git diff-tree --pretty --patch-with-stat side
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-raw_initial b/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-raw_initial
new file mode 100644
index 0000000..a3203bd
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-raw_initial
@@ -0,0 +1,38 @@
+$ git diff-tree --pretty --root --patch-with-raw initial
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+
+:000000 100644 0000000000000000000000000000000000000000 35d242ba79ae89ac695e26b3d4c27a8e6f028f9e A dir/sub
+:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file0
+:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file2
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial
new file mode 100644
index 0000000..7dfa6af
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial
@@ -0,0 +1,39 @@
+$ git diff-tree --pretty --root --patch-with-stat initial
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 +++
+ 3 files changed, 8 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial b/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial
new file mode 100644
index 0000000..43bfce2
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial
@@ -0,0 +1,15 @@
+$ git diff-tree --pretty --root --stat --summary initial
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 +++
+ 3 files changed, 8 insertions(+), 0 deletions(-)
+ create mode 100644 dir/sub
+ create mode 100644 file0
+ create mode 100644 file2
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial b/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial
new file mode 100644
index 0000000..9154aa4
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial
@@ -0,0 +1,12 @@
+$ git diff-tree --pretty --root --stat initial
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 +++
+ 3 files changed, 8 insertions(+), 0 deletions(-)
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--summary_-r_initial b/t/t4013/diff.diff-tree_--pretty_--root_--summary_-r_initial
new file mode 100644
index 0000000..ccdaafb
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_--root_--summary_-r_initial
@@ -0,0 +1,11 @@
+$ git diff-tree --pretty --root --summary -r initial
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+
+ create mode 100644 dir/sub
+ create mode 100644 file0
+ create mode 100644 file2
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--summary_initial b/t/t4013/diff.diff-tree_--pretty_--root_--summary_initial
new file mode 100644
index 0000000..ea48205
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_--root_--summary_initial
@@ -0,0 +1,11 @@
+$ git diff-tree --pretty --root --summary initial
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+
+ create mode 040000 dir
+ create mode 100644 file0
+ create mode 100644 file2
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_--root_-p_initial b/t/t4013/diff.diff-tree_--pretty_--root_-p_initial
new file mode 100644
index 0000000..d0411f6
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_--root_-p_initial
@@ -0,0 +1,34 @@
+$ git diff-tree --pretty --root -p initial
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_--root_initial b/t/t4013/diff.diff-tree_--pretty_--root_initial
new file mode 100644
index 0000000..94e32ea
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_--root_initial
@@ -0,0 +1,11 @@
+$ git diff-tree --pretty --root initial
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+
+:000000 040000 0000000000000000000000000000000000000000 da7a33fa77d8066d6698643940ce5860fe2d7fb3 A dir
+:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file0
+:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file2
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_--stat_--summary_initial b/t/t4013/diff.diff-tree_--pretty_--stat_--summary_initial
new file mode 100644
index 0000000..c22983a
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_--stat_--summary_initial
@@ -0,0 +1,2 @@
+$ git diff-tree --pretty --stat --summary initial
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_--stat_initial b/t/t4013/diff.diff-tree_--pretty_--stat_initial
new file mode 100644
index 0000000..8fdcfb4
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_--stat_initial
@@ -0,0 +1,2 @@
+$ git diff-tree --pretty --stat initial
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_--summary_initial b/t/t4013/diff.diff-tree_--pretty_--summary_initial
new file mode 100644
index 0000000..9bc2c4f
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_--summary_initial
@@ -0,0 +1,2 @@
+$ git diff-tree --pretty --summary initial
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_-p_initial b/t/t4013/diff.diff-tree_--pretty_-p_initial
new file mode 100644
index 0000000..3c9942f
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_-p_initial
@@ -0,0 +1,2 @@
+$ git diff-tree --pretty -p initial
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_-p_side b/t/t4013/diff.diff-tree_--pretty_-p_side
new file mode 100644
index 0000000..b993aa7
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_-p_side
@@ -0,0 +1,38 @@
+$ git diff-tree --pretty -p side
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_initial b/t/t4013/diff.diff-tree_--pretty_initial
new file mode 100644
index 0000000..14715bf
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_initial
@@ -0,0 +1,2 @@
+$ git diff-tree --pretty initial
+$
diff --git a/t/t4013/diff.diff-tree_--pretty_side b/t/t4013/diff.diff-tree_--pretty_side
new file mode 100644
index 0000000..e9b6e1c
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--pretty_side
@@ -0,0 +1,11 @@
+$ git diff-tree --pretty side
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+:040000 040000 da7a33fa77d8066d6698643940ce5860fe2d7fb3 f977ed46ae6873c1c30ab878e15a4accedc3618b M dir
+:100644 100644 01e79c32a8c99c557f0757da7cb6d65b3414466d f4615da674c09df322d6ba8d6b21ecfb1b1ba510 M file0
+:000000 100644 0000000000000000000000000000000000000000 7289e35bff32727c08dda207511bec138fdb9ea5 A file3
+$
diff --git a/t/t4013/diff.diff-tree_--root_--abbrev_initial b/t/t4013/diff.diff-tree_--root_--abbrev_initial
new file mode 100644
index 0000000..5aa84b2
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--root_--abbrev_initial
@@ -0,0 +1,6 @@
+$ git diff-tree --root --abbrev initial
+444ac553ac7612cc88969031b02b3767fb8a353a
+:000000 040000 0000000... da7a33f... A dir
+:000000 100644 0000000... 01e79c3... A file0
+:000000 100644 0000000... 01e79c3... A file2
+$
diff --git a/t/t4013/diff.diff-tree_--root_--patch-with-raw_initial b/t/t4013/diff.diff-tree_--root_--patch-with-raw_initial
new file mode 100644
index 0000000..d295e47
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--root_--patch-with-raw_initial
@@ -0,0 +1,33 @@
+$ git diff-tree --root --patch-with-raw initial
+444ac553ac7612cc88969031b02b3767fb8a353a
+:000000 100644 0000000000000000000000000000000000000000 35d242ba79ae89ac695e26b3d4c27a8e6f028f9e A dir/sub
+:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file0
+:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file2
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial
new file mode 100644
index 0000000..1562b62
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial
@@ -0,0 +1,34 @@
+$ git diff-tree --root --patch-with-stat initial
+444ac553ac7612cc88969031b02b3767fb8a353a
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 +++
+ 3 files changed, 8 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.diff-tree_--root_-p_initial b/t/t4013/diff.diff-tree_--root_-p_initial
new file mode 100644
index 0000000..3219c72
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--root_-p_initial
@@ -0,0 +1,29 @@
+$ git diff-tree --root -p initial
+444ac553ac7612cc88969031b02b3767fb8a353a
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.diff-tree_--root_-r_--abbrev=4_initial b/t/t4013/diff.diff-tree_--root_-r_--abbrev=4_initial
new file mode 100644
index 0000000..0c53616
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--root_-r_--abbrev=4_initial
@@ -0,0 +1,6 @@
+$ git diff-tree --root -r --abbrev=4 initial
+444ac553ac7612cc88969031b02b3767fb8a353a
+:000000 100644 0000... 35d2... A dir/sub
+:000000 100644 0000... 01e7... A file0
+:000000 100644 0000... 01e7... A file2
+$
diff --git a/t/t4013/diff.diff-tree_--root_-r_--abbrev_initial b/t/t4013/diff.diff-tree_--root_-r_--abbrev_initial
new file mode 100644
index 0000000..c7b460f
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--root_-r_--abbrev_initial
@@ -0,0 +1,6 @@
+$ git diff-tree --root -r --abbrev initial
+444ac553ac7612cc88969031b02b3767fb8a353a
+:000000 100644 0000000... 35d242b... A dir/sub
+:000000 100644 0000000... 01e79c3... A file0
+:000000 100644 0000000... 01e79c3... A file2
+$
diff --git a/t/t4013/diff.diff-tree_--root_-r_initial b/t/t4013/diff.diff-tree_--root_-r_initial
new file mode 100644
index 0000000..eed435e
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--root_-r_initial
@@ -0,0 +1,6 @@
+$ git diff-tree --root -r initial
+444ac553ac7612cc88969031b02b3767fb8a353a
+:000000 100644 0000000000000000000000000000000000000000 35d242ba79ae89ac695e26b3d4c27a8e6f028f9e A dir/sub
+:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file0
+:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file2
+$
diff --git a/t/t4013/diff.diff-tree_--root_initial b/t/t4013/diff.diff-tree_--root_initial
new file mode 100644
index 0000000..ddf6b06
--- /dev/null
+++ b/t/t4013/diff.diff-tree_--root_initial
@@ -0,0 +1,6 @@
+$ git diff-tree --root initial
+444ac553ac7612cc88969031b02b3767fb8a353a
+:000000 040000 0000000000000000000000000000000000000000 da7a33fa77d8066d6698643940ce5860fe2d7fb3 A dir
+:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file0
+:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file2
+$
diff --git a/t/t4013/diff.diff-tree_-c_--abbrev_master b/t/t4013/diff.diff-tree_-c_--abbrev_master
new file mode 100644
index 0000000..39d511a
--- /dev/null
+++ b/t/t4013/diff.diff-tree_-c_--abbrev_master
@@ -0,0 +1,5 @@
+$ git diff-tree -c --abbrev master
+176b998f5d647cbd77a9d8acf4531e930754d16d
+::100644 100644 100644 cead32e... 7289e35... 992913c... MM dir/sub
+::100644 100644 100644 b414108... f4615da... 10a8a9f... MM file0
+$
diff --git a/t/t4013/diff.diff-tree_-c_--stat_--summary_master b/t/t4013/diff.diff-tree_-c_--stat_--summary_master
new file mode 100644
index 0000000..2d239fe
--- /dev/null
+++ b/t/t4013/diff.diff-tree_-c_--stat_--summary_master
@@ -0,0 +1,6 @@
+$ git diff-tree -c --stat --summary master
+176b998f5d647cbd77a9d8acf4531e930754d16d
+ dir/sub | 2 ++
+ file0 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+$
diff --git a/t/t4013/diff.diff-tree_-c_--stat_--summary_side b/t/t4013/diff.diff-tree_-c_--stat_--summary_side
new file mode 100644
index 0000000..2afcca1
--- /dev/null
+++ b/t/t4013/diff.diff-tree_-c_--stat_--summary_side
@@ -0,0 +1,8 @@
+$ git diff-tree -c --stat --summary side
+c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+ create mode 100644 file3
+$
diff --git a/t/t4013/diff.diff-tree_-c_--stat_master b/t/t4013/diff.diff-tree_-c_--stat_master
new file mode 100644
index 0000000..226300b
--- /dev/null
+++ b/t/t4013/diff.diff-tree_-c_--stat_master
@@ -0,0 +1,6 @@
+$ git diff-tree -c --stat master
+176b998f5d647cbd77a9d8acf4531e930754d16d
+ dir/sub | 2 ++
+ file0 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+$
diff --git a/t/t4013/diff.diff-tree_-c_master b/t/t4013/diff.diff-tree_-c_master
new file mode 100644
index 0000000..c258efe
--- /dev/null
+++ b/t/t4013/diff.diff-tree_-c_master
@@ -0,0 +1,5 @@
+$ git diff-tree -c master
+176b998f5d647cbd77a9d8acf4531e930754d16d
+::100644 100644 100644 cead32e925b1420c84c14cbf7cf755e7e45af8ad 7289e35bff32727c08dda207511bec138fdb9ea5 992913c5aa0a5476d10c49ed0f21fc0c6d1aedf3 MM dir/sub
+::100644 100644 100644 b414108e81e5091fe0974a1858b4d0d22b107f70 f4615da674c09df322d6ba8d6b21ecfb1b1ba510 10a8a9f3657f91a156b9f0184ed79a20adef9f7f MM file0
+$
diff --git a/t/t4013/diff.diff-tree_-p_-m_master b/t/t4013/diff.diff-tree_-p_-m_master
new file mode 100644
index 0000000..1be7215
--- /dev/null
+++ b/t/t4013/diff.diff-tree_-p_-m_master
@@ -0,0 +1,80 @@
+$ git diff-tree -p -m master
+176b998f5d647cbd77a9d8acf4531e930754d16d
+diff --git a/dir/sub b/dir/sub
+index cead32e..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -4,3 +4,5 @@ C
+ D
+ E
+ F
++1
++2
+diff --git a/file0 b/file0
+index b414108..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -4,3 +4,6 @@
+ 4
+ 5
+ 6
++A
++B
++C
+176b998f5d647cbd77a9d8acf4531e930754d16d
+diff --git a/dir/sub b/dir/sub
+index 7289e35..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,4 +1,8 @@
+ A
+ B
++C
++D
++E
++F
+ 1
+ 2
+diff --git a/file0 b/file0
+index f4615da..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -1,6 +1,9 @@
+ 1
+ 2
+ 3
++4
++5
++6
+ A
+ B
+ C
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+diff --git a/file3 b/file3
+deleted file mode 100644
+index 7289e35..0000000
+--- a/file3
++++ /dev/null
+@@ -1,4 +0,0 @@
+-A
+-B
+-1
+-2
+$
diff --git a/t/t4013/diff.diff-tree_-p_initial b/t/t4013/diff.diff-tree_-p_initial
new file mode 100644
index 0000000..e20ce88
--- /dev/null
+++ b/t/t4013/diff.diff-tree_-p_initial
@@ -0,0 +1,2 @@
+$ git diff-tree -p initial
+$
diff --git a/t/t4013/diff.diff-tree_-p_master b/t/t4013/diff.diff-tree_-p_master
new file mode 100644
index 0000000..b182875
--- /dev/null
+++ b/t/t4013/diff.diff-tree_-p_master
@@ -0,0 +1,2 @@
+$ git diff-tree -p master
+$
diff --git a/t/t4013/diff.diff-tree_-r_--abbrev=4_initial b/t/t4013/diff.diff-tree_-r_--abbrev=4_initial
new file mode 100644
index 0000000..c5a3aa5
--- /dev/null
+++ b/t/t4013/diff.diff-tree_-r_--abbrev=4_initial
@@ -0,0 +1,2 @@
+$ git diff-tree -r --abbrev=4 initial
+$
diff --git a/t/t4013/diff.diff-tree_-r_--abbrev_initial b/t/t4013/diff.diff-tree_-r_--abbrev_initial
new file mode 100644
index 0000000..0b689b7
--- /dev/null
+++ b/t/t4013/diff.diff-tree_-r_--abbrev_initial
@@ -0,0 +1,2 @@
+$ git diff-tree -r --abbrev initial
+$
diff --git a/t/t4013/diff.diff-tree_-r_initial b/t/t4013/diff.diff-tree_-r_initial
new file mode 100644
index 0000000..1765d83
--- /dev/null
+++ b/t/t4013/diff.diff-tree_-r_initial
@@ -0,0 +1,2 @@
+$ git diff-tree -r initial
+$
diff --git a/t/t4013/diff.diff-tree_initial b/t/t4013/diff.diff-tree_initial
new file mode 100644
index 0000000..b49fc53
--- /dev/null
+++ b/t/t4013/diff.diff-tree_initial
@@ -0,0 +1,2 @@
+$ git diff-tree initial
+$
diff --git a/t/t4013/diff.diff-tree_master b/t/t4013/diff.diff-tree_master
new file mode 100644
index 0000000..fe9226f
--- /dev/null
+++ b/t/t4013/diff.diff-tree_master
@@ -0,0 +1,2 @@
+$ git diff-tree master
+$
diff --git a/t/t4013/diff.diff_--abbrev_initial..side b/t/t4013/diff.diff_--abbrev_initial..side
new file mode 100644
index 0000000..a88e66f
--- /dev/null
+++ b/t/t4013/diff.diff_--abbrev_initial..side
@@ -0,0 +1,32 @@
+$ git diff --abbrev initial..side
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+$
diff --git a/t/t4013/diff.diff_--patch-with-raw_-r_initial..side b/t/t4013/diff.diff_--patch-with-raw_-r_initial..side
new file mode 100644
index 0000000..3590dc7
--- /dev/null
+++ b/t/t4013/diff.diff_--patch-with-raw_-r_initial..side
@@ -0,0 +1,36 @@
+$ git diff --patch-with-raw -r initial..side
+:100644 100644 35d242b... 7289e35... M dir/sub
+:100644 100644 01e79c3... f4615da... M file0
+:000000 100644 0000000... 7289e35... A file3
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+$
diff --git a/t/t4013/diff.diff_--patch-with-raw_initial..side b/t/t4013/diff.diff_--patch-with-raw_initial..side
new file mode 100644
index 0000000..b21d5dc
--- /dev/null
+++ b/t/t4013/diff.diff_--patch-with-raw_initial..side
@@ -0,0 +1,36 @@
+$ git diff --patch-with-raw initial..side
+:100644 100644 35d242b... 7289e35... M dir/sub
+:100644 100644 01e79c3... f4615da... M file0
+:000000 100644 0000000... 7289e35... A file3
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+$
diff --git a/t/t4013/diff.diff_--patch-with-stat_-r_initial..side b/t/t4013/diff.diff_--patch-with-stat_-r_initial..side
new file mode 100644
index 0000000..9ed317a
--- /dev/null
+++ b/t/t4013/diff.diff_--patch-with-stat_-r_initial..side
@@ -0,0 +1,37 @@
+$ git diff --patch-with-stat -r initial..side
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+$
diff --git a/t/t4013/diff.diff_--patch-with-stat_initial..side b/t/t4013/diff.diff_--patch-with-stat_initial..side
new file mode 100644
index 0000000..8b50629
--- /dev/null
+++ b/t/t4013/diff.diff_--patch-with-stat_initial..side
@@ -0,0 +1,37 @@
+$ git diff --patch-with-stat initial..side
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+$
diff --git a/t/t4013/diff.diff_--stat_initial..side b/t/t4013/diff.diff_--stat_initial..side
new file mode 100644
index 0000000..0517b5d
--- /dev/null
+++ b/t/t4013/diff.diff_--stat_initial..side
@@ -0,0 +1,6 @@
+$ git diff --stat initial..side
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+$
diff --git a/t/t4013/diff.diff_-r_--stat_initial..side b/t/t4013/diff.diff_-r_--stat_initial..side
new file mode 100644
index 0000000..245220d
--- /dev/null
+++ b/t/t4013/diff.diff_-r_--stat_initial..side
@@ -0,0 +1,6 @@
+$ git diff -r --stat initial..side
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+$
diff --git a/t/t4013/diff.diff_-r_initial..side b/t/t4013/diff.diff_-r_initial..side
new file mode 100644
index 0000000..5bb2fe2
--- /dev/null
+++ b/t/t4013/diff.diff_-r_initial..side
@@ -0,0 +1,32 @@
+$ git diff -r initial..side
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+$
diff --git a/t/t4013/diff.diff_initial..side b/t/t4013/diff.diff_initial..side
new file mode 100644
index 0000000..c8adaf5
--- /dev/null
+++ b/t/t4013/diff.diff_initial..side
@@ -0,0 +1,32 @@
+$ git diff initial..side
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+$
diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master b/t/t4013/diff.format-patch_--attach_--stdout_initial..master
new file mode 100644
index 0000000..a89bbbb
--- /dev/null
+++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master
@@ -0,0 +1,165 @@
+$ git format-patch --attach --stdout initial..master
+From 7952a93e09bf565b5592766a438b40cd81f4846f Mon Sep 17 00:00:00 2001
+From: A U Thor <author@example.com>
+Date: Mon, 26 Jun 2006 00:01:00 +0000
+Subject: [PATCH] Second
+MIME-Version: 1.0
+Content-Type: multipart/mixed;
+ boundary="------------g-i-t--v-e-r-s-i-o-n"
+
+This is a multi-part message in MIME format.
+--------------g-i-t--v-e-r-s-i-o-n
+Content-Type: text/plain; charset=UTF-8; format=fixed
+Content-Transfer-Encoding: 8bit
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+--------------g-i-t--v-e-r-s-i-o-n
+Content-Type: text/x-patch;
+ name="7952a93e09bf565b5592766a438b40cd81f4846f.diff"
+Content-Transfer-Encoding: 8bit
+Content-Disposition: inline;
+ filename="7952a93e09bf565b5592766a438b40cd81f4846f.diff"
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+--------------g-i-t--v-e-r-s-i-o-n--
+
+
+
+From 889b315013ef9f2e2f90aa0b054b267c8a557847 Mon Sep 17 00:00:00 2001
+From: A U Thor <author@example.com>
+Date: Mon, 26 Jun 2006 00:02:00 +0000
+Subject: [PATCH] Third
+MIME-Version: 1.0
+Content-Type: multipart/mixed;
+ boundary="------------g-i-t--v-e-r-s-i-o-n"
+
+This is a multi-part message in MIME format.
+--------------g-i-t--v-e-r-s-i-o-n
+Content-Type: text/plain; charset=UTF-8; format=fixed
+Content-Transfer-Encoding: 8bit
+---
+ dir/sub | 2 ++
+ file1 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+--------------g-i-t--v-e-r-s-i-o-n
+Content-Type: text/x-patch;
+ name="889b315013ef9f2e2f90aa0b054b267c8a557847.diff"
+Content-Transfer-Encoding: 8bit
+Content-Disposition: inline;
+ filename="889b315013ef9f2e2f90aa0b054b267c8a557847.diff"
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+--------------g-i-t--v-e-r-s-i-o-n--
+
+
+
+From c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Mon Sep 17 00:00:00 2001
+From: A U Thor <author@example.com>
+Date: Mon, 26 Jun 2006 00:03:00 +0000
+Subject: [PATCH] Side
+MIME-Version: 1.0
+Content-Type: multipart/mixed;
+ boundary="------------g-i-t--v-e-r-s-i-o-n"
+
+This is a multi-part message in MIME format.
+--------------g-i-t--v-e-r-s-i-o-n
+Content-Type: text/plain; charset=UTF-8; format=fixed
+Content-Transfer-Encoding: 8bit
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+--------------g-i-t--v-e-r-s-i-o-n
+Content-Type: text/x-patch;
+ name="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff"
+Content-Transfer-Encoding: 8bit
+Content-Disposition: inline;
+ filename="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff"
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+--------------g-i-t--v-e-r-s-i-o-n--
+
+
+$
diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^
new file mode 100644
index 0000000..4de9091
--- /dev/null
+++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^
@@ -0,0 +1,106 @@
+$ git format-patch --attach --stdout initial..master^
+From 7952a93e09bf565b5592766a438b40cd81f4846f Mon Sep 17 00:00:00 2001
+From: A U Thor <author@example.com>
+Date: Mon, 26 Jun 2006 00:01:00 +0000
+Subject: [PATCH] Second
+MIME-Version: 1.0
+Content-Type: multipart/mixed;
+ boundary="------------g-i-t--v-e-r-s-i-o-n"
+
+This is a multi-part message in MIME format.
+--------------g-i-t--v-e-r-s-i-o-n
+Content-Type: text/plain; charset=UTF-8; format=fixed
+Content-Transfer-Encoding: 8bit
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+--------------g-i-t--v-e-r-s-i-o-n
+Content-Type: text/x-patch;
+ name="7952a93e09bf565b5592766a438b40cd81f4846f.diff"
+Content-Transfer-Encoding: 8bit
+Content-Disposition: inline;
+ filename="7952a93e09bf565b5592766a438b40cd81f4846f.diff"
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+--------------g-i-t--v-e-r-s-i-o-n--
+
+
+
+From 889b315013ef9f2e2f90aa0b054b267c8a557847 Mon Sep 17 00:00:00 2001
+From: A U Thor <author@example.com>
+Date: Mon, 26 Jun 2006 00:02:00 +0000
+Subject: [PATCH] Third
+MIME-Version: 1.0
+Content-Type: multipart/mixed;
+ boundary="------------g-i-t--v-e-r-s-i-o-n"
+
+This is a multi-part message in MIME format.
+--------------g-i-t--v-e-r-s-i-o-n
+Content-Type: text/plain; charset=UTF-8; format=fixed
+Content-Transfer-Encoding: 8bit
+---
+ dir/sub | 2 ++
+ file1 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+--------------g-i-t--v-e-r-s-i-o-n
+Content-Type: text/x-patch;
+ name="889b315013ef9f2e2f90aa0b054b267c8a557847.diff"
+Content-Transfer-Encoding: 8bit
+Content-Disposition: inline;
+ filename="889b315013ef9f2e2f90aa0b054b267c8a557847.diff"
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+--------------g-i-t--v-e-r-s-i-o-n--
+
+
+$
diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..side b/t/t4013/diff.format-patch_--attach_--stdout_initial..side
new file mode 100644
index 0000000..3769fa6
--- /dev/null
+++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..side
@@ -0,0 +1,60 @@
+$ git format-patch --attach --stdout initial..side
+From c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Mon Sep 17 00:00:00 2001
+From: A U Thor <author@example.com>
+Date: Mon, 26 Jun 2006 00:03:00 +0000
+Subject: [PATCH] Side
+MIME-Version: 1.0
+Content-Type: multipart/mixed;
+ boundary="------------g-i-t--v-e-r-s-i-o-n"
+
+This is a multi-part message in MIME format.
+--------------g-i-t--v-e-r-s-i-o-n
+Content-Type: text/plain; charset=UTF-8; format=fixed
+Content-Transfer-Encoding: 8bit
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+--------------g-i-t--v-e-r-s-i-o-n
+Content-Type: text/x-patch;
+ name="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff"
+Content-Transfer-Encoding: 8bit
+Content-Disposition: inline;
+ filename="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff"
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+--------------g-i-t--v-e-r-s-i-o-n--
+
+
+$
diff --git a/t/t4013/diff.format-patch_--stdout_initial..master b/t/t4013/diff.format-patch_--stdout_initial..master
new file mode 100644
index 0000000..b7b4e7c
--- /dev/null
+++ b/t/t4013/diff.format-patch_--stdout_initial..master
@@ -0,0 +1,120 @@
+$ git format-patch --stdout initial..master
+From 7952a93e09bf565b5592766a438b40cd81f4846f Mon Sep 17 00:00:00 2001
+From: A U Thor <author@example.com>
+Date: Mon, 26 Jun 2006 00:01:00 +0000
+Subject: [PATCH] Second
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+--
+g-i-t--v-e-r-s-i-o-n
+
+
+From 889b315013ef9f2e2f90aa0b054b267c8a557847 Mon Sep 17 00:00:00 2001
+From: A U Thor <author@example.com>
+Date: Mon, 26 Jun 2006 00:02:00 +0000
+Subject: [PATCH] Third
+---
+ dir/sub | 2 ++
+ file1 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+--
+g-i-t--v-e-r-s-i-o-n
+
+
+From c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Mon Sep 17 00:00:00 2001
+From: A U Thor <author@example.com>
+Date: Mon, 26 Jun 2006 00:03:00 +0000
+Subject: [PATCH] Side
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+--
+g-i-t--v-e-r-s-i-o-n
+
+$
diff --git a/t/t4013/diff.format-patch_--stdout_initial..master^ b/t/t4013/diff.format-patch_--stdout_initial..master^
new file mode 100644
index 0000000..e56dd98
--- /dev/null
+++ b/t/t4013/diff.format-patch_--stdout_initial..master^
@@ -0,0 +1,76 @@
+$ git format-patch --stdout initial..master^
+From 7952a93e09bf565b5592766a438b40cd81f4846f Mon Sep 17 00:00:00 2001
+From: A U Thor <author@example.com>
+Date: Mon, 26 Jun 2006 00:01:00 +0000
+Subject: [PATCH] Second
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+--
+g-i-t--v-e-r-s-i-o-n
+
+
+From 889b315013ef9f2e2f90aa0b054b267c8a557847 Mon Sep 17 00:00:00 2001
+From: A U Thor <author@example.com>
+Date: Mon, 26 Jun 2006 00:02:00 +0000
+Subject: [PATCH] Third
+---
+ dir/sub | 2 ++
+ file1 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+--
+g-i-t--v-e-r-s-i-o-n
+
+$
diff --git a/t/t4013/diff.format-patch_--stdout_initial..side b/t/t4013/diff.format-patch_--stdout_initial..side
new file mode 100644
index 0000000..e7ddbf4
--- /dev/null
+++ b/t/t4013/diff.format-patch_--stdout_initial..side
@@ -0,0 +1,45 @@
+$ git format-patch --stdout initial..side
+From c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Mon Sep 17 00:00:00 2001
+From: A U Thor <author@example.com>
+Date: Mon, 26 Jun 2006 00:03:00 +0000
+Subject: [PATCH] Side
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+--
+g-i-t--v-e-r-s-i-o-n
+
+$
diff --git a/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_
new file mode 100644
index 0000000..cc55376
--- /dev/null
+++ b/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_
@@ -0,0 +1,72 @@
+$ git log --patch-with-stat --summary master -- dir/
+commit 176b998f5d647cbd77a9d8acf4531e930754d16d
+Merge: 889b315... c7a2ab9...
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+---
+ dir/sub | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+---
+ dir/sub | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+$
diff --git a/t/t4013/diff.log_--patch-with-stat_master b/t/t4013/diff.log_--patch-with-stat_master
new file mode 100644
index 0000000..b97969d
--- /dev/null
+++ b/t/t4013/diff.log_--patch-with-stat_master
@@ -0,0 +1,127 @@
+$ git log --patch-with-stat master
+commit 176b998f5d647cbd77a9d8acf4531e930754d16d
+Merge: 889b315... c7a2ab9...
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+---
+ dir/sub | 2 ++
+ file1 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+$
diff --git a/t/t4013/diff.log_--patch-with-stat_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_master_--_dir_
new file mode 100644
index 0000000..71a6d0f
--- /dev/null
+++ b/t/t4013/diff.log_--patch-with-stat_master_--_dir_
@@ -0,0 +1,72 @@
+$ git log --patch-with-stat master -- dir/
+commit 176b998f5d647cbd77a9d8acf4531e930754d16d
+Merge: 889b315... c7a2ab9...
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+---
+ dir/sub | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+---
+ dir/sub | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+$
diff --git a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master
new file mode 100644
index 0000000..b652c6a
--- /dev/null
+++ b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master
@@ -0,0 +1,197 @@
+$ git log --root --cc --patch-with-stat --summary master
+commit 176b998f5d647cbd77a9d8acf4531e930754d16d
+Merge: 889b315... c7a2ab9...
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+ dir/sub | 2 ++
+ file0 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --cc dir/sub
+index cead32e,7289e35..992913c
+--- a/dir/sub
++++ b/dir/sub
+@@@ -1,6 -1,4 +1,8 @@@
+ A
+ B
+ +C
+ +D
+ +E
+ +F
++ 1
++ 2
+diff --cc file0
+index b414108,f4615da..10a8a9f
+--- a/file0
++++ b/file0
+@@@ -1,6 -1,6 +1,9 @@@
+ 1
+ 2
+ 3
+ +4
+ +5
+ +6
++ A
++ B
++ C
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+ create mode 100644 file3
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+---
+ dir/sub | 2 ++
+ file1 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+ create mode 100644 file1
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+ delete mode 100644 file2
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 +++
+ 3 files changed, 8 insertions(+), 0 deletions(-)
+ create mode 100644 dir/sub
+ create mode 100644 file0
+ create mode 100644 file2
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.log_--root_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--patch-with-stat_--summary_master
new file mode 100644
index 0000000..b24a504
--- /dev/null
+++ b/t/t4013/diff.log_--root_--patch-with-stat_--summary_master
@@ -0,0 +1,165 @@
+$ git log --root --patch-with-stat --summary master
+commit 176b998f5d647cbd77a9d8acf4531e930754d16d
+Merge: 889b315... c7a2ab9...
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+ create mode 100644 file3
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+---
+ dir/sub | 2 ++
+ file1 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+ create mode 100644 file1
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+ delete mode 100644 file2
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 +++
+ 3 files changed, 8 insertions(+), 0 deletions(-)
+ create mode 100644 dir/sub
+ create mode 100644 file0
+ create mode 100644 file2
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.log_--root_--patch-with-stat_master b/t/t4013/diff.log_--root_--patch-with-stat_master
new file mode 100644
index 0000000..1e9bdc4
--- /dev/null
+++ b/t/t4013/diff.log_--root_--patch-with-stat_master
@@ -0,0 +1,159 @@
+$ git log --root --patch-with-stat master
+commit 176b998f5d647cbd77a9d8acf4531e930754d16d
+Merge: 889b315... c7a2ab9...
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+---
+ dir/sub | 2 ++
+ file1 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 +++
+ 3 files changed, 8 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master
new file mode 100644
index 0000000..3a155d2
--- /dev/null
+++ b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master
@@ -0,0 +1,197 @@
+$ git log --root -c --patch-with-stat --summary master
+commit 176b998f5d647cbd77a9d8acf4531e930754d16d
+Merge: 889b315... c7a2ab9...
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+ dir/sub | 2 ++
+ file0 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --combined dir/sub
+index cead32e,7289e35..992913c
+--- a/dir/sub
++++ b/dir/sub
+@@@ -1,6 -1,4 +1,8 @@@
+ A
+ B
+ +C
+ +D
+ +E
+ +F
++ 1
++ 2
+diff --combined file0
+index b414108,f4615da..10a8a9f
+--- a/file0
++++ b/file0
+@@@ -1,6 -1,6 +1,9 @@@
+ 1
+ 2
+ 3
+ +4
+ +5
+ +6
++ A
++ B
++ C
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+ create mode 100644 file3
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+---
+ dir/sub | 2 ++
+ file1 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+ create mode 100644 file1
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+ delete mode 100644 file2
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 +++
+ 3 files changed, 8 insertions(+), 0 deletions(-)
+ create mode 100644 dir/sub
+ create mode 100644 file0
+ create mode 100644 file2
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.log_--root_-p_master b/t/t4013/diff.log_--root_-p_master
new file mode 100644
index 0000000..2296986
--- /dev/null
+++ b/t/t4013/diff.log_--root_-p_master
@@ -0,0 +1,140 @@
+$ git log --root -p master
+commit 176b998f5d647cbd77a9d8acf4531e930754d16d
+Merge: 889b315... c7a2ab9...
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.log_--root_master b/t/t4013/diff.log_--root_master
new file mode 100644
index 0000000..7554a46
--- /dev/null
+++ b/t/t4013/diff.log_--root_master
@@ -0,0 +1,32 @@
+$ git log --root master
+commit 176b998f5d647cbd77a9d8acf4531e930754d16d
+Merge: 889b315... c7a2ab9...
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+$
diff --git a/t/t4013/diff.log_-SF_-p_master b/t/t4013/diff.log_-SF_-p_master
new file mode 100644
index 0000000..db2264c
--- /dev/null
+++ b/t/t4013/diff.log_-SF_-p_master
@@ -0,0 +1,18 @@
+$ git log -SF -p master
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+$
diff --git a/t/t4013/diff.log_-SF_master b/t/t4013/diff.log_-SF_master
new file mode 100644
index 0000000..f307b4d
--- /dev/null
+++ b/t/t4013/diff.log_-SF_master
@@ -0,0 +1,8 @@
+$ git log -SF master
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+
+$
diff --git a/t/t4013/diff.log_-p_master b/t/t4013/diff.log_-p_master
new file mode 100644
index 0000000..e82a72f
--- /dev/null
+++ b/t/t4013/diff.log_-p_master
@@ -0,0 +1,113 @@
+$ git log -p master
+commit 176b998f5d647cbd77a9d8acf4531e930754d16d
+Merge: 889b315... c7a2ab9...
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+$
diff --git a/t/t4013/diff.log_master b/t/t4013/diff.log_master
new file mode 100644
index 0000000..7b86ed1
--- /dev/null
+++ b/t/t4013/diff.log_master
@@ -0,0 +1,32 @@
+$ git log master
+commit 176b998f5d647cbd77a9d8acf4531e930754d16d
+Merge: 889b315... c7a2ab9...
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+$
diff --git a/t/t4013/diff.show_--patch-with-raw_side b/t/t4013/diff.show_--patch-with-raw_side
new file mode 100644
index 0000000..221b46a
--- /dev/null
+++ b/t/t4013/diff.show_--patch-with-raw_side
@@ -0,0 +1,42 @@
+$ git show --patch-with-raw side
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+:100644 100644 35d242b... 7289e35... M dir/sub
+:100644 100644 01e79c3... f4615da... M file0
+:000000 100644 0000000... 7289e35... A file3
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+$
diff --git a/t/t4013/diff.show_--patch-with-stat_--summary_side b/t/t4013/diff.show_--patch-with-stat_--summary_side
new file mode 100644
index 0000000..377f2b7
--- /dev/null
+++ b/t/t4013/diff.show_--patch-with-stat_--summary_side
@@ -0,0 +1,44 @@
+$ git show --patch-with-stat --summary side
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+ create mode 100644 file3
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+$
diff --git a/t/t4013/diff.show_--patch-with-stat_side b/t/t4013/diff.show_--patch-with-stat_side
new file mode 100644
index 0000000..fb14c53
--- /dev/null
+++ b/t/t4013/diff.show_--patch-with-stat_side
@@ -0,0 +1,43 @@
+$ git show --patch-with-stat side
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+$
diff --git a/t/t4013/diff.show_--root_initial b/t/t4013/diff.show_--root_initial
new file mode 100644
index 0000000..8c89136
--- /dev/null
+++ b/t/t4013/diff.show_--root_initial
@@ -0,0 +1,34 @@
+$ git show --root initial
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.show_--stat_--summary_side b/t/t4013/diff.show_--stat_--summary_side
new file mode 100644
index 0000000..5bd5977
--- /dev/null
+++ b/t/t4013/diff.show_--stat_--summary_side
@@ -0,0 +1,13 @@
+$ git show --stat --summary side
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+ create mode 100644 file3
+$
diff --git a/t/t4013/diff.show_--stat_side b/t/t4013/diff.show_--stat_side
new file mode 100644
index 0000000..3b22327
--- /dev/null
+++ b/t/t4013/diff.show_--stat_side
@@ -0,0 +1,12 @@
+$ git show --stat side
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+$
diff --git a/t/t4013/diff.show_initial b/t/t4013/diff.show_initial
new file mode 100644
index 0000000..4c4066a
--- /dev/null
+++ b/t/t4013/diff.show_initial
@@ -0,0 +1,7 @@
+$ git show initial
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+$
diff --git a/t/t4013/diff.show_master b/t/t4013/diff.show_master
new file mode 100644
index 0000000..3772a87
--- /dev/null
+++ b/t/t4013/diff.show_master
@@ -0,0 +1,36 @@
+$ git show master
+commit 176b998f5d647cbd77a9d8acf4531e930754d16d
+Merge: 889b315... c7a2ab9...
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+diff --cc dir/sub
+index cead32e,7289e35..992913c
+--- a/dir/sub
++++ b/dir/sub
+@@@ -1,6 -1,4 +1,8 @@@
+ A
+ B
+ +C
+ +D
+ +E
+ +F
++ 1
++ 2
+diff --cc file0
+index b414108,f4615da..10a8a9f
+--- a/file0
++++ b/file0
+@@@ -1,6 -1,6 +1,9 @@@
+ 1
+ 2
+ 3
+ +4
+ +5
+ +6
++ A
++ B
++ C
+$
diff --git a/t/t4013/diff.show_side b/t/t4013/diff.show_side
new file mode 100644
index 0000000..530a073
--- /dev/null
+++ b/t/t4013/diff.show_side
@@ -0,0 +1,38 @@
+$ git show side
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+$
diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_
new file mode 100644
index 0000000..054513f
--- /dev/null
+++ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_
@@ -0,0 +1,59 @@
+$ git whatchanged --patch-with-stat --summary master -- dir/
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+---
+ dir/sub | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+---
+ dir/sub | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+$
diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master b/t/t4013/diff.whatchanged_--patch-with-stat_master
new file mode 100644
index 0000000..a89b573
--- /dev/null
+++ b/t/t4013/diff.whatchanged_--patch-with-stat_master
@@ -0,0 +1,114 @@
+$ git whatchanged --patch-with-stat master
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+---
+ dir/sub | 2 ++
+ file1 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+$
diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_
new file mode 100644
index 0000000..b6d9752
--- /dev/null
+++ b/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_
@@ -0,0 +1,59 @@
+$ git whatchanged --patch-with-stat master -- dir/
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+---
+ dir/sub | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+---
+ dir/sub | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+$
diff --git a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master
new file mode 100644
index 0000000..e9e17cd
--- /dev/null
+++ b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master
@@ -0,0 +1,197 @@
+$ git whatchanged --root --cc --patch-with-stat --summary master
+commit 176b998f5d647cbd77a9d8acf4531e930754d16d
+Merge: 889b315... c7a2ab9...
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+ dir/sub | 2 ++
+ file0 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --cc dir/sub
+index cead32e,7289e35..992913c
+--- a/dir/sub
++++ b/dir/sub
+@@@ -1,6 -1,4 +1,8 @@@
+ A
+ B
+ +C
+ +D
+ +E
+ +F
++ 1
++ 2
+diff --cc file0
+index b414108,f4615da..10a8a9f
+--- a/file0
++++ b/file0
+@@@ -1,6 -1,6 +1,9 @@@
+ 1
+ 2
+ 3
+ +4
+ +5
+ +6
++ A
++ B
++ C
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+ create mode 100644 file3
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+---
+ dir/sub | 2 ++
+ file1 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+ create mode 100644 file1
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+ delete mode 100644 file2
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 +++
+ 3 files changed, 8 insertions(+), 0 deletions(-)
+ create mode 100644 dir/sub
+ create mode 100644 file0
+ create mode 100644 file2
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master
new file mode 100644
index 0000000..f707bfa
--- /dev/null
+++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master
@@ -0,0 +1,158 @@
+$ git whatchanged --root --patch-with-stat --summary master
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+ create mode 100644 file3
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+---
+ dir/sub | 2 ++
+ file1 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+ create mode 100644 file1
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+ delete mode 100644 file2
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 +++
+ 3 files changed, 8 insertions(+), 0 deletions(-)
+ create mode 100644 dir/sub
+ create mode 100644 file0
+ create mode 100644 file2
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_master
new file mode 100644
index 0000000..61aca41
--- /dev/null
+++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_master
@@ -0,0 +1,152 @@
+$ git whatchanged --root --patch-with-stat master
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+---
+ dir/sub | 2 ++
+ file1 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 +++
+ 3 files changed, 8 insertions(+), 0 deletions(-)
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master
new file mode 100644
index 0000000..596765e
--- /dev/null
+++ b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master
@@ -0,0 +1,197 @@
+$ git whatchanged --root -c --patch-with-stat --summary master
+commit 176b998f5d647cbd77a9d8acf4531e930754d16d
+Merge: 889b315... c7a2ab9...
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:04:00 2006 +0000
+
+ Merge branch 'side'
+
+ dir/sub | 2 ++
+ file0 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --combined dir/sub
+index cead32e,7289e35..992913c
+--- a/dir/sub
++++ b/dir/sub
+@@@ -1,6 -1,4 +1,8 @@@
+ A
+ B
+ +C
+ +D
+ +E
+ +F
++ 1
++ 2
+diff --combined file0
+index b414108,f4615da..10a8a9f
+--- a/file0
++++ b/file0
+@@@ -1,6 -1,6 +1,9 @@@
+ 1
+ 2
+ 3
+ +4
+ +5
+ +6
++ A
++ B
++ C
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file3 | 4 ++++
+ 3 files changed, 9 insertions(+), 0 deletions(-)
+ create mode 100644 file3
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+---
+ dir/sub | 2 ++
+ file1 | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+ create mode 100644 file1
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+ delete mode 100644 file2
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+---
+ dir/sub | 2 ++
+ file0 | 3 +++
+ file2 | 3 +++
+ 3 files changed, 8 insertions(+), 0 deletions(-)
+ create mode 100644 dir/sub
+ create mode 100644 file0
+ create mode 100644 file2
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.whatchanged_--root_-p_master b/t/t4013/diff.whatchanged_--root_-p_master
new file mode 100644
index 0000000..b4cd05e
--- /dev/null
+++ b/t/t4013/diff.whatchanged_--root_-p_master
@@ -0,0 +1,133 @@
+$ git whatchanged --root -p master
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..35d242b
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000..01e79c3
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.whatchanged_--root_master b/t/t4013/diff.whatchanged_--root_master
new file mode 100644
index 0000000..011a221
--- /dev/null
+++ b/t/t4013/diff.whatchanged_--root_master
@@ -0,0 +1,40 @@
+$ git whatchanged --root master
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+:100644 100644 35d242b... 7289e35... M dir/sub
+:100644 100644 01e79c3... f4615da... M file0
+:000000 100644 0000000... 7289e35... A file3
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+
+:100644 100644 8422d40... cead32e... M dir/sub
+:000000 100644 0000000... b1e6722... A file1
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+
+:100644 100644 35d242b... 8422d40... M dir/sub
+:100644 100644 01e79c3... b414108... M file0
+:100644 000000 01e79c3... 0000000... D file2
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:00:00 2006 +0000
+
+ Initial
+
+:000000 100644 0000000... 35d242b... A dir/sub
+:000000 100644 0000000... 01e79c3... A file0
+:000000 100644 0000000... 01e79c3... A file2
+$
diff --git a/t/t4013/diff.whatchanged_-SF_-p_master b/t/t4013/diff.whatchanged_-SF_-p_master
new file mode 100644
index 0000000..6a76f4e
--- /dev/null
+++ b/t/t4013/diff.whatchanged_-SF_-p_master
@@ -0,0 +1,18 @@
+$ git whatchanged -SF -p master
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+$
diff --git a/t/t4013/diff.whatchanged_-SF_master b/t/t4013/diff.whatchanged_-SF_master
new file mode 100644
index 0000000..a4fe6f8
--- /dev/null
+++ b/t/t4013/diff.whatchanged_-SF_master
@@ -0,0 +1,9 @@
+$ git whatchanged -SF master
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+
+:100644 100644 8422d40... cead32e... M dir/sub
+$
diff --git a/t/t4013/diff.whatchanged_-p_master b/t/t4013/diff.whatchanged_-p_master
new file mode 100644
index 0000000..f9a4456
--- /dev/null
+++ b/t/t4013/diff.whatchanged_-p_master
@@ -0,0 +1,100 @@
+$ git whatchanged -p master
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..7289e35 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++1
++2
+diff --git a/file0 b/file0
+index 01e79c3..f4615da 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++A
++B
++C
+diff --git a/file3 b/file3
+new file mode 100644
+index 0000000..7289e35
+--- /dev/null
++++ b/file3
+@@ -0,0 +1,4 @@
++A
++B
++1
++2
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+$
diff --git a/t/t4013/diff.whatchanged_master b/t/t4013/diff.whatchanged_master
new file mode 100644
index 0000000..c22416c
--- /dev/null
+++ b/t/t4013/diff.whatchanged_master
@@ -0,0 +1,30 @@
+$ git whatchanged master
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:03:00 2006 +0000
+
+ Side
+
+:100644 100644 35d242b... 7289e35... M dir/sub
+:100644 100644 01e79c3... f4615da... M file0
+:000000 100644 0000000... 7289e35... A file3
+
+commit 889b315013ef9f2e2f90aa0b054b267c8a557847
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+
+:100644 100644 8422d40... cead32e... M dir/sub
+:000000 100644 0000000... b1e6722... A file1
+
+commit 7952a93e09bf565b5592766a438b40cd81f4846f
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:01:00 2006 +0000
+
+ Second
+
+:100644 100644 35d242b... 8422d40... M dir/sub
+:100644 100644 01e79c3... b414108... M file0
+:100644 000000 01e79c3... 0000000... D file2
+$
diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh
new file mode 100755
index 0000000..63e49f3
--- /dev/null
+++ b/t/t6200-fmt-merge-msg.sh
@@ -0,0 +1,163 @@
+#!/bin/sh
+#
+# Copyright (c) 2006, Junio C Hamano
+#
+
+test_description='fmt-merge-msg test'
+
+. ./test-lib.sh
+
+datestamp=1151939923
+setdate () {
+ GIT_COMMITTER_DATE="$datestamp +0200"
+ GIT_AUTHOR_DATE="$datestamp +0200"
+ datestamp=`expr "$datestamp" + 1`
+ export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
+}
+
+test_expect_success setup '
+ echo one >one &&
+ git add one &&
+ setdate &&
+ git commit -m "Initial" &&
+
+ echo uno >one &&
+ echo dos >two &&
+ git add two &&
+ setdate &&
+ git commit -a -m "Second" &&
+
+ git checkout -b left &&
+
+ echo $datestamp >one &&
+ setdate &&
+ git commit -a -m "Common #1" &&
+
+ echo $datestamp >one &&
+ setdate &&
+ git commit -a -m "Common #2" &&
+
+ git branch right &&
+
+ echo $datestamp >two &&
+ setdate &&
+ git commit -a -m "Left #3" &&
+
+ echo $datestamp >two &&
+ setdate &&
+ git commit -a -m "Left #4" &&
+
+ echo $datestamp >two &&
+ setdate &&
+ git commit -a -m "Left #5" &&
+
+ git checkout right &&
+
+ echo $datestamp >three &&
+ git add three &&
+ setdate &&
+ git commit -a -m "Right #3" &&
+
+ echo $datestamp >three &&
+ setdate &&
+ git commit -a -m "Right #4" &&
+
+ echo $datestamp >three &&
+ setdate &&
+ git commit -a -m "Right #5" &&
+
+ git show-branch
+'
+
+cat >expected <<\EOF
+Merge branch 'left'
+EOF
+
+test_expect_success 'merge-msg test #1' '
+
+ git checkout master &&
+ git fetch . left &&
+
+ git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+ diff -u actual expected
+'
+
+cat >expected <<\EOF
+Merge branch 'left' of ../trash
+EOF
+
+test_expect_success 'merge-msg test #2' '
+
+ git checkout master &&
+ git fetch ../trash left &&
+
+ git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+ diff -u actual expected
+'
+
+cat >expected <<\EOF
+Merge branch 'left'
+
+* left:
+ Left #5
+ Left #4
+ Left #3
+ Common #2
+ Common #1
+EOF
+
+test_expect_success 'merge-msg test #3' '
+
+ git repo-config merge.summary true &&
+
+ git checkout master &&
+ setdate &&
+ git fetch . left &&
+
+ git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+ diff -u actual expected
+'
+
+cat >expected <<\EOF
+Merge branches 'left' and 'right'
+
+* left:
+ Left #5
+ Left #4
+ Left #3
+ Common #2
+ Common #1
+
+* right:
+ Right #5
+ Right #4
+ Right #3
+ Common #2
+ Common #1
+EOF
+
+test_expect_success 'merge-msg test #4' '
+
+ git repo-config merge.summary true &&
+
+ git checkout master &&
+ setdate &&
+ git fetch . left right &&
+
+ git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+ diff -u actual expected
+'
+
+test_expect_success 'merge-msg test #5' '
+
+ git repo-config merge.summary yes &&
+
+ git checkout master &&
+ setdate &&
+ git fetch . left right &&
+
+ git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+ diff -u actual expected
+'
+
+test_done
diff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh
index 2496397..3a6490e 100755
--- a/t/t8001-annotate.sh
+++ b/t/t8001-annotate.sh
@@ -6,4 +6,10 @@ test_description='git-annotate'
PROG='git annotate'
. ../annotate-tests.sh
+test_expect_success \
+ 'Annotating an old revision works' \
+ '[ $(git annotate file master | awk "{print \$3}" | grep -c "^A$") -eq 2 ] && \
+ [ $(git annotate file master | awk "{print \$3}" | grep -c "^B$") -eq 2 ]'
+
+
test_done
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index a61da1e..e9ea33c 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -25,10 +25,13 @@ test_expect_success \
git add fake.sendmail
GIT_AUTHOR_NAME="A" git commit -a -m "Second."'
-test_expect_success \
- 'Extract patches and send' \
- 'git format-patch -n HEAD^1
- git send-email -from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" ./0001*txt'
+test_expect_success 'Extract patches' '
+ patches=`git format-patch -n HEAD^1`
+'
+
+test_expect_success 'Send patches' '
+ git send-email -from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
+'
cat >expected <<\EOF
!nobody@example.com!
diff --git a/test-sha1.c b/test-sha1.c
new file mode 100644
index 0000000..78d7e98
--- /dev/null
+++ b/test-sha1.c
@@ -0,0 +1,47 @@
+#include "cache.h"
+
+int main(int ac, char **av)
+{
+ SHA_CTX ctx;
+ unsigned char sha1[20];
+ unsigned bufsz = 8192;
+ char *buffer;
+
+ if (ac == 2)
+ bufsz = strtoul(av[1], NULL, 10) * 1024 * 1024;
+
+ if (!bufsz)
+ bufsz = 8192;
+
+ while ((buffer = malloc(bufsz)) == NULL) {
+ fprintf(stderr, "bufsz %u is too big, halving...\n", bufsz);
+ bufsz /= 2;
+ if (bufsz < 1024)
+ die("OOPS");
+ }
+
+ SHA1_Init(&ctx);
+
+ while (1) {
+ ssize_t sz, this_sz;
+ char *cp = buffer;
+ unsigned room = bufsz;
+ this_sz = 0;
+ while (room) {
+ sz = xread(0, cp, room);
+ if (sz == 0)
+ break;
+ if (sz < 0)
+ die("test-sha1: %s", strerror(errno));
+ this_sz += sz;
+ cp += sz;
+ room -= sz;
+ }
+ if (this_sz == 0)
+ break;
+ SHA1_Update(&ctx, buffer, this_sz);
+ }
+ SHA1_Final(sha1, &ctx);
+ puts(sha1_to_hex(sha1));
+ exit(0);
+}
diff --git a/test-sha1.sh b/test-sha1.sh
new file mode 100755
index 0000000..640856a
--- /dev/null
+++ b/test-sha1.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+dd if=/dev/zero bs=1048576 count=100 2>/dev/null |
+/usr/bin/time ./test-sha1 >/dev/null
+
+while read expect cnt pfx
+do
+ case "$expect" in '#'*) continue ;; esac
+ actual=`
+ {
+ test -z "$pfx" || echo "$pfx"
+ dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |
+ tr '[\0]' '[g]'
+ } | ./test-sha1 $cnt
+ `
+ if test "$expect" = "$actual"
+ then
+ echo "OK: $expect $cnt $pfx"
+ else
+ echo >&2 "OOPS: $cnt"
+ echo >&2 "expect: $expect"
+ echo >&2 "actual: $actual"
+ exit 1
+ fi
+done <<EOF
+da39a3ee5e6b4b0d3255bfef95601890afd80709 0
+3f786850e387550fdab836ed7e6dc881de23001b 0 a
+5277cbb45a15902137d332d97e89cf8136545485 0 ab
+03cfd743661f07975fa2f1220c5194cbaff48451 0 abc
+3330b4373640f9e4604991e73c7e86bfd8da2dc3 0 abcd
+ec11312386ad561674f724b8cca7cf1796e26d1d 0 abcde
+bdc37c074ec4ee6050d68bc133c6b912f36474df 0 abcdef
+69bca99b923859f2dc486b55b87f49689b7358c7 0 abcdefg
+e414af7161c9554089f4106d6f1797ef14a73666 0 abcdefgh
+0707f2970043f9f7c22029482db27733deaec029 0 abcdefghi
+a4dd8aa74a5636728fe52451636e2e17726033aa 1
+9986b45e2f4d7086372533bb6953a8652fa3644a 1 frotz
+23d8d4f788e8526b4877548a32577543cbaaf51f 10
+8cd23f822ab44c7f481b8c92d591f6d1fcad431c 10 frotz
+f3b5604a4e604899c1233edb3bf1cc0ede4d8c32 512
+b095bd837a371593048136e429e9ac4b476e1bb3 512 frotz
+08fa81d6190948de5ccca3966340cc48c10cceac 1200 xyzzy
+e33a291f42c30a159733dd98b8b3e4ff34158ca0 4090 4G
+#a3bf783bc20caa958f6cb24dd140a7b21984838d 9999 nitfol
+EOF
+
+exit
+
+# generating test vectors
+# inputs are number of megabytes followed by some random string to prefix.
+
+while read cnt pfx
+do
+ actual=`
+ {
+ test -z "$pfx" || echo "$pfx"
+ dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |
+ tr '[\0]' '[g]'
+ } | sha1sum |
+ sed -e 's/ .*//'
+ `
+ echo "$actual $cnt $pfx"
+done <<EOF
+0
+0 a
+0 ab
+0 abc
+0 abcd
+0 abcde
+0 abcdef
+0 abcdefg
+0 abcdefgh
+0 abcdefghi
+1
+1 frotz
+10
+10 frotz
+512
+512 frotz
+1200 xyzzy
+4090 4G
+9999 nitfol
+EOF