Merge branch 'lt/approxidate'

* lt/approxidate:
  fix approxidate parsing of relative months and years
  tests: add date printing and parsing tests
  refactor test-date interface
  Add date formatting and parsing functions relative to a given time
  Further 'approxidate' improvements
  Improve on 'approxidate'

Conflicts:
	date.c
diff --git a/Documentation/RelNotes-1.6.4.2.txt b/Documentation/RelNotes-1.6.4.2.txt
new file mode 100644
index 0000000..c11ec01
--- /dev/null
+++ b/Documentation/RelNotes-1.6.4.2.txt
@@ -0,0 +1,32 @@
+GIT v1.6.4.2 Release Notes
+==========================
+
+Fixes since v1.6.4.1
+--------------------
+
+* --date=relative output between 1 and 5 years ago rounded the number of
+    years when saying X years Y months ago, instead of rounding it down.
+
+* "git add -p" did not handle changes in executable bits correctly
+  (a regression around 1.6.3).
+
+* "git apply" did not honor GNU diff's convention to mark the creation/deletion
+  event with UNIX epoch timestamp on missing side.
+
+* "git checkout" incorrectly removed files in a directory pointed by a
+  symbolic link during a branch switch that replaces a directory with
+  a symbolic link.
+
+* "git clean -d -f" happily descended into a subdirectory that is managed by a
+  separate git repository.  It now requires two -f options for safety.
+
+* "git fetch/push" over http transports had two rather grave bugs.
+
+* "git format-patch --cover-letter" did not prepare the cover letter file
+  for use with non-ASCII strings when there are the series contributors with
+  non-ASCII names.
+
+* "git pull origin branch" and "git fetch origin && git merge origin/branch"
+  left different merge messages in the resulting commit.
+
+Other minor documentation updates are included.
diff --git a/Documentation/RelNotes-1.6.5.txt b/Documentation/RelNotes-1.6.5.txt
index 856047d..84a8451 100644
--- a/Documentation/RelNotes-1.6.5.txt
+++ b/Documentation/RelNotes-1.6.5.txt
@@ -31,14 +31,68 @@
 
 (subsystems)
 
+ * various updates to git-svn and gitweb.
+
 (portability)
 
+ * more improvements on mingw port.
+
 (performance)
 
+ * On major platforms, the system can be compiled to use with Linus's
+   block-sha1 implementation of the SHA-1 hash algorithm, which
+   outperforms the default fallback implementation we borrowed from
+   Mozzilla.
+
 (usability, bells and whistles)
 
+ * refs/replace/ hierarchy is designed to be usable as a replacement
+   of the "grafts" mechanism, with the added advantage that it can be
+   transferred across repositories.
+
+ * "git am" learned to optionally ignore whitespace differences.
+
+ * "git am" handles input e-mail files that has CRLF line endings sensibly.
+
+ * "git commit --dry-run $args" is a new recommended way to ask "what would
+   happen if I try to commit with these arguments."
+
+ * "git cvsimport" now supports password-protected pserver access.
+
+ * "git fast-export" learned --no-data option that can be useful when
+   reordering commits and trees without touching the contents of
+   blobs.
+
+ * "git init" learned to mkdir/chdir into a directory when given an
+   extra argument (i.e. "git init this").
+
+ * "git instaweb" optionally can use mongoose as the web server.
+
+ * "git log --decorate" can optionally be told with --decorate=full to
+   give the reference name in full.
+
+ * "git push" can be told to be --quiet.
+
+ * informational output from "git reset" that lists the locally modified
+   paths is made consistent with that of "git checkout $another_branch".
+
+ * "git status" gives more descriptive output for unmerged paths.
+
+ * "git submodule" learned to give submodule name to scripts run with
+   "foreach" subcommand.
+
+ * various subcommands to "git submodule" learned --recursive option.
+
+ * "git submodule summary" learned --files option to compare the work
+   tree vs the commit bound at submodule path, instead of comparing
+   the index.
+
 (developers)
 
+ * With GIT_TEST_OPTS="--root=/p/a/t/h", tests can be run outside the
+   source directory; using tmpfs may give faster turnaround.
+
+
 Fixes since v1.6.4
 ------------------
 
@@ -48,4 +102,8 @@
 # Here are fixes that this release has, but have not been backported to
 # v1.6.4.X series.
 
-
+--
+exec >/var/tmp/1
+O=v1.6.4.1-266-g235db15
+echo O=$(git describe master)
+git shortlog --no-merges $O..master --not maint
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index bc132c8..92444dd 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -9,7 +9,7 @@
 SYNOPSIS
 --------
 [verse]
-'git archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>]
+'git archive' [--format=<fmt>] [--list] [--prefix=<prefix>/] [<extra>]
 	      [--output=<file>] [--worktree-attributes]
 	      [--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish>
 	      [path...]
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index ae201de..aad71dc 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -76,6 +76,7 @@
 	based sha1 expressions such as "<branchname>@\{yesterday}".
 
 -f::
+--force::
 	Reset <branchname> to <startpoint> if <branchname> exists
 	already. Without `-f` 'git-branch' refuses to change an existing branch.
 
@@ -209,6 +210,12 @@
 - `--no-merged` is used to find branches which are candidates for merging
   into HEAD, since those branches are not fully contained by HEAD.
 
+SEE ALSO
+--------
+linkgit:git-check-ref-format[1],
+linkgit:git-fetch[1],
+linkgit:git-remote[1].
+
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org> and Junio C Hamano <gitster@pobox.com>
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index ad4b31e..b1314b5 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -45,9 +45,11 @@
 OPTIONS
 -------
 -q::
+--quiet::
 	Quiet, suppress feedback messages.
 
 -f::
+--force::
 	When switching branches, proceed even if the index or the
 	working tree differs from HEAD.  This is used to throw away
 	local changes.
diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt
index ae8938b..9d291bd 100644
--- a/Documentation/git-clean.txt
+++ b/Documentation/git-clean.txt
@@ -32,6 +32,7 @@
 	if you really want to remove such a directory.
 
 -f::
+--force::
 	If the git configuration specifies clean.requireForce as true,
 	'git-clean' will refuse to run unless given -f or -n.
 
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 2c63a0f..88ea272 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -12,7 +12,7 @@
 'git clone' [--template=<template_directory>]
 	  [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
 	  [-o <name>] [-u <upload-pack>] [--reference <repository>]
-	  [--depth <depth>] [--] <repository> [<directory>]
+	  [--depth <depth>] [--recursive] [--] <repository> [<directory>]
 
 DESCRIPTION
 -----------
@@ -147,6 +147,14 @@
 	with a long history, and would want to send in fixes
 	as patches.
 
+--recursive::
+	After the clone is created, initialize all submodules within,
+	using their default settings. This is equivalent to running
+	'git submodule update --init --recursive' immediately after
+	the clone is finished. This option is ignored if the cloned
+	repository does not have a worktree/checkout (i.e. if any of
+	`--no-checkout`/`-n`, `--bare`, or `--mirror` is given)
+
 <repository>::
 	The (possibly remote) repository to clone from.  See the
 	<<URLS,URLS>> section below for more information on specifying
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index b5d81be..64f94cf 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -8,8 +8,8 @@
 SYNOPSIS
 --------
 [verse]
-'git commit' [-a | --interactive] [-s] [-v] [-u<mode>] [--amend]
-	   [(-c | -C) <commit>] [-F <file> | -m <msg>]
+'git commit' [-a | --interactive] [-s] [-v] [-u<mode>] [--amend] [--dry-run]
+	   [(-c | -C) <commit>] [-F <file> | -m <msg>] [--dry-run]
 	   [--allow-empty] [--no-verify] [-e] [--author=<author>]
 	   [--cleanup=<mode>] [--] [[-i | -o ]<file>...]
 
@@ -42,10 +42,9 @@
    by one which files should be part of the commit, before finalizing the
    operation.  Currently, this is done by invoking 'git-add --interactive'.
 
-The 'git-status' command can be used to obtain a
+The `--dry-run` option can be used to obtain a
 summary of what is included by any of the above for the next
-commit by giving the same set of parameters you would give to
-this command.
+commit by giving the same set of parameters (options and paths).
 
 If you make a commit and then find a mistake immediately after
 that, you can recover from it with 'git-reset'.
@@ -70,6 +69,12 @@
 	Like '-C', but with '-c' the editor is invoked, so that
 	the user can further edit the commit message.
 
+--dry-run::
+	Do not actually make a commit, but show the list of paths
+	with updates in the index, paths with changes in the work tree,
+	and paths that are untracked, similar to the one that is given
+	in the commit log editor.
+
 -F <file>::
 --file=<file>::
 	Take the commit message from the given file.  Use '-' to
@@ -198,6 +203,11 @@
 --quiet::
 	Suppress commit summary message.
 
+--dry-run::
+	Do not create a commit, but show a list of paths that are
+	to be committed, paths with local changes that will be left
+	uncommitted and paths that are untracked.
+
 \--::
 	Do not interpret any more arguments as options.
 
diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index b292e98..dcac8c8 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -61,7 +61,7 @@
 
 --prune=<date>::
 	Prune loose objects older than date (default is 2 weeks ago,
-	overrideable by the config variable `gc.pruneExpire`).  This
+	overridable by the config variable `gc.pruneExpire`).  This
 	option is on by default.
 
 --no-prune::
diff --git a/Documentation/git-instaweb.txt b/Documentation/git-instaweb.txt
index 22da21a..0771f25 100644
--- a/Documentation/git-instaweb.txt
+++ b/Documentation/git-instaweb.txt
@@ -29,7 +29,7 @@
 	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, apache2 and webrick are supported.
+	Currently apache2, lighttpd, mongoose and webrick are supported.
 	(Default: lighttpd)
 
 -m::
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 34cf4e5..3d79de1 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -37,8 +37,12 @@
 	and <until>, see "SPECIFYING REVISIONS" section in
 	linkgit:git-rev-parse[1].
 
---decorate::
-	Print out the ref names of any commits that are shown.
+--decorate[=short|full]::
+	Print out the ref names of any commits that are shown. If 'short' is
+	specified, the ref name prefixes 'refs/heads/', 'refs/tags/' and
+	'refs/remotes/' will not be printed. If 'full' is specified, the
+	full ref name (including prefix) will be printed. The default option
+	is 'short'.
 
 --source::
 	Print out the ref name given on the command line by which each
diff --git a/Documentation/git-mv.txt b/Documentation/git-mv.txt
index 9c56602..bdcb585 100644
--- a/Documentation/git-mv.txt
+++ b/Documentation/git-mv.txt
@@ -28,6 +28,7 @@
 OPTIONS
 -------
 -f::
+--force::
 	Force renaming or moving of a file even if the target exists
 -k::
         Skip move or rename actions which would lead to an error
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index 7dd73ae..5ccdd18 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -11,12 +11,12 @@
 [verse]
 'git submodule' [--quiet] add [-b branch]
 	      [--reference <repository>] [--] <repository> <path>
-'git submodule' [--quiet] status [--cached] [--] [<path>...]
+'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
 'git submodule' [--quiet] init [--] [<path>...]
 'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase]
-	      [--reference <repository>] [--merge] [--] [<path>...]
-'git submodule' [--quiet] summary [--cached] [--summary-limit <n>] [commit] [--] [<path>...]
-'git submodule' [--quiet] foreach <command>
+	      [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
+'git submodule' [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
+'git submodule' [--quiet] foreach [--recursive] <command>
 'git submodule' [--quiet] sync [--] [<path>...]
 
 
@@ -100,6 +100,9 @@
 	initialized and `+` if the currently checked out submodule commit
 	does not match the SHA-1 found in the index of the containing
 	repository. This command is the default command for 'git-submodule'.
++
+If '--recursive' is specified, this command will recurse into nested
+submodules, and show their status as well.
 
 init::
 	Initialize the submodules, i.e. register each submodule name
@@ -122,21 +125,31 @@
 If the submodule is not yet initialized, and you just want to use the
 setting as stored in .gitmodules, you can automatically initialize the
 submodule with the --init option.
++
+If '--recursive' is specified, this command will recurse into the
+registered submodules, and update any nested submodules within.
 
 summary::
 	Show commit summary between the given commit (defaults to HEAD) and
 	working tree/index. For a submodule in question, a series of commits
 	in the submodule between the given super project commit and the
-	index or working tree (switched by --cached) are shown.
+	index or working tree (switched by --cached) are shown. If the option
+	--files is given, show the series of commits in the submodule between
+	the index of the super project and the working tree of the submodule
+	(this option doesn't allow to use the --cached option or to provide an
+	explicit commit).
 
 foreach::
 	Evaluates an arbitrary shell command in each checked out submodule.
-	The command has access to the variables $path and $sha1:
+	The command has access to the variables $name, $path and $sha1:
+	$name is the name of the relevant submodule section in .gitmodules,
 	$path is the name of the submodule directory relative to the
 	superproject, and $sha1 is the commit as recorded in the superproject.
 	Any submodules defined in the superproject but not checked out are
 	ignored by this command. Unless given --quiet, foreach prints the name
 	of each submodule before evaluating the command.
+	If --recursive is given, submodules are traversed recursively (i.e.
+	the given shell command is evaluated in nested submodules as well).
 	A non-zero return from the command in any submodule causes
 	the processing to terminate. This can be overridden by adding '|| :'
 	to the end of the command.
@@ -169,6 +182,11 @@
 	commands typically use the commit found in the submodule HEAD, but
 	with this option, the commit stored in the index is used instead.
 
+--files::
+	This option is only valid for the summary command. This command
+	compares the commit in the index with that in the submodule HEAD
+	when this option is used.
+
 -n::
 --summary-limit::
 	This option is only valid for the summary command.
@@ -209,6 +227,12 @@
 *NOTE*: Do *not* use this option unless you have read the note
 for linkgit:git-clone[1]'s --reference and --shared options carefully.
 
+--recursive::
+	This option is only valid for foreach, update and status commands.
+	Traverse submodules recursively. The operation is performed not
+	only in the submodules of the current repo, but also
+	in any nested submodules inside those submodules (and so on).
+
 <path>...::
 	Paths to submodule(s). When specified this will restrict the command
 	to only operate on the submodules found at the specified paths.
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 1118ce2..299b04f 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -10,17 +10,15 @@
 --------
 [verse]
 'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]
-	<name> [<commit> | <object>]
-'git tag' -d <name>...
+	<tagname> [<commit> | <object>]
+'git tag' -d <tagname>...
 'git tag' [-n[<num>]] -l [--contains <commit>] [<pattern>]
-'git tag' -v <name>...
+'git tag' -v <tagname>...
 
 DESCRIPTION
 -----------
 
-Adds a 'tag' reference in `.git/refs/tags/`.  The tag <name> must pass
-linkgit:git-check-ref-format[1] which basicly means that control characters,
-space, ~, ^, :, ?, *, [ and \ are prohibited.
+Adds a tag reference in `.git/refs/tags/`.
 
 Unless `-f` is given, the tag must not yet exist in
 `.git/refs/tags/` directory.
@@ -53,6 +51,7 @@
 	Make a GPG-signed tag, using the given key
 
 -f::
+--force::
 	Replace an existing tag with the given name (instead of failing)
 
 -d::
@@ -88,6 +87,12 @@
 	Implies `-a` if none of `-a`, `-s`, or `-u <key-id>`
 	is given.
 
+<tagname>::
+	The name of the tag to create, delete, or describe.
+	The new tag name must pass all checks defined by
+	linkgit:git-check-ref-format[1].  Some of these checks
+	may restrict the characters allowed in a tag name.
+
 CONFIGURATION
 -------------
 By default, 'git-tag' in sign-with-default mode (-s) will use your
@@ -252,6 +257,10 @@
 ------------
 
 
+SEE ALSO
+--------
+linkgit:git-check-ref-format[1].
+
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>,
diff --git a/Documentation/git-verify-pack.txt b/Documentation/git-verify-pack.txt
index d791a80..97f7f91 100644
--- a/Documentation/git-verify-pack.txt
+++ b/Documentation/git-verify-pack.txt
@@ -25,7 +25,13 @@
 -v::
 --verbose::
 	After verifying the pack, show list of objects contained
-	in the pack.
+	in the pack and a histogram of delta chain length.
+
+-s::
+--stat-only::
+	Do not verify the pack contents; only show the histogram of delta
+	chain length.  With `--verbose`, list of objects is also shown.
+
 \--::
 	Do not interpret any more arguments as options.
 
diff --git a/Documentation/git-write-tree.txt b/Documentation/git-write-tree.txt
index 26d3850..c8899d5 100644
--- a/Documentation/git-write-tree.txt
+++ b/Documentation/git-write-tree.txt
@@ -12,7 +12,8 @@
 
 DESCRIPTION
 -----------
-Creates a tree object using the current index.
+Creates a tree object using the current index. The name of the new
+tree object is printed to standard output.
 
 The index must be in a fully merged state.
 
diff --git a/Documentation/git.txt b/Documentation/git.txt
index a9bacfb..ad44cac 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,9 +43,10 @@
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.6.4.1/git.html[documentation for release 1.6.4.1]
+* link:v1.6.4.2/git.html[documentation for release 1.6.4.2]
 
 * release notes for
+  link:RelNotes-1.6.4.2.txt[1.6.4.2],
   link:RelNotes-1.6.4.1.txt[1.6.4.1],
   link:RelNotes-1.6.4.txt[1.6.4].
 
diff --git a/Makefile b/Makefile
index 66eedef..a614347 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@
 # when attempting to read from an fopen'ed directory.
 #
 # Define NO_OPENSSL environment variable if you do not have OpenSSL.
-# This also implies MOZILLA_SHA1.
+# This also implies BLK_SHA1.
 #
 # Define NO_CURL if you do not have libcurl installed.  git-http-pull and
 # git-http-push are not built, and you cannot use http:// and https://
@@ -91,14 +91,6 @@
 # Define PPC_SHA1 environment variable when running make to make use of
 # a bundled SHA1 routine optimized for PowerPC.
 #
-# Define ARM_SHA1 environment variable when running make to make use of
-# a bundled SHA1 routine optimized for ARM.
-#
-# Define MOZILLA_SHA1 environment variable when running make to make use of
-# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast
-# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default
-# choice) has very fast version optimized for i586.
-#
 # Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin).
 #
 # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
@@ -365,7 +357,6 @@
 PROGRAMS += git-shell$X
 PROGRAMS += git-show-index$X
 PROGRAMS += git-unpack-file$X
-PROGRAMS += git-update-server-info$X
 PROGRAMS += git-upload-pack$X
 PROGRAMS += git-var$X
 
@@ -644,6 +635,7 @@
 BUILTIN_OBJS += builtin-unpack-objects.o
 BUILTIN_OBJS += builtin-update-index.o
 BUILTIN_OBJS += builtin-update-ref.o
+BUILTIN_OBJS += builtin-update-server-info.o
 BUILTIN_OBJS += builtin-upload-archive.o
 BUILTIN_OBJS += builtin-verify-pack.o
 BUILTIN_OBJS += builtin-verify-tag.o
@@ -757,9 +749,6 @@
 		NO_C99_FORMAT = YesPlease
 		NO_STRTOUMAX = YesPlease
 	endif
-	ifdef NO_IPV6
-		NEEDS_RESOLV = YesPlease
-	endif
 	INSTALL = /usr/ucb/install
 	TAR = gtar
 	BASIC_CFLAGS += -D__EXTENSIONS__ -D__sun__ -DHAVE_ALLOCA_H
@@ -928,10 +917,6 @@
 	NO_PTHREADS = YesPlease
 endif
 endif
-ifneq (,$(findstring arm,$(uname_M)))
-	ARM_SHA1 = YesPlease
-	NO_MKSTEMPS = YesPlease
-endif
 
 -include config.mak.autogen
 -include config.mak
@@ -1024,7 +1009,7 @@
 	endif
 else
 	BASIC_CFLAGS += -DNO_OPENSSL
-	MOZILLA_SHA1 = 1
+	BLK_SHA1 = 1
 	OPENSSL_LIBSSL =
 endif
 ifdef NEEDS_SSL_WITH_CRYPTO
@@ -1181,20 +1166,10 @@
 	SHA1_HEADER = "ppc/sha1.h"
 	LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
 else
-ifdef ARM_SHA1
-	SHA1_HEADER = "arm/sha1.h"
-	LIB_OBJS += arm/sha1.o arm/sha1_arm.o
-else
-ifdef MOZILLA_SHA1
-	SHA1_HEADER = "mozilla-sha1/sha1.h"
-	LIB_OBJS += mozilla-sha1/sha1.o
-else
 	SHA1_HEADER = <openssl/sha.h>
 	EXTLIBS += $(LIB_4_CRYPTO)
 endif
 endif
-endif
-endif
 ifdef NO_PERL_MAKEMAKER
 	export NO_PERL_MAKEMAKER
 endif
diff --git a/abspath.c b/abspath.c
index 4bee0ba..b88122c 100644
--- a/abspath.c
+++ b/abspath.c
@@ -18,7 +18,7 @@
 {
 	static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
 	char cwd[1024] = "";
-	int buf_index = 1, len;
+	int buf_index = 1;
 
 	int depth = MAXDEPTH;
 	char *last_elem = NULL;
@@ -50,7 +50,7 @@
 			die_errno ("Could not get current working directory");
 
 		if (last_elem) {
-			int len = strlen(buf);
+			size_t len = strlen(buf);
 			if (len + strlen(last_elem) + 2 > PATH_MAX)
 				die ("Too long path name: '%s/%s'",
 						buf, last_elem);
@@ -61,7 +61,7 @@
 		}
 
 		if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
-			len = readlink(buf, next_buf, PATH_MAX);
+			ssize_t len = readlink(buf, next_buf, PATH_MAX);
 			if (len < 0)
 				die_errno ("Invalid symlink '%s'", buf);
 			if (PATH_MAX <= len)
diff --git a/arm/sha1.c b/arm/sha1.c
deleted file mode 100644
index c61ad4a..0000000
--- a/arm/sha1.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * SHA-1 implementation optimized for ARM
- *
- * Copyright:   (C) 2005 by Nicolas Pitre <nico@cam.org>
- * Created:     September 17, 2005
- */
-
-#include <string.h>
-#include "sha1.h"
-
-extern void arm_sha_transform(uint32_t *hash, const unsigned char *data, uint32_t *W);
-
-void arm_SHA1_Init(arm_SHA_CTX *c)
-{
-	c->len = 0;
-	c->hash[0] = 0x67452301;
-	c->hash[1] = 0xefcdab89;
-	c->hash[2] = 0x98badcfe;
-	c->hash[3] = 0x10325476;
-	c->hash[4] = 0xc3d2e1f0;
-}
-
-void arm_SHA1_Update(arm_SHA_CTX *c, const void *p, unsigned long n)
-{
-	uint32_t workspace[80];
-	unsigned int partial;
-	unsigned long done;
-
-	partial = c->len & 0x3f;
-	c->len += n;
-	if ((partial + n) >= 64) {
-		if (partial) {
-			done = 64 - partial;
-			memcpy(c->buffer + partial, p, done);
-			arm_sha_transform(c->hash, c->buffer, workspace);
-			partial = 0;
-		} else
-			done = 0;
-		while (n >= done + 64) {
-			arm_sha_transform(c->hash, p + done, workspace);
-			done += 64;
-		}
-	} else
-		done = 0;
-	if (n - done)
-		memcpy(c->buffer + partial, p + done, n - done);
-}
-
-void arm_SHA1_Final(unsigned char *hash, arm_SHA_CTX *c)
-{
-	uint64_t bitlen;
-	uint32_t bitlen_hi, bitlen_lo;
-	unsigned int i, offset, padlen;
-	unsigned char bits[8];
-	static const unsigned char padding[64] = { 0x80, };
-
-	bitlen = c->len << 3;
-	offset = c->len & 0x3f;
-	padlen = ((offset < 56) ? 56 : (64 + 56)) - offset;
-	arm_SHA1_Update(c, padding, padlen);
-
-	bitlen_hi = bitlen >> 32;
-	bitlen_lo = bitlen & 0xffffffff;
-	bits[0] = bitlen_hi >> 24;
-	bits[1] = bitlen_hi >> 16;
-	bits[2] = bitlen_hi >> 8;
-	bits[3] = bitlen_hi;
-	bits[4] = bitlen_lo >> 24;
-	bits[5] = bitlen_lo >> 16;
-	bits[6] = bitlen_lo >> 8;
-	bits[7] = bitlen_lo;
-	arm_SHA1_Update(c, bits, 8);
-
-	for (i = 0; i < 5; i++) {
-		uint32_t v = c->hash[i];
-		hash[0] = v >> 24;
-		hash[1] = v >> 16;
-		hash[2] = v >> 8;
-		hash[3] = v;
-		hash += 4;
-	}
-}
diff --git a/arm/sha1.h b/arm/sha1.h
deleted file mode 100644
index b61b618..0000000
--- a/arm/sha1.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SHA-1 implementation optimized for ARM
- *
- * Copyright:	(C) 2005 by Nicolas Pitre <nico@cam.org>
- * Created:	September 17, 2005
- */
-
-#include <stdint.h>
-
-typedef struct {
-	uint64_t len;
-	uint32_t hash[5];
-	unsigned char buffer[64];
-} arm_SHA_CTX;
-
-void arm_SHA1_Init(arm_SHA_CTX *c);
-void arm_SHA1_Update(arm_SHA_CTX *c, const void *p, unsigned long n);
-void arm_SHA1_Final(unsigned char *hash, arm_SHA_CTX *c);
-
-#define git_SHA_CTX	arm_SHA_CTX
-#define git_SHA1_Init	arm_SHA1_Init
-#define git_SHA1_Update	arm_SHA1_Update
-#define git_SHA1_Final	arm_SHA1_Final
diff --git a/arm/sha1_arm.S b/arm/sha1_arm.S
deleted file mode 100644
index 41e9263..0000000
--- a/arm/sha1_arm.S
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- *  SHA transform optimized for ARM
- *
- *  Copyright:	(C) 2005 by Nicolas Pitre <nico@cam.org>
- *  Created:	September 17, 2005
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- */
-
-	.text
-	.globl	arm_sha_transform
-
-/*
- * void sha_transform(uint32_t *hash, const unsigned char *data, uint32_t *W);
- *
- * note: the "data" pointer may be unaligned.
- */
-
-arm_sha_transform:
-
-	stmfd	sp!, {r4 - r8, lr}
-
-	@ for (i = 0; i < 16; i++)
-	@         W[i] = ntohl(((uint32_t *)data)[i]);
-
-#ifdef __ARMEB__
-	mov	r4, r0
-	mov	r0, r2
-	mov	r2, #64
-	bl	memcpy
-	mov	r2, r0
-	mov	r0, r4
-#else
-	mov	r3, r2
-	mov	lr, #16
-1:	ldrb	r4, [r1], #1
-	ldrb	r5, [r1], #1
-	ldrb	r6, [r1], #1
-	ldrb	r7, [r1], #1
-	subs	lr, lr, #1
-	orr	r5, r5, r4, lsl #8
-	orr	r6, r6, r5, lsl #8
-	orr	r7, r7, r6, lsl #8
-	str	r7, [r3], #4
-	bne	1b
-#endif
-
-	@ for (i = 0; i < 64; i++)
-	@         W[i+16] = ror(W[i+13] ^ W[i+8] ^ W[i+2] ^ W[i], 31);
-
-	sub	r3, r2, #4
-	mov	lr, #64
-2:	ldr	r4, [r3, #4]!
-	subs	lr, lr, #1
-	ldr	r5, [r3, #8]
-	ldr	r6, [r3, #32]
-	ldr	r7, [r3, #52]
-	eor	r4, r4, r5
-	eor	r4, r4, r6
-	eor	r4, r4, r7
-	mov	r4, r4, ror #31
-	str	r4, [r3, #64]
-	bne	2b
-
-	/*
-	 * The SHA functions are:
-	 *
-	 * f1(B,C,D) = (D ^ (B & (C ^ D)))
-	 * f2(B,C,D) = (B ^ C ^ D)
-	 * f3(B,C,D) = ((B & C) | (D & (B | C)))
-	 *
-	 * Then the sub-blocks are processed as follows:
-	 *
-	 * A' = ror(A, 27) + f(B,C,D) + E + K + *W++
-	 * B' = A
-	 * C' = ror(B, 2)
-	 * D' = C
-	 * E' = D
-	 *
-	 * We therefore unroll each loop 5 times to avoid register shuffling.
-	 * Also the ror for C (and also D and E which are successivelyderived
-	 * from it) is applied in place to cut on an additional mov insn for
-	 * each round.
-	 */
-
-	.macro	sha_f1, A, B, C, D, E
-	ldr	r3, [r2], #4
-	eor	ip, \C, \D
-	add	\E, r1, \E, ror #2
-	and	ip, \B, ip, ror #2
-	add	\E, \E, \A, ror #27
-	eor	ip, ip, \D, ror #2
-	add	\E, \E, r3
-	add	\E, \E, ip
-	.endm
-
-	.macro	sha_f2, A, B, C, D, E
-	ldr	r3, [r2], #4
-	add	\E, r1, \E, ror #2
-	eor	ip, \B, \C, ror #2
-	add	\E, \E, \A, ror #27
-	eor	ip, ip, \D, ror #2
-	add	\E, \E, r3
-	add	\E, \E, ip
-	.endm
-
-	.macro	sha_f3, A, B, C, D, E
-	ldr	r3, [r2], #4
-	add	\E, r1, \E, ror #2
-	orr	ip, \B, \C, ror #2
-	add	\E, \E, \A, ror #27
-	and	ip, ip, \D, ror #2
-	add	\E, \E, r3
-	and	r3, \B, \C, ror #2
-	orr	ip, ip, r3
-	add	\E, \E, ip
-	.endm
-
-	ldmia	r0, {r4 - r8}
-
-	mov	lr, #4
-	ldr	r1, .L_sha_K + 0
-
-	/* adjust initial values */
-	mov	r6, r6, ror #30
-	mov	r7, r7, ror #30
-	mov	r8, r8, ror #30
-
-3:	subs	lr, lr, #1
-	sha_f1	r4, r5, r6, r7, r8
-	sha_f1	r8, r4, r5, r6, r7
-	sha_f1	r7, r8, r4, r5, r6
-	sha_f1	r6, r7, r8, r4, r5
-	sha_f1	r5, r6, r7, r8, r4
-	bne	3b
-
-	ldr	r1, .L_sha_K + 4
-	mov	lr, #4
-
-4:	subs	lr, lr, #1
-	sha_f2	r4, r5, r6, r7, r8
-	sha_f2	r8, r4, r5, r6, r7
-	sha_f2	r7, r8, r4, r5, r6
-	sha_f2	r6, r7, r8, r4, r5
-	sha_f2	r5, r6, r7, r8, r4
-	bne	4b
-
-	ldr	r1, .L_sha_K + 8
-	mov	lr, #4
-
-5:	subs	lr, lr, #1
-	sha_f3	r4, r5, r6, r7, r8
-	sha_f3	r8, r4, r5, r6, r7
-	sha_f3	r7, r8, r4, r5, r6
-	sha_f3	r6, r7, r8, r4, r5
-	sha_f3	r5, r6, r7, r8, r4
-	bne	5b
-
-	ldr	r1, .L_sha_K + 12
-	mov	lr, #4
-
-6:	subs	lr, lr, #1
-	sha_f2	r4, r5, r6, r7, r8
-	sha_f2	r8, r4, r5, r6, r7
-	sha_f2	r7, r8, r4, r5, r6
-	sha_f2	r6, r7, r8, r4, r5
-	sha_f2	r5, r6, r7, r8, r4
-	bne	6b
-
-	ldmia	r0, {r1, r2, r3, ip, lr}
-	add	r4, r1, r4
-	add	r5, r2, r5
-	add	r6, r3, r6, ror #2
-	add	r7, ip, r7, ror #2
-	add	r8, lr, r8, ror #2
-	stmia	r0, {r4 - r8}
-
-	ldmfd	sp!, {r4 - r8, pc}
-
-.L_sha_K:
-	.word	0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6
diff --git a/bisect.c b/bisect.c
index 7f20acb..dc18db8 100644
--- a/bisect.c
+++ b/bisect.c
@@ -991,7 +991,7 @@
 
 	if (!hashcmp(bisect_rev, current_bad_sha1)) {
 		exit_if_skipped_commits(tried, current_bad_sha1);
-		printf("%s is first bad commit\n", bisect_rev_hex);
+		printf("%s is the first bad commit\n", bisect_rev_hex);
 		show_diff_tree(prefix, revs.commits->item);
 		/* This means the bisection process succeeded. */
 		exit(10);
diff --git a/block-sha1/sha1.c b/block-sha1/sha1.c
index 464cb25..d893475 100644
--- a/block-sha1/sha1.c
+++ b/block-sha1/sha1.c
@@ -1,15 +1,17 @@
 /*
- * Based on the Mozilla SHA1 (see mozilla-sha1/sha1.c),
- * optimized to do word accesses rather than byte accesses,
+ * SHA1 routine optimized to do word accesses rather than byte accesses,
  * and to avoid unnecessary copies into the context array.
+ *
+ * This was initially based on the Mozilla SHA1 implementation, although
+ * none of the original Mozilla code remains.
  */
 
-#include <string.h>
-#include <arpa/inet.h>
+/* this is only to get definitions for memcpy(), ntohl() and htonl() */
+#include "../git-compat-util.h"
 
 #include "sha1.h"
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
 
 /*
  * Force usage of rol or ror by selecting the one with the smaller constant.
@@ -54,7 +56,7 @@
 
 #if defined(__i386__) || defined(__x86_64__)
   #define setW(x, val) (*(volatile unsigned int *)&W(x) = (val))
-#elif defined(__arm__)
+#elif defined(__GNUC__) && defined(__arm__)
   #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0)
 #else
   #define setW(x, val) (W(x) = (val))
diff --git a/block-sha1/sha1.h b/block-sha1/sha1.h
index c1ae74d..b864df6 100644
--- a/block-sha1/sha1.h
+++ b/block-sha1/sha1.h
@@ -1,13 +1,15 @@
 /*
- * Based on the Mozilla SHA1 (see mozilla-sha1/sha1.h),
- * optimized to do word accesses rather than byte accesses,
+ * SHA1 routine optimized to do word accesses rather than byte accesses,
  * and to avoid unnecessary copies into the context array.
+ *
+ * This was initially based on the Mozilla SHA1 implementation, although
+ * none of the original Mozilla code remains.
  */
 
 typedef struct {
+	unsigned long long size;
 	unsigned int H[5];
 	unsigned int W[16];
-	unsigned long long size;
 } blk_SHA_CTX;
 
 void blk_SHA1_Init(blk_SHA_CTX *ctx);
diff --git a/builtin-add.c b/builtin-add.c
index 581a2a1..006fd08 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -105,8 +105,8 @@
 	for (specs = 0; pathspec[specs];  specs++)
 		/* nothing */;
 	seen = xcalloc(specs, 1);
-	refresh_index(&the_index, verbose ? REFRESH_SAY_CHANGED : REFRESH_QUIET,
-		      pathspec, seen);
+	refresh_index(&the_index, verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET,
+		      pathspec, seen, "Unstaged changes after refreshing the index:");
 	for (i = 0; i < specs; i++) {
 		if (!seen[i])
 			die("pathspec '%s' did not match any files", pathspec[i]);
diff --git a/builtin-branch.c b/builtin-branch.c
index 1a03d5f..9f57992 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -586,7 +586,7 @@
 		OPT_BIT('m', NULL, &rename, "move/rename a branch and its reflog", 1),
 		OPT_BIT('M', NULL, &rename, "move/rename a branch, even if target exists", 2),
 		OPT_BOOLEAN('l', NULL, &reflog, "create the branch's reflog"),
-		OPT_BOOLEAN('f', NULL, &force_create, "force creation (when already exists)"),
+		OPT_BOOLEAN('f', "force", &force_create, "force creation (when already exists)"),
 		{
 			OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref,
 			"commit", "print only not merged branches",
diff --git a/builtin-checkout.c b/builtin-checkout.c
index 8a9a474..36e2116 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -402,7 +402,9 @@
 		topts.dir = xcalloc(1, sizeof(*topts.dir));
 		topts.dir->flags |= DIR_SHOW_IGNORED;
 		topts.dir->exclude_per_dir = ".gitignore";
-		tree = parse_tree_indirect(old->commit->object.sha1);
+		tree = parse_tree_indirect(old->commit ?
+					   old->commit->object.sha1 :
+					   (unsigned char *)EMPTY_TREE_SHA1_BIN);
 		init_tree_desc(&trees[0], tree->buffer, tree->size);
 		tree = parse_tree_indirect(new->commit->object.sha1);
 		init_tree_desc(&trees[1], tree->buffer, tree->size);
@@ -541,14 +543,6 @@
 		parse_commit(new->commit);
 	}
 
-	if (!old.commit && !opts->force) {
-		if (!opts->quiet) {
-			warning("You appear to be on a branch yet to be born.");
-			warning("Forcing checkout of %s.", new->name);
-		}
-		opts->force = 1;
-	}
-
 	ret = merge_working_tree(opts, &old, new);
 	if (ret)
 		return ret;
@@ -590,7 +584,7 @@
 			    2),
 		OPT_SET_INT('3', "theirs", &opts.writeout_stage, "stage",
 			    3),
-		OPT_BOOLEAN('f', NULL, &opts.force, "force"),
+		OPT_BOOLEAN('f', "force", &opts.force, "force"),
 		OPT_BOOLEAN('m', "merge", &opts.merge, "merge"),
 		OPT_STRING(0, "conflict", &conflict_style, "style",
 			   "conflict style (merge or diff3)"),
diff --git a/builtin-clean.c b/builtin-clean.c
index 05c763c..28cdcd0 100644
--- a/builtin-clean.c
+++ b/builtin-clean.c
@@ -41,7 +41,7 @@
 	struct option options[] = {
 		OPT__QUIET(&quiet),
 		OPT__DRY_RUN(&show_only),
-		OPT_BOOLEAN('f', NULL, &force, "force"),
+		OPT_BOOLEAN('f', "force", &force, "force"),
 		OPT_BOOLEAN('d', NULL, &remove_directories,
 				"remove whole directories"),
 		OPT_BOOLEAN('x', NULL, &ignored, "remove ignored files, too"),
diff --git a/builtin-clone.c b/builtin-clone.c
index 32dea74..0d2b4a8 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -38,7 +38,7 @@
 };
 
 static int option_quiet, option_no_checkout, option_bare, option_mirror;
-static int option_local, option_no_hardlinks, option_shared;
+static int option_local, option_no_hardlinks, option_shared, option_recursive;
 static char *option_template, *option_reference, *option_depth;
 static char *option_origin = NULL;
 static char *option_upload_pack = "git-upload-pack";
@@ -59,6 +59,8 @@
 		    "don't use local hardlinks, always copy"),
 	OPT_BOOLEAN('s', "shared", &option_shared,
 		    "setup as shared repository"),
+	OPT_BOOLEAN(0, "recursive", &option_recursive,
+		    "setup as shared repository"),
 	OPT_STRING(0, "template", &option_template, "path",
 		   "path the template repository"),
 	OPT_STRING(0, "reference", &option_reference, "repo",
@@ -73,6 +75,10 @@
 	OPT_END()
 };
 
+static const char *argv_submodule[] = {
+	"submodule", "update", "--init", "--recursive", NULL
+};
+
 static char *get_repo_path(const char *repo, int *is_bundle)
 {
 	static char *suffix[] = { "/.git", ".git", "" };
@@ -608,6 +614,9 @@
 
 		err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1),
 				sha1_to_hex(remote_head->old_sha1), "1", NULL);
+
+		if (!err && option_recursive)
+			err = run_command_v_opt(argv_submodule, RUN_GIT_CMD);
 	}
 
 	strbuf_release(&reflog_msg);
diff --git a/builtin-commit.c b/builtin-commit.c
index 4bcce06..200ffda 100644
--- a/builtin-commit.c
+++ b/builtin-commit.c
@@ -51,7 +51,7 @@
 static char *edit_message, *use_message;
 static char *author_name, *author_email, *author_date;
 static int all, edit_flag, also, interactive, only, amend, signoff;
-static int quiet, verbose, no_verify, allow_empty;
+static int quiet, verbose, no_verify, allow_empty, dry_run;
 static char *untracked_files_arg;
 /*
  * The default commit message cleanup mode will remove the lines
@@ -103,6 +103,7 @@
 	OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
 	OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
 	OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
+	OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"),
 	OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
 	{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
 	OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"),
@@ -217,12 +218,15 @@
 		exit(128); /* We've already reported the error, finish dying */
 }
 
-static char *prepare_index(int argc, const char **argv, const char *prefix)
+static char *prepare_index(int argc, const char **argv, const char *prefix, int is_status)
 {
 	int fd;
 	struct string_list partial;
 	const char **pathspec = NULL;
+	int refresh_flags = REFRESH_QUIET;
 
+	if (is_status)
+		refresh_flags |= REFRESH_UNMERGED;
 	if (interactive) {
 		if (interactive_add(argc, argv, prefix) != 0)
 			die("interactive add failed");
@@ -253,7 +257,7 @@
 	if (all || (also && pathspec && *pathspec)) {
 		int fd = hold_locked_index(&index_lock, 1);
 		add_files_to_cache(also ? prefix : NULL, pathspec, 0);
-		refresh_cache(REFRESH_QUIET);
+		refresh_cache(refresh_flags);
 		if (write_cache(fd, active_cache, active_nr) ||
 		    close_lock_file(&index_lock))
 			die("unable to write new_index file");
@@ -272,7 +276,7 @@
 	 */
 	if (!pathspec || !*pathspec) {
 		fd = hold_locked_index(&index_lock, 1);
-		refresh_cache(REFRESH_QUIET);
+		refresh_cache(refresh_flags);
 		if (write_cache(fd, active_cache, active_nr) ||
 		    commit_locked_index(&index_lock))
 			die("unable to write new_index file");
@@ -339,27 +343,24 @@
 	return false_lock.filename;
 }
 
-static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn)
+static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn,
+		      struct wt_status *s)
 {
-	struct wt_status s;
-
-	wt_status_prepare(&s);
-	if (wt_status_relative_paths)
-		s.prefix = prefix;
+	if (s->relative_paths)
+		s->prefix = prefix;
 
 	if (amend) {
-		s.amend = 1;
-		s.reference = "HEAD^1";
+		s->amend = 1;
+		s->reference = "HEAD^1";
 	}
-	s.verbose = verbose;
-	s.untracked = (show_untracked_files == SHOW_ALL_UNTRACKED_FILES);
-	s.index_file = index_file;
-	s.fp = fp;
-	s.nowarn = nowarn;
+	s->verbose = verbose;
+	s->index_file = index_file;
+	s->fp = fp;
+	s->nowarn = nowarn;
 
-	wt_status_print(&s);
+	wt_status_print(s);
 
-	return s.commitable;
+	return s->commitable;
 }
 
 static int is_a_merge(const unsigned char *sha1)
@@ -413,7 +414,8 @@
 	author_date = date;
 }
 
-static int prepare_to_commit(const char *index_file, const char *prefix)
+static int prepare_to_commit(const char *index_file, const char *prefix,
+			     struct wt_status *s)
 {
 	struct stat statbuf;
 	int commitable, saved_color_setting;
@@ -555,10 +557,10 @@
 		if (ident_shown)
 			fprintf(fp, "#\n");
 
-		saved_color_setting = wt_status_use_color;
-		wt_status_use_color = 0;
-		commitable = run_status(fp, index_file, prefix, 1);
-		wt_status_use_color = saved_color_setting;
+		saved_color_setting = s->use_color;
+		s->use_color = 0;
+		commitable = run_status(fp, index_file, prefix, 1, s);
+		s->use_color = saved_color_setting;
 	} else {
 		unsigned char sha1[20];
 		const char *parent = "HEAD";
@@ -579,7 +581,7 @@
 
 	if (!commitable && !in_merge && !allow_empty &&
 	    !(amend && is_a_merge(head_sha1))) {
-		run_status(stdout, index_file, prefix, 0);
+		run_status(stdout, index_file, prefix, 0, s);
 		return 0;
 	}
 
@@ -691,7 +693,8 @@
 
 static int parse_and_validate_options(int argc, const char *argv[],
 				      const char * const usage[],
-				      const char *prefix)
+				      const char *prefix,
+				      struct wt_status *s)
 {
 	int f = 0;
 
@@ -794,11 +797,11 @@
 	if (!untracked_files_arg)
 		; /* default already initialized */
 	else if (!strcmp(untracked_files_arg, "no"))
-		show_untracked_files = SHOW_NO_UNTRACKED_FILES;
+		s->show_untracked_files = SHOW_NO_UNTRACKED_FILES;
 	else if (!strcmp(untracked_files_arg, "normal"))
-		show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
+		s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
 	else if (!strcmp(untracked_files_arg, "all"))
-		show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
+		s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
 	else
 		die("Invalid untracked files mode '%s'", untracked_files_arg);
 
@@ -810,30 +813,95 @@
 	return argc;
 }
 
-int cmd_status(int argc, const char **argv, const char *prefix)
+static int dry_run_commit(int argc, const char **argv, const char *prefix,
+			  struct wt_status *s)
 {
-	const char *index_file;
 	int commitable;
+	const char *index_file;
 
-	git_config(git_status_config, NULL);
-
-	if (wt_status_use_color == -1)
-		wt_status_use_color = git_use_color_default;
-
-	if (diff_use_color_default == -1)
-		diff_use_color_default = git_use_color_default;
-
-	argc = parse_and_validate_options(argc, argv, builtin_status_usage, prefix);
-
-	index_file = prepare_index(argc, argv, prefix);
-
-	commitable = run_status(stdout, index_file, prefix, 0);
-
+	index_file = prepare_index(argc, argv, prefix, 1);
+	commitable = run_status(stdout, index_file, prefix, 0, s);
 	rollback_index_files();
 
 	return commitable ? 0 : 1;
 }
 
+static int parse_status_slot(const char *var, int offset)
+{
+	if (!strcasecmp(var+offset, "header"))
+		return WT_STATUS_HEADER;
+	if (!strcasecmp(var+offset, "updated")
+		|| !strcasecmp(var+offset, "added"))
+		return WT_STATUS_UPDATED;
+	if (!strcasecmp(var+offset, "changed"))
+		return WT_STATUS_CHANGED;
+	if (!strcasecmp(var+offset, "untracked"))
+		return WT_STATUS_UNTRACKED;
+	if (!strcasecmp(var+offset, "nobranch"))
+		return WT_STATUS_NOBRANCH;
+	if (!strcasecmp(var+offset, "unmerged"))
+		return WT_STATUS_UNMERGED;
+	die("bad config variable '%s'", var);
+}
+
+static int git_status_config(const char *k, const char *v, void *cb)
+{
+	struct wt_status *s = cb;
+
+	if (!strcmp(k, "status.submodulesummary")) {
+		int is_bool;
+		s->submodule_summary = git_config_bool_or_int(k, v, &is_bool);
+		if (is_bool && s->submodule_summary)
+			s->submodule_summary = -1;
+		return 0;
+	}
+	if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
+		s->use_color = git_config_colorbool(k, v, -1);
+		return 0;
+	}
+	if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
+		int slot = parse_status_slot(k, 13);
+		if (!v)
+			return config_error_nonbool(k);
+		color_parse(v, k, s->color_palette[slot]);
+		return 0;
+	}
+	if (!strcmp(k, "status.relativepaths")) {
+		s->relative_paths = git_config_bool(k, v);
+		return 0;
+	}
+	if (!strcmp(k, "status.showuntrackedfiles")) {
+		if (!v)
+			return config_error_nonbool(k);
+		else if (!strcmp(v, "no"))
+			s->show_untracked_files = SHOW_NO_UNTRACKED_FILES;
+		else if (!strcmp(v, "normal"))
+			s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
+		else if (!strcmp(v, "all"))
+			s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
+		else
+			return error("Invalid untracked files mode '%s'", v);
+		return 0;
+	}
+	return git_diff_ui_config(k, v, NULL);
+}
+
+int cmd_status(int argc, const char **argv, const char *prefix)
+{
+	struct wt_status s;
+
+	wt_status_prepare(&s);
+	git_config(git_status_config, &s);
+	if (s.use_color == -1)
+		s.use_color = git_use_color_default;
+	if (diff_use_color_default == -1)
+		diff_use_color_default = git_use_color_default;
+
+	argc = parse_and_validate_options(argc, argv, builtin_status_usage,
+					  prefix, &s);
+	return dry_run_commit(argc, argv, prefix, &s);
+}
+
 static void print_summary(const char *prefix, const unsigned char *sha1)
 {
 	struct rev_info rev;
@@ -883,10 +951,12 @@
 
 static int git_commit_config(const char *k, const char *v, void *cb)
 {
+	struct wt_status *s = cb;
+
 	if (!strcmp(k, "commit.template"))
 		return git_config_string(&template_file, k, v);
 
-	return git_status_config(k, v, cb);
+	return git_status_config(k, v, s);
 }
 
 int cmd_commit(int argc, const char **argv, const char *prefix)
@@ -899,19 +969,26 @@
 	struct commit_list *parents = NULL, **pptr = &parents;
 	struct stat statbuf;
 	int allow_fast_forward = 1;
+	struct wt_status s;
 
-	git_config(git_commit_config, NULL);
+	wt_status_prepare(&s);
+	git_config(git_commit_config, &s);
 
-	if (wt_status_use_color == -1)
-		wt_status_use_color = git_use_color_default;
+	if (s.use_color == -1)
+		s.use_color = git_use_color_default;
 
-	argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix);
-
-	index_file = prepare_index(argc, argv, prefix);
+	argc = parse_and_validate_options(argc, argv, builtin_commit_usage,
+					  prefix, &s);
+	if (dry_run) {
+		if (diff_use_color_default == -1)
+			diff_use_color_default = git_use_color_default;
+		return dry_run_commit(argc, argv, prefix, &s);
+	}
+	index_file = prepare_index(argc, argv, prefix, 0);
 
 	/* Set up everything for writing the commit object.  This includes
 	   running hooks, writing the trees, and interacting with the user.  */
-	if (!prepare_to_commit(index_file, prefix)) {
+	if (!prepare_to_commit(index_file, prefix, &s)) {
 		rollback_index_files();
 		return 1;
 	}
diff --git a/builtin-log.c b/builtin-log.c
index 82236c5..25e21ed 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -35,6 +35,7 @@
 		      struct rev_info *rev)
 {
 	int i;
+	int decoration_style = 0;
 
 	rev->abbrev = DEFAULT_ABBREV;
 	rev->commit_format = CMIT_FMT_DEFAULT;
@@ -61,8 +62,15 @@
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 		if (!strcmp(arg, "--decorate")) {
-			load_ref_decorations();
-			rev->show_decorations = 1;
+			decoration_style = DECORATE_SHORT_REFS;
+		} else if (!prefixcmp(arg, "--decorate=")) {
+			const char *v = skip_prefix(arg, "--decorate=");
+			if (!strcmp(v, "full"))
+				decoration_style = DECORATE_FULL_REFS;
+			else if (!strcmp(v, "short"))
+				decoration_style = DECORATE_SHORT_REFS;
+			else
+				die("invalid --decorate option: %s", arg);
 		} else if (!strcmp(arg, "--source")) {
 			rev->show_source = 1;
 		} else if (!strcmp(arg, "-h")) {
@@ -70,6 +78,10 @@
 		} else
 			die("unrecognized argument: %s", arg);
 	}
+	if (decoration_style) {
+		rev->show_decorations = 1;
+		load_ref_decorations(decoration_style);
+	}
 }
 
 /*
diff --git a/builtin-mv.c b/builtin-mv.c
index b592c36..1b20028 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -53,7 +53,7 @@
 	int verbose = 0, show_only = 0, force = 0, ignore_errors = 0;
 	struct option builtin_mv_options[] = {
 		OPT__DRY_RUN(&show_only),
-		OPT_BOOLEAN('f', NULL, &force, "force move/rename even if target exists"),
+		OPT_BOOLEAN('f', "force", &force, "force move/rename even if target exists"),
 		OPT_BOOLEAN('k', NULL, &ignore_errors, "skip move/rename errors"),
 		OPT_END(),
 	};
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index 9c2d634..14c836b 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -113,13 +113,15 @@
 	argc = parse_options(argc, argv, unused_prefix, read_tree_options,
 			     read_tree_usage, 0);
 
-	if (read_cache_unmerged() && (opts.prefix || opts.merge))
-		die("You need to resolve your current index first");
-
 	prefix_set = opts.prefix ? 1 : 0;
 	if (1 < opts.merge + opts.reset + prefix_set)
 		die("Which one? -m, --reset, or --prefix?");
-	stage = opts.merge = (opts.reset || opts.merge || prefix_set);
+
+	if (opts.reset || opts.merge || opts.prefix) {
+		if (read_cache_unmerged() && (opts.prefix || opts.merge))
+			die("You need to resolve your current index first");
+		stage = opts.merge = 1;
+	}
 
 	for (i = 0; i < argc; i++) {
 		const char *arg = argv[i];
diff --git a/builtin-reset.c b/builtin-reset.c
index 5fa1789..0fc0b07 100644
--- a/builtin-reset.c
+++ b/builtin-reset.c
@@ -108,7 +108,8 @@
 	if (read_cache() < 0)
 		return error("Could not read index");
 
-	result = refresh_cache(flags) ? 1 : 0;
+	result = refresh_index(&the_index, (flags), NULL, NULL,
+			       "Unstaged changes after reset:") ? 1 : 0;
 	if (write_cache(fd, active_cache, active_nr) ||
 			commit_locked_index(index_lock))
 		return error ("Could not refresh index");
@@ -261,7 +262,7 @@
 			die("Cannot do %s reset with paths.",
 					reset_type_names[reset_type]);
 		return read_from_tree(prefix, argv + i, sha1,
-				quiet ? REFRESH_QUIET : REFRESH_SAY_CHANGED);
+				quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN);
 	}
 	if (reset_type == NONE)
 		reset_type = MIXED; /* by default */
@@ -302,7 +303,7 @@
 		break;
 	case MIXED: /* Report what has not been updated. */
 		update_index_refresh(0, NULL,
-				quiet ? REFRESH_QUIET : REFRESH_SAY_CHANGED);
+				quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN);
 		break;
 	}
 
diff --git a/builtin-tag.c b/builtin-tag.c
index a51a6d1..c479018 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -390,7 +390,7 @@
 		OPT_BOOLEAN('s', NULL, &sign, "annotated and GPG-signed tag"),
 		OPT_STRING('u', NULL, &keyid, "key-id",
 					"use another key to sign the tag"),
-		OPT_BOOLEAN('f', NULL, &force, "replace the tag if exists"),
+		OPT_BOOLEAN('f', "force", &force, "replace the tag if exists"),
 
 		OPT_GROUP("Tag listing options"),
 		{
diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c
index 968fda7..685566e 100644
--- a/builtin-unpack-objects.c
+++ b/builtin-unpack-objects.c
@@ -181,10 +181,10 @@
 static int check_object(struct object *obj, int type, void *data)
 {
 	if (!obj)
-		return 0;
+		return 1;
 
 	if (obj->flags & FLAG_WRITTEN)
-		return 1;
+		return 0;
 
 	if (type != OBJ_ANY && obj->type != type)
 		die("object type mismatch");
@@ -195,22 +195,24 @@
 		if (type != obj->type || type <= 0)
 			die("object of unexpected type");
 		obj->flags |= FLAG_WRITTEN;
-		return 1;
+		return 0;
 	}
 
 	if (fsck_object(obj, 1, fsck_error_function))
 		die("Error in object");
-	if (!fsck_walk(obj, check_object, NULL))
+	if (fsck_walk(obj, check_object, NULL))
 		die("Error on reachable objects of %s", sha1_to_hex(obj->sha1));
 	write_cached_object(obj);
-	return 1;
+	return 0;
 }
 
 static void write_rest(void)
 {
 	unsigned i;
-	for (i = 0; i < nr_objects; i++)
-		check_object(obj_list[i].obj, OBJ_ANY, NULL);
+	for (i = 0; i < nr_objects; i++) {
+		if (obj_list[i].obj)
+			check_object(obj_list[i].obj, OBJ_ANY, NULL);
+	}
 }
 
 static void added_object(unsigned nr, enum object_type type,
diff --git a/builtin-update-server-info.c b/builtin-update-server-info.c
new file mode 100644
index 0000000..2b3fddc
--- /dev/null
+++ b/builtin-update-server-info.c
@@ -0,0 +1,25 @@
+#include "cache.h"
+#include "builtin.h"
+#include "parse-options.h"
+
+static const char * const update_server_info_usage[] = {
+	"git update-server-info [--force]",
+	NULL
+};
+
+int cmd_update_server_info(int argc, const char **argv, const char *prefix)
+{
+	int force = 0;
+	struct option options[] = {
+		OPT_BOOLEAN('f', "force", &force,
+			"update the info files from scratch"),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options,
+			     update_server_info_usage, 0);
+	if (argc > 0)
+		usage_with_options(update_server_info_usage, options);
+
+	return !!update_server_info(force);
+}
diff --git a/builtin-verify-pack.c b/builtin-verify-pack.c
index b5bd28e..b6079ae 100644
--- a/builtin-verify-pack.c
+++ b/builtin-verify-pack.c
@@ -6,10 +6,14 @@
 
 #define MAX_CHAIN 50
 
-static void show_pack_info(struct packed_git *p)
+#define VERIFY_PACK_VERBOSE 01
+#define VERIFY_PACK_STAT_ONLY 02
+
+static void show_pack_info(struct packed_git *p, unsigned int flags)
 {
 	uint32_t nr_objects, i;
 	int cnt;
+	int stat_only = flags & VERIFY_PACK_STAT_ONLY;
 	unsigned long chain_histogram[MAX_CHAIN+1], baseobjects;
 
 	nr_objects = p->num_objects;
@@ -32,16 +36,19 @@
 		type = packed_object_info_detail(p, offset, &size, &store_size,
 						 &delta_chain_length,
 						 base_sha1);
-		printf("%s ", sha1_to_hex(sha1));
+		if (!stat_only)
+			printf("%s ", sha1_to_hex(sha1));
 		if (!delta_chain_length) {
-			printf("%-6s %lu %lu %"PRIuMAX"\n",
-			       type, size, store_size, (uintmax_t)offset);
+			if (!stat_only)
+				printf("%-6s %lu %lu %"PRIuMAX"\n",
+				       type, size, store_size, (uintmax_t)offset);
 			baseobjects++;
 		}
 		else {
-			printf("%-6s %lu %lu %"PRIuMAX" %u %s\n",
-			       type, size, store_size, (uintmax_t)offset,
-			       delta_chain_length, sha1_to_hex(base_sha1));
+			if (!stat_only)
+				printf("%-6s %lu %lu %"PRIuMAX" %u %s\n",
+				       type, size, store_size, (uintmax_t)offset,
+				       delta_chain_length, sha1_to_hex(base_sha1));
 			if (delta_chain_length <= MAX_CHAIN)
 				chain_histogram[delta_chain_length]++;
 			else
@@ -66,10 +73,12 @@
 		       chain_histogram[0] > 1 ? "s" : "");
 }
 
-static int verify_one_pack(const char *path, int verbose)
+static int verify_one_pack(const char *path, unsigned int flags)
 {
 	char arg[PATH_MAX];
 	int len;
+	int verbose = flags & VERIFY_PACK_VERBOSE;
+	int stat_only = flags & VERIFY_PACK_STAT_ONLY;
 	struct packed_git *pack;
 	int err;
 
@@ -105,14 +114,19 @@
 		return error("packfile %s not found.", arg);
 
 	install_packed_git(pack);
-	err = verify_pack(pack);
 
-	if (verbose) {
+	if (!stat_only)
+		err = verify_pack(pack);
+	else
+		err = open_pack_index(pack);
+
+	if (verbose || stat_only) {
 		if (err)
 			printf("%s: bad\n", pack->pack_name);
 		else {
-			show_pack_info(pack);
-			printf("%s: ok\n", pack->pack_name);
+			show_pack_info(pack, flags);
+			if (!stat_only)
+				printf("%s: ok\n", pack->pack_name);
 		}
 	}
 
@@ -120,17 +134,20 @@
 }
 
 static const char * const verify_pack_usage[] = {
-	"git verify-pack [-v|--verbose] <pack>...",
+	"git verify-pack [-v|--verbose] [-s|--stat-only] <pack>...",
 	NULL
 };
 
 int cmd_verify_pack(int argc, const char **argv, const char *prefix)
 {
 	int err = 0;
-	int verbose = 0;
+	unsigned int flags = 0;
 	int i;
 	const struct option verify_pack_options[] = {
-		OPT__VERBOSE(&verbose),
+		OPT_BIT('v', "verbose", &flags, "verbose",
+			VERIFY_PACK_VERBOSE),
+		OPT_BIT('s', "stat-only", &flags, "show statistics only",
+			VERIFY_PACK_STAT_ONLY),
 		OPT_END()
 	};
 
@@ -140,7 +157,7 @@
 	if (argc < 1)
 		usage_with_options(verify_pack_usage, verify_pack_options);
 	for (i = 0; i < argc; i++) {
-		if (verify_one_pack(argv[i], verbose))
+		if (verify_one_pack(argv[i], flags))
 			err = 1;
 		discard_revindex();
 	}
diff --git a/builtin.h b/builtin.h
index 51e4ba7..a2174dc 100644
--- a/builtin.h
+++ b/builtin.h
@@ -102,6 +102,7 @@
 extern int cmd_unpack_objects(int argc, const char **argv, const char *prefix);
 extern int cmd_update_index(int argc, const char **argv, const char *prefix);
 extern int cmd_update_ref(int argc, const char **argv, const char *prefix);
+extern int cmd_update_server_info(int argc, const char **argv, const char *prefix);
 extern int cmd_upload_archive(int argc, const char **argv, const char *prefix);
 extern int cmd_upload_tar(int argc, const char **argv, const char *prefix);
 extern int cmd_verify_tag(int argc, const char **argv, const char *prefix);
diff --git a/cache.h b/cache.h
index cd5aa89..5fad24c 100644
--- a/cache.h
+++ b/cache.h
@@ -330,7 +330,7 @@
 #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
 #define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags))
 #define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags))
-#define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL)
+#define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL, NULL)
 #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
 #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
 #define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
@@ -469,15 +469,15 @@
 extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
 
 /* "careful lstat()" */
-extern int check_path(const char *path, int len, struct stat *st);
+extern int check_path(const char *path, int len, struct stat *st, int skiplen);
 
 #define REFRESH_REALLY		0x0001	/* ignore_valid */
 #define REFRESH_UNMERGED	0x0002	/* allow unmerged */
 #define REFRESH_QUIET		0x0004	/* be quiet about it */
 #define REFRESH_IGNORE_MISSING	0x0008	/* ignore non-existent */
 #define REFRESH_IGNORE_SUBMODULES	0x0010	/* ignore submodules */
-#define REFRESH_SAY_CHANGED	0x0020	/* say "changed" not "needs update" */
-extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen);
+#define REFRESH_IN_PORCELAIN	0x0020	/* user friendly output, not "needs update" */
+extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, char *header_msg);
 
 struct lock_file {
 	struct lock_file *next;
diff --git a/commit.c b/commit.c
index e2bcbe8..a6c6f70 100644
--- a/commit.c
+++ b/commit.c
@@ -564,13 +564,13 @@
 	while (interesting(list)) {
 		struct commit *commit;
 		struct commit_list *parents;
-		struct commit_list *n;
+		struct commit_list *next;
 		int flags;
 
 		commit = list->item;
-		n = list->next;
+		next = list->next;
 		free(list);
-		list = n;
+		list = next;
 
 		flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
 		if (flags == (PARENT1 | PARENT2)) {
@@ -598,11 +598,11 @@
 	free_commit_list(list);
 	list = result; result = NULL;
 	while (list) {
-		struct commit_list *n = list->next;
+		struct commit_list *next = list->next;
 		if (!(list->item->object.flags & STALE))
 			insert_by_date(list->item, &result);
 		free(list);
-		list = n;
+		list = next;
 	}
 	return result;
 }
diff --git a/compat/bswap.h b/compat/bswap.h
new file mode 100644
index 0000000..7246a12
--- /dev/null
+++ b/compat/bswap.h
@@ -0,0 +1,36 @@
+/*
+ * Let's make sure we always have a sane definition for ntohl()/htonl().
+ * Some libraries define those as a function call, just to perform byte
+ * shifting, bringing significant overhead to what should be a simple
+ * operation.
+ */
+
+/*
+ * Default version that the compiler ought to optimize properly with
+ * constant values.
+ */
+static inline unsigned int default_swab32(unsigned int val)
+{
+	return (((val & 0xff000000) >> 24) |
+		((val & 0x00ff0000) >>  8) |
+		((val & 0x0000ff00) <<  8) |
+		((val & 0x000000ff) << 24));
+}
+
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
+#define bswap32(x) ({ \
+	unsigned int __res; \
+	if (__builtin_constant_p(x)) { \
+		__res = default_swab32(x); \
+	} else { \
+		__asm__("bswap %0" : "=r" (__res) : "0" (x)); \
+	} \
+	__res; })
+
+#undef ntohl
+#undef htonl
+#define ntohl(x) bswap32(x)
+#define htonl(x) bswap32(x)
+
+#endif
diff --git a/configure.ac b/configure.ac
index 3f1922d..b09b8e4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -156,19 +156,11 @@
 # tests.  These tests take up a significant amount of the total test time
 # but are not needed unless you plan to talk to SVN repos.
 #
-# Define MOZILLA_SHA1 environment variable when running make to make use of
-# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast
-# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default
-# choice) has very fast version optimized for i586.
-#
 # Define PPC_SHA1 environment variable when running make to make use of
 # a bundled SHA1 routine optimized for PowerPC.
 #
-# Define ARM_SHA1 environment variable when running make to make use of
-# a bundled SHA1 routine optimized for ARM.
-#
 # Define NO_OPENSSL environment variable if you do not have OpenSSL.
-# This also implies MOZILLA_SHA1.
+# This also implies BLK_SHA1.
 #
 # Define OPENSSLDIR=/foo/bar if your openssl header and library files are in
 # /foo/bar/include and /foo/bar/lib directories.
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index 342529d..38438f3 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -201,7 +201,7 @@
 def isModeExecChanged(src_mode, dst_mode):
     return isModeExec(src_mode) != isModeExec(dst_mode)
 
-def p4CmdList(cmd, stdin=None, stdin_mode='w+b'):
+def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None):
     cmd = p4_build_cmd("-G %s" % (cmd))
     if verbose:
         sys.stderr.write("Opening pipe: %s\n" % cmd)
@@ -224,7 +224,10 @@
     try:
         while True:
             entry = marshal.load(p4.stdout)
-            result.append(entry)
+	    if cb is not None:
+		cb(entry)
+	    else:
+		result.append(entry)
     except EOFError:
         pass
     exitCode = p4.wait()
@@ -950,10 +953,84 @@
 
         return branches
 
-    ## Should move this out, doesn't use SELF.
-    def readP4Files(self, files):
+    # output one file from the P4 stream
+    # - helper for streamP4Files
+
+    def streamOneP4File(self, file, contents):
+	if file["type"] == "apple":
+	    print "\nfile %s is a strange apple file that forks. Ignoring" % \
+		file['depotFile']
+	    return
+
+        relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes)
+        if verbose:
+            sys.stderr.write("%s\n" % relPath)
+
+        mode = "644"
+        if isP4Exec(file["type"]):
+            mode = "755"
+        elif file["type"] == "symlink":
+            mode = "120000"
+            # p4 print on a symlink contains "target\n", so strip it off
+            last = contents.pop()
+            last = last[:-1]
+            contents.append(last)
+
+        if self.isWindows and file["type"].endswith("text"):
+            mangled = []
+            for data in contents:
+                data = data.replace("\r\n", "\n")
+                mangled.append(data)
+            contents = mangled
+
+        if file['type'] in ('text+ko', 'unicode+ko', 'binary+ko'):
+            contents = map(lambda text: re.sub(r'(?i)\$(Id|Header):[^$]*\$',r'$\1$', text), contents)
+        elif file['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'):
+            contents = map(lambda text: re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$\n]*\$',r'$\1$', text), contents)
+
+        self.gitStream.write("M %s inline %s\n" % (mode, relPath))
+
+        # total length...
+        length = 0
+        for d in contents:
+            length = length + len(d)
+
+        self.gitStream.write("data %d\n" % length)
+        for d in contents:
+            self.gitStream.write(d)
+        self.gitStream.write("\n")
+
+    def streamOneP4Deletion(self, file):
+        relPath = self.stripRepoPath(file['path'], self.branchPrefixes)
+        if verbose:
+            sys.stderr.write("delete %s\n" % relPath)
+        self.gitStream.write("D %s\n" % relPath)
+
+    # handle another chunk of streaming data
+    def streamP4FilesCb(self, marshalled):
+
+	if marshalled.has_key('depotFile') and self.stream_have_file_info:
+	    # start of a new file - output the old one first
+	    self.streamOneP4File(self.stream_file, self.stream_contents)
+	    self.stream_file = {}
+	    self.stream_contents = []
+	    self.stream_have_file_info = False
+
+	# pick up the new file information... for the
+	# 'data' field we need to append to our array
+	for k in marshalled.keys():
+	    if k == 'data':
+		self.stream_contents.append(marshalled['data'])
+	    else:
+		self.stream_file[k] = marshalled[k]
+
+	self.stream_have_file_info = True
+
+    # Stream directly from "p4 files" into "git fast-import"
+    def streamP4Files(self, files):
         filesForCommit = []
         filesToRead = []
+        filesToDelete = []
 
         for f in files:
             includeFile = True
@@ -967,50 +1044,35 @@
                 filesForCommit.append(f)
                 if f['action'] not in ('delete', 'purge'):
                     filesToRead.append(f)
+                else:
+                    filesToDelete.append(f)
 
-        filedata = []
+        # deleted files...
+        for f in filesToDelete:
+            self.streamOneP4Deletion(f)
+
         if len(filesToRead) > 0:
-            filedata = p4CmdList('-x - print',
-                                 stdin='\n'.join(['%s#%s' % (f['path'], f['rev'])
+            self.stream_file = {}
+            self.stream_contents = []
+            self.stream_have_file_info = False
+
+	    # curry self argument
+	    def streamP4FilesCbSelf(entry):
+		self.streamP4FilesCb(entry)
+
+	    p4CmdList("-x - print",
+		'\n'.join(['%s#%s' % (f['path'], f['rev'])
                                                   for f in filesToRead]),
-                                 stdin_mode='w+')
+	        cb=streamP4FilesCbSelf)
 
-            if "p4ExitCode" in filedata[0]:
-                die("Problems executing p4. Error: [%d]."
-                    % (filedata[0]['p4ExitCode']));
-
-        j = 0;
-        contents = {}
-        while j < len(filedata):
-            stat = filedata[j]
-            j += 1
-            text = ''
-            while j < len(filedata) and filedata[j]['code'] in ('text', 'unicode', 'binary'):
-                text += filedata[j]['data']
-                del filedata[j]['data']
-                j += 1
-
-            if not stat.has_key('depotFile'):
-                sys.stderr.write("p4 print fails with: %s\n" % repr(stat))
-                continue
-
-            if stat['type'] in ('text+ko', 'unicode+ko', 'binary+ko'):
-                text = re.sub(r'(?i)\$(Id|Header):[^$]*\$',r'$\1$', text)
-            elif stat['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'):
-                text = re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$\n]*\$',r'$\1$', text)
-
-            contents[stat['depotFile']] = text
-
-        for f in filesForCommit:
-            path = f['path']
-            if contents.has_key(path):
-                f['data'] = contents[path]
-
-        return filesForCommit
+            # do the last chunk
+            if self.stream_file.has_key('depotFile'):
+                self.streamOneP4File(self.stream_file, self.stream_contents)
 
     def commit(self, details, files, branch, branchPrefixes, parent = ""):
         epoch = details["time"]
         author = details["user"]
+	self.branchPrefixes = branchPrefixes
 
         if self.verbose:
             print "commit into %s" % branch
@@ -1023,7 +1085,6 @@
                 new_files.append (f)
             else:
                 sys.stderr.write("Ignoring file outside of prefix: %s\n" % path)
-        files = self.readP4Files(new_files)
 
         self.gitStream.write("commit %s\n" % branch)
 #        gitStream.write("mark :%s\n" % details["change"])
@@ -1051,33 +1112,7 @@
                 print "parent %s" % parent
             self.gitStream.write("from %s\n" % parent)
 
-        for file in files:
-            if file["type"] == "apple":
-                print "\nfile %s is a strange apple file that forks. Ignoring!" % file['path']
-                continue
-
-            relPath = self.stripRepoPath(file['path'], branchPrefixes)
-            if file["action"] in ("delete", "purge"):
-                self.gitStream.write("D %s\n" % relPath)
-            else:
-                data = file['data']
-
-                mode = "644"
-                if isP4Exec(file["type"]):
-                    mode = "755"
-                elif file["type"] == "symlink":
-                    mode = "120000"
-                    # p4 print on a symlink contains "target\n", so strip it off
-                    data = data[:-1]
-
-                if self.isWindows and file["type"].endswith("text"):
-                    data = data.replace("\r\n", "\n")
-
-                self.gitStream.write("M %s inline %s\n" % (mode, relPath))
-                self.gitStream.write("data %s\n" % len(data))
-                self.gitStream.write(data)
-                self.gitStream.write("\n")
-
+        self.streamP4Files(new_files)
         self.gitStream.write("\n")
 
         change = int(details["change"])
diff --git a/diff-lib.c b/diff-lib.c
index ad2a4cd..0c74ef5 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -162,7 +162,8 @@
 		if (ce_uptodate(ce))
 			continue;
 
-		changed = check_removed(ce, &st);
+		/* If CE_VALID is set, don't look at workdir for file removal */
+		changed = (ce->ce_flags & CE_VALID) ? 0 : check_removed(ce, &st);
 		if (changed) {
 			if (changed < 0) {
 				perror(ce->name);
@@ -309,22 +310,6 @@
 }
 
 /*
- * This turns all merge entries into "stage 3". That guarantees that
- * when we read in the new tree (into "stage 1"), we won't lose sight
- * of the fact that we had unmerged entries.
- */
-static void mark_merge_entries(void)
-{
-	int i;
-	for (i = 0; i < active_nr; i++) {
-		struct cache_entry *ce = active_cache[i];
-		if (!ce_stage(ce))
-			continue;
-		ce->ce_flags |= CE_STAGEMASK;
-	}
-}
-
-/*
  * This gets a mix of an existing index and a tree, one pathname entry
  * at a time. The index entry may be a single stage-0 one, but it could
  * also be multiple unmerged entries (in which case idx_pos/idx_nr will
@@ -337,6 +322,8 @@
 	struct rev_info *revs = o->unpack_data;
 	int match_missing, cached;
 
+	/* if the entry is not checked out, don't examine work tree */
+	cached = o->index_only || (idx && (idx->ce_flags & CE_VALID));
 	/*
 	 * Backward compatibility wart - "diff-index -m" does
 	 * not mean "do not ignore merges", but "match_missing".
@@ -344,12 +331,11 @@
 	 * But with the revision flag parsing, that's found in
 	 * "!revs->ignore_merges".
 	 */
-	cached = o->index_only;
 	match_missing = !revs->ignore_merges;
 
 	if (cached && idx && ce_stage(idx)) {
-		if (tree)
-			diff_unmerge(&revs->diffopt, idx->name, idx->ce_mode, idx->sha1);
+		diff_unmerge(&revs->diffopt, idx->name, idx->ce_mode,
+			     idx->sha1);
 		return;
 	}
 
@@ -435,8 +421,6 @@
 	struct unpack_trees_options opts;
 	struct tree_desc t;
 
-	mark_merge_entries();
-
 	ent = revs->pending.objects[0].item;
 	tree_name = revs->pending.objects[0].name;
 	tree = parse_tree_indirect(ent->sha1);
diff --git a/entry.c b/entry.c
index f276cf3..06d24f1 100644
--- a/entry.c
+++ b/entry.c
@@ -177,11 +177,15 @@
 
 /*
  * This is like 'lstat()', except it refuses to follow symlinks
- * in the path.
+ * in the path, after skipping "skiplen".
  */
-int check_path(const char *path, int len, struct stat *st)
+int check_path(const char *path, int len, struct stat *st, int skiplen)
 {
-	if (has_symlink_leading_path(path, len)) {
+	const char *slash = path + len;
+
+	while (path < slash && *slash != '/')
+		slash--;
+	if (!has_dirs_only_path(path, slash - path, skiplen)) {
 		errno = ENOENT;
 		return -1;
 	}
@@ -201,7 +205,7 @@
 	strcpy(path + len, ce->name);
 	len += ce_namelen(ce);
 
-	if (!check_path(path, len, &st)) {
+	if (!check_path(path, len, &st, state->base_dir_len)) {
 		unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
 		if (!changed)
 			return 0;
diff --git a/git-bisect.sh b/git-bisect.sh
index 8969553..6f6f039 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -405,7 +405,7 @@
 	  exit $res
       fi
 
-      if grep "is first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null; then
+      if grep "is the first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null; then
 	  echo "bisect run success"
 	  exit 0;
       fi
diff --git a/git-compat-util.h b/git-compat-util.h
index 71b5acb..e5e9f39 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -174,6 +174,8 @@
 #endif
 #endif
 
+#include "compat/bswap.h"
+
 /* General helper functions */
 extern void usage(const char *err) NORETURN;
 extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
diff --git a/git-instaweb.sh b/git-instaweb.sh
index 5f5cac7..d96eddb 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -77,11 +77,30 @@
 	resolve_full_httpd
 
 	# don't quote $full_httpd, there can be arguments to it (-f)
-	$full_httpd "$fqgitdir/gitweb/httpd.conf"
-	if test $? != 0; then
-		echo "Could not execute http daemon $httpd."
-		exit 1
-	fi
+	case "$httpd" in
+	*mongoose*)
+		#The mongoose server doesn't have a daemon mode so we'll have to fork it
+		$full_httpd "$fqgitdir/gitweb/httpd.conf" &
+		#Save the pid before doing anything else (we'll print it later)
+		pid=$!
+
+		if test $? != 0; then
+			echo "Could not execute http daemon $httpd."
+			exit 1
+		fi
+
+		cat > "$fqgitdir/pid" <<EOF
+$pid
+EOF
+		;;
+	*)
+		$full_httpd "$fqgitdir/gitweb/httpd.conf"
+		if test $? != 0; then
+			echo "Could not execute http daemon $httpd."
+			exit 1
+		fi
+		;;
+	esac
 }
 
 stop_httpd () {
@@ -308,6 +327,31 @@
 	fi
 }
 
+mongoose_conf() {
+	cat > "$conf" <<EOF
+# Mongoose web server configuration file.
+# Lines starting with '#' and empty lines are ignored.
+# For detailed description of every option, visit
+# http://code.google.com/p/mongoose/wiki/MongooseManual
+
+root		$fqgitdir/gitweb
+ports		$port
+index_files	gitweb.cgi
+#ssl_cert	$fqgitdir/gitweb/ssl_cert.pem
+error_log	$fqgitdir/gitweb/error.log
+access_log	$fqgitdir/gitweb/access.log
+
+#cgi setup
+cgi_env		PATH=/usr/local/bin:/usr/bin:/bin,GIT_DIR=$GIT_DIR,GIT_EXEC_PATH=$GIT_EXEC_PATH
+cgi_interp	$PERL
+cgi_ext		cgi,pl
+
+# mimetype mapping
+mime_types	.gz=application/x-gzip,.tar.gz=application/x-tgz,.tgz=application/x-tgz,.tar=application/x-tar,.zip=application/zip,.gif=image/gif,.jpg=image/jpeg,.jpeg=image/jpeg,.png=image/png,.css=text/css,.html=text/html,.htm=text/html,.js=text/javascript,.c=text/plain,.cpp=text/plain,.log=text/plain,.conf=text/plain,.text=text/plain,.txt=text/plain,.dtd=text/xml,.bz2=application/x-bzip,.tbz=application/x-bzip-compressed-tar,.tar.bz2=application/x-bzip-compressed-tar
+EOF
+}
+
+
 script='
 s#^(my|our) \$projectroot =.*#$1 \$projectroot = "'$(dirname "$fqgitdir")'";#;
 s#(my|our) \$gitbin =.*#$1 \$gitbin = "'$GIT_EXEC_PATH'";#;
@@ -344,6 +388,9 @@
 webrick)
 	webrick_conf
 	;;
+*mongoose*)
+	mongoose_conf
+	;;
 *)
 	echo "Unknown httpd specified: $httpd"
 	exit 1
diff --git a/git-stash.sh b/git-stash.sh
index 03e589f..d61c9d0 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -162,10 +162,6 @@
 }
 
 apply_stash () {
-	git update-index -q --refresh &&
-	git diff-files --quiet --ignore-submodules ||
-		die 'Cannot apply to a dirty working tree, please stage your changes'
-
 	unstash_index=
 
 	while test $# != 0
@@ -184,18 +180,27 @@
 		shift
 	done
 
-	# current index state
-	c_tree=$(git write-tree) ||
-		die 'Cannot apply a stash in the middle of a merge'
+	if test $# = 0
+	then
+		have_stash || die 'Nothing to apply'
+	fi
 
 	# stash records the work tree, and is a merge between the
 	# base commit (first parent) and the index tree (second parent).
-	s=$(git rev-parse --verify --default $ref_stash "$@") &&
-	w_tree=$(git rev-parse --verify "$s:") &&
-	b_tree=$(git rev-parse --verify "$s^1:") &&
-	i_tree=$(git rev-parse --verify "$s^2:") ||
+	s=$(git rev-parse --quiet --verify --default $ref_stash "$@") &&
+	w_tree=$(git rev-parse --quiet --verify "$s:") &&
+	b_tree=$(git rev-parse --quiet --verify "$s^1:") &&
+	i_tree=$(git rev-parse --quiet --verify "$s^2:") ||
 		die "$*: no valid stashed state found"
 
+	git update-index -q --refresh &&
+	git diff-files --quiet --ignore-submodules ||
+		die 'Cannot apply to a dirty working tree, please stage your changes'
+
+	# current index state
+	c_tree=$(git write-tree) ||
+		die 'Cannot apply a stash in the middle of a merge'
+
 	unstashed_index_tree=
 	if test -n "$unstash_index" && test "$b_tree" != "$i_tree" &&
 			test "$c_tree" != "$i_tree"
diff --git a/git-submodule.sh b/git-submodule.sh
index ebed711..bfbd36b 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -4,9 +4,14 @@
 #
 # Copyright (c) 2007 Lars Hjemli
 
-USAGE="[--quiet] [--cached] \
-[add [-b branch] <repo> <path>]|[status|init|update [-i|--init] [-N|--no-fetch] [--rebase|--merge]|summary [-n|--summary-limit <n>] [<commit>]] \
-[--] [<path>...]|[foreach <command>]|[sync [--] [<path>...]]"
+dashless=$(basename "$0" | sed -e 's/-/ /')
+USAGE="[--quiet] add [-b branch] [--reference <repository>] [--] <repository> <path>
+   or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
+   or: $dashless [--quiet] init [--] [<path>...]
+   or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
+   or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
+   or: $dashless [--quiet] foreach [--recursive] <command>
+   or: $dashless [--quiet] sync [--] [<path>...]"
 OPTIONS_SPEC=
 . git-sh-setup
 . git-parse-remote
@@ -16,8 +21,10 @@
 branch=
 reference=
 cached=
+files=
 nofetch=
 update=
+prefix=
 
 # Resolve relative url by appending to parent's url
 resolve_relative_url ()
@@ -237,13 +244,43 @@
 #
 cmd_foreach()
 {
+	# parse $args after "submodule ... foreach".
+	while test $# -ne 0
+	do
+		case "$1" in
+		-q|--quiet)
+			GIT_QUIET=1
+			;;
+		--recursive)
+			recursive=1
+			;;
+		-*)
+			usage
+			;;
+		*)
+			break
+			;;
+		esac
+		shift
+	done
+
 	module_list |
 	while read mode sha1 stage path
 	do
 		if test -e "$path"/.git
 		then
-			say "Entering '$path'"
-			(cd "$path" && eval "$@") ||
+			say "Entering '$prefix$path'"
+			name=$(module_name "$path")
+			(
+				prefix="$prefix$path/"
+				unset GIT_DIR
+				cd "$path" &&
+				eval "$@" &&
+				if test -n "$recursive"
+				then
+					cmd_foreach "--recursive" "$@"
+				fi
+			) ||
 			die "Stopping at '$path'; script returned non-zero status."
 		fi
 	done
@@ -316,6 +353,7 @@
 cmd_update()
 {
 	# parse $args after "submodule ... update".
+	orig_args="$@"
 	while test $# -ne 0
 	do
 		case "$1" in
@@ -348,6 +386,10 @@
 			shift
 			update="merge"
 			;;
+		--recursive)
+			shift
+			recursive=1
+			;;
 		--)
 			shift
 			break
@@ -434,6 +476,12 @@
 			die "Unable to $action '$sha1' in submodule path '$path'"
 			say "Submodule path '$path': $msg '$sha1'"
 		fi
+
+		if test -n "$recursive"
+		then
+			(unset GIT_DIR; cd "$path" && cmd_update $orig_args) ||
+			die "Failed to recurse into submodule path '$path'"
+		fi
 	done
 }
 
@@ -460,6 +508,7 @@
 cmd_summary() {
 	summary_limit=-1
 	for_status=
+	diff_cmd=diff-index
 
 	# parse $args after "submodule ... summary".
 	while test $# -ne 0
@@ -468,6 +517,9 @@
 		--cached)
 			cached="$1"
 			;;
+		--files)
+			files="$1"
+			;;
 		--for-status)
 			for_status="$1"
 			;;
@@ -504,9 +556,17 @@
 		head=HEAD
 	fi
 
+	if [ -n "$files" ]
+	then
+		test -n "$cached" &&
+		die "--cached cannot be used with --files"
+		diff_cmd=diff-files
+		head=
+	fi
+
 	cd_to_toplevel
 	# Get modified modules cared by user
-	modules=$(git diff-index $cached --raw $head -- "$@" |
+	modules=$(git $diff_cmd $cached --raw $head -- "$@" |
 		egrep '^:([0-7]* )?160000' |
 		while read mod_src mod_dst sha1_src sha1_dst status name
 		do
@@ -520,7 +580,7 @@
 
 	test -z "$modules" && return
 
-	git diff-index $cached --raw $head -- $modules |
+	git $diff_cmd $cached --raw $head -- $modules |
 	egrep '^:([0-7]* )?160000' |
 	cut -c2- |
 	while read mod_src mod_dst sha1_src sha1_dst status name
@@ -643,6 +703,7 @@
 cmd_status()
 {
 	# parse $args after "submodule ... status".
+	orig_args="$@"
 	while test $# -ne 0
 	do
 		case "$1" in
@@ -652,6 +713,9 @@
 		--cached)
 			cached=1
 			;;
+		--recursive)
+			recursive=1
+			;;
 		--)
 			shift
 			break
@@ -671,22 +735,34 @@
 	do
 		name=$(module_name "$path") || exit
 		url=$(git config submodule."$name".url)
+		displaypath="$prefix$path"
 		if test -z "$url" || ! test -d "$path"/.git -o -f "$path"/.git
 		then
-			say "-$sha1 $path"
+			say "-$sha1 $displaypath"
 			continue;
 		fi
 		set_name_rev "$path" "$sha1"
 		if git diff-files --quiet -- "$path"
 		then
-			say " $sha1 $path$revname"
+			say " $sha1 $displaypath$revname"
 		else
 			if test -z "$cached"
 			then
 				sha1=$(unset GIT_DIR; cd "$path" && git rev-parse --verify HEAD)
 				set_name_rev "$path" "$sha1"
 			fi
-			say "+$sha1 $path$revname"
+			say "+$sha1 $displaypath$revname"
+		fi
+
+		if test -n "$recursive"
+		then
+			(
+				prefix="$displaypath/"
+				unset GIT_DIR
+				cd "$path" &&
+				cmd_status $orig_args
+			) ||
+			die "Failed to recurse into submodule path '$path'"
 		fi
 	done
 }
diff --git a/git.c b/git.c
index 5da6c65..0b22595 100644
--- a/git.c
+++ b/git.c
@@ -359,6 +359,7 @@
 		{ "unpack-objects", cmd_unpack_objects, RUN_SETUP },
 		{ "update-index", cmd_update_index, RUN_SETUP },
 		{ "update-ref", cmd_update_ref, RUN_SETUP },
+		{ "update-server-info", cmd_update_server_info, RUN_SETUP },
 		{ "upload-archive", cmd_upload_archive },
 		{ "verify-tag", cmd_verify_tag, RUN_SETUP },
 		{ "version", cmd_version },
diff --git a/gitweb/INSTALL b/gitweb/INSTALL
index 18c9ce3..b76a0cf 100644
--- a/gitweb/INSTALL
+++ b/gitweb/INSTALL
@@ -123,6 +123,15 @@
 	$feature{'snapshot'}{'default'} = ['zip', 'tgz'];
 	$feature{'snapshot'}{'override'} = 1;
 
+If you allow overriding for the snapshot feature, you can specify which
+snapshot formats are globally disabled. You can also add any command line
+options you want (such as setting the compression level). For instance,
+you can disable Zip compressed snapshots and set GZip to run at level 6 by
+adding the following lines to your $GITWEB_CONFIG:
+
+	$known_snapshot_formats{'zip'}{'disabled'} = 1;
+	$known_snapshot_formats{'tgz'}{'compressor'} = ['gzip','-6'];
+
 
 Gitweb repositories
 -------------------
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index be7358f..24b2193 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -160,7 +160,8 @@
 	# 	'suffix' => filename suffix,
 	# 	'format' => --format for git-archive,
 	# 	'compressor' => [compressor command and arguments]
-	# 	                (array reference, optional)}
+	# 	                (array reference, optional)
+	# 	'disabled' => boolean (optional)}
 	#
 	'tgz' => {
 		'display' => 'tar.gz',
@@ -176,6 +177,14 @@
 		'format' => 'tar',
 		'compressor' => ['bzip2']},
 
+	'txz' => {
+		'display' => 'tar.xz',
+		'type' => 'application/x-xz',
+		'suffix' => '.tar.xz',
+		'format' => 'tar',
+		'compressor' => ['xz'],
+		'disabled' => 1},
+
 	'zip' => {
 		'display' => 'zip',
 		'type' => 'application/x-zip',
@@ -188,6 +197,7 @@
 our %known_snapshot_format_aliases = (
 	'gzip'  => 'tgz',
 	'bzip2' => 'tbz2',
+	'xz'    => 'txz',
 
 	# backward compatibility: legacy gitweb config support
 	'x-gzip' => undef, 'gz' => undef,
@@ -405,7 +415,7 @@
 		@{$feature{$name}{'default'}});
 	if (!$override) { return @defaults; }
 	if (!defined $sub) {
-		warn "feature $name is not overrideable";
+		warn "feature $name is not overridable";
 		return @defaults;
 	}
 	return $sub->(@defaults);
@@ -494,7 +504,8 @@
 		exists $known_snapshot_format_aliases{$_} ?
 		       $known_snapshot_format_aliases{$_} : $_} @fmts;
 	@fmts = grep {
-		exists $known_snapshot_formats{$_} } @fmts;
+		exists $known_snapshot_formats{$_} &&
+		!$known_snapshot_formats{$_}{'disabled'}} @fmts;
 }
 
 our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
@@ -1513,10 +1524,10 @@
 		$long =~ s/[[:cntrl:]]/?/g;
 		return $cgi->a({-href => $href, -class => "list subject",
 		                -title => to_utf8($long)},
-		       esc_html($short) . $extra);
+		       esc_html($short)) . $extra;
 	} else {
 		return $cgi->a({-href => $href, -class => "list subject"},
-		       esc_html($long)  . $extra);
+		       esc_html($long)) . $extra;
 	}
 }
 
@@ -5179,6 +5190,8 @@
 		die_error(400, "Invalid snapshot format parameter");
 	} elsif (!exists($known_snapshot_formats{$format})) {
 		die_error(400, "Unknown snapshot format");
+	} elsif ($known_snapshot_formats{$format}{'disabled'}) {
+		die_error(403, "Snapshot format not allowed");
 	} elsif (!grep($_ eq $format, @snapshot_fmts)) {
 		die_error(403, "Unsupported snapshot format");
 	}
diff --git a/graph.c b/graph.c
index f3226ec..6746d42 100644
--- a/graph.c
+++ b/graph.c
@@ -291,9 +291,10 @@
 	}
 
 	/*
-	 * Uninteresting and pruned commits won't be printed
+	 * Otherwise, use get_commit_action() to see if this commit is
+	 * interesting
 	 */
-	return (commit->object.flags & (UNINTERESTING | TREESAME)) ? 0 : 1;
+	return get_commit_action(graph->revs, commit) == commit_show;
 }
 
 static struct commit_list *next_interesting_parent(struct git_graph *graph,
diff --git a/http.c b/http.c
index eb0c669..5926c5b 100644
--- a/http.c
+++ b/http.c
@@ -1289,5 +1289,10 @@
 		free(freq->url);
 		freq->url = NULL;
 	}
-	freq->slot = NULL;
+	if (freq->slot != NULL) {
+		freq->slot->callback_func = NULL;
+		freq->slot->callback_data = NULL;
+		release_active_slot(freq->slot);
+		freq->slot = NULL;
+	}
 }
diff --git a/log-tree.c b/log-tree.c
index a3b4c06..1c9eefe 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -25,7 +25,8 @@
 	struct object *obj = parse_object(sha1);
 	if (!obj)
 		return 0;
-	refname = prettify_refname(refname);
+	if (!cb_data || *(int *)cb_data == DECORATE_SHORT_REFS)
+		refname = prettify_refname(refname);
 	add_name_decoration("", refname, obj);
 	while (obj->type == OBJ_TAG) {
 		obj = ((struct tag *)obj)->tagged;
@@ -36,12 +37,12 @@
 	return 0;
 }
 
-void load_ref_decorations(void)
+void load_ref_decorations(int flags)
 {
 	static int loaded;
 	if (!loaded) {
 		loaded = 1;
-		for_each_ref(add_ref_decoration, NULL);
+		for_each_ref(add_ref_decoration, &flags);
 	}
 }
 
diff --git a/log-tree.h b/log-tree.h
index 20b5caf..3f7b400 100644
--- a/log-tree.h
+++ b/log-tree.h
@@ -17,7 +17,7 @@
 			     const char **subject_p,
 			     const char **extra_headers_p,
 			     int *need_8bit_cte_p);
-void load_ref_decorations(void);
+void load_ref_decorations(int flags);
 
 #define FORMAT_PATCH_NAME_MAX 64
 void get_patch_filename(struct commit *commit, int nr, const char *suffix,
diff --git a/mozilla-sha1/sha1.c b/mozilla-sha1/sha1.c
deleted file mode 100644
index 95a4ebf..0000000
--- a/mozilla-sha1/sha1.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is SHA 180-1 Reference Implementation (Compact version)
- *
- * The Initial Developer of the Original Code is Paul Kocher of
- * Cryptography Research.  Portions created by Paul Kocher are
- * Copyright (C) 1995-9 by Cryptography Research, Inc.  All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- *     Paul Kocher
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above.  If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL.  If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-#include "sha1.h"
-
-static void shaHashBlock(moz_SHA_CTX *ctx);
-
-void moz_SHA1_Init(moz_SHA_CTX *ctx) {
-  int i;
-
-  ctx->lenW = 0;
-  ctx->sizeHi = ctx->sizeLo = 0;
-
-  /* Initialize H with the magic constants (see FIPS180 for constants)
-   */
-  ctx->H[0] = 0x67452301;
-  ctx->H[1] = 0xefcdab89;
-  ctx->H[2] = 0x98badcfe;
-  ctx->H[3] = 0x10325476;
-  ctx->H[4] = 0xc3d2e1f0;
-
-  for (i = 0; i < 80; i++)
-    ctx->W[i] = 0;
-}
-
-
-void moz_SHA1_Update(moz_SHA_CTX *ctx, const void *_dataIn, int len) {
-  const unsigned char *dataIn = _dataIn;
-  int i;
-
-  /* Read the data into W and process blocks as they get full
-   */
-  for (i = 0; i < len; i++) {
-    ctx->W[ctx->lenW / 4] <<= 8;
-    ctx->W[ctx->lenW / 4] |= (unsigned int)dataIn[i];
-    if ((++ctx->lenW) % 64 == 0) {
-      shaHashBlock(ctx);
-      ctx->lenW = 0;
-    }
-    ctx->sizeLo += 8;
-    ctx->sizeHi += (ctx->sizeLo < 8);
-  }
-}
-
-
-void moz_SHA1_Final(unsigned char hashout[20], moz_SHA_CTX *ctx) {
-  unsigned char pad0x80 = 0x80;
-  unsigned char pad0x00 = 0x00;
-  unsigned char padlen[8];
-  int i;
-
-  /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length
-   */
-  padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255);
-  padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255);
-  padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255);
-  padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255);
-  padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255);
-  padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255);
-  padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255);
-  padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255);
-  moz_SHA1_Update(ctx, &pad0x80, 1);
-  while (ctx->lenW != 56)
-    moz_SHA1_Update(ctx, &pad0x00, 1);
-  moz_SHA1_Update(ctx, padlen, 8);
-
-  /* Output hash
-   */
-  for (i = 0; i < 20; i++) {
-    hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24);
-    ctx->H[i / 4] <<= 8;
-  }
-
-  /*
-   *  Re-initialize the context (also zeroizes contents)
-   */
-  moz_SHA1_Init(ctx);
-}
-
-
-#define SHA_ROT(X,n) (((X) << (n)) | ((X) >> (32-(n))))
-
-static void shaHashBlock(moz_SHA_CTX *ctx) {
-  int t;
-  unsigned int A,B,C,D,E,TEMP;
-
-  for (t = 16; t <= 79; t++)
-    ctx->W[t] =
-      SHA_ROT(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1);
-
-  A = ctx->H[0];
-  B = ctx->H[1];
-  C = ctx->H[2];
-  D = ctx->H[3];
-  E = ctx->H[4];
-
-  for (t = 0; t <= 19; t++) {
-    TEMP = SHA_ROT(A,5) + (((C^D)&B)^D)     + E + ctx->W[t] + 0x5a827999;
-    E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP;
-  }
-  for (t = 20; t <= 39; t++) {
-    TEMP = SHA_ROT(A,5) + (B^C^D)           + E + ctx->W[t] + 0x6ed9eba1;
-    E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP;
-  }
-  for (t = 40; t <= 59; t++) {
-    TEMP = SHA_ROT(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdc;
-    E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP;
-  }
-  for (t = 60; t <= 79; t++) {
-    TEMP = SHA_ROT(A,5) + (B^C^D)           + E + ctx->W[t] + 0xca62c1d6;
-    E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP;
-  }
-
-  ctx->H[0] += A;
-  ctx->H[1] += B;
-  ctx->H[2] += C;
-  ctx->H[3] += D;
-  ctx->H[4] += E;
-}
diff --git a/mozilla-sha1/sha1.h b/mozilla-sha1/sha1.h
deleted file mode 100644
index aa48a46..0000000
--- a/mozilla-sha1/sha1.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is SHA 180-1 Header File
- *
- * The Initial Developer of the Original Code is Paul Kocher of
- * Cryptography Research.  Portions created by Paul Kocher are
- * Copyright (C) 1995-9 by Cryptography Research, Inc.  All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- *     Paul Kocher
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above.  If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL.  If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-typedef struct {
-  unsigned int H[5];
-  unsigned int W[80];
-  int lenW;
-  unsigned int sizeHi,sizeLo;
-} moz_SHA_CTX;
-
-void moz_SHA1_Init(moz_SHA_CTX *ctx);
-void moz_SHA1_Update(moz_SHA_CTX *ctx, const void *dataIn, int len);
-void moz_SHA1_Final(unsigned char hashout[20], moz_SHA_CTX *ctx);
-
-#define git_SHA_CTX	moz_SHA_CTX
-#define git_SHA1_Init	moz_SHA1_Init
-#define git_SHA1_Update	moz_SHA1_Update
-#define git_SHA1_Final	moz_SHA1_Final
diff --git a/pretty.c b/pretty.c
index 3b2ecdd..f5983f8 100644
--- a/pretty.c
+++ b/pretty.c
@@ -583,7 +583,7 @@
 	struct name_decoration *d;
 	const char *prefix = " (";
 
-	load_ref_decorations();
+	load_ref_decorations(DECORATE_SHORT_REFS);
 	d = lookup_decoration(&name_decoration, &commit->object);
 	while (d) {
 		strbuf_addstr(sb, prefix);
diff --git a/read-cache.c b/read-cache.c
index 4e3e272..1bbaf1c 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1065,7 +1065,18 @@
 	return updated;
 }
 
-int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec, char *seen)
+static void show_file(const char * fmt, const char * name, int in_porcelain,
+		      int * first, char *header_msg)
+{
+	if (in_porcelain && *first && header_msg) {
+		printf("%s\n", header_msg);
+		*first=0;
+	}
+	printf(fmt, name);
+}
+
+int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec,
+		  char *seen, char *header_msg)
 {
 	int i;
 	int has_errors = 0;
@@ -1074,11 +1085,14 @@
 	int quiet = (flags & REFRESH_QUIET) != 0;
 	int not_new = (flags & REFRESH_IGNORE_MISSING) != 0;
 	int ignore_submodules = (flags & REFRESH_IGNORE_SUBMODULES) != 0;
+	int first = 1;
+	int in_porcelain = (flags & REFRESH_IN_PORCELAIN);
 	unsigned int options = really ? CE_MATCH_IGNORE_VALID : 0;
-	const char *needs_update_message;
+	const char *needs_update_fmt;
+	const char *needs_merge_fmt;
 
-	needs_update_message = ((flags & REFRESH_SAY_CHANGED)
-				? "locally modified" : "needs update");
+	needs_update_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n");
+	needs_merge_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n");
 	for (i = 0; i < istate->cache_nr; i++) {
 		struct cache_entry *ce, *new;
 		int cache_errno = 0;
@@ -1094,7 +1108,7 @@
 			i--;
 			if (allow_unmerged)
 				continue;
-			printf("%s: needs merge\n", ce->name);
+			show_file(needs_merge_fmt, ce->name, in_porcelain, &first, header_msg);
 			has_errors = 1;
 			continue;
 		}
@@ -1117,7 +1131,7 @@
 			}
 			if (quiet)
 				continue;
-			printf("%s: %s\n", ce->name, needs_update_message);
+			show_file(needs_update_fmt, ce->name, in_porcelain, &first, header_msg);
 			has_errors = 1;
 			continue;
 		}
diff --git a/revision.c b/revision.c
index 9f5dac5..35eca4a 100644
--- a/revision.c
+++ b/revision.c
@@ -1052,7 +1052,7 @@
 		revs->simplify_by_decoration = 1;
 		revs->limited = 1;
 		revs->prune = 1;
-		load_ref_decorations();
+		load_ref_decorations(DECORATE_SHORT_REFS);
 	} else if (!strcmp(arg, "--date-order")) {
 		revs->lifo = 0;
 		revs->topo_order = 1;
@@ -1664,7 +1664,7 @@
 	return (revs->rewrite_parents || revs->children.name);
 }
 
-enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
+enum commit_action get_commit_action(struct rev_info *revs, struct commit *commit)
 {
 	if (commit->object.flags & SHOWN)
 		return commit_ignore;
@@ -1692,12 +1692,23 @@
 			if (!commit->parents || !commit->parents->next)
 				return commit_ignore;
 		}
-		if (want_ancestry(revs) && rewrite_parents(revs, commit) < 0)
-			return commit_error;
 	}
 	return commit_show;
 }
 
+enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
+{
+	enum commit_action action = get_commit_action(revs, commit);
+
+	if (action == commit_show &&
+	    !revs->show_all &&
+	    revs->prune && revs->dense && want_ancestry(revs)) {
+		if (rewrite_parents(revs, commit) < 0)
+			return commit_error;
+	}
+	return action;
+}
+
 static struct commit *get_revision_1(struct rev_info *revs)
 {
 	if (!revs->commits)
diff --git a/revision.h b/revision.h
index fb74492..9d0dddb 100644
--- a/revision.h
+++ b/revision.h
@@ -15,6 +15,9 @@
 #define SYMMETRIC_LEFT	(1u<<8)
 #define ALL_REV_FLAGS	((1u<<9)-1)
 
+#define DECORATE_SHORT_REFS	1
+#define DECORATE_FULL_REFS	2
+
 struct rev_info;
 struct log_info;
 
@@ -165,6 +168,7 @@
 	commit_error
 };
 
+extern enum commit_action get_commit_action(struct rev_info *revs, struct commit *commit);
 extern enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit);
 
 #endif
diff --git a/t/gitweb-lib.sh b/t/gitweb-lib.sh
new file mode 100644
index 0000000..8452532
--- /dev/null
+++ b/t/gitweb-lib.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Jakub Narebski
+#
+
+gitweb_init () {
+	safe_pwd="$(perl -MPOSIX=getcwd -e 'print quotemeta(getcwd)')"
+	cat >gitweb_config.perl <<EOF
+#!/usr/bin/perl
+
+# gitweb configuration for tests
+
+our \$version = 'current';
+our \$GIT = 'git';
+our \$projectroot = "$safe_pwd";
+our \$project_maxdepth = 8;
+our \$home_link_str = 'projects';
+our \$site_name = '[localhost]';
+our \$site_header = '';
+our \$site_footer = '';
+our \$home_text = 'indextext.html';
+our @stylesheets = ('file:///$TEST_DIRECTORY/../gitweb/gitweb.css');
+our \$logo = 'file:///$TEST_DIRECTORY/../gitweb/git-logo.png';
+our \$favicon = 'file:///$TEST_DIRECTORY/../gitweb/git-favicon.png';
+our \$projects_list = '';
+our \$export_ok = '';
+our \$strict_export = '';
+
+EOF
+
+	cat >.git/description <<EOF
+$0 test repository
+EOF
+}
+
+gitweb_run () {
+	GATEWAY_INTERFACE='CGI/1.1'
+	HTTP_ACCEPT='*/*'
+	REQUEST_METHOD='GET'
+	SCRIPT_NAME="$TEST_DIRECTORY/../gitweb/gitweb.perl"
+	QUERY_STRING=""$1""
+	PATH_INFO=""$2""
+	export GATEWAY_INTERFACE HTTP_ACCEPT REQUEST_METHOD \
+		SCRIPT_NAME QUERY_STRING PATH_INFO
+
+	GITWEB_CONFIG=$(pwd)/gitweb_config.perl
+	export GITWEB_CONFIG
+
+	# some of git commands write to STDERR on error, but this is not
+	# written to web server logs, so we are not interested in that:
+	# we are interested only in properly formatted errors/warnings
+	rm -f gitweb.log &&
+	perl -- "$SCRIPT_NAME" \
+		>gitweb.output 2>gitweb.log &&
+	if grep '^[[]' gitweb.log >/dev/null 2>&1; then false; else true; fi
+
+	# gitweb.log is left for debugging
+	# gitweb.output is used to parse http output
+}
+
+. ./test-lib.sh
+
+if ! test_have_prereq PERL; then
+	say 'skipping gitweb tests, perl not available'
+	test_done
+fi
+
+perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || {
+    say 'skipping gitweb tests, perl version is too old'
+    test_done
+}
+
+gitweb_init
diff --git a/t/t1009-read-tree-new-index.sh b/t/t1009-read-tree-new-index.sh
new file mode 100755
index 0000000..59b3aa4
--- /dev/null
+++ b/t/t1009-read-tree-new-index.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+test_description='test read-tree into a fresh index file'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+	echo one >a &&
+	git add a &&
+	git commit -m initial
+'
+
+test_expect_success 'non-existent index file' '
+	rm -f new-index &&
+	GIT_INDEX_FILE=new-index git read-tree master
+'
+
+test_expect_success 'empty index file' '
+	rm -f new-index &&
+	> new-index &&
+	GIT_INDEX_FILE=new-index git read-tree master
+'
+
+test_done
+
diff --git a/t/t2000-checkout-cache-clash.sh b/t/t2000-checkout-cache-clash.sh
index f7e1a73..de3edb5 100755
--- a/t/t2000-checkout-cache-clash.sh
+++ b/t/t2000-checkout-cache-clash.sh
@@ -48,4 +48,13 @@
     'git checkout-index conflicting paths.' \
     'test -f path0 && test -d path1 && test -f path1/file1'
 
+test_expect_success SYMLINKS 'checkout-index -f twice with --prefix' '
+	mkdir -p tar/get &&
+	ln -s tar/get there &&
+	echo first &&
+	git checkout-index -a -f --prefix=there/ &&
+	echo second &&
+	git checkout-index -a -f --prefix=there/
+'
+
 test_done
diff --git a/t/t2015-checkout-unborn.sh b/t/t2015-checkout-unborn.sh
new file mode 100755
index 0000000..c551d39
--- /dev/null
+++ b/t/t2015-checkout-unborn.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+test_description='checkout from unborn branch protects contents'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	mkdir parent &&
+	(cd parent &&
+	 git init &&
+	 echo content >file &&
+	 git add file &&
+	 git commit -m base
+	) &&
+	git fetch parent master:origin
+'
+
+test_expect_success 'checkout from unborn preserves untracked files' '
+	echo precious >expect &&
+	echo precious >file &&
+	test_must_fail git checkout -b new origin &&
+	test_cmp expect file
+'
+
+test_expect_success 'checkout from unborn preserves index contents' '
+	echo precious >expect &&
+	echo precious >file &&
+	git add file &&
+	test_must_fail git checkout -b new origin &&
+	test_cmp expect file &&
+	git show :file >file &&
+	test_cmp expect file
+'
+
+test_expect_success 'checkout from unborn merges identical index contents' '
+	echo content >file &&
+	git add file &&
+	git checkout -b new origin
+'
+
+test_done
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 8b33321..8e3694e 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -207,6 +207,7 @@
 log -SF master
 log -SF -p master
 log --decorate --all
+log --decorate=full --all
 
 rev-list --parents HEAD
 rev-list --children HEAD
diff --git a/t/t4013/diff.log_--decorate=full_--all b/t/t4013/diff.log_--decorate=full_--all
new file mode 100644
index 0000000..903d9d9
--- /dev/null
+++ b/t/t4013/diff.log_--decorate=full_--all
@@ -0,0 +1,34 @@
+$ git log --decorate=full --all
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (refs/heads/master)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (refs/heads/side)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:03:00 2006 +0000
+
+    Side
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a (refs/heads/initial)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
diff --git a/t/t4039-diff-assume-unchanged.sh b/t/t4039-diff-assume-unchanged.sh
new file mode 100755
index 0000000..9d9498b
--- /dev/null
+++ b/t/t4039-diff-assume-unchanged.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+test_description='diff with assume-unchanged entries'
+
+. ./test-lib.sh
+
+# external diff has been tested in t4020-diff-external.sh
+
+test_expect_success 'setup' '
+	echo zero > zero &&
+	git add zero &&
+	git commit -m zero &&
+	echo one > one &&
+	echo two > two &&
+	git add one two &&
+	git commit -m onetwo &&
+	git update-index --assume-unchanged one &&
+	echo borked >> one &&
+	test "$(git ls-files -v one)" = "h one"
+'
+
+test_expect_success 'diff-index does not examine assume-unchanged entries' '
+	git diff-index HEAD^ -- one | grep -q 5626abf0f72e58d7a153368ba57db4c673c0e171
+'
+
+test_expect_success 'diff-files does not examine assume-unchanged entries' '
+	rm one &&
+	test -z "$(git diff-files -- one)"
+'
+
+test_done
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index a8c2ca2..18376d6 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -139,6 +139,36 @@
 	)
 '
 
+test_expect_success 'simple fetch in shallow repo' '
+	(
+		cd shallow &&
+		git fetch
+	)
+'
+
+test_expect_success 'no changes expected' '
+	(
+		cd shallow &&
+		git count-objects -v
+	) > count.shallow.2 &&
+	cmp count.shallow count.shallow.2
+'
+
+test_expect_success 'fetch same depth in shallow repo' '
+	(
+		cd shallow &&
+		git fetch --depth=2
+	)
+'
+
+test_expect_success 'no changes expected' '
+	(
+		cd shallow &&
+		git count-objects -v
+	) > count.shallow.3 &&
+	cmp count.shallow count.shallow.3
+'
+
 test_expect_success 'add two more' '
 	add B66 $B65 &&
 	add B67 $B66
@@ -201,4 +231,21 @@
 	)
 '
 
+test_expect_success 'additional simple shallow deepenings' '
+	(
+		cd shallow &&
+		git fetch --depth=8 &&
+		git fetch --depth=10 &&
+		git fetch --depth=11
+	)
+'
+
+test_expect_success 'clone shallow object count' '
+	(
+		cd shallow &&
+		git count-objects -v
+	) > count.shallow &&
+	grep "^count: 52" count.shallow
+'
+
 test_done
diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh
new file mode 100644
index 0000000..65d8d47
--- /dev/null
+++ b/t/t5531-deep-submodule-push.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+test_description='unpack-objects'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+	mkdir pub.git &&
+	GIT_DIR=pub.git git init --bare
+	GIT_DIR=pub.git git config receive.fsckobjects true &&
+	mkdir work &&
+	(
+		cd work &&
+		git init &&
+		mkdir -p gar/bage &&
+		(
+			cd gar/bage &&
+			git init &&
+			>junk &&
+			git add junk &&
+			git commit -m "Initial junk"
+		) &&
+		git add gar/bage &&
+		git commit -m "Initial superproject"
+	)
+'
+
+test_expect_success push '
+	(
+		cd work &&
+		git push ../pub.git master
+	)
+'
+
+test_done
diff --git a/t/t6015-rev-list-show-all-parents.sh b/t/t6015-rev-list-show-all-parents.sh
new file mode 100755
index 0000000..8b146fb
--- /dev/null
+++ b/t/t6015-rev-list-show-all-parents.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+test_description='--show-all --parents does not rewrite TREESAME commits'
+
+. ./test-lib.sh
+
+test_expect_success 'set up --show-all --parents test' '
+	test_commit one foo.txt &&
+	commit1=`git rev-list -1 HEAD` &&
+	test_commit two bar.txt &&
+	commit2=`git rev-list -1 HEAD` &&
+	test_commit three foo.txt &&
+	commit3=`git rev-list -1 HEAD`
+	'
+
+test_expect_success '--parents rewrites TREESAME parents correctly' '
+	echo $commit3 $commit1 > expected &&
+	echo $commit1 >> expected &&
+	git rev-list --parents HEAD -- foo.txt > actual &&
+	test_cmp expected actual
+	'
+
+test_expect_success '--parents --show-all does not rewrites TREESAME parents' '
+	echo $commit3 $commit2 > expected &&
+	echo $commit2 $commit1 >> expected &&
+	echo $commit1 >> expected &&
+	git rev-list --parents --show-all HEAD -- foo.txt > actual &&
+	test_cmp expected actual
+	'
+
+test_done
diff --git a/t/t6016-rev-list-graph-simplify-history.sh b/t/t6016-rev-list-graph-simplify-history.sh
new file mode 100755
index 0000000..27fd52b
--- /dev/null
+++ b/t/t6016-rev-list-graph-simplify-history.sh
@@ -0,0 +1,276 @@
+#!/bin/sh
+
+# There's more than one "correct" way to represent the history graphically.
+# These tests depend on the current behavior of the graphing code.  If the
+# graphing code is ever changed to draw the output differently, these tests
+# cases will need to be updated to know about the new layout.
+
+test_description='--graph and simplified history'
+
+. ./test-lib.sh
+
+test_expect_success 'set up rev-list --graph test' '
+	# 3 commits on branch A
+	test_commit A1 foo.txt &&
+	test_commit A2 bar.txt &&
+	test_commit A3 bar.txt &&
+	git branch -m master A &&
+
+	# 2 commits on branch B, started from A1
+	git checkout -b B A1 &&
+	test_commit B1 foo.txt &&
+	test_commit B2 abc.txt &&
+
+	# 2 commits on branch C, started from A2
+	git checkout -b C A2 &&
+	test_commit C1 xyz.txt &&
+	test_commit C2 xyz.txt &&
+
+	# Octopus merge B and C into branch A
+	git checkout A &&
+	git merge B C &&
+	git tag A4
+
+	test_commit A5 bar.txt &&
+
+	# More commits on C, then merge C into A
+	git checkout C &&
+	test_commit C3 foo.txt &&
+	test_commit C4 bar.txt &&
+	git checkout A &&
+	git merge -s ours C &&
+	git tag A6
+
+	test_commit A7 bar.txt &&
+
+	# Store commit names in variables for later use
+	A1=$(git rev-parse --verify A1) &&
+	A2=$(git rev-parse --verify A2) &&
+	A3=$(git rev-parse --verify A3) &&
+	A4=$(git rev-parse --verify A4) &&
+	A5=$(git rev-parse --verify A5) &&
+	A6=$(git rev-parse --verify A6) &&
+	A7=$(git rev-parse --verify A7) &&
+	B1=$(git rev-parse --verify B1) &&
+	B2=$(git rev-parse --verify B2) &&
+	C1=$(git rev-parse --verify C1) &&
+	C2=$(git rev-parse --verify C2) &&
+	C3=$(git rev-parse --verify C3) &&
+	C4=$(git rev-parse --verify C4)
+	'
+
+test_expect_success '--graph --all' '
+	rm -f expected &&
+	echo "* $A7" >> expected &&
+	echo "*   $A6" >> expected &&
+	echo "|\\  " >> expected &&
+	echo "| * $C4" >> expected &&
+	echo "| * $C3" >> expected &&
+	echo "* | $A5" >> expected &&
+	echo "| |     " >> expected &&
+	echo "|  \\    " >> expected &&
+	echo "*-. \\   $A4" >> expected &&
+	echo "|\\ \\ \\  " >> expected &&
+	echo "| | |/  " >> expected &&
+	echo "| | * $C2" >> expected &&
+	echo "| | * $C1" >> expected &&
+	echo "| * | $B2" >> expected &&
+	echo "| * | $B1" >> expected &&
+	echo "* | | $A3" >> expected &&
+	echo "| |/  " >> expected &&
+	echo "|/|   " >> expected &&
+	echo "* | $A2" >> expected &&
+	echo "|/  " >> expected &&
+	echo "* $A1" >> expected &&
+	git rev-list --graph --all > actual &&
+	test_cmp expected actual
+	'
+
+# Make sure the graph_is_interesting() code still realizes
+# that undecorated merges are interesting, even with --simplify-by-decoration
+test_expect_success '--graph --simplify-by-decoration' '
+	rm -f expected &&
+	git tag -d A4
+	echo "* $A7" >> expected &&
+	echo "*   $A6" >> expected &&
+	echo "|\\  " >> expected &&
+	echo "| * $C4" >> expected &&
+	echo "| * $C3" >> expected &&
+	echo "* | $A5" >> expected &&
+	echo "| |     " >> expected &&
+	echo "|  \\    " >> expected &&
+	echo "*-. \\   $A4" >> expected &&
+	echo "|\\ \\ \\  " >> expected &&
+	echo "| | |/  " >> expected &&
+	echo "| | * $C2" >> expected &&
+	echo "| | * $C1" >> expected &&
+	echo "| * | $B2" >> expected &&
+	echo "| * | $B1" >> expected &&
+	echo "* | | $A3" >> expected &&
+	echo "| |/  " >> expected &&
+	echo "|/|   " >> expected &&
+	echo "* | $A2" >> expected &&
+	echo "|/  " >> expected &&
+	echo "* $A1" >> expected &&
+	git rev-list --graph --all --simplify-by-decoration > actual &&
+	test_cmp expected actual
+	'
+
+# Get rid of all decorations on branch B, and graph with it simplified away
+test_expect_success '--graph --simplify-by-decoration prune branch B' '
+	rm -f expected &&
+	git tag -d B2
+	git tag -d B1
+	git branch -d B
+	echo "* $A7" >> expected &&
+	echo "*   $A6" >> expected &&
+	echo "|\\  " >> expected &&
+	echo "| * $C4" >> expected &&
+	echo "| * $C3" >> expected &&
+	echo "* | $A5" >> expected &&
+	echo "* |   $A4" >> expected &&
+	echo "|\\ \\  " >> expected &&
+	echo "| |/  " >> expected &&
+	echo "| * $C2" >> expected &&
+	echo "| * $C1" >> expected &&
+	echo "* | $A3" >> expected &&
+	echo "|/  " >> expected &&
+	echo "* $A2" >> expected &&
+	echo "* $A1" >> expected &&
+	git rev-list --graph --simplify-by-decoration --all > actual &&
+	test_cmp expected actual
+	'
+
+test_expect_success '--graph --full-history -- bar.txt' '
+	rm -f expected &&
+	git tag -d B2
+	git tag -d B1
+	git branch -d B
+	echo "* $A7" >> expected &&
+	echo "*   $A6" >> expected &&
+	echo "|\\  " >> expected &&
+	echo "| * $C4" >> expected &&
+	echo "* | $A5" >> expected &&
+	echo "* |   $A4" >> expected &&
+	echo "|\\ \\  " >> expected &&
+	echo "| |/  " >> expected &&
+	echo "* | $A3" >> expected &&
+	echo "|/  " >> expected &&
+	echo "* $A2" >> expected &&
+	git rev-list --graph --full-history --all -- bar.txt > actual &&
+	test_cmp expected actual
+	'
+
+test_expect_success '--graph --full-history --simplify-merges -- bar.txt' '
+	rm -f expected &&
+	git tag -d B2
+	git tag -d B1
+	git branch -d B
+	echo "* $A7" >> expected &&
+	echo "*   $A6" >> expected &&
+	echo "|\\  " >> expected &&
+	echo "| * $C4" >> expected &&
+	echo "* | $A5" >> expected &&
+	echo "* | $A3" >> expected &&
+	echo "|/  " >> expected &&
+	echo "* $A2" >> expected &&
+	git rev-list --graph --full-history --simplify-merges --all \
+		-- bar.txt > actual &&
+	test_cmp expected actual
+	'
+
+test_expect_success '--graph -- bar.txt' '
+	rm -f expected &&
+	git tag -d B2
+	git tag -d B1
+	git branch -d B
+	echo "* $A7" >> expected &&
+	echo "* $A5" >> expected &&
+	echo "* $A3" >> expected &&
+	echo "| * $C4" >> expected &&
+	echo "|/  " >> expected &&
+	echo "* $A2" >> expected &&
+	git rev-list --graph --all -- bar.txt > actual &&
+	test_cmp expected actual
+	'
+
+test_expect_success '--graph --sparse -- bar.txt' '
+	rm -f expected &&
+	git tag -d B2
+	git tag -d B1
+	git branch -d B
+	echo "* $A7" >> expected &&
+	echo "* $A6" >> expected &&
+	echo "* $A5" >> expected &&
+	echo "* $A4" >> expected &&
+	echo "* $A3" >> expected &&
+	echo "| * $C4" >> expected &&
+	echo "| * $C3" >> expected &&
+	echo "| * $C2" >> expected &&
+	echo "| * $C1" >> expected &&
+	echo "|/  " >> expected &&
+	echo "* $A2" >> expected &&
+	echo "* $A1" >> expected &&
+	git rev-list --graph --sparse --all -- bar.txt > actual &&
+	test_cmp expected actual
+	'
+
+test_expect_success '--graph ^C4' '
+	rm -f expected &&
+	echo "* $A7" >> expected &&
+	echo "* $A6" >> expected &&
+	echo "* $A5" >> expected &&
+	echo "*   $A4" >> expected &&
+	echo "|\\  " >> expected &&
+	echo "| * $B2" >> expected &&
+	echo "| * $B1" >> expected &&
+	echo "* $A3" >> expected &&
+	git rev-list --graph --all ^C4 > actual &&
+	test_cmp expected actual
+	'
+
+test_expect_success '--graph ^C3' '
+	rm -f expected &&
+	echo "* $A7" >> expected &&
+	echo "*   $A6" >> expected &&
+	echo "|\\  " >> expected &&
+	echo "| * $C4" >> expected &&
+	echo "* $A5" >> expected &&
+	echo "*   $A4" >> expected &&
+	echo "|\\  " >> expected &&
+	echo "| * $B2" >> expected &&
+	echo "| * $B1" >> expected &&
+	echo "* $A3" >> expected &&
+	git rev-list --graph --all ^C3 > actual &&
+	test_cmp expected actual
+	'
+
+# I don't think the ordering of the boundary commits is really
+# that important, but this test depends on it.  If the ordering ever changes
+# in the code, we'll need to update this test.
+test_expect_success '--graph --boundary ^C3' '
+	rm -f expected &&
+	echo "* $A7" >> expected &&
+	echo "*   $A6" >> expected &&
+	echo "|\\  " >> expected &&
+	echo "| * $C4" >> expected &&
+	echo "* | $A5" >> expected &&
+	echo "| |     " >> expected &&
+	echo "|  \\    " >> expected &&
+	echo "*-. \\   $A4" >> expected &&
+	echo "|\\ \\ \\  " >> expected &&
+	echo "| * | | $B2" >> expected &&
+	echo "| * | | $B1" >> expected &&
+	echo "* | | | $A3" >> expected &&
+	echo "o | | | $A2" >> expected &&
+	echo "|/ / /  " >> expected &&
+	echo "o | | $A1" >> expected &&
+	echo " / /  " >> expected &&
+	echo "| o $C3" >> expected &&
+	echo "|/  " >> expected &&
+	echo "o $C2" >> expected &&
+	git rev-list --graph --boundary --all ^C3 > actual &&
+	test_cmp expected actual
+	'
+
+test_done
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 1315bab..def397c 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -175,7 +175,7 @@
 	git bisect start $HASH4 $HASH1 &&
 	git bisect skip &&
 	git bisect bad > my_bisect_log.txt &&
-	grep "$HASH2 is first bad commit" my_bisect_log.txt &&
+	grep "$HASH2 is the first bad commit" my_bisect_log.txt &&
 	git bisect reset
 '
 
@@ -261,7 +261,7 @@
      git bisect good $HASH1 &&
      git bisect bad $HASH4 &&
      git bisect run ./test_script.sh > my_bisect_log.txt &&
-     grep "$HASH3 is first bad commit" my_bisect_log.txt &&
+     grep "$HASH3 is the first bad commit" my_bisect_log.txt &&
      git bisect reset'
 
 # We want to automatically find the commit that
@@ -274,7 +274,7 @@
      chmod +x test_script.sh &&
      git bisect start $HASH4 $HASH1 &&
      git bisect run ./test_script.sh > my_bisect_log.txt &&
-     grep "$HASH4 is first bad commit" my_bisect_log.txt &&
+     grep "$HASH4 is the first bad commit" my_bisect_log.txt &&
      git bisect reset'
 
 # $HASH1 is good, $HASH5 is bad, we skip $HASH3
@@ -287,14 +287,14 @@
 	git bisect start $HASH5 $HASH1 &&
 	git bisect skip &&
 	git bisect good > my_bisect_log.txt &&
-	grep "$HASH5 is first bad commit" my_bisect_log.txt &&
+	grep "$HASH5 is the first bad commit" my_bisect_log.txt &&
 	git bisect log > log_to_replay.txt &&
 	git bisect reset
 '
 
 test_expect_success 'bisect skip and bisect replay' '
 	git bisect replay log_to_replay.txt > my_bisect_log.txt &&
-	grep "$HASH5 is first bad commit" my_bisect_log.txt &&
+	grep "$HASH5 is the first bad commit" my_bisect_log.txt &&
 	git bisect reset
 '
 
@@ -335,7 +335,7 @@
 	chmod +x test_script.sh &&
 	git bisect start $HASH7 $HASH1 &&
 	git bisect run ./test_script.sh > my_bisect_log.txt &&
-	grep "$HASH6 is first bad commit" my_bisect_log.txt
+	grep "$HASH6 is the first bad commit" my_bisect_log.txt
 '
 
 test_expect_success 'bisect skip only one range' '
@@ -385,7 +385,7 @@
 	rev_hash6=$(git rev-parse --verify HEAD) &&
 	test "$rev_hash6" = "$HASH6" &&
 	git bisect good > my_bisect_log.txt &&
-	grep "$HASH7 is first bad commit" my_bisect_log.txt &&
+	grep "$HASH7 is the first bad commit" my_bisect_log.txt &&
 	git bisect reset &&
 	rev_hash6=$(git rev-parse --verify bisect) &&
 	test "$rev_hash6" = "$HASH6" &&
@@ -534,7 +534,7 @@
 	para1=$(git rev-parse --verify HEAD) &&
 	test "$para1" = "$PARA_HASH1" &&
 	git bisect bad > my_bisect_log.txt &&
-	grep "$PARA_HASH1 is first bad commit" my_bisect_log.txt
+	grep "$PARA_HASH1 is the first bad commit" my_bisect_log.txt
 '
 
 test_expect_success 'restricting bisection on one dir and a file' '
@@ -552,7 +552,7 @@
 	para1=$(git rev-parse --verify HEAD) &&
 	test "$para1" = "$PARA_HASH1" &&
 	git bisect good > my_bisect_log.txt &&
-	grep "$PARA_HASH4 is first bad commit" my_bisect_log.txt
+	grep "$PARA_HASH4 is the first bad commit" my_bisect_log.txt
 '
 
 test_expect_success 'skipping away from skipped commit' '
diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh
new file mode 100755
index 0000000..1044aa6
--- /dev/null
+++ b/t/t7060-wtstatus.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+test_description='basic work tree status reporting'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+	test_commit A &&
+	test_commit B oneside added &&
+	git checkout A^0 &&
+	test_commit C oneside created
+'
+
+test_expect_success 'A/A conflict' '
+	git checkout B^0 &&
+	test_must_fail git merge C
+'
+
+test_expect_success 'Report path with conflict' '
+	git diff --cached --name-status >actual &&
+	echo "U	oneside" >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'Report new path with conflict' '
+	git diff --cached --name-status HEAD^ >actual &&
+	echo "U	oneside" >expect &&
+	test_cmp expect actual
+'
+
+cat >expect <<EOF
+# On branch side
+# Unmerged paths:
+#   (use "git reset HEAD <file>..." to unstage)
+#   (use "git add <file>..." to mark resolution)
+#
+#	deleted by us:      foo
+#
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
+
+test_expect_success 'M/D conflict does not segfault' '
+	mkdir mdconflict &&
+	(
+		cd mdconflict &&
+		git init &&
+		test_commit initial foo "" &&
+		test_commit modify foo foo &&
+		git checkout -b side HEAD^ &&
+		git rm foo &&
+		git commit -m delete &&
+		test_must_fail git merge master &&
+		test_must_fail git status > ../actual
+	) &&
+	test_cmp expect actual
+'
+
+test_done
diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh
index e637c7d..e85ff02 100755
--- a/t/t7102-reset.sh
+++ b/t/t7102-reset.sh
@@ -419,7 +419,8 @@
 '
 
 cat > expect << EOF
-file2: locally modified
+Unstaged changes after reset:
+M	file2
 EOF
 
 test_expect_success '--mixed refreshes the index' '
diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh
index 6149829..6cc16c3 100755
--- a/t/t7401-submodule-summary.sh
+++ b/t/t7401-submodule-summary.sh
@@ -56,6 +56,15 @@
 EOF
 "
 
+test_expect_success 'modified submodule(forward), --files' "
+	git submodule summary --files >actual &&
+	diff actual - <<-EOF
+* sm1 $head1...$head2 (1):
+  > Add foo3
+
+EOF
+"
+
 commit_file sm1 &&
 cd sm1 &&
 git reset --hard HEAD~2 >/dev/null &&
@@ -114,6 +123,15 @@
 EOF
 "
 
+test_expect_success 'typechanged submodule(submodule->blob), --files' "
+    git submodule summary --files >actual &&
+    diff actual - <<-EOF
+* sm1 $head5(blob)->$head4(submodule) (3):
+  > Add foo5
+
+EOF
+"
+
 rm -rf sm1 &&
 git checkout-index sm1
 test_expect_success 'typechanged submodule(submodule->blob)' "
@@ -205,4 +223,8 @@
 EOF
 "
 
+test_expect_success 'fail when using --files together with --cached' "
+    test_must_fail git submodule summary --files --cached
+"
+
 test_done
diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
new file mode 100755
index 0000000..2a52775
--- /dev/null
+++ b/t/t7407-submodule-foreach.sh
@@ -0,0 +1,237 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Johan Herland
+#
+
+test_description='Test "git submodule foreach"
+
+This test verifies that "git submodule foreach" correctly visits all submodules
+that are currently checked out.
+'
+
+. ./test-lib.sh
+
+
+test_expect_success 'setup a submodule tree' '
+	echo file > file &&
+	git add file &&
+	test_tick &&
+	git commit -m upstream
+	git clone . super &&
+	git clone super submodule &&
+	(
+		cd super &&
+		git submodule add ../submodule sub1 &&
+		git submodule add ../submodule sub2 &&
+		git submodule add ../submodule sub3 &&
+		git config -f .gitmodules --rename-section \
+			submodule.sub1 submodule.foo1 &&
+		git config -f .gitmodules --rename-section \
+			submodule.sub2 submodule.foo2 &&
+		git config -f .gitmodules --rename-section \
+			submodule.sub3 submodule.foo3 &&
+		git add .gitmodules
+		test_tick &&
+		git commit -m "submodules" &&
+		git submodule init sub1 &&
+		git submodule init sub2 &&
+		git submodule init sub3
+	) &&
+	(
+		cd submodule &&
+		echo different > file &&
+		git add file &&
+		test_tick &&
+		git commit -m "different"
+	) &&
+	(
+		cd super &&
+		(
+			cd sub3 &&
+			git pull
+		) &&
+		git add sub3 &&
+		test_tick &&
+		git commit -m "update sub3"
+	)
+'
+
+sub1sha1=$(cd super/sub1 && git rev-parse HEAD)
+sub3sha1=$(cd super/sub3 && git rev-parse HEAD)
+
+cat > expect <<EOF
+Entering 'sub1'
+foo1-sub1-$sub1sha1
+Entering 'sub3'
+foo3-sub3-$sub3sha1
+EOF
+
+test_expect_success 'test basic "submodule foreach" usage' '
+	git clone super clone &&
+	(
+		cd clone &&
+		git submodule update --init -- sub1 sub3 &&
+		git submodule foreach "echo \$name-\$path-\$sha1" > ../actual
+	) &&
+	test_cmp expect actual
+'
+
+test_expect_success 'setup nested submodules' '
+	git clone submodule nested1 &&
+	git clone submodule nested2 &&
+	git clone submodule nested3 &&
+	(
+		cd nested3 &&
+		git submodule add ../submodule submodule &&
+		test_tick &&
+		git commit -m "submodule" &&
+		git submodule init submodule
+	) &&
+	(
+		cd nested2 &&
+		git submodule add ../nested3 nested3 &&
+		test_tick &&
+		git commit -m "nested3" &&
+		git submodule init nested3
+	) &&
+	(
+		cd nested1 &&
+		git submodule add ../nested2 nested2 &&
+		test_tick &&
+		git commit -m "nested2" &&
+		git submodule init nested2
+	) &&
+	(
+		cd super &&
+		git submodule add ../nested1 nested1 &&
+		test_tick &&
+		git commit -m "nested1" &&
+		git submodule init nested1
+	)
+'
+
+test_expect_success 'use "submodule foreach" to checkout 2nd level submodule' '
+	git clone super clone2 &&
+	(
+		cd clone2 &&
+		test ! -d sub1/.git &&
+		test ! -d sub2/.git &&
+		test ! -d sub3/.git &&
+		test ! -d nested1/.git &&
+		git submodule update --init &&
+		test -d sub1/.git &&
+		test -d sub2/.git &&
+		test -d sub3/.git &&
+		test -d nested1/.git &&
+		test ! -d nested1/nested2/.git &&
+		git submodule foreach "git submodule update --init" &&
+		test -d nested1/nested2/.git &&
+		test ! -d nested1/nested2/nested3/.git
+	)
+'
+
+test_expect_success 'use "foreach --recursive" to checkout all submodules' '
+	(
+		cd clone2 &&
+		git submodule foreach --recursive "git submodule update --init" &&
+		test -d nested1/nested2/nested3/.git &&
+		test -d nested1/nested2/nested3/submodule/.git
+	)
+'
+
+cat > expect <<EOF
+Entering 'nested1'
+Entering 'nested1/nested2'
+Entering 'nested1/nested2/nested3'
+Entering 'nested1/nested2/nested3/submodule'
+Entering 'sub1'
+Entering 'sub2'
+Entering 'sub3'
+EOF
+
+test_expect_success 'test messages from "foreach --recursive"' '
+	(
+		cd clone2 &&
+		git submodule foreach --recursive "true" > ../actual
+	) &&
+	test_cmp expect actual
+'
+
+cat > expect <<EOF
+nested1-nested1
+nested2-nested2
+nested3-nested3
+submodule-submodule
+foo1-sub1
+foo2-sub2
+foo3-sub3
+EOF
+
+test_expect_success 'test "foreach --quiet --recursive"' '
+	(
+		cd clone2 &&
+		git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
+	) &&
+	test_cmp expect actual
+'
+
+test_expect_success 'use "update --recursive" to checkout all submodules' '
+	git clone super clone3 &&
+	(
+		cd clone3 &&
+		test ! -d sub1/.git &&
+		test ! -d sub2/.git &&
+		test ! -d sub3/.git &&
+		test ! -d nested1/.git &&
+		git submodule update --init --recursive &&
+		test -d sub1/.git &&
+		test -d sub2/.git &&
+		test -d sub3/.git &&
+		test -d nested1/.git &&
+		test -d nested1/nested2/.git &&
+		test -d nested1/nested2/nested3/.git &&
+		test -d nested1/nested2/nested3/submodule/.git
+	)
+'
+
+nested1sha1=$(cd clone3/nested1 && git rev-parse HEAD)
+nested2sha1=$(cd clone3/nested1/nested2 && git rev-parse HEAD)
+nested3sha1=$(cd clone3/nested1/nested2/nested3 && git rev-parse HEAD)
+submodulesha1=$(cd clone3/nested1/nested2/nested3/submodule && git rev-parse HEAD)
+sub1sha1=$(cd clone3/sub1 && git rev-parse HEAD)
+sub2sha1=$(cd clone3/sub2 && git rev-parse HEAD)
+sub3sha1=$(cd clone3/sub3 && git rev-parse HEAD)
+sub1sha1_short=$(cd clone3/sub1 && git rev-parse --short HEAD)
+sub2sha1_short=$(cd clone3/sub2 && git rev-parse --short HEAD)
+
+cat > expect <<EOF
+ $nested1sha1 nested1 (heads/master)
+ $nested2sha1 nested1/nested2 (heads/master)
+ $nested3sha1 nested1/nested2/nested3 (heads/master)
+ $submodulesha1 nested1/nested2/nested3/submodule (heads/master)
+ $sub1sha1 sub1 ($sub1sha1_short)
+ $sub2sha1 sub2 ($sub2sha1_short)
+ $sub3sha1 sub3 (heads/master)
+EOF
+
+test_expect_success 'test "status --recursive"' '
+	(
+		cd clone3 &&
+		git submodule status --recursive > ../actual
+	) &&
+	test_cmp expect actual
+'
+
+test_expect_success 'use "git clone --recursive" to checkout all submodules' '
+	git clone --recursive super clone4 &&
+	test -d clone4/.git &&
+	test -d clone4/sub1/.git &&
+	test -d clone4/sub2/.git &&
+	test -d clone4/sub3/.git &&
+	test -d clone4/nested1/.git &&
+	test -d clone4/nested1/nested2/.git &&
+	test -d clone4/nested1/nested2/nested3/.git &&
+	test -d clone4/nested1/nested2/nested3/submodule/.git
+'
+
+test_done
diff --git a/t/t8005/iso8859-5.txt b/t/t8005/iso8859-5.txt
deleted file mode 100644
index 2e4b80c..0000000
--- a/t/t8005/iso8859-5.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-ISO8859_5_NAME="¸ÒÐÝ ¿ÕâàÞÒØç ÁØÔÞàÞÒ"
-ISO8859_5_MSG="ÂÕáâÞÒÞÕ áÞÞÑéÕÝØÕ"
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index 6275181..2fc7fdb 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -9,73 +9,8 @@
 commandline, and checks that it would not write any errors
 or warnings to log.'
 
-gitweb_init () {
-	safe_pwd="$(perl -MPOSIX=getcwd -e 'print quotemeta(getcwd)')"
-	cat >gitweb_config.perl <<EOF
-#!/usr/bin/perl
 
-# gitweb configuration for tests
-
-our \$version = "current";
-our \$GIT = "git";
-our \$projectroot = "$safe_pwd";
-our \$project_maxdepth = 8;
-our \$home_link_str = "projects";
-our \$site_name = "[localhost]";
-our \$site_header = "";
-our \$site_footer = "";
-our \$home_text = "indextext.html";
-our @stylesheets = ("file:///$TEST_DIRECTORY/../gitweb/gitweb.css");
-our \$logo = "file:///$TEST_DIRECTORY/../gitweb/git-logo.png";
-our \$favicon = "file:///$TEST_DIRECTORY/../gitweb/git-favicon.png";
-our \$projects_list = "";
-our \$export_ok = "";
-our \$strict_export = "";
-
-EOF
-
-	cat >.git/description <<EOF
-$0 test repository
-EOF
-}
-
-gitweb_run () {
-	GATEWAY_INTERFACE="CGI/1.1"
-	HTTP_ACCEPT="*/*"
-	REQUEST_METHOD="GET"
-	SCRIPT_NAME="$TEST_DIRECTORY/../gitweb/gitweb.perl"
-	QUERY_STRING=""$1""
-	PATH_INFO=""$2""
-	export GATEWAY_INTERFACE HTTP_ACCEPT REQUEST_METHOD \
-		SCRIPT_NAME QUERY_STRING PATH_INFO
-
-	GITWEB_CONFIG=$(pwd)/gitweb_config.perl
-	export GITWEB_CONFIG
-
-	# some of git commands write to STDERR on error, but this is not
-	# written to web server logs, so we are not interested in that:
-	# we are interested only in properly formatted errors/warnings
-	rm -f gitweb.log &&
-	perl -- "$SCRIPT_NAME" \
-		>/dev/null 2>gitweb.log &&
-	if grep "^[[]" gitweb.log >/dev/null 2>&1; then false; else true; fi
-
-	# gitweb.log is left for debugging
-}
-
-. ./test-lib.sh
-
-if ! test_have_prereq PERL; then
-	say 'skipping gitweb tests, perl not available'
-	test_done
-fi
-
-perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || {
-    say 'skipping gitweb tests, perl version is too old'
-    test_done
-}
-
-gitweb_init
+. ./gitweb-lib.sh
 
 # ----------------------------------------------------------------------
 # no commits (empty, just initialized repository)
diff --git a/t/t9501-gitweb-standalone-http-status.sh b/t/t9501-gitweb-standalone-http-status.sh
new file mode 100644
index 0000000..d0ff21d
--- /dev/null
+++ b/t/t9501-gitweb-standalone-http-status.sh
@@ -0,0 +1,78 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Mark Rada
+#
+
+test_description='gitweb as standalone script (http status tests).
+
+This test runs gitweb (git web interface) as a CGI script from the
+commandline, and checks that it returns the expected HTTP status
+code and message.'
+
+
+. ./gitweb-lib.sh
+
+# ----------------------------------------------------------------------
+# snapshot settings
+
+test_commit \
+	'SnapshotTests' \
+	'i can has snapshot?'
+
+cat >>gitweb_config.perl <<\EOF
+$feature{'snapshot'}{'override'} = 0;
+EOF
+
+test_expect_success \
+    'snapshots: tgz only default format enabled' \
+    'gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tgz" &&
+    grep "Status: 200 OK" gitweb.output &&
+    gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tbz2" &&
+    grep "403 - Unsupported snapshot format" gitweb.output &&
+    gitweb_run "p=.git;a=snapshot;h=HEAD;sf=txz" &&
+    grep "403 - Snapshot format not allowed" gitweb.output &&
+    gitweb_run "p=.git;a=snapshot;h=HEAD;sf=zip" &&
+    grep "403 - Unsupported snapshot format" gitweb.output'
+test_debug 'cat gitweb.output'
+
+
+cat >>gitweb_config.perl <<\EOF
+$feature{'snapshot'}{'default'} = ['tgz','tbz2','txz','zip'];
+EOF
+
+test_expect_success \
+    'snapshots: all enabled in default, use default disabled value' \
+    'gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tgz" &&
+    grep "Status: 200 OK" gitweb.output &&
+    gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tbz2" &&
+    grep "Status: 200 OK" gitweb.output &&
+    gitweb_run "p=.git;a=snapshot;h=HEAD;sf=txz" &&
+    grep "403 - Snapshot format not allowed" gitweb.output &&
+    gitweb_run "p=.git;a=snapshot;h=HEAD;sf=zip" &&
+    grep "Status: 200 OK" gitweb.output'
+test_debug 'cat gitweb.output'
+
+
+cat >>gitweb_config.perl <<\EOF
+$known_snapshot_formats{'zip'}{'disabled'} = 1;
+EOF
+
+test_expect_success \
+    'snapshots: zip explicitly disabled' \
+    'gitweb_run "p=.git;a=snapshot;h=HEAD;sf=zip" &&
+    grep "403 - Snapshot format not allowed" gitweb.output'
+test_debug 'cat gitweb.output'
+
+
+cat >>gitweb_config.perl <<\EOF
+$known_snapshot_formats{'tgz'}{'disabled'} = 0;
+EOF
+
+test_expect_success \
+    'snapshots: tgz explicitly enabled' \
+    'gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tgz" &&
+    grep "Status: 200 OK" gitweb.output'
+test_debug 'cat gitweb.output'
+
+
+test_done
diff --git a/t/test-lib.sh b/t/test-lib.sh
index a5b8d03..f2ca536 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -685,6 +685,21 @@
 	esac
 done
 
+# Provide an implementation of the 'yes' utility
+yes () {
+	if test $# = 0
+	then
+		y=y
+	else
+		y="$*"
+	fi
+
+	while echo "$y"
+	do
+		:
+	done
+}
+
 # Fix some commands on Windows
 case $(uname -s) in
 *MINGW*)
diff --git a/transport.c b/transport.c
index faee154..f7e1663 100644
--- a/transport.c
+++ b/transport.c
@@ -1059,11 +1059,12 @@
 int transport_fetch_refs(struct transport *transport, const struct ref *refs)
 {
 	int rc;
-	int nr_heads = 0, nr_alloc = 0;
+	int nr_heads = 0, nr_alloc = 0, nr_refs = 0;
 	const struct ref **heads = NULL;
 	const struct ref *rm;
 
 	for (rm = refs; rm; rm = rm->next) {
+		nr_refs++;
 		if (rm->peer_ref &&
 		    !hashcmp(rm->peer_ref->old_sha1, rm->old_sha1))
 			continue;
@@ -1071,6 +1072,19 @@
 		heads[nr_heads++] = rm;
 	}
 
+	if (!nr_heads) {
+		/*
+		 * When deepening of a shallow repository is requested,
+		 * then local and remote refs are likely to still be equal.
+		 * Just feed them all to the fetch method in that case.
+		 * This condition shouldn't be met in a non-deepening fetch
+		 * (see builtin-fetch.c:quickfetch()).
+		 */
+		heads = xmalloc(nr_refs * sizeof(*heads));
+		for (rm = refs; rm; rm = rm->next)
+			heads[nr_heads++] = rm;
+	}
+
 	rc = transport->fetch(transport, nr_heads, heads);
 	free(heads);
 	return rc;
diff --git a/update-server-info.c b/update-server-info.c
deleted file mode 100644
index 7b38fd8..0000000
--- a/update-server-info.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include "cache.h"
-#include "exec_cmd.h"
-
-static const char update_server_info_usage[] =
-"git update-server-info [--force]";
-
-int main(int ac, char **av)
-{
-	int i;
-	int force = 0;
-	for (i = 1; i < ac; i++) {
-		if (av[i][0] == '-') {
-			if (!strcmp("--force", av[i]) ||
-			    !strcmp("-f", av[i]))
-				force = 1;
-			else
-				usage(update_server_info_usage);
-		}
-	}
-	if (i != ac)
-		usage(update_server_info_usage);
-
-	git_extract_argv0_path(av[0]);
-
-	setup_git_directory();
-
-	return !!update_server_info(force);
-}
diff --git a/wt-status.c b/wt-status.c
index 47735d8..63598ce 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1,6 +1,5 @@
 #include "cache.h"
 #include "wt-status.h"
-#include "color.h"
 #include "object.h"
 #include "dir.h"
 #include "commit.h"
@@ -11,38 +10,18 @@
 #include "run-command.h"
 #include "remote.h"
 
-int wt_status_relative_paths = 1;
-int wt_status_use_color = -1;
-static int wt_status_submodule_summary;
-static char wt_status_colors[][COLOR_MAXLEN] = {
+static char default_wt_status_colors[][COLOR_MAXLEN] = {
 	GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */
 	GIT_COLOR_GREEN,  /* WT_STATUS_UPDATED */
 	GIT_COLOR_RED,    /* WT_STATUS_CHANGED */
 	GIT_COLOR_RED,    /* WT_STATUS_UNTRACKED */
 	GIT_COLOR_RED,    /* WT_STATUS_NOBRANCH */
+	GIT_COLOR_RED,    /* WT_STATUS_UNMERGED */
 };
 
-enum untracked_status_type show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
-
-static int parse_status_slot(const char *var, int offset)
+static const char *color(int slot, struct wt_status *s)
 {
-	if (!strcasecmp(var+offset, "header"))
-		return WT_STATUS_HEADER;
-	if (!strcasecmp(var+offset, "updated")
-		|| !strcasecmp(var+offset, "added"))
-		return WT_STATUS_UPDATED;
-	if (!strcasecmp(var+offset, "changed"))
-		return WT_STATUS_CHANGED;
-	if (!strcasecmp(var+offset, "untracked"))
-		return WT_STATUS_UNTRACKED;
-	if (!strcasecmp(var+offset, "nobranch"))
-		return WT_STATUS_NOBRANCH;
-	die("bad config variable '%s'", var);
-}
-
-static const char *color(int slot)
-{
-	return wt_status_use_color > 0 ? wt_status_colors[slot] : "";
+	return s->use_color > 0 ? s->color_palette[slot] : "";
 }
 
 void wt_status_prepare(struct wt_status *s)
@@ -51,16 +30,35 @@
 	const char *head;
 
 	memset(s, 0, sizeof(*s));
+	memcpy(s->color_palette, default_wt_status_colors,
+	       sizeof(default_wt_status_colors));
+	s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
+	s->use_color = -1;
+	s->relative_paths = 1;
 	head = resolve_ref("HEAD", sha1, 0, NULL);
 	s->branch = head ? xstrdup(head) : NULL;
 	s->reference = "HEAD";
 	s->fp = stdout;
 	s->index_file = get_index_file();
+	s->change.strdup_strings = 1;
+	s->untracked.strdup_strings = 1;
+}
+
+static void wt_status_print_unmerged_header(struct wt_status *s)
+{
+	const char *c = color(WT_STATUS_HEADER, s);
+	color_fprintf_ln(s->fp, c, "# Unmerged paths:");
+	if (!s->is_initial)
+		color_fprintf_ln(s->fp, c, "#   (use \"git reset %s <file>...\" to unstage)", s->reference);
+	else
+		color_fprintf_ln(s->fp, c, "#   (use \"git rm --cached <file>...\" to unstage)");
+	color_fprintf_ln(s->fp, c, "#   (use \"git add <file>...\" to mark resolution)");
+	color_fprintf_ln(s->fp, c, "#");
 }
 
 static void wt_status_print_cached_header(struct wt_status *s)
 {
-	const char *c = color(WT_STATUS_HEADER);
+	const char *c = color(WT_STATUS_HEADER, s);
 	color_fprintf_ln(s->fp, c, "# Changes to be committed:");
 	if (!s->is_initial) {
 		color_fprintf_ln(s->fp, c, "#   (use \"git reset %s <file>...\" to unstage)", s->reference);
@@ -73,7 +71,7 @@
 static void wt_status_print_dirty_header(struct wt_status *s,
 					 int has_deleted)
 {
-	const char *c = color(WT_STATUS_HEADER);
+	const char *c = color(WT_STATUS_HEADER, s);
 	color_fprintf_ln(s->fp, c, "# Changed but not updated:");
 	if (!has_deleted)
 		color_fprintf_ln(s->fp, c, "#   (use \"git add <file>...\" to update what will be committed)");
@@ -85,7 +83,7 @@
 
 static void wt_status_print_untracked_header(struct wt_status *s)
 {
-	const char *c = color(WT_STATUS_HEADER);
+	const char *c = color(WT_STATUS_HEADER, s);
 	color_fprintf_ln(s->fp, c, "# Untracked files:");
 	color_fprintf_ln(s->fp, c, "#   (use \"git add <file>...\" to include in what will be committed)");
 	color_fprintf_ln(s->fp, c, "#");
@@ -93,23 +91,63 @@
 
 static void wt_status_print_trailer(struct wt_status *s)
 {
-	color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
+	color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
 }
 
 #define quote_path quote_path_relative
 
-static void wt_status_print_filepair(struct wt_status *s,
-				     int t, struct diff_filepair *p)
+static void wt_status_print_unmerged_data(struct wt_status *s,
+					  struct string_list_item *it)
 {
-	const char *c = color(t);
+	const char *c = color(WT_STATUS_UNMERGED, s);
+	struct wt_status_change_data *d = it->util;
+	struct strbuf onebuf = STRBUF_INIT;
+	const char *one, *how = "bug";
+
+	one = quote_path(it->string, -1, &onebuf, s->prefix);
+	color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
+	switch (d->stagemask) {
+	case 1: how = "both deleted:"; break;
+	case 2: how = "added by us:"; break;
+	case 3: how = "deleted by them:"; break;
+	case 4: how = "added by them:"; break;
+	case 5: how = "deleted by us:"; break;
+	case 6: how = "both added:"; break;
+	case 7: how = "both modified:"; break;
+	}
+	color_fprintf(s->fp, c, "%-20s%s\n", how, one);
+	strbuf_release(&onebuf);
+}
+
+static void wt_status_print_change_data(struct wt_status *s,
+					int change_type,
+					struct string_list_item *it)
+{
+	struct wt_status_change_data *d = it->util;
+	const char *c = color(change_type, s);
+	int status = status;
+	char *one_name;
+	char *two_name;
 	const char *one, *two;
 	struct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT;
 
-	one = quote_path(p->one->path, -1, &onebuf, s->prefix);
-	two = quote_path(p->two->path, -1, &twobuf, s->prefix);
+	one_name = two_name = it->string;
+	switch (change_type) {
+	case WT_STATUS_UPDATED:
+		status = d->index_status;
+		if (d->head_path)
+			one_name = d->head_path;
+		break;
+	case WT_STATUS_CHANGED:
+		status = d->worktree_status;
+		break;
+	}
 
-	color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
-	switch (p->status) {
+	one = quote_path(one_name, -1, &onebuf, s->prefix);
+	two = quote_path(two_name, -1, &twobuf, s->prefix);
+
+	color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
+	switch (status) {
 	case DIFF_STATUS_ADDED:
 		color_fprintf(s->fp, c, "new file:   %s", one);
 		break;
@@ -135,64 +173,114 @@
 		color_fprintf(s->fp, c, "unmerged:   %s", one);
 		break;
 	default:
-		die("bug: unhandled diff status %c", p->status);
+		die("bug: unhandled diff status %c", status);
 	}
 	fprintf(s->fp, "\n");
 	strbuf_release(&onebuf);
 	strbuf_release(&twobuf);
 }
 
-static void wt_status_print_updated_cb(struct diff_queue_struct *q,
-		struct diff_options *options,
-		void *data)
+static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
+					 struct diff_options *options,
+					 void *data)
 {
 	struct wt_status *s = data;
-	int shown_header = 0;
 	int i;
+
+	if (!q->nr)
+		return;
+	s->workdir_dirty = 1;
 	for (i = 0; i < q->nr; i++) {
-		if (q->queue[i]->status == 'U')
-			continue;
-		if (!shown_header) {
-			wt_status_print_cached_header(s);
-			s->commitable = 1;
-			shown_header = 1;
+		struct diff_filepair *p;
+		struct string_list_item *it;
+		struct wt_status_change_data *d;
+
+		p = q->queue[i];
+		it = string_list_insert(p->one->path, &s->change);
+		d = it->util;
+		if (!d) {
+			d = xcalloc(1, sizeof(*d));
+			it->util = d;
 		}
-		wt_status_print_filepair(s, WT_STATUS_UPDATED, q->queue[i]);
+		if (!d->worktree_status)
+			d->worktree_status = p->status;
 	}
-	if (shown_header)
-		wt_status_print_trailer(s);
 }
 
-static void wt_status_print_changed_cb(struct diff_queue_struct *q,
-                        struct diff_options *options,
-                        void *data)
+static int unmerged_mask(const char *path)
+{
+	int pos, mask;
+	struct cache_entry *ce;
+
+	pos = cache_name_pos(path, strlen(path));
+	if (0 <= pos)
+		return 0;
+
+	mask = 0;
+	pos = -pos-1;
+	while (pos < active_nr) {
+		ce = active_cache[pos++];
+		if (strcmp(ce->name, path) || !ce_stage(ce))
+			break;
+		mask |= (1 << (ce_stage(ce) - 1));
+	}
+	return mask;
+}
+
+static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
+					 struct diff_options *options,
+					 void *data)
 {
 	struct wt_status *s = data;
 	int i;
-	if (q->nr) {
-		int has_deleted = 0;
-		s->workdir_dirty = 1;
-		for (i = 0; i < q->nr; i++)
-			if (q->queue[i]->status == DIFF_STATUS_DELETED) {
-				has_deleted = 1;
-				break;
-			}
-		wt_status_print_dirty_header(s, has_deleted);
+
+	for (i = 0; i < q->nr; i++) {
+		struct diff_filepair *p;
+		struct string_list_item *it;
+		struct wt_status_change_data *d;
+
+		p = q->queue[i];
+		it = string_list_insert(p->two->path, &s->change);
+		d = it->util;
+		if (!d) {
+			d = xcalloc(1, sizeof(*d));
+			it->util = d;
+		}
+		if (!d->index_status)
+			d->index_status = p->status;
+		switch (p->status) {
+		case DIFF_STATUS_COPIED:
+		case DIFF_STATUS_RENAMED:
+			d->head_path = xstrdup(p->one->path);
+			break;
+		case DIFF_STATUS_UNMERGED:
+			d->stagemask = unmerged_mask(p->two->path);
+			break;
+		}
 	}
-	for (i = 0; i < q->nr; i++)
-		wt_status_print_filepair(s, WT_STATUS_CHANGED, q->queue[i]);
-	if (q->nr)
-		wt_status_print_trailer(s);
 }
 
-static void wt_status_print_updated(struct wt_status *s)
+static void wt_status_collect_changes_worktree(struct wt_status *s)
 {
 	struct rev_info rev;
+
+	init_revisions(&rev, NULL);
+	setup_revisions(0, NULL, &rev, NULL);
+	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = wt_status_collect_changed_cb;
+	rev.diffopt.format_callback_data = s;
+	run_diff_files(&rev, 0);
+}
+
+static void wt_status_collect_changes_index(struct wt_status *s)
+{
+	struct rev_info rev;
+
 	init_revisions(&rev, NULL);
 	setup_revisions(0, NULL, &rev,
 		s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference);
 	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
-	rev.diffopt.format_callback = wt_status_print_updated_cb;
+	rev.diffopt.format_callback = wt_status_collect_updated_cb;
 	rev.diffopt.format_callback_data = s;
 	rev.diffopt.detect_rename = 1;
 	rev.diffopt.rename_limit = 200;
@@ -200,15 +288,155 @@
 	run_diff_index(&rev, 1);
 }
 
+static void wt_status_collect_changes_initial(struct wt_status *s)
+{
+	int i;
+
+	for (i = 0; i < active_nr; i++) {
+		struct string_list_item *it;
+		struct wt_status_change_data *d;
+		struct cache_entry *ce = active_cache[i];
+
+		it = string_list_insert(ce->name, &s->change);
+		d = it->util;
+		if (!d) {
+			d = xcalloc(1, sizeof(*d));
+			it->util = d;
+		}
+		if (ce_stage(ce)) {
+			d->index_status = DIFF_STATUS_UNMERGED;
+			d->stagemask |= (1 << (ce_stage(ce) - 1));
+		}
+		else
+			d->index_status = DIFF_STATUS_ADDED;
+	}
+}
+
+static void wt_status_collect_untracked(struct wt_status *s)
+{
+	int i;
+	struct dir_struct dir;
+
+	if (!s->show_untracked_files)
+		return;
+	memset(&dir, 0, sizeof(dir));
+	if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES)
+		dir.flags |=
+			DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
+	setup_standard_excludes(&dir);
+
+	fill_directory(&dir, NULL);
+	for(i = 0; i < dir.nr; i++) {
+		struct dir_entry *ent = dir.entries[i];
+		if (!cache_name_is_other(ent->name, ent->len))
+			continue;
+		s->workdir_untracked = 1;
+		string_list_insert(ent->name, &s->untracked);
+	}
+}
+
+void wt_status_collect(struct wt_status *s)
+{
+	wt_status_collect_changes_worktree(s);
+
+	if (s->is_initial)
+		wt_status_collect_changes_initial(s);
+	else
+		wt_status_collect_changes_index(s);
+	wt_status_collect_untracked(s);
+}
+
+static void wt_status_print_unmerged(struct wt_status *s)
+{
+	int shown_header = 0;
+	int i;
+
+	for (i = 0; i < s->change.nr; i++) {
+		struct wt_status_change_data *d;
+		struct string_list_item *it;
+		it = &(s->change.items[i]);
+		d = it->util;
+		if (!d->stagemask)
+			continue;
+		if (!shown_header) {
+			wt_status_print_unmerged_header(s);
+			shown_header = 1;
+		}
+		wt_status_print_unmerged_data(s, it);
+	}
+	if (shown_header)
+		wt_status_print_trailer(s);
+
+}
+
+static void wt_status_print_updated(struct wt_status *s)
+{
+	int shown_header = 0;
+	int i;
+
+	for (i = 0; i < s->change.nr; i++) {
+		struct wt_status_change_data *d;
+		struct string_list_item *it;
+		it = &(s->change.items[i]);
+		d = it->util;
+		if (!d->index_status ||
+		    d->index_status == DIFF_STATUS_UNMERGED)
+			continue;
+		if (!shown_header) {
+			wt_status_print_cached_header(s);
+			s->commitable = 1;
+			shown_header = 1;
+		}
+		wt_status_print_change_data(s, WT_STATUS_UPDATED, it);
+	}
+	if (shown_header)
+		wt_status_print_trailer(s);
+}
+
+/*
+ * -1 : has delete
+ *  0 : no change
+ *  1 : some change but no delete
+ */
+static int wt_status_check_worktree_changes(struct wt_status *s)
+{
+	int i;
+	int changes = 0;
+
+	for (i = 0; i < s->change.nr; i++) {
+		struct wt_status_change_data *d;
+		d = s->change.items[i].util;
+		if (!d->worktree_status ||
+		    d->worktree_status == DIFF_STATUS_UNMERGED)
+			continue;
+		changes = 1;
+		if (d->worktree_status == DIFF_STATUS_DELETED)
+			return -1;
+	}
+	return changes;
+}
+
 static void wt_status_print_changed(struct wt_status *s)
 {
-	struct rev_info rev;
-	init_revisions(&rev, "");
-	setup_revisions(0, NULL, &rev, NULL);
-	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
-	rev.diffopt.format_callback = wt_status_print_changed_cb;
-	rev.diffopt.format_callback_data = s;
-	run_diff_files(&rev, 0);
+	int i;
+	int worktree_changes = wt_status_check_worktree_changes(s);
+
+	if (!worktree_changes)
+		return;
+
+	wt_status_print_dirty_header(s, worktree_changes < 0);
+
+	for (i = 0; i < s->change.nr; i++) {
+		struct wt_status_change_data *d;
+		struct string_list_item *it;
+		it = &(s->change.items[i]);
+		d = it->util;
+		if (!d->worktree_status ||
+		    d->worktree_status == DIFF_STATUS_UNMERGED)
+			continue;
+		wt_status_print_change_data(s, WT_STATUS_CHANGED, it);
+	}
+	wt_status_print_trailer(s);
 }
 
 static void wt_status_print_submodule_summary(struct wt_status *s)
@@ -228,7 +456,7 @@
 		NULL
 	};
 
-	sprintf(summary_limit, "%d", wt_status_submodule_summary);
+	sprintf(summary_limit, "%d", s->submodule_summary);
 	snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", s->index_file);
 
 	memset(&sm_summary, 0, sizeof(sm_summary));
@@ -243,32 +471,20 @@
 
 static void wt_status_print_untracked(struct wt_status *s)
 {
-	struct dir_struct dir;
 	int i;
-	int shown_header = 0;
 	struct strbuf buf = STRBUF_INIT;
 
-	memset(&dir, 0, sizeof(dir));
+	if (!s->untracked.nr)
+		return;
 
-	if (!s->untracked)
-		dir.flags |=
-			DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
-	setup_standard_excludes(&dir);
-
-	fill_directory(&dir, NULL);
-	for(i = 0; i < dir.nr; i++) {
-		struct dir_entry *ent = dir.entries[i];
-		if (!cache_name_is_other(ent->name, ent->len))
-			continue;
-		if (!shown_header) {
-			s->workdir_untracked = 1;
-			wt_status_print_untracked_header(s);
-			shown_header = 1;
-		}
-		color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
-		color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED), "%s",
-				quote_path(ent->name, ent->len,
-					&buf, s->prefix));
+	wt_status_print_untracked_header(s);
+	for (i = 0; i < s->untracked.nr; i++) {
+		struct string_list_item *it;
+		it = &(s->untracked.items[i]);
+		color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
+		color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED, s), "%s",
+				 quote_path(it->string, strlen(it->string),
+					    &buf, s->prefix));
 	}
 	strbuf_release(&buf);
 }
@@ -310,15 +526,15 @@
 		return;
 
 	for (cp = sb.buf; (ep = strchr(cp, '\n')) != NULL; cp = ep + 1)
-		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER),
+		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s),
 				 "# %.*s", (int)(ep - cp), cp);
-	color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
+	color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
 }
 
 void wt_status_print(struct wt_status *s)
 {
 	unsigned char sha1[20];
-	const char *branch_color = color(WT_STATUS_HEADER);
+	const char *branch_color = color(WT_STATUS_HEADER, s);
 
 	s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0;
 	if (s->branch) {
@@ -328,26 +544,29 @@
 			branch_name += 11;
 		else if (!strcmp(branch_name, "HEAD")) {
 			branch_name = "";
-			branch_color = color(WT_STATUS_NOBRANCH);
+			branch_color = color(WT_STATUS_NOBRANCH, s);
 			on_what = "Not currently on any branch.";
 		}
-		color_fprintf(s->fp, color(WT_STATUS_HEADER), "# ");
+		color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "# ");
 		color_fprintf_ln(s->fp, branch_color, "%s%s", on_what, branch_name);
 		if (!s->is_initial)
 			wt_status_print_tracking(s);
 	}
 
+	wt_status_collect(s);
+
 	if (s->is_initial) {
-		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
-		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "# Initial commit");
-		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
+		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
+		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "# Initial commit");
+		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
 	}
 
+	wt_status_print_unmerged(s);
 	wt_status_print_updated(s);
 	wt_status_print_changed(s);
-	if (wt_status_submodule_summary)
+	if (s->submodule_summary)
 		wt_status_print_submodule_summary(s);
-	if (show_untracked_files)
+	if (s->show_untracked_files)
 		wt_status_print_untracked(s);
 	else if (s->commitable)
 		 fprintf(s->fp, "# Untracked files not listed (use -u option to show untracked files)\n");
@@ -361,53 +580,13 @@
 			; /* nothing */
 		else if (s->workdir_dirty)
 			printf("no changes added to commit (use \"git add\" and/or \"git commit -a\")\n");
-		else if (s->workdir_untracked)
+		else if (s->untracked.nr)
 			printf("nothing added to commit but untracked files present (use \"git add\" to track)\n");
 		else if (s->is_initial)
 			printf("nothing to commit (create/copy files and use \"git add\" to track)\n");
-		else if (!show_untracked_files)
+		else if (!s->show_untracked_files)
 			printf("nothing to commit (use -u to show untracked files)\n");
 		else
 			printf("nothing to commit (working directory clean)\n");
 	}
 }
-
-int git_status_config(const char *k, const char *v, void *cb)
-{
-	if (!strcmp(k, "status.submodulesummary")) {
-		int is_bool;
-		wt_status_submodule_summary = git_config_bool_or_int(k, v, &is_bool);
-		if (is_bool && wt_status_submodule_summary)
-			wt_status_submodule_summary = -1;
-		return 0;
-	}
-	if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
-		wt_status_use_color = git_config_colorbool(k, v, -1);
-		return 0;
-	}
-	if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
-		int slot = parse_status_slot(k, 13);
-		if (!v)
-			return config_error_nonbool(k);
-		color_parse(v, k, wt_status_colors[slot]);
-		return 0;
-	}
-	if (!strcmp(k, "status.relativepaths")) {
-		wt_status_relative_paths = git_config_bool(k, v);
-		return 0;
-	}
-	if (!strcmp(k, "status.showuntrackedfiles")) {
-		if (!v)
-			return config_error_nonbool(k);
-		else if (!strcmp(v, "no"))
-			show_untracked_files = SHOW_NO_UNTRACKED_FILES;
-		else if (!strcmp(v, "normal"))
-			show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
-		else if (!strcmp(v, "all"))
-			show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
-		else
-			return error("Invalid untracked files mode '%s'", v);
-		return 0;
-	}
-	return git_diff_ui_config(k, v, cb);
-}
diff --git a/wt-status.h b/wt-status.h
index 78add09..a0e7517 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -2,13 +2,16 @@
 #define STATUS_H
 
 #include <stdio.h>
+#include "string-list.h"
+#include "color.h"
 
 enum color_wt_status {
-	WT_STATUS_HEADER,
+	WT_STATUS_HEADER = 0,
 	WT_STATUS_UPDATED,
 	WT_STATUS_CHANGED,
 	WT_STATUS_UNTRACKED,
 	WT_STATUS_NOBRANCH,
+	WT_STATUS_UNMERGED,
 };
 
 enum untracked_status_type {
@@ -16,7 +19,13 @@
 	SHOW_NORMAL_UNTRACKED_FILES,
 	SHOW_ALL_UNTRACKED_FILES
 };
-extern enum untracked_status_type show_untracked_files;
+
+struct wt_status_change_data {
+	int worktree_status;
+	int index_status;
+	int stagemask;
+	char *head_path;
+};
 
 struct wt_status {
 	int is_initial;
@@ -24,8 +33,13 @@
 	const char *reference;
 	int verbose;
 	int amend;
-	int untracked;
 	int nowarn;
+	int use_color;
+	int relative_paths;
+	int submodule_summary;
+	enum untracked_status_type show_untracked_files;
+	char color_palette[WT_STATUS_UNMERGED+1][COLOR_MAXLEN];
+
 	/* These are computed during processing of the individual sections */
 	int commitable;
 	int workdir_dirty;
@@ -33,12 +47,12 @@
 	const char *index_file;
 	FILE *fp;
 	const char *prefix;
+	struct string_list change;
+	struct string_list untracked;
 };
 
-int git_status_config(const char *var, const char *value, void *cb);
-extern int wt_status_use_color;
-extern int wt_status_relative_paths;
 void wt_status_prepare(struct wt_status *s);
 void wt_status_print(struct wt_status *s);
+void wt_status_collect(struct wt_status *s);
 
 #endif /* STATUS_H */
diff --git a/xdiff/xutils.c b/xdiff/xutils.c
index 04ad468..bc12f29 100644
--- a/xdiff/xutils.c
+++ b/xdiff/xutils.c
@@ -190,48 +190,66 @@
 {
 	int i1, i2;
 
+	if (!(flags & XDF_WHITESPACE_FLAGS))
+		return s1 == s2 && !memcmp(l1, l2, s1);
+
+	i1 = 0;
+	i2 = 0;
+
+	/*
+	 * -w matches everything that matches with -b, and -b in turn
+	 * matches everything that matches with --ignore-space-at-eol.
+	 *
+	 * Each flavor of ignoring needs different logic to skip whitespaces
+	 * while we have both sides to compare.
+	 */
 	if (flags & XDF_IGNORE_WHITESPACE) {
-		for (i1 = i2 = 0; i1 < s1 && i2 < s2; ) {
-			if (isspace(l1[i1]))
-				while (isspace(l1[i1]) && i1 < s1)
-					i1++;
-			if (isspace(l2[i2]))
-				while (isspace(l2[i2]) && i2 < s2)
-					i2++;
-			if (i1 < s1 && i2 < s2 && l1[i1++] != l2[i2++])
+		goto skip_ws;
+		while (i1 < s1 && i2 < s2) {
+			if (l1[i1++] != l2[i2++])
 				return 0;
+		skip_ws:
+			while (i1 < s1 && isspace(l1[i1]))
+				i1++;
+			while (i2 < s2 && isspace(l2[i2]))
+				i2++;
 		}
-		return (i1 >= s1 && i2 >= s2);
 	} else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) {
-		for (i1 = i2 = 0; i1 < s1 && i2 < s2; ) {
-			if (isspace(l1[i1])) {
-				if (!isspace(l2[i2]))
-					return 0;
-				while (isspace(l1[i1]) && i1 < s1)
-					i1++;
-				while (isspace(l2[i2]) && i2 < s2)
-					i2++;
-			} else if (l1[i1++] != l2[i2++])
-				return 0;
-		}
-		return (i1 >= s1 && i2 >= s2);
-	} else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL) {
-		for (i1 = i2 = 0; i1 < s1 && i2 < s2; ) {
-			if (l1[i1] != l2[i2]) {
+		while (i1 < s1 && i2 < s2) {
+			if (isspace(l1[i1]) && isspace(l2[i2])) {
+				/* Skip matching spaces and try again */
 				while (i1 < s1 && isspace(l1[i1]))
 					i1++;
 				while (i2 < s2 && isspace(l2[i2]))
 					i2++;
-				if (i1 < s1 || i2 < s2)
-					return 0;
-				return 1;
+				continue;
 			}
-			i1++;
-			i2++;
+			if (l1[i1++] != l2[i2++])
+				return 0;
 		}
-		return i1 >= s1 && i2 >= s2;
-	} else
-		return s1 == s2 && !memcmp(l1, l2, s1);
+	} else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL) {
+		while (i1 < s1 && i2 < s2 && l1[i1++] == l2[i2++])
+			; /* keep going */
+	}
+
+	/*
+	 * After running out of one side, the remaining side must have
+	 * nothing but whitespace for the lines to match.  Note that
+	 * ignore-whitespace-at-eol case may break out of the loop
+	 * while there still are characters remaining on both lines.
+	 */
+	if (i1 < s1) {
+		while (i1 < s1 && isspace(l1[i1]))
+			i1++;
+		if (s1 != i1)
+			return 0;
+	}
+	if (i2 < s2) {
+		while (i2 < s2 && isspace(l2[i2]))
+			i2++;
+		return (s2 == i2);
+	}
+	return 1;
 }
 
 static unsigned long xdl_hash_record_with_whitespace(char const **data,
@@ -242,18 +260,20 @@
 	for (; ptr < top && *ptr != '\n'; ptr++) {
 		if (isspace(*ptr)) {
 			const char *ptr2 = ptr;
+			int at_eol;
 			while (ptr + 1 < top && isspace(ptr[1])
 					&& ptr[1] != '\n')
 				ptr++;
+			at_eol = (top <= ptr + 1 || ptr[1] == '\n');
 			if (flags & XDF_IGNORE_WHITESPACE)
 				; /* already handled */
 			else if (flags & XDF_IGNORE_WHITESPACE_CHANGE
-					&& ptr[1] != '\n') {
+				 && !at_eol) {
 				ha += (ha << 5);
 				ha ^= (unsigned long) ' ';
 			}
 			else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL
-					&& ptr[1] != '\n') {
+				 && !at_eol) {
 				while (ptr2 != ptr + 1) {
 					ha += (ha << 5);
 					ha ^= (unsigned long) *ptr2;