Merge branch 'ap/trackinfo'

* ap/trackinfo:
  Reword "your branch has diverged..." lines to reduce line length
diff --git a/.mailmap b/.mailmap
index f88ae77..373476b 100644
--- a/.mailmap
+++ b/.mailmap
@@ -5,22 +5,28 @@
 # same person appearing not to be so.
 #
 
+Alexander Gavrilov <angavrilov@gmail.com>
 Aneesh Kumar K.V <aneesh.kumar@gmail.com>
 Brian M. Carlson <sandals@crustytoothpaste.ath.cx>
 Chris Shoemaker <c.shoemaker@cox.net>
 Dana L. How <danahow@gmail.com>
 Dana L. How <how@deathvalley.cswitch.com>
 Daniel Barkalow <barkalow@iabervon.org>
+David D. Kilzer <ddkilzer@kilzer.net>
 David Kågedal <davidk@lysator.liu.se>
+David S. Miller <davem@davemloft.net>
+Dirk Süsserott <newsletter@dirk.my1.cc>
 Fredrik Kuivinen <freku045@student.liu.se>
 H. Peter Anvin <hpa@bonde.sc.orionmulti.com>
 H. Peter Anvin <hpa@tazenda.sc.orionmulti.com>
 H. Peter Anvin <hpa@trantor.hos.anvin.org>
 Horst H. von Brand <vonbrand@inf.utfsm.cl>
+İsmail Dönmez <ismail@pardus.org.tr>
 Jay Soffian <jaysoffian+git@gmail.com>
 Joachim Berdal Haga <cjhaga@fys.uio.no>
 Jon Loeliger <jdl@freescale.com>
 Jon Seymour <jon@blackcubes.dyndns.org>
+Jonathan Nieder <jrnieder@uchicago.edu>
 Junio C Hamano <junio@twinsun.com>
 Karl Hasselström <kha@treskal.com>
 Kent Engstrom <kent@lysator.liu.se>
@@ -30,9 +36,12 @@
 Lukas Sandström <lukass@etek.chalmers.se>
 Martin Langhoff <martin@catalyst.net.nz>
 Michael Coleman <tutufan@gmail.com>
+Michael W. Olson <mwolson@gnu.org>
 Michele Ballabio <barra_cuda@katamail.com>
 Nanako Shiraishi <nanako3@bluebottle.com>
+Nanako Shiraishi <nanako3@lavabit.com>
 Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
+Philippe Bruhat <book@cpan.org>
 Ramsay Allan Jones <ramsay@ramsay1.demon.co.uk>
 René Scharfe <rene.scharfe@lsrfire.ath.cx>
 Robert Fitzsimons <robfitz@273k.net>
diff --git a/Documentation/RelNotes-1.5.6.4.txt b/Documentation/RelNotes-1.5.6.4.txt
new file mode 100644
index 0000000..d8968f1
--- /dev/null
+++ b/Documentation/RelNotes-1.5.6.4.txt
@@ -0,0 +1,47 @@
+GIT v1.5.6.4 Release Notes
+==========================
+
+Fixes since v1.5.6.3
+--------------------
+
+* Various commands could overflow its internal buffer on a platform
+  with small PATH_MAX value in a repository that has contents with
+  long pathnames.
+
+* There wasn't a way to make --pretty=format:%<> specifiers to honor
+  .mailmap name rewriting for authors and committers.  Now you can with
+  %aN and %cN.
+
+* Bash completion wasted too many cycles; this has been optimized to be
+  usable again.
+
+* Bash completion lost ref part when completing something like "git show
+  pu:Makefile".
+
+* "git-cvsserver" did not clean up its temporary working area after annotate
+  request.
+
+* "git-daemon" called syslog() from its signal handler, which was a
+  no-no.
+
+* "git-fetch" into an empty repository used to remind that the fetch will
+   be huge by saying "no common commits", but this was an unnecessary
+   noise; it is already known by the user anyway.
+
+* "git-http-fetch" would have segfaulted when pack idx file retrieved
+  from the other side was corrupt.
+
+* "git-index-pack" used too much memory when dealing with a deep delta chain.
+
+* "git-mailinfo" (hence "git-am") did not correctly handle in-body [PATCH]
+  line to override the commit title taken from the mail Subject header.
+
+* "git-rebase -i -p" lost parents that are not involved in the history
+  being rewritten.
+
+* "git-rm" lost track of where the index file was when GIT_DIR was
+  specified as a relative path.
+
+* "git-rev-list --quiet" was not quiet as advertised.
+
+Contains other various documentation fixes.
diff --git a/Documentation/RelNotes-1.6.0.txt b/Documentation/RelNotes-1.6.0.txt
index 89ea1e9..7da62d0 100644
--- a/Documentation/RelNotes-1.6.0.txt
+++ b/Documentation/RelNotes-1.6.0.txt
@@ -21,13 +21,19 @@
 By default, packfiles created with this version uses delta-base-offset
 encoding introduced in v1.4.4.  Pack idx files are using version 2 that
 allows larger packs and added robustness thanks to its CRC checking,
-introduced in v1.5.2.
+introduced in v1.5.2 and v1.4.4.5.  If you want to keep your repositories
+backwards compatible past these versions, set repack.useDeltaBaseOffset
+to false or pack.indexVersion to 1, respectively.
 
 GIT_CONFIG, which was only documented as affecting "git config", but
 actually affected all git commands, now only affects "git config".
 GIT_LOCAL_CONFIG, also only documented as affecting "git config" and
 not different from GIT_CONFIG in a useful way, is removed.
 
+The ".dotest" temporary area "git am" and "git rebase" use is now moved
+inside the $GIT_DIR, to avoid mistakes of adding it to the project by
+accident.
+
 An ancient merge strategy "stupid" has been removed.
 
 
@@ -67,7 +73,8 @@
 
 (performance, robustness, sanity etc.)
 
-* even more documentation pages are now accessible via "man" and "git help".
+* index-pack used too much memory when dealing with a deep delta chain.
+  This has been optimized.
 
 * reduced excessive inlining to shrink size of the "git" binary.
 
@@ -79,6 +86,8 @@
   repack -a -f" can be used to fix such a corruption as long as necessary
   objects are available.
 
+* Performance of "git-blame -C -C" operation is vastly improved.
+
 * git-clone does not create refs in loose form anymore (it behaves as
   if you immediately ran git-pack-refs after cloning).  This will help
   repositories with insanely large number of refs.
@@ -92,6 +101,8 @@
 
 (usability, bells and whistles)
 
+* even more documentation pages are now accessible via "man" and "git help".
+
 * A new environment variable GIT_CEILING_DIRECTORIES can be used to stop
   the discovery process of the toplevel of working tree; this may be useful
   when you are working in a slow network disk and are outside any working tree,
@@ -125,6 +136,9 @@
 * git-archive can be told to omit certain paths from its output using
   export-ignore attributes.
 
+* git-archive uses the zlib default compression level when creating
+  zip archive.
+
 * With -v option, git-branch describes the remote tracking statistics
   similar to the way git-checkout reports by how many commits your branch
   is ahead/behind.
@@ -144,6 +158,8 @@
 * git-clone can clone from a remote whose URL would be rewritten by
   configuration stored in $HOME/.gitconfig now.
 
+* git-cvsserver learned to respond to "cvs co -c".
+
 * git-diff --check now checks leftover merge conflict markers.
 
 * When remote side used to have branch 'foo' and git-fetch finds that now
@@ -155,6 +171,8 @@
 * fast-export learned to export and import marks file; this can be used to
   interface with fast-import incrementally.
 
+* fast-import and fast-export learned to export and import gitlinks.
+
 * git-rebase records the original tip of branch in ORIG_HEAD before it is
   rewound.
 
@@ -188,6 +206,8 @@
 
 (internal)
 
+* git-merge has been reimplemented in C.
+
 
 Fixes since v1.5.6
 ------------------
@@ -195,12 +215,8 @@
 All of the fixes in v1.5.6 maintenance series are included in
 this release, unless otherwise noted.
 
- * "git fetch" into an empty repository used to remind the fetch will
-   be huge by saying "no common commits", but it is already known by
-   the user anyway (need to backport 8cb560f to 'maint').
-
 ---
 exec >/var/tmp/1
-O=v1.5.6.3-350-g499027b
+O=v1.5.6.4-432-g6796399
 echo O=$(git describe refs/heads/master)
 git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index 3558905..2b6d6c8 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -9,7 +9,7 @@
 --------
 [verse]
 'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
-	  [--update | -u] [--refresh] [--ignore-errors] [--]
+	  [--all | [--update | -u]] [--refresh] [--ignore-errors] [--]
 	  <filepattern>...
 
 DESCRIPTION
@@ -86,6 +86,12 @@
 	command line. If no paths are specified, all tracked files in the
 	current directory and its subdirectories are updated.
 
+-A::
+--all::
+	Update files that git already knows about (same as '\--update')
+	and add all untracked files that are not ignored by '.gitignore'
+	mechanism.
+
 --refresh::
 	Don't add the file(s), but only refresh their stat()
 	information in the index.
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 2d7f162..e010a16 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -13,7 +13,7 @@
          [--3way] [--interactive] [--binary]
          [--whitespace=<option>] [-C<n>] [-p<n>]
 	 [<mbox> | <Maildir>...]
-'git am' (--skip | --resolved)
+'git am' (--skip | --resolved | --abort)
 
 DESCRIPTION
 -----------
@@ -99,6 +99,9 @@
 	or `--skip` to handle the failure.  This is solely
 	for internal use between 'git-rebase' and 'git-am'.
 
+--abort::
+	Restore the original branch and abort the patching operation.
+
 DISCUSSION
 ----------
 
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index a691173..50fb3d5 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -58,14 +58,14 @@
 	Usually the command automatically creates a commit with
 	a commit log message stating which commit was
 	cherry-picked.  This flag applies the change necessary
-	to cherry-pick the named commit to your working tree,
-	but does not make the commit.  In addition, when this
-	option is used, your working tree does not have to match
+	to cherry-pick the named commit to your working tree
+	and the index, but does not make the commit.  In addition,
+	when this option is used, your index does not have to match
 	the HEAD commit.  The cherry-pick is done against the
-	beginning state of your working tree.
+	beginning state of your index.
 +
 This is useful when cherry-picking more than one commits'
-effect to your working tree in a row.
+effect to your index in a row.
 
 -s::
 --signoff::
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index 2d01d0d..c2f483a 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -481,6 +481,9 @@
   what you want.
 * `100755` or `755`: A normal, but executable, file.
 * `120000`: A symlink, the content of the file will be the link target.
+* `160000`: A gitlink, SHA-1 of the object refers to a commit in
+  another repository. Git links can only be specified by SHA or through
+  a commit mark. They are used to implement submodules.
 
 In both formats `<path>` is the complete path of the file to be added
 (if not already existing) or modified (if already existing).
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 019e4ca..a7487d3 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -57,50 +57,31 @@
 
 A merge is always between the current `HEAD` and one or more
 commits (usually, branch head or tag), and the index file must
-exactly match the
-tree of `HEAD` commit (i.e. the contents of the last commit) when
-it happens.  In other words, `git diff --cached HEAD` must
-report no changes.
+match the tree of `HEAD` commit (i.e. the contents of the last commit)
+when it starts out.  In other words, `git diff --cached HEAD` must
+report no changes.  (One exception is when the changed index
+entries are already in the same state that would result from
+the merge anyway.)
 
-[NOTE]
-This is a bit of a lie.  In certain special cases, your index is
-allowed to be different from the tree of the `HEAD` commit.  The most
-notable case is when your `HEAD` commit is already ahead of what
-is being merged, in which case your index can have arbitrary
-differences from your `HEAD` commit.  Also, your index entries
-may have differences from your `HEAD` commit that match
-the result of a trivial merge (e.g. you received the same patch
-from an external source to produce the same result as what you are
-merging).  For example, if a path did not exist in the common
-ancestor and your head commit but exists in the tree you are
-merging into your repository, and if you already happen to have
-that path exactly in your index, the merge does not have to
-fail.
+Three kinds of merge can happen:
 
-Otherwise, merge will refuse to do any harm to your repository
-(that is, it may fetch the objects from remote, and it may even
-update the local branch used to keep track of the remote branch
-with `git pull remote rbranch:lbranch`, but your working tree,
-`.git/HEAD` pointer and index file are left intact).  In addition,
-merge always sets `.git/ORIG_HEAD` to the original state of HEAD so
-a problematic merge can be removed by using `git reset ORIG_HEAD`.
+* The merged commit is already contained in `HEAD`. This is the
+  simplest case, called "Already up-to-date."
 
-You may have local modifications in the working tree files.  In
-other words, 'git-diff' is allowed to report changes.
-However, the merge uses your working tree as the working area,
-and in order to prevent the merge operation from losing such
-changes, it makes sure that they do not interfere with the
-merge. Those complex tables in read-tree documentation define
-what it means for a path to "interfere with the merge".  And if
-your local modifications interfere with the merge, again, it
-stops before touching anything.
+* `HEAD` is already contained in the merged commit. This is the
+  most common case especially when involved through 'git pull':
+  you are tracking an upstream repository, committed no local
+  changes and now you want to update to a newer upstream revision.
+  Your `HEAD` (and the index) is updated to at point the merged
+  commit, without creating an extra merge commit.  This is
+  called "Fast-forward".
 
-So in the above two "failed merge" case, you do not have to
-worry about loss of data --- you simply were not ready to do
-a merge, so no merge happened at all.  You may want to finish
-whatever you were in the middle of doing, and retry the same
-pull after you are done and ready.
+* Both the merged commit and `HEAD` are independent and must be
+  tied together by a merge commit that has them both as its parents.
+  The rest of this section describes this "True merge" case.
 
+The chosen merge strategy merges the two commits into a single
+new source tree.
 When things cleanly merge, these things happen:
 
 1. The results are updated both in the index file and in your
@@ -142,12 +123,13 @@
 
  * Decide not to merge.  The only clean-up you need are to reset
    the index file to the `HEAD` commit to reverse 2. and to clean
-   up working tree changes made by 2. and 3.; 'git-reset' can
+   up working tree changes made by 2. and 3.; 'git-reset --hard' can
    be used for this.
 
  * Resolve the conflicts.  `git diff` would report only the
-   conflicting paths because of the above 2. and 3.  Edit the
-   working tree files into a desirable shape, 'git-add' or 'git-rm'
+   conflicting paths because of the above 2. and 3.
+   Edit the working tree files into a desirable shape
+   ('git mergetool' can ease this task), 'git-add' or 'git-rm'
    them, to make the index file contain what the merge result
    should be, and run 'git-commit' to commit the result.
 
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 5411edc..271850f 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -43,16 +43,16 @@
 -n::
 --no-commit::
 	Usually the command automatically creates a commit with
-	a commit log message stating which commit was reverted.
-	This flag applies the change necessary to revert the
-	named commit to your working tree, but does not make the
-	commit.  In addition, when this option is used, your
-	working tree does not have to match the HEAD commit.
-	The revert is done against the beginning state of your
-	working tree.
+	a commit log message stating which commit was
+	reverted.  This flag applies the change necessary
+	to revert the named commit to your working tree
+	and the index, but does not make the commit.  In addition,
+	when this option is used, your index does not have to match
+	the HEAD commit.  The revert is done against the
+	beginning state of your index.
 +
 This is useful when reverting more than one commits'
-effect to your working tree in a row.
+effect to your index in a row.
 
 -s::
 --signoff::
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index 76702a0..829b032 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -16,6 +16,48 @@
 'git submodule' [--quiet] summary [--summary-limit <n>] [commit] [--] [<path>...]
 
 
+DESCRIPTION
+-----------
+Submodules allow foreign repositories to be embedded within
+a dedicated subdirectory of the source tree, always pointed
+at a particular commit.
+
+They are not to be confused with remotes, which are meant mainly
+for branches of the same project; submodules are meant for
+different projects you would like to make part of your source tree,
+while the history of the two projects still stays completely
+independent and you cannot modify the contents of the submodule
+from within the main project.
+If you want to merge the project histories and want to treat the
+aggregated whole as a single project from then on, you may want to
+add a remote for the other project and use the 'subtree' merge strategy,
+instead of treating the other project as a submodule. Directories
+that come from both projects can be cloned and checked out as a whole
+if you choose to go that route.
+
+Submodules are composed from a so-called `gitlink` tree entry
+in the main repository that refers to a particular commit object
+within the inner repository that is completely separate.
+A record in the `.gitmodules` file at the root of the source
+tree assigns a logical name to the submodule and describes
+the default URL the submodule shall be cloned from.
+The logical name can be used for overriding this URL within your
+local repository configuration (see 'submodule init').
+
+This command will manage the tree entries and contents of the
+gitmodules file for you, as well as inspect the status of your
+submodules and update them.
+When adding a new submodule to the tree, the 'add' subcommand
+is to be used.  However, when pulling a tree containing submodules,
+these will not be checked out by default;
+the 'init' and 'update' subcommands will maintain submodules
+checked out and at appropriate revision in your working tree.
+You can briefly inspect the up-to-date status of your submodules
+using the 'status' subcommand and get a detailed overview of the
+difference between the index and checkouts using the 'summary'
+subcommand.
+
+
 COMMANDS
 --------
 add::
@@ -56,10 +98,15 @@
 	repository. This command is the default command for 'git-submodule'.
 
 init::
-	Initialize the submodules, i.e. register in .git/config each submodule
-	name and url found in .gitmodules. The key used in .git/config is
-	`submodule.$name.url`. This command does not alter existing information
-	in .git/config.
+	Initialize the submodules, i.e. register each submodule name
+	and url found in .gitmodules into .git/config.
+	The key used in .git/config is `submodule.$name.url`.
+	This command does not alter existing information in .git/config.
+	You can then customize the submodule clone URLs in .git/config
+	for your local setup and proceed to 'git submodule update';
+	you can also just use 'git submodule update --init' without
+	the explicit 'init' step if you do not intend to customize
+	any submodule locations.
 
 update::
 	Update the registered submodules, i.e. clone missing submodules and
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index a91fd21..6b930bc 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -88,6 +88,16 @@
 	sometimes helpful when working with a big project on a
 	filesystem that has very slow lstat(2) system call
 	(e.g. cifs).
++
+This option can be also used as a coarse file-level mechanism
+to ignore uncommitted changes in tracked files (akin to what
+`.gitignore` does for untracked files).
+You should remember that an explicit 'git add' operation will
+still cause the file to be refreshed from the working tree.
+Git will fail (gracefully) in case it needs to modify this file
+in the index e.g. when merging in a commit;
+thus, in case the assumed-untracked file is changed upstream,
+you will need to handle the situation manually.
 
 -g::
 --again::
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 27b9d31..44ea35e 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,12 +43,13 @@
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.5.6.3/git.html[documentation for release 1.5.6.3]
+* link:v1.5.6.4/git.html[documentation for release 1.5.6.4]
 
 * release notes for
-  link:RelNotes-1.5.6.3.txt[1.5.6.3].
-  link:RelNotes-1.5.6.2.txt[1.5.6.2].
-  link:RelNotes-1.5.6.1.txt[1.5.6.1].
+  link:RelNotes-1.5.6.4.txt[1.5.6.4],
+  link:RelNotes-1.5.6.3.txt[1.5.6.3],
+  link:RelNotes-1.5.6.2.txt[1.5.6.2],
+  link:RelNotes-1.5.6.1.txt[1.5.6.1],
   link:RelNotes-1.5.6.txt[1.5.6].
 
 * link:v1.5.5.4/git.html[documentation for release 1.5.5.4]
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index fc0efd8..59321a2 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -13,9 +13,14 @@
 -----------
 
 A `gitignore` file specifies intentionally untracked files that
-git should ignore.  Each line in a `gitignore` file specifies a
-pattern.
+git should ignore.
+Note that all the `gitignore` files really concern only files
+that are not already tracked by git;
+in order to ignore uncommitted changes in already tracked files,
+please refer to the 'git update-index --assume-unchanged'
+documentation.
 
+Each line in a `gitignore` file specifies a pattern.
 When deciding whether to ignore a path, git normally checks
 `gitignore` patterns from multiple sources, with the following
 order of precedence, from highest to lowest (within one level of
diff --git a/Documentation/technical/api-run-command.txt b/Documentation/technical/api-run-command.txt
index 3e1342a..75aa5d4 100644
--- a/Documentation/technical/api-run-command.txt
+++ b/Documentation/technical/api-run-command.txt
@@ -30,7 +30,7 @@
 	start_command() followed by finish_command(). Takes a pointer
 	to a `struct child_process` that specifies the details.
 
-`run_command_v_opt`, `run_command_v_opt_dir`, `run_command_v_opt_cd_env`::
+`run_command_v_opt`, `run_command_v_opt_cd`, `run_command_v_opt_cd_env`::
 
 	Convenience functions that encapsulate a sequence of
 	start_command() followed by finish_command(). The argument argv
diff --git a/Makefile b/Makefile
index 9b52071..551bde9 100644
--- a/Makefile
+++ b/Makefile
@@ -324,6 +324,7 @@
 export PERL_PATH
 
 LIB_FILE=libgit.a
+COMPAT_LIB = compat/lib.a
 XDIFF_LIB=xdiff/lib.a
 
 LIB_H += archive.h
@@ -741,7 +742,7 @@
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat
 	COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
-	COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o
+	COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o compat/winansi.o
 	EXTLIBS += -lws2_32
 	X = .exe
 	template_dir = ../share/git-core/templates/
@@ -1203,6 +1204,12 @@
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
 
+$(COMPAT_LIB): $(COMPAT_OBJS)
+	$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(COMPAT_OBJS)
+
+git-shell$X: abspath.o ctype.o exec_cmd.o quote.o strbuf.o usage.o wrapper.o shell.o $(COMPAT_LIB)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(COMPAT_LIB)
+
 $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
 $(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
 builtin-revert.o wt-status.o: wt-status.h
@@ -1298,7 +1305,7 @@
 	for i in *.c; do sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; done
 
 remove-dashes:
-	./fixup-builtins $(BUILT_INS)
+	./fixup-builtins $(BUILT_INS) $(PROGRAMS) $(SCRIPTS)
 
 ### Installation rules
 
@@ -1399,7 +1406,7 @@
 
 clean:
 	$(RM) *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o xdiff/*.o \
-		$(LIB_FILE) $(XDIFF_LIB)
+		$(LIB_FILE) $(XDIFF_LIB) $(COMPAT_LIB)
 	$(RM) $(ALL_PROGRAMS) $(BUILT_INS) git$X
 	$(RM) $(TEST_PROGRAMS)
 	$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope*
diff --git a/archive-tar.c b/archive-tar.c
index 99db58f..1302961 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -2,9 +2,7 @@
  * Copyright (c) 2005, 2006 Rene Scharfe
  */
 #include "cache.h"
-#include "commit.h"
 #include "tar.h"
-#include "builtin.h"
 #include "archive.h"
 
 #define RECORDSIZE	(512)
@@ -13,11 +11,7 @@
 static char block[BLOCKSIZE];
 static unsigned long offset;
 
-static time_t archive_time;
 static int tar_umask = 002;
-static int verbose;
-static const struct commit *commit;
-static size_t base_len;
 
 /* writes out the whole block, but only if it is full */
 static void write_if_needed(void)
@@ -114,22 +108,24 @@
 	return chksum;
 }
 
-static int get_path_prefix(const struct strbuf *path, int maxlen)
+static size_t get_path_prefix(const char *path, size_t pathlen, size_t maxlen)
 {
-	int i = path->len;
+	size_t i = pathlen;
 	if (i > maxlen)
 		i = maxlen;
 	do {
 		i--;
-	} while (i > 0 && path->buf[i] != '/');
+	} while (i > 0 && path[i] != '/');
 	return i;
 }
 
-static void write_entry(const unsigned char *sha1, struct strbuf *path,
-                        unsigned int mode, void *buffer, unsigned long size)
+static int write_tar_entry(struct archiver_args *args,
+		const unsigned char *sha1, const char *path, size_t pathlen,
+		unsigned int mode, void *buffer, unsigned long size)
 {
 	struct ustar_header header;
 	struct strbuf ext_header;
+	int err = 0;
 
 	memset(&header, 0, sizeof(header));
 	strbuf_init(&ext_header, 0);
@@ -143,8 +139,6 @@
 		mode = 0100666;
 		sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1));
 	} else {
-		if (verbose)
-			fprintf(stderr, "%.*s\n", (int)path->len, path->buf);
 		if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
 			*header.typeflag = TYPEFLAG_DIR;
 			mode = (mode | 0777) & ~tar_umask;
@@ -155,24 +149,24 @@
 			*header.typeflag = TYPEFLAG_REG;
 			mode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask;
 		} else {
-			error("unsupported file mode: 0%o (SHA1: %s)",
-			      mode, sha1_to_hex(sha1));
-			return;
+			return error("unsupported file mode: 0%o (SHA1: %s)",
+					mode, sha1_to_hex(sha1));
 		}
-		if (path->len > sizeof(header.name)) {
-			int plen = get_path_prefix(path, sizeof(header.prefix));
-			int rest = path->len - plen - 1;
+		if (pathlen > sizeof(header.name)) {
+			size_t plen = get_path_prefix(path, pathlen,
+					sizeof(header.prefix));
+			size_t rest = pathlen - plen - 1;
 			if (plen > 0 && rest <= sizeof(header.name)) {
-				memcpy(header.prefix, path->buf, plen);
-				memcpy(header.name, path->buf + plen + 1, rest);
+				memcpy(header.prefix, path, plen);
+				memcpy(header.name, path + plen + 1, rest);
 			} else {
 				sprintf(header.name, "%s.data",
 				        sha1_to_hex(sha1));
 				strbuf_append_ext_header(&ext_header, "path",
-				                         path->buf, path->len);
+						path, pathlen);
 			}
 		} else
-			memcpy(header.name, path->buf, path->len);
+			memcpy(header.name, path, pathlen);
 	}
 
 	if (S_ISLNK(mode) && buffer) {
@@ -187,7 +181,7 @@
 
 	sprintf(header.mode, "%07o", mode & 07777);
 	sprintf(header.size, "%011lo", S_ISREG(mode) ? size : 0);
-	sprintf(header.mtime, "%011lo", archive_time);
+	sprintf(header.mtime, "%011lo", args->time);
 
 	sprintf(header.uid, "%07o", 0);
 	sprintf(header.gid, "%07o", 0);
@@ -202,22 +196,30 @@
 	sprintf(header.chksum, "%07o", ustar_header_chksum(&header));
 
 	if (ext_header.len > 0) {
-		write_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);
+		err = write_tar_entry(args, sha1, NULL, 0, 0, ext_header.buf,
+				ext_header.len);
+		if (err)
+			return err;
 	}
 	strbuf_release(&ext_header);
 	write_blocked(&header, sizeof(header));
 	if (S_ISREG(mode) && buffer && size > 0)
 		write_blocked(buffer, size);
+	return err;
 }
 
-static void write_global_extended_header(const unsigned char *sha1)
+static int write_global_extended_header(struct archiver_args *args)
 {
+	const unsigned char *sha1 = args->commit_sha1;
 	struct strbuf ext_header;
+	int err;
 
 	strbuf_init(&ext_header, 0);
 	strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40);
-	write_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);
+	err = write_tar_entry(args, NULL, NULL, 0, 0, ext_header.buf,
+			ext_header.len);
 	strbuf_release(&ext_header);
+	return err;
 }
 
 static int git_tar_config(const char *var, const char *value, void *cb)
@@ -234,64 +236,17 @@
 	return git_default_config(var, value, cb);
 }
 
-static int write_tar_entry(const unsigned char *sha1,
-                           const char *base, int baselen,
-                           const char *filename, unsigned mode, int stage)
-{
-	static struct strbuf path = STRBUF_INIT;
-	void *buffer;
-	enum object_type type;
-	unsigned long size;
-
-	strbuf_reset(&path);
-	strbuf_grow(&path, PATH_MAX);
-	strbuf_add(&path, base, baselen);
-	strbuf_addstr(&path, filename);
-	if (is_archive_path_ignored(path.buf + base_len))
-		return 0;
-	if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
-		strbuf_addch(&path, '/');
-		buffer = NULL;
-		size = 0;
-	} else {
-		buffer = sha1_file_to_archive(path.buf + base_len, sha1, mode,
-				&type, &size, commit);
-		if (!buffer)
-			die("cannot read %s", sha1_to_hex(sha1));
-	}
-
-	write_entry(sha1, &path, mode, buffer, size);
-	free(buffer);
-
-	return READ_TREE_RECURSIVE;
-}
-
 int write_tar_archive(struct archiver_args *args)
 {
-	int plen = args->base ? strlen(args->base) : 0;
+	int err = 0;
 
 	git_config(git_tar_config, NULL);
 
-	archive_time = args->time;
-	verbose = args->verbose;
-	commit = args->commit;
-	base_len = args->base ? strlen(args->base) : 0;
-
 	if (args->commit_sha1)
-		write_global_extended_header(args->commit_sha1);
-
-	if (args->base && plen > 0 && args->base[plen - 1] == '/') {
-		char *base = xstrdup(args->base);
-		int baselen = strlen(base);
-
-		while (baselen > 0 && base[baselen - 1] == '/')
-			base[--baselen] = '\0';
-		write_tar_entry(args->tree->object.sha1, "", 0, base, 040777, 0);
-		free(base);
-	}
-	read_tree_recursive(args->tree, args->base, plen, 0,
-			    args->pathspec, write_tar_entry);
-	write_trailer();
-
-	return 0;
+		err = write_global_extended_header(args);
+	if (!err)
+		err = write_archive_entries(args, write_tar_entry);
+	if (!err)
+		write_trailer();
+	return err;
 }
diff --git a/archive-zip.c b/archive-zip.c
index 5742762..cf28504 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -2,18 +2,10 @@
  * Copyright (c) 2006 Rene Scharfe
  */
 #include "cache.h"
-#include "commit.h"
-#include "blob.h"
-#include "tree.h"
-#include "quote.h"
-#include "builtin.h"
 #include "archive.h"
 
-static int verbose;
 static int zip_date;
 static int zip_time;
-static const struct commit *commit;
-static size_t base_len;
 
 static unsigned char *zip_dir;
 static unsigned int zip_dir_size;
@@ -96,7 +88,7 @@
 }
 
 static void *zlib_deflate(void *data, unsigned long size,
-                          unsigned long *compressed_size)
+		int compression_level, unsigned long *compressed_size)
 {
 	z_stream stream;
 	unsigned long maxsize;
@@ -104,7 +96,7 @@
 	int result;
 
 	memset(&stream, 0, sizeof(stream));
-	deflateInit(&stream, zlib_compression_level);
+	deflateInit(&stream, compression_level);
 	maxsize = deflateBound(&stream, size);
 	buffer = xmalloc(maxsize);
 
@@ -128,33 +120,9 @@
 	return buffer;
 }
 
-static char *construct_path(const char *base, int baselen,
-                            const char *filename, int isdir, int *pathlen)
-{
-	int filenamelen = strlen(filename);
-	int len = baselen + filenamelen;
-	char *path, *p;
-
-	if (isdir)
-		len++;
-	p = path = xmalloc(len + 1);
-
-	memcpy(p, base, baselen);
-	p += baselen;
-	memcpy(p, filename, filenamelen);
-	p += filenamelen;
-	if (isdir)
-		*p++ = '/';
-	*p = '\0';
-
-	*pathlen = len;
-
-	return path;
-}
-
-static int write_zip_entry(const unsigned char *sha1,
-                           const char *base, int baselen,
-                           const char *filename, unsigned mode, int stage)
+static int write_zip_entry(struct archiver_args *args,
+		const unsigned char *sha1, const char *path, size_t pathlen,
+		unsigned int mode, void *buffer, unsigned long size)
 {
 	struct zip_local_header header;
 	struct zip_dir_header dirent;
@@ -163,33 +131,20 @@
 	unsigned long uncompressed_size;
 	unsigned long crc;
 	unsigned long direntsize;
-	unsigned long size;
 	int method;
-	int result = -1;
-	int pathlen;
 	unsigned char *out;
-	char *path;
-	enum object_type type;
-	void *buffer = NULL;
 	void *deflated = NULL;
 
 	crc = crc32(0, NULL, 0);
 
-	path = construct_path(base, baselen, filename, S_ISDIR(mode), &pathlen);
-	if (is_archive_path_ignored(path + base_len))
-		return 0;
-	if (verbose)
-		fprintf(stderr, "%s\n", path);
 	if (pathlen > 0xffff) {
-		error("path too long (%d chars, SHA1: %s): %s", pathlen,
-		      sha1_to_hex(sha1), path);
-		goto out;
+		return error("path too long (%d chars, SHA1: %s): %s",
+				(int)pathlen, sha1_to_hex(sha1), path);
 	}
 
 	if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
 		method = 0;
 		attr2 = 16;
-		result = (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
 		out = NULL;
 		uncompressed_size = 0;
 		compressed_size = 0;
@@ -197,25 +152,20 @@
 		method = 0;
 		attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) :
 			(mode & 0111) ? ((mode) << 16) : 0;
-		if (S_ISREG(mode) && zlib_compression_level != 0)
+		if (S_ISREG(mode) && args->compression_level != 0)
 			method = 8;
-		result = 0;
-		buffer = sha1_file_to_archive(path + base_len, sha1, mode,
-				&type, &size, commit);
-		if (!buffer)
-			die("cannot read %s", sha1_to_hex(sha1));
 		crc = crc32(crc, buffer, size);
 		out = buffer;
 		uncompressed_size = size;
 		compressed_size = size;
 	} else {
-		error("unsupported file mode: 0%o (SHA1: %s)", mode,
-		      sha1_to_hex(sha1));
-		goto out;
+		return error("unsupported file mode: 0%o (SHA1: %s)", mode,
+				sha1_to_hex(sha1));
 	}
 
 	if (method == 8) {
-		deflated = zlib_deflate(buffer, size, &compressed_size);
+		deflated = zlib_deflate(buffer, size, args->compression_level,
+				&compressed_size);
 		if (deflated && compressed_size - 6 < size) {
 			/* ZLIB --> raw compressed data (see RFC 1950) */
 			/* CMF and FLG ... */
@@ -278,12 +228,9 @@
 		zip_offset += compressed_size;
 	}
 
-out:
-	free(buffer);
 	free(deflated);
-	free(path);
 
-	return result;
+	return 0;
 }
 
 static void write_zip_trailer(const unsigned char *sha1)
@@ -316,43 +263,18 @@
 
 int write_zip_archive(struct archiver_args *args)
 {
-	int plen = strlen(args->base);
+	int err;
 
 	dos_time(&args->time, &zip_date, &zip_time);
 
 	zip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE);
 	zip_dir_size = ZIP_DIRECTORY_MIN_SIZE;
-	verbose = args->verbose;
-	commit = args->commit;
-	base_len = args->base ? strlen(args->base) : 0;
 
-	if (args->base && plen > 0 && args->base[plen - 1] == '/') {
-		char *base = xstrdup(args->base);
-		int baselen = strlen(base);
-
-		while (baselen > 0 && base[baselen - 1] == '/')
-			base[--baselen] = '\0';
-		write_zip_entry(args->tree->object.sha1, "", 0, base, 040777, 0);
-		free(base);
-	}
-	read_tree_recursive(args->tree, args->base, plen, 0,
-			    args->pathspec, write_zip_entry);
-	write_zip_trailer(args->commit_sha1);
+	err = write_archive_entries(args, write_zip_entry);
+	if (!err)
+		write_zip_trailer(args->commit_sha1);
 
 	free(zip_dir);
 
-	return 0;
-}
-
-void *parse_extra_zip_args(int argc, const char **argv)
-{
-	for (; argc > 0; argc--, argv++) {
-		const char *arg = argv[0];
-
-		if (arg[0] == '-' && isdigit(arg[1]) && arg[2] == '\0')
-			zlib_compression_level = arg[1] - '0';
-		else
-			die("Unknown argument for zip format: %s", arg);
-	}
-	return NULL;
+	return err;
 }
diff --git a/archive.c b/archive.c
index 6502b76..b8b45ba 100644
--- a/archive.c
+++ b/archive.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "commit.h"
 #include "attr.h"
+#include "archive.h"
 
 static void format_subst(const struct commit *commit,
                          const char *src, size_t len,
@@ -35,34 +36,9 @@
 	free(to_free);
 }
 
-static int convert_to_archive(const char *path,
-                              const void *src, size_t len,
-                              struct strbuf *buf,
-                              const struct commit *commit)
-{
-	static struct git_attr *attr_export_subst;
-	struct git_attr_check check[1];
-
-	if (!commit)
-		return 0;
-
-	if (!attr_export_subst)
-		attr_export_subst = git_attr("export-subst", 12);
-
-	check[0].attr = attr_export_subst;
-	if (git_checkattr(path, ARRAY_SIZE(check), check))
-		return 0;
-	if (!ATTR_TRUE(check[0].value))
-		return 0;
-
-	format_subst(commit, src, len, buf);
-	return 1;
-}
-
-void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
-                           unsigned int mode, enum object_type *type,
-                           unsigned long *sizep,
-                           const struct commit *commit)
+static void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
+		unsigned int mode, enum object_type *type,
+		unsigned long *sizep, const struct commit *commit)
 {
 	void *buffer;
 
@@ -74,7 +50,8 @@
 		strbuf_init(&buf, 0);
 		strbuf_attach(&buf, buffer, *sizep, *sizep + 1);
 		convert_to_working_tree(path, buf.buf, buf.len, &buf);
-		convert_to_archive(path, buf.buf, buf.len, &buf, commit);
+		if (commit)
+			format_subst(commit, buf.buf, buf.len, &buf);
 		buffer = strbuf_detach(&buf, &size);
 		*sizep = size;
 	}
@@ -82,16 +59,99 @@
 	return buffer;
 }
 
-int is_archive_path_ignored(const char *path)
+static void setup_archive_check(struct git_attr_check *check)
 {
 	static struct git_attr *attr_export_ignore;
-	struct git_attr_check check[1];
+	static struct git_attr *attr_export_subst;
 
-	if (!attr_export_ignore)
+	if (!attr_export_ignore) {
 		attr_export_ignore = git_attr("export-ignore", 13);
-
+		attr_export_subst = git_attr("export-subst", 12);
+	}
 	check[0].attr = attr_export_ignore;
-	if (git_checkattr(path, ARRAY_SIZE(check), check))
-		return 0;
-	return ATTR_TRUE(check[0].value);
+	check[1].attr = attr_export_subst;
+}
+
+struct archiver_context {
+	struct archiver_args *args;
+	write_archive_entry_fn_t write_entry;
+};
+
+static int write_archive_entry(const unsigned char *sha1, const char *base,
+		int baselen, const char *filename, unsigned mode, int stage,
+		void *context)
+{
+	static struct strbuf path = STRBUF_INIT;
+	struct archiver_context *c = context;
+	struct archiver_args *args = c->args;
+	write_archive_entry_fn_t write_entry = c->write_entry;
+	struct git_attr_check check[2];
+	const char *path_without_prefix;
+	int convert = 0;
+	int err;
+	enum object_type type;
+	unsigned long size;
+	void *buffer;
+
+	strbuf_reset(&path);
+	strbuf_grow(&path, PATH_MAX);
+	strbuf_add(&path, base, baselen);
+	strbuf_addstr(&path, filename);
+	path_without_prefix = path.buf + args->baselen;
+
+	setup_archive_check(check);
+	if (!git_checkattr(path_without_prefix, ARRAY_SIZE(check), check)) {
+		if (ATTR_TRUE(check[0].value))
+			return 0;
+		convert = ATTR_TRUE(check[1].value);
+	}
+
+	if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
+		strbuf_addch(&path, '/');
+		if (args->verbose)
+			fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
+		err = write_entry(args, sha1, path.buf, path.len, mode, NULL, 0);
+		if (err)
+			return err;
+		return READ_TREE_RECURSIVE;
+	}
+
+	buffer = sha1_file_to_archive(path_without_prefix, sha1, mode,
+			&type, &size, convert ? args->commit : NULL);
+	if (!buffer)
+		return error("cannot read %s", sha1_to_hex(sha1));
+	if (args->verbose)
+		fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
+	err = write_entry(args, sha1, path.buf, path.len, mode, buffer, size);
+	free(buffer);
+	return err;
+}
+
+int write_archive_entries(struct archiver_args *args,
+		write_archive_entry_fn_t write_entry)
+{
+	struct archiver_context context;
+	int err;
+
+	if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
+		size_t len = args->baselen;
+
+		while (len > 1 && args->base[len - 2] == '/')
+			len--;
+		if (args->verbose)
+			fprintf(stderr, "%.*s\n", (int)len, args->base);
+		err = write_entry(args, args->tree->object.sha1, args->base,
+				len, 040777, NULL, 0);
+		if (err)
+			return err;
+	}
+
+	context.args = args;
+	context.write_entry = write_entry;
+
+	err =  read_tree_recursive(args->tree, args->base, args->baselen, 0,
+			args->pathspec, write_archive_entry, &context);
+	if (err == READ_TREE_RECURSIVE)
+		err = 0;
+	return err;
 }
diff --git a/archive.h b/archive.h
index ddf004a..4a02371 100644
--- a/archive.h
+++ b/archive.h
@@ -6,29 +6,27 @@
 
 struct archiver_args {
 	const char *base;
+	size_t baselen;
 	struct tree *tree;
 	const unsigned char *commit_sha1;
 	const struct commit *commit;
 	time_t time;
 	const char **pathspec;
 	unsigned int verbose : 1;
-	void *extra;
+	int compression_level;
 };
 
 typedef int (*write_archive_fn_t)(struct archiver_args *);
 
-typedef void *(*parse_extra_args_fn_t)(int argc, const char **argv);
+typedef int (*write_archive_entry_fn_t)(struct archiver_args *args, const unsigned char *sha1, const char *path, size_t pathlen, unsigned int mode, void *buffer, unsigned long size);
 
 struct archiver {
 	const char *name;
-	struct archiver_args args;
 	write_archive_fn_t write_archive;
-	parse_extra_args_fn_t parse_extra;
+	unsigned int flags;
 };
 
-extern int parse_archive_args(int argc,
-			      const char **argv,
-			      struct archiver *ar);
+extern int parse_archive_args(int argc, const char **argv, const struct archiver **ar, struct archiver_args *args);
 
 extern void parse_treeish_arg(const char **treeish,
 			      struct archiver_args *ar_args,
@@ -41,9 +39,7 @@
  */
 extern int write_tar_archive(struct archiver_args *);
 extern int write_zip_archive(struct archiver_args *);
-extern void *parse_extra_zip_args(int argc, const char **argv);
 
-extern void *sha1_file_to_archive(const char *path, const unsigned char *sha1, unsigned int mode, enum object_type *type, unsigned long *size, const struct commit *commit);
-extern int is_archive_path_ignored(const char *path);
+extern int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry);
 
 #endif	/* ARCHIVE_H */
diff --git a/attr.c b/attr.c
index 0fb47d3..17f6a4d 100644
--- a/attr.c
+++ b/attr.c
@@ -459,7 +459,9 @@
 {
 	struct attr_stack *elem, *info;
 	int len;
-	char pathbuf[PATH_MAX];
+	struct strbuf pathbuf;
+
+	strbuf_init(&pathbuf, dirlen+2+strlen(GITATTRIBUTES_FILE));
 
 	/*
 	 * At the bottom of the attribute stack is the built-in
@@ -510,13 +512,14 @@
 			len = strlen(attr_stack->origin);
 			if (dirlen <= len)
 				break;
-			memcpy(pathbuf, path, dirlen);
-			memcpy(pathbuf + dirlen, "/", 2);
-			cp = strchr(pathbuf + len + 1, '/');
+			strbuf_reset(&pathbuf);
+			strbuf_add(&pathbuf, path, dirlen);
+			strbuf_addch(&pathbuf, '/');
+			cp = strchr(pathbuf.buf + len + 1, '/');
 			strcpy(cp + 1, GITATTRIBUTES_FILE);
-			elem = read_attr(pathbuf, 0);
+			elem = read_attr(pathbuf.buf, 0);
 			*cp = '\0';
-			elem->origin = strdup(pathbuf);
+			elem->origin = strdup(pathbuf.buf);
 			elem->prev = attr_stack;
 			attr_stack = elem;
 			debug_push(elem);
diff --git a/builtin-add.c b/builtin-add.c
index 9930cf5..fc3f96e 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -16,7 +16,7 @@
 #include "parse-options.h"
 
 static const char * const builtin_add_usage[] = {
-	"git-add [options] [--] <filepattern>...",
+	"git add [options] [--] <filepattern>...",
 	NULL
 };
 static int patch_interactive = 0, add_interactive = 0;
@@ -140,9 +140,8 @@
 	for (specs = 0; pathspec[specs];  specs++)
 		/* nothing */;
 	seen = xcalloc(specs, 1);
-	if (read_cache() < 0)
-		die("index file corrupt");
-	refresh_index(&the_index, verbose ? 0 : REFRESH_QUIET, pathspec, seen);
+	refresh_index(&the_index, verbose ? REFRESH_SAY_CHANGED : REFRESH_QUIET,
+		      pathspec, seen);
 	for (i = 0; i < specs; i++) {
 		if (!seen[i])
 			die("pathspec '%s' did not match any files", pathspec[i]);
@@ -192,7 +191,7 @@
 "The following paths are ignored by one of your .gitignore files:\n";
 
 static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
-static int ignore_add_errors;
+static int ignore_add_errors, addremove;
 
 static struct option builtin_add_options[] = {
 	OPT__DRY_RUN(&show_only),
@@ -202,6 +201,7 @@
 	OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
 	OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored files"),
 	OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
+	OPT_BOOLEAN('A', "all", &addremove, "add all, noticing removal of tracked files"),
 	OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
 	OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"),
 	OPT_END(),
@@ -216,13 +216,36 @@
 	return git_default_config(var, value, cb);
 }
 
+static int add_files(struct dir_struct *dir, int flags)
+{
+	int i, exit_status = 0;
+
+	if (dir->ignored_nr) {
+		fprintf(stderr, ignore_error);
+		for (i = 0; i < dir->ignored_nr; i++)
+			fprintf(stderr, "%s\n", dir->ignored[i]->name);
+		fprintf(stderr, "Use -f if you really want to add them.\n");
+		die("no files added");
+	}
+
+	for (i = 0; i < dir->nr; i++)
+		if (add_file_to_cache(dir->entries[i]->name, flags)) {
+			if (!ignore_add_errors)
+				die("adding files failed");
+			exit_status = 1;
+		}
+	return exit_status;
+}
+
 int cmd_add(int argc, const char **argv, const char *prefix)
 {
 	int exit_status = 0;
-	int i, newfd;
+	int newfd;
 	const char **pathspec;
 	struct dir_struct dir;
 	int flags;
+	int add_new_files;
+	int require_pathspec;
 
 	argc = parse_options(argc, argv, builtin_add_options,
 			  builtin_add_usage, 0);
@@ -233,53 +256,51 @@
 
 	git_config(add_config, NULL);
 
+	if (addremove && take_worktree_changes)
+		die("-A and -u are mutually incompatible");
+	if (addremove && !argc) {
+		static const char *here[2] = { ".", NULL };
+		argc = 1;
+		argv = here;
+	}
+
+	add_new_files = !take_worktree_changes && !refresh_only;
+	require_pathspec = !take_worktree_changes;
+
 	newfd = hold_locked_index(&lock_file, 1);
 
 	flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
 		 (show_only ? ADD_CACHE_PRETEND : 0) |
 		 (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0));
 
-	if (take_worktree_changes) {
-		const char **pathspec;
-		if (read_cache() < 0)
-			die("index file corrupt");
-		pathspec = get_pathspec(prefix, argv);
-		exit_status = add_files_to_cache(prefix, pathspec, flags);
-		goto finish;
-	}
-
-	if (argc == 0) {
+	if (require_pathspec && argc == 0) {
 		fprintf(stderr, "Nothing specified, nothing added.\n");
 		fprintf(stderr, "Maybe you wanted to say 'git add .'?\n");
 		return 0;
 	}
 	pathspec = get_pathspec(prefix, argv);
 
+	/*
+	 * If we are adding new files, we need to scan the working
+	 * tree to find the ones that match pathspecs; this needs
+	 * to be done before we read the index.
+	 */
+	if (add_new_files)
+		fill_directory(&dir, pathspec, ignored_too);
+
+	if (read_cache() < 0)
+		die("index file corrupt");
+
 	if (refresh_only) {
 		refresh(verbose, pathspec);
 		goto finish;
 	}
 
-	fill_directory(&dir, pathspec, ignored_too);
+	if (take_worktree_changes || addremove)
+		exit_status |= add_files_to_cache(prefix, pathspec, flags);
 
-	if (read_cache() < 0)
-		die("index file corrupt");
-
-	if (dir.ignored_nr) {
-		fprintf(stderr, ignore_error);
-		for (i = 0; i < dir.ignored_nr; i++) {
-			fprintf(stderr, "%s\n", dir.ignored[i]->name);
-		}
-		fprintf(stderr, "Use -f if you really want to add them.\n");
-		die("no files added");
-	}
-
-	for (i = 0; i < dir.nr; i++)
-		if (add_file_to_cache(dir.entries[i]->name, flags)) {
-			if (!ignore_add_errors)
-				die("adding files failed");
-			exit_status = 1;
-		}
+	if (add_new_files)
+		exit_status |= add_files(&dir, flags);
 
  finish:
 	if (active_cache_changed) {
diff --git a/builtin-apply.c b/builtin-apply.c
index d13313f..e15471b 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -46,7 +46,7 @@
 static int line_termination = '\n';
 static unsigned long p_context = ULONG_MAX;
 static const char apply_usage[] =
-"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|fix|error|error-all>] <patch>...";
+"git apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|fix|error|error-all>] <patch>...";
 
 static enum ws_error_action {
 	nowarn_ws_error,
diff --git a/builtin-archive.c b/builtin-archive.c
index c2e0c1e..df97724 100644
--- a/builtin-archive.c
+++ b/builtin-archive.c
@@ -7,22 +7,17 @@
 #include "archive.h"
 #include "commit.h"
 #include "tree-walk.h"
-#include "exec_cmd.h"
 #include "pkt-line.h"
 #include "sideband.h"
-#include "attr.h"
 
 static const char archive_usage[] = \
-"git-archive --format=<fmt> [--prefix=<prefix>/] [--verbose] [<extra>] <tree-ish> [path...]";
+"git archive --format=<fmt> [--prefix=<prefix>/] [--verbose] [<extra>] <tree-ish> [path...]";
 
-static struct archiver_desc
-{
-	const char *name;
-	write_archive_fn_t write_archive;
-	parse_extra_args_fn_t parse_extra;
-} archivers[] = {
-	{ "tar", write_tar_archive, NULL },
-	{ "zip", write_zip_archive, parse_extra_zip_args },
+#define USES_ZLIB_COMPRESSION 1
+
+const struct archiver archivers[] = {
+	{ "tar", write_tar_archive },
+	{ "zip", write_zip_archive, USES_ZLIB_COMPRESSION },
 };
 
 static int run_remote_archiver(const char *remote, int argc,
@@ -79,21 +74,15 @@
 	return !!rv;
 }
 
-static int init_archiver(const char *name, struct archiver *ar)
+static const struct archiver *lookup_archiver(const char *name)
 {
-	int rv = -1, i;
+	int i;
 
 	for (i = 0; i < ARRAY_SIZE(archivers); i++) {
-		if (!strcmp(name, archivers[i].name)) {
-			memset(ar, 0, sizeof(*ar));
-			ar->name = archivers[i].name;
-			ar->write_archive = archivers[i].write_archive;
-			ar->parse_extra = archivers[i].parse_extra;
-			rv = 0;
-			break;
-		}
+		if (!strcmp(name, archivers[i].name))
+			return &archivers[i];
 	}
-	return rv;
+	return NULL;
 }
 
 void parse_pathspec_arg(const char **pathspec, struct archiver_args *ar_args)
@@ -145,12 +134,12 @@
 	ar_args->time = archive_time;
 }
 
-int parse_archive_args(int argc, const char **argv, struct archiver *ar)
+int parse_archive_args(int argc, const char **argv, const struct archiver **ar,
+		struct archiver_args *args)
 {
-	const char *extra_argv[MAX_EXTRA_ARGS];
-	int extra_argc = 0;
 	const char *format = "tar";
 	const char *base = "";
+	int compression_level = -1;
 	int verbose = 0;
 	int i;
 
@@ -178,29 +167,34 @@
 			i++;
 			break;
 		}
-		if (arg[0] == '-') {
-			if (extra_argc > MAX_EXTRA_ARGS - 1)
-				die("Too many extra options");
-			extra_argv[extra_argc++] = arg;
+		if (arg[0] == '-' && isdigit(arg[1]) && arg[2] == '\0') {
+			compression_level = arg[1] - '0';
 			continue;
 		}
+		if (arg[0] == '-')
+			die("Unknown argument: %s", arg);
 		break;
 	}
 
 	/* We need at least one parameter -- tree-ish */
 	if (argc - 1 < i)
 		usage(archive_usage);
-	if (init_archiver(format, ar) < 0)
+	*ar = lookup_archiver(format);
+	if (!*ar)
 		die("Unknown archive format '%s'", format);
 
-	if (extra_argc) {
-		if (!ar->parse_extra)
-			die("'%s' format does not handle %s",
-			    ar->name, extra_argv[0]);
-		ar->args.extra = ar->parse_extra(extra_argc, extra_argv);
+	args->compression_level = Z_DEFAULT_COMPRESSION;
+	if (compression_level != -1) {
+		if ((*ar)->flags & USES_ZLIB_COMPRESSION)
+			args->compression_level = compression_level;
+		else {
+			die("Argument not supported for format '%s': -%d",
+					format, compression_level);
+		}
 	}
-	ar->args.verbose = verbose;
-	ar->args.base = base;
+	args->verbose = verbose;
+	args->base = base;
+	args->baselen = strlen(base);
 
 	return i;
 }
@@ -238,7 +232,8 @@
 
 int cmd_archive(int argc, const char **argv, const char *prefix)
 {
-	struct archiver ar;
+	const struct archiver *ar = NULL;
+	struct archiver_args args;
 	int tree_idx;
 	const char *remote = NULL;
 
@@ -248,14 +243,13 @@
 
 	setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
 
-	memset(&ar, 0, sizeof(ar));
-	tree_idx = parse_archive_args(argc, argv, &ar);
+	tree_idx = parse_archive_args(argc, argv, &ar, &args);
 	if (prefix == NULL)
 		prefix = setup_git_directory();
 
 	argv += tree_idx;
-	parse_treeish_arg(argv, &ar.args, prefix);
-	parse_pathspec_arg(argv + 1, &ar.args);
+	parse_treeish_arg(argv, &args, prefix);
+	parse_pathspec_arg(argv + 1, &args);
 
-	return ar.write_archive(&ar.args);
+	return ar->write_archive(&args);
 }
diff --git a/builtin-blame.c b/builtin-blame.c
index 06c7de4..9bced3b 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -20,7 +20,7 @@
 #include "mailmap.h"
 #include "parse-options.h"
 
-static char blame_usage[] = "git-blame [options] [rev-opts] [rev] [--] file";
+static char blame_usage[] = "git blame [options] [rev-opts] [rev] [--] file";
 
 static const char *blame_opt_usage[] = {
 	blame_usage,
@@ -153,6 +153,10 @@
 	 */
 	char guilty;
 
+	/* true if the entry has been scanned for copies in the current parent
+	 */
+	char scanned;
+
 	/* the line number of the first line of this group in the
 	 * suspect's file; internally all line numbers are 0 based.
 	 */
@@ -1008,7 +1012,8 @@
 	while (made_progress) {
 		made_progress = 0;
 		for (e = sb->ent; e; e = e->next) {
-			if (e->guilty || !same_suspect(e->suspect, target))
+			if (e->guilty || !same_suspect(e->suspect, target) ||
+			    ent_score(sb, e) < blame_move_score)
 				continue;
 			find_copy_in_blob(sb, e, parent, split, &file_p);
 			if (split[1].suspect &&
@@ -1033,6 +1038,7 @@
  */
 static struct blame_list *setup_blame_list(struct scoreboard *sb,
 					   struct origin *target,
+					   int min_score,
 					   int *num_ents_p)
 {
 	struct blame_entry *e;
@@ -1040,12 +1046,16 @@
 	struct blame_list *blame_list = NULL;
 
 	for (e = sb->ent, num_ents = 0; e; e = e->next)
-		if (!e->guilty && same_suspect(e->suspect, target))
+		if (!e->scanned && !e->guilty &&
+		    same_suspect(e->suspect, target) &&
+		    min_score < ent_score(sb, e))
 			num_ents++;
 	if (num_ents) {
 		blame_list = xcalloc(num_ents, sizeof(struct blame_list));
 		for (e = sb->ent, i = 0; e; e = e->next)
-			if (!e->guilty && same_suspect(e->suspect, target))
+			if (!e->scanned && !e->guilty &&
+			    same_suspect(e->suspect, target) &&
+			    min_score < ent_score(sb, e))
 				blame_list[i++].ent = e;
 	}
 	*num_ents_p = num_ents;
@@ -1053,6 +1063,16 @@
 }
 
 /*
+ * Reset the scanned status on all entries.
+ */
+static void reset_scanned_flag(struct scoreboard *sb)
+{
+	struct blame_entry *e;
+	for (e = sb->ent; e; e = e->next)
+		e->scanned = 0;
+}
+
+/*
  * For lines target is suspected for, see if we can find code movement
  * across file boundary from the parent commit.  porigin is the path
  * in the parent we already tried.
@@ -1070,7 +1090,7 @@
 	struct blame_list *blame_list;
 	int num_ents;
 
-	blame_list = setup_blame_list(sb, target, &num_ents);
+	blame_list = setup_blame_list(sb, target, blame_copy_score, &num_ents);
 	if (!blame_list)
 		return 1; /* nothing remains for this target */
 
@@ -1144,18 +1164,21 @@
 				split_blame(sb, split, blame_list[j].ent);
 				made_progress = 1;
 			}
+			else
+				blame_list[j].ent->scanned = 1;
 			decref_split(split);
 		}
 		free(blame_list);
 
 		if (!made_progress)
 			break;
-		blame_list = setup_blame_list(sb, target, &num_ents);
+		blame_list = setup_blame_list(sb, target, blame_copy_score, &num_ents);
 		if (!blame_list) {
 			retval = 1;
 			break;
 		}
 	}
+	reset_scanned_flag(sb);
 	diff_flush(&diff_opts);
 	diff_tree_release_paths(&diff_opts);
 	return retval;
diff --git a/builtin-branch.c b/builtin-branch.c
index 7dae22c..b885bd1 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -15,10 +15,10 @@
 #include "branch.h"
 
 static const char * const builtin_branch_usage[] = {
-	"git-branch [options] [-r | -a] [--merged | --no-merged]",
-	"git-branch [options] [-l] [-f] <branchname> [<start-point>]",
-	"git-branch [options] [-r] (-d | -D) <branchname>",
-	"git-branch [options] (-m | -M) [<oldbranch>] <newbranch>",
+	"git branch [options] [-r | -a] [--merged | --no-merged]",
+	"git branch [options] [-l] [-f] <branchname> [<start-point>]",
+	"git branch [options] [-r] (-d | -D) <branchname>",
+	"git branch [options] (-m | -M) [<oldbranch>] <newbranch>",
 	NULL
 };
 
diff --git a/builtin-cat-file.c b/builtin-cat-file.c
index 880e75a..7441a56 100644
--- a/builtin-cat-file.c
+++ b/builtin-cat-file.c
@@ -202,8 +202,8 @@
 }
 
 static const char * const cat_file_usage[] = {
-	"git-cat-file [-t|-s|-e|-p|<type>] <sha1>",
-	"git-cat-file [--batch|--batch-check] < <list_of_sha1s>",
+	"git cat-file [-t|-s|-e|-p|<type>] <sha1>",
+	"git cat-file [--batch|--batch-check] < <list_of_sha1s>",
 	NULL
 };
 
diff --git a/builtin-check-attr.c b/builtin-check-attr.c
index 6afdfa1..cb783fc 100644
--- a/builtin-check-attr.c
+++ b/builtin-check-attr.c
@@ -4,7 +4,7 @@
 #include "quote.h"
 
 static const char check_attr_usage[] =
-"git-check-attr attr... [--] pathname...";
+"git check-attr attr... [--] pathname...";
 
 int cmd_check_attr(int argc, const char **argv, const char *prefix)
 {
diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c
index eb1fc9a..71ebabf 100644
--- a/builtin-checkout-index.c
+++ b/builtin-checkout-index.c
@@ -154,7 +154,7 @@
 }
 
 static const char checkout_cache_usage[] =
-"git-checkout-index [-u] [-q] [-a] [-f] [-n] [--stage=[123]|all] [--prefix=<string>] [--temp] [--] <file>...";
+"git checkout-index [-u] [-q] [-a] [-f] [-n] [--stage=[123]|all] [--prefix=<string>] [--temp] [--] <file>...";
 
 static struct lock_file lock_file;
 
diff --git a/builtin-checkout.c b/builtin-checkout.c
index d6641c2..fbd5105 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -43,7 +43,7 @@
 }
 
 static int update_some(const unsigned char *sha1, const char *base, int baselen,
-		       const char *pathname, unsigned mode, int stage)
+		const char *pathname, unsigned mode, int stage, void *context)
 {
 	int len;
 	struct cache_entry *ce;
@@ -67,7 +67,7 @@
 
 static int read_tree_some(struct tree *tree, const char **pathspec)
 {
-	read_tree_recursive(tree, "", 0, 0, pathspec, update_some);
+	read_tree_recursive(tree, "", 0, 0, pathspec, update_some, NULL);
 
 	/* update the index with the given tree's info
 	 * for all args, expanding wildcards, and exit
diff --git a/builtin-clean.c b/builtin-clean.c
index 80a7ff9..48bf29f 100644
--- a/builtin-clean.c
+++ b/builtin-clean.c
@@ -15,7 +15,7 @@
 static int force = -1; /* unset */
 
 static const char *const builtin_clean_usage[] = {
-	"git-clean [-d] [-f] [-n] [-q] [-x | -X] [--] <paths>...",
+	"git clean [-d] [-f] [-n] [-q] [-x | -X] [--] <paths>...",
 	NULL
 };
 
diff --git a/builtin-clone.c b/builtin-clone.c
index ec36209..3522245 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -29,7 +29,7 @@
  *
  */
 static const char * const builtin_clone_usage[] = {
-	"git-clone [options] [--] <repo> [<dir>]",
+	"git clone [options] [--] <repo> [<dir>]",
 	NULL
 };
 
@@ -95,35 +95,38 @@
 
 static char *guess_dir_name(const char *repo, int is_bundle)
 {
-	const char *p, *start, *end, *limit;
-	int after_slash_or_colon;
+	const char *end = repo + strlen(repo), *start;
 
-	/* Guess dir name from repository: strip trailing '/',
-	 * strip trailing '[:/]*.{git,bundle}', strip leading '.*[/:]'. */
+	/*
+	 * Strip trailing slashes and /.git
+	 */
+	while (repo < end && is_dir_sep(end[-1]))
+		end--;
+	if (end - repo > 5 && is_dir_sep(end[-5]) &&
+	    !strncmp(end - 4, ".git", 4)) {
+		end -= 5;
+		while (repo < end && is_dir_sep(end[-1]))
+			end--;
+	}
 
-	after_slash_or_colon = 1;
-	limit = repo + strlen(repo);
-	start = repo;
-	end = limit;
-	for (p = repo; p < limit; p++) {
-		const char *prefix = is_bundle ? ".bundle" : ".git";
-		if (!prefixcmp(p, prefix)) {
-			if (!after_slash_or_colon)
-				end = p;
-			p += strlen(prefix) - 1;
-		} else if (!prefixcmp(p, ".bundle")) {
-			if (!after_slash_or_colon)
-				end = p;
-			p += 7;
-		} else if (*p == '/' || *p == ':') {
-			if (end == limit)
-				end = p;
-			after_slash_or_colon = 1;
-		} else if (after_slash_or_colon) {
-			start = p;
-			end = limit;
-			after_slash_or_colon = 0;
-		}
+	/*
+	 * Find last component, but be prepared that repo could have
+	 * the form  "remote.example.com:foo.git", i.e. no slash
+	 * in the directory part.
+	 */
+	start = end;
+	while (repo < start && !is_dir_sep(start[-1]) && start[-1] != ':')
+		start--;
+
+	/*
+	 * Strip .{bundle,git}.
+	 */
+	if (is_bundle) {
+		if (end - start > 7 && !strncmp(end - 7, ".bundle", 7))
+			end -= 7;
+	} else {
+		if (end - start > 4 && !strncmp(end - 4, ".git", 4))
+			end -= 4;
 	}
 
 	return xstrndup(start, end - start);
diff --git a/builtin-commit.c b/builtin-commit.c
index bdc83df..ed3fe3f 100644
--- a/builtin-commit.c
+++ b/builtin-commit.c
@@ -26,12 +26,12 @@
 #include "unpack-trees.h"
 
 static const char * const builtin_commit_usage[] = {
-	"git-commit [options] [--] <filepattern>...",
+	"git commit [options] [--] <filepattern>...",
 	NULL
 };
 
 static const char * const builtin_status_usage[] = {
-	"git-status [options] [--] <filepattern>...",
+	"git status [options] [--] <filepattern>...",
 	NULL
 };
 
diff --git a/builtin-config.c b/builtin-config.c
index 39f63d7..0cf191a 100644
--- a/builtin-config.c
+++ b/builtin-config.c
@@ -3,7 +3,7 @@
 #include "color.h"
 
 static const char git_config_set_usage[] =
-"git-config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty]";
+"git config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty]";
 
 static char *key;
 static regex_t *key_regexp;
diff --git a/builtin-count-objects.c b/builtin-count-objects.c
index f00306f..91b5487 100644
--- a/builtin-count-objects.c
+++ b/builtin-count-objects.c
@@ -67,7 +67,7 @@
 }
 
 static char const * const count_objects_usage[] = {
-	"git-count-objects [-v]",
+	"git count-objects [-v]",
 	NULL
 };
 
diff --git a/builtin-describe.c b/builtin-describe.c
index e515f9c..ec404c8 100644
--- a/builtin-describe.c
+++ b/builtin-describe.c
@@ -10,7 +10,7 @@
 #define MAX_TAGS	(FLAG_BITS - 1)
 
 static const char * const describe_usage[] = {
-	"git-describe [options] <committish>*",
+	"git describe [options] <committish>*",
 	NULL
 };
 
@@ -20,7 +20,7 @@
 static int longformat;
 static int abbrev = DEFAULT_ABBREV;
 static int max_candidates = 10;
-const char *pattern = NULL;
+static const char *pattern;
 static int always;
 
 struct commit_name {
diff --git a/builtin-diff-files.c b/builtin-diff-files.c
index 384d871..9bf10bb 100644
--- a/builtin-diff-files.c
+++ b/builtin-diff-files.c
@@ -10,7 +10,7 @@
 #include "builtin.h"
 
 static const char diff_files_usage[] =
-"git-diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
+"git diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
 COMMON_DIFF_OPTIONS_HELP;
 
 int cmd_diff_files(int argc, const char **argv, const char *prefix)
diff --git a/builtin-diff-index.c b/builtin-diff-index.c
index 2f44ebf..17d851b 100644
--- a/builtin-diff-index.c
+++ b/builtin-diff-index.c
@@ -5,7 +5,7 @@
 #include "builtin.h"
 
 static const char diff_cache_usage[] =
-"git-diff-index [-m] [--cached] "
+"git diff-index [-m] [--cached] "
 "[<common diff options>] <tree-ish> [<path>...]"
 COMMON_DIFF_OPTIONS_HELP;
 
diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c
index 9d2a48f..415cb16 100644
--- a/builtin-diff-tree.c
+++ b/builtin-diff-tree.c
@@ -53,7 +53,7 @@
 }
 
 static const char diff_tree_usage[] =
-"git-diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] "
+"git diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] "
 "[<common diff options>] <tree-ish> [<tree-ish>] [<path>...]\n"
 "  -r            diff recursively\n"
 "  --root        include the initial commit as diff against /dev/null\n"
diff --git a/builtin-diff.c b/builtin-diff.c
index 4c289e7..faaa85a 100644
--- a/builtin-diff.c
+++ b/builtin-diff.c
@@ -21,7 +21,7 @@
 };
 
 static const char builtin_diff_usage[] =
-"git-diff <options> <rev>{0,2} -- <path>*";
+"git diff <options> <rev>{0,2} -- <path>*";
 
 static void stuff_change(struct diff_options *opt,
 			 unsigned old_mode, unsigned new_mode,
diff --git a/builtin-fast-export.c b/builtin-fast-export.c
index 75132ba..a443d59 100644
--- a/builtin-fast-export.c
+++ b/builtin-fast-export.c
@@ -18,7 +18,7 @@
 #include "parse-options.h"
 
 static const char *fast_export_usage[] = {
-	"git-fast-export [rev-list-opts]",
+	"git fast-export [rev-list-opts]",
 	NULL
 };
 
@@ -136,9 +136,18 @@
 		if (is_null_sha1(spec->sha1))
 			printf("D %s\n", spec->path);
 		else {
-			struct object *object = lookup_object(spec->sha1);
-			printf("M %06o :%d %s\n", spec->mode,
-			       get_object_mark(object), spec->path);
+			/*
+			 * Links refer to objects in another repositories;
+			 * output the SHA-1 verbatim.
+			 */
+			if (S_ISGITLINK(spec->mode))
+				printf("M %06o %s %s\n", spec->mode,
+				       sha1_to_hex(spec->sha1), spec->path);
+			else {
+				struct object *object = lookup_object(spec->sha1);
+				printf("M %06o :%d %s\n", spec->mode,
+				       get_object_mark(object), spec->path);
+			}
 		}
 	}
 }
@@ -196,8 +205,10 @@
 		diff_root_tree_sha1(commit->tree->object.sha1,
 				    "", &rev->diffopt);
 
+	/* Export the referenced blobs, and remember the marks. */
 	for (i = 0; i < diff_queued_diff.nr; i++)
-		handle_object(diff_queued_diff.queue[i]->two->sha1);
+		if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode))
+			handle_object(diff_queued_diff.queue[i]->two->sha1);
 
 	mark_next_object(&commit->object);
 	if (!is_encoding_utf8(encoding))
diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c
index 1ea7040..273239a 100644
--- a/builtin-fetch-pack.c
+++ b/builtin-fetch-pack.c
@@ -18,7 +18,7 @@
 };
 
 static const char fetch_pack_usage[] =
-"git-fetch-pack [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>...]";
+"git fetch-pack [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>...]";
 
 #define COMPLETE	(1U << 0)
 #define COMMON		(1U << 1)
diff --git a/builtin-fetch.c b/builtin-fetch.c
index 97fdc51..61de50a 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -12,7 +12,7 @@
 #include "parse-options.h"
 
 static const char * const builtin_fetch_usage[] = {
-	"git-fetch [options] [<repository> <refspec>...]",
+	"git fetch [options] [<repository> <refspec>...]",
 	NULL
 };
 
diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c
index dbd7d2d..df02ba7 100644
--- a/builtin-fmt-merge-msg.c
+++ b/builtin-fmt-merge-msg.c
@@ -6,7 +6,7 @@
 #include "tag.h"
 
 static const char *fmt_merge_msg_usage =
-	"git-fmt-merge-msg [--log] [--no-log] [--file <file>]";
+	"git fmt-merge-msg [--log] [--no-log] [--file <file>]";
 
 static int merge_summary;
 
diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c
index fef93d7..76282ad 100644
--- a/builtin-for-each-ref.c
+++ b/builtin-for-each-ref.c
@@ -831,7 +831,7 @@
 }
 
 static char const * const for_each_ref_usage[] = {
-	"git-for-each-ref [options] [<pattern>]",
+	"git for-each-ref [options] [<pattern>]",
 	NULL
 };
 
diff --git a/builtin-fsck.c b/builtin-fsck.c
index b0f9648..7326dc3 100644
--- a/builtin-fsck.c
+++ b/builtin-fsck.c
@@ -539,7 +539,7 @@
 }
 
 static char const * const fsck_usage[] = {
-	"git-fsck [options] [<object>...]",
+	"git fsck [options] [<object>...]",
 	NULL
 };
 
diff --git a/builtin-gc.c b/builtin-gc.c
index f5625bb..fac200e 100644
--- a/builtin-gc.c
+++ b/builtin-gc.c
@@ -18,7 +18,7 @@
 #define FAILED_RUN "failed to run %s"
 
 static const char * const builtin_gc_usage[] = {
-	"git-gc [options]",
+	"git gc [options]",
 	NULL
 };
 
diff --git a/builtin-grep.c b/builtin-grep.c
index ef29910..631129d 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -427,33 +427,35 @@
 	struct name_entry entry;
 	char *down;
 	int tn_len = strlen(tree_name);
-	char *path_buf = xmalloc(PATH_MAX + tn_len + 100);
+	struct strbuf pathbuf;
+
+	strbuf_init(&pathbuf, PATH_MAX + tn_len);
 
 	if (tn_len) {
-		tn_len = sprintf(path_buf, "%s:", tree_name);
-		down = path_buf + tn_len;
-		strcat(down, base);
+		strbuf_add(&pathbuf, tree_name, tn_len);
+		strbuf_addch(&pathbuf, ':');
+		tn_len = pathbuf.len;
 	}
-	else {
-		down = path_buf;
-		strcpy(down, base);
-	}
-	len = strlen(path_buf);
+	strbuf_addstr(&pathbuf, base);
+	len = pathbuf.len;
 
 	while (tree_entry(tree, &entry)) {
-		strcpy(path_buf + len, entry.path);
+		int te_len = tree_entry_len(entry.path, entry.sha1);
+		pathbuf.len = len;
+		strbuf_add(&pathbuf, entry.path, te_len);
 
 		if (S_ISDIR(entry.mode))
 			/* Match "abc/" against pathspec to
 			 * decide if we want to descend into "abc"
 			 * directory.
 			 */
-			strcpy(path_buf + len + tree_entry_len(entry.path, entry.sha1), "/");
+			strbuf_addch(&pathbuf, '/');
 
+		down = pathbuf.buf + tn_len;
 		if (!pathspec_matches(paths, down))
 			;
 		else if (S_ISREG(entry.mode))
-			hit |= grep_sha1(opt, entry.sha1, path_buf, tn_len);
+			hit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len);
 		else if (S_ISDIR(entry.mode)) {
 			enum object_type type;
 			struct tree_desc sub;
@@ -469,6 +471,7 @@
 			free(data);
 		}
 	}
+	strbuf_release(&pathbuf);
 	return hit;
 }
 
@@ -495,7 +498,7 @@
 }
 
 static const char builtin_grep_usage[] =
-"git-grep <option>* <rev>* [-e] <pattern> [<path>...]";
+"git grep <option>* [-e] <pattern> <rev>* [[--] <path>...]";
 
 static const char emsg_invalid_context_len[] =
 "%s: invalid context length argument";
diff --git a/builtin-init-db.c b/builtin-init-db.c
index 5ba213a..38b4fcb 100644
--- a/builtin-init-db.c
+++ b/builtin-init-db.c
@@ -354,7 +354,7 @@
 }
 
 static const char init_db_usage[] =
-"git-init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]]";
+"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]]";
 
 /*
  * If you want to, you can share the DB area with any number of branches.
diff --git a/builtin-log.c b/builtin-log.c
index 430d876..f4975cf 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -313,7 +313,7 @@
 
 static int show_tree_object(const unsigned char *sha1,
 		const char *base, int baselen,
-		const char *pathname, unsigned mode, int stage)
+		const char *pathname, unsigned mode, int stage, void *context)
 {
 	printf("%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
 	return 0;
@@ -366,7 +366,7 @@
 					name,
 					diff_get_color_opt(&rev.diffopt, DIFF_RESET));
 			read_tree_recursive((struct tree *)o, "", 0, 0, NULL,
-					show_tree_object);
+					show_tree_object, NULL);
 			break;
 		case OBJ_COMMIT:
 			rev.pending.nr = rev.pending.alloc = 0;
@@ -1082,7 +1082,7 @@
 }
 
 static const char cherry_usage[] =
-"git-cherry [-v] <upstream> [<head>] [<limit>]";
+"git cherry [-v] <upstream> [<head>] [<limit>]";
 int cmd_cherry(int argc, const char **argv, const char *prefix)
 {
 	struct rev_info revs;
diff --git a/builtin-ls-files.c b/builtin-ls-files.c
index 75ba422..e8d568e 100644
--- a/builtin-ls-files.c
+++ b/builtin-ls-files.c
@@ -423,7 +423,7 @@
 }
 
 static const char ls_files_usage[] =
-	"git-ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* "
+	"git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* "
 	"[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] "
 	"[ --exclude-per-directory=<filename> ] [--exclude-standard] "
 	"[--full-name] [--abbrev] [--] [<file>]*";
diff --git a/builtin-ls-remote.c b/builtin-ls-remote.c
index 06ab8da..c21b841 100644
--- a/builtin-ls-remote.c
+++ b/builtin-ls-remote.c
@@ -4,7 +4,7 @@
 #include "remote.h"
 
 static const char ls_remote_usage[] =
-"git-ls-remote [--upload-pack=<git-upload-pack>] [<host>:]<directory>";
+"git ls-remote [--upload-pack=<git-upload-pack>] [<host>:]<directory>";
 
 /*
  * Is there one among the list of patterns that match the tail part
diff --git a/builtin-ls-tree.c b/builtin-ls-tree.c
index f4a75dd..d25767a 100644
--- a/builtin-ls-tree.c
+++ b/builtin-ls-tree.c
@@ -23,7 +23,7 @@
 static const char *ls_tree_prefix;
 
 static const char ls_tree_usage[] =
-	"git-ls-tree [-d] [-r] [-t] [-l] [-z] [--name-only] [--name-status] [--full-name] [--abbrev[=<n>]] <tree-ish> [path...]";
+	"git ls-tree [-d] [-r] [-t] [-l] [-z] [--name-only] [--name-status] [--full-name] [--abbrev[=<n>]] <tree-ish> [path...]";
 
 static int show_recursive(const char *base, int baselen, const char *pathname)
 {
@@ -56,7 +56,7 @@
 }
 
 static int show_tree(const unsigned char *sha1, const char *base, int baselen,
-		     const char *pathname, unsigned mode, int stage)
+		const char *pathname, unsigned mode, int stage, void *context)
 {
 	int retval = 0;
 	const char *type = blob_type;
@@ -189,7 +189,7 @@
 	tree = parse_tree_indirect(sha1);
 	if (!tree)
 		die("not a tree object");
-	read_tree_recursive(tree, "", 0, 0, pathspec, show_tree);
+	read_tree_recursive(tree, "", 0, 0, pathspec, show_tree, NULL);
 
 	return 0;
 }
diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
index 13f0502..b99a5b6 100644
--- a/builtin-mailinfo.c
+++ b/builtin-mailinfo.c
@@ -5,14 +5,15 @@
 #include "cache.h"
 #include "builtin.h"
 #include "utf8.h"
+#include "strbuf.h"
 
 static FILE *cmitmsg, *patchfile, *fin, *fout;
 
 static int keep_subject;
 static const char *metainfo_charset;
-static char line[1000];
-static char name[1000];
-static char email[1000];
+static struct strbuf line = STRBUF_INIT;
+static struct strbuf name = STRBUF_INIT;
+static struct strbuf email = STRBUF_INIT;
 
 static enum  {
 	TE_DONTCARE, TE_QP, TE_BASE64,
@@ -21,74 +22,79 @@
 	TYPE_TEXT, TYPE_OTHER,
 } message_type;
 
-static char charset[256];
+static struct strbuf charset = STRBUF_INIT;
 static int patch_lines;
-static char **p_hdr_data, **s_hdr_data;
+static struct strbuf **p_hdr_data, **s_hdr_data;
 
 #define MAX_HDR_PARSED 10
 #define MAX_BOUNDARIES 5
 
-static char *sanity_check(char *name, char *email)
+static void get_sane_name(struct strbuf *out, struct strbuf *name, struct strbuf *email)
 {
-	int len = strlen(name);
-	if (len < 3 || len > 60)
-		return email;
-	if (strchr(name, '@') || strchr(name, '<') || strchr(name, '>'))
-		return email;
-	return name;
+	struct strbuf *src = name;
+	if (name->len < 3 || 60 < name->len || strchr(name->buf, '@') ||
+		strchr(name->buf, '<') || strchr(name->buf, '>'))
+		src = email;
+	else if (name == out)
+		return;
+	strbuf_reset(out);
+	strbuf_addbuf(out, src);
 }
 
-static int bogus_from(char *line)
+static void parse_bogus_from(const struct strbuf *line)
 {
 	/* John Doe <johndoe> */
-	char *bra, *ket, *dst, *cp;
 
+	char *bra, *ket;
 	/* This is fallback, so do not bother if we already have an
 	 * e-mail address.
 	 */
-	if (*email)
-		return 0;
+	if (email.len)
+		return;
 
-	bra = strchr(line, '<');
+	bra = strchr(line->buf, '<');
 	if (!bra)
-		return 0;
+		return;
 	ket = strchr(bra, '>');
 	if (!ket)
-		return 0;
+		return;
 
-	for (dst = email, cp = bra+1; cp < ket; )
-		*dst++ = *cp++;
-	*dst = 0;
-	for (cp = line; isspace(*cp); cp++)
-		;
-	for (bra--; isspace(*bra); bra--)
-		*bra = 0;
-	cp = sanity_check(cp, email);
-	strcpy(name, cp);
-	return 1;
+	strbuf_reset(&email);
+	strbuf_add(&email, bra + 1, ket - bra - 1);
+
+	strbuf_reset(&name);
+	strbuf_add(&name, line->buf, bra - line->buf);
+	strbuf_trim(&name);
+	get_sane_name(&name, &name, &email);
 }
 
-static int handle_from(char *in_line)
+static void handle_from(const struct strbuf *from)
 {
-	char line[1000];
 	char *at;
-	char *dst;
+	size_t el;
+	struct strbuf f;
 
-	strcpy(line, in_line);
-	at = strchr(line, '@');
-	if (!at)
-		return bogus_from(line);
+	strbuf_init(&f, from->len);
+	strbuf_addbuf(&f, from);
+
+	at = strchr(f.buf, '@');
+	if (!at) {
+		parse_bogus_from(from);
+		return;
+	}
 
 	/*
 	 * If we already have one email, don't take any confusing lines
 	 */
-	if (*email && strchr(at+1, '@'))
-		return 0;
+	if (email.len && strchr(at + 1, '@')) {
+		strbuf_release(&f);
+		return;
+	}
 
 	/* Pick up the string around '@', possibly delimited with <>
-	 * pair; that is the email part.  White them out while copying.
+	 * pair; that is the email part.
 	 */
-	while (at > line) {
+	while (at > f.buf) {
 		char c = at[-1];
 		if (isspace(c))
 			break;
@@ -98,56 +104,35 @@
 		}
 		at--;
 	}
-	dst = email;
-	for (;;) {
-		unsigned char c = *at;
-		if (!c || c == '>' || isspace(c)) {
-			if (c == '>')
-				*at = ' ';
-			break;
-		}
-		*at++ = ' ';
-		*dst++ = c;
-	}
-	*dst++ = 0;
+	el = strcspn(at, " \n\t\r\v\f>");
+	strbuf_reset(&email);
+	strbuf_add(&email, at, el);
+	strbuf_remove(&f, at - f.buf, el + 1);
 
 	/* The remainder is name.  It could be "John Doe <john.doe@xz>"
-	 * or "john.doe@xz (John Doe)", but we have whited out the
+	 * or "john.doe@xz (John Doe)", but we have removed the
 	 * email part, so trim from both ends, possibly removing
 	 * the () pair at the end.
 	 */
-	at = line + strlen(line);
-	while (at > line) {
-		unsigned char c = *--at;
-		if (!isspace(c)) {
-			at[(c == ')') ? 0 : 1] = 0;
-			break;
-		}
-	}
+	strbuf_trim(&f);
+	if (f.buf[0] == '(')
+		strbuf_remove(&name, 0, 1);
+	if (f.len && f.buf[f.len - 1] == ')')
+		strbuf_setlen(&f, f.len - 1);
 
-	at = line;
-	for (;;) {
-		unsigned char c = *at;
-		if (!c || !isspace(c)) {
-			if (c == '(')
-				at++;
-			break;
-		}
-		at++;
-	}
-	at = sanity_check(at, email);
-	strcpy(name, at);
-	return 1;
+	get_sane_name(&name, &f, &email);
+	strbuf_release(&f);
 }
 
-static int handle_header(char *line, char *data, int ofs)
+static void handle_header(struct strbuf **out, const struct strbuf *line)
 {
-	if (!line || !data)
-		return 1;
+	if (!*out) {
+		*out = xmalloc(sizeof(struct strbuf));
+		strbuf_init(*out, line->len);
+	} else
+		strbuf_reset(*out);
 
-	strcpy(data, line+ofs);
-
-	return 0;
+	strbuf_addbuf(*out, line);
 }
 
 /* NOTE NOTE NOTE.  We do not claim we do full MIME.  We just attempt
@@ -156,13 +141,13 @@
  * case insensitively.
  */
 
-static int slurp_attr(const char *line, const char *name, char *attr)
+static int slurp_attr(const char *line, const char *name, struct strbuf *attr)
 {
 	const char *ends, *ap = strcasestr(line, name);
 	size_t sz;
 
 	if (!ap) {
-		*attr = 0;
+		strbuf_setlen(attr, 0);
 		return 0;
 	}
 	ap += strlen(name);
@@ -173,182 +158,171 @@
 	else
 		ends = "; \t";
 	sz = strcspn(ap, ends);
-	memcpy(attr, ap, sz);
-	attr[sz] = 0;
+	strbuf_add(attr, ap, sz);
 	return 1;
 }
 
-struct content_type {
-	char *boundary;
-	int boundary_len;
-};
+static struct strbuf *content[MAX_BOUNDARIES];
 
-static struct content_type content[MAX_BOUNDARIES];
+static struct strbuf **content_top = content;
 
-static struct content_type *content_top = content;
-
-static int handle_content_type(char *line)
+static void handle_content_type(struct strbuf *line)
 {
-	char boundary[256];
+	struct strbuf *boundary = xmalloc(sizeof(struct strbuf));
+	strbuf_init(boundary, line->len);
 
-	if (strcasestr(line, "text/") == NULL)
+	if (!strcasestr(line->buf, "text/"))
 		 message_type = TYPE_OTHER;
-	if (slurp_attr(line, "boundary=", boundary + 2)) {
-		memcpy(boundary, "--", 2);
+	if (slurp_attr(line->buf, "boundary=", boundary)) {
+		strbuf_insert(boundary, 0, "--", 2);
 		if (content_top++ >= &content[MAX_BOUNDARIES]) {
 			fprintf(stderr, "Too many boundaries to handle\n");
 			exit(1);
 		}
-		content_top->boundary_len = strlen(boundary);
-		content_top->boundary = xmalloc(content_top->boundary_len+1);
-		strcpy(content_top->boundary, boundary);
+		*content_top = boundary;
+		boundary = NULL;
 	}
-	if (slurp_attr(line, "charset=", charset)) {
-		int i, c;
-		for (i = 0; (c = charset[i]) != 0; i++)
-			charset[i] = tolower(c);
+	if (slurp_attr(line->buf, "charset=", &charset))
+		strbuf_tolower(&charset);
+
+	if (boundary) {
+		strbuf_release(boundary);
+		free(boundary);
 	}
-	return 0;
 }
 
-static int handle_content_transfer_encoding(char *line)
+static void handle_content_transfer_encoding(const struct strbuf *line)
 {
-	if (strcasestr(line, "base64"))
+	if (strcasestr(line->buf, "base64"))
 		transfer_encoding = TE_BASE64;
-	else if (strcasestr(line, "quoted-printable"))
+	else if (strcasestr(line->buf, "quoted-printable"))
 		transfer_encoding = TE_QP;
 	else
 		transfer_encoding = TE_DONTCARE;
-	return 0;
 }
 
-static int is_multipart_boundary(const char *line)
+static int is_multipart_boundary(const struct strbuf *line)
 {
-	return (!memcmp(line, content_top->boundary, content_top->boundary_len));
+	return !strbuf_cmp(line, *content_top);
 }
 
-static int eatspace(char *line)
+static void cleanup_subject(struct strbuf *subject)
 {
-	int len = strlen(line);
-	while (len > 0 && isspace(line[len-1]))
-		line[--len] = 0;
-	return len;
-}
-
-static char *cleanup_subject(char *subject)
-{
-	for (;;) {
-		char *p;
-		int len, remove;
-		switch (*subject) {
+	char *pos;
+	size_t remove;
+	while (subject->len) {
+		switch (*subject->buf) {
 		case 'r': case 'R':
-			if (!memcmp("e:", subject+1, 2)) {
-				subject += 3;
+			if (subject->len <= 3)
+				break;
+			if (!memcmp(subject->buf + 1, "e:", 2)) {
+				strbuf_remove(subject, 0, 3);
 				continue;
 			}
 			break;
 		case ' ': case '\t': case ':':
-			subject++;
+			strbuf_remove(subject, 0, 1);
 			continue;
-
 		case '[':
-			p = strchr(subject, ']');
-			if (!p) {
-				subject++;
-				continue;
-			}
-			len = strlen(p);
-			remove = p - subject;
-			if (remove <= len *2) {
-				subject = p+1;
-				continue;
-			}
+			if ((pos = strchr(subject->buf, ']'))) {
+				remove = pos - subject->buf;
+				if (remove <= (subject->len - remove) * 2) {
+					strbuf_remove(subject, 0, remove + 1);
+					continue;
+				}
+			} else
+				strbuf_remove(subject, 0, 1);
 			break;
 		}
-		eatspace(subject);
-		return subject;
+		strbuf_trim(subject);
+		return;
 	}
 }
 
-static void cleanup_space(char *buf)
+static void cleanup_space(struct strbuf *sb)
 {
-	unsigned char c;
-	while ((c = *buf) != 0) {
-		buf++;
-		if (isspace(c)) {
-			buf[-1] = ' ';
-			c = *buf;
-			while (isspace(c)) {
-				int len = strlen(buf);
-				memmove(buf, buf+1, len);
-				c = *buf;
-			}
+	size_t pos, cnt;
+	for (pos = 0; pos < sb->len; pos++) {
+		if (isspace(sb->buf[pos])) {
+			sb->buf[pos] = ' ';
+			for (cnt = 0; isspace(sb->buf[pos + cnt + 1]); cnt++);
+			strbuf_remove(sb, pos + 1, cnt);
 		}
 	}
 }
 
-static void decode_header(char *it, unsigned itsize);
+static void decode_header(struct strbuf *line);
 static const char *header[MAX_HDR_PARSED] = {
 	"From","Subject","Date",
 };
 
-static int check_header(char *line, unsigned linesize, char **hdr_data, int overwrite)
+static inline int cmp_header(const struct strbuf *line, const char *hdr)
 {
-	int i;
+	int len = strlen(hdr);
+	return !strncasecmp(line->buf, hdr, len) && line->len > len &&
+			line->buf[len] == ':' && isspace(line->buf[len + 1]);
+}
 
+static int check_header(const struct strbuf *line,
+				struct strbuf *hdr_data[], int overwrite)
+{
+	int i, ret = 0, len;
+	struct strbuf sb = STRBUF_INIT;
 	/* search for the interesting parts */
 	for (i = 0; header[i]; i++) {
 		int len = strlen(header[i]);
-		if ((!hdr_data[i] || overwrite) &&
-		    !strncasecmp(line, header[i], len) &&
-		    line[len] == ':' && isspace(line[len + 1])) {
+		if ((!hdr_data[i] || overwrite) && cmp_header(line, header[i])) {
 			/* Unwrap inline B and Q encoding, and optionally
 			 * normalize the meta information to utf8.
 			 */
-			decode_header(line + len + 2, linesize - len - 2);
-			hdr_data[i] = xmalloc(1000 * sizeof(char));
-			if (! handle_header(line, hdr_data[i], len + 2)) {
-				return 1;
-			}
+			strbuf_add(&sb, line->buf + len + 2, line->len - len - 2);
+			decode_header(&sb);
+			handle_header(&hdr_data[i], &sb);
+			ret = 1;
+			goto check_header_out;
 		}
 	}
 
 	/* Content stuff */
-	if (!strncasecmp(line, "Content-Type", 12) &&
-		line[12] == ':' && isspace(line[12 + 1])) {
-		decode_header(line + 12 + 2, linesize - 12 - 2);
-		if (! handle_content_type(line)) {
-			return 1;
-		}
+	if (cmp_header(line, "Content-Type")) {
+		len = strlen("Content-Type: ");
+		strbuf_add(&sb, line->buf + len, line->len - len);
+		decode_header(&sb);
+		strbuf_insert(&sb, 0, "Content-Type: ", len);
+		handle_content_type(&sb);
+		ret = 1;
+		goto check_header_out;
 	}
-	if (!strncasecmp(line, "Content-Transfer-Encoding", 25) &&
-		line[25] == ':' && isspace(line[25 + 1])) {
-		decode_header(line + 25 + 2, linesize - 25 - 2);
-		if (! handle_content_transfer_encoding(line)) {
-			return 1;
-		}
+	if (cmp_header(line, "Content-Transfer-Encoding")) {
+		len = strlen("Content-Transfer-Encoding: ");
+		strbuf_add(&sb, line->buf + len, line->len - len);
+		decode_header(&sb);
+		handle_content_transfer_encoding(&sb);
+		ret = 1;
+		goto check_header_out;
 	}
 
 	/* for inbody stuff */
-	if (!memcmp(">From", line, 5) && isspace(line[5]))
-		return 1;
-	if (!memcmp("[PATCH]", line, 7) && isspace(line[7])) {
+	if (!prefixcmp(line->buf, ">From") && isspace(line->buf[5])) {
+		ret = 1; /* Should this return 0? */
+		goto check_header_out;
+	}
+	if (!prefixcmp(line->buf, "[PATCH]") && isspace(line->buf[7])) {
 		for (i = 0; header[i]; i++) {
 			if (!memcmp("Subject", header[i], 7)) {
-				if (!hdr_data[i])
-					hdr_data[i] = xmalloc(linesize + 20);
-				if (! handle_header(line, hdr_data[i], 0)) {
-					return 1;
-				}
+				handle_header(&hdr_data[i], line);
+				ret = 1;
+				goto check_header_out;
 			}
 		}
 	}
 
-	/* no match */
-	return 0;
+check_header_out:
+	strbuf_release(&sb);
+	return ret;
 }
 
-static int is_rfc2822_header(char *line)
+static int is_rfc2822_header(const struct strbuf *line)
 {
 	/*
 	 * The section that defines the loosest possible
@@ -359,15 +333,15 @@
 	 * ftext = %d33-57 / %59-126
 	 */
 	int ch;
-	char *cp = line;
+	char *cp = line->buf;
 
 	/* Count mbox From headers as headers */
-	if (!memcmp(line, "From ", 5) || !memcmp(line, ">From ", 6))
+	if (!prefixcmp(cp, "From ") || !prefixcmp(cp, ">From "))
 		return 1;
 
 	while ((ch = *cp++)) {
 		if (ch == ':')
-			return cp != line;
+			return 1;
 		if ((33 <= ch && ch <= 57) ||
 		    (59 <= ch && ch <= 126))
 			continue;
@@ -376,34 +350,20 @@
 	return 0;
 }
 
-/*
- * sz is size of 'line' buffer in bytes.  Must be reasonably
- * long enough to hold one physical real-world e-mail line.
- */
-static int read_one_header_line(char *line, int sz, FILE *in)
+static int read_one_header_line(struct strbuf *line, FILE *in)
 {
-	int len;
-
-	/*
-	 * We will read at most (sz-1) bytes and then potentially
-	 * re-add NUL after it.  Accessing line[sz] after this is safe
-	 * and we can allow len to grow up to and including sz.
-	 */
-	sz--;
-
 	/* Get the first part of the line. */
-	if (!fgets(line, sz, in))
+	if (strbuf_getline(line, in, '\n'))
 		return 0;
 
 	/*
 	 * Is it an empty line or not a valid rfc2822 header?
 	 * If so, stop here, and return false ("not a header")
 	 */
-	len = eatspace(line);
-	if (!len || !is_rfc2822_header(line)) {
+	strbuf_rtrim(line);
+	if (!line->len || !is_rfc2822_header(line)) {
 		/* Re-add the newline */
-		line[len] = '\n';
-		line[len + 1] = '\0';
+		strbuf_addch(line, '\n');
 		return 0;
 	}
 
@@ -412,65 +372,53 @@
 	 * Yuck, 2822 header "folding"
 	 */
 	for (;;) {
-		int peek, addlen;
-		static char continuation[1000];
+		int peek;
+		struct strbuf continuation = STRBUF_INIT;
 
 		peek = fgetc(in); ungetc(peek, in);
 		if (peek != ' ' && peek != '\t')
 			break;
-		if (!fgets(continuation, sizeof(continuation), in))
+		if (strbuf_getline(&continuation, in, '\n'))
 			break;
-		addlen = eatspace(continuation);
-		if (len < sz - 1) {
-			if (addlen >= sz - len)
-				addlen = sz - len - 1;
-			memcpy(line + len, continuation, addlen);
-			line[len] = '\n';
-			len += addlen;
-		}
+		continuation.buf[0] = '\n';
+		strbuf_rtrim(&continuation);
+		strbuf_addbuf(line, &continuation);
 	}
-	line[len] = 0;
 
 	return 1;
 }
 
-static int decode_q_segment(char *in, char *ot, unsigned otsize, char *ep, int rfc2047)
+static struct strbuf *decode_q_segment(const struct strbuf *q_seg, int rfc2047)
 {
-	char *otbegin = ot;
-	char *otend = ot + otsize;
+	const char *in = q_seg->buf;
 	int c;
-	while ((c = *in++) != 0 && (in <= ep)) {
-		if (ot == otend) {
-			*--ot = '\0';
-			return -1;
-		}
+	struct strbuf *out = xmalloc(sizeof(struct strbuf));
+	strbuf_init(out, q_seg->len);
+
+	while ((c = *in++) != 0) {
 		if (c == '=') {
 			int d = *in++;
 			if (d == '\n' || !d)
 				break; /* drop trailing newline */
-			*ot++ = ((hexval(d) << 4) | hexval(*in++));
+			strbuf_addch(out, (hexval(d) << 4) | hexval(*in++));
 			continue;
 		}
 		if (rfc2047 && c == '_') /* rfc2047 4.2 (2) */
 			c = 0x20;
-		*ot++ = c;
+		strbuf_addch(out, c);
 	}
-	*ot = 0;
-	return (ot - otbegin);
+	return out;
 }
 
-static int decode_b_segment(char *in, char *ot, unsigned otsize, char *ep)
+static struct strbuf *decode_b_segment(const struct strbuf *b_seg)
 {
 	/* Decode in..ep, possibly in-place to ot */
 	int c, pos = 0, acc = 0;
-	char *otbegin = ot;
-	char *otend = ot + otsize;
+	const char *in = b_seg->buf;
+	struct strbuf *out = xmalloc(sizeof(struct strbuf));
+	strbuf_init(out, b_seg->len);
 
-	while ((c = *in++) != 0 && (in <= ep)) {
-		if (ot == otend) {
-			*--ot = '\0';
-			return -1;
-		}
+	while ((c = *in++) != 0) {
 		if (c == '+')
 			c = 62;
 		else if (c == '/')
@@ -495,21 +443,20 @@
 			acc = (c << 2);
 			break;
 		case 1:
-			*ot++ = (acc | (c >> 4));
+			strbuf_addch(out, (acc | (c >> 4)));
 			acc = (c & 15) << 4;
 			break;
 		case 2:
-			*ot++ = (acc | (c >> 2));
+			strbuf_addch(out, (acc | (c >> 2)));
 			acc = (c & 3) << 6;
 			break;
 		case 3:
-			*ot++ = (acc | c);
+			strbuf_addch(out, (acc | c));
 			acc = pos = 0;
 			break;
 		}
 	}
-	*ot = 0;
-	return (ot - otbegin);
+	return out;
 }
 
 /*
@@ -523,16 +470,16 @@
  * Otherwise, we default to assuming it is Latin1 for historical
  * reasons.
  */
-static const char *guess_charset(const char *line, const char *target_charset)
+static const char *guess_charset(const struct strbuf *line, const char *target_charset)
 {
 	if (is_encoding_utf8(target_charset)) {
-		if (is_utf8(line))
+		if (is_utf8(line->buf))
 			return NULL;
 	}
 	return "latin1";
 }
 
-static void convert_to_utf8(char *line, unsigned linesize, const char *charset)
+static void convert_to_utf8(struct strbuf *line, const char *charset)
 {
 	char *out;
 
@@ -544,112 +491,118 @@
 
 	if (!strcmp(metainfo_charset, charset))
 		return;
-	out = reencode_string(line, metainfo_charset, charset);
+	out = reencode_string(line->buf, metainfo_charset, charset);
 	if (!out)
 		die("cannot convert from %s to %s\n",
 		    charset, metainfo_charset);
-	strlcpy(line, out, linesize);
-	free(out);
+	strbuf_attach(line, out, strlen(out), strlen(out));
 }
 
-static int decode_header_bq(char *it, unsigned itsize)
+static int decode_header_bq(struct strbuf *it)
 {
-	char *in, *out, *ep, *cp, *sp;
-	char outbuf[1000];
+	char *in, *ep, *cp;
+	struct strbuf outbuf = STRBUF_INIT, *dec;
+	struct strbuf charset_q = STRBUF_INIT, piecebuf = STRBUF_INIT;
 	int rfc2047 = 0;
 
-	in = it;
-	out = outbuf;
-	while ((ep = strstr(in, "=?")) != NULL) {
-		int sz, encoding;
-		char charset_q[256], piecebuf[256];
+	in = it->buf;
+	while (in - it->buf <= it->len && (ep = strstr(in, "=?")) != NULL) {
+		int encoding;
+		strbuf_reset(&charset_q);
+		strbuf_reset(&piecebuf);
 		rfc2047 = 1;
 
 		if (in != ep) {
-			sz = ep - in;
-			memcpy(out, in, sz);
-			out += sz;
-			in += sz;
+			strbuf_add(&outbuf, in, ep - in);
+			in = ep;
 		}
 		/* E.g.
 		 * ep : "=?iso-2022-jp?B?GyR...?= foo"
 		 * ep : "=?ISO-8859-1?Q?Foo=FCbar?= baz"
 		 */
 		ep += 2;
-		cp = strchr(ep, '?');
-		if (!cp)
-			return rfc2047; /* no munging */
-		for (sp = ep; sp < cp; sp++)
-			charset_q[sp - ep] = tolower(*sp);
-		charset_q[cp - ep] = 0;
+
+		if (ep - it->buf >= it->len || !(cp = strchr(ep, '?')))
+			goto decode_header_bq_out;
+
+		if (cp + 3 - it->buf > it->len)
+			goto decode_header_bq_out;
+		strbuf_add(&charset_q, ep, cp - ep);
+		strbuf_tolower(&charset_q);
+
 		encoding = cp[1];
 		if (!encoding || cp[2] != '?')
-			return rfc2047; /* no munging */
+			goto decode_header_bq_out;
 		ep = strstr(cp + 3, "?=");
 		if (!ep)
-			return rfc2047; /* no munging */
+			goto decode_header_bq_out;
+		strbuf_add(&piecebuf, cp + 3, ep - cp - 3);
 		switch (tolower(encoding)) {
 		default:
-			return rfc2047; /* no munging */
+			goto decode_header_bq_out;
 		case 'b':
-			sz = decode_b_segment(cp + 3, piecebuf, sizeof(piecebuf), ep);
+			dec = decode_b_segment(&piecebuf);
 			break;
 		case 'q':
-			sz = decode_q_segment(cp + 3, piecebuf, sizeof(piecebuf), ep, 1);
+			dec = decode_q_segment(&piecebuf, 1);
 			break;
 		}
-		if (sz < 0)
-			return rfc2047;
 		if (metainfo_charset)
-			convert_to_utf8(piecebuf, sizeof(piecebuf), charset_q);
+			convert_to_utf8(dec, charset_q.buf);
 
-		sz = strlen(piecebuf);
-		if (outbuf + sizeof(outbuf) <= out + sz)
-			return rfc2047; /* no munging */
-		strcpy(out, piecebuf);
-		out += sz;
+		strbuf_addbuf(&outbuf, dec);
+		strbuf_release(dec);
+		free(dec);
 		in = ep + 2;
 	}
-	strcpy(out, in);
-	strlcpy(it, outbuf, itsize);
+	strbuf_addstr(&outbuf, in);
+	strbuf_reset(it);
+	strbuf_addbuf(it, &outbuf);
+decode_header_bq_out:
+	strbuf_release(&outbuf);
+	strbuf_release(&charset_q);
+	strbuf_release(&piecebuf);
 	return rfc2047;
 }
 
-static void decode_header(char *it, unsigned itsize)
+static void decode_header(struct strbuf *it)
 {
-
-	if (decode_header_bq(it, itsize))
+	if (decode_header_bq(it))
 		return;
 	/* otherwise "it" is a straight copy of the input.
 	 * This can be binary guck but there is no charset specified.
 	 */
 	if (metainfo_charset)
-		convert_to_utf8(it, itsize, "");
+		convert_to_utf8(it, "");
 }
 
-static int decode_transfer_encoding(char *line, unsigned linesize, int inputlen)
+static void decode_transfer_encoding(struct strbuf *line)
 {
-	char *ep;
+	struct strbuf *ret;
 
 	switch (transfer_encoding) {
 	case TE_QP:
-		ep = line + inputlen;
-		return decode_q_segment(line, line, linesize, ep, 0);
+		ret = decode_q_segment(line, 0);
+		break;
 	case TE_BASE64:
-		ep = line + inputlen;
-		return decode_b_segment(line, line, linesize, ep);
+		ret = decode_b_segment(line);
+		break;
 	case TE_DONTCARE:
 	default:
-		return inputlen;
+		return;
 	}
+	strbuf_reset(line);
+	strbuf_addbuf(line, ret);
+	strbuf_release(ret);
+	free(ret);
 }
 
-static int handle_filter(char *line, unsigned linesize, int linelen);
+static void handle_filter(struct strbuf *line);
 
 static int find_boundary(void)
 {
-	while(fgets(line, sizeof(line), fin) != NULL) {
-		if (is_multipart_boundary(line))
+	while (!strbuf_getline(&line, fin, '\n')) {
+		if (is_multipart_boundary(&line))
 			return 1;
 	}
 	return 0;
@@ -657,12 +610,17 @@
 
 static int handle_boundary(void)
 {
-	char newline[]="\n";
+	struct strbuf newline = STRBUF_INIT;
+
+	strbuf_addch(&newline, '\n');
 again:
-	if (!memcmp(line+content_top->boundary_len, "--", 2)) {
+	if (line.len >= (*content_top)->len + 2 &&
+	    !memcmp(line.buf + (*content_top)->len, "--", 2)) {
 		/* we hit an end boundary */
 		/* pop the current boundary off the stack */
-		free(content_top->boundary);
+		strbuf_release(*content_top);
+		free(*content_top);
+		*content_top = NULL;
 
 		/* technically won't happen as is_multipart_boundary()
 		   will fail first.  But just in case..
@@ -672,7 +630,8 @@
 					"can't recover\n");
 			exit(1);
 		}
-		handle_filter(newline, sizeof(newline), strlen(newline));
+		handle_filter(&newline);
+		strbuf_release(&newline);
 
 		/* skip to the next boundary */
 		if (!find_boundary())
@@ -682,39 +641,44 @@
 
 	/* set some defaults */
 	transfer_encoding = TE_DONTCARE;
-	charset[0] = 0;
+	strbuf_reset(&charset);
 	message_type = TYPE_TEXT;
 
 	/* slurp in this section's info */
-	while (read_one_header_line(line, sizeof(line), fin))
-		check_header(line, sizeof(line), p_hdr_data, 0);
+	while (read_one_header_line(&line, fin))
+		check_header(&line, p_hdr_data, 0);
 
+	strbuf_release(&newline);
 	/* eat the blank line after section info */
-	return (fgets(line, sizeof(line), fin) != NULL);
+	return (strbuf_getline(&line, fin, '\n') == 0);
 }
 
-static inline int patchbreak(const char *line)
+static inline int patchbreak(const struct strbuf *line)
 {
+	size_t i;
+
 	/* Beginning of a "diff -" header? */
-	if (!memcmp("diff -", line, 6))
+	if (!prefixcmp(line->buf, "diff -"))
 		return 1;
 
 	/* CVS "Index: " line? */
-	if (!memcmp("Index: ", line, 7))
+	if (!prefixcmp(line->buf, "Index: "))
 		return 1;
 
 	/*
 	 * "--- <filename>" starts patches without headers
 	 * "---<sp>*" is a manual separator
 	 */
-	if (!memcmp("---", line, 3)) {
-		line += 3;
+	if (line->len < 4)
+		return 0;
+
+	if (!prefixcmp(line->buf, "---")) {
 		/* space followed by a filename? */
-		if (line[0] == ' ' && !isspace(line[1]))
+		if (line->buf[3] == ' ' && !isspace(line->buf[4]))
 			return 1;
 		/* Just whitespace? */
-		for (;;) {
-			unsigned char c = *line++;
+		for (i = 3; i < line->len; i++) {
+			unsigned char c = line->buf[i];
 			if (c == '\n')
 				return 1;
 			if (!isspace(c))
@@ -725,32 +689,24 @@
 	return 0;
 }
 
-
-static int handle_commit_msg(char *line, unsigned linesize)
+static int handle_commit_msg(struct strbuf *line)
 {
 	static int still_looking = 1;
-	char *endline = line + linesize;
 
 	if (!cmitmsg)
 		return 0;
 
 	if (still_looking) {
-		char *cp = line;
-		if (isspace(*line)) {
-			for (cp = line + 1; *cp; cp++) {
-				if (!isspace(*cp))
-					break;
-			}
-			if (!*cp)
-				return 0;
-		}
-		if ((still_looking = check_header(cp, endline - cp, s_hdr_data, 0)) != 0)
+		strbuf_ltrim(line);
+		if (!line->len)
+			return 0;
+		if ((still_looking = check_header(line, s_hdr_data, 0)) != 0)
 			return 0;
 	}
 
 	/* normalize the log message to UTF-8. */
 	if (metainfo_charset)
-		convert_to_utf8(line, endline - line, charset);
+		convert_to_utf8(line, charset.buf);
 
 	if (patchbreak(line)) {
 		fclose(cmitmsg);
@@ -758,142 +714,132 @@
 		return 1;
 	}
 
-	fputs(line, cmitmsg);
+	fputs(line->buf, cmitmsg);
 	return 0;
 }
 
-static int handle_patch(char *line, int len)
+static void handle_patch(const struct strbuf *line)
 {
-	fwrite(line, 1, len, patchfile);
+	fwrite(line->buf, 1, line->len, patchfile);
 	patch_lines++;
-	return 0;
 }
 
-static int handle_filter(char *line, unsigned linesize, int linelen)
+static void handle_filter(struct strbuf *line)
 {
 	static int filter = 0;
 
-	/* filter tells us which part we left off on
-	 * a non-zero return indicates we hit a filter point
-	 */
+	/* filter tells us which part we left off on */
 	switch (filter) {
 	case 0:
-		if (!handle_commit_msg(line, linesize))
+		if (!handle_commit_msg(line))
 			break;
 		filter++;
 	case 1:
-		if (!handle_patch(line, linelen))
-			break;
-		filter++;
-	default:
-		return 1;
+		handle_patch(line);
+		break;
 	}
-
-	return 0;
 }
 
 static void handle_body(void)
 {
-	int rc = 0;
-	static char newline[2000];
-	static char *np = newline;
-	int len = strlen(line);
+	int len = 0;
+	struct strbuf prev = STRBUF_INIT;
 
 	/* Skip up to the first boundary */
-	if (content_top->boundary) {
+	if (*content_top) {
 		if (!find_boundary())
-			return;
+			goto handle_body_out;
 	}
 
 	do {
+		strbuf_setlen(&line, line.len + len);
+
 		/* process any boundary lines */
-		if (content_top->boundary && is_multipart_boundary(line)) {
+		if (*content_top && is_multipart_boundary(&line)) {
 			/* flush any leftover */
-			if (np != newline)
-				handle_filter(newline, sizeof(newline),
-					      np - newline);
+			if (line.len)
+				handle_filter(&line);
+
 			if (!handle_boundary())
-				return;
-			len = strlen(line);
+				goto handle_body_out;
 		}
 
 		/* Unwrap transfer encoding */
-		len = decode_transfer_encoding(line, sizeof(line), len);
-		if (len < 0) {
-			error("Malformed input line");
-			return;
-		}
+		decode_transfer_encoding(&line);
 
 		switch (transfer_encoding) {
 		case TE_BASE64:
 		case TE_QP:
 		{
-			char *op = line;
+			struct strbuf **lines, **it, *sb;
+
+			/* Prepend any previous partial lines */
+			strbuf_insert(&line, 0, prev.buf, prev.len);
+			strbuf_reset(&prev);
 
 			/* binary data most likely doesn't have newlines */
 			if (message_type != TYPE_TEXT) {
-				rc = handle_filter(line, sizeof(line), len);
+				handle_filter(&line);
 				break;
 			}
-
 			/*
 			 * This is a decoded line that may contain
 			 * multiple new lines.  Pass only one chunk
 			 * at a time to handle_filter()
 			 */
-			do {
-				while (op < line + len && *op != '\n')
-					*np++ = *op++;
-				*np = *op;
-				if (*np != 0) {
-					/* should be sitting on a new line */
-					*(++np) = 0;
-					op++;
-					rc = handle_filter(newline, sizeof(newline), np - newline);
-					np = newline;
-				}
-			} while (op < line + len);
+			lines = strbuf_split(&line, '\n');
+			for (it = lines; (sb = *it); it++) {
+				if (*(it + 1) == NULL) /* The last line */
+					if (sb->buf[sb->len - 1] != '\n') {
+						/* Partial line, save it for later. */
+						strbuf_addbuf(&prev, sb);
+						break;
+					}
+				handle_filter(sb);
+			}
 			/*
-			 * The partial chunk is saved in newline and will be
+			 * The partial chunk is saved in "prev" and will be
 			 * appended by the next iteration of read_line_with_nul().
 			 */
+			strbuf_list_free(lines);
 			break;
 		}
 		default:
-			rc = handle_filter(line, sizeof(line), len);
+			handle_filter(&line);
 		}
-		if (rc)
-			/* nothing left to filter */
-			break;
-	} while ((len = read_line_with_nul(line, sizeof(line), fin)));
 
-	return;
+		strbuf_reset(&line);
+		if (strbuf_avail(&line) < 100)
+			strbuf_grow(&line, 100);
+	} while ((len = read_line_with_nul(line.buf, strbuf_avail(&line), fin)));
+
+handle_body_out:
+	strbuf_release(&prev);
 }
 
-static void output_header_lines(FILE *fout, const char *hdr, char *data)
+static void output_header_lines(FILE *fout, const char *hdr, const struct strbuf *data)
 {
+	const char *sp = data->buf;
 	while (1) {
-		char *ep = strchr(data, '\n');
+		char *ep = strchr(sp, '\n');
 		int len;
 		if (!ep)
-			len = strlen(data);
+			len = strlen(sp);
 		else
-			len = ep - data;
-		fprintf(fout, "%s: %.*s\n", hdr, len, data);
+			len = ep - sp;
+		fprintf(fout, "%s: %.*s\n", hdr, len, sp);
 		if (!ep)
 			break;
-		data = ep + 1;
+		sp = ep + 1;
 	}
 }
 
 static void handle_info(void)
 {
-	char *sub;
-	char *hdr;
+	struct strbuf *hdr;
 	int i;
 
 	for (i = 0; header[i]; i++) {
-
 		/* only print inbody headers if we output a patch file */
 		if (patch_lines && s_hdr_data[i])
 			hdr = s_hdr_data[i];
@@ -903,20 +849,18 @@
 			continue;
 
 		if (!memcmp(header[i], "Subject", 7)) {
-			if (keep_subject)
-				sub = hdr;
-			else {
-				sub = cleanup_subject(hdr);
-				cleanup_space(sub);
+			if (!keep_subject) {
+				cleanup_subject(hdr);
+				cleanup_space(hdr);
 			}
-			output_header_lines(fout, "Subject", sub);
+			output_header_lines(fout, "Subject", hdr);
 		} else if (!memcmp(header[i], "From", 4)) {
 			handle_from(hdr);
-			fprintf(fout, "Author: %s\n", name);
-			fprintf(fout, "Email: %s\n", email);
+			fprintf(fout, "Author: %s\n", name.buf);
+			fprintf(fout, "Email: %s\n", email.buf);
 		} else {
 			cleanup_space(hdr);
-			fprintf(fout, "%s: %s\n", header[i], hdr);
+			fprintf(fout, "%s: %s\n", header[i], hdr->buf);
 		}
 	}
 	fprintf(fout, "\n");
@@ -943,8 +887,8 @@
 		return -1;
 	}
 
-	p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(char *));
-	s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(char *));
+	p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*p_hdr_data));
+	s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*s_hdr_data));
 
 	do {
 		peek = fgetc(in);
@@ -952,8 +896,8 @@
 	ungetc(peek, in);
 
 	/* process the email header */
-	while (read_one_header_line(line, sizeof(line), fin))
-		check_header(line, sizeof(line), p_hdr_data, 1);
+	while (read_one_header_line(&line, fin))
+		check_header(&line, p_hdr_data, 1);
 
 	handle_body();
 	handle_info();
@@ -962,7 +906,7 @@
 }
 
 static const char mailinfo_usage[] =
-	"git-mailinfo [-k] [-u | --encoding=<encoding> | -n] msg patch <mail >info";
+	"git mailinfo [-k] [-u | --encoding=<encoding> | -n] msg patch <mail >info";
 
 int cmd_mailinfo(int argc, const char **argv, const char *prefix)
 {
diff --git a/builtin-mailsplit.c b/builtin-mailsplit.c
index e8cbe67..13c60c3 100644
--- a/builtin-mailsplit.c
+++ b/builtin-mailsplit.c
@@ -9,7 +9,7 @@
 #include "path-list.h"
 
 static const char git_mailsplit_usage[] =
-"git-mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> [<mbox>|<Maildir>...]";
+"git mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> [<mbox>|<Maildir>...]";
 
 static int is_from_line(const char *line, int len)
 {
diff --git a/builtin-merge-base.c b/builtin-merge-base.c
index bcf9395..1cb2925 100644
--- a/builtin-merge-base.c
+++ b/builtin-merge-base.c
@@ -20,7 +20,7 @@
 }
 
 static const char merge_base_usage[] =
-"git-merge-base [--all] <commit-id> <commit-id>";
+"git merge-base [--all] <commit-id> <commit-id>";
 
 int cmd_merge_base(int argc, const char **argv, const char *prefix)
 {
diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c
index 3731853..652a2c3 100644
--- a/builtin-merge-recursive.c
+++ b/builtin-merge-recursive.c
@@ -248,7 +248,7 @@
 
 static int save_files_dirs(const unsigned char *sha1,
 		const char *base, int baselen, const char *path,
-		unsigned int mode, int stage)
+		unsigned int mode, int stage, void *context)
 {
 	int len = strlen(path);
 	char *newpath = xmalloc(baselen + len + 1);
@@ -268,7 +268,7 @@
 static int get_files_dirs(struct tree *tree)
 {
 	int n;
-	if (read_tree_recursive(tree, "", 0, 0, NULL, save_files_dirs) != 0)
+	if (read_tree_recursive(tree, "", 0, 0, NULL, save_files_dirs, NULL))
 		return 0;
 	n = current_file_set.nr + current_directory_set.nr;
 	return n;
diff --git a/builtin-merge.c b/builtin-merge.c
index 129b4e6..e97c79e 100644
--- a/builtin-merge.c
+++ b/builtin-merge.c
@@ -50,11 +50,9 @@
 static const char *branch;
 
 static struct strategy all_strategy[] = {
-	{ "recur",      NO_TRIVIAL },
 	{ "recursive",  DEFAULT_TWOHEAD | NO_TRIVIAL },
 	{ "octopus",    DEFAULT_OCTOPUS },
 	{ "resolve",    0 },
-	{ "stupid",     0 },
 	{ "ours",       NO_FAST_FORWARD | NO_TRIVIAL },
 	{ "subtree",    NO_FAST_FORWARD | NO_TRIVIAL },
 };
@@ -68,10 +66,11 @@
 
 	if (unset)
 		strbuf_setlen(buf, 0);
-	else {
+	else if (arg) {
 		strbuf_addf(buf, "%s\n\n", arg);
 		have_message = 1;
-	}
+	} else
+		return error("switch `m' requires a value");
 	return 0;
 }
 
diff --git a/builtin-mv.c b/builtin-mv.c
index 5530e11..ba9ceda 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -11,7 +11,7 @@
 #include "parse-options.h"
 
 static const char * const builtin_mv_usage[] = {
-	"git-mv [options] <source>... <destination>",
+	"git mv [options] <source>... <destination>",
 	NULL
 };
 
diff --git a/builtin-name-rev.c b/builtin-name-rev.c
index f153da0..85612c4 100644
--- a/builtin-name-rev.c
+++ b/builtin-name-rev.c
@@ -172,7 +172,7 @@
 }
 
 static char const * const name_rev_usage[] = {
-	"git-name-rev [options] ( --all | --stdin | <commit>... )",
+	"git name-rev [options] ( --all | --stdin | <commit>... )",
 	NULL
 };
 
diff --git a/builtin-pack-refs.c b/builtin-pack-refs.c
index ff90aef..34246df 100644
--- a/builtin-pack-refs.c
+++ b/builtin-pack-refs.c
@@ -3,7 +3,7 @@
 #include "pack-refs.h"
 
 static char const * const pack_refs_usage[] = {
-	"git-pack-refs [options]",
+	"git pack-refs [options]",
 	NULL
 };
 
diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c
index 241afbb..10cb8df 100644
--- a/builtin-prune-packed.c
+++ b/builtin-prune-packed.c
@@ -3,7 +3,7 @@
 #include "progress.h"
 
 static const char prune_packed_usage[] =
-"git-prune-packed [-n] [-q]";
+"git prune-packed [-n] [-q]";
 
 #define DRY_RUN 01
 #define VERBOSE 02
diff --git a/builtin-prune.c b/builtin-prune.c
index bd3d2f6..7de4cab 100644
--- a/builtin-prune.c
+++ b/builtin-prune.c
@@ -7,7 +7,7 @@
 #include "parse-options.h"
 
 static const char * const prune_usage[] = {
-	"git-prune [-n] [--expire <time>] [--] [<head>...]",
+	"git prune [-n] [--expire <time>] [--] [<head>...]",
 	NULL
 };
 static int show_only;
diff --git a/builtin-push.c b/builtin-push.c
index b35aad6..c1ed68d 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -10,11 +10,11 @@
 #include "parse-options.h"
 
 static const char * const push_usage[] = {
-	"git-push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]",
+	"git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]",
 	NULL,
 };
 
-static int thin, verbose;
+static int thin;
 static const char *receivepack;
 
 static const char **refspec;
@@ -84,7 +84,7 @@
 		if (thin)
 			transport_set_option(transport, TRANS_OPT_THIN, "yes");
 
-		if (verbose)
+		if (flags & TRANSPORT_PUSH_VERBOSE)
 			fprintf(stderr, "Pushing to %s\n", remote->url[i]);
 		err = transport_push(transport, refspec_nr, refspec, flags);
 		err |= transport_disconnect(transport);
@@ -101,22 +101,19 @@
 int cmd_push(int argc, const char **argv, const char *prefix)
 {
 	int flags = 0;
-	int all = 0;
-	int mirror = 0;
-	int dry_run = 0;
-	int force = 0;
 	int tags = 0;
 	int rc;
 	const char *repo = NULL;	/* default repository */
 
 	struct option options[] = {
-		OPT__VERBOSE(&verbose),
+		OPT_BIT('v', "verbose", &flags, "be verbose", TRANSPORT_PUSH_VERBOSE),
 		OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
-		OPT_BOOLEAN( 0 , "all", &all, "push all refs"),
-		OPT_BOOLEAN( 0 , "mirror", &mirror, "mirror all refs"),
+		OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL),
+		OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
+			    (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
 		OPT_BOOLEAN( 0 , "tags", &tags, "push tags"),
-		OPT_BOOLEAN( 0 , "dry-run", &dry_run, "dry run"),
-		OPT_BOOLEAN('f', "force", &force, "force updates"),
+		OPT_BIT( 0 , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
+		OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
 		OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
 		OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
 		OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
@@ -125,18 +122,8 @@
 
 	argc = parse_options(argc, argv, options, push_usage, 0);
 
-	if (force)
-		flags |= TRANSPORT_PUSH_FORCE;
-	if (dry_run)
-		flags |= TRANSPORT_PUSH_DRY_RUN;
-	if (verbose)
-		flags |= TRANSPORT_PUSH_VERBOSE;
 	if (tags)
 		add_refspec("refs/tags/*");
-	if (all)
-		flags |= TRANSPORT_PUSH_ALL;
-	if (mirror)
-		flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
 
 	if (argc > 0) {
 		repo = argv[0];
diff --git a/builtin-reflog.c b/builtin-reflog.c
index 125d455..0c34e37 100644
--- a/builtin-reflog.c
+++ b/builtin-reflog.c
@@ -13,9 +13,9 @@
  */
 
 static const char reflog_expire_usage[] =
-"git-reflog (show|expire) [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
+"git reflog (show|expire) [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
 static const char reflog_delete_usage[] =
-"git-reflog delete [--verbose] [--dry-run] [--rewrite] [--updateref] <refs>...";
+"git reflog delete [--verbose] [--dry-run] [--rewrite] [--updateref] <refs>...";
 
 static unsigned long default_reflog_expire;
 static unsigned long default_reflog_expire_unreachable;
@@ -630,7 +630,7 @@
  */
 
 static const char reflog_usage[] =
-"git-reflog (expire | ...)";
+"git reflog (expire | ...)";
 
 int cmd_reflog(int argc, const char **argv, const char *prefix)
 {
diff --git a/builtin-remote.c b/builtin-remote.c
index 1491354..db12668 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -147,6 +147,15 @@
 
 static struct path_list branch_list;
 
+static const char *abbrev_ref(const char *name, const char *prefix)
+{
+	const char *abbrev = skip_prefix(name, prefix);
+	if (abbrev)
+		return abbrev;
+	return name;
+}
+#define abbrev_branch(name) abbrev_ref((name), "refs/heads/")
+
 static int config_read_branches(const char *key, const char *value, void *cb)
 {
 	if (!prefixcmp(key, "branch.")) {
@@ -176,18 +185,12 @@
 			info->remote = xstrdup(value);
 		} else {
 			char *space = strchr(value, ' ');
-			const char *ptr = skip_prefix(value, "refs/heads/");
-			if (ptr)
-				value = ptr;
+			value = abbrev_branch(value);
 			while (space) {
 				char *merge;
 				merge = xstrndup(value, space - value);
 				path_list_append(merge, &info->merge);
-				ptr = skip_prefix(space + 1, "refs/heads/");
-				if (ptr)
-					value = ptr;
-				else
-					value = space + 1;
+				value = abbrev_branch(space + 1);
 				space = strchr(value, ' ');
 			}
 			path_list_append(xstrdup(value), &info->merge);
@@ -219,12 +222,7 @@
 	refspec.dst = (char *)refname;
 	if (!remote_find_tracking(states->remote, &refspec)) {
 		struct path_list_item *item;
-		const char *name, *ptr;
-		ptr = skip_prefix(refspec.src, "refs/heads/");
-		if (ptr)
-			name = ptr;
-		else
-			name = refspec.src;
+		const char *name = abbrev_branch(refspec.src);
 		/* symbolic refs pointing nowhere were handled already */
 		if ((flags & REF_ISSYMREF) ||
 				unsorted_path_list_has_path(&states->tracked,
@@ -253,7 +251,6 @@
 		struct path_list *target = &states->tracked;
 		unsigned char sha1[20];
 		void *util = NULL;
-		const char *ptr;
 
 		if (!ref->peer_ref || read_ref(ref->peer_ref->name, sha1))
 			target = &states->new;
@@ -262,10 +259,7 @@
 			if (hashcmp(sha1, ref->new_sha1))
 				util = &states;
 		}
-		ptr = skip_prefix(ref->name, "refs/heads/");
-		if (!ptr)
-			ptr = ref->name;
-		path_list_append(ptr, target)->util = util;
+		path_list_append(abbrev_branch(ref->name), target)->util = util;
 	}
 	free_refs(fetch_map);
 
@@ -460,10 +454,8 @@
 
 	memset(&refspec, 0, sizeof(refspec));
 	refspec.dst = (char *)refname;
-	if (!remote_find_tracking(states->remote, &refspec)) {
-		path_list_append(skip_prefix(refspec.src, "refs/heads/"),
-			&states->tracked);
-	}
+	if (!remote_find_tracking(states->remote, &refspec))
+		path_list_append(abbrev_branch(refspec.src), &states->tracked);
 
 	return 0;
 }
@@ -530,15 +522,10 @@
 					"es" : "");
 			for (i = 0; i < states.remote->push_refspec_nr; i++) {
 				struct refspec *spec = states.remote->push + i;
-				const char *p = "", *q = "";
-				if (spec->src)
-					p = skip_prefix(spec->src, "refs/heads/");
-				if (spec->dst)
-					q = skip_prefix(spec->dst, "refs/heads/");
 				printf(" %s%s%s%s", spec->force ? "+" : "",
-					p ? p : spec->src,
-					spec->dst ? ":" : "",
-					q ? q : spec->dst);
+				       abbrev_branch(spec->src),
+				       spec->dst ? ":" : "",
+				       spec->dst ? abbrev_branch(spec->dst) : "");
 			}
 			printf("\n");
 		}
@@ -588,7 +575,7 @@
 				result |= delete_ref(refname, NULL);
 
 			printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned",
-			       skip_prefix(refname, "refs/remotes/"));
+			       abbrev_ref(refname, "refs/remotes/"));
 		}
 
 		/* NEEDSWORK: free remote */
diff --git a/builtin-rerere.c b/builtin-rerere.c
index 5d40e16..5805805 100644
--- a/builtin-rerere.c
+++ b/builtin-rerere.c
@@ -6,7 +6,7 @@
 #include "xdiff-interface.h"
 
 static const char git_rerere_usage[] =
-"git-rerere [clear | status | diff | gc]";
+"git rerere [clear | status | diff | gc]";
 
 /* these values are days */
 static int cutoff_noresolve = 15;
diff --git a/builtin-reset.c b/builtin-reset.c
index a0321694..4d246c3 100644
--- a/builtin-reset.c
+++ b/builtin-reset.c
@@ -20,8 +20,8 @@
 #include "parse-options.h"
 
 static const char * const git_reset_usage[] = {
-	"git-reset [--mixed | --soft | --hard] [-q] [<commit>]",
-	"git-reset [--mixed] <commit> [--] <paths>...",
+	"git reset [--mixed | --soft | --hard] [-q] [<commit>]",
+	"git reset [--mixed] <commit> [--] <paths>...",
 	NULL
 };
 
@@ -96,7 +96,7 @@
 
 	if (read_cache() < 0)
 		return error("Could not read index");
-	result = refresh_cache(0) ? 1 : 0;
+	result = refresh_cache(REFRESH_SAY_CHANGED) ? 1 : 0;
 	if (write_cache(fd, active_cache, active_nr) ||
 			commit_locked_index(index_lock))
 		return error ("Could not refresh index");
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index b4a2c44..893762c 100644
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
@@ -17,7 +17,7 @@
 #define COUNTED		(1u<<16)
 
 static const char rev_list_usage[] =
-"git-rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
+"git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
 "  limiting output:\n"
 "    --max-count=nr\n"
 "    --max-age=epoch\n"
@@ -590,6 +590,7 @@
 	revs.commit_format = CMIT_FMT_UNSPECIFIED;
 	argc = setup_revisions(argc, argv, &revs, NULL);
 
+	quiet = DIFF_OPT_TST(&revs.diffopt, QUIET);
 	for (i = 1 ; i < argc; i++) {
 		const char *arg = argv[i];
 
@@ -621,10 +622,6 @@
 			read_revisions_from_stdin(&revs);
 			continue;
 		}
-		if (!strcmp(arg, "--quiet")) {
-			quiet = 1;
-			continue;
-		}
 		usage(rev_list_usage);
 
 	}
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index a7860ed..aa71f4a 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -268,7 +268,7 @@
 {
 	static int keep_dashdash = 0;
 	static char const * const parseopt_usage[] = {
-		"git-rev-parse --parseopt [options] -- [<args>...]",
+		"git rev-parse --parseopt [options] -- [<args>...]",
 		NULL
 	};
 	static struct option parseopt_opts[] = {
diff --git a/builtin-revert.c b/builtin-revert.c
index f3d4524..e9da870 100644
--- a/builtin-revert.c
+++ b/builtin-revert.c
@@ -24,12 +24,12 @@
  */
 
 static const char * const revert_usage[] = {
-	"git-revert [options] <commit-ish>",
+	"git revert [options] <commit-ish>",
 	NULL
 };
 
 static const char * const cherry_pick_usage[] = {
-	"git-cherry-pick [options] <commit-ish>",
+	"git cherry-pick [options] <commit-ish>",
 	NULL
 };
 
diff --git a/builtin-rm.c b/builtin-rm.c
index 22c9bd1..ee8247b 100644
--- a/builtin-rm.c
+++ b/builtin-rm.c
@@ -11,7 +11,7 @@
 #include "parse-options.h"
 
 static const char * const builtin_rm_usage[] = {
-	"git-rm [options] [--] <file>...",
+	"git rm [options] [--] <file>...",
 	NULL
 };
 
@@ -146,11 +146,6 @@
 
 	git_config(git_default_config, NULL);
 
-	newfd = hold_locked_index(&lock_file, 1);
-
-	if (read_cache() < 0)
-		die("index file corrupt");
-
 	argc = parse_options(argc, argv, builtin_rm_options, builtin_rm_usage, 0);
 	if (!argc)
 		usage_with_options(builtin_rm_usage, builtin_rm_options);
@@ -158,6 +153,11 @@
 	if (!index_only)
 		setup_work_tree();
 
+	newfd = hold_locked_index(&lock_file, 1);
+
+	if (read_cache() < 0)
+		die("index file corrupt");
+
 	pathspec = get_pathspec(prefix, argv);
 	seen = NULL;
 	for (i = 0; pathspec[i] ; i++)
diff --git a/builtin-send-pack.c b/builtin-send-pack.c
index a708d0a..7588d22 100644
--- a/builtin-send-pack.c
+++ b/builtin-send-pack.c
@@ -8,7 +8,7 @@
 #include "send-pack.h"
 
 static const char send_pack_usage[] =
-"git-send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
+"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
 "  --all and explicit <ref> specification are mutually exclusive.";
 
 static struct send_pack_args args = {
diff --git a/builtin-shortlog.c b/builtin-shortlog.c
index f8bcbfc..94c4723 100644
--- a/builtin-shortlog.c
+++ b/builtin-shortlog.c
@@ -10,7 +10,7 @@
 #include "parse-options.h"
 
 static char const * const shortlog_usage[] = {
-	"git-shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]",
+	"git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]",
 	"",
 	"[rev-opts] are documented in git-rev-list(1)",
 	NULL
diff --git a/builtin-show-branch.c b/builtin-show-branch.c
index 93047f5..233eed4 100644
--- a/builtin-show-branch.c
+++ b/builtin-show-branch.c
@@ -4,7 +4,7 @@
 #include "builtin.h"
 
 static const char show_branch_usage[] =
-"git-show-branch [--sparse] [--current] [--all] [--remotes] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...] | --reflog[=n[,b]] <branch>";
+"git show-branch [--sparse] [--current] [--all] [--remotes] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...] | --reflog[=n[,b]] <branch>";
 static const char show_branch_usage_reflog[] =
 "--reflog is incompatible with --all, --remotes, --independent or --merge-base";
 
diff --git a/builtin-symbolic-ref.c b/builtin-symbolic-ref.c
index b49bdb6..bfc78bb 100644
--- a/builtin-symbolic-ref.c
+++ b/builtin-symbolic-ref.c
@@ -4,7 +4,7 @@
 #include "parse-options.h"
 
 static const char * const git_symbolic_ref_usage[] = {
-	"git-symbolic-ref [options] name [ref]",
+	"git symbolic-ref [options] name [ref]",
 	NULL
 };
 
diff --git a/builtin-tag.c b/builtin-tag.c
index a70922b..c2cca6c 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -14,10 +14,10 @@
 #include "parse-options.h"
 
 static const char * const git_tag_usage[] = {
-	"git-tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
-	"git-tag -d <tagname>...",
-	"git-tag -l [-n[<num>]] [<pattern>]",
-	"git-tag -v <tagname>...",
+	"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
+	"git tag -d <tagname>...",
+	"git tag -l [-n[<num>]] [<pattern>]",
+	"git tag -v <tagname>...",
 	NULL
 };
 
diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c
index b04719e..f4bea4a 100644
--- a/builtin-tar-tree.c
+++ b/builtin-tar-tree.c
@@ -8,7 +8,7 @@
 #include "quote.h"
 
 static const char tar_tree_usage[] =
-"git-tar-tree [--remote=<repo>] <tree-ish> [basedir]\n"
+"git tar-tree [--remote=<repo>] <tree-ish> [basedir]\n"
 "*** Note that this command is now deprecated; use git-archive instead.";
 
 int cmd_tar_tree(int argc, const char **argv, const char *prefix)
diff --git a/builtin-update-index.c b/builtin-update-index.c
index 9e0d7ab..38eb53c 100644
--- a/builtin-update-index.c
+++ b/builtin-update-index.c
@@ -387,7 +387,7 @@
 }
 
 static const char update_index_usage[] =
-"git-update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] <file>...";
+"git update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] <file>...";
 
 static unsigned char head_sha1[20];
 static unsigned char merge_head_sha1[20];
diff --git a/builtin-update-ref.c b/builtin-update-ref.c
index d90d11d..56a0b1b 100644
--- a/builtin-update-ref.c
+++ b/builtin-update-ref.c
@@ -4,8 +4,8 @@
 #include "parse-options.h"
 
 static const char * const git_update_ref_usage[] = {
-	"git-update-ref [options] -d <refname> [<oldval>]",
-	"git-update-ref [options]    <refname> <newval> [<oldval>]",
+	"git update-ref [options] -d <refname> [<oldval>]",
+	"git update-ref [options]    <refname> <newval> [<oldval>]",
 	NULL
 };
 
diff --git a/builtin-upload-archive.c b/builtin-upload-archive.c
index 371400d..13a6c62 100644
--- a/builtin-upload-archive.c
+++ b/builtin-upload-archive.c
@@ -8,18 +8,19 @@
 #include "sideband.h"
 
 static const char upload_archive_usage[] =
-	"git-upload-archive <repo>";
+	"git upload-archive <repo>";
 
 static const char deadchild[] =
-"git-upload-archive: archiver died with error";
+"git upload-archive: archiver died with error";
 
 static const char lostchild[] =
-"git-upload-archive: archiver process was lost";
+"git upload-archive: archiver process was lost";
 
 
 static int run_upload_archive(int argc, const char **argv, const char *prefix)
 {
-	struct archiver ar;
+	const struct archiver *ar;
+	struct archiver_args args;
 	const char *sent_argv[MAX_ARGS];
 	const char *arg_cmd = "argument ";
 	char *p, buf[4096];
@@ -65,12 +66,12 @@
 	sent_argv[sent_argc] = NULL;
 
 	/* parse all options sent by the client */
-	treeish_idx = parse_archive_args(sent_argc, sent_argv, &ar);
+	treeish_idx = parse_archive_args(sent_argc, sent_argv, &ar, &args);
 
-	parse_treeish_arg(sent_argv + treeish_idx, &ar.args, prefix);
-	parse_pathspec_arg(sent_argv + treeish_idx + 1, &ar.args);
+	parse_treeish_arg(sent_argv + treeish_idx, &args, prefix);
+	parse_pathspec_arg(sent_argv + treeish_idx + 1, &args);
 
-	return ar.write_archive(&ar.args);
+	return ar->write_archive(&args);
 }
 
 static void error_clnt(const char *fmt, ...)
diff --git a/builtin-verify-tag.c b/builtin-verify-tag.c
index 92eaa89..7d837f0 100644
--- a/builtin-verify-tag.c
+++ b/builtin-verify-tag.c
@@ -12,7 +12,7 @@
 #include <signal.h>
 
 static const char builtin_verify_tag_usage[] =
-		"git-verify-tag [-v|--verbose] <tag>...";
+		"git verify-tag [-v|--verbose] <tag>...";
 
 #define PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----"
 
diff --git a/builtin-write-tree.c b/builtin-write-tree.c
index c218799..52a3c01 100644
--- a/builtin-write-tree.c
+++ b/builtin-write-tree.c
@@ -9,7 +9,7 @@
 #include "cache-tree.h"
 
 static const char write_tree_usage[] =
-"git-write-tree [--missing-ok] [--prefix=<prefix>/]";
+"git write-tree [--missing-ok] [--prefix=<prefix>/]";
 
 int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
 {
diff --git a/cache-tree.c b/cache-tree.c
index 73cb340..5f8ee87 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -507,7 +507,7 @@
 	return read_one(&buffer, &size);
 }
 
-struct cache_tree *cache_tree_find(struct cache_tree *it, const char *path)
+static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *path)
 {
 	while (*path) {
 		const char *slash;
diff --git a/cache-tree.h b/cache-tree.h
index 44aad42..cf8b790 100644
--- a/cache-tree.h
+++ b/cache-tree.h
@@ -28,8 +28,6 @@
 int cache_tree_fully_valid(struct cache_tree *);
 int cache_tree_update(struct cache_tree *, struct cache_entry **, int, int, int);
 
-struct cache_tree *cache_tree_find(struct cache_tree *, const char *);
-
 #define WRITE_TREE_UNREADABLE_INDEX (-1)
 #define WRITE_TREE_UNMERGED_INDEX (-2)
 #define WRITE_TREE_PREFIX_ERROR (-3)
diff --git a/cache.h b/cache.h
index a779d92..38985aa 100644
--- a/cache.h
+++ b/cache.h
@@ -397,7 +397,8 @@
 #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	0x0008	/* ignore submodules */
+#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);
 
 struct lock_file {
diff --git a/compat/mingw.c b/compat/mingw.c
index c0bc849..772cad5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -536,7 +536,8 @@
 		return xstrdup(path);
 	path[strlen(path)-4] = '\0';
 	if ((!exe_only || isexe) && access(path, F_OK) == 0)
-		return xstrdup(path);
+		if (!(GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY))
+			return xstrdup(path);
 	return NULL;
 }
 
diff --git a/compat/mingw.h b/compat/mingw.h
index 5a3bcee..8ffec51 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -194,6 +194,17 @@
 #define signal mingw_signal
 
 /*
+ * ANSI emulation wrappers
+ */
+
+int winansi_fputs(const char *str, FILE *stream);
+int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
+int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
+#define fputs winansi_fputs
+#define printf(...) winansi_printf(__VA_ARGS__)
+#define fprintf(...) winansi_fprintf(__VA_ARGS__)
+
+/*
  * git specific compatibility
  */
 
diff --git a/compat/winansi.c b/compat/winansi.c
new file mode 100644
index 0000000..e2d96df
--- /dev/null
+++ b/compat/winansi.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2008 Peter Harris <git@peter.is-a-geek.org>
+ */
+
+#include <windows.h>
+#include "../git-compat-util.h"
+
+/*
+ Functions to be wrapped:
+*/
+#undef printf
+#undef fprintf
+#undef fputs
+/* TODO: write */
+
+/*
+ ANSI codes used by git: m, K
+
+ This file is git-specific. Therefore, this file does not attempt
+ to implement any codes that are not used by git.
+
+ TODO: K
+*/
+
+static HANDLE console;
+static WORD plain_attr;
+static WORD attr;
+static int negative;
+
+static void init(void)
+{
+	CONSOLE_SCREEN_BUFFER_INFO sbi;
+
+	static int initialized = 0;
+	if (initialized)
+		return;
+
+	console = GetStdHandle(STD_OUTPUT_HANDLE);
+	if (console == INVALID_HANDLE_VALUE)
+		console = NULL;
+
+	if (!console)
+		return;
+
+	GetConsoleScreenBufferInfo(console, &sbi);
+	attr = plain_attr = sbi.wAttributes;
+	negative = 0;
+
+	initialized = 1;
+}
+
+
+#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
+#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
+
+static void set_console_attr(void)
+{
+	WORD attributes = attr;
+	if (negative) {
+		attributes &= ~FOREGROUND_ALL;
+		attributes &= ~BACKGROUND_ALL;
+
+		/* This could probably use a bitmask
+		   instead of a series of ifs */
+		if (attr & FOREGROUND_RED)
+			attributes |= BACKGROUND_RED;
+		if (attr & FOREGROUND_GREEN)
+			attributes |= BACKGROUND_GREEN;
+		if (attr & FOREGROUND_BLUE)
+			attributes |= BACKGROUND_BLUE;
+
+		if (attr & BACKGROUND_RED)
+			attributes |= FOREGROUND_RED;
+		if (attr & BACKGROUND_GREEN)
+			attributes |= FOREGROUND_GREEN;
+		if (attr & BACKGROUND_BLUE)
+			attributes |= FOREGROUND_BLUE;
+	}
+	SetConsoleTextAttribute(console, attributes);
+}
+
+static const char *set_attr(const char *str)
+{
+	const char *func;
+	size_t len = strspn(str, "0123456789;");
+	func = str + len;
+
+	switch (*func) {
+	case 'm':
+		do {
+			long val = strtol(str, (char **)&str, 10);
+			switch (val) {
+			case 0: /* reset */
+				attr = plain_attr;
+				negative = 0;
+				break;
+			case 1: /* bold */
+				attr |= FOREGROUND_INTENSITY;
+				break;
+			case 2:  /* faint */
+			case 22: /* normal */
+				attr &= ~FOREGROUND_INTENSITY;
+				break;
+			case 3:  /* italic */
+				/* Unsupported */
+				break;
+			case 4:  /* underline */
+			case 21: /* double underline */
+				/* Wikipedia says this flag does nothing */
+				/* Furthermore, mingw doesn't define this flag
+				attr |= COMMON_LVB_UNDERSCORE; */
+				break;
+			case 24: /* no underline */
+				/* attr &= ~COMMON_LVB_UNDERSCORE; */
+				break;
+			case 5:  /* slow blink */
+			case 6:  /* fast blink */
+				/* We don't have blink, but we do have
+				   background intensity */
+				attr |= BACKGROUND_INTENSITY;
+				break;
+			case 25: /* no blink */
+				attr &= ~BACKGROUND_INTENSITY;
+				break;
+			case 7:  /* negative */
+				negative = 1;
+				break;
+			case 27: /* positive */
+				negative = 0;
+				break;
+			case 8:  /* conceal */
+			case 28: /* reveal */
+				/* Unsupported */
+				break;
+			case 30: /* Black */
+				attr &= ~FOREGROUND_ALL;
+				break;
+			case 31: /* Red */
+				attr &= ~FOREGROUND_ALL;
+				attr |= FOREGROUND_RED;
+				break;
+			case 32: /* Green */
+				attr &= ~FOREGROUND_ALL;
+				attr |= FOREGROUND_GREEN;
+				break;
+			case 33: /* Yellow */
+				attr &= ~FOREGROUND_ALL;
+				attr |= FOREGROUND_RED | FOREGROUND_GREEN;
+				break;
+			case 34: /* Blue */
+				attr &= ~FOREGROUND_ALL;
+				attr |= FOREGROUND_BLUE;
+				break;
+			case 35: /* Magenta */
+				attr &= ~FOREGROUND_ALL;
+				attr |= FOREGROUND_RED | FOREGROUND_BLUE;
+				break;
+			case 36: /* Cyan */
+				attr &= ~FOREGROUND_ALL;
+				attr |= FOREGROUND_GREEN | FOREGROUND_BLUE;
+				break;
+			case 37: /* White */
+				attr |= FOREGROUND_RED |
+					FOREGROUND_GREEN |
+					FOREGROUND_BLUE;
+				break;
+			case 38: /* Unknown */
+				break;
+			case 39: /* reset */
+				attr &= ~FOREGROUND_ALL;
+				attr |= (plain_attr & FOREGROUND_ALL);
+				break;
+			case 40: /* Black */
+				attr &= ~BACKGROUND_ALL;
+				break;
+			case 41: /* Red */
+				attr &= ~BACKGROUND_ALL;
+				attr |= BACKGROUND_RED;
+				break;
+			case 42: /* Green */
+				attr &= ~BACKGROUND_ALL;
+				attr |= BACKGROUND_GREEN;
+				break;
+			case 43: /* Yellow */
+				attr &= ~BACKGROUND_ALL;
+				attr |= BACKGROUND_RED | BACKGROUND_GREEN;
+				break;
+			case 44: /* Blue */
+				attr &= ~BACKGROUND_ALL;
+				attr |= BACKGROUND_BLUE;
+				break;
+			case 45: /* Magenta */
+				attr &= ~BACKGROUND_ALL;
+				attr |= BACKGROUND_RED | BACKGROUND_BLUE;
+				break;
+			case 46: /* Cyan */
+				attr &= ~BACKGROUND_ALL;
+				attr |= BACKGROUND_GREEN | BACKGROUND_BLUE;
+				break;
+			case 47: /* White */
+				attr |= BACKGROUND_RED |
+					BACKGROUND_GREEN |
+					BACKGROUND_BLUE;
+				break;
+			case 48: /* Unknown */
+				break;
+			case 49: /* reset */
+				attr &= ~BACKGROUND_ALL;
+				attr |= (plain_attr & BACKGROUND_ALL);
+				break;
+			default:
+				/* Unsupported code */
+				break;
+			}
+			str++;
+		} while (*(str-1) == ';');
+
+		set_console_attr();
+		break;
+	case 'K':
+		/* TODO */
+		break;
+	default:
+		/* Unsupported code */
+		break;
+	}
+
+	return func + 1;
+}
+
+static int ansi_emulate(const char *str, FILE *stream)
+{
+	int rv = 0;
+	const char *pos = str;
+
+	while (*pos) {
+		pos = strstr(str, "\033[");
+		if (pos) {
+			size_t len = pos - str;
+
+			if (len) {
+				size_t out_len = fwrite(str, 1, len, stream);
+				rv += out_len;
+				if (out_len < len)
+					return rv;
+			}
+
+			str = pos + 2;
+			rv += 2;
+
+			fflush(stream);
+
+			pos = set_attr(str);
+			rv += pos - str;
+			str = pos;
+		} else {
+			rv += strlen(str);
+			fputs(str, stream);
+			return rv;
+		}
+	}
+	return rv;
+}
+
+int winansi_fputs(const char *str, FILE *stream)
+{
+	int rv;
+
+	if (!isatty(fileno(stream)))
+		return fputs(str, stream);
+
+	init();
+
+	if (!console)
+		return fputs(str, stream);
+
+	rv = ansi_emulate(str, stream);
+
+	if (rv >= 0)
+		return 0;
+	else
+		return EOF;
+}
+
+static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+{
+	int len, rv;
+	char small_buf[256];
+	char *buf = small_buf;
+	va_list cp;
+
+	if (!isatty(fileno(stream)))
+		goto abort;
+
+	init();
+
+	if (!console)
+		goto abort;
+
+	va_copy(cp, list);
+	len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
+	va_end(cp);
+
+	if (len > sizeof(small_buf) - 1) {
+		buf = malloc(len + 1);
+		if (!buf)
+			goto abort;
+
+		len = vsnprintf(buf, len + 1, format, list);
+	}
+
+	rv = ansi_emulate(buf, stream);
+
+	if (buf != small_buf)
+		free(buf);
+	return rv;
+
+abort:
+	rv = vfprintf(stream, format, list);
+	return rv;
+}
+
+int winansi_fprintf(FILE *stream, const char *format, ...)
+{
+	va_list list;
+	int rv;
+
+	va_start(list, format);
+	rv = winansi_vfprintf(stream, format, list);
+	va_end(list);
+
+	return rv;
+}
+
+int winansi_printf(const char *format, ...)
+{
+	va_list list;
+	int rv;
+
+	va_start(list, format);
+	rv = winansi_vfprintf(stdout, format, list);
+	va_end(list);
+
+	return rv;
+}
diff --git a/contrib/examples/git-merge.sh b/contrib/examples/git-merge.sh
index 8026ccf..e9588ee 100755
--- a/contrib/examples/git-merge.sh
+++ b/contrib/examples/git-merge.sh
@@ -5,8 +5,8 @@
 
 OPTIONS_KEEPDASHDASH=
 OPTIONS_SPEC="\
-git-merge [options] <remote>...
-git-merge [options] <msg> HEAD <remote>
+git merge [options] <remote>...
+git merge [options] <msg> HEAD <remote>
 --
 stat                 show a diffstat at the end of the merge
 n                    don't show a diffstat at the end of the merge
diff --git a/daemon.c b/daemon.c
index ce3a6f5..7df41a6 100644
--- a/daemon.c
+++ b/daemon.c
@@ -18,7 +18,7 @@
 static int reuseaddr;
 
 static const char daemon_usage[] =
-"git-daemon [--verbose] [--syslog] [--export-all]\n"
+"git daemon [--verbose] [--syslog] [--export-all]\n"
 "           [--timeout=n] [--init-timeout=n] [--strict-paths]\n"
 "           [--base-path=path] [--base-path-relaxed]\n"
 "           [--user-path | --user-path=path]\n"
diff --git a/diff-lib.c b/diff-lib.c
index b17722d..e7eaff9 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -171,7 +171,7 @@
 			if (silent_on_removed)
 				continue;
 			diff_addremove(&revs->diffopt, '-', ce->ce_mode,
-				       ce->sha1, ce->name, NULL);
+				       ce->sha1, ce->name);
 			continue;
 		}
 		changed = ce_match_stat(ce, &st, ce_option);
@@ -184,7 +184,7 @@
 		newmode = ce_mode_from_stat(ce, st.st_mode);
 		diff_change(&revs->diffopt, oldmode, newmode,
 			    ce->sha1, (changed ? null_sha1 : ce->sha1),
-			    ce->name, NULL);
+			    ce->name);
 
 	}
 	diffcore_std(&revs->diffopt);
@@ -208,7 +208,7 @@
 				 const unsigned char *sha1, unsigned int mode)
 {
 	diff_addremove(&revs->diffopt, prefix[0], mode,
-		       sha1, ce->name, NULL);
+		       sha1, ce->name);
 }
 
 static int get_stat_data(struct cache_entry *ce,
@@ -312,7 +312,7 @@
 		return 0;
 
 	diff_change(&revs->diffopt, oldmode, mode,
-		    old->sha1, sha1, old->name, NULL);
+		    old->sha1, sha1, old->name);
 	return 0;
 }
 
diff --git a/diff.c b/diff.c
index 6a39b39..a07812c 100644
--- a/diff.c
+++ b/diff.c
@@ -3412,9 +3412,8 @@
 void diff_addremove(struct diff_options *options,
 		    int addremove, unsigned mode,
 		    const unsigned char *sha1,
-		    const char *base, const char *path)
+		    const char *concatpath)
 {
-	char concatpath[PATH_MAX];
 	struct diff_filespec *one, *two;
 
 	if (DIFF_OPT_TST(options, IGNORE_SUBMODULES) && S_ISGITLINK(mode))
@@ -3436,9 +3435,6 @@
 		addremove = (addremove == '+' ? '-' :
 			     addremove == '-' ? '+' : addremove);
 
-	if (!path) path = "";
-	sprintf(concatpath, "%s%s", base, path);
-
 	if (options->prefix &&
 	    strncmp(concatpath, options->prefix, options->prefix_length))
 		return;
@@ -3459,9 +3455,8 @@
 		 unsigned old_mode, unsigned new_mode,
 		 const unsigned char *old_sha1,
 		 const unsigned char *new_sha1,
-		 const char *base, const char *path)
+		 const char *concatpath)
 {
-	char concatpath[PATH_MAX];
 	struct diff_filespec *one, *two;
 
 	if (DIFF_OPT_TST(options, IGNORE_SUBMODULES) && S_ISGITLINK(old_mode)
@@ -3474,8 +3469,6 @@
 		tmp = old_mode; old_mode = new_mode; new_mode = tmp;
 		tmp_c = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_c;
 	}
-	if (!path) path = "";
-	sprintf(concatpath, "%s%s", base, path);
 
 	if (options->prefix &&
 	    strncmp(concatpath, options->prefix, options->prefix_length))
diff --git a/diff.h b/diff.h
index 5dc0cb5..50fb5dd 100644
--- a/diff.h
+++ b/diff.h
@@ -14,12 +14,12 @@
 		 unsigned old_mode, unsigned new_mode,
 		 const unsigned char *old_sha1,
 		 const unsigned char *new_sha1,
-		 const char *base, const char *path);
+		 const char *fullpath);
 
 typedef void (*add_remove_fn_t)(struct diff_options *options,
 		    int addremove, unsigned mode,
 		    const unsigned char *sha1,
-		    const char *base, const char *path);
+		    const char *fullpath);
 
 typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
 		struct diff_options *options, void *data);
@@ -164,14 +164,13 @@
 			   int addremove,
 			   unsigned mode,
 			   const unsigned char *sha1,
-			   const char *base,
-			   const char *path);
+			   const char *fullpath);
 
 extern void diff_change(struct diff_options *,
 			unsigned mode1, unsigned mode2,
 			const unsigned char *sha1,
 			const unsigned char *sha2,
-			const char *base, const char *path);
+			const char *fullpath);
 
 extern void diff_unmerge(struct diff_options *,
 			 const char *path,
diff --git a/fast-import.c b/fast-import.c
index e72b286..7089e6f 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -1868,6 +1868,7 @@
 	case S_IFREG | 0644:
 	case S_IFREG | 0755:
 	case S_IFLNK:
+	case S_IFGITLINK:
 	case 0644:
 	case 0755:
 		/* ok */
@@ -1900,7 +1901,20 @@
 		p = uq.buf;
 	}
 
-	if (inline_data) {
+	if (S_ISGITLINK(mode)) {
+		if (inline_data)
+			die("Git links cannot be specified 'inline': %s",
+				command_buf.buf);
+		else if (oe) {
+			if (oe->type != OBJ_COMMIT)
+				die("Not a commit (actually a %s): %s",
+					typename(oe->type), command_buf.buf);
+		}
+		/*
+		 * Accept the sha1 without checking; it expected to be in
+		 * another repository.
+		 */
+	} else if (inline_data) {
 		static struct strbuf buf = STRBUF_INIT;
 
 		if (p != uq.buf) {
@@ -2374,7 +2388,7 @@
 }
 
 static const char fast_import_usage[] =
-"git-fast-import [--date-format=f] [--max-pack-size=n] [--depth=n] [--active-branches=n] [--export-marks=marks.file]";
+"git fast-import [--date-format=f] [--max-pack-size=n] [--depth=n] [--active-branches=n] [--export-marks=marks.file]";
 
 int main(int argc, const char **argv)
 {
diff --git a/fixup-builtins b/fixup-builtins
index 49e861d..63dfa4c 100755
--- a/fixup-builtins
+++ b/fixup-builtins
@@ -1,16 +1,16 @@
 #!/bin/sh
 while [ "$1" ]
 do
-	old="$1"
-	new=$(echo "$1" | sed 's/git-/git /')
-	echo "Converting '$old' to '$new'"
-	git ls-files '*.sh' | while read file
-	do
-		sed "s/\\<$old\\>/$new/g" < $file > $file.new
-		chmod --reference=$file $file.new
-		mv $file.new $file
-	done
+	if [ "$1" != "git-sh-setup" -a "$1" != "git-parse-remote" -a "$1" != "git-svn" ]; then
+		old="$1"
+		new=$(echo "$1" | sed 's/git-/git /')
+		echo "Converting '$old' to '$new'"
+		sed -i "s/\\<$old\\>/$new/g" $(git ls-files '*.sh')
+	fi
 	shift
 done
+
+sed -i 's/git merge-one-file/git-merge-one-file/g
+s/git rebase-todo/git-rebase-todo/g' $(git ls-files '*.sh')
 git update-index --refresh >& /dev/null
 exit 0
diff --git a/git-am.sh b/git-am.sh
index cc8787b..60aaa4a 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -5,9 +5,9 @@
 SUBDIRECTORY_OK=Yes
 OPTIONS_KEEPDASHDASH=
 OPTIONS_SPEC="\
-git-am [options] [<mbox>|<Maildir>...]
-git-am [options] --resolved
-git-am [options] --skip
+git am [options] [<mbox>|<Maildir>...]
+git am [options] --resolved
+git am [options] --skip
 --
 d,dotest=       (removed -- do not use)
 i,interactive   run interactively
@@ -22,6 +22,7 @@
 resolvemsg=     override error message when patch failure occurs
 r,resolved      to be used after a patch failure
 skip            skip the current patch
+abort           restore the original branch and abort the patching operation.
 rebasing        (internal use for git-rebase)"
 
 . git-sh-setup
@@ -54,6 +55,7 @@
     fi
     echo "When you have resolved this problem run \"$cmdline --resolved\"."
     echo "If you would prefer to skip this patch, instead run \"$cmdline --skip\"."
+    echo "To restore the original branch and stop patching run \"$cmdline --abort\"."
 
     stop_here $1
 }
@@ -120,7 +122,7 @@
 
 prec=4
 dotest="$GIT_DIR/rebase"
-sign= utf8=t keep= skip= interactive= resolved= binary= rebasing=
+sign= utf8=t keep= skip= interactive= resolved= binary= rebasing= abort=
 resolvemsg= resume=
 git_apply_opt=
 
@@ -145,6 +147,8 @@
 		resolved=t ;;
 	--skip)
 		skip=t ;;
+	--abort)
+		abort=t ;;
 	--rebasing)
 		rebasing=t threeway=t keep=t binary=t ;;
 	-d|--dotest)
@@ -177,7 +181,7 @@
 
 if test -d "$dotest"
 then
-	case "$#,$skip$resolved" in
+	case "$#,$skip$resolved$abort" in
 	0,*t*)
 		# Explicit resume command and we do not have file, so
 		# we are happy.
@@ -197,9 +201,18 @@
 	esac ||
 	die "previous rebase directory $dotest still exists but mbox given."
 	resume=yes
+
+	case "$abort" in
+	t)
+		git rerere clear
+		git read-tree --reset -u HEAD ORIG_HEAD
+		git reset ORIG_HEAD
+		rm -fr "$dotest"
+		exit ;;
+	esac
 else
-	# Make sure we are not given --skip nor --resolved
-	test ",$skip,$resolved," = ,,, ||
+	# Make sure we are not given --skip, --resolved, nor --abort
+	test "$skip$resolved$abort" = "" ||
 		die "Resolve operation not in progress, we are not resuming."
 
 	# Start afresh.
diff --git a/git-archimport.perl b/git-archimport.perl
index 9a7a906..98f3ede 100755
--- a/git-archimport.perl
+++ b/git-archimport.perl
@@ -9,7 +9,7 @@
 
 =head1 Invocation
 
-    git-archimport [ -h ] [ -v ] [ -o ] [ -a ] [ -f ] [ -T ]
+    git archimport [ -h ] [ -v ] [ -o ] [ -a ] [ -f ] [ -T ]
 	[ -D depth] [ -t tempdir ] <archive>/<branch> [ <archive>/<branch> ]
 
 Imports a project from one or more Arch repositories. It will follow branches
@@ -74,7 +74,7 @@
 
 sub usage() {
     print STDERR <<END;
-Usage: ${\basename $0}     # fetch/update GIT from Arch
+Usage: git archimport     # fetch/update GIT from Arch
        [ -h ] [ -v ] [ -o ] [ -a ] [ -f ] [ -T ] [ -D depth ] [ -t tempdir ]
        repository/arch-branch [ repository/arch-branch] ...
 END
diff --git a/git-bisect.sh b/git-bisect.sh
index 991b2ef..3cac20d 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -149,7 +149,7 @@
 	echo "$start_head" >"$GIT_DIR/BISECT_START" &&
 	sq "$@" >"$GIT_DIR/BISECT_NAMES" &&
 	eval "$eval" &&
-	echo "git-bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit
+	echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit
 	#
 	# Check if we can proceed to the next bisect state.
 	#
@@ -169,7 +169,7 @@
 	esac
 	git update-ref "refs/bisect/$tag" "$rev" || exit
 	echo "# $state: $(git show-branch $rev)" >>"$GIT_DIR/BISECT_LOG"
-	test -n "$nolog" || echo "git-bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
+	test -n "$nolog" || echo "git bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
 }
 
 bisect_state() {
@@ -426,9 +426,13 @@
 bisect_replay () {
 	test -r "$1" || die "cannot read $1 for replaying"
 	bisect_reset
-	while read bisect command rev
+	while read git bisect command rev
 	do
-		test "$bisect" = "git-bisect" || continue
+		test "$git $bisect" = "git bisect" -o "$git" = "git-bisect" || continue
+		if test "$git" = "git-bisect"; then
+			rev="$command"
+			command="$bisect"
+		fi
 		case "$command" in
 		start)
 			cmd="bisect_start $rev"
diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl
index c6c70e9..6d9f0ef 100755
--- a/git-cvsexportcommit.perl
+++ b/git-cvsexportcommit.perl
@@ -370,7 +370,7 @@
 
 sub usage {
 	print STDERR <<END;
-Usage: GIT_DIR=/path/to/.git ${\basename $0} [-h] [-p] [-v] [-c] [-f] [-u] [-w cvsworkdir] [-m msgprefix] [ parent ] commit
+Usage: GIT_DIR=/path/to/.git git cvsexportcommit [-h] [-p] [-v] [-c] [-f] [-u] [-w cvsworkdir] [-m msgprefix] [ parent ] commit
 END
 	exit(1);
 }
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index cacbfc0..e2664ef 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -36,7 +36,7 @@
 	my $msg = shift;
 	print(STDERR "Error: $msg\n") if $msg;
 	print STDERR <<END;
-Usage: ${\basename $0}     # fetch/update GIT from CVS
+Usage: git cvsimport     # fetch/update GIT from CVS
        [-o branch-for-HEAD] [-h] [-v] [-d CVSROOT] [-A author-conv-file]
        [-p opts-for-cvsps] [-P file] [-C GIT_repository] [-z fuzz] [-i] [-k]
        [-u] [-s subst] [-a] [-m] [-M regex] [-S regex] [-L commitlimit]
diff --git a/git-cvsserver.perl b/git-cvsserver.perl
index 920bbe1..b0a805c 100755
--- a/git-cvsserver.perl
+++ b/git-cvsserver.perl
@@ -101,7 +101,7 @@
 $log->info("--------------- STARTING -----------------");
 
 my $usage =
-    "Usage: git-cvsserver [options] [pserver|server] [<directory> ...]\n".
+    "Usage: git cvsserver [options] [pserver|server] [<directory> ...]\n".
     "    --base-path <path>  : Prepend to requested CVSROOT\n".
     "    --strict-paths      : Don't allow recursing into subdirectories\n".
     "    --export-all        : Don't check for gitcvs.enabled in config\n".
@@ -801,6 +801,18 @@
 
     argsplit("co");
 
+    # Provide list of modules, if -c was used.
+    if (exists $state->{opt}{c}) {
+        my $showref = `git show-ref --heads`;
+        for my $line (split '\n', $showref) {
+            if ( $line =~ m% refs/heads/(.*)$% ) {
+                print "M $1\t$1\n";
+            }
+        }
+        print "ok\n";
+        return 1;
+    }
+
     my $module = $state->{args}[0];
     $state->{module} = $module;
     my $checkout_path = $module;
@@ -947,21 +959,15 @@
     # projects (heads in this case) to checkout.
     #
     if ($state->{module} eq '') {
-	my $heads_dir = $state->{CVSROOT} . '/refs/heads';
-	if (!opendir HEADS, $heads_dir) {
-	    print "E [server aborted]: Failed to open directory, "
-	      . "$heads_dir: $!\nerror\n";
-	    return 0;
-	}
+        my $showref = `git show-ref --heads`;
         print "E cvs update: Updating .\n";
-	while (my $head = readdir(HEADS)) {
-	    if (-f $state->{CVSROOT} . '/refs/heads/' . $head) {
-	        print "E cvs update: New directory `$head'\n";
-	    }
-	}
-	closedir HEADS;
-	print "ok\n";
-	return 1;
+        for my $line (split '\n', $showref) {
+            if ( $line =~ m% refs/heads/(.*)$% ) {
+                print "E cvs update: New directory `$1'\n";
+            }
+        }
+        print "ok\n";
+        return 1;
     }
 
 
@@ -1884,7 +1890,7 @@
     }
 
     # done; get out of the tempdir
-    cleanupWorkDir();
+    cleanupWorkTree();
 
     print "ok\n";
 
diff --git a/git-instaweb.sh b/git-instaweb.sh
index af0fde5..0843372 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -6,7 +6,7 @@
 PERL='@@PERL@@'
 OPTIONS_KEEPDASHDASH=
 OPTIONS_SPEC="\
-git-instaweb [options] (--start | --stop | --restart)
+git instaweb [options] (--start | --stop | --restart)
 --
 l,local        only bind on 127.0.0.1
 p,port=        the port to bind to
diff --git a/git-pull.sh b/git-pull.sh
index 809e537..6afd4e2 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -121,7 +121,7 @@
 		"refs/remotes/$origin/$reflist" 2>/dev/null)"
 }
 orig_head=$(git rev-parse --verify HEAD 2>/dev/null)
-git-fetch --update-head-ok "$@" || exit 1
+git fetch --update-head-ok "$@" || exit 1
 
 curr_head=$(git rev-parse --verify HEAD 2>/dev/null)
 if test "$curr_head" != "$orig_head"
diff --git a/git-quiltimport.sh b/git-quiltimport.sh
index d1efa1d..c9aecfd 100755
--- a/git-quiltimport.sh
+++ b/git-quiltimport.sh
@@ -1,7 +1,7 @@
 #!/bin/sh
 OPTIONS_KEEPDASHDASH=
 OPTIONS_SPEC="\
-git-quiltimport [options]
+git quiltimport [options]
 --
 n,dry-run     dry run
 author=       author name and email address for patches without any
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index da79a24..e63a864 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -174,6 +174,8 @@
 				new_parents="$new_parents $new_p"
 				;;
 			esac
+		else
+			new_parents="$new_parents $p"
 		fi
 	done
 	case $fast_forward in
diff --git a/git-rebase.sh b/git-rebase.sh
index 56cf6f0..6ef5754 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -376,8 +376,7 @@
 
 # Detach HEAD and reset the tree
 echo "First, rewinding head to replay your work on top of it..."
-git checkout "$onto^0" >/dev/null 2>&1 ||
-	die "could not detach HEAD"
+git checkout -q "$onto^0" || die "could not detach HEAD"
 git update-ref ORIG_HEAD $branch
 
 # If the $onto is a proper descendant of the tip of the branch, then
diff --git a/git-relink.perl b/git-relink.perl
index 15fb932..937c69a 100755
--- a/git-relink.perl
+++ b/git-relink.perl
@@ -163,7 +163,7 @@
 
 
 sub usage() {
-	print("Usage: $0 [--safe] <dir> [<dir> ...] <master_dir> \n");
+	print("Usage: git relink [--safe] <dir> [<dir> ...] <master_dir> \n");
 	print("All directories should contain a .git/objects/ subdirectory.\n");
 	print("Options\n");
 	print("\t--safe\t" .
diff --git a/git-repack.sh b/git-repack.sh
index 8c3bc13..683960b 100755
--- a/git-repack.sh
+++ b/git-repack.sh
@@ -5,7 +5,7 @@
 
 OPTIONS_KEEPDASHDASH=
 OPTIONS_SPEC="\
-git-repack [options]
+git repack [options]
 --
 a               pack everything in a single pack
 A               same as -a, and turn unreachable objects loose
diff --git a/git-send-email.perl b/git-send-email.perl
index 6adb669..2e4a44a 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -38,7 +38,7 @@
 
 sub usage {
 	print <<EOT;
-git-send-email [options] <file | directory>...
+git send-email [options] <file | directory>...
 Options:
    --from         Specify the "From:" line of the email to be sent.
 
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 9cceb21..dbdf209 100755
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -32,15 +32,16 @@
 		echo exit $?
 	)"
 else
+	dashless=$(basename "$0" | sed -e 's/-/ /')
 	usage() {
-		die "Usage: $0 $USAGE"
+		die "Usage: $dashless $USAGE"
 	}
 
 	if [ -z "$LONG_USAGE" ]
 	then
-		LONG_USAGE="Usage: $0 $USAGE"
+		LONG_USAGE="Usage: $dashless $USAGE"
 	else
-		LONG_USAGE="Usage: $0 $USAGE
+		LONG_USAGE="Usage: $dashless $USAGE
 
 $LONG_USAGE"
 	fi
diff --git a/git-svn.perl b/git-svn.perl
index 3750e47..2e0e552 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -261,7 +261,7 @@
 	my $fd = $exit ? \*STDERR : \*STDOUT;
 	print $fd <<"";
 git-svn - bidirectional operations between a single Subversion tree and git
-Usage: $0 <command> [options] [arguments]\n
+Usage: git svn <command> [options] [arguments]\n
 
 	print $fd "Available commands:\n" unless $cmd;
 
@@ -1226,7 +1226,7 @@
 
 sub find_file_type_and_diff_status {
 	my ($path) = @_;
-	return ('dir', '') if $path eq '.';
+	return ('dir', '') if $path eq '';
 
 	my $diff_output =
 	    command_oneline(qw(diff --cached --name-status --), $path) || "";
diff --git a/hash-object.c b/hash-object.c
index 48d5223..46c06a9 100644
--- a/hash-object.c
+++ b/hash-object.c
@@ -52,7 +52,7 @@
 }
 
 static const char hash_object_usage[] =
-"git-hash-object [ [-t <type>] [-w] [--stdin] <file>... | --stdin-paths < <list-of-paths> ]";
+"git hash-object [ [-t <type>] [-w] [--stdin] <file>... | --stdin-paths < <list-of-paths> ]";
 
 int main(int argc, char **argv)
 {
diff --git a/help.c b/help.c
index 52d39b8..bfc84ae 100644
--- a/help.c
+++ b/help.c
@@ -40,7 +40,7 @@
 };
 
 static const char * const builtin_help_usage[] = {
-	"git-help [--all] [--man|--web|--info] [command]",
+	"git help [--all] [--man|--web|--info] [command]",
 	NULL
 };
 
diff --git a/http-push.c b/http-push.c
index 2cd068a..6805288 100644
--- a/http-push.c
+++ b/http-push.c
@@ -14,7 +14,7 @@
 #include <expat.h>
 
 static const char http_push_usage[] =
-"git-http-push [--all] [--dry-run] [--force] [--verbose] <remote> [<head>...]\n";
+"git http-push [--all] [--dry-run] [--force] [--verbose] <remote> [<head>...]\n";
 
 #ifndef XML_STATUS_OK
 enum XML_Status {
diff --git a/http-walker.c b/http-walker.c
index 51c18f2..9dc6b27 100644
--- a/http-walker.c
+++ b/http-walker.c
@@ -442,6 +442,8 @@
 		return -1;
 
 	new_pack = parse_pack_index(sha1);
+	if (!new_pack)
+		return -1; /* parse_pack_index() already issued error message */
 	new_pack->next = repo->packs;
 	repo->packs = new_pack;
 	return 0;
diff --git a/index-pack.c b/index-pack.c
index 25db5db..ac20a46 100644
--- a/index-pack.c
+++ b/index-pack.c
@@ -10,7 +10,7 @@
 #include "fsck.h"
 
 static const char index_pack_usage[] =
-"git-index-pack [-v] [-o <index-file>] [{ ---keep | --keep=<msg> }] [--strict] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
+"git index-pack [-v] [-o <index-file>] [{ ---keep | --keep=<msg> }] [--strict] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
 
 struct object_entry
 {
@@ -26,6 +26,14 @@
 	off_t offset;
 };
 
+struct base_data {
+	struct base_data *base;
+	struct base_data *child;
+	struct object_entry *obj;
+	void *data;
+	unsigned long size;
+};
+
 /*
  * Even if sizeof(union delta_base) == 24 on 64-bit archs, we really want
  * to memcmp() only the first 20 bytes.
@@ -43,6 +51,8 @@
 
 static struct object_entry *objects;
 static struct delta_entry *deltas;
+static struct base_data *base_cache;
+static size_t base_cache_used;
 static int nr_objects;
 static int nr_deltas;
 static int nr_resolved_deltas;
@@ -211,6 +221,46 @@
 	die("pack has bad object at offset %lu: %s", offset, buf);
 }
 
+static void prune_base_data(struct base_data *retain)
+{
+	struct base_data *b = base_cache;
+	for (b = base_cache;
+	     base_cache_used > delta_base_cache_limit && b;
+	     b = b->child) {
+		if (b->data && b != retain) {
+			free(b->data);
+			b->data = NULL;
+			base_cache_used -= b->size;
+		}
+	}
+}
+
+static void link_base_data(struct base_data *base, struct base_data *c)
+{
+	if (base)
+		base->child = c;
+	else
+		base_cache = c;
+
+	c->base = base;
+	c->child = NULL;
+	base_cache_used += c->size;
+	prune_base_data(c);
+}
+
+static void unlink_base_data(struct base_data *c)
+{
+	struct base_data *base = c->base;
+	if (base)
+		base->child = NULL;
+	else
+		base_cache = NULL;
+	if (c->data) {
+		free(c->data);
+		base_cache_used -= c->size;
+	}
+}
+
 static void *unpack_entry_data(unsigned long offset, unsigned long size)
 {
 	z_stream stream;
@@ -426,33 +476,60 @@
 	}
 }
 
-static void resolve_delta(struct object_entry *delta_obj, void *base_data,
-			  unsigned long base_size, enum object_type type)
+static void *get_base_data(struct base_data *c)
+{
+	if (!c->data) {
+		struct object_entry *obj = c->obj;
+
+		if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA) {
+			void *base = get_base_data(c->base);
+			void *raw = get_data_from_pack(obj);
+			c->data = patch_delta(
+				base, c->base->size,
+				raw, obj->size,
+				&c->size);
+			free(raw);
+			if (!c->data)
+				bad_object(obj->idx.offset, "failed to apply delta");
+		} else
+			c->data = get_data_from_pack(obj);
+
+		base_cache_used += c->size;
+		prune_base_data(c);
+	}
+	return c->data;
+}
+
+static void resolve_delta(struct object_entry *delta_obj,
+			  struct base_data *base_obj, enum object_type type)
 {
 	void *delta_data;
 	unsigned long delta_size;
-	void *result;
-	unsigned long result_size;
 	union delta_base delta_base;
 	int j, first, last;
+	struct base_data result;
 
 	delta_obj->real_type = type;
 	delta_data = get_data_from_pack(delta_obj);
 	delta_size = delta_obj->size;
-	result = patch_delta(base_data, base_size, delta_data, delta_size,
-			     &result_size);
+	result.data = patch_delta(get_base_data(base_obj), base_obj->size,
+			     delta_data, delta_size,
+			     &result.size);
 	free(delta_data);
-	if (!result)
+	if (!result.data)
 		bad_object(delta_obj->idx.offset, "failed to apply delta");
-	sha1_object(result, result_size, type, delta_obj->idx.sha1);
+	sha1_object(result.data, result.size, type, delta_obj->idx.sha1);
 	nr_resolved_deltas++;
 
+	result.obj = delta_obj;
+	link_base_data(base_obj, &result);
+
 	hashcpy(delta_base.sha1, delta_obj->idx.sha1);
 	if (!find_delta_children(&delta_base, &first, &last)) {
 		for (j = first; j <= last; j++) {
 			struct object_entry *child = objects + deltas[j].obj_no;
 			if (child->real_type == OBJ_REF_DELTA)
-				resolve_delta(child, result, result_size, type);
+				resolve_delta(child, &result, type);
 		}
 	}
 
@@ -462,11 +539,11 @@
 		for (j = first; j <= last; j++) {
 			struct object_entry *child = objects + deltas[j].obj_no;
 			if (child->real_type == OBJ_OFS_DELTA)
-				resolve_delta(child, result, result_size, type);
+				resolve_delta(child, &result, type);
 		}
 	}
 
-	free(result);
+	unlink_base_data(&result);
 }
 
 static int compare_delta_entry(const void *a, const void *b)
@@ -481,7 +558,6 @@
 {
 	int i;
 	struct delta_entry *delta = deltas;
-	void *data;
 	struct stat st;
 
 	/*
@@ -496,7 +572,7 @@
 				nr_objects);
 	for (i = 0; i < nr_objects; i++) {
 		struct object_entry *obj = &objects[i];
-		data = unpack_raw_entry(obj, &delta->base);
+		void *data = unpack_raw_entry(obj, &delta->base);
 		obj->real_type = obj->type;
 		if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA) {
 			nr_deltas++;
@@ -545,6 +621,7 @@
 		struct object_entry *obj = &objects[i];
 		union delta_base base;
 		int j, ref, ref_first, ref_last, ofs, ofs_first, ofs_last;
+		struct base_data base_obj;
 
 		if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA)
 			continue;
@@ -555,22 +632,24 @@
 		ofs = !find_delta_children(&base, &ofs_first, &ofs_last);
 		if (!ref && !ofs)
 			continue;
-		data = get_data_from_pack(obj);
+		base_obj.data = get_data_from_pack(obj);
+		base_obj.size = obj->size;
+		base_obj.obj = obj;
+		link_base_data(NULL, &base_obj);
+
 		if (ref)
 			for (j = ref_first; j <= ref_last; j++) {
 				struct object_entry *child = objects + deltas[j].obj_no;
 				if (child->real_type == OBJ_REF_DELTA)
-					resolve_delta(child, data,
-						      obj->size, obj->type);
+					resolve_delta(child, &base_obj, obj->type);
 			}
 		if (ofs)
 			for (j = ofs_first; j <= ofs_last; j++) {
 				struct object_entry *child = objects + deltas[j].obj_no;
 				if (child->real_type == OBJ_OFS_DELTA)
-					resolve_delta(child, data,
-						      obj->size, obj->type);
+					resolve_delta(child, &base_obj, obj->type);
 			}
-		free(data);
+		unlink_base_data(&base_obj);
 		display_progress(progress, nr_resolved_deltas);
 	}
 }
@@ -601,7 +680,8 @@
 	return size;
 }
 
-static void append_obj_to_pack(const unsigned char *sha1, void *buf,
+static struct object_entry *append_obj_to_pack(
+			       const unsigned char *sha1, void *buf,
 			       unsigned long size, enum object_type type)
 {
 	struct object_entry *obj = &objects[nr_objects++];
@@ -622,6 +702,7 @@
 	obj[1].idx.offset = obj[0].idx.offset + n;
 	obj[1].idx.offset += write_compressed(output_fd, buf, size, &obj[0].idx.crc32);
 	hashcpy(obj->idx.sha1, sha1);
+	return obj;
 }
 
 static int delta_pos_compare(const void *_a, const void *_b)
@@ -656,28 +737,31 @@
 
 	for (i = 0; i < n; i++) {
 		struct delta_entry *d = sorted_by_pos[i];
-		void *data;
-		unsigned long size;
 		enum object_type type;
 		int j, first, last;
+		struct base_data base_obj;
 
 		if (objects[d->obj_no].real_type != OBJ_REF_DELTA)
 			continue;
-		data = read_sha1_file(d->base.sha1, &type, &size);
-		if (!data)
+		base_obj.data = read_sha1_file(d->base.sha1, &type, &base_obj.size);
+		if (!base_obj.data)
 			continue;
 
+		if (check_sha1_signature(d->base.sha1, base_obj.data,
+				base_obj.size, typename(type)))
+			die("local object %s is corrupt", sha1_to_hex(d->base.sha1));
+		base_obj.obj = append_obj_to_pack(d->base.sha1, base_obj.data,
+			base_obj.size, type);
+		link_base_data(NULL, &base_obj);
+
 		find_delta_children(&d->base, &first, &last);
 		for (j = first; j <= last; j++) {
 			struct object_entry *child = objects + deltas[j].obj_no;
 			if (child->real_type == OBJ_REF_DELTA)
-				resolve_delta(child, data, size, type);
+				resolve_delta(child, &base_obj, type);
 		}
 
-		if (check_sha1_signature(d->base.sha1, data, size, typename(type)))
-			die("local object %s is corrupt", sha1_to_hex(d->base.sha1));
-		append_obj_to_pack(d->base.sha1, data, size, type);
-		free(data);
+		unlink_base_data(&base_obj);
 		display_progress(progress, nr_resolved_deltas);
 	}
 	free(sorted_by_pos);
diff --git a/pack-redundant.c b/pack-redundant.c
index f5cd0ac..25b81a4 100644
--- a/pack-redundant.c
+++ b/pack-redundant.c
@@ -11,7 +11,7 @@
 #define BLKSIZE 512
 
 static const char pack_redundant_usage[] =
-"git-pack-redundant [ --verbose ] [ --alt-odb ] < --all | <.pack filename> ...>";
+"git pack-redundant [ --verbose ] [ --alt-odb ] < --all | <.pack filename> ...>";
 
 static int load_all_packs, verbose, alt_odb;
 
diff --git a/parse-options.c b/parse-options.c
index 2fd5edb..987b015 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -214,7 +214,7 @@
 	return -2;
 }
 
-void check_typos(const char *arg, const struct option *options)
+static void check_typos(const char *arg, const struct option *options)
 {
 	if (strlen(arg) < 3)
 		return;
diff --git a/read-cache.c b/read-cache.c
index d801f9d..a50a851 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -528,7 +528,7 @@
 		ce = create_alias_ce(ce, alias);
 	ce->ce_flags |= CE_ADDED;
 
-	/* It was suspected to be recily clean, but it turns out to be Ok */
+	/* It was suspected to be racily clean, but it turns out to be Ok */
 	was_same = (alias &&
 		    !ce_stage(alias) &&
 		    !hashcmp(alias->sha1, ce->sha1) &&
@@ -980,7 +980,10 @@
 	int not_new = (flags & REFRESH_IGNORE_MISSING) != 0;
 	int ignore_submodules = (flags & REFRESH_IGNORE_SUBMODULES) != 0;
 	unsigned int options = really ? CE_MATCH_IGNORE_VALID : 0;
+	const char *needs_update_message;
 
+	needs_update_message = ((flags & REFRESH_SAY_CHANGED)
+				? "locally modified" : "needs update");
 	for (i = 0; i < istate->cache_nr; i++) {
 		struct cache_entry *ce, *new;
 		int cache_errno = 0;
@@ -1019,7 +1022,7 @@
 			}
 			if (quiet)
 				continue;
-			printf("%s: needs update\n", ce->name);
+			printf("%s: %s\n", ce->name, needs_update_message);
 			has_errors = 1;
 			continue;
 		}
diff --git a/rerere.c b/rerere.c
index 1258921..0456aa6 100644
--- a/rerere.c
+++ b/rerere.c
@@ -278,10 +278,13 @@
 
 		if (has_resolution(name)) {
 			if (!merge(name, path)) {
-				fprintf(stderr, "Resolved '%s' using "
-						"previous resolution.\n", path);
 				if (rerere_autoupdate)
 					path_list_insert(path, &update);
+				fprintf(stderr,
+					"%s '%s' using previous resolution.\n",
+					rerere_autoupdate
+					? "Staged" : "Resolved",
+					path);
 				goto mark_resolved;
 			}
 		}
diff --git a/revision.c b/revision.c
index 846af7b..3897fec 100644
--- a/revision.c
+++ b/revision.c
@@ -260,7 +260,7 @@
 static void file_add_remove(struct diff_options *options,
 		    int addremove, unsigned mode,
 		    const unsigned char *sha1,
-		    const char *base, const char *path)
+		    const char *fullpath)
 {
 	int diff = REV_TREE_DIFFERENT;
 
@@ -286,7 +286,7 @@
 		 unsigned old_mode, unsigned new_mode,
 		 const unsigned char *old_sha1,
 		 const unsigned char *new_sha1,
-		 const char *base, const char *path)
+		 const char *fullpath)
 {
 	tree_difference = REV_TREE_DIFFERENT;
 	DIFF_OPT_SET(options, HAS_CHANGES);
diff --git a/strbuf.c b/strbuf.c
index 4aed752..720737d 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -60,6 +60,18 @@
 	ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
 }
 
+void strbuf_trim(struct strbuf *sb)
+{
+	char *b = sb->buf;
+	while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
+		sb->len--;
+	while (sb->len > 0 && isspace(*b)) {
+		b++;
+		sb->len--;
+	}
+	memmove(sb->buf, b, sb->len);
+	sb->buf[sb->len] = '\0';
+}
 void strbuf_rtrim(struct strbuf *sb)
 {
 	while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
@@ -67,7 +79,65 @@
 	sb->buf[sb->len] = '\0';
 }
 
-int strbuf_cmp(struct strbuf *a, struct strbuf *b)
+void strbuf_ltrim(struct strbuf *sb)
+{
+	char *b = sb->buf;
+	while (sb->len > 0 && isspace(*b)) {
+		b++;
+		sb->len--;
+	}
+	memmove(sb->buf, b, sb->len);
+	sb->buf[sb->len] = '\0';
+}
+
+void strbuf_tolower(struct strbuf *sb)
+{
+	int i;
+	for (i = 0; i < sb->len; i++)
+		sb->buf[i] = tolower(sb->buf[i]);
+}
+
+struct strbuf **strbuf_split(const struct strbuf *sb, int delim)
+{
+	int alloc = 2, pos = 0;
+	char *n, *p;
+	struct strbuf **ret;
+	struct strbuf *t;
+
+	ret = xcalloc(alloc, sizeof(struct strbuf *));
+	p = n = sb->buf;
+	while (n < sb->buf + sb->len) {
+		int len;
+		n = memchr(n, delim, sb->len - (n - sb->buf));
+		if (pos + 1 >= alloc) {
+			alloc = alloc * 2;
+			ret = xrealloc(ret, sizeof(struct strbuf *) * alloc);
+		}
+		if (!n)
+			n = sb->buf + sb->len - 1;
+		len = n - p + 1;
+		t = xmalloc(sizeof(struct strbuf));
+		strbuf_init(t, len);
+		strbuf_add(t, p, len);
+		ret[pos] = t;
+		ret[++pos] = NULL;
+		p = ++n;
+	}
+	return ret;
+}
+
+void strbuf_list_free(struct strbuf **sbs)
+{
+	struct strbuf **s = sbs;
+
+	while (*s) {
+		strbuf_release(*s);
+		free(*s++);
+	}
+	free(sbs);
+}
+
+int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
 {
 	int cmp;
 	if (a->len < b->len) {
diff --git a/strbuf.h b/strbuf.h
index faec229..0c6ffad 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -61,7 +61,7 @@
 }
 
 /*----- strbuf size related -----*/
-static inline size_t strbuf_avail(struct strbuf *sb) {
+static inline size_t strbuf_avail(const struct strbuf *sb) {
 	return sb->alloc ? sb->alloc - sb->len - 1 : 0;
 }
 
@@ -77,8 +77,14 @@
 #define strbuf_reset(sb)  strbuf_setlen(sb, 0)
 
 /*----- content related -----*/
+extern void strbuf_trim(struct strbuf *);
 extern void strbuf_rtrim(struct strbuf *);
-extern int strbuf_cmp(struct strbuf *, struct strbuf *);
+extern void strbuf_ltrim(struct strbuf *);
+extern int strbuf_cmp(const struct strbuf *, const struct strbuf *);
+extern void strbuf_tolower(struct strbuf *);
+
+extern struct strbuf **strbuf_split(const struct strbuf *, int delim);
+extern void strbuf_list_free(struct strbuf **);
 
 /*----- add data in your buffer -----*/
 static inline void strbuf_addch(struct strbuf *sb, int c) {
@@ -98,7 +104,7 @@
 static inline void strbuf_addstr(struct strbuf *sb, const char *s) {
 	strbuf_add(sb, s, strlen(s));
 }
-static inline void strbuf_addbuf(struct strbuf *sb, struct strbuf *sb2) {
+static inline void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2) {
 	strbuf_add(sb, sb2->buf, sb2->len);
 }
 extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len);
diff --git a/t/Makefile b/t/Makefile
index a778865..0d65ced 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -26,7 +26,7 @@
 	$(RM) -r 'trash directory' test-results
 
 aggregate-results:
-	./aggregate-results.sh test-results/t*-*
+	'$(SHELL_PATH_SQ)' ./aggregate-results.sh test-results/t*-*
 
 # we can test NO_OPTIMIZE_COMMITS independently of LC_ALL
 full-svn-test:
diff --git a/t/aggregate-results.sh b/t/aggregate-results.sh
index 52e88e3..d5bab75 100755
--- a/t/aggregate-results.sh
+++ b/t/aggregate-results.sh
@@ -10,9 +10,9 @@
 do
 	while read type value
 	do
-               case $type in
-               '')
-                       continue ;;
+		case $type in
+		'')
+			continue ;;
 		fixed)
 			fixed=$(($fixed + $value)) ;;
 		success)
@@ -20,9 +20,9 @@
 		failed)
 			failed=$(($failed + $value)) ;;
 		broken)
-			broken=$(( $broken + $value)) ;;
+			broken=$(($broken + $value)) ;;
 		total)
-			total=$(( $total + $value)) ;;
+			total=$(($total + $value)) ;;
 		esac
 	done <"$file"
 done
diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh
index 5d3bd9d..a841df2 100644
--- a/t/lib-git-svn.sh
+++ b/t/lib-git-svn.sh
@@ -98,7 +98,7 @@
 LoadModule dav_svn_module $SVN_HTTPD_MODULE_PATH/mod_dav_svn.so
 <Location /$repo_base_path>
 	DAV svn
-	SVNPath $rawsvnrepo
+	SVNPath "$rawsvnrepo"
 </Location>
 EOF
 	"$SVN_HTTPD_PATH" -f "$GIT_DIR"/httpd.conf -k start
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index d7cbc5c..70df15c 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -63,7 +63,7 @@
 
 # updating a new file without --add should fail.
 test_expect_success 'git update-index without --add should fail adding.' '
-    ! git update-index should-be-empty
+    test_must_fail git update-index should-be-empty
 '
 
 # and with --add it should succeed, even if it is empty (it used to fail).
@@ -83,7 +83,7 @@
 # Removing paths.
 rm -f should-be-empty full-of-directories
 test_expect_success 'git update-index without --remove should fail removing.' '
-    ! git update-index should-be-empty
+    test_must_fail git update-index should-be-empty
 '
 
 test_expect_success \
@@ -217,7 +217,7 @@
     'git update-index --index-info < badobjects'
 
 test_expect_success 'writing this tree without --missing-ok.' '
-    ! git write-tree
+    test_must_fail git write-tree
 '
 
 test_expect_success \
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index d31887f..2a38d98 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -83,11 +83,11 @@
 
 	(
 		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
-		mkdir git-init-bare.git &&
-		cd git-init-bare.git &&
+		mkdir init-bare.git &&
+		cd init-bare.git &&
 		git init --bare
 	) &&
-	check_config git-init-bare.git true unset
+	check_config init-bare.git true unset
 '
 
 test_expect_success 'GIT_DIR non-bare' '
diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh
index 2bfeac9..1be7446 100755
--- a/t/t0020-crlf.sh
+++ b/t/t0020-crlf.sh
@@ -52,7 +52,7 @@
 	git config core.safecrlf true &&
 
 	for w in I am all CRLF; do echo $w; done | append_cr >allcrlf &&
-	! git add allcrlf
+	test_must_fail git add allcrlf
 '
 
 test_expect_success 'safecrlf: autocrlf=input, mixed LF/CRLF' '
@@ -61,7 +61,7 @@
 	git config core.safecrlf true &&
 
 	for w in Oh here is CRLFQ in text; do echo $w; done | q_to_cr >mixed &&
-	! git add mixed
+	test_must_fail git add mixed
 '
 
 test_expect_success 'safecrlf: autocrlf=true, all LF' '
@@ -70,7 +70,7 @@
 	git config core.safecrlf true &&
 
 	for w in I am all LF; do echo $w; done >alllf &&
-	! git add alllf
+	test_must_fail git add alllf
 '
 
 test_expect_success 'safecrlf: autocrlf=true mixed LF/CRLF' '
@@ -79,7 +79,7 @@
 	git config core.safecrlf true &&
 
 	for w in Oh here is CRLFQ in text; do echo $w; done | q_to_cr >mixed &&
-	! git add mixed
+	test_must_fail git add mixed
 '
 
 test_expect_success 'safecrlf: print warning only once' '
diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh
index c5360e2..b177174 100755
--- a/t/t0050-filesystem.sh
+++ b/t/t0050-filesystem.sh
@@ -43,7 +43,7 @@
 else
 test_expect_success "detection of case insensitive filesystem during repo init" '
 
-	! git config --bool core.ignorecase >/dev/null ||
+	test_must_fail git config --bool core.ignorecase >/dev/null ||
 	test $(git config --bool core.ignorecase) = false
 '
 fi
diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh
index 0526295..1ec0535 100755
--- a/t/t1007-hash-object.sh
+++ b/t/t1007-hash-object.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description=git-hash-object
+test_description="git-hash-object"
 
 . ./test-lib.sh
 
diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh
index dcb3108..09a8199 100755
--- a/t/t1200-tutorial.sh
+++ b/t/t1200-tutorial.sh
@@ -102,7 +102,7 @@
 git commit -m 'Some fun.' -i hello example
 
 test_expect_success 'git resolve now fails' '
-	! git merge -m "Merge work in mybranch" mybranch
+	test_must_fail git merge -m "Merge work in mybranch" mybranch
 '
 
 cat > hello << EOF
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index afe7e66..64567fb 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -201,7 +201,7 @@
 	'test wow = $(git config --get nextsection.nonewline !for)'
 
 test_expect_success 'ambiguous get' '
-	! git config --get nextsection.nonewline
+	test_must_fail git config --get nextsection.nonewline
 '
 
 test_expect_success 'get multivar' \
@@ -223,15 +223,15 @@
 test_expect_success 'multivar replace' 'cmp .git/config expect'
 
 test_expect_success 'ambiguous value' '
-	! git config nextsection.nonewline
+	test_must_fail git config nextsection.nonewline
 '
 
 test_expect_success 'ambiguous unset' '
-	! git config --unset nextsection.nonewline
+	test_must_fail git config --unset nextsection.nonewline
 '
 
 test_expect_success 'invalid unset' '
-	! git config --unset somesection.nonewline
+	test_must_fail git config --unset somesection.nonewline
 '
 
 git config --unset nextsection.nonewline "wow3$"
@@ -248,7 +248,7 @@
 
 test_expect_success 'multivar unset' 'cmp .git/config expect'
 
-test_expect_success 'invalid key' '! git config inval.2key blabla'
+test_expect_success 'invalid key' 'test_must_fail git config inval.2key blabla'
 
 test_expect_success 'correct key' 'git config 123456.a123 987'
 
@@ -430,7 +430,8 @@
 test_expect_success "rename succeeded" "test_cmp expect .git/config"
 
 test_expect_success "rename non-existing section" '
-	! git config --rename-section branch."world domination" branch.drei
+	test_must_fail git config --rename-section \
+		branch."world domination" branch.drei
 '
 
 test_expect_success "rename succeeded" "test_cmp expect .git/config"
@@ -545,11 +546,11 @@
 test_expect_success 'invalid bool (--get)' '
 
 	git config bool.nobool foobar &&
-	! git config --bool --get bool.nobool'
+	test_must_fail git config --bool --get bool.nobool'
 
 test_expect_success 'invalid bool (set)' '
 
-	! git config --bool bool.nobool foobar'
+	test_must_fail git config --bool bool.nobool foobar'
 
 rm .git/config
 
@@ -669,7 +670,7 @@
 test_expect_success 'quoting' 'cmp .git/config expect'
 
 test_expect_success 'key with newline' '
-	! git config "key.with
+	test_must_fail git config "key.with
 newline" 123'
 
 test_expect_success 'value with newline' 'git config key.sub value.with\\\
diff --git a/t/t1302-repo-version.sh b/t/t1302-repo-version.sh
index 9be0770..8d305b4 100755
--- a/t/t1302-repo-version.sh
+++ b/t/t1302-repo-version.sh
@@ -41,7 +41,7 @@
 	cd test && git apply --check --index ../test.patch)'
 
 test_expect_success 'gitdir required mode on unsupported repo' '
-	(cd test2 && ! git apply --check --index ../test.patch)
+	(cd test2 && test_must_fail git apply --check --index ../test.patch)
 '
 
 test_done
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index ca99d37..b31e4b1 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -76,7 +76,7 @@
 rm -f .git/$m
 
 test_expect_success '(not) create HEAD with old sha1' "
-	! git update-ref HEAD $A $B
+	test_must_fail git update-ref HEAD $A $B
 "
 test_expect_success "(not) prior created .git/$m" "
 	! test -f .git/$m
@@ -87,7 +87,7 @@
 	"create HEAD" \
 	"git update-ref HEAD $A"
 test_expect_success '(not) change HEAD with wrong SHA1' "
-	! git update-ref HEAD $B $Z
+	test_must_fail git update-ref HEAD $B $Z
 "
 test_expect_success "(not) changed .git/$m" "
 	! test $B"' = $(cat .git/'"$m"')
diff --git a/t/t2000-checkout-cache-clash.sh b/t/t2000-checkout-cache-clash.sh
index 5141fab..f7e1a73 100755
--- a/t/t2000-checkout-cache-clash.sh
+++ b/t/t2000-checkout-cache-clash.sh
@@ -38,7 +38,7 @@
 
 test_expect_success \
     'git checkout-index without -f should fail on conflicting work tree.' \
-    '! git checkout-index -a'
+    'test_must_fail git checkout-index -a'
 
 test_expect_success \
     'git checkout-index with -f should succeed.' \
diff --git a/t/t2100-update-cache-badpath.sh b/t/t2100-update-cache-badpath.sh
index 9beaecd..6ef2dcf 100755
--- a/t/t2100-update-cache-badpath.sh
+++ b/t/t2100-update-cache-badpath.sh
@@ -46,6 +46,6 @@
 do
 	test_expect_success \
 	    "git update-index to add conflicting path $p should fail." \
-	    "! git update-index --add -- $p"
+	    "test_must_fail git update-index --add -- $p"
 done
 test_done
diff --git a/t/t2103-update-index-ignore-missing.sh b/t/t2103-update-index-ignore-missing.sh
new file mode 100755
index 0000000..332694e
--- /dev/null
+++ b/t/t2103-update-index-ignore-missing.sh
@@ -0,0 +1,89 @@
+#!/bin/sh
+
+test_description='update-index with options'
+
+. ./test-lib.sh
+
+test_expect_success basics '
+	>one &&
+	>two &&
+	>three &&
+
+	# need --add when adding
+	test_must_fail git update-index one &&
+	test -z "$(git ls-files)" &&
+	git update-index --add one &&
+	test zone = "z$(git ls-files)" &&
+
+	# update-index is atomic
+	echo 1 >one &&
+	test_must_fail git update-index one two &&
+	echo "M	one" >expect &&
+	git diff-files --name-status >actual &&
+	test_cmp expect actual &&
+
+	git update-index --add one two three &&
+	for i in one three two; do echo $i; done >expect &&
+	git ls-files >actual &&
+	test_cmp expect actual &&
+
+	test_tick &&
+	(
+		test_create_repo xyzzy &&
+		cd xyzzy &&
+		>file &&
+		git add file
+		git commit -m "sub initial"
+	) &&
+	git add xyzzy &&
+
+	test_tick &&
+	git commit -m initial &&
+	git tag initial
+'
+
+test_expect_success '--ignore-missing --refresh' '
+	git reset --hard initial &&
+	echo 2 >one &&
+	test_must_fail git update-index --refresh &&
+	echo 1 >one &&
+	git update-index --refresh &&
+	rm -f two &&
+	test_must_fail git update-index --refresh &&
+	git update-index --ignore-missing --refresh
+
+'
+
+test_expect_success '--unmerged --refresh' '
+	git reset --hard initial &&
+	info=$(git ls-files -s one | sed -e "s/ 0	/ 1	/") &&
+	git rm --cached one &&
+	echo "$info" | git update-index --index-info &&
+	test_must_fail git update-index --refresh &&
+	git update-index --unmerged --refresh &&
+	echo 2 >two &&
+	test_must_fail git update-index --unmerged --refresh >actual &&
+	grep two actual &&
+	! grep one actual &&
+	! grep three actual
+'
+
+test_expect_success '--ignore-submodules --refresh (1)' '
+	git reset --hard initial &&
+	rm -f two &&
+	test_must_fail git update-index --ignore-submodules --refresh
+'
+
+test_expect_success '--ignore-submodules --refresh (2)' '
+	git reset --hard initial &&
+	test_tick &&
+	(
+		cd xyzzy &&
+		git commit -m "sub second" --allow-empty
+	) &&
+	test_must_fail git update-index --refresh &&
+	test_must_fail git update-index --ignore-missing --refresh &&
+	git update-index --ignore-submodules --refresh
+'
+
+test_done
diff --git a/t/t2202-add-addremove.sh b/t/t2202-add-addremove.sh
new file mode 100755
index 0000000..6a81510
--- /dev/null
+++ b/t/t2202-add-addremove.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+test_description='git add --all'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+	(
+		echo .gitignore
+		echo will-remove
+	) >expect &&
+	(
+		echo actual
+		echo expect
+		echo ignored
+	) >.gitignore &&
+	>will-remove &&
+	git add --all &&
+	test_tick &&
+	git commit -m initial &&
+	git ls-files >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git add --all' '
+	(
+		echo .gitignore
+		echo not-ignored
+		echo "M	.gitignore"
+		echo "A	not-ignored"
+		echo "D	will-remove"
+	) >expect &&
+	>ignored &&
+	>not-ignored &&
+	echo modification >>.gitignore &&
+	rm -f will-remove &&
+	git add --all &&
+	git update-index --refresh &&
+	git ls-files >actual &&
+	git diff-index --name-status --cached HEAD >>actual &&
+	test_cmp expect actual
+'
+
+test_done
diff --git a/t/t3020-ls-files-error-unmatch.sh b/t/t3020-ls-files-error-unmatch.sh
index f4da869..af8c412 100755
--- a/t/t3020-ls-files-error-unmatch.sh
+++ b/t/t3020-ls-files-error-unmatch.sh
@@ -17,7 +17,7 @@
 
 test_expect_success \
     'git ls-files --error-unmatch should fail with unmatched path.' \
-    '! git ls-files --error-unmatch foo bar-does-not-match'
+    'test_must_fail git ls-files --error-unmatch foo bar-does-not-match'
 
 test_expect_success \
     'git ls-files --error-unmatch should succeed eith matched paths.' \
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 8d87686..7c583c8 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -78,13 +78,13 @@
 test_expect_success 'git branch -m o/o o should fail when o/p exists' '
 	git branch o/o &&
         git branch o/p &&
-	! git branch -m o/o o
+	test_must_fail git branch -m o/o o
 '
 
 test_expect_success 'git branch -m q r/q should fail when r exists' '
 	git branch q &&
 	git branch r &&
-	! git branch -m q r/q
+	test_must_fail git branch -m q r/q
 '
 
 mv .git/config .git/config-saved
@@ -110,14 +110,14 @@
 
 test_expect_success 'config information was renamed, too' \
 	"test $(git config branch.s.dummy) = Hello &&
-	 ! git config branch.s/s/dummy"
+	 test_must_fail git config branch.s/s/dummy"
 
 test_expect_success \
     'git branch -m u v should fail when the reflog for u is a symlink' '
      git branch -l u &&
      mv .git/logs/refs/heads/u real-u &&
      ln -s real-u .git/logs/refs/heads/u &&
-     ! git branch -m u v
+     test_must_fail git branch -m u v
 '
 
 test_expect_success 'test tracking setup via --track' \
diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh
index b64ccfb..c2dec1c 100755
--- a/t/t3210-pack-refs.sh
+++ b/t/t3210-pack-refs.sh
@@ -43,7 +43,7 @@
      git branch c &&
      git pack-refs --all &&
      rm -f .git/refs/heads/c &&
-     ! git branch c/d
+     test_must_fail git branch c/d
 '
 
 test_expect_success \
@@ -72,7 +72,7 @@
 test_expect_success 'git branch i/j/k should barf if branch i exists' '
      git branch i &&
      git pack-refs --all --prune &&
-     ! git branch i/j/k
+     test_must_fail git branch i/j/k
 '
 
 test_expect_success \
diff --git a/t/t3403-rebase-skip.sh b/t/t3403-rebase-skip.sh
index 0a26099..0d33c71 100755
--- a/t/t3403-rebase-skip.sh
+++ b/t/t3403-rebase-skip.sh
@@ -32,7 +32,7 @@
 	'
 
 test_expect_success 'rebase with git am -3 (default)' '
-	! git rebase master
+	test_must_fail git rebase master
 '
 
 test_expect_success 'rebase --skip with am -3' '
@@ -43,7 +43,7 @@
 	test refs/heads/skip-reference = $(git symbolic-ref HEAD) &&
 	git branch post-rebase &&
 	git reset --hard pre-rebase &&
-	! git rebase master &&
+	test_must_fail git rebase master &&
 	echo "hello" > hello &&
 	git add hello &&
 	git rebase --continue &&
@@ -53,7 +53,9 @@
 
 test_expect_success 'checkout skip-merge' 'git checkout -f skip-merge'
 
-test_expect_success 'rebase with --merge' '! git rebase --merge master'
+test_expect_success 'rebase with --merge' '
+	test_must_fail git rebase --merge master
+'
 
 test_expect_success 'rebase --skip with --merge' '
 	git rebase --skip
diff --git a/t/t3502-cherry-pick-merge.sh b/t/t3502-cherry-pick-merge.sh
index 7c92e26..0ab52da 100755
--- a/t/t3502-cherry-pick-merge.sh
+++ b/t/t3502-cherry-pick-merge.sh
@@ -35,7 +35,7 @@
 
 	git reset --hard &&
 	git checkout a^0 &&
-	! git cherry-pick -m 1 b &&
+	test_must_fail git cherry-pick -m 1 b &&
 	git diff --exit-code a --
 
 '
@@ -44,7 +44,7 @@
 
 	git reset --hard &&
 	git checkout a^0 &&
-	! git cherry-pick c &&
+	test_must_fail git cherry-pick c &&
 	git diff --exit-code a --
 
 '
@@ -71,7 +71,7 @@
 
 	git reset --hard &&
 	git checkout b^0 &&
-	! git cherry-pick -m 3 c
+	test_must_fail git cherry-pick -m 3 c
 
 '
 
@@ -79,7 +79,7 @@
 
 	git reset --hard &&
 	git checkout c^0 &&
-	! git revert -m 1 b &&
+	test_must_fail git revert -m 1 b &&
 	git diff --exit-code c
 
 '
@@ -88,7 +88,7 @@
 
 	git reset --hard &&
 	git checkout c^0 &&
-	! git revert c &&
+	test_must_fail git revert c &&
 	git diff --exit-code c
 
 '
@@ -115,7 +115,7 @@
 
 	git reset --hard &&
 	git checkout c^0 &&
-	! git revert -m 3 c &&
+	test_must_fail git revert -m 3 c &&
 	git diff --exit-code c
 
 '
diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
index f542f0a..79c06ad 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -67,7 +67,7 @@
      echo "other content" > foo
      git add foo
      echo "yet another content" > foo
-     ! git rm --cached foo
+     test_must_fail git rm --cached foo
 '
 
 test_expect_success \
@@ -82,7 +82,7 @@
 
 test_expect_success \
     'Post-check that foo exists but is not in index after git rm foo' \
-    '[ -f foo ] && ! git ls-files --error-unmatch foo'
+    '[ -f foo ] && test_must_fail git ls-files --error-unmatch foo'
 
 test_expect_success \
     'Pre-check that bar exists and is in index before "git rm bar"' \
@@ -94,7 +94,7 @@
 
 test_expect_success \
     'Post-check that bar does not exist and is not in index after "git rm -f bar"' \
-    '! [ -f bar ] && ! git ls-files --error-unmatch bar'
+    '! [ -f bar ] && test_must_fail git ls-files --error-unmatch bar'
 
 test_expect_success \
     'Test that "git rm -- -q" succeeds (remove a file that looks like an option)' \
@@ -109,7 +109,7 @@
 chmod a-w .
 test_expect_success \
     'Test that "git rm -f" fails if its rm fails' \
-    '! git rm -f baz'
+    'test_must_fail git rm -f baz'
 chmod 775 .
 else
     test_expect_success 'skipping removal failure (perhaps running as root?)' :
@@ -151,7 +151,7 @@
 
 test_expect_success 'Modify foo -- rm should refuse' '
 	echo >>foo &&
-	! git rm foo baz &&
+	test_must_fail git rm foo baz &&
 	test -f foo &&
 	test -f baz &&
 	git ls-files --error-unmatch foo baz
@@ -161,8 +161,8 @@
 	git rm -f foo baz &&
 	test ! -f foo &&
 	test ! -f baz &&
-	! git ls-files --error-unmatch foo &&
-	! git ls-files --error-unmatch bar
+	test_must_fail git ls-files --error-unmatch foo &&
+	test_must_fail git ls-files --error-unmatch bar
 '
 
 test_expect_success 'Re-add foo and baz for HEAD tests' '
@@ -173,7 +173,7 @@
 '
 
 test_expect_success 'foo is different in index from HEAD -- rm should refuse' '
-	! git rm foo baz &&
+	test_must_fail git rm foo baz &&
 	test -f foo &&
 	test -f baz &&
 	git ls-files --error-unmatch foo baz
@@ -183,8 +183,8 @@
 	git rm -f foo baz &&
 	test ! -f foo &&
 	test ! -f baz &&
-	! git ls-files --error-unmatch foo
-	! git ls-files --error-unmatch baz
+	test_must_fail git ls-files --error-unmatch foo
+	test_must_fail git ls-files --error-unmatch baz
 '
 
 test_expect_success 'Recursive test setup' '
@@ -195,14 +195,14 @@
 '
 
 test_expect_success 'Recursive without -r fails' '
-	! git rm frotz &&
+	test_must_fail git rm frotz &&
 	test -d frotz &&
 	test -f frotz/nitfol
 '
 
 test_expect_success 'Recursive with -r but dirty' '
 	echo qfwfq >>frotz/nitfol
-	! git rm -r frotz &&
+	test_must_fail git rm -r frotz &&
 	test -d frotz &&
 	test -f frotz/nitfol
 '
@@ -214,7 +214,19 @@
 '
 
 test_expect_success 'Remove nonexistent file returns nonzero exit status' '
-	! git rm nonexistent
+	test_must_fail git rm nonexistent
+'
+
+test_expect_success 'Call "rm" from outside the work tree' '
+	mkdir repo &&
+	cd repo &&
+	git init &&
+	echo something > somefile &&
+	git add somefile &&
+	git commit -m "add a file" &&
+	(cd .. &&
+	 git --git-dir=repo/.git --work-tree=repo rm somefile) &&
+	test_must_fail git ls-files --error-unmatch somefile
 '
 
 test_done
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index e83fa1f..7d123d1 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -85,12 +85,12 @@
 '
 
 test_expect_success 'error out when attempting to add ignored ones without -f' '
-	! git add a.?? &&
+	test_must_fail git add a.?? &&
 	! (git ls-files | grep "\\.ig")
 '
 
 test_expect_success 'error out when attempting to add ignored ones without -f' '
-	! git add d.?? &&
+	test_must_fail git add d.?? &&
 	! (git ls-files | grep "\\.ig")
 '
 
diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
index 0922c70..a27fccc 100755
--- a/t/t4015-diff-whitespace.sh
+++ b/t/t4015-diff-whitespace.sh
@@ -144,7 +144,7 @@
 test_expect_success 'check with trailing whitespace' '
 
 	echo "foo(); " > x &&
-	! git diff --check
+	test_must_fail git diff --check
 
 '
 
@@ -152,7 +152,7 @@
 
 	# indent has space followed by hard tab
 	echo " 	foo();" > x &&
-	! git diff --check
+	test_must_fail git diff --check
 
 '
 
@@ -181,7 +181,7 @@
 
 	echo "foo(); " > x &&
 	git add x &&
-	! git diff --cached --check
+	test_must_fail git diff --cached --check
 
 '
 
@@ -190,7 +190,7 @@
 	# indent has space followed by hard tab
 	echo " 	foo();" > x &&
 	git add x &&
-	! git diff --cached --check
+	test_must_fail git diff --cached --check
 
 '
 
@@ -206,7 +206,7 @@
 
 	echo "foo(); " > x &&
 	git add x &&
-	! git diff-index --check HEAD
+	test_must_fail git diff-index --check HEAD
 
 '
 
@@ -215,7 +215,7 @@
 	# indent has space followed by hard tab
 	echo " 	foo();" > x &&
 	git add x &&
-	! git diff-index --check HEAD
+	test_must_fail git diff-index --check HEAD
 
 '
 
@@ -231,7 +231,7 @@
 
 	echo "foo(); " > x &&
 	git add x &&
-	! git diff-index --cached --check HEAD
+	test_must_fail git diff-index --cached --check HEAD
 
 '
 
@@ -240,7 +240,7 @@
 	# indent has space followed by hard tab
 	echo " 	foo();" > x &&
 	git add x &&
-	! git diff-index --cached --check HEAD
+	test_must_fail git diff-index --cached --check HEAD
 
 '
 
@@ -256,7 +256,7 @@
 
 	echo "foo(); " > x &&
 	git commit -m "another commit" x &&
-	! git diff-tree --check HEAD^ HEAD
+	test_must_fail git diff-tree --check HEAD^ HEAD
 
 '
 
@@ -265,7 +265,7 @@
 	# indent has space followed by hard tab
 	echo " 	foo();" > x &&
 	git commit -m "yet another" x &&
-	! git diff-tree --check HEAD^ HEAD
+	test_must_fail git diff-tree --check HEAD^ HEAD
 
 '
 
@@ -281,7 +281,7 @@
 
 	git config core.whitespace "trailing-space" &&
 	echo "foo ();   " > x &&
-	! git diff --check
+	test_must_fail git diff --check
 
 '
 
@@ -299,7 +299,7 @@
 	# indent contains space followed by HT
 	git config core.whitespace "space-before-tab" &&
 	echo " 	foo ();   " > x &&
-	! git diff --check
+	test_must_fail git diff --check
 
 '
 
@@ -315,7 +315,7 @@
 
 	git config core.whitespace "indent-with-non-tab" &&
 	echo "        foo ();" > x &&
-	! git diff --check
+	test_must_fail git diff --check
 
 '
 
@@ -323,7 +323,7 @@
 
 	git config core.whitespace "indent-with-non-tab" &&
 	echo "	                foo ();" > x &&
-	! git diff --check
+	test_must_fail git diff --check
 
 '
 
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index 6d3ef6c..833d6cb 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -54,7 +54,7 @@
 
 test_expect_success 'last regexp must not be negated' '
 	git config diff.java.funcname "!static" &&
-	! git diff --no-index Beer.java Beer-correct.java
+	test_must_fail git diff --no-index Beer.java Beer-correct.java
 '
 
 test_done
diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh
index 1b58233..7da0b4b 100755
--- a/t/t4103-apply-binary.sh
+++ b/t/t4103-apply-binary.sh
@@ -48,22 +48,22 @@
 
 test_expect_success 'check binary diff -- should fail.' \
 	'git-checkout master &&
-	 ! git apply --check B.diff'
+	 test_must_fail git apply --check B.diff'
 
 test_expect_success 'check binary diff (copy) -- should fail.' \
 	'git-checkout master &&
-	 ! git apply --check C.diff'
+	 test_must_fail git apply --check C.diff'
 
 test_expect_success \
 	'check incomplete binary diff with replacement -- should fail.' '
 	git-checkout master &&
-	! git apply --check --allow-binary-replacement B.diff
+	test_must_fail git apply --check --allow-binary-replacement B.diff
 '
 
 test_expect_success \
     'check incomplete binary diff with replacement (copy) -- should fail.' '
 	 git-checkout master &&
-	 ! git apply --check --allow-binary-replacement C.diff
+	 test_must_fail git apply --check --allow-binary-replacement C.diff
 '
 
 test_expect_success 'check binary diff with replacement.' \
@@ -84,19 +84,19 @@
 
 test_expect_success 'apply binary diff -- should fail.' \
 	'do_reset &&
-	 ! git apply B.diff'
+	 test_must_fail git apply B.diff'
 
 test_expect_success 'apply binary diff -- should fail.' \
 	'do_reset &&
-	 ! git apply --index B.diff'
+	 test_must_fail git apply --index B.diff'
 
 test_expect_success 'apply binary diff (copy) -- should fail.' \
 	'do_reset &&
-	 ! git apply C.diff'
+	 test_must_fail git apply C.diff'
 
 test_expect_success 'apply binary diff (copy) -- should fail.' \
 	'do_reset &&
-	 ! git apply --index C.diff'
+	 test_must_fail git apply --index C.diff'
 
 test_expect_success 'apply binary diff without replacement.' \
 	'do_reset &&
diff --git a/t/t4113-apply-ending.sh b/t/t4113-apply-ending.sh
index d741039..66fa515 100755
--- a/t/t4113-apply-ending.sh
+++ b/t/t4113-apply-ending.sh
@@ -30,7 +30,7 @@
 # test
 
 test_expect_success 'apply at the end' \
-    '! git apply --index test-patch'
+    'test_must_fail git apply --index test-patch'
 
 cat >test-patch <<\EOF
 diff a/file b/file
@@ -48,6 +48,6 @@
 git update-index file
 
 test_expect_success 'apply at the beginning' \
-	'! git apply --index test-patch'
+	'test_must_fail git apply --index test-patch'
 
 test_done
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 5cbd5ef..98ba020 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -182,7 +182,7 @@
 
 test_expect_success 'am pauses on conflict' '
 	git checkout lorem2^^ &&
-	! git am lorem-move.patch &&
+	test_must_fail git am lorem-move.patch &&
 	test -d .git/rebase
 '
 
@@ -195,7 +195,7 @@
 
 test_expect_success 'am --resolved works' '
 	git checkout lorem2^^ &&
-	! git am lorem-move.patch &&
+	test_must_fail git am lorem-move.patch &&
 	test -d .git/rebase &&
 	echo resolved >>file &&
 	git add file &&
@@ -212,13 +212,13 @@
 '
 
 test_expect_success 'am fails on mail without patch' '
-	! git am <failmail &&
+	test_must_fail git am <failmail &&
 	rm -r .git/rebase/
 '
 
 test_expect_success 'am fails on empty patch' '
 	echo "---" >>failmail &&
-	! git am <failmail &&
+	test_must_fail git am <failmail &&
 	git am --skip &&
 	! test -d .git/rebase
 '
diff --git a/t/t4151-am-abort.sh b/t/t4151-am-abort.sh
new file mode 100755
index 0000000..dda7e2c
--- /dev/null
+++ b/t/t4151-am-abort.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+test_description='am --abort'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+	for i in a b c d e f g
+	do
+		echo $i
+	done >file-1 &&
+	cp file-1 file-2 &&
+	test_tick &&
+	git add file-1 file-2 &&
+	git commit -m initial &&
+	git tag initial &&
+	for i in 2 3 4 5
+	do
+		echo $i >>file-1 &&
+		test_tick &&
+		git commit -a -m $i || break
+	done &&
+	git format-patch initial &&
+	git checkout -b side initial &&
+	echo local change >file-2-expect
+'
+
+for with3 in '' ' -3'
+do
+	test_expect_success "am$with3 stops at a patch that does not apply" '
+
+		git reset --hard initial &&
+		cp file-2-expect file-2 &&
+
+		test_must_fail git am$with3 000[124]-*.patch &&
+		git log --pretty=tformat:%s >actual &&
+		for i in 3 2 initial
+		do
+			echo $i
+		done >expect &&
+		test_cmp expect actual
+	'
+
+	test_expect_success "am --abort goes back after failed am$with3" '
+		git-am --abort &&
+		git rev-parse HEAD >actual &&
+		git rev-parse initial >expect &&
+		test_cmp expect actual &&
+		test_cmp file-2-expect file-2 &&
+		git diff-index --exit-code --cached HEAD &&
+		test ! -f .git/rr-cache/MERGE_RR
+	'
+
+done
+
+test_done
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index b5a4202..b68ab11 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -45,7 +45,7 @@
 
 test_expect_success 'nothing recorded without rerere' '
 	(rm -rf .git/rr-cache; git config rerere.enabled false) &&
-	! git merge first &&
+	test_must_fail git merge first &&
 	! test -d .git/rr-cache
 '
 
@@ -54,7 +54,7 @@
 	git reset --hard &&
 	mkdir .git/rr-cache &&
 	git config --unset rerere.enabled &&
-	! git merge first
+	test_must_fail git merge first
 '
 
 sha1=$(sed -e 's/	.*//' .git/MERGE_RR)
@@ -65,7 +65,7 @@
 	rm -rf .git/rr-cache &&
 	git config rerere.enabled true &&
 	git reset --hard &&
-	! git merge first &&
+	test_must_fail git merge first &&
 	grep ^=======$ $rr/preimage
 '
 
@@ -134,7 +134,7 @@
 	git checkout -b third master &&
 	git show second^:a1 | sed "s/To die: t/To die! T/" > a1 &&
 	git commit -q -a -m third &&
-	! git pull . first
+	test_must_fail git pull . first
 '
 
 git show first:a1 | sed 's/To die: t/To die! T/' > expect
@@ -189,7 +189,7 @@
 	echo Bello > file2 &&
 	git add file2 &&
 	git commit -m version2 &&
-	! git merge fourth &&
+	test_must_fail git merge fourth &&
 	sha1=$(sed -e "s/	.*//" .git/MERGE_RR) &&
 	rr=.git/rr-cache/$sha1 &&
 	echo Cello > file2 &&
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 983a393..645583f 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -266,7 +266,7 @@
 
 test_expect_success \
     'make sure index-pack detects the SHA1 collision' \
-    '! git-index-pack -o bad.idx test-3.pack'
+    'test_must_fail git-index-pack -o bad.idx test-3.pack'
 
 test_expect_success \
     'honor pack.packSizeLimit' \
diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh
index ecec591..0639772 100755
--- a/t/t5302-pack-index.sh
+++ b/t/t5302-pack-index.sh
@@ -118,7 +118,7 @@
 
 test_expect_success \
     '[index v1] 4) confirm that the pack is actually corrupted' \
-    '! git fsck --full $commit'
+    'test_must_fail git fsck --full $commit'
 
 test_expect_success \
     '[index v1] 5) pack-objects happily reuses corrupted data' \
@@ -127,7 +127,7 @@
 
 test_expect_success \
     '[index v1] 6) newly created pack is BAD !' \
-    '! git verify-pack -v "test-4-${pack1}.pack"'
+    'test_must_fail git verify-pack -v "test-4-${pack1}.pack"'
 
 test_expect_success \
     '[index v2] 1) stream pack to repository' \
@@ -156,11 +156,11 @@
 
 test_expect_success \
     '[index v2] 4) confirm that the pack is actually corrupted' \
-    '! git fsck --full $commit'
+    'test_must_fail git fsck --full $commit'
 
 test_expect_success \
     '[index v2] 5) pack-objects refuses to reuse corrupted data' \
-    '! git pack-objects test-5 <obj-list'
+    'test_must_fail git pack-objects test-5 <obj-list'
 
 test_expect_success \
     '[index v2] 6) verify-pack detects CRC mismatch' \
@@ -173,7 +173,8 @@
      ( while read obj
        do git cat-file -p $obj >/dev/null || exit 1
        done <obj-list ) &&
-     err=$(! git verify-pack ".git/objects/pack/pack-${pack1}.pack" 2>&1) &&
+     err=$(test_must_fail git verify-pack \
+       ".git/objects/pack/pack-${pack1}.pack" 2>&1) &&
      echo "$err" | grep "CRC mismatch"'
 
 test_done
diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh
index 2fff300..ee769d6 100755
--- a/t/t5401-update-hooks.sh
+++ b/t/t5401-update-hooks.sh
@@ -61,7 +61,8 @@
 chmod u+x victim/.git/hooks/post-update
 
 test_expect_success push '
-    ! git-send-pack --force ./victim/.git master tofail >send.out 2>send.err
+	test_must_fail git-send-pack --force ./victim/.git \
+		master tofail >send.out 2>send.err
 '
 
 test_expect_success 'updated as expected' '
diff --git a/t/t5404-tracking-branches.sh b/t/t5404-tracking-branches.sh
index 64fe261..c240035 100755
--- a/t/t5404-tracking-branches.sh
+++ b/t/t5404-tracking-branches.sh
@@ -35,7 +35,9 @@
 	git commit -a -m aa-master
 '
 
-test_expect_success 'mixed-success push returns error' '! git push'
+test_expect_success 'mixed-success push returns error' '
+	test_must_fail git push
+'
 
 test_expect_success 'check tracking branches updated correctly after push' '
 	test "$(git rev-parse origin/master)" = "$(git rev-parse master)"
diff --git a/t/t5406-remote-rejects.sh b/t/t5406-remote-rejects.sh
index 46b2cb4..59e80a5 100755
--- a/t/t5406-remote-rejects.sh
+++ b/t/t5406-remote-rejects.sh
@@ -17,7 +17,7 @@
 	git commit -a -m 2
 '
 
-test_expect_success 'push reports error' '! git push 2>stderr'
+test_expect_success 'push reports error' 'test_must_fail git push 2>stderr'
 
 test_expect_success 'individual ref reports error' 'grep rejected stderr'
 
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 140e874..362cf7e 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -177,6 +177,6 @@
 	"test \"count: 18\" = \"$(grep count count.shallow)\""
 
 test_expect_success "pull in shallow repo with missing merge base" \
-	"(cd shallow && ! git pull --depth 4 .. A)"
+	"(cd shallow && test_must_fail git pull --depth 4 .. A)"
 
 test_done
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 1e192a2..be9ee93 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -164,7 +164,7 @@
 	 git fetch origin &&
 	 git remote prune origin &&
 	 git rev-parse refs/remotes/origin/side2 &&
-	 ! git rev-parse refs/remotes/origin/side)
+	 test_must_fail git rev-parse refs/remotes/origin/side)
 '
 
 cat > test/expect << EOF
@@ -179,7 +179,7 @@
 	(cd test &&
 	 git remote prune --dry-run origin > output &&
 	 git rev-parse refs/remotes/origin/side2 &&
-	 ! git rev-parse refs/remotes/origin/side &&
+	 test_must_fail git rev-parse refs/remotes/origin/side &&
 	(cd ../one &&
 	 git branch -m side side2) &&
 	 test_cmp expect output)
@@ -194,10 +194,10 @@
 	 git branch -m side2 side) &&
 	(cd mirror &&
 	 git rev-parse --verify refs/heads/side2 &&
-	 ! git rev-parse --verify refs/heads/side &&
+	 test_must_fail git rev-parse --verify refs/heads/side &&
 	 git fetch origin &&
 	 git remote prune origin &&
-	 ! git rev-parse --verify refs/heads/side2 &&
+	 test_must_fail git rev-parse --verify refs/heads/side2 &&
 	 git rev-parse --verify refs/heads/side)
 '
 
@@ -212,10 +212,10 @@
 	 git branch -m side side2) &&
 	(cd alttst &&
 	 git rev-parse --verify refs/remotes/origin/side &&
-	 ! git rev-parse --verify refs/remotes/origin/side2 &&
+	 test_must_fail git rev-parse --verify refs/remotes/origin/side2 &&
 	 git fetch alt &&
 	 git remote prune alt &&
-	 ! git rev-parse --verify refs/remotes/origin/side &&
+	 test_must_fail git rev-parse --verify refs/remotes/origin/side &&
 	 git rev-parse --verify refs/remotes/origin/side2)
 '
 
@@ -320,7 +320,7 @@
 
 test_expect_success 'reject adding remote with an invalid name' '
 
-	! git remote add some:url desired-name
+	test_must_fail git remote add some:url desired-name
 
 '
 
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index df7750f..13d1d82 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -104,7 +104,7 @@
 	cd five &&
 	git init &&
 
-	! git fetch .. anno:five
+	test_must_fail git fetch .. anno:five
 
 '
 
@@ -117,7 +117,7 @@
 	cd six &&
 	git init &&
 
-	! git fetch .. six:six
+	test_must_fail git fetch .. six:six
 
 '
 
@@ -143,7 +143,7 @@
 test_expect_success 'unbundle 1' '
 	cd "$D/bundle" &&
 	git checkout -b some-branch &&
-	! git fetch "$D/bundle1" master:master
+	test_must_fail git fetch "$D/bundle1" master:master
 '
 
 test_expect_success 'bundle 1 has only 3 files ' '
@@ -236,7 +236,7 @@
 
 # the strange name is: a\!'b
 test_expect_success 'quoting of a strangely named repo' '
-	! git fetch "a\\!'\''b" > result 2>&1 &&
+	test_must_fail git fetch "a\\!'\''b" > result 2>&1 &&
 	cat result &&
 	grep "fatal: '\''a\\\\!'\''b'\''" result
 '
@@ -264,7 +264,7 @@
 		git fetch origin master &&
 		n=$(git rev-parse --verify refs/remotes/origin/master) &&
 		test "$o" = "$n" &&
-		! git rev-parse --verify refs/remotes/origin/side
+		test_must_fail git rev-parse --verify refs/remotes/origin/side
 	)
 '
 
@@ -278,7 +278,7 @@
 		git pull origin master &&
 		n=$(git rev-parse --verify refs/remotes/origin/master) &&
 		test "$o" = "$n" &&
-		! git rev-parse --verify refs/remotes/origin/side
+		test_must_fail git rev-parse --verify refs/remotes/origin/side
 	)
 '
 
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 6805032..f0030ad 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -178,7 +178,7 @@
 	mk_test heads/master &&
 	git push testrepo : &&
 	git commit --amend -massaged &&
-	! git push testrepo &&
+	test_must_fail git push testrepo &&
 	check_push_result $the_commit heads/master &&
 	git reset --hard $the_commit
 
@@ -374,7 +374,7 @@
 
 	# Without force rewinding should fail
 	git reset --hard HEAD^ &&
-	! git push testrepo HEAD &&
+	test_must_fail git push testrepo HEAD &&
 	check_push_result $the_commit heads/local &&
 
 	# With force rewinding should succeed
@@ -448,7 +448,7 @@
 	git clone parent child &&
 	(cd child &&
 		echo two >foo && git commit -a -m two &&
-		! git push &&
+		test_must_fail git push &&
 		test $(git rev-parse master) != \
 			$(git rev-parse remotes/origin/master))
 
@@ -459,7 +459,7 @@
 	pwd &&
 	rm -f testrepo/.git/objects/??/* &&
 	git push testrepo :refs/heads/master &&
-	(cd testrepo && ! git rev-parse --verify refs/heads/master)
+	(cd testrepo && test_must_fail git rev-parse --verify refs/heads/master)
 
 '
 
diff --git a/t/t5530-upload-pack-error.sh b/t/t5530-upload-pack-error.sh
index 8b05091..1a15817 100755
--- a/t/t5530-upload-pack-error.sh
+++ b/t/t5530-upload-pack-error.sh
@@ -27,7 +27,7 @@
 '
 
 test_expect_success 'fsck fails' '
-	! git fsck
+	test_must_fail git fsck
 '
 
 test_expect_success 'upload-pack fails due to error in pack-objects' '
@@ -46,7 +46,7 @@
 '
 
 test_expect_success 'fsck fails' '
-	! git fsck
+	test_must_fail git fsck
 '
 test_expect_success 'upload-pack fails due to error in rev-list' '
 
@@ -66,7 +66,7 @@
 
 test_expect_success 'fetch fails' '
 
-	! git fetch .. master
+	test_must_fail git fetch .. master
 
 '
 
diff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh
index 21dbb55..f8c17cd 100755
--- a/t/t5540-http-push.sh
+++ b/t/t5540-http-push.sh
@@ -73,7 +73,7 @@
 	git push origin :dev &&
 	git branch -d -r origin/dev &&
 	git fetch &&
-	! git show-ref --verify refs/remotes/origin/dev
+	test_must_fail git show-ref --verify refs/remotes/origin/dev
 '
 
 stop_httpd
diff --git a/t/t5600-clone-fail-cleanup.sh b/t/t5600-clone-fail-cleanup.sh
index acf34ce..3c013e2 100755
--- a/t/t5600-clone-fail-cleanup.sh
+++ b/t/t5600-clone-fail-cleanup.sh
@@ -13,7 +13,7 @@
 
 test_expect_success \
     'clone of non-existent source should fail' \
-    '! git-clone foo bar'
+    'test_must_fail git-clone foo bar'
 
 test_expect_success \
     'failed clone should not leave a directory' \
@@ -29,7 +29,7 @@
 # current path not to the target dir
 test_expect_success \
     'clone of non-existent (relative to $PWD) source should fail' \
-    '! git-clone ../foo baz'
+    'test_must_fail git-clone ../foo baz'
 
 test_expect_success \
     'clone should work now that source exists' \
diff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh
index 74e9e66..f674c48 100755
--- a/t/t6023-merge-file.sh
+++ b/t/t6023-merge-file.sh
@@ -67,7 +67,7 @@
 
 cp test.txt backup.txt
 test_expect_success "merge with conflicts" \
-	"! git merge-file test.txt orig.txt new3.txt"
+	"test_must_fail git merge-file test.txt orig.txt new3.txt"
 
 cat > expect.txt << EOF
 <<<<<<< test.txt
@@ -90,7 +90,7 @@
 
 cp backup.txt test.txt
 test_expect_success "merge with conflicts, using -L" \
-	"! git merge-file -L 1 -L 2 test.txt orig.txt new3.txt"
+	"test_must_fail git merge-file -L 1 -L 2 test.txt orig.txt new3.txt"
 
 cat > expect.txt << EOF
 <<<<<<< 1
@@ -114,7 +114,7 @@
 
 sed "s/ tu / TU /" < new1.txt > new5.txt
 test_expect_success "conflict in removed tail" \
-	"! git merge-file -p orig.txt new1.txt new5.txt > out"
+	"test_must_fail git merge-file -p orig.txt new1.txt new5.txt > out"
 
 cat > expect << EOF
 Dominus regit me,
@@ -135,7 +135,8 @@
 test_expect_success "expected conflict markers" "test_cmp expect out"
 
 test_expect_success 'binary files cannot be merged' '
-	! git merge-file -p orig.txt ../test4012.png new1.txt 2> merge.err &&
+	test_must_fail git merge-file -p \
+		orig.txt ../test4012.png new1.txt 2> merge.err &&
 	grep "Cannot merge binary files" merge.err
 '
 
@@ -144,7 +145,7 @@
 
 test_expect_success 'MERGE_ZEALOUS simplifies non-conflicts' '
 
-	! git merge-file -p new6.txt new5.txt new7.txt > output &&
+	test_must_fail git merge-file -p new6.txt new5.txt new7.txt > output &&
 	test 1 = $(grep ======= < output | wc -l)
 
 '
@@ -154,7 +155,8 @@
 
 test_expect_success 'ZEALOUS_ALNUM' '
 
-	! git merge-file -p new8.txt new5.txt new9.txt > merge.out &&
+	test_must_fail git merge-file -p \
+		new8.txt new5.txt new9.txt > merge.out &&
 	test 1 = $(grep ======= < merge.out | wc -l)
 
 '
diff --git a/t/t6024-recursive-merge.sh b/t/t6024-recursive-merge.sh
index 6a6a130..802d0d0 100755
--- a/t/t6024-recursive-merge.sh
+++ b/t/t6024-recursive-merge.sh
@@ -60,7 +60,9 @@
 GIT_AUTHOR_DATE="2006-12-12 23:00:08" git commit -m F
 '
 
-test_expect_success "combined merge conflicts" "! git merge -m final G"
+test_expect_success "combined merge conflicts" "
+	test_must_fail git merge -m final G
+"
 
 cat > expect << EOF
 <<<<<<< HEAD:a1
@@ -90,7 +92,7 @@
 	printf "\0\0" > binary-file &&
 	git add binary-file &&
 	git commit -m binary2 &&
-	! git merge F > merge.out 2> merge.err &&
+	test_must_fail git merge F > merge.out 2> merge.err &&
 	grep "Cannot merge binary files: HEAD:binary-file vs. F:binary-file" \
 		merge.err
 '
diff --git a/t/t6025-merge-symlinks.sh b/t/t6025-merge-symlinks.sh
index 6004deb..fc58456 100755
--- a/t/t6025-merge-symlinks.sh
+++ b/t/t6025-merge-symlinks.sh
@@ -33,7 +33,7 @@
 test_expect_success \
 'merge master into b-symlink, which has a different symbolic link' '
 git-checkout b-symlink &&
-! git-merge master'
+test_must_fail git-merge master'
 
 test_expect_success \
 'the merge result must be a file' '
@@ -42,7 +42,7 @@
 test_expect_success \
 'merge master into b-file, which has a file instead of a symbolic link' '
 git-reset --hard && git-checkout b-file &&
-! git-merge master'
+test_must_fail git-merge master'
 
 test_expect_success \
 'the merge result must be a file' '
@@ -52,7 +52,7 @@
 'merge b-file, which has a file instead of a symbolic link, into master' '
 git-reset --hard &&
 git-checkout master &&
-! git-merge b-file'
+test_must_fail git-merge b-file'
 
 test_expect_success \
 'the merge result must be a file' '
diff --git a/t/t6101-rev-parse-parents.sh b/t/t6101-rev-parse-parents.sh
index 2328b69..efc8313 100755
--- a/t/t6101-rev-parse-parents.sh
+++ b/t/t6101-rev-parse-parents.sh
@@ -26,7 +26,7 @@
 test_expect_success 'final^1^2' "test $(git rev-parse start2) = $(git rev-parse final^1^2)"
 test_expect_success 'final^1^2 != final^1^1' "test $(git rev-parse final^1^2) != $(git rev-parse final^1^1)"
 test_expect_success 'final^1^3 not valid' "if git rev-parse --verify final^1^3; then false; else :; fi"
-test_expect_success '--verify start2^1' '! git rev-parse --verify start2^1'
+test_expect_success '--verify start2^1' 'test_must_fail git rev-parse --verify start2^1'
 test_expect_success '--verify start2^0' 'git rev-parse --verify start2^0'
 
 test_expect_success 'repack for next test' 'git repack -a -d'
diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index fa382c5..336cfaa 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -80,7 +80,7 @@
 
 test_expect_success \
     'do not move directory over existing directory' \
-    'mkdir path0 && mkdir path0/path2 && ! git mv path2 path0'
+    'mkdir path0 && mkdir path0/path2 && test_must_fail git mv path2 path0'
 
 test_expect_success \
     'move into "."' \
@@ -149,7 +149,7 @@
 	>sub/file &&
 	git add sub/file &&
 
-	! git mv sub "$out/out" &&
+	test_must_fail git mv sub "$out/out" &&
 	test -d sub &&
 	! test -d ../in &&
 	git ls-files --error-unmatch sub/file
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 241c70d..bc7ce2c 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -30,17 +30,17 @@
 	'! (tag_exists mytag)'
 
 test_expect_success 'creating a tag in an empty tree should fail' '
-	! git-tag mynotag &&
+	test_must_fail git-tag mynotag &&
 	! tag_exists mynotag
 '
 
 test_expect_success 'creating a tag for HEAD in an empty tree should fail' '
-	! git-tag mytaghead HEAD &&
+	test_must_fail git-tag mytaghead HEAD &&
 	! tag_exists mytaghead
 '
 
 test_expect_success 'creating a tag for an unknown revision should fail' '
-	! git-tag mytagnorev aaaaaaaaaaa &&
+	test_must_fail git-tag mytagnorev aaaaaaaaaaa &&
 	! tag_exists mytagnorev
 '
 
@@ -85,16 +85,16 @@
 
 test_expect_success \
 	'trying to create a tag with the name of one existing should fail' \
-	'! git tag mytag'
+	'test_must_fail git tag mytag'
 
 test_expect_success \
 	'trying to create a tag with a non-valid name should fail' '
 	test `git-tag -l | wc -l` -eq 1 &&
-	! git tag "" &&
-	! git tag .othertag &&
-	! git tag "other tag" &&
-	! git tag "othertag^" &&
-	! git tag "other~tag" &&
+	test_must_fail git tag "" &&
+	test_must_fail git tag .othertag &&
+	test_must_fail git tag "other tag" &&
+	test_must_fail git tag "othertag^" &&
+	test_must_fail git tag "other~tag" &&
 	test `git-tag -l | wc -l` -eq 1
 '
 
@@ -107,7 +107,7 @@
 
 test_expect_success 'trying to delete an unknown tag should fail' '
 	! tag_exists unknown-tag &&
-	! git-tag -d unknown-tag
+	test_must_fail git-tag -d unknown-tag
 '
 
 cat >expect <<EOF
@@ -141,13 +141,13 @@
 	'trying to delete two tags, existing and not, should fail in the 2nd' '
 	tag_exists mytag &&
 	! tag_exists myhead &&
-	! git-tag -d mytag anothertag &&
+	test_must_fail git-tag -d mytag anothertag &&
 	! tag_exists mytag &&
 	! tag_exists myhead
 '
 
 test_expect_success 'trying to delete an already deleted tag should fail' \
-	'! git-tag -d mytag'
+	'test_must_fail git-tag -d mytag'
 
 # listing various tags with pattern matching:
 
@@ -266,15 +266,15 @@
 '
 
 test_expect_success 'trying to verify an unknown tag should fail' \
-	'! git-tag -v unknown-tag'
+	'test_must_fail git-tag -v unknown-tag'
 
 test_expect_success \
 	'trying to verify a non-annotated and non-signed tag should fail' \
-	'! git-tag -v non-annotated-tag'
+	'test_must_fail git-tag -v non-annotated-tag'
 
 test_expect_success \
 	'trying to verify many non-annotated or unknown tags, should fail' \
-	'! git-tag -v unknown-tag1 non-annotated-tag unknown-tag2'
+	'test_must_fail git-tag -v unknown-tag1 non-annotated-tag unknown-tag2'
 
 # creating annotated tags:
 
@@ -334,7 +334,7 @@
 	'trying to create a tag with a non-existing -F file should fail' '
 	! test -f nonexistingfile &&
 	! tag_exists notag &&
-	! git-tag -F nonexistingfile notag &&
+	test_must_fail git-tag -F nonexistingfile notag &&
 	! tag_exists notag
 '
 
@@ -343,11 +343,12 @@
 	echo "message file 1" >msgfile1 &&
 	echo "message file 2" >msgfile2 &&
 	! tag_exists msgtag &&
-	! git-tag -m "message 1" -F msgfile1 msgtag &&
+	test_must_fail git-tag -m "message 1" -F msgfile1 msgtag &&
 	! tag_exists msgtag &&
-	! git-tag -F msgfile1 -m "message 1" msgtag &&
+	test_must_fail git-tag -F msgfile1 -m "message 1" msgtag &&
 	! tag_exists msgtag &&
-	! git-tag -m "message 1" -F msgfile1 -m "message 2" msgtag &&
+	test_must_fail git-tag -m "message 1" -F msgfile1 \
+		-m "message 2" msgtag &&
 	! tag_exists msgtag
 '
 
@@ -591,19 +592,19 @@
 test_expect_success \
 	'trying to verify an annotated non-signed tag should fail' '
 	tag_exists annotated-tag &&
-	! git-tag -v annotated-tag
+	test_must_fail git-tag -v annotated-tag
 '
 
 test_expect_success \
 	'trying to verify a file-annotated non-signed tag should fail' '
 	tag_exists file-annotated-tag &&
-	! git-tag -v file-annotated-tag
+	test_must_fail git-tag -v file-annotated-tag
 '
 
 test_expect_success \
 	'trying to verify two annotated non-signed tags should fail' '
 	tag_exists annotated-tag file-annotated-tag &&
-	! git-tag -v annotated-tag file-annotated-tag
+	test_must_fail git-tag -v annotated-tag file-annotated-tag
 '
 
 # creating and verifying signed tags:
@@ -651,13 +652,14 @@
 
 test_expect_success 'sign with an unknown id (1)' '
 
-	! git tag -u author@example.com -m "Another message" o-signed-tag
+	test_must_fail git tag -u author@example.com \
+		-m "Another message" o-signed-tag
 
 '
 
 test_expect_success 'sign with an unknown id (2)' '
 
-	! git tag -u DEADBEEF -m "Another message" o-signed-tag
+	test_must_fail git tag -u DEADBEEF -m "Another message" o-signed-tag
 
 '
 
@@ -718,7 +720,7 @@
 	'trying to create a signed tag with non-existing -F file should fail' '
 	! test -f nonexistingfile &&
 	! tag_exists nosigtag &&
-	! git-tag -s -F nonexistingfile nosigtag &&
+	test_must_fail git-tag -s -F nonexistingfile nosigtag &&
 	! tag_exists nosigtag
 '
 
@@ -730,10 +732,11 @@
 
 test_expect_success \
 	'verifying many signed and non-signed tags should fail' '
-	! git-tag -v signed-tag annotated-tag &&
-	! git-tag -v file-annotated-tag file-signed-tag &&
-	! git-tag -v annotated-tag file-signed-tag file-annotated-tag &&
-	! git-tag -v signed-tag annotated-tag file-signed-tag
+	test_must_fail git-tag -v signed-tag annotated-tag &&
+	test_must_fail git-tag -v file-annotated-tag file-signed-tag &&
+	test_must_fail git-tag -v annotated-tag \
+		file-signed-tag file-annotated-tag &&
+	test_must_fail git-tag -v signed-tag annotated-tag file-signed-tag
 '
 
 test_expect_success 'verifying a forged tag should fail' '
@@ -741,7 +744,7 @@
 		sed -e "s/signed-tag/forged-tag/" |
 		git mktag) &&
 	git tag forged-tag $forged &&
-	! git-tag -v forged-tag
+	test_must_fail git-tag -v forged-tag
 '
 
 # blank and empty messages for signed tags:
@@ -1031,7 +1034,7 @@
 git config user.signingkey BobTheMouse
 test_expect_success \
 	'git-tag -s fails if gpg is misconfigured' \
-	'! git tag -s -m tail tag-gpg-failure'
+	'test_must_fail git tag -s -m tail tag-gpg-failure'
 git config --unset user.signingkey
 
 # try to verify without gpg:
@@ -1039,7 +1042,7 @@
 rm -rf gpghome
 test_expect_success \
 	'verify signed tag fails when public key is not present' \
-	'! git-tag -v signed-tag'
+	'test_must_fail git-tag -v signed-tag'
 
 test_expect_success \
 	'git-tag -a fails if tag annotation is empty' '
diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh
index 96d1508..29f5678 100755
--- a/t/t7102-reset.sh
+++ b/t/t7102-reset.sh
@@ -52,10 +52,10 @@
 EOF
 
 test_expect_success 'giving a non existing revision should fail' '
-	! git reset aaaaaa &&
-	! git reset --mixed aaaaaa &&
-	! git reset --soft aaaaaa &&
-	! git reset --hard aaaaaa &&
+	test_must_fail git reset aaaaaa &&
+	test_must_fail git reset --mixed aaaaaa &&
+	test_must_fail git reset --soft aaaaaa &&
+	test_must_fail git reset --hard aaaaaa &&
 	check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc
 '
 
@@ -63,29 +63,29 @@
 	touch .git/MERGE_HEAD &&
 	echo "100644 44c5b5884550c17758737edcced463447b91d42b 1	un" |
 		git update-index --index-info &&
-	! git reset --soft HEAD &&
+	test_must_fail git reset --soft HEAD &&
 	rm .git/MERGE_HEAD &&
 	git rm --cached -- un
 '
 
 test_expect_success \
 	'giving paths with options different than --mixed should fail' '
-	! git reset --soft -- first &&
-	! git reset --hard -- first &&
-	! git reset --soft HEAD^ -- first &&
-	! git reset --hard HEAD^ -- first &&
+	test_must_fail git reset --soft -- first &&
+	test_must_fail git reset --hard -- first &&
+	test_must_fail git reset --soft HEAD^ -- first &&
+	test_must_fail git reset --hard HEAD^ -- first &&
 	check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc
 '
 
 test_expect_success 'giving unrecognized options should fail' '
-	! git reset --other &&
-	! git reset -o &&
-	! git reset --mixed --other &&
-	! git reset --mixed -o &&
-	! git reset --soft --other &&
-	! git reset --soft -o &&
-	! git reset --hard --other &&
-	! git reset --hard -o &&
+	test_must_fail git reset --other &&
+	test_must_fail git reset -o &&
+	test_must_fail git reset --mixed --other &&
+	test_must_fail git reset --mixed -o &&
+	test_must_fail git reset --soft --other &&
+	test_must_fail git reset --soft -o &&
+	test_must_fail git reset --hard --other &&
+	test_must_fail git reset --hard -o &&
 	check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc
 '
 
@@ -102,8 +102,8 @@
 	echo "3rd line in branch2" >>secondfile &&
 	git commit -a -m "change in branch2" &&
 
-	! git merge branch1 &&
-	! git reset --soft &&
+	test_must_fail git merge branch1 &&
+	test_must_fail git reset --soft &&
 
 	printf "1st line 2nd file\n2nd line 2nd file\n3rd line" >secondfile &&
 	git commit -a -m "the change in branch2" &&
@@ -126,7 +126,7 @@
 	echo "3rd line in branch4" >>secondfile &&
 
 	git checkout -m branch3 &&
-	! git reset --soft &&
+	test_must_fail git reset --soft &&
 
 	printf "1st line 2nd file\n2nd line 2nd file\n3rd line" >secondfile &&
 	git commit -a -m "the line in branch3" &&
@@ -326,7 +326,7 @@
 	echo "3rd line in branch2" >>secondfile &&
 	git commit -a -m "change in branch2" &&
 
-	! git pull . branch1 &&
+	test_must_fail git pull . branch1 &&
 	git reset --hard &&
 	check_changes 77abb337073fb4369a7ad69ff6f5ec0e4d6b54bb
 '
@@ -388,7 +388,7 @@
 	echo 4 > file4 &&
 	echo 5 > file1 &&
 	git add file1 file3 file4 &&
-	! git reset HEAD -- file1 file2 file3 &&
+	test_must_fail git reset HEAD -- file1 file2 file3 &&
 	git diff > output &&
 	test_cmp output expect &&
 	git diff --cached > output &&
@@ -402,11 +402,11 @@
 	>sub/file2 &&
 	git update-index --add sub/file1 sub/file2 &&
 	T=$(git write-tree) &&
-	! git reset HEAD sub/file2 &&
+	test_must_fail git reset HEAD sub/file2 &&
 	U=$(git write-tree) &&
 	echo "$T" &&
 	echo "$U" &&
-	! git diff-index --cached --exit-code "$T" &&
+	test_must_fail git diff-index --cached --exit-code "$T" &&
 	test "$T" != "$U"
 
 '
@@ -419,7 +419,7 @@
 '
 
 cat > expect << EOF
-file2: needs update
+file2: locally modified
 EOF
 
 test_expect_success '--mixed refreshes the index' '
diff --git a/t/t7103-reset-bare.sh b/t/t7103-reset-bare.sh
index b25a77f..cdecebe 100755
--- a/t/t7103-reset-bare.sh
+++ b/t/t7103-reset-bare.sh
@@ -17,7 +17,7 @@
 '
 
 test_expect_success 'hard reset is not allowed' '
-	! git reset --hard HEAD^
+	test_must_fail  git reset --hard HEAD^
 '
 
 test_expect_success 'soft reset is allowed' '
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index bd77239..2b51c0d 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -316,14 +316,14 @@
 test_expect_success 'clean.requireForce defaults to true' '
 
 	git config --unset clean.requireForce &&
-	! git-clean
+	test_must_fail git clean
 
 '
 
 test_expect_success 'clean.requireForce' '
 
 	git config clean.requireForce true &&
-	! git-clean
+	test_must_fail git clean
 
 '
 
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 6c7b902..cbc0c34 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -75,7 +75,7 @@
 	then
 		echo "[OOPS] init succeeded but submodule url is wrong"
 		false
-	elif ! git config submodule.example.url ./.subrepo
+	elif test_must_fail git config submodule.example.url ./.subrepo
 	then
 		echo "[OOPS] init succeeded but update of url failed"
 		false
diff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh
index 5becb3e..f919c8d 100755
--- a/t/t7402-submodule-rebase.sh
+++ b/t/t7402-submodule-rebase.sh
@@ -71,7 +71,7 @@
 	test_tick &&
 	git commit -m rewrite file &&
 	echo dirty > file &&
-	! git rebase --onto HEAD~2 HEAD^
+	test_must_fail git rebase --onto HEAD~2 HEAD^
 
 '
 
diff --git a/t/t7500-commit.sh b/t/t7500-commit.sh
index baed6ce..d89f91a 100755
--- a/t/t7500-commit.sh
+++ b/t/t7500-commit.sh
@@ -23,12 +23,12 @@
 test_expect_success 'nonexistent template file should return error' '
 	echo changes >> foo &&
 	git add foo &&
-	! git commit --template "$PWD"/notexist
+	test_must_fail git commit --template "$PWD"/notexist
 '
 
 test_expect_success 'nonexistent template file in config should return error' '
 	git config commit.template "$PWD"/notexist &&
-	! git commit &&
+	test_must_fail git commit &&
 	git config --unset commit.template
 '
 
@@ -37,12 +37,12 @@
 
 test_expect_success 'unedited template should not commit' '
 	echo "template line" > "$TEMPLATE" &&
-	! git commit --template "$TEMPLATE"
+	test_must_fail git commit --template "$TEMPLATE"
 '
 
 test_expect_success 'unedited template with comments should not commit' '
 	echo "# comment in template" >> "$TEMPLATE" &&
-	! git commit --template "$TEMPLATE"
+	test_must_fail git commit --template "$TEMPLATE"
 '
 
 test_expect_success 'a Signed-off-by line by itself should not commit' '
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index d3370ff..0edd9dd 100755
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -19,7 +19,7 @@
 
 test_expect_success \
 	"fail initial amend" \
-	"! git-commit --amend"
+	"test_must_fail git-commit --amend"
 
 test_expect_success \
 	"initial commit" \
@@ -27,16 +27,16 @@
 
 test_expect_success \
 	"invalid options 1" \
-	"! git-commit -m foo -m bar -F file"
+	"test_must_fail git-commit -m foo -m bar -F file"
 
 test_expect_success \
 	"invalid options 2" \
-	"! git-commit -C HEAD -m illegal"
+	"test_must_fail git-commit -C HEAD -m illegal"
 
 test_expect_success \
 	"using paths with -a" \
 	"echo King of the bongo >file &&
-	! git-commit -m foo -a file"
+	test_must_fail git-commit -m foo -a file"
 
 test_expect_success \
 	"using paths with --interactive" \
@@ -45,11 +45,11 @@
 
 test_expect_success \
 	"using invalid commit with -C" \
-	"! git-commit -C bogus"
+	"test_must_fail git-commit -C bogus"
 
 test_expect_success \
 	"testing nothing to commit" \
-	"! git-commit -m initial"
+	"test_must_fail git-commit -m initial"
 
 test_expect_success \
 	"next commit" \
@@ -59,7 +59,7 @@
 test_expect_success \
 	"commit message from non-existing file" \
 	"echo 'more bongo: bongo bongo bongo bongo' >file && \
-	 ! git-commit -F gah -a"
+	 test_must_fail git-commit -F gah -a"
 
 # Empty except stray tabs and spaces on a few lines.
 sed -e 's/@$//' >msg <<EOF
@@ -70,7 +70,7 @@
 EOF
 test_expect_success \
 	"empty commit message" \
-	"! git-commit -F msg -a"
+	"test_must_fail git-commit -F msg -a"
 
 test_expect_success \
 	"commit message from file" \
@@ -91,7 +91,7 @@
 test_expect_success \
 	"passing -m and -F" \
 	"echo 'enough with the bongos' >file && \
-	 ! git-commit -F msg -m amending ."
+	 test_must_fail git-commit -F msg -m amending ."
 
 test_expect_success \
 	"using message from other commit" \
diff --git a/t/t7503-pre-commit-hook.sh b/t/t7503-pre-commit-hook.sh
index 2dd5a5e..b069095 100755
--- a/t/t7503-pre-commit-hook.sh
+++ b/t/t7503-pre-commit-hook.sh
@@ -56,7 +56,7 @@
 
 	echo "another" >> file &&
 	git add file &&
-	! git commit -m "another"
+	test_must_fail git commit -m "another"
 
 '
 
diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh
index 88577af..47680e6 100755
--- a/t/t7504-commit-msg-hook.sh
+++ b/t/t7504-commit-msg-hook.sh
@@ -105,7 +105,7 @@
 
 	echo "another" >> file &&
 	git add file &&
-	! git commit -m "another"
+	test_must_fail git commit -m "another"
 
 '
 
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index d4cf628..5eeb6c2 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -126,7 +126,7 @@
 		echo "[OOPS] unmerged files"
 		false
 	fi &&
-	if ! git diff --exit-code
+	if test_must_fail git diff --exit-code
 	then
 		echo "[OOPS] working tree != index"
 		false
@@ -222,36 +222,12 @@
 test_debug 'gitk --all'
 
 test_expect_success 'test option parsing' '
-	if git merge -$ c1
-	then
-		echo "[OOPS] -$ accepted"
-		false
-	fi &&
-	if git merge --no-such c1
-	then
-		echo "[OOPS] --no-such accepted"
-		false
-	fi &&
-	if git merge -s foobar c1
-	then
-		echo "[OOPS] -s foobar accepted"
-		false
-	fi &&
-	if git merge -s=foobar c1
-	then
-		echo "[OOPS] -s=foobar accepted"
-		false
-	fi &&
-	if git merge -m
-	then
-		echo "[OOPS] missing commit msg accepted"
-		false
-	fi &&
-	if git merge
-	then
-		echo "[OOPS] missing commit references accepted"
-		false
-	fi
+	test_must_fail git merge -$ c1 &&
+	test_must_fail git merge --no-such c1 &&
+	test_must_fail git merge -s foobar c1 &&
+	test_must_fail git merge -s=foobar c1 &&
+	test_must_fail git merge -m &&
+	test_must_fail git merge
 '
 
 test_expect_success 'merge c0 with c1' '
diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh
index 6b0483f..9285071 100755
--- a/t/t7610-mergetool.sh
+++ b/t/t7610-mergetool.sh
@@ -35,7 +35,7 @@
     git config mergetool.mytool.cmd "cat \"\$REMOTE\" >\"\$MERGED\"" &&
     git config mergetool.mytool.trustExitCode true &&
 	git checkout branch1 &&
-    ! git merge master >/dev/null 2>&1 &&
+    test_must_fail git merge master >/dev/null 2>&1 &&
     ( yes "" | git mergetool file1>/dev/null 2>&1 ) &&
     ( yes "" | git mergetool file2>/dev/null 2>&1 ) &&
     test "$(cat file1)" = "master updated" &&
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 3e4eb63..1c857cf 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -13,7 +13,7 @@
 
 test_expect_success \
     'Setup helper tool' \
-    '(echo "#!/bin/sh"
+    '(echo "#!$SHELL_PATH"
       echo shift
       echo output=1
       echo "while test -f commandline\$output; do output=\$((\$output+1)); done"
@@ -91,7 +91,7 @@
 	clean_fake_sendmail &&
 	cp $patches longline.patch &&
 	echo $z512$z512 >>longline.patch &&
-	! git send-email \
+	test_must_fail git send-email \
 		--from="Example <nobody@example.com>" \
 		--to=nobody@example.com \
 		--smtp-server="$(pwd)/fake.sendmail" \
@@ -138,7 +138,7 @@
 '
 
 test_expect_success 'setup fake editor' '
-	(echo "#!/bin/sh" &&
+	(echo "#!$SHELL_PATH" &&
 	 echo "echo fake edit >>\"\$1\""
 	) >fake-editor &&
 	chmod +x fake-editor
@@ -235,7 +235,7 @@
 
 test_expect_success '--compose adds MIME for utf8 body' '
 	clean_fake_sendmail &&
-	(echo "#!/bin/sh" &&
+	(echo "#!$SHELL_PATH" &&
 	 echo "echo utf8 body: àéìöú >>\"\$1\""
 	) >fake-editor-utf8 &&
 	chmod +x fake-editor-utf8 &&
@@ -254,7 +254,7 @@
 
 test_expect_success '--compose respects user mime type' '
 	clean_fake_sendmail &&
-	(echo "#!/bin/sh" &&
+	(echo "#!$SHELL_PATH" &&
 	 echo "(echo MIME-Version: 1.0"
 	 echo " echo Content-Type: text/plain\\; charset=iso-8859-1"
 	 echo " echo Content-Transfer-Encoding: 8bit"
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index 3bc6164..843a501 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -63,7 +63,7 @@
 	git update-index --remove dir/file &&
 	git update-index --add dir/file/file &&
 	git commit -m '$name' &&
-	! git-svn set-tree --find-copies-harder --rmdir \
+	test_must_fail git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch" || true
 
 
@@ -77,7 +77,7 @@
 	git update-index --remove -- bar/zzz &&
 	git update-index --add -- bar &&
 	git commit -m "$name" &&
-	! git-svn set-tree --find-copies-harder --rmdir \
+	test_must_fail git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch2' || true
 
 
@@ -91,7 +91,7 @@
 	echo yyy > bar/zzz/yyy &&
 	git update-index --add bar/zzz/yyy &&
 	git commit -m "$name" &&
-	! git-svn set-tree --find-copies-harder --rmdir \
+	test_must_fail git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch3' || true
 
 
@@ -105,7 +105,7 @@
 	echo asdf > dir &&
 	git update-index --add -- dir &&
 	git commit -m "$name" &&
-	! git-svn set-tree --find-copies-harder --rmdir \
+	test_must_fail git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch4' || true
 
 
@@ -216,7 +216,7 @@
 test_expect_success 'exit if remote refs are ambigious' "
         git config --add svn-remote.svn.fetch \
                               bar:refs/remotes/git-svn &&
-	! git-svn migrate
+	test_must_fail git-svn migrate
 "
 
 test_expect_success 'exit if init-ing a would clobber a URL' '
@@ -224,7 +224,7 @@
         svn mkdir -m "mkdir bar" "${svnrepo}2/bar" &&
         git config --unset svn-remote.svn.fetch \
                                 "^bar:refs/remotes/git-svn$" &&
-	! git-svn init "${svnrepo}2/bar"
+	test_must_fail git-svn init "${svnrepo}2/bar"
         '
 
 test_expect_success \
diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh
index 27a65e0..08bf1f0 100755
--- a/t/t9106-git-svn-commit-diff-clobber.sh
+++ b/t/t9106-git-svn-commit-diff-clobber.sh
@@ -27,7 +27,7 @@
 test_expect_success 'commit conflicting change from git' '
 	echo second line from git >> file &&
 	git commit -a -m "second line from git" &&
-	! git-svn commit-diff -r1 HEAD~1 HEAD "$svnrepo"
+	test_must_fail git-svn commit-diff -r1 HEAD~1 HEAD "$svnrepo"
 '
 
 test_expect_success 'commit complementing change from git' '
@@ -52,7 +52,7 @@
 	rm -rf t.svn &&
 	echo "fourth line from git" >> file &&
 	git commit -a -m "fourth line from git" &&
-	! git-svn dcommit
+	test_must_fail git-svn dcommit
 	'
 
 test_expect_success 'dcommit does the svn equivalent of an index merge' "
@@ -83,7 +83,7 @@
 	git commit -a -m 'new file' &&
 	echo clobber > file &&
 	git commit -a -m 'clobber' &&
-	! git svn dcommit
+	test_must_fail git svn dcommit
 	"
 
 
diff --git a/t/t9106-git-svn-dcommit-clobber-series.sh b/t/t9106-git-svn-dcommit-clobber-series.sh
index f8f4718..bc37db9 100755
--- a/t/t9106-git-svn-dcommit-clobber-series.sh
+++ b/t/t9106-git-svn-dcommit-clobber-series.sh
@@ -57,7 +57,7 @@
 test_expect_success 'attempt to dcommit with a dirty index' '
 	echo foo >>file &&
 	git add file &&
-	! git svn dcommit
+	test_must_fail git svn dcommit
 '
 
 test_done
diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh
index b1dc32d..3e32e84 100755
--- a/t/t9200-git-cvsexportcommit.sh
+++ b/t/t9200-git-cvsexportcommit.sh
@@ -100,7 +100,7 @@
      git commit -a -m "generation 2" &&
      id=$(git rev-list --max-count=1 HEAD) &&
      (cd "$CVSWORK" &&
-     ! git cvsexportcommit -c $id
+     test_must_fail git cvsexportcommit -c $id
      )'
 
 #test_expect_success \
@@ -112,7 +112,7 @@
 #     git commit -a -m "generation 3" &&
 #     id=$(git rev-list --max-count=1 HEAD) &&
 #     (cd "$CVSWORK" &&
-#     ! git cvsexportcommit -c $id
+#     test_must_fail git cvsexportcommit -c $id
 #     )'
 
 # We reuse the state from two tests back here
@@ -222,7 +222,7 @@
       git commit -a -m "Update two" &&
       id=$(git rev-list --max-count=1 HEAD) &&
       (cd "$CVSWORK" &&
-      ! git-cvsexportcommit -c $id
+      test_must_fail git-cvsexportcommit -c $id
       )'
 
 case "$(git config --bool core.filemode)" in
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 5edf56f..1fc06c5 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -166,7 +166,7 @@
 
 INPUT_END
 test_expect_success 'B: fail on invalid blob sha1' '
-    ! git-fast-import <input
+    test_must_fail git-fast-import <input
 '
 rm -f .git/objects/pack_* .git/objects/index_*
 
@@ -181,7 +181,7 @@
 
 INPUT_END
 test_expect_success 'B: fail on invalid branch name ".badbranchname"' '
-    ! git-fast-import <input
+    test_must_fail git-fast-import <input
 '
 rm -f .git/objects/pack_* .git/objects/index_*
 
@@ -196,7 +196,7 @@
 
 INPUT_END
 test_expect_success 'B: fail on invalid branch name "bad[branch]name"' '
-    ! git-fast-import <input
+    test_must_fail git-fast-import <input
 '
 rm -f .git/objects/pack_* .git/objects/index_*
 
@@ -340,7 +340,7 @@
 
 INPUT_END
 test_expect_success 'E: rfc2822 date, --date-format=raw' '
-    ! git-fast-import --date-format=raw <input
+    test_must_fail git-fast-import --date-format=raw <input
 '
 test_expect_success \
     'E: rfc2822 date, --date-format=rfc2822' \
@@ -918,4 +918,156 @@
 	 grep "progress " <input >expect &&
 	 test_cmp expect actual'
 
+###
+### series P (gitlinks)
+###
+
+cat >input <<INPUT_END
+blob
+mark :1
+data 10
+test file
+
+reset refs/heads/sub
+commit refs/heads/sub
+mark :2
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data 12
+sub_initial
+M 100644 :1 file
+
+blob
+mark :3
+data <<DATAEND
+[submodule "sub"]
+	path = sub
+	url = "`pwd`/sub"
+DATAEND
+
+commit refs/heads/subuse1
+mark :4
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data 8
+initial
+from refs/heads/master
+M 100644 :3 .gitmodules
+M 160000 :2 sub
+
+blob
+mark :5
+data 20
+test file
+more data
+
+commit refs/heads/sub
+mark :6
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data 11
+sub_second
+from :2
+M 100644 :5 file
+
+commit refs/heads/subuse1
+mark :7
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data 7
+second
+from :4
+M 160000 :6 sub
+
+INPUT_END
+
+test_expect_success \
+	'P: supermodule & submodule mix' \
+	'git-fast-import <input &&
+	 git checkout subuse1 &&
+	 rm -rf sub && mkdir sub && cd sub &&
+	 git init &&
+	 git fetch .. refs/heads/sub:refs/heads/master &&
+	 git checkout master &&
+	 cd .. &&
+	 git submodule init &&
+	 git submodule update'
+
+SUBLAST=$(git-rev-parse --verify sub)
+SUBPREV=$(git-rev-parse --verify sub^)
+
+cat >input <<INPUT_END
+blob
+mark :1
+data <<DATAEND
+[submodule "sub"]
+	path = sub
+	url = "`pwd`/sub"
+DATAEND
+
+commit refs/heads/subuse2
+mark :2
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data 8
+initial
+from refs/heads/master
+M 100644 :1 .gitmodules
+M 160000 $SUBPREV sub
+
+commit refs/heads/subuse2
+mark :3
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data 7
+second
+from :2
+M 160000 $SUBLAST sub
+
+INPUT_END
+
+test_expect_success \
+	'P: verbatim SHA gitlinks' \
+	'git branch -D sub &&
+	 git gc && git prune &&
+	 git-fast-import <input &&
+	 test $(git-rev-parse --verify subuse2) = $(git-rev-parse --verify subuse1)'
+
+test_tick
+cat >input <<INPUT_END
+commit refs/heads/subuse3
+mark :1
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+corrupt
+COMMIT
+
+from refs/heads/subuse2
+M 160000 inline sub
+data <<DATA
+$SUBPREV
+DATA
+
+INPUT_END
+
+test_expect_success 'P: fail on inline gitlink' '
+    ! git-fast-import <input'
+
+test_tick
+cat >input <<INPUT_END
+blob
+mark :1
+data <<DATA
+$SUBPREV
+DATA
+
+commit refs/heads/subuse3
+mark :2
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+corrupt
+COMMIT
+
+from refs/heads/subuse2
+M 160000 :1 sub
+
+INPUT_END
+
+test_expect_success 'P: fail on blob mark in gitlink' '
+    ! git-fast-import <input'
+
 test_done
diff --git a/t/t9301-fast-export.sh b/t/t9301-fast-export.sh
index f1bc5ce..8324f6e 100755
--- a/t/t9301-fast-export.sh
+++ b/t/t9301-fast-export.sh
@@ -59,7 +59,7 @@
 		 test $MASTER != $(git rev-parse --verify refs/heads/partial) &&
 		 git diff master..partial &&
 		 git diff master^..partial^ &&
-		 ! git rev-parse partial~2)
+		 test_must_fail git rev-parse partial~2)
 
 '
 
@@ -125,7 +125,7 @@
 
 test_expect_success 'signed-tags=abort' '
 
-	! git fast-export --signed-tags=abort sign-your-name
+	test_must_fail git fast-export --signed-tags=abort sign-your-name
 
 '
 
@@ -143,4 +143,46 @@
 
 '
 
+test_expect_success 'setup submodule' '
+
+	git checkout -f master &&
+	mkdir sub &&
+	cd sub &&
+	git init  &&
+	echo test file > file &&
+	git add file &&
+	git commit -m sub_initial &&
+	cd .. &&
+	git submodule add "`pwd`/sub" sub &&
+	git commit -m initial &&
+	test_tick &&
+	cd sub &&
+	echo more data >> file &&
+	git add file &&
+	git commit -m sub_second &&
+	cd .. &&
+	git add sub &&
+	git commit -m second
+
+'
+
+test_expect_success 'submodule fast-export | fast-import' '
+
+	SUBENT1=$(git ls-tree master^ sub) &&
+	SUBENT2=$(git ls-tree master sub) &&
+	rm -rf new &&
+	mkdir new &&
+	git --git-dir=new/.git init &&
+	git fast-export --signed-tags=strip --all |
+	(cd new &&
+	 git fast-import &&
+	 test "$SUBENT1" = "$(git ls-tree refs/heads/master^ sub)" &&
+	 test "$SUBENT2" = "$(git ls-tree refs/heads/master sub)" &&
+	 git checkout master &&
+	 git submodule init &&
+	 git submodule update &&
+	 cmp sub/file ../sub/file)
+
+'
+
 test_done
diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
index e97aaa6..4b91f8d 100755
--- a/t/t9400-git-cvsserver-server.sh
+++ b/t/t9400-git-cvsserver-server.sh
@@ -438,6 +438,13 @@
     test -z "$(cat failures)"
 '
 
+cd "$WORKDIR"
+test_expect_success 'cvs update (module list supports packed refs)' '
+    GIT_DIR="$SERVERDIR" git pack-refs --all &&
+    GIT_CONFIG="$git_config" cvs -n up -d 2> out &&
+    grep "cvs update: New directory \`master'\''" < out
+'
+
 #------------
 # CVS STATUS
 #------------
@@ -470,4 +477,15 @@
     ! grep / <../out
 '
 
+#------------
+# CVS CHECKOUT
+#------------
+
+cd "$WORKDIR"
+test_expect_success 'cvs co -c (shows module database)' '
+    GIT_CONFIG="$git_config" cvs co -c > out &&
+    grep "^master[	 ]\+master$" < out &&
+    ! grep -v "^master[	 ]\+master$" < out
+'
+
 test_done
diff --git a/t/t9600-cvsimport.sh b/t/t9600-cvsimport.sh
index 1e01e5c..0d7786a 100755
--- a/t/t9600-cvsimport.sh
+++ b/t/t9600-cvsimport.sh
@@ -5,6 +5,7 @@
 
 CVSROOT=$(pwd)/cvsroot
 export CVSROOT
+unset CVS_SERVER
 # for clean cvsps cache
 HOME=$(pwd)
 export HOME
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 8e2849b..11c0275 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -379,7 +379,7 @@
 
 test_must_fail () {
 	"$@"
-	test $? -gt 0 -a $? -le 129
+	test $? -gt 0 -a $? -le 129 -o $? -gt 192
 }
 
 # test_cmp is a helper function to compare actual and expected output.
diff --git a/tree-diff.c b/tree-diff.c
index e1e2e6c..bbb126f 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -15,6 +15,15 @@
 	return newbase;
 }
 
+static char *malloc_fullname(const char *base, int baselen, const char *path, int pathlen)
+{
+	char *fullname = xmalloc(baselen + pathlen + 1);
+	memcpy(fullname, base, baselen);
+	memcpy(fullname + baselen, path, pathlen);
+	fullname[baselen + pathlen] = 0;
+	return fullname;
+}
+
 static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,
 		       const char *base, int baselen);
 
@@ -24,6 +33,7 @@
 	const char *path1, *path2;
 	const unsigned char *sha1, *sha2;
 	int cmp, pathlen1, pathlen2;
+	char *fullname;
 
 	sha1 = tree_entry_extract(t1, &path1, &mode1);
 	sha2 = tree_entry_extract(t2, &path2, &mode2);
@@ -55,15 +65,20 @@
 	if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) {
 		int retval;
 		char *newbase = malloc_base(base, baselen, path1, pathlen1);
-		if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE))
+		if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) {
+			newbase[baselen + pathlen1] = 0;
 			opt->change(opt, mode1, mode2,
-				    sha1, sha2, base, path1);
+				    sha1, sha2, newbase);
+			newbase[baselen + pathlen1] = '/';
+		}
 		retval = diff_tree_sha1(sha1, sha2, newbase, opt);
 		free(newbase);
 		return retval;
 	}
 
-	opt->change(opt, mode1, mode2, sha1, sha2, base, path1);
+	fullname = malloc_fullname(base, baselen, path1, pathlen1);
+	opt->change(opt, mode1, mode2, sha1, sha2, fullname);
+	free(fullname);
 	return 0;
 }
 
@@ -205,10 +220,10 @@
 	unsigned mode;
 	const char *path;
 	const unsigned char *sha1 = tree_entry_extract(desc, &path, &mode);
+	int pathlen = tree_entry_len(path, sha1);
 
 	if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode)) {
 		enum object_type type;
-		int pathlen = tree_entry_len(path, sha1);
 		char *newbase = malloc_base(base, baselen, path, pathlen);
 		struct tree_desc inner;
 		void *tree;
@@ -224,7 +239,9 @@
 		free(tree);
 		free(newbase);
 	} else {
-		opt->add_remove(opt, prefix[0], mode, sha1, base, path);
+		char *fullname = malloc_fullname(base, baselen, path, pathlen);
+		opt->add_remove(opt, prefix[0], mode, sha1, fullname);
+		free(fullname);
 	}
 }
 
diff --git a/tree.c b/tree.c
index 4b1825c..03e782a 100644
--- a/tree.c
+++ b/tree.c
@@ -29,7 +29,7 @@
 	return add_cache_entry(ce, opt);
 }
 
-static int read_one_entry(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
+static int read_one_entry(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)
 {
 	return read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,
 				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
@@ -39,7 +39,7 @@
  * This is used when the caller knows there is no existing entries at
  * the stage that will conflict with the entry being added.
  */
-static int read_one_entry_quick(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
+static int read_one_entry_quick(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)
 {
 	return read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,
 				  ADD_CACHE_JUST_APPEND);
@@ -92,7 +92,7 @@
 int read_tree_recursive(struct tree *tree,
 			const char *base, int baselen,
 			int stage, const char **match,
-			read_tree_fn_t fn)
+			read_tree_fn_t fn, void *context)
 {
 	struct tree_desc desc;
 	struct name_entry entry;
@@ -106,7 +106,7 @@
 		if (!match_tree_entry(base, baselen, entry.path, entry.mode, match))
 			continue;
 
-		switch (fn(entry.sha1, base, baselen, entry.path, entry.mode, stage)) {
+		switch (fn(entry.sha1, base, baselen, entry.path, entry.mode, stage, context)) {
 		case 0:
 			continue;
 		case READ_TREE_RECURSIVE:
@@ -126,7 +126,7 @@
 			retval = read_tree_recursive(lookup_tree(entry.sha1),
 						     newbase,
 						     baselen + pathlen + 1,
-						     stage, match, fn);
+						     stage, match, fn, context);
 			free(newbase);
 			if (retval)
 				return -1;
@@ -174,7 +174,7 @@
 
 	if (!fn)
 		fn = read_one_entry_quick;
-	err = read_tree_recursive(tree, "", 0, stage, match, fn);
+	err = read_tree_recursive(tree, "", 0, stage, match, fn, NULL);
 	if (fn == read_one_entry || err)
 		return err;
 
diff --git a/tree.h b/tree.h
index dd25c53..2ff01a4 100644
--- a/tree.h
+++ b/tree.h
@@ -21,12 +21,12 @@
 struct tree *parse_tree_indirect(const unsigned char *sha1);
 
 #define READ_TREE_RECURSIVE 1
-typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const char *, unsigned int, int);
+typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
 
 extern int read_tree_recursive(struct tree *tree,
 			       const char *base, int baselen,
 			       int stage, const char **match,
-			       read_tree_fn_t fn);
+			       read_tree_fn_t fn, void *context);
 
 extern int read_tree(struct tree *tree, int stage, const char **paths);
 
diff --git a/update-server-info.c b/update-server-info.c
index 0b6c383..7e8209e 100644
--- a/update-server-info.c
+++ b/update-server-info.c
@@ -1,7 +1,7 @@
 #include "cache.h"
 
 static const char update_server_info_usage[] =
-"git-update-server-info [--force]";
+"git update-server-info [--force]";
 
 int main(int ac, char **av)
 {
diff --git a/wrapper.c b/wrapper.c
index 4e04f76..93562f0 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -133,6 +133,44 @@
 	}
 }
 
+ssize_t read_in_full(int fd, void *buf, size_t count)
+{
+	char *p = buf;
+	ssize_t total = 0;
+
+	while (count > 0) {
+		ssize_t loaded = xread(fd, p, count);
+		if (loaded <= 0)
+			return total ? total : loaded;
+		count -= loaded;
+		p += loaded;
+		total += loaded;
+	}
+
+	return total;
+}
+
+ssize_t write_in_full(int fd, const void *buf, size_t count)
+{
+	const char *p = buf;
+	ssize_t total = 0;
+
+	while (count > 0) {
+		ssize_t written = xwrite(fd, p, count);
+		if (written < 0)
+			return -1;
+		if (!written) {
+			errno = ENOSPC;
+			return -1;
+		}
+		count -= written;
+		p += written;
+		total += written;
+	}
+
+	return total;
+}
+
 int xdup(int fd)
 {
 	int ret = dup(fd);
diff --git a/write_or_die.c b/write_or_die.c
index e4c8e22..4c29255 100644
--- a/write_or_die.c
+++ b/write_or_die.c
@@ -45,44 +45,6 @@
 	}
 }
 
-ssize_t read_in_full(int fd, void *buf, size_t count)
-{
-	char *p = buf;
-	ssize_t total = 0;
-
-	while (count > 0) {
-		ssize_t loaded = xread(fd, p, count);
-		if (loaded <= 0)
-			return total ? total : loaded;
-		count -= loaded;
-		p += loaded;
-		total += loaded;
-	}
-
-	return total;
-}
-
-ssize_t write_in_full(int fd, const void *buf, size_t count)
-{
-	const char *p = buf;
-	ssize_t total = 0;
-
-	while (count > 0) {
-		ssize_t written = xwrite(fd, p, count);
-		if (written < 0)
-			return -1;
-		if (!written) {
-			errno = ENOSPC;
-			return -1;
-		}
-		count -= written;
-		p += written;
-		total += written;
-	}
-
-	return total;
-}
-
 void fsync_or_die(int fd, const char *msg)
 {
 	if (fsync(fd) < 0) {