GIT 1.5.6.6

Signed-off-by: Junio C Hamano <gitster@pobox.com>
diff --git a/Documentation/.gitignore b/Documentation/.gitignore
index 2f938f4..d8edd90 100644
--- a/Documentation/.gitignore
+++ b/Documentation/.gitignore
@@ -2,7 +2,9 @@
 *.html
 *.[1-8]
 *.made
+*.texi
 git.info
+gitman.info
 howto-index.txt
 doc.dep
 cmds-*.txt
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index 994eb91..d2a0a76 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -89,6 +89,8 @@
    of "else if" statements, it can make sense to add braces to
    single line blocks.
 
+ - We try to avoid assignments inside if().
+
  - Try to make your code understandable.  You may put comments
    in, but comments invariably tend to stale out when the code
    they were describing changes.  Often splitting a function
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 43781fb..62269e3 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -1,9 +1,12 @@
 MAN1_TXT= \
 	$(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
 		$(wildcard git-*.txt)) \
-	gitk.txt
-MAN5_TXT=gitattributes.txt gitignore.txt gitcli.txt gitmodules.txt
-MAN7_TXT=git.txt
+	gitk.txt git.txt
+MAN5_TXT=gitattributes.txt gitignore.txt gitmodules.txt githooks.txt \
+	gitrepository-layout.txt
+MAN7_TXT=gitcli.txt gittutorial.txt gittutorial-2.txt \
+	gitcvs-migration.txt gitcore-tutorial.txt gitglossary.txt \
+	gitdiffcore.txt
 
 MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT)
 MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
@@ -11,17 +14,9 @@
 
 DOC_HTML=$(MAN_HTML)
 
-ARTICLES = tutorial
-ARTICLES += tutorial-2
-ARTICLES += core-tutorial
-ARTICLES += cvs-migration
-ARTICLES += diffcore
-ARTICLES += howto-index
-ARTICLES += repository-layout
-ARTICLES += hooks
+ARTICLES = howto-index
 ARTICLES += everyday
 ARTICLES += git-tools
-ARTICLES += glossary
 # with their own formatting rules.
 SP_ARTICLES = howto/revert-branch-rebase howto/using-merge-subtree user-manual
 API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt)))
@@ -144,8 +139,6 @@
 	$(PERL_PATH) ./cmd-list.perl ../command-list.txt
 	date >$@
 
-git.7 git.html: git.txt
-
 clean:
 	$(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7
 	$(RM) *.texi *.texi+ git.info gitman.info
diff --git a/Documentation/RelNotes-1.5.2.txt b/Documentation/RelNotes-1.5.2.txt
index 6195715..e8328d0 100644
--- a/Documentation/RelNotes-1.5.2.txt
+++ b/Documentation/RelNotes-1.5.2.txt
@@ -36,7 +36,7 @@
   expansion).  These conversions apply when checking files in
   or out, and exporting via git-archive.
 
-* The packfile format now optionally suports 64-bit index.
+* The packfile format now optionally supports 64-bit index.
 
   This release supports the "version 2" format of the .idx
   file.  This is automatically enabled when a huge packfile
diff --git a/Documentation/RelNotes-1.5.3.txt b/Documentation/RelNotes-1.5.3.txt
index d03894b..0668d3c 100644
--- a/Documentation/RelNotes-1.5.3.txt
+++ b/Documentation/RelNotes-1.5.3.txt
@@ -86,7 +86,7 @@
 
   - "git rev-list" learned --regexp-ignore-case and
     --extended-regexp options to tweak its matching logic used
-    for --grep fitering.
+    for --grep filtering.
 
   - "git describe --contains" is a handier way to call more
     obscure command "git name-rev --tags".
@@ -243,7 +243,7 @@
 
   - We used to have core.legacyheaders configuration, when
     set to false, allowed git to write loose objects in a format
-    that mimicks the format used by objects stored in packs.  It
+    that mimics the format used by objects stored in packs.  It
     turns out that this was not so useful.  Although we will
     continue to read objects written in that format, we do not
     honor that configuration anymore and create loose objects in
@@ -302,7 +302,7 @@
     small enough delta results it creates while looking for the
     best delta candidates.
 
-  - "git pack-objects" learned a new heuristcs to prefer delta
+  - "git pack-objects" learned a new heuristic to prefer delta
     that is shallower in depth over the smallest delta
     possible.  This improves both overall packfile access
     performance and packfile density.
diff --git a/Documentation/RelNotes-1.5.4.4.txt b/Documentation/RelNotes-1.5.4.4.txt
index 89fa6d0..323c1a8 100644
--- a/Documentation/RelNotes-1.5.4.4.txt
+++ b/Documentation/RelNotes-1.5.4.4.txt
@@ -55,7 +55,7 @@
 
  * "git log --merge" did not work well with --left-right option.
 
- * "git svn" promprted for client cert password every time it accessed the
+ * "git svn" prompted for client cert password every time it accessed the
    server.
 
  * The reset command in "git fast-import" data stream was documented to
diff --git a/Documentation/RelNotes-1.5.4.5.txt b/Documentation/RelNotes-1.5.4.5.txt
index 0282341..bbd130e 100644
--- a/Documentation/RelNotes-1.5.4.5.txt
+++ b/Documentation/RelNotes-1.5.4.5.txt
@@ -9,7 +9,7 @@
    1.5.4).
 
  * Bogus refspec configuration such as "remote.there.fetch = =" were not
-   detected as errors (regressionin 1.5.4).
+   detected as errors (regression in 1.5.4).
 
  * You couldn't specify a custom editor whose path contains a whitespace
    via GIT_EDITOR (and core.editor).
diff --git a/Documentation/RelNotes-1.5.6.1.txt b/Documentation/RelNotes-1.5.6.1.txt
new file mode 100644
index 0000000..4864b16
--- /dev/null
+++ b/Documentation/RelNotes-1.5.6.1.txt
@@ -0,0 +1,28 @@
+GIT v1.5.6.1 Release Notes
+==========================
+
+Fixes since v1.5.6
+------------------
+
+* Last minute change broke loose object creation on AIX.
+
+* (performance fix) We used to make $GIT_DIR absolute path early in the
+  programs but keeping it relative to the current directory internally
+  gives 1-3 per-cent performance boost.
+
+* bash completion knows the new --graph option to git-log family.
+
+
+* git-diff -c/--cc showed unnecessary "deletion" lines at the context
+  boundary.
+
+* git-for-each-ref ignored %(object) and %(type) requests for tag
+  objects.
+
+* git-merge usage had a typo.
+
+* Rebuilding of git-svn metainfo database did not take rewriteRoot
+  option into account.
+
+* Running "git-rebase --continue/--skip/--abort" before starting a
+  rebase gave nonsense error messages.
diff --git a/Documentation/RelNotes-1.5.6.2.txt b/Documentation/RelNotes-1.5.6.2.txt
new file mode 100644
index 0000000..5902a85
--- /dev/null
+++ b/Documentation/RelNotes-1.5.6.2.txt
@@ -0,0 +1,40 @@
+GIT v1.5.6.2 Release Notes
+==========================
+
+Futureproof
+-----------
+
+ * "git-shell" accepts requests without a dash between "git" and
+   subcommand name (e.g. "git upload-pack") which the newer client will
+   start to make sometime in the future.
+
+Fixes since v1.5.6.1
+--------------------
+
+* "git clone" from a remote that is named with url.insteadOf setting in
+  $HOME/.gitconfig did not work well.
+
+* "git describe --long --tags" segfaulted when the described revision was
+  tagged with a lightweight tag.
+
+* "git diff --check" did not report the result via its exit status
+  reliably.
+
+* When remote side used to have branch 'foo' and git-fetch finds that now
+  it has branch 'foo/bar', it refuses to lose the existing remote tracking
+  branch and its reflog.  The error message has been improved to suggest
+  pruning the remote if the user wants to proceed and get the latest set
+  of branches from the remote, including such 'foo/bar'.
+
+* "git reset file" should mean the same thing as "git reset HEAD file",
+  but we required disambiguating -- even when "file" is not ambiguous.
+
+* "git show" segfaulted when an annotated tag that points at another
+  annotated tag was given to it.
+
+* Optimization for a large import via "git-svn" introduced in v1.5.6 had a
+  serious memory and temporary file leak, which made it unusable for
+  moderately large import.
+
+* "git-svn" mangled remote nickname used in the configuration file
+  unnecessarily.
diff --git a/Documentation/RelNotes-1.5.6.3.txt b/Documentation/RelNotes-1.5.6.3.txt
new file mode 100644
index 0000000..9426112
--- /dev/null
+++ b/Documentation/RelNotes-1.5.6.3.txt
@@ -0,0 +1,52 @@
+GIT v1.5.6.3 Release Notes
+==========================
+
+Fixes since v1.5.6.2
+--------------------
+
+* Setting core.sharerepository to traditional "true" value was supposed to make
+  the repository group writable but should not affect permission for others.
+  However, since 1.5.6, it was broken to drop permission for others when umask is
+  022, making the repository unreadable by others.
+
+* Setting GIT_TRACE will report spawning of external process via run_command().
+
+* Using an object with very deep delta chain pinned memory needed for extracting
+  intermediate base objects unnecessarily long, leading to excess memory usage.
+
+* Bash completion script did not notice '--' marker on the command
+  line and tried the relatively slow "ref completion" even when
+  completing arguments after one.
+
+* Registering a non-empty blob racily and then truncating the working
+  tree file for it confused "racy-git avoidance" logic into thinking
+  that the path is now unchanged.
+
+* The section that describes attributes related to git-archive were placed
+  in a wrong place in the gitattributes(5) manual page.
+
+* "git am" was not helpful to the users when it detected that the committer
+  information is not set up properly yet.
+
+* "git clone" had a leftover debugging fprintf().
+
+* "git clone -q" was not quiet enough as it used to and gave object count
+  and progress reports.
+
+* "git clone" marked downloaded packfile with .keep; this could be a
+  good thing if the remote side is well packed but otherwise not,
+  especially for a project that is not really big.
+
+* "git daemon" used to call syslog() from a signal handler, which
+  could raise signals of its own but generally is not reentrant.  This
+  was fixed by restructuring the code to report syslog() after the handler
+  returns.
+
+* When "git push" tries to remove a remote ref, and corresponding
+  tracking ref is missing, we used to report error (i.e. failure to
+  remove something that does not exist).
+
+* "git mailinfo" (hence "git am") did not handle commit log messages in a
+  MIME multipart mail correctly.
+
+Contains other various documentation fixes.
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.5.6.5.txt b/Documentation/RelNotes-1.5.6.5.txt
new file mode 100644
index 0000000..47ca172
--- /dev/null
+++ b/Documentation/RelNotes-1.5.6.5.txt
@@ -0,0 +1,29 @@
+GIT v1.5.6.5 Release Notes
+==========================
+
+Fixes since v1.5.6.4
+--------------------
+
+* "git cvsimport" used to spit out "UNKNOWN LINE..." diagnostics to stdout.
+
+* "git commit -F filename" and "git tag -F filename" run from subdirectories
+  did not read the right file.
+
+* "git init --template=" with blank "template" parameter linked files
+  under root directories to .git, which was a total nonsense.  Instead, it
+  means "I do not want to use anything from the template directory".
+
+* "git diff-tree" and other diff plumbing ignored diff.renamelimit configuration
+  variable when the user explicitly asked for rename detection.
+
+* "git name-rev --name-only" did not work when "--stdin" option was in effect.
+
+* "git show-branch" mishandled its 8th branch.
+
+* Addition of "git update-index --ignore-submodules" that happened during
+  1.5.6 cycle broke "git update-index --ignore-missing".
+
+* "git send-email" did not parse charset from an existing Content-type:
+  header properly.
+
+Contains other various documentation fixes.
diff --git a/Documentation/RelNotes-1.5.6.6.txt b/Documentation/RelNotes-1.5.6.6.txt
new file mode 100644
index 0000000..79da23d
--- /dev/null
+++ b/Documentation/RelNotes-1.5.6.6.txt
@@ -0,0 +1,10 @@
+GIT v1.5.6.6 Release Notes
+==========================
+
+Fixes since 1.5.6.5
+-------------------
+
+ * Removed support for an obsolete gitweb request URI, whose
+   implementation ran "git diff" Porcelain, instead of using plumbing,
+   which would have run an external diff command specified in the
+   repository configuration as the gitweb user.
diff --git a/Documentation/RelNotes-1.5.6.txt b/Documentation/RelNotes-1.5.6.txt
new file mode 100644
index 0000000..e143d8d
--- /dev/null
+++ b/Documentation/RelNotes-1.5.6.txt
@@ -0,0 +1,115 @@
+GIT v1.5.6 Release Notes
+========================
+
+Updates since v1.5.5
+--------------------
+
+(subsystems)
+
+* Comes with updated gitk and git-gui.
+
+(portability)
+
+* git will build on AIX better than before now.
+
+* core.ignorecase configuration variable can be used to work better on
+  filesystems that are not case sensitive.
+
+* "git init" now autodetects the case sensitivity of the filesystem and
+  sets core.ignorecase accordingly.
+
+* cpio is no longer used; neither "curl" binary (libcurl is still used).
+
+(documentation)
+
+* Many freestanding documentation pages have been converted and made
+  available to "git help" (aka "man git<something>") as section 7 of
+  the manual pages. This means bookmarks to some HTML documentation
+  files may need to be updated (eg "tutorial.html" became
+  "gittutorial.html").
+
+(performance)
+
+* "git clone" was rewritten in C.  This will hopefully help cloning a
+  repository with insane number of refs.
+
+* "git rebase --onto $there $from $branch" used to switch to the tip of
+  $branch only to immediately reset back to $from, smudging work tree
+  files unnecessarily.  This has been optimized.
+
+* Object creation codepath in "git-svn" has been optimized by enhancing
+  plumbing commands git-cat-file and git-hash-object.
+
+(usability, bells and whistles)
+
+* "git add -p" (and the "patch" subcommand of "git add -i") can choose to
+  apply (or not apply) mode changes independently from contents changes.
+
+* "git bisect help" gives longer and more helpful usage information.
+
+* "git bisect" does not use a special branch "bisect" anymore; instead, it
+  does its work on a detached HEAD.
+
+* "git branch" (and "git checkout -b") can be told to set up
+  branch.<name>.rebase automatically, so that later you can say "git pull"
+  and magically cause "git pull --rebase" to happen.
+
+* "git branch --merged" and "git branch --no-merged" can be used to list
+  branches that have already been merged (or not yet merged) to the
+  current branch.
+
+* "git cherry-pick" and "git revert" can add a sign-off.
+
+* "git commit" mentions the author identity when you are committing
+  somebody else's changes.
+
+* "git diff/log --dirstat" output is consistent between binary and textual
+  changes.
+
+* "git filter-branch" rewrites signed tags by demoting them to annotated.
+
+* "git format-patch --no-binary" can produce a patch that lack binary
+  changes (i.e. cannot be used to propagate the whole changes) meant only
+  for reviewing.
+
+* "git init --bare" is a synonym for "git --bare init" now.
+
+* "git gc --auto" honors a new pre-auto-gc hook to temporarily disable it.
+
+* "git log --pretty=tformat:<custom format>" gives a LF after each entry,
+  instead of giving a LF between each pair of entries which is how
+  "git log --pretty=format:<custom format>" works.
+
+* "git log" and friends learned the "--graph" option to show the ancestry
+  graph at the left margin of the output.
+
+* "git log" and friends can be told to use date format that is different
+  from the default via 'log.date' configuration variable.
+
+* "git send-email" now can send out messages outside a git repository.
+
+* "git send-email --compose" was made aware of rfc2047 quoting.
+
+* "git status" can optionally include output from "git submodule
+  summary".
+
+* "git svn" learned --add-author-from option to propagate the authorship
+  by munging the commit log message.
+
+* new object creation and looking up in "git svn" has been optimized.
+
+* "gitweb" can read from a system-wide configuration file.
+
+(internal)
+
+* "git unpack-objects" and "git receive-pack" is now more strict about
+  detecting breakage in the objects they receive over the wire.
+
+
+Fixes since v1.5.5
+------------------
+
+All of the fixes in v1.5.5 maintenance series are included in
+this release, unless otherwise noted.
+
+And there are too numerous small fixes to otherwise note here ;-)
diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt
index c11bb7d..5428111 100644
--- a/Documentation/blame-options.txt
+++ b/Documentation/blame-options.txt
@@ -41,7 +41,8 @@
 -S <revs-file>::
 	Use revs from revs-file instead of calling linkgit:git-rev-list[1].
 
--p, --porcelain::
+-p::
+--porcelain::
 	Show in a format designed for machine consumption.
 
 --incremental::
@@ -83,5 +84,6 @@
 between files for it to associate those lines with the parent
 commit.
 
--h, --help::
+-h::
+--help::
 	Show help message.
diff --git a/Documentation/cat-texi.perl b/Documentation/cat-texi.perl
index e3d8e9f..dbc133c 100755
--- a/Documentation/cat-texi.perl
+++ b/Documentation/cat-texi.perl
@@ -11,7 +11,7 @@
 	if (s/^\@top (.*)/\@node $1,,,Top/) {
 		push @menu, $1;
 	}
-	s/\(\@pxref{\[URLS\]}\)//;
+	s/\(\@pxref{\[(URLS|REMOTES)\]}\)//;
 	print TMP;
 }
 close TMP;
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 273b358..da2cb3f 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -92,7 +92,7 @@
 
 	# Our diff algorithm
 	[diff]
-		external = "/usr/local/bin/gnu-diff -u"
+		external = /usr/local/bin/diff-wrapper
 		renames = true
 
 	[branch "devel"]
@@ -205,10 +205,13 @@
 handling).
 
 core.ignoreStat::
-	The working copy files are assumed to stay unchanged until you
-	mark them otherwise manually - Git will not detect the file changes
-	by lstat() calls. This is useful on systems where those are very
-	slow, such as Microsoft Windows.  See linkgit:git-update-index[1].
+	If true, commands which modify both the working tree and the index
+	will mark the updated paths with the "assume unchanged" bit in the
+	index. These marked files are then assumed to stay unchanged in the
+	working copy, until you	mark them otherwise manually - Git will not
+	detect the file changes	by lstat() calls. This is useful on systems
+	where those are very slow, such as Microsoft Windows.
+	See linkgit:git-update-index[1].
 	False by default.
 
 core.preferSymlinkRefs::
@@ -234,7 +237,13 @@
 	used in combination with repositories found automatically in
 	a .git directory (i.e. $GIT_DIR is not set).
 	This can be overridden by the GIT_WORK_TREE environment
-	variable and the '--work-tree' command line option.
+	variable and the '--work-tree' command line option. It can be
+	a absolute path or relative path to the directory specified by
+	--git-dir or GIT_DIR.
+	Note: If --git-dir or GIT_DIR are specified but none of
+	--work-tree, GIT_WORK_TREE and core.worktree is specified,
+	the current working directory is regarded as the top directory
+	of your working tree.
 
 core.logAllRefUpdates::
 	Enable the reflog. Updates to a ref <ref> is logged to the file
@@ -261,7 +270,12 @@
 	group-writable). When 'all' (or 'world' or 'everybody'), the
 	repository will be readable by all users, additionally to being
 	group-shareable. When 'umask' (or 'false'), git will use permissions
-	reported by umask(2). See linkgit:git-init[1]. False by default.
+	reported by umask(2). When '0xxx', where '0xxx' is an octal number,
+	files in the repository will have this mode value. '0xxx' will override
+	user's umask value, and thus, users with a safe umask (0077) can use
+	this option. Examples: '0660' is equivalent to 'group'. '0640' is a
+	repository that is group-readable but not group-writable.
+	See linkgit:git-init[1]. False by default.
 
 core.warnAmbiguousRefs::
 	If true, git will warn you if the ref name you passed it is ambiguous
@@ -358,6 +372,14 @@
   does not trigger if the character before such a carriage-return
   is not a whitespace (not enabled by default).
 
+core.fsyncobjectfiles::
+	This boolean will enable 'fsync()' when writing object files.
++
+This is a total waste of time and effort on a filesystem that orders
+data writes properly, but can be useful for filesystems that do not use
+journalling (traditional UNIX filesystems) or that only journal metadata
+and not file contents (OS X's HFS+, or Linux ext3 with "data=writeback").
+
 alias.*::
 	Command aliases for the linkgit:git[1] command wrapper - e.g.
 	after defining "alias.last = cat-file commit HEAD", the invocation
@@ -388,6 +410,21 @@
 	done when the starting point is either a local branch or remote
 	branch. This option defaults to true.
 
+branch.autosetuprebase::
+	When a new branch is created with `git-branch` or `git-checkout`
+	that tracks another branch, this variable tells git to set
+	up pull to rebase instead of merge (see "branch.<name>.rebase").
+	When `never`, rebase is never automatically set to true.
+	When `local`, rebase is set to true for tracked branches of
+	other local branches.
+	When `remote`, rebase is set to true for tracked branches of
+	remote branches.
+	When `always`, rebase will be set to true for all tracking
+	branches.
+	See "branch.autosetupmerge" for details on how to set up a
+	branch to track another branch.
+	This option defaults to never.
+
 branch.<name>.remote::
 	When in branch <name>, it tells `git fetch` which remote to fetch.
 	If this option is not given, `git fetch` defaults to remote "origin".
@@ -497,8 +534,10 @@
 	one of `header` (the header text of the status message),
 	`added` or `updated` (files which are added but not committed),
 	`changed` (files which are changed but not added in the index),
-	or `untracked` (files which are not tracked by git). The values of
-	these variables may be specified as in color.branch.<slot>.
+	`untracked` (files which are not tracked by git), or
+	`nobranch` (the color the 'no branch' warning is shown in, defaulting
+	to red). The values of these variables may be specified as in
+	color.branch.<slot>.
 
 commit.template::
 	Specify a file to use as the template for new commit messages.
@@ -523,9 +562,11 @@
 diff.external::
 	If this config variable is set, diff generation is not
 	performed using the internal diff machinery, but using the
-	given command.  Note: if you want to use an external diff
-	program only on a subset of your files, you might want to
-	use linkgit:gitattributes[5] instead.
+	given command.  Can be overridden with the `GIT_EXTERNAL_DIFF'
+	environment variable.  The command is called with parameters
+	as described under "git Diffs" in linkgit:git[1].  Note: if
+	you want to use an external diff program only on a subset of
+	your files, you	might want to use linkgit:gitattributes[5] instead.
 
 diff.renameLimit::
 	The number of files to consider when performing the copy/rename
@@ -634,11 +675,24 @@
 	Path to a log file where the CVS server interface well... logs
 	various stuff. See linkgit:git-cvsserver[1].
 
+gitcvs.usecrlfattr
+	If true, the server will look up the `crlf` attribute for
+	files to determine the '-k' modes to use. If `crlf` is set,
+	the '-k' mode will be left blank, so cvs clients will
+	treat it as text. If `crlf` is explicitly unset, the file
+	will be set with '-kb' mode, which supresses any newline munging
+	the client might otherwise do. If `crlf` is not specified,
+	then 'gitcvs.allbinary' is used. See linkgit:gitattribute[5].
+
 gitcvs.allbinary::
-	If true, all files are sent to the client in mode '-kb'. This
-	causes the client to treat all files as binary files which suppresses
-	any newline munging it otherwise might do. A work-around for the
-	fact that there is no way yet to set single files to mode '-kb'.
+	This is used if 'gitcvs.usecrlfattr' does not resolve
+	the correct '-kb' mode to use. If true, all
+	unresolved files are sent to the client in
+	mode '-kb'. This causes the client to treat them
+	as binary files, which suppresses any newline munging it
+	otherwise might do. Alternatively, if it is set to "guess",
+	then the contents of the file are examined to decide if
+	it is binary, similar to 'core.autocrlf'.
 
 gitcvs.dbname::
 	Database used by git-cvsserver to cache revision information
@@ -669,11 +723,42 @@
 	linkgit:git-cvsserver[1] for details).  Any non-alphabetic
 	characters will be replaced with underscores.
 
-All gitcvs variables except for 'gitcvs.allbinary' can also be
-specified as 'gitcvs.<access_method>.<varname>' (where 'access_method'
+All gitcvs variables except for 'gitcvs.usecrlfattr' and
+'gitcvs.allbinary' can also be specified as
+'gitcvs.<access_method>.<varname>' (where 'access_method'
 is one of "ext" and "pserver") to make them apply only for the given
 access method.
 
+gui.commitmsgwidth::
+	Defines how wide the commit message window is in the
+	linkgit:git-gui[1]. "75" is the default.
+
+gui.diffcontext::
+	Specifies how many context lines should be used in calls to diff
+	made by the linkgit:git-gui[1]. The default is "5".
+
+gui.matchtrackingbranch::
+	Determines if new branches created with linkgit:git-gui[1] should
+	default to tracking remote branches with matching names or
+	not. Default: "false".
+
+gui.newbranchtemplate::
+	Is used as suggested name when creating new branches using the
+	linkgit:git-gui[1].
+
+gui.pruneduringfetch::
+	"true" if linkgit:git-gui[1] should prune tracking branches when
+	performing a fetch. The default value is "false".
+
+gui.trustmtime::
+	Determines if linkgit:git-gui[1] should trust the file modification
+	timestamp or not. By default the timestamps are not trusted.
+
+gui.spellingdictionary::
+	Specifies the dictionary used for spell checking commit messages in
+	the linkgit:git-gui[1]. When set to "none" spell checking is turned
+	off.
+
 help.browser::
 	Specify the browser that will be used to display help in the
 	'web' format. See linkgit:git-help[1].
@@ -759,6 +844,12 @@
 	The port number to bind the gitweb httpd to. See
 	linkgit:git-instaweb[1].
 
+log.date::
+	Set default date-time mode for the log command. Setting log.date
+	value is similar to using git log's --date option. The value is one of
+	following alternatives: {relative,local,default,iso,rfc,short}.
+	See linkgit:git-log[1].
+
 log.showroot::
 	If true, the initial commit will be shown as a big creation event.
 	This is equivalent to a diff against an empty tree.
@@ -769,37 +860,16 @@
 	Specify the programs that may be used to display help in the
 	'man' format. See linkgit:git-help[1].
 
-merge.summary::
-	Whether to include summaries of merged commits in newly created
-	merge commit messages. False by default.
+include::merge-config.txt[]
 
-merge.tool::
-	Controls which merge resolution program is used by
-	linkgit:git-mergetool[1].  Valid built-in values are: "kdiff3",
-	"tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and
-	"opendiff".  Any other value is treated is custom merge tool
-	and there must be a corresponing mergetool.<tool>.cmd option.
+man.<tool>.cmd::
+	Specify the command to invoke the specified man viewer. The
+	specified command is evaluated in shell with the man page
+	passed as argument. (See linkgit:git-help[1].)
 
-merge.verbosity::
-	Controls the amount of output shown by the recursive merge
-	strategy.  Level 0 outputs nothing except a final error
-	message if conflicts were detected. Level 1 outputs only
-	conflicts, 2 outputs conflicts and file changes.  Level 5 and
-	above outputs debugging information.  The default is level 2.
-	Can be overridden by 'GIT_MERGE_VERBOSITY' environment variable.
-
-merge.<driver>.name::
-	Defines a human readable name for a custom low-level
-	merge driver.  See linkgit:gitattributes[5] for details.
-
-merge.<driver>.driver::
-	Defines the command that implements a custom low-level
-	merge driver.  See linkgit:gitattributes[5] for details.
-
-merge.<driver>.recursive::
-	Names a low-level merge driver to be used when
-	performing an internal merge between common ancestors.
-	See linkgit:gitattributes[5] for details.
+man.<tool>.path::
+	Override the path for the given tool that may be used to
+	display help in the 'man' format. See linkgit:git-help[1].
 
 mergetool.<tool>.path::
 	Override the path for the given tool.  This is useful in case
@@ -911,6 +981,10 @@
 	The default set of "refspec" for linkgit:git-push[1]. See
 	linkgit:git-push[1].
 
+remote.<name>.mirror::
+	If true, pushing to this remote will automatically behave
+	as if the `\--mirror` option was given on the command line.
+
 remote.<name>.skipDefaultUpdate::
 	If true, this remote will be skipped by default when updating
 	using the update subcommand of linkgit:git-remote[1].
@@ -992,6 +1066,12 @@
 	The configuration variables in the 'imap' section are described
 	in linkgit:git-imap-send[1].
 
+receive.fsckObjects::
+	If it is set to true, git-receive-pack will check all received
+	objects. It will abort in the case of a malformed object or a
+	broken link. The result of an abort are only dangling objects.
+	Defaults to false.
+
 receive.unpackLimit::
 	If the number of objects received in a push is below this
 	limit then the objects will be unpacked into loose object
diff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt
index 029c5f2..517e1eb 100644
--- a/Documentation/diff-generate-patch.txt
+++ b/Documentation/diff-generate-patch.txt
@@ -96,7 +96,7 @@
 +
 or like this (when '--cc' option is used):
 
-       diff --c file
+       diff --cc file
 
 2.   It is followed by one or more extended header lines
      (this example shows a merge with two parents):
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 13234fa..5721548 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -228,6 +228,9 @@
 --no-ext-diff::
 	Disallow external diff drivers.
 
+--ignore-submodules::
+	Ignore changes to submodules in the diff generation.
+
 --src-prefix=<prefix>::
 	Show the given source prefix instead of "a/".
 
@@ -238,4 +241,4 @@
 	Do not show any source or destination prefix.
 
 For more detailed explanation on these common options, see also
-link:diffcore.html[diffcore documentation].
+linkgit:gitdiffcore[7][diffcore documentation].
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index b675911..85c8718 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -1,22 +1,26 @@
--q, \--quiet::
+-q::
+--quiet::
 	Pass --quiet to git-fetch-pack and silence any other internally
 	used programs.
 
--v, \--verbose::
+-v::
+--verbose::
 	Be verbose.
 
--a, \--append::
+-a::
+--append::
 	Append ref names and object names of fetched refs to the
 	existing contents of `.git/FETCH_HEAD`.  Without this
 	option old data in `.git/FETCH_HEAD` will be overwritten.
 
-\--upload-pack <upload-pack>::
+--upload-pack <upload-pack>::
 	When given, and the repository to fetch from is handled
 	by 'git-fetch-pack', '--exec=<upload-pack>' is passed to
 	the command to specify non-default path for the command
 	run on the other end.
 
--f, \--force::
+-f::
+--force::
 	When `git-fetch` is used with `<rbranch>:<lbranch>`
 	refspec, it refuses to update the local branch
 	`<lbranch>` unless the remote branch `<rbranch>` it
@@ -24,16 +28,18 @@
 	overrides that check.
 
 ifdef::git-pull[]
-\--no-tags::
+--no-tags::
 endif::git-pull[]
 ifndef::git-pull[]
--n, \--no-tags::
+-n::
+--no-tags::
 endif::git-pull[]
 	By default, tags that point at objects that are downloaded
 	from the remote repository are fetched and stored locally.
 	This option disables this automatic tag following.
 
--t, \--tags::
+-t::
+--tags::
 	Most of the tags are fetched automatically as branch
 	heads are downloaded, but tags that do not point at
 	objects reachable from the branch heads that are being
@@ -41,10 +47,12 @@
 	flag lets all tags and their associated objects be
 	downloaded.
 
--k, \--keep::
+-k::
+--keep::
 	Keep downloaded pack.
 
--u, \--update-head-ok::
+-u::
+--update-head-ok::
 	By default `git-fetch` refuses to update the head which
 	corresponds to the current branch.  This flag disables the
 	check.  This is purely for the internal use for `git-pull`
@@ -52,7 +60,7 @@
 	implementing your own Porcelain you are not supposed to
 	use it.
 
-\--depth=<depth>::
+--depth=<depth>::
 	Deepen the history of a 'shallow' repository created by
 	`git clone` with `--depth=<depth>` option (see linkgit:git-clone[1])
 	by the specified number of commits.
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index e2389e3..815864c 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -8,8 +8,9 @@
 SYNOPSIS
 --------
 [verse]
-'git-add' [-n] [-v] [-f] [--interactive | -i] [--patch | -p] [-u] [--refresh]
-          [--] <filepattern>...
+'git-add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
+	  [--update | -u] [--refresh] [--ignore-errors] [--]
+	  <filepattern>...
 
 DESCRIPTION
 -----------
@@ -50,27 +51,33 @@
 	and `dir/file2`) can be given to add all files in the
 	directory, recursively.
 
--n, \--dry-run::
+-n::
+--dry-run::
         Don't actually add the file(s), just show if they exist.
 
--v, \--verbose::
+-v::
+--verbose::
         Be verbose.
 
 -f::
+--force::
 	Allow adding otherwise ignored files.
 
--i, \--interactive::
+-i::
+--interactive::
 	Add modified contents in the working tree interactively to
 	the index. Optional path arguments may be supplied to limit
 	operation to a subset of the working tree. See ``Interactive
 	mode'' for details.
 
--p, \--patch::
+-p::
+--patch::
 	Similar to Interactive mode but the initial command loop is
 	bypassed and the 'patch' subcommand is invoked using each of
 	the specified filepatterns before exiting.
 
 -u::
+--update::
 	Update only files that git already knows about, staging modified
 	content for commit and marking deleted files for removal. This
 	is similar
@@ -79,10 +86,15 @@
 	command line. If no paths are specified, all tracked files in the
 	current directory and its subdirectories are updated.
 
-\--refresh::
+--refresh::
 	Don't add the file(s), but only refresh their stat()
 	information in the index.
 
+--ignore-errors::
+	If some files could not be added because of errors indexing
+	them, do not abort the operation, but continue adding the
+	others. The command shall still exit with non-zero status.
+
 \--::
 	This option can be used to separate command-line options from
 	the list of files, (useful when filenames might be mistaken
@@ -95,26 +107,32 @@
 The optional configuration variable 'core.excludesfile' indicates a path to a
 file containing patterns of file names to exclude from git-add, similar to
 $GIT_DIR/info/exclude.  Patterns in the exclude file are used in addition to
-those in info/exclude.  See link:repository-layout.html[repository layout].
+those in info/exclude.  See linkgit:gitrepository-layout[5][repository layout].
 
 
 EXAMPLES
 --------
-git-add Documentation/\\*.txt::
 
-	Adds content from all `\*.txt` files under `Documentation`
-	directory and its subdirectories.
+* Adds content from all `\*.txt` files under `Documentation` directory
+and its subdirectories:
++
+------------
+$ git add Documentation/\\*.txt
+------------
 +
 Note that the asterisk `\*` is quoted from the shell in this
 example; this lets the command to include the files from
 subdirectories of `Documentation/` directory.
 
-git-add git-*.sh::
-
-	Considers adding content from all git-*.sh scripts.
-	Because this example lets shell expand the asterisk
-	(i.e. you are listing the files explicitly), it does not
-	consider `subdir/git-foo.sh`.
+* Considers adding content from all git-*.sh scripts:
++
+------------
+$ git add git-*.sh
+------------
++
+Because this example lets shell expand the asterisk (i.e. you are
+listing the files explicitly), it does not consider
+`subdir/git-foo.sh`.
 
 Interactive mode
 ----------------
@@ -169,8 +187,9 @@
    "Update>>".  When the prompt ends with double '>>', you can
    make more than one selection, concatenated with whitespace or
    comma.  Also you can say ranges.  E.g. "2-5 7,9" to choose
-   2,3,4,5,7,9 from the list.  You can say '*' to choose
-   everything.
+   2,3,4,5,7,9 from the list.  If the second number in a range is
+   omitted, all remaining patches are taken.  E.g. "7-" to choose
+   7,8,9 from the list.  You can say '*' to choose everything.
 +
 What you chose are then highlighted with '*',
 like this:
@@ -235,7 +254,7 @@
 used to work this limitation around to some degree, but backslash,
 double-quote and control characters will still have problems.
 
-See Also
+SEE ALSO
 --------
 linkgit:git-status[1]
 linkgit:git-rm[1]
@@ -254,4 +273,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 2387a8d..5622971 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -28,14 +28,17 @@
 	supply this argument, reads from the standard input. If you supply
 	directories, they'll be treated as Maildirs.
 
--s, --signoff::
+-s::
+--signoff::
 	Add `Signed-off-by:` line to the commit message, using
 	the committer identity of yourself.
 
--k, --keep::
+-k::
+--keep::
 	Pass `-k` flag to `git-mailinfo` (see linkgit:git-mailinfo[1]).
 
--u, --utf8::
+-u::
+--utf8::
 	Pass `-u` flag to `git-mailinfo` (see linkgit:git-mailinfo[1]).
 	The proposed commit log message taken from the e-mail
 	is re-coded into UTF-8 encoding (configuration variable
@@ -49,13 +52,15 @@
 	Pass `-n` flag to `git-mailinfo` (see
 	linkgit:git-mailinfo[1]).
 
--3, --3way::
+-3::
+--3way::
 	When the patch does not apply cleanly, fall back on
 	3-way merge, if the patch records the identity of blobs
 	it is supposed to apply to, and we have those blobs
 	available locally.
 
--b, --binary::
+-b::
+--binary::
 	Pass `--allow-binary-replacement` flag to `git-apply`
 	(see linkgit:git-apply[1]).
 
@@ -64,19 +69,22 @@
 	program that applies
 	the patch.
 
--C<n>, -p<n>::
+-C<n>::
+-p<n>::
 	These flags are passed to the `git-apply` (see linkgit:git-apply[1])
 	program that applies
 	the patch.
 
--i, --interactive::
+-i::
+--interactive::
 	Run interactively.
 
 --skip::
 	Skip the current patch.  This is only meaningful when
 	restarting an aborted patch.
 
--r, --resolved::
+-r::
+--resolved::
 	After a patch failure (e.g. attempting to apply
 	conflicting patch), the user has applied it by hand and
 	the index file stores the result of the application.
@@ -145,7 +153,7 @@
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -153,4 +161,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-annotate.txt b/Documentation/git-annotate.txt
index 45a6a72..da15379 100644
--- a/Documentation/git-annotate.txt
+++ b/Documentation/git-annotate.txt
@@ -28,4 +28,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt
index 2dec2ec..c834763 100644
--- a/Documentation/git-apply.txt
+++ b/Documentation/git-apply.txt
@@ -73,7 +73,8 @@
 When a pure mode change is encountered (which has no index information),
 the information is read from the current index instead.
 
--R, --reverse::
+-R::
+--reverse::
 	Apply the patch in reverse.
 
 --reject::
@@ -124,7 +125,8 @@
 	the result with this option, which would apply the
 	deletion part but not addition part.
 
---allow-binary-replacement, --binary::
+--allow-binary-replacement::
+--binary::
 	Historically we did not allow binary patch applied
 	without an explicit permission from the user, and this
 	flag was the way to do so.  Currently we always allow binary
@@ -169,7 +171,8 @@
 	correctly. This option adds support for applying such patches by
 	working around this bug.
 
--v, --verbose::
+-v::
+--verbose::
 	Report progress to stderr. By default, only a message about the
 	current patch being applied will be printed. This option will cause
 	additional information to be reported.
@@ -206,4 +209,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-archimport.txt b/Documentation/git-archimport.txt
index bd20fd8..603117c 100644
--- a/Documentation/git-archimport.txt
+++ b/Documentation/git-archimport.txt
@@ -117,4 +117,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index d3eaa16..9b5f3ae 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -36,10 +36,12 @@
 	Format of the resulting archive: 'tar' or 'zip'.  The default
 	is 'tar'.
 
---list, -l::
+-l::
+--list::
 	Show all available formats.
 
---verbose, -v::
+-v::
+--verbose::
 	Report progress to stderr.
 
 --prefix=<prefix>/::
@@ -118,4 +120,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt
index 0855b98..3ca0d33 100644
--- a/Documentation/git-bisect.txt
+++ b/Documentation/git-bisect.txt
@@ -15,6 +15,7 @@
 The command takes various subcommands, and different options depending
 on the subcommand:
 
+ git bisect help
  git bisect start [<bad> [<good>...]] [--] [<paths>...]
  git bisect bad [<rev>]
  git bisect good [<rev>...]
@@ -29,6 +30,12 @@
 binary search process to find which change introduced a bug, given an
 old "good" commit object name and a later "bad" commit object name.
 
+Getting help
+~~~~~~~~~~~~
+
+Use "git bisect" to get a short usage description, and "git bisect
+help" or "git bisect -h" to get a long usage description.
+
 Basic bisect commands: start, bad, good
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -78,10 +85,9 @@
 $ git bisect reset
 ------------------------------------------------
 
-to get back to the original branch, instead of being in one of the
-bisection branches ("git bisect start" will do that for you too,
-actually: it will reset the bisection state, and before it does that
-it checks that you're not using some old bisection branch).
+to get back to the original branch, instead of being on the bisection
+commit ("git bisect start" will do that for you too, actually: it will
+reset the bisection state).
 
 Bisect visualize
 ~~~~~~~~~~~~~~~~
@@ -217,6 +223,55 @@
 the status of the real test to let "git bisect run" command loop to
 know the outcome.
 
+EXAMPLES
+--------
+
+* Automatically bisect a broken build between v1.2 and HEAD:
++
+------------
+$ git bisect start HEAD v1.2 --      # HEAD is bad, v1.2 is good
+$ git bisect run make                # "make" builds the app
+------------
+
+* Automatically bisect a broken test suite:
++
+------------
+$ cat ~/test.sh
+#!/bin/sh
+make || exit 125                   # this "skip"s broken builds
+make test                          # "make test" runs the test suite
+$ git bisect start v1.3 v1.1 --    # v1.3 is bad, v1.1 is good
+$ git bisect run ~/test.sh
+------------
++
+Here we use a "test.sh" custom script. In this script, if "make"
+fails, we "skip" the current commit.
++
+It's safer to use a custom script outside the repo to prevent
+interactions between the bisect, make and test processes and the
+script.
++
+And "make test" should "exit 0", if the test suite passes, and
+"exit 1" (for example) otherwise.
+
+* Automatically bisect a broken test case:
++
+------------
+$ cat ~/test.sh
+#!/bin/sh
+make || exit 125                     # this "skip"s broken builds
+~/check_test_case.sh                 # does the test case passes ?
+$ git bisect start HEAD HEAD~10 --   # culprit is among the last 10
+$ git bisect run ~/test.sh
+------------
++
+Here "check_test_case.sh" should "exit 0", if the test case passes,
+and "exit 1" (for example) otherwise.
++
+It's safer if both "test.sh" and "check_test_case.sh" scripts are
+outside the repo to prevent interactions between the bisect, make and
+test processes and the scripts.
+
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>
@@ -227,4 +282,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt
index 14163b6..0e0196e 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.txt
@@ -52,12 +52,14 @@
 	a certain threshold for git-blame to consider those lines
 	of code to have been moved.
 
--f, --show-name::
+-f::
+--show-name::
 	Show filename in the original commit.  By default
 	filename is shown if there is any line that came from a
 	file with different name, due to rename detection.
 
--n, --show-number::
+-n::
+--show-number::
 	Show line number in the original commit (Default: off).
 
 -s::
@@ -188,8 +190,8 @@
 
 AUTHOR
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 6f07a17..39cd5d9 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -8,7 +8,7 @@
 SYNOPSIS
 --------
 [verse]
-'git-branch' [--color | --no-color] [-r | -a]
+'git-branch' [--color | --no-color] [-r | -a] [--merged | --no-merged]
 	   [-v [--abbrev=<length> | --no-abbrev]]
 	   [--contains <commit>]
 'git-branch' [--track | --no-track] [-l] [-f] <branchname> [<start-point>]
@@ -24,6 +24,8 @@
 With `--contains <commit>`, shows only the branches that
 contains the named commit (in other words, the branches whose
 tip commits are descendant of the named commit).
+With `--merged`, only branches merged into HEAD will be listed, and
+with `--no-merged` only branches not merged into HEAD will be listed.
 
 In its second form, a new branch named <branchname> will be created.
 It will start out with a head equal to the one given as <start-point>.
@@ -93,7 +95,8 @@
 -a::
 	List both remote-tracking branches and local branches.
 
--v, --verbose::
+-v::
+--verbose::
 	Show sha1 and commit subject line for each head.
 
 --abbrev=<length>::
@@ -118,6 +121,15 @@
 --no-track::
 	Ignore the branch.autosetupmerge configuration variable.
 
+--contains <commit>::
+	Only list branches which contain the specified commit.
+
+--merged::
+	Only list branches which are fully contained by HEAD.
+
+--no-merged::
+	Do not list branches which are fully contained by HEAD.
+
 <branchname>::
 	The name of the branch to create or delete.
 	The new branch name must pass all checks defined by
@@ -175,10 +187,22 @@
 easier to use the git checkout command with its `-b` option to create
 a branch and check it out with a single command.
 
+The options `--contains`, `--merged` and `--no-merged` serves three related
+but different purposes:
+
+- `--contains <commit>` is used to find all branches which will need
+  special attention if <commit> were to be rebased or amended, since those
+  branches contain the specified <commit>.
+
+- `--merged` is used to find all branches which can be safely deleted,
+  since those branches are fully contained by HEAD.
+
+- `--no-merged` is used to find branches which are candidates for merging
+  into HEAD, since those branches are not fully contained by HEAD.
 
 Author
 ------
-Written by Linus Torvalds <torvalds@osdl.org> and Junio C Hamano <junkio@cox.net>
+Written by Linus Torvalds <torvalds@osdl.org> and Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -186,4 +210,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt
index 18330cd..f6a0612 100644
--- a/Documentation/git-bundle.txt
+++ b/Documentation/git-bundle.txt
@@ -171,4 +171,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index df42cb1..f58013c 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -8,13 +8,18 @@
 
 SYNOPSIS
 --------
+[verse]
 'git-cat-file' [-t | -s | -e | -p | <type>] <object>
+'git-cat-file' [--batch | --batch-check] < <list-of-objects>
 
 DESCRIPTION
 -----------
-Provides content or type of objects in the repository. The type
-is required unless '-t' or '-p' is used to find the object type,
-or '-s' is used to find the object size.
+In the first form, provides content or type of objects in the repository. The
+type is required unless '-t' or '-p' is used to find the object type, or '-s'
+is used to find the object size.
+
+In the second form, a list of object (separated by LFs) is provided on stdin,
+and the SHA1, type, and size of each object is printed on stdout.
 
 OPTIONS
 -------
@@ -46,6 +51,14 @@
 	or to ask for a "blob" with <object> being a tag object that
 	points at it.
 
+--batch::
+	Print the SHA1, type, size, and contents of each object provided on
+	stdin. May not be combined with any other options or arguments.
+
+--batch-check::
+	Print the SHA1, type, and size of each object provided on stdin. May not be
+	combined with any other options or arguments.
+
 OUTPUT
 ------
 If '-t' is specified, one of the <type>.
@@ -56,9 +69,30 @@
 
 If '-p' is specified, the contents of <object> are pretty-printed.
 
-Otherwise the raw (though uncompressed) contents of the <object> will
-be returned.
+If <type> is specified, the raw (though uncompressed) contents of the <object>
+will be returned.
 
+If '--batch' is specified, output of the following form is printed for each
+object specified on stdin:
+
+------------
+<sha1> SP <type> SP <size> LF
+<contents> LF
+------------
+
+If '--batch-check' is specified, output of the following form is printed for
+each object specified fon stdin:
+
+------------
+<sha1> SP <type> SP <size> LF
+------------
+
+For both '--batch' and '--batch-check', output of the following form is printed
+for each object specified on stdin that does not exist in the repository:
+
+------------
+<object> SP missing LF
+------------
 
 Author
 ------
@@ -70,4 +104,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-check-attr.txt b/Documentation/git-check-attr.txt
index 290f10f..f8e1bd5 100644
--- a/Documentation/git-check-attr.txt
+++ b/Documentation/git-check-attr.txt
@@ -30,7 +30,7 @@
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -38,4 +38,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt
index a676880..c560c0a 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -52,4 +52,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-checkout-index.txt b/Documentation/git-checkout-index.txt
index cbbb0b5..676203b 100644
--- a/Documentation/git-checkout-index.txt
+++ b/Documentation/git-checkout-index.txt
@@ -22,21 +22,26 @@
 
 OPTIONS
 -------
--u|--index::
+-u::
+--index::
 	update stat information for the checked out entries in
 	the index file.
 
--q|--quiet::
+-q::
+--quiet::
 	be quiet if files exist or are not in the index
 
--f|--force::
+-f::
+--force::
 	forces overwrite of existing files
 
--a|--all::
+-a::
+--all::
 	checks out all files in the index.  Cannot be used
 	together with explicit filenames.
 
--n|--no-create::
+-n::
+--no-create::
 	Don't checkout new files, only refresh files already checked
 	out.
 
@@ -181,4 +186,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index e11cddb..3ad9760 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -47,6 +47,7 @@
 	by linkgit:git-check-ref-format[1].  Some of these checks
 	may restrict the characters allowed in a branch name.
 
+-t::
 --track::
 	When creating a new branch, set up configuration so that git-pull
 	will automatically retrieve data from the start point, which must be
@@ -215,4 +216,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index f0beb41..44e7749 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -7,7 +7,7 @@
 
 SYNOPSIS
 --------
-'git-cherry-pick' [--edit] [-n] [-m parent-number] [-x] <commit>
+'git-cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] <commit>
 
 DESCRIPTION
 -----------
@@ -22,7 +22,8 @@
 	For a more complete list of ways to spell commits, see
 	"SPECIFYING REVISIONS" section in linkgit:git-rev-parse[1].
 
--e|--edit::
+-e::
+--edit::
 	With this option, `git-cherry-pick` will let you edit the commit
 	message prior to committing.
 
@@ -44,30 +45,36 @@
 	described above, and `-r` was to disable it.  Now the
 	default is not to do `-x` so this option is a no-op.
 
--m parent-number|--mainline parent-number::
+-m parent-number::
+--mainline parent-number::
 	Usually you cannot cherry-pick a merge because you do not know which
 	side of the merge should be considered the mainline.  This
 	option specifies the parent number (starting from 1) of
 	the mainline and allows cherry-pick to replay the change
 	relative to the specified parent.
 
--n|--no-commit::
+-n::
+--no-commit::
 	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::
+	Add Signed-off-by line at the end of the commit message.
 
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -75,4 +82,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-cherry.txt b/Documentation/git-cherry.txt
index b0468aa..9126011 100644
--- a/Documentation/git-cherry.txt
+++ b/Documentation/git-cherry.txt
@@ -13,6 +13,8 @@
 -----------
 The changeset (or "diff") of each commit between the fork-point and <head>
 is compared against each commit between the fork-point and <upstream>.
+The commits are compared with their 'patch id', obtained from linkgit:git-patch-id[1]
+program.
 
 Every commit that doesn't exist in the <upstream> branch
 has its id (sha1) reported, prefixed by a symbol.  The ones that have
@@ -56,9 +58,13 @@
 <limit>::
 	Do not report commits up to (and including) limit.
 
+SEE ALSO
+--------
+linkgit:git-patch-id[1]
+
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -66,4 +72,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-citool.txt b/Documentation/git-citool.txt
index aca1d75..09108d0 100644
--- a/Documentation/git-citool.txt
+++ b/Documentation/git-citool.txt
@@ -29,4 +29,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt
index 5e9da03..37a82ee 100644
--- a/Documentation/git-clean.txt
+++ b/Documentation/git-clean.txt
@@ -30,9 +30,11 @@
 	git-clean will refuse to run unless given -f or -n.
 
 -n::
+--dry-run::
 	Don't actually remove anything, just show what would be done.
 
 -q::
+--quiet::
 	Be quiet, only report errors, but not the files that are
 	successfully removed.
 
@@ -54,4 +56,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 9b56442..7973e6a 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -205,4 +205,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt
index 170803a..728c2fa 100644
--- a/Documentation/git-commit-tree.txt
+++ b/Documentation/git-commit-tree.txt
@@ -88,7 +88,7 @@
 
 include::i18n.txt[]
 
-See Also
+SEE ALSO
 --------
 linkgit:git-write-tree[1]
 
@@ -103,4 +103,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index 4bb51cc..861ce93 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -8,9 +8,9 @@
 SYNOPSIS
 --------
 [verse]
-'git-commit' [-a | --interactive] [-s] [-v] [-u]
-	   [(-c | -C) <commit> | -F <file> | -m <msg> | --amend]
-	   [--allow-empty] [--no-verify] [-e] [--author <author>]
+'git-commit' [-a | --interactive] [-s] [-v] [-u] [--amend]
+	   [(-c | -C) <commit>] [-F <file> | -m <msg>]
+	   [--allow-empty] [--no-verify] [-e] [--author=<author>]
 	   [--cleanup=<mode>] [--] [[-i | -o ]<file>...]
 
 DESCRIPTION
@@ -52,42 +52,52 @@
 
 OPTIONS
 -------
--a|--all::
+-a::
+--all::
 	Tell the command to automatically stage files that have
 	been modified and deleted, but new files you have not
 	told git about are not affected.
 
--c or -C <commit>::
-	Take existing commit object, and reuse the log message
+-C <commit>::
+--reuse-message=<commit>::
+	Take an existing commit object, and reuse the log message
 	and the authorship information (including the timestamp)
-	when creating the commit.  With '-C', the editor is not
-	invoked; with '-c' the user can further edit the commit
-	message.
+	when creating the commit.
+
+-c <commit>::
+--reedit-message=<commit>::
+	Like '-C', but with '-c' the editor is invoked, so that
+	the user can further edit the commit message.
 
 -F <file>::
+--file=<file>::
 	Take the commit message from the given file.  Use '-' to
 	read the message from the standard input.
 
---author <author>::
+--author=<author>::
 	Override the author name used in the commit.  Use
 	`A U Thor <author@example.com>` format.
 
--m <msg>|--message=<msg>::
+-m <msg>::
+--message=<msg>::
 	Use the given <msg> as the commit message.
 
--t <file>|--template=<file>::
+-t <file>::
+--template=<file>::
 	Use the contents of the given file as the initial version
 	of the commit message. The editor is invoked and you can
 	make subsequent changes. If a message is specified using
 	the `-m` or `-F` options, this option has no effect. This
 	overrides the `commit.template` configuration variable.
 
--s|--signoff::
+-s::
+--signoff::
 	Add Signed-off-by line at the end of the commit message.
 
+-n::
 --no-verify::
 	This option bypasses the pre-commit and commit-msg hooks.
-	See also link:hooks.html[hooks].
+	See also linkgit:githooks[5][hooks].
 
 --allow-empty::
 	Usually recording a commit that has the exact same tree as its
@@ -105,14 +115,14 @@
 	'whitespace' removes just leading/trailing whitespace lines
 	and 'strip' removes both whitespace and commentary.
 
--e|--edit::
+-e::
+--edit::
 	The message taken from file with `-F`, command line with
 	`-m`, and from file with `-C` are usually used as the
 	commit log message unmodified.  This option lets you
 	further edit the message taken from these sources.
 
 --amend::
-
 	Used to amend the tip of the current branch. Prepare the tree
 	object you would want to replace the latest commit as usual
 	(this includes the usual -i/-o and explicit paths), and the
@@ -133,13 +143,15 @@
 but can be used to amend a merge commit.
 --
 
--i|--include::
+-i::
+--include::
 	Before making a commit out of staged contents so far,
 	stage the contents of paths given on the command line
 	as well.  This is usually not what you want unless you
 	are concluding a conflicted merge.
 
--o|--only::
+-o::
+--only::
 	Make a commit only from the paths specified on the
 	command line, disregarding any contents that have been
 	staged so far. This is the default mode of operation of
@@ -150,20 +162,23 @@
 	the last commit without committing changes that have
 	already been staged.
 
--u|--untracked-files::
+-u::
+--untracked-files::
 	Show all untracked files, also those in uninteresting
 	directories, in the "Untracked files:" section of commit
 	message template.  Without this option only its name and
 	a trailing slash are displayed for each untracked
 	directory.
 
--v|--verbose::
+-v::
+--verbose::
 	Show unified diff between the HEAD commit and what
 	would be committed at the bottom of the commit message
 	template.  Note that this diff output doesn't have its
 	lines prefixed with '#'.
 
--q|--quiet::
+-q::
+--quiet::
 	Suppress commit summary message.
 
 \--::
@@ -292,7 +307,7 @@
 HOOKS
 -----
 This command can run `commit-msg`, `prepare-commit-msg`, `pre-commit`,
-and `post-commit` hooks.  See link:hooks.html[hooks] for more
+and `post-commit` hooks.  See linkgit:githooks[5][hooks] for more
 information.
 
 
@@ -307,9 +322,9 @@
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org> and
-Junio C Hamano <junkio@cox.net>
+Junio C Hamano <gitster@pobox.com>
 
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index fa16171..b0f20e2 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -101,7 +101,8 @@
 +
 See also <<FILES>>.
 
--f config-file, --file config-file::
+-f config-file::
+--file config-file::
 	Use the given config file instead of the one specified by GIT_CONFIG.
 
 --remove-section::
@@ -116,7 +117,8 @@
 --unset-all::
 	Remove all lines matching the key from config file.
 
--l, --list::
+-l::
+--list::
 	List all variables set in config file.
 
 --bool::
@@ -128,7 +130,8 @@
 	in the config file will cause the value to be multiplied
 	by 1024, 1048576, or 1073741824 prior to output.
 
--z, --null::
+-z::
+--null::
 	For all options that output values and/or keys, always
 	end values with the null character (instead of a
 	newline). Use newline instead as a delimiter between
@@ -144,6 +147,8 @@
 	"auto".  If `stdout-is-tty` is missing, then checks the standard
 	output of the command itself, and exits with status 0 if color
 	is to be used, or exits with status 1 otherwise.
+	When the color setting for `name` is undefined, the command uses
+	`color.ui` as fallback.
 
 --get-color name default::
 
@@ -226,7 +231,7 @@
 
 	; Our diff algorithm
 	[diff]
-		external = "/usr/local/bin/gnu-diff -u"
+		external = /usr/local/bin/diff-wrapper
 		renames = true
 
 	; Proxy settings
@@ -332,4 +337,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-count-objects.txt b/Documentation/git-count-objects.txt
index 7fb08e9..4a9dcd7 100644
--- a/Documentation/git-count-objects.txt
+++ b/Documentation/git-count-objects.txt
@@ -18,6 +18,7 @@
 OPTIONS
 -------
 -v::
+--verbose::
 	In addition to the number of loose objects and disk
 	space consumed, it reports the number of in-pack
 	objects, number of packs, and number of objects that can be
@@ -26,7 +27,7 @@
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -34,4 +35,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-cvsexportcommit.txt b/Documentation/git-cvsexportcommit.txt
index 9a47b4c..5fa91e5 100644
--- a/Documentation/git-cvsexportcommit.txt
+++ b/Documentation/git-cvsexportcommit.txt
@@ -8,7 +8,7 @@
 
 SYNOPSIS
 --------
-'git-cvsexportcommit' [-h] [-u] [-v] [-c] [-P] [-p] [-a] [-d cvsroot] [-w cvsworkdir] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
+'git-cvsexportcommit' [-h] [-u] [-v] [-c] [-P] [-p] [-a] [-d cvsroot] [-w cvsworkdir] [-W] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
 
 
 DESCRIPTION
@@ -65,11 +65,22 @@
 -w::
 	Specify the location of the CVS checkout to use for the export. This
 	option does not require GIT_DIR to be set before execution if the
-	current directory is within a git repository.
+	current directory is within a git repository.  The default is the
+	value of 'cvsexportcommit.cvsdir'.
+
+-W::
+	Tell cvsexportcommit that the current working directory is not only
+	a Git checkout, but also the CVS checkout.  Therefore, Git will
+	reset the working directory to the parent commit before proceeding.
 
 -v::
 	Verbose.
 
+CONFIGURATION
+-------------
+cvsexportcommit.cvsdir::
+	The default location of the CVS checkout to use for the export.
+
 EXAMPLES
 --------
 
@@ -106,4 +117,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt
index 58eefd4..93b7d2d 100644
--- a/Documentation/git-cvsimport.txt
+++ b/Documentation/git-cvsimport.txt
@@ -31,6 +31,12 @@
 any CVS branches, yourself.  It is advisable to specify a named remote via
 -r to separate and protect the incoming branches.
 
+If you intend to set up a shared public repository that all developers can
+read/write, or if you want to use linkgit:git-cvsserver[1], then you
+probably want to make a bare clone of the imported repository,
+and use the clone as the shared repository.
+See linkgit:gitcvs-migration[7].
+
 
 OPTIONS
 -------
@@ -170,4 +176,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt
index b110671..19da87e 100644
--- a/Documentation/git-cvsserver.txt
+++ b/Documentation/git-cvsserver.txt
@@ -41,10 +41,13 @@
 Don't check for `gitcvs.enabled` in config. You also have to specify a list
 of allowed directories (see below) if you want to use this option.
 
---version, -V::
+-V::
+--version::
 Print version information and exit
 
---help, -h, -H::
+-h::
+-H::
+--help::
 Print usage information and exit
 
 <directory>::
@@ -130,6 +133,9 @@
 <<dbbackend,Database Backend>>. If you want to offer write access over
 SSH, the users of course also need write access to the git repository itself.
 
+You also need to ensure that each repository is "bare" (without a git index
+file) for `cvs commit` to work. See linkgit:gitcvs-migration[7].
+
 [[configaccessmethod]]
 All configuration variables can also be overridden for a specific method of
 access. Valid method names are "ext" (for SSH access) and "pserver". The
@@ -301,11 +307,33 @@
 Legacy monitoring operations are not supported (edit, watch and related).
 Exports and tagging (tags and branches) are not supported at this stage.
 
-The server should set the '-k' mode to binary when relevant, however,
-this is not really implemented yet. For now, you can force the server
-to set '-kb' for all files by setting the `gitcvs.allbinary` config
-variable. In proper GIT tradition, the contents of the files are
-always respected. No keyword expansion or newline munging is supported.
+CRLF Line Ending Conversions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+By default the server leaves the '-k' mode blank for all files,
+which causes the cvs client to treat them as a text files, subject
+to crlf conversion on some platforms.
+
+You can make the server use `crlf` attributes to set the '-k' modes
+for files by setting the `gitcvs.usecrlfattr` config variable.
+In this case, if `crlf` is explicitly unset ('-crlf'), then the
+server will set '-kb' mode for binary files. If `crlf` is set,
+then the '-k' mode will explicitly be left blank.  See
+also linkgit:gitattributes[5] for more information about the `crlf`
+attribute.
+
+Alternatively, if `gitcvs.usecrlfattr` config is not enabled
+or if the `crlf` attribute is unspecified for a filename, then
+the server uses the `gitcvs.allbinary` config for the default setting.
+If `gitcvs.allbinary` is set, then file not otherwise
+specified will default to '-kb' mode. Otherwise the '-k' mode
+is left blank. But if `gitcvs.allbinary` is set to "guess", then
+the correct '-k' mode will be guessed based on the contents of
+the file.
+
+For best consistency with cvs, it is probably best to override the
+defaults by setting `gitcvs.usecrlfattr` to true,
+and `gitcvs.allbinary` to "guess".
 
 Dependencies
 ------------
@@ -330,4 +358,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt
index cf261dd..344f24e 100644
--- a/Documentation/git-daemon.txt
+++ b/Documentation/git-daemon.txt
@@ -103,7 +103,8 @@
 	Log to syslog instead of stderr. Note that this option does not imply
 	--verbose, thus by default only error conditions will be logged.
 
---user-path, --user-path=path::
+--user-path::
+--user-path=path::
 	Allow ~user notation to be used in requests.  When
 	specified with no parameter, requests to
 	git://host/~alice/foo is taken as a request to access
@@ -127,7 +128,8 @@
 	Save the process id in 'file'.  Ignored when the daemon
 	is run under `--inetd`.
 
---user=user, --group=group::
+--user=user::
+--group=group::
 	Change daemon's uid and gid before entering the service loop.
 	When only `--user` is given without `--group`, the
 	primary group ID for the user is used.  The values of
@@ -138,14 +140,16 @@
 the facility of inet daemon to achieve the same before spawning
 `git-daemon` if needed.
 
---enable=service, --disable=service::
+--enable=service::
+--disable=service::
 	Enable/disable the service site-wide per default.  Note
 	that a service disabled site-wide can still be enabled
 	per repository if it is marked overridable and the
 	repository enables the service with an configuration
 	item.
 
---allow-override=service, --forbid-override=service::
+--allow-override=service::
+--forbid-override=service::
 	Allow/forbid overriding the site-wide default with per
 	repository configuration.  By default, all the services
 	are overridable.
@@ -272,4 +276,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt
index 69e1ab7..44aaa40 100644
--- a/Documentation/git-describe.txt
+++ b/Documentation/git-describe.txt
@@ -70,6 +70,9 @@
 	Only consider tags matching the given pattern (can be used to avoid
 	leaking private tags made from the repository).
 
+--always::
+	Show uniquely abbreviated commit object as fallback.
+
 EXAMPLES
 --------
 
@@ -133,7 +136,7 @@
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>, but somewhat
-butchered by Junio C Hamano <junkio@cox.net>.  Later significantly
+butchered by Junio C Hamano <gitster@pobox.com>.  Later significantly
 updated by Shawn Pearce <spearce@spearce.org>.
 
 Documentation
@@ -142,4 +145,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-diff-files.txt b/Documentation/git-diff-files.txt
index 6d2ea16..8a64869 100644
--- a/Documentation/git-diff-files.txt
+++ b/Documentation/git-diff-files.txt
@@ -8,7 +8,7 @@
 
 SYNOPSIS
 --------
-'git-diff-files' [-q] [-0|-1|-2|-3|-c|--cc|--no-index] [<common diff options>] [<path>...]
+'git-diff-files' [-q] [-0|-1|-2|-3|-c|--cc] [<common diff options>] [<path>...]
 
 DESCRIPTION
 -----------
@@ -30,15 +30,13 @@
 cleanly resolved paths.  The option -0 can be given to
 omit diff output for unmerged entries and just show "Unmerged".
 
--c,--cc::
+-c::
+--cc::
 	This compares stage 2 (our branch), stage 3 (their
 	branch) and the working tree file and outputs a combined
 	diff, similar to the way 'diff-tree' shows a merge
 	commit with these flags.
 
---no-index::
-	Compare the two given files / directories.
-
 -q::
 	Remain silent even on nonexistent files
 
@@ -57,4 +55,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-diff-index.txt b/Documentation/git-diff-index.txt
index e867778..f6e844f 100644
--- a/Documentation/git-diff-index.txt
+++ b/Documentation/git-diff-index.txt
@@ -129,4 +129,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-diff-tree.txt b/Documentation/git-diff-tree.txt
index 58d02c6..5d23985 100644
--- a/Documentation/git-diff-tree.txt
+++ b/Documentation/git-diff-tree.txt
@@ -49,13 +49,13 @@
 --stdin::
 	When '--stdin' is specified, the command does not take
 	<tree-ish> arguments from the command line.  Instead, it
-	reads either one <commit> or a pair of <tree-ish>
+	reads either one <commit> or a list of <commit>
 	separated with a single space from its standard input.
 +
 When a single commit is given on one line of such input, it compares
 the commit with its parents.  The following flags further affects its
-behavior.  This does not apply to the case where two <tree-ish>
-separated with a single space are given.
+behavior.  The remaining commits, when given, are used as if they are
+parents of the first commit.
 
 -m::
 	By default, "git-diff-tree --stdin" does not show
@@ -93,11 +93,11 @@
 	This flag changes the way a merge commit patch is displayed,
 	in a similar way to the '-c' option. It implies the '-c'
 	and '-p' options and further compresses the patch output
-	by omitting hunks that show differences from only one
-	parent, or show the same change from all but one parent
-	for an Octopus merge.  When this optimization makes all
-	hunks disappear, the commit itself and the commit log
-	message is not shown, just like in any other "empty diff" case.
+	by omitting uninteresting hunks whose the contents in the parents
+	have only two variants and the merge result picks one of them
+	without modification.  When all hunks are uninteresting, the commit
+	itself and the commit log message is not shown, just like in any other
+	"empty diff" case.
 
 --always::
 	Show the commit itself and the commit log message even
@@ -165,4 +165,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index 57c2862..7acd428 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -168,4 +168,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.txt
index 6dac475..332346c 100644
--- a/Documentation/git-fast-export.txt
+++ b/Documentation/git-fast-export.txt
@@ -80,4 +80,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index c29a4f8..395c055 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -1119,4 +1119,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt
index 57598eb..282fcaf 100644
--- a/Documentation/git-fetch-pack.txt
+++ b/Documentation/git-fetch-pack.txt
@@ -28,30 +28,32 @@
 
 OPTIONS
 -------
-\--all::
+--all::
 	Fetch all remote refs.
 
-\--quiet, \-q::
+-q::
+--quiet::
 	Pass '-q' flag to 'git-unpack-objects'; this makes the
 	cloning process less verbose.
 
-\--keep, \-k::
+-k::
+--keep::
 	Do not invoke 'git-unpack-objects' on received data, but
 	create a single packfile out of it instead, and store it
 	in the object database. If provided twice then the pack is
 	locked against repacking.
 
-\--thin::
+--thin::
 	Spend extra cycles to minimize the number of objects to be sent.
 	Use it on slower connection.
 
-\--include-tag::
+--include-tag::
 	If the remote side supports it, annotated tags objects will
 	be downloaded on the same connection as the other objects if
 	the object the tag references is downloaded.  The caller must
 	otherwise determine the tags this option made available.
 
-\--upload-pack=<git-upload-pack>::
+--upload-pack=<git-upload-pack>::
 	Use this to specify the path to 'git-upload-pack' on the
 	remote side, if is not found on your $PATH.
 	Installations of sshd ignores the user's environment
@@ -63,16 +65,16 @@
 	shells by having a lean .bashrc file (they set most of
 	the things up in .bash_profile).
 
-\--exec=<git-upload-pack>::
+--exec=<git-upload-pack>::
 	Same as \--upload-pack=<git-upload-pack>.
 
-\--depth=<n>::
+--depth=<n>::
 	Limit fetching to ancestor-chains not longer than n.
 
-\--no-progress::
+--no-progress::
 	Do not show the progress.
 
-\-v::
+-v::
 	Run verbosely.
 
 <host>::
@@ -99,4 +101,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index d982f96..4fae7fb 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -45,7 +45,7 @@
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org> and
-Junio C Hamano <junkio@cox.net>
+Junio C Hamano <gitster@pobox.com>
 
 Documentation
 -------------
@@ -53,4 +53,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 4a53096..ea77f1f 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -113,7 +113,7 @@
 	stdin.  The commit id is expected on stdout.
 +
 As a special extension, the commit filter may emit multiple
-commit ids; in that case, ancestors of the original commit will
+commit ids; in that case, the rewritten children of the original commit will
 have all of them as parents.
 +
 You can use the 'map' convenience function in this filter, and other
@@ -133,10 +133,16 @@
 case, be very careful and make sure you have the old tags
 backed up in case the conversion has run afoul.
 +
-Note that there is currently no support for proper rewriting of
-tag objects; in layman terms, if the tag has a message or signature
-attached, the rewritten tag won't have it.  Sorry.  (It is by
-definition impossible to preserve signatures at any rate.)
+Nearly proper rewriting of tag objects is supported. If the tag has
+a message attached, a new tag object will be created with the same message,
+author, and timestamp. If the tag has a signature attached, the
+signature will be stripped. It is by definition impossible to preserve
+signatures. The reason this is "nearly" proper, is because ideally if
+the tag did not change (points to the same object, has the same name, etc.)
+it should retain any signature. That is not the case, signatures will always
+be removed, buyer beware. There is also no support for changing the
+author or timestamp (or the tag message for that matter). Tags which point
+to other tags will be rewritten to point to the underlying commit.
 
 --subdirectory-filter <directory>::
 	Only look at the history which touches the given subdirectory.
@@ -155,7 +161,8 @@
 	does this in the '.git-rewrite/' directory but you can override
 	that choice by this parameter.
 
--f|--force::
+-f::
+--force::
 	`git filter-branch` refuses to start with an existing temporary
 	directory or when there are already refs starting with
 	'refs/original/', unless forced.
@@ -311,4 +318,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-fmt-merge-msg.txt b/Documentation/git-fmt-merge-msg.txt
index 8615ae3..222052f 100644
--- a/Documentation/git-fmt-merge-msg.txt
+++ b/Documentation/git-fmt-merge-msg.txt
@@ -9,8 +9,8 @@
 SYNOPSIS
 --------
 [verse]
-git-fmt-merge-msg [--summary | --no-summary] <$GIT_DIR/FETCH_HEAD
-git-fmt-merge-msg [--summary | --no-summary] -F <file>
+git-fmt-merge-msg [--log | --no-log] <$GIT_DIR/FETCH_HEAD
+git-fmt-merge-msg [--log | --no-log] -F <file>
 
 DESCRIPTION
 -----------
@@ -24,26 +24,36 @@
 OPTIONS
 -------
 
---summary::
+--log::
 	In addition to branch names, populate the log message with
 	one-line descriptions from the actual commits that are being
 	merged.
 
---no-summary::
+--no-log::
 	Do not list one-line descriptions from the actual commits being
 	merged.
 
---file <file>, -F <file>::
+--summary::
+--no-summary::
+	Synonyms to --log and --no-log; these are deprecated and will be
+	removed in the future.
+
+-F <file>::
+--file <file>::
 	Take the list of merged objects from <file> instead of
 	stdin.
 
 CONFIGURATION
 -------------
 
-merge.summary::
+merge.log::
 	Whether to include summaries of merged commits in newly
 	merge commit messages. False by default.
 
+merge.summary::
+	Synonym to `merge.log`; this is deprecated and will be removed in
+	the future.
+
 SEE ALSO
 --------
 linkgit:git-merge[1]
@@ -51,7 +61,7 @@
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -59,4 +69,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 6325ff9..b347bfb 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -53,7 +53,10 @@
 	literally, in the latter case matching completely or from the
 	beginning up to a slash.
 
---shell, --perl, --python, --tcl::
+--shell::
+--perl::
+--python::
+--tcl::
 	If given, strings that substitute `%(fieldname)`
 	placeholders are quoted as string literals suitable for
 	the specified host language.  This is meant to produce
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index b5207b7..ee27eff 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -74,14 +74,17 @@
 -<n>::
 	Limits the number of patches to prepare.
 
--o|--output-directory <dir>::
+-o <dir>::
+--output-directory <dir>::
 	Use <dir> to store the resulting files, instead of the
 	current working directory.
 
--n|--numbered::
+-n::
+--numbered::
 	Name output in '[PATCH n/m]' format.
 
--N|--no-numbered::
+-N::
+--no-numbered::
 	Name output in '[PATCH]' format.
 
 --start-number <n>::
@@ -92,11 +95,13 @@
 	without the default first line of the commit appended.
 	Mutually exclusive with the --stdout option.
 
--k|--keep-subject::
+-k::
+--keep-subject::
 	Do not strip/add '[PATCH]' from the first line of the
 	commit log message.
 
--s|--signoff::
+-s::
+--signoff::
 	Add `Signed-off-by:` line to the commit message, using
 	the committer identity of yourself.
 
@@ -156,6 +161,12 @@
 the first letter does not have to be a dot.  Leaving it empty would
 not add any suffix.
 
+--no-binary::
+	Don't output contents of changes in binary files, just take note
+	that they differ.  Note that this disable the patch to be properly
+	applied.  By default the contents of changes in those files are
+	encoded in the patch.
+
 CONFIGURATION
 -------------
 You can specify extra mail header lines to be added to each message
@@ -168,47 +179,63 @@
         subjectprefix = CHANGE
         suffix = .txt
         numbered = auto
+	cc = <email>
 ------------
 
 
 EXAMPLES
 --------
 
-git-format-patch -k --stdout R1..R2 | git-am -3 -k::
-	Extract commits between revisions R1 and R2, and apply
-	them on top of the current branch using `git-am` to
-	cherry-pick them.
+* Extract commits between revisions R1 and R2, and apply them on top of
+the current branch using `git-am` to cherry-pick them:
++
+------------
+$ git format-patch -k --stdout R1..R2 | git-am -3 -k
+------------
 
-git-format-patch origin::
-	Extract all commits which are in the current branch but
-	not in the origin branch.  For each commit a separate file
-	is created in the current directory.
+* Extract all commits which are in the current branch but not in the
+origin branch:
++
+------------
+$ git format-patch origin
+------------
++
+For each commit a separate file is created in the current directory.
 
-git-format-patch \--root origin::
-	Extract all commits that lead to 'origin' since the
-	inception of the project.
+* Extract all commits that lead to 'origin' since the inception of the
+project:
++
+------------
+$ git format-patch \--root origin
+------------
 
-git-format-patch -M -B origin::
-	The same as the previous one.  Additionally, it detects
-	and handles renames and complete rewrites intelligently to
-	produce a renaming patch.  A renaming patch reduces the
-	amount of text output, and generally makes it easier to
-	review it.  Note that the "patch" program does not
-	understand renaming patches, so use it only when you know
-	the recipient uses git to apply your patch.
+* The same as the previous one:
++
+------------
+$ git format-patch -M -B origin
+------------
++
+Additionally, it detects and handles renames and complete rewrites
+intelligently to produce a renaming patch.  A renaming patch reduces
+the amount of text output, and generally makes it easier to review it.
+Note that the "patch" program does not understand renaming patches, so
+use it only when you know the recipient uses git to apply your patch.
 
-git-format-patch -3::
-	Extract three topmost commits from the current branch
-	and format them as e-mailable patches.
+* Extract three topmost commits from the current branch and format them
+as e-mailable patches:
++
+------------
+$ git format-patch -3
+------------
 
-See Also
+SEE ALSO
 --------
 linkgit:git-am[1], linkgit:git-send-email[1]
 
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -216,4 +243,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.txt
index f16cb98..9846c85 100644
--- a/Documentation/git-fsck.txt
+++ b/Documentation/git-fsck.txt
@@ -22,7 +22,8 @@
 	An object to treat as the head of an unreachability trace.
 +
 If no objects are given, git-fsck defaults to using the
-index file and all SHA1 references in .git/refs/* as heads.
+index file, all SHA1 references in .git/refs/*, and all reflogs (unless
+--no-reflogs is given) as heads.
 
 --unreachable::
 	Print out objects that exist but that aren't readable from any
@@ -150,4 +151,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index b6b5ce1..6ace615 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -119,7 +119,7 @@
 all of those locations and decide whether it makes sense in your case to
 remove those references.
 
-See Also
+SEE ALSO
 --------
 linkgit:git-prune[1]
 linkgit:git-reflog[1]
@@ -132,4 +132,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-get-tar-commit-id.txt b/Documentation/git-get-tar-commit-id.txt
index dea4149..c13bf98 100644
--- a/Documentation/git-get-tar-commit-id.txt
+++ b/Documentation/git-get-tar-commit-id.txt
@@ -33,4 +33,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index a97f055..1b646b7 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -33,25 +33,30 @@
 	Instead of searching in the working tree files, check
 	the blobs registered in the index file.
 
--a | --text::
+-a::
+--text::
 	Process binary files as if they were text.
 
--i | --ignore-case::
+-i::
+--ignore-case::
 	Ignore case differences between the patterns and the
 	files.
 
 -I::
 	Don't match the pattern in binary files.
 
--w | --word-regexp::
+-w::
+--word-regexp::
 	Match the pattern only at word boundary (either begin at the
 	beginning of a line, or preceded by a non-word character; end at
 	the end of a line or followed by a non-word character).
 
--v | --invert-match::
+-v::
+--invert-match::
 	Select non-matching lines.
 
--h | -H::
+-h::
+-H::
 	By default, the command shows the filename for each
 	match.  `-h` option is used to suppress this output.
 	`-H` is there for completeness and does not do anything
@@ -64,24 +69,33 @@
 	option forces paths to be output relative to the project
 	top directory.
 
--E | --extended-regexp | -G | --basic-regexp::
+-E::
+--extended-regexp::
+-G::
+--basic-regexp::
 	Use POSIX extended/basic regexp for patterns.  Default
 	is to use basic regexp.
 
--F | --fixed-strings::
+-F::
+--fixed-strings::
 	Use fixed strings for patterns (don't interpret pattern
 	as a regex).
 
 -n::
 	Prefix the line number to matching lines.
 
--l | --files-with-matches | --name-only | -L | --files-without-match::
+-l::
+--files-with-matches::
+--name-only::
+-L::
+--files-without-match::
 	Instead of showing every matched line, show only the
 	names of files that contain (or do not contain) matches.
 	For better compatibility with git-diff, --name-only is a
 	synonym for --files-with-matches.
 
--c | --count::
+-c::
+--count::
 	Instead of showing every matched line, show the number of
 	lines that match.
 
@@ -103,7 +117,10 @@
 	scripts passing user input to grep.  Multiple patterns are
 	combined by 'or'.
 
---and | --or | --not | ( | )::
+--and::
+--or::
+--not::
+( ... )::
 	Specify how multiple patterns are combined using Boolean
 	expressions.  `--or` is the default operator.  `--and` has
 	higher precedence than `--or`.  `-e` has to be used for all
@@ -145,4 +162,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-gui.txt b/Documentation/git-gui.txt
index 6d6cd5d..105397f 100644
--- a/Documentation/git-gui.txt
+++ b/Documentation/git-gui.txt
@@ -79,9 +79,9 @@
 	selected in the browser can be viewed with the internal
 	blame viewer.
 
-See Also
+SEE ALSO
 --------
-'gitk(1)'::
+linkgit:gitk[1]::
 	The git repository browser.  Shows branches, commit history
 	and file differences.  gitk is the utility started by
 	git-gui's Repository Visualize actions.
@@ -112,4 +112,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-hash-object.txt b/Documentation/git-hash-object.txt
index 33030c0..1abcd96 100644
--- a/Documentation/git-hash-object.txt
+++ b/Documentation/git-hash-object.txt
@@ -8,7 +8,7 @@
 
 SYNOPSIS
 --------
-'git-hash-object' [-t <type>] [-w] [--stdin] [--] <file>...
+'git-hash-object' [-t <type>] [-w] [--stdin | --stdin-paths] [--] <file>...
 
 DESCRIPTION
 -----------
@@ -32,9 +32,12 @@
 --stdin::
 	Read the object from standard input instead of from a file.
 
+--stdin-paths::
+	Read file names from stdin instead of from the command-line.
+
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -42,4 +45,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt
index be2ae53..faecd6b 100644
--- a/Documentation/git-help.txt
+++ b/Documentation/git-help.txt
@@ -28,15 +28,18 @@
 
 OPTIONS
 -------
--a|--all::
+-a::
+--all::
 	Prints all the available commands on the standard output. This
 	option supersedes any other option.
 
--i|--info::
+-i::
+--info::
 	Display manual page for the command in the 'info' format. The
 	'info' program will be used for that purpose.
 
--m|--man::
+-m::
+--man::
 	Display manual page for the command in the 'man' format. This
 	option may be used to override a value set in the
 	'help.format' configuration variable.
@@ -45,7 +48,8 @@
 but the 'man.viewer' configuration variable may be used to choose
 other display programs (see below).
 
--w|--web::
+-w::
+--web::
 	Display manual page for the command in the 'web' (HTML)
 	format. A web browser will be used for that purpose.
 +
@@ -82,28 +86,75 @@
 ~~~~~~~~~~
 
 The 'man.viewer' config variable will be checked if the 'man' format
-is chosen. Only the following values are currently supported:
+is chosen. The following values are currently supported:
 
 * "man": use the 'man' program as usual,
 * "woman": use 'emacsclient' to launch the "woman" mode in emacs
 (this only works starting with emacsclient versions 22),
-* "konqueror": use a man KIO slave in konqueror.
+* "konqueror": use 'kfmclient' to open the man page in a new konqueror
+tab (see 'Note about konqueror' below).
 
-Multiple values may be given to this configuration variable. Their
-corresponding programs will be tried in the order listed in the
-configuration file.
+Values for other tools can be used if there is a corresponding
+'man.<tool>.cmd' configuration entry (see below).
+
+Multiple values may be given to the 'man.viewer' configuration
+variable. Their corresponding programs will be tried in the order
+listed in the configuration file.
 
 For example, this configuration:
 
+------------------------------------------------
 	[man]
 		viewer = konqueror
 		viewer = woman
+------------------------------------------------
 
 will try to use konqueror first. But this may fail (for example if
 DISPLAY is not set) and in that case emacs' woman mode will be tried.
 
 If everything fails the 'man' program will be tried anyway.
 
+man.<tool>.path
+~~~~~~~~~~~~~~~
+
+You can explicitly provide a full path to your preferred man viewer by
+setting the configuration variable 'man.<tool>.path'. For example, you
+can configure the absolute path to konqueror by setting
+'man.konqueror.path'. Otherwise, 'git help' assumes the tool is
+available in PATH.
+
+man.<tool>.cmd
+~~~~~~~~~~~~~~
+
+When the man viewer, specified by the 'man.viewer' configuration
+variables, is not among the supported ones, then the corresponding
+'man.<tool>.cmd' configuration variable will be looked up. If this
+variable exists then the specified tool will be treated as a custom
+command and a shell eval will be used to run the command with the man
+page passed as arguments.
+
+Note about konqueror
+~~~~~~~~~~~~~~~~~~~~
+
+When 'konqueror' is specified in the 'man.viewer' configuration
+variable, we launch 'kfmclient' to try to open the man page on an
+already opened konqueror in a new tab if possible.
+
+For consistency, we also try such a trick if 'man.konqueror.path' is
+set to something like 'A_PATH_TO/konqueror'. That means we will try to
+launch 'A_PATH_TO/kfmclient' instead.
+
+If you really want to use 'konqueror', then you can use something like
+the following:
+
+------------------------------------------------
+	[man]
+		viewer = konq
+
+	[man "konq"]
+		cmd = A_PATH_TO/konqueror
+------------------------------------------------
+
 Note about git config --global
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -125,10 +176,10 @@
 
 Documentation
 -------------
-Initial documentation was part of the linkgit:git[7] man page.
+Initial documentation was part of the linkgit:git[1] man page.
 Christian Couder <chriscool@tuxfamily.org> extracted and rewrote it a
 little. Maintenance is done by the git-list <git@vger.kernel.org>.
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-http-fetch.txt b/Documentation/git-http-fetch.txt
index b784a9d..70fb635 100644
--- a/Documentation/git-http-fetch.txt
+++ b/Documentation/git-http-fetch.txt
@@ -53,4 +53,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-http-push.txt b/Documentation/git-http-push.txt
index 0b82722..d69b205 100644
--- a/Documentation/git-http-push.txt
+++ b/Documentation/git-http-push.txt
@@ -15,8 +15,8 @@
 Sends missing objects to remote repository, and updates the
 remote branch.
 
-*NOTE*: This command is temporarily disabled if your cURL
-library is older than 7.16, as the combination has been reported
+*NOTE*: This command is temporarily disabled if your libcurl
+is older than 7.16, as the combination has been reported
 not to work and sometimes corrupts repository.
 
 OPTIONS
@@ -40,7 +40,8 @@
 	Report the list of objects being walked locally and the
 	list of objects successfully sent to the remote repository.
 
--d, -D::
+-d::
+-D::
 	Remove <ref> from remote repository.  The specified branch
 	cannot be the remote HEAD.  If -d is specified the following
 	other conditions must also be met:
@@ -101,4 +102,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt
index 522b73c..f4fdc24 100644
--- a/Documentation/git-imap-send.txt
+++ b/Documentation/git-imap-send.txt
@@ -59,4 +59,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.txt
index a7825b6..6409363 100644
--- a/Documentation/git-index-pack.txt
+++ b/Documentation/git-index-pack.txt
@@ -100,4 +100,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-init.txt b/Documentation/git-init.txt
index 62914da..792643c 100644
--- a/Documentation/git-init.txt
+++ b/Documentation/git-init.txt
@@ -8,7 +8,7 @@
 
 SYNOPSIS
 --------
-'git-init' [-q | --quiet] [--template=<template_directory>] [--shared[=<permissions>]]
+'git-init' [-q | --quiet] [--bare] [--template=<template_directory>] [--shared[=<permissions>]]
 
 
 OPTIONS
@@ -16,10 +16,16 @@
 
 --
 
--q, \--quiet::
+-q::
+--quiet::
 
 Only print error and warning messages, all other output will be suppressed.
 
+--bare::
+
+Create a bare repository. If GIT_DIR environment is not set, it is set to the
+current working directory.
+
 --template=<template_directory>::
 
 Provide the directory from which templates will be used.  The default template
@@ -31,7 +37,7 @@
 "hook" files.  The suggested patterns and hook files are all modifiable and
 extensible.
 
---shared[={false|true|umask|group|all|world|everybody}]::
+--shared[={false|true|umask|group|all|world|everybody|0xxx}]::
 
 Specify that the git repository is to be shared amongst several users.  This
 allows users belonging to the same group to push into that
@@ -52,6 +58,12 @@
  - 'all' (or 'world' or 'everybody'): Same as 'group', but make the repository
    readable by all users.
 
+ - '0xxx': '0xxx' is an octal number and each file will have mode '0xxx'
+   Any option except 'umask' can be set using this option. '0xxx' will
+   override users umask(2) value, and thus, users with a safe umask (0077)
+   can use this option. '0640' will create a repository which is group-readable
+   but not writable. '0660' is equivalent to 'group'.
+
 By default, the configuration flag receive.denyNonFastForwards is enabled
 in shared repositories, so that you cannot force a non fast-forwarding push
 into it.
@@ -111,4 +123,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-instaweb.txt b/Documentation/git-instaweb.txt
index 51f1532..7da5b8d 100644
--- a/Documentation/git-instaweb.txt
+++ b/Documentation/git-instaweb.txt
@@ -20,24 +20,29 @@
 OPTIONS
 -------
 
--l|--local::
+-l::
+--local::
 	Only bind the web server to the local IP (127.0.0.1).
 
--d|--httpd::
+-d::
+--httpd::
 	The HTTP daemon command-line that will be executed.
 	Command-line options may be specified here, and the
 	configuration file will be added at the end of the command-line.
 	Currently lighttpd, apache2 and webrick are supported.
 	(Default: lighttpd)
 
--m|--module-path::
+-m::
+--module-path::
 	The module path (only needed if httpd is Apache).
 	(Default: /usr/lib/apache2/modules)
 
--p|--port::
+-p::
+--port::
 	The port number to bind the httpd to.  (Default: 1234)
 
--b|--browser::
+-b::
+--browser::
 	The web browser that should be used to view the gitweb
 	page. This will be passed to the 'git-web--browse' helper
 	script along with the URL of the gitweb instance. See
@@ -86,4 +91,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index ebaee4b..db61bc9 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -112,4 +112,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-lost-found.txt b/Documentation/git-lost-found.txt
index b1c797f..4dc475e 100644
--- a/Documentation/git-lost-found.txt
+++ b/Documentation/git-lost-found.txt
@@ -78,4 +78,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index da9ebf4..560594e 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -30,23 +30,29 @@
 
 OPTIONS
 -------
--c|--cached::
+-c::
+--cached::
 	Show cached files in the output (default)
 
--d|--deleted::
+-d::
+--deleted::
 	Show deleted files in the output
 
--m|--modified::
+-m::
+--modified::
 	Show modified files in the output
 
--o|--others::
+-o::
+--others::
 	Show other files in the output
 
--i|--ignored::
+-i::
+--ignored::
 	Show ignored files in the output.
 	Note that this also reverses any exclude list present.
 
--s|--stage::
+-s::
+--stage::
 	Show stage files in the output
 
 --directory::
@@ -56,10 +62,12 @@
 --no-empty-directory::
 	Do not list empty directories. Has no effect without --directory.
 
--u|--unmerged::
+-u::
+--unmerged::
 	Show unmerged files in the output (forces --stage)
 
--k|--killed::
+-k::
+--killed::
 	Show files on the filesystem that need to be removed due
 	to file/directory conflicts for checkout-index to
 	succeed.
@@ -67,11 +75,13 @@
 -z::
 	\0 line termination on output.
 
--x|--exclude=<pattern>::
+-x <pattern>::
+--exclude=<pattern>::
 	Skips files matching pattern.
 	Note that pattern is a shell wildcard pattern.
 
--X|--exclude-from=<file>::
+-X <file>::
+--exclude-from=<file>::
 	exclude patterns are read from <file>; 1 per line.
 
 --exclude-per-directory=<file>::
@@ -177,7 +187,7 @@
 by --exclude-per-directory is relative to the directory that the
 pattern file appears in.
 
-See Also
+SEE ALSO
 --------
 linkgit:git-read-tree[1], linkgit:gitignore[5]
 
@@ -192,4 +202,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt
index c5ba0aa..f282164 100644
--- a/Documentation/git-ls-remote.txt
+++ b/Documentation/git-ls-remote.txt
@@ -20,13 +20,17 @@
 
 OPTIONS
 -------
--h|--heads, -t|--tags::
+-h::
+--heads::
+-t::
+--tags::
 	Limit to only refs/heads and refs/tags, respectively.
 	These options are _not_ mutually exclusive; when given
 	both, references stored in refs/heads and refs/tags are
 	displayed.
 
--u <exec>, --upload-pack=<exec>::
+-u <exec>::
+--upload-pack=<exec>::
 	Specify the full path of linkgit:git-upload-pack[1] on the remote
 	host. This allows listing references from repositories accessed via
 	SSH and where the SSH daemon does not use the PATH configured by the
@@ -65,8 +69,8 @@
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-ls-tree.txt b/Documentation/git-ls-tree.txt
index 360c0a1..8955b71 100644
--- a/Documentation/git-ls-tree.txt
+++ b/Documentation/git-ls-tree.txt
@@ -81,7 +81,7 @@
 Author
 ------
 Written by Petr Baudis <pasky@suse.cz>
-Completely rewritten from scratch by Junio C Hamano <junkio@cox.net>,
+Completely rewritten from scratch by Junio C Hamano <gitster@pobox.com>,
 another major rewrite by Linus Torvalds <torvalds@osdl.org>
 
 Documentation
@@ -91,4 +91,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-mailinfo.txt b/Documentation/git-mailinfo.txt
index 3846f0e..0b23fae 100644
--- a/Documentation/git-mailinfo.txt
+++ b/Documentation/git-mailinfo.txt
@@ -8,7 +8,7 @@
 
 SYNOPSIS
 --------
-'git-mailinfo' [-k] [-u | --encoding=<encoding>] <msg> <patch>
+'git-mailinfo' [-k] [-u | --encoding=<encoding> | -n] <msg> <patch>
 
 
 DESCRIPTION
@@ -46,6 +46,9 @@
 	from what is specified by i18n.commitencoding, this flag
 	can be used to override it.
 
+-n::
+	Disable all charset re-coding of the metadata.
+
 <msg>::
 	The commit log message extracted from e-mail, usually
 	except the title line which comes from e-mail Subject.
@@ -57,7 +60,7 @@
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org> and
-Junio C Hamano <junkio@cox.net>
+Junio C Hamano <gitster@pobox.com>
 
 
 Documentation
@@ -66,4 +69,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-mailsplit.txt b/Documentation/git-mailsplit.txt
index 8243f69..1a0df38 100644
--- a/Documentation/git-mailsplit.txt
+++ b/Documentation/git-mailsplit.txt
@@ -27,7 +27,7 @@
 	Root of the Maildir to split. This directory should contain the cur, tmp
 	and new subdirectories.
 
-<directory>::
+-o<directory>::
 	Directory in which to place the individual messages.
 
 -b::
@@ -46,7 +46,7 @@
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>
-and Junio C Hamano <junkio@cox.net>
+and Junio C Hamano <gitster@pobox.com>
 
 
 Documentation
@@ -55,4 +55,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-merge-base.txt b/Documentation/git-merge-base.txt
index 07f78b4..bbe8512 100644
--- a/Documentation/git-merge-base.txt
+++ b/Documentation/git-merge-base.txt
@@ -39,4 +39,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-merge-file.txt b/Documentation/git-merge-file.txt
index c513184..149f131 100644
--- a/Documentation/git-merge-file.txt
+++ b/Documentation/git-merge-file.txt
@@ -89,4 +89,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-merge-index.txt b/Documentation/git-merge-index.txt
index 19ee017..a0ead2b 100644
--- a/Documentation/git-merge-index.txt
+++ b/Documentation/git-merge-index.txt
@@ -84,4 +84,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-merge-one-file.txt b/Documentation/git-merge-one-file.txt
index ee95df3..546ebe8 100644
--- a/Documentation/git-merge-one-file.txt
+++ b/Documentation/git-merge-one-file.txt
@@ -18,7 +18,7 @@
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>,
-Junio C Hamano <junkio@cox.net> and Petr Baudis <pasky@suse.cz>.
+Junio C Hamano <gitster@pobox.com> and Petr Baudis <pasky@suse.cz>.
 
 Documentation
 --------------
@@ -26,4 +26,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt
index 4cc0964..b785e0f 100644
--- a/Documentation/git-merge-tree.txt
+++ b/Documentation/git-merge-tree.txt
@@ -33,4 +33,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index c136b10..b05e0ce 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -9,7 +9,7 @@
 SYNOPSIS
 --------
 [verse]
-'git-merge' [-n] [--summary] [--no-commit] [--squash] [-s <strategy>]...
+'git-merge' [-n] [--stat] [--no-commit] [--squash] [-s <strategy>]...
 	[-m <msg>] <remote> <remote>...
 'git-merge' <msg> HEAD <remote>...
 
@@ -46,18 +46,7 @@
 
 CONFIGURATION
 -------------
-
-merge.summary::
-	Whether to include summaries of merged commits in newly
-	created merge commit. False by default.
-
-merge.verbosity::
-	Controls the amount of output shown by the recursive merge
-	strategy.  Level 0 outputs nothing except a final error
-	message if conflicts were detected. Level 1 outputs only
-	conflicts, 2 outputs conflicts and file changes.  Level 5 and
-	above outputs debugging information.  The default is level 2.
-	Can be overridden by 'GIT_MERGE_VERBOSITY' environment variable.
+include::merge-config.txt[]
 
 branch.<name>.mergeoptions::
 	Sets default options for merging into branch <name>. The syntax and
@@ -170,7 +159,7 @@
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 
 Documentation
@@ -179,4 +168,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt
index 8ed4494..8352560 100644
--- a/Documentation/git-mergetool.txt
+++ b/Documentation/git-mergetool.txt
@@ -70,4 +70,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-mktag.txt b/Documentation/git-mktag.txt
index 82db9f5..232bc1a 100644
--- a/Documentation/git-mktag.txt
+++ b/Documentation/git-mktag.txt
@@ -43,4 +43,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-mktree.txt b/Documentation/git-mktree.txt
index f312036..6927eb9 100644
--- a/Documentation/git-mktree.txt
+++ b/Documentation/git-mktree.txt
@@ -23,7 +23,7 @@
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -31,4 +31,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-mv.txt b/Documentation/git-mv.txt
index bff3fbe..3391906 100644
--- a/Documentation/git-mv.txt
+++ b/Documentation/git-mv.txt
@@ -34,7 +34,8 @@
 	condition. An error happens when a source is neither existing nor
         controlled by GIT, or when it would overwrite an existing
         file unless '-f' is given.
--n, \--dry-run::
+-n::
+--dry-run::
 	Do nothing; only show what would happen
 
 
@@ -50,4 +51,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt
index efcabdc..83d8e4a 100644
--- a/Documentation/git-name-rev.txt
+++ b/Documentation/git-name-rev.txt
@@ -38,8 +38,14 @@
 	Instead of printing both the SHA-1 and the name, print only
 	the name.  If given with --tags the usual tag prefix of
 	"tags/" is also omitted from the name, matching the output
-	of linkgit:git-describe[1] more closely.  This option
-	cannot be combined with --stdin.
+	of linkgit:git-describe[1] more closely.
+
+--no-undefined::
+	Die with error code != 0 when a reference is undefined,
+	instead of printing `undefined`.
+
+--always::
+	Show uniquely abbreviated commit object as fallback.
 
 EXAMPLE
 -------
@@ -75,4 +81,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt
index 3a1be08..f4d8d68 100644
--- a/Documentation/git-pack-objects.txt
+++ b/Documentation/git-pack-objects.txt
@@ -79,7 +79,8 @@
 	reference was included in the resulting packfile.  This
 	can be useful to send new tags to native git clients.
 
---window=[N], --depth=[N]::
+--window=[N]::
+--depth=[N]::
 	These two options affect how the objects contained in
 	the pack are stored using delta compression.  The
 	objects are first internally sorted by type, size and
@@ -200,7 +201,7 @@
 -------------
 Documentation by Junio C Hamano
 
-See Also
+SEE ALSO
 --------
 linkgit:git-rev-list[1]
 linkgit:git-repack[1]
@@ -208,4 +209,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-pack-redundant.txt b/Documentation/git-pack-redundant.txt
index af4aa4a..6737326 100644
--- a/Documentation/git-pack-redundant.txt
+++ b/Documentation/git-pack-redundant.txt
@@ -46,7 +46,7 @@
 --------------
 Documentation by Lukas Sandström <lukass@etek.chalmers.se>
 
-See Also
+SEE ALSO
 --------
 linkgit:git-pack-objects[1]
 linkgit:git-repack[1]
@@ -54,4 +54,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-pack-refs.txt b/Documentation/git-pack-refs.txt
index e4ff934..c071846 100644
--- a/Documentation/git-pack-refs.txt
+++ b/Documentation/git-pack-refs.txt
@@ -42,7 +42,7 @@
 OPTIONS
 -------
 
-\--all::
+--all::
 
 The command by default packs all tags and refs that are already
 packed, and leaves other refs
@@ -51,7 +51,7 @@
 This option causes branch tips to be packed as well.  Useful for
 a repository with many branches of historical interests.
 
-\--no-prune::
+--no-prune::
 
 The command usually removes loose refs under `$GIT_DIR/refs`
 hierarchy after packing them.  This option tells it not to.
@@ -63,4 +63,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-parse-remote.txt b/Documentation/git-parse-remote.txt
index deb8b2f..951dbd6 100644
--- a/Documentation/git-parse-remote.txt
+++ b/Documentation/git-parse-remote.txt
@@ -47,4 +47,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-patch-id.txt b/Documentation/git-patch-id.txt
index 894852a..bb8a079 100644
--- a/Documentation/git-patch-id.txt
+++ b/Documentation/git-patch-id.txt
@@ -39,4 +39,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-peek-remote.txt b/Documentation/git-peek-remote.txt
index 0001710..3fb17f9 100644
--- a/Documentation/git-peek-remote.txt
+++ b/Documentation/git-peek-remote.txt
@@ -16,7 +16,7 @@
 
 OPTIONS
 -------
-\--upload-pack=<git-upload-pack>::
+--upload-pack=<git-upload-pack>::
 	Use this to specify the path to 'git-upload-pack' on the
 	remote side, if it is not found on your $PATH. Some
 	installations of sshd ignores the user's environment
@@ -39,7 +39,7 @@
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -47,4 +47,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-prune-packed.txt b/Documentation/git-prune-packed.txt
index 93ee82a..f330b8a 100644
--- a/Documentation/git-prune-packed.txt
+++ b/Documentation/git-prune-packed.txt
@@ -42,11 +42,11 @@
 --------------
 Documentation by Ryan Anderson <ryan@michonline.com>
 
-See Also
+SEE ALSO
 --------
 linkgit:git-pack-objects[1]
 linkgit:git-repack[1]
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-prune.txt b/Documentation/git-prune.txt
index f151cff..ec335d6 100644
--- a/Documentation/git-prune.txt
+++ b/Documentation/git-prune.txt
@@ -13,14 +13,20 @@
 DESCRIPTION
 -----------
 
+NOTE: In most cases, users should run linkgit:git-gc[1], which calls
+git-prune. See the section "NOTES", below.
+
 This runs `git-fsck --unreachable` using all the refs
 available in `$GIT_DIR/refs`, optionally with additional set of
-objects specified on the command line, and prunes all
+objects specified on the command line, and prunes all unpacked
 objects unreachable from any of these head objects from the object database.
 In addition, it
 prunes the unpacked objects that are also found in packs by
 running `git prune-packed`.
 
+Note that unreachable, packed objects will remain.  If this is
+not desired, see linkgit:git-repack[1].
+
 OPTIONS
 -------
 
@@ -31,7 +37,7 @@
 \--::
 	Do not interpret any more arguments as options.
 
-\--expire <time>::
+--expire <time>::
 	Only expire loose objects older than <time>.
 
 <head>...::
@@ -50,6 +56,23 @@
 $ git prune $(cd ../another && $(git-rev-parse --all))
 ------------
 
+Notes
+-----
+
+In most cases, users will not need to call git-prune directly, but
+should instead call linkgit:git-gc[1], which handles pruning along with
+many other housekeeping tasks.
+
+For a description of which objects are considered for pruning, see
+git-fsck's --unreachable option.
+
+SEE ALSO
+--------
+
+linkgit:git-fsck[1],
+linkgit:git-gc[1],
+linkgit:git-reflog[1]
+
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>
@@ -60,4 +83,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 3405ca0..c731bdc 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -30,7 +30,7 @@
 
 :git-pull: 1
 
-\--rebase::
+--rebase::
 	Instead of a merge, perform a rebase after fetching.  If
 	there is a remote ref for the upstream branch, and this branch
 	was rebased since last fetched, the rebase uses that information
@@ -38,13 +38,14 @@
 	for branch `<name>`, set configuration `branch.<name>.rebase`
 	to `true`.
 +
-*NOTE:* This is a potentially _dangerous_ mode of operation.
+[NOTE]
+This is a potentially _dangerous_ mode of operation.
 It rewrites history, which does not bode well when you
 published that history already.  Do *not* use this option
 unless you have read linkgit:git-rebase[1] carefully.
 
-\--no-rebase::
-	Override earlier \--rebase.
+--no-rebase::
+	Override earlier --rebase.
 
 include::fetch-options.txt[]
 
@@ -111,40 +112,58 @@
 EXAMPLES
 --------
 
-git pull, git pull origin::
-	Update the remote-tracking branches for the repository
-	you cloned from, then merge one of them into your
-	current branch.  Normally the branch merged in is
-	the HEAD of the remote repository, but the choice is
-	determined by the branch.<name>.remote and
-	branch.<name>.merge options; see linkgit:git-config[1]
-	for details.
+* Update the remote-tracking branches for the repository
+  you cloned from, then merge one of them into your
+  current branch:
++
+------------------------------------------------
+$ git pull, git pull origin
+------------------------------------------------
++
+Normally the branch merged in is the HEAD of the remote repository,
+but the choice is determined by the branch.<name>.remote and
+branch.<name>.merge options; see linkgit:git-config[1] for details.
 
-git pull origin next::
-	Merge into the current branch the remote branch `next`;
-	leaves a copy of `next` temporarily in FETCH_HEAD, but
-	does not update any remote-tracking branches.
+* Merge into the current branch the remote branch `next`:
++
+------------------------------------------------
+$ git pull origin next
+------------------------------------------------
++
+This leaves a copy of `next` temporarily in FETCH_HEAD, but
+does not update any remote-tracking branches.
 
-git pull . fixes enhancements::
-	Bundle local branch `fixes` and `enhancements` on top of
-	the current branch, making an Octopus merge.  This `git pull .`
-	syntax is equivalent to `git merge`.
+* Bundle local branch `fixes` and `enhancements` on top of
+  the current branch, making an Octopus merge:
++
+------------------------------------------------
+$ git pull . fixes enhancements
+------------------------------------------------
++
+This `git pull .` syntax is equivalent to `git merge`.
 
-git pull -s ours . obsolete::
-	Merge local branch `obsolete` into the current branch,
-	using `ours` merge strategy.
+* Merge local branch `obsolete` into the current branch, using `ours`
+  merge strategy:
++
+------------------------------------------------
+$ git pull -s ours . obsolete
+------------------------------------------------
 
-git pull --no-commit . maint::
-	Merge local branch `maint` into the current branch, but
-	do not make a commit automatically.  This can be used
-	when you want to include further changes to the merge,
-	or want to write your own merge commit message.
+* Merge local branch `maint` into the current branch, but do not make
+  a commit automatically:
++
+------------------------------------------------
+$ git pull --no-commit . maint
+------------------------------------------------
++
+This can be used when you want to include further changes to the
+merge, or want to write your own merge commit message.
 +
 You should refrain from abusing this option to sneak substantial
 changes into a merge commit.  Small fixups like bumping
 release/version name would be acceptable.
 
-Command line pull of multiple branches from one repository::
+* Command line pull of multiple branches from one repository:
 +
 ------------------------------------------------
 $ git checkout master
@@ -152,12 +171,12 @@
 $ git pull . tmp
 ------------------------------------------------
 +
-This updates (or creates, as necessary) branches `pu` and `tmp`
-in the local repository by fetching from the branches
-(respectively) `pu` and `maint` from the remote repository.
+This updates (or creates, as necessary) branches `pu` and `tmp` in
+the local repository by fetching from the branches (respectively)
+`pu` and `maint` from the remote repository.
 +
-The `pu` branch will be updated even if it is does not
-fast-forward; the others will not be.
+The `pu` branch will be updated even if it is does not fast-forward;
+the others will not be.
 +
 The final command then merges the newly fetched `tmp` into master.
 
@@ -175,7 +194,7 @@
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>
-and Junio C Hamano <junkio@cox.net>
+and Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -185,4 +204,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 0585949..60d5339 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -31,7 +31,7 @@
 
 <refspec>::
 	The canonical format of a <refspec> parameter is
-	`+?<src>:<dst>`; that is, an optional plus `+`, followed
+	`+?<src>:<dst>`; that is, an optional plus `{plus}`, followed
 	by the source ref, followed by a colon `:`, followed by
 	the destination ref.
 +
@@ -46,12 +46,6 @@
 the optional leading plus `+` is used, the remote ref is updated
 even if it does not result in a fast forward update.
 +
-Note: If no explicit refspec is found, (that is neither
-on the command line nor in any Push line of the
-corresponding remotes file---see below), then "matching" heads are
-pushed: for every head that exists on the local side, the remote side is
-updated if a head of the same name already exists on the remote side.
-+
 `tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
 +
 A parameter <ref> without a colon pushes the <ref> from the source
@@ -59,52 +53,64 @@
 +
 Pushing an empty <src> allows you to delete the <dst> ref from
 the remote repository.
++
+The special refspec `:` (or `+:` to allow non-fast forward updates)
+directs git to push "matching" heads: for every head that exists on
+the local side, the remote side is updated if a head of the same name
+already exists on the remote side.  This is the default operation mode
+if no explicit refspec is found (that is neither on the command line
+nor in any Push line of the corresponding remotes file---see below).
 
-\--all::
+--all::
 	Instead of naming each ref to push, specifies that all
 	refs under `$GIT_DIR/refs/heads/` be pushed.
 
-\--mirror::
+--mirror::
 	Instead of naming each ref to push, specifies that all
 	refs under `$GIT_DIR/refs/heads/` and `$GIT_DIR/refs/tags/`
 	be mirrored to the remote repository.  Newly created local
 	refs will be pushed to the remote end, locally updated refs
 	will be force updated on the remote end, and deleted refs
-	will be removed from the remote end.
+	will be removed from the remote end.  This is the default
+	if the configuration option `remote.<remote>.mirror` is
+	set.
 
-\--dry-run::
+--dry-run::
 	Do everything except actually send the updates.
 
-\--tags::
+--tags::
 	All refs under `$GIT_DIR/refs/tags` are pushed, in
 	addition to refspecs explicitly listed on the command
 	line.
 
-\--receive-pack=<git-receive-pack>::
+--receive-pack=<git-receive-pack>::
 	Path to the 'git-receive-pack' program on the remote
 	end.  Sometimes useful when pushing to a remote
 	repository over ssh, and you do not have the program in
 	a directory on the default $PATH.
 
-\--exec=<git-receive-pack>::
+--exec=<git-receive-pack>::
 	Same as \--receive-pack=<git-receive-pack>.
 
--f, \--force::
+-f::
+--force::
 	Usually, the command refuses to update a remote ref that is
 	not an ancestor of the local ref used to overwrite it.
 	This flag disables the check.  This can cause the
 	remote repository to lose commits; use it with care.
 
-\--repo=<repo>::
+--repo=<repo>::
 	When no repository is specified the command defaults to
 	"origin"; this overrides it.
 
-\--thin, \--no-thin::
+--thin::
+--no-thin::
 	These options are passed to `git-send-pack`.  Thin
 	transfer spends extra cycles to minimize the number of
 	objects to be sent and meant to be used on slower connection.
 
--v, \--verbose::
+-v::
+--verbose::
 	Run verbosely.
 
 include::urls-remotes.txt[]
@@ -188,7 +194,7 @@
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>, later rewritten in C
+Written by Junio C Hamano <gitster@pobox.com>, later rewritten in C
 by Linus Torvalds <torvalds@osdl.org>
 
 Documentation
@@ -197,4 +203,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-quiltimport.txt b/Documentation/git-quiltimport.txt
index 0fc2b56..0600379 100644
--- a/Documentation/git-quiltimport.txt
+++ b/Documentation/git-quiltimport.txt
@@ -29,6 +29,8 @@
 
 OPTIONS
 -------
+
+-n::
 --dry-run::
 	Walk through the patches in the series and warn
 	if we cannot find all of the necessary information to commit
@@ -57,4 +59,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt
index c95ad9f..58fb906 100644
--- a/Documentation/git-read-tree.txt
+++ b/Documentation/git-read-tree.txt
@@ -348,7 +348,7 @@
 have finished your work-in-progress), attempt the merge again.
 
 
-See Also
+SEE ALSO
 --------
 linkgit:git-write-tree[1]; linkgit:git-ls-files[1];
 linkgit:gitignore[5]
@@ -364,4 +364,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index e0412e0..b7e1da0 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -213,19 +213,22 @@
 --skip::
 	Restart the rebasing process by skipping the current patch.
 
--m, \--merge::
+-m::
+--merge::
 	Use merging strategies to rebase.  When the recursive (default) merge
 	strategy is used, this allows rebase to be aware of renames on the
 	upstream side.
 
--s <strategy>, \--strategy=<strategy>::
+-s <strategy>::
+--strategy=<strategy>::
 	Use the given merge strategy; can be supplied more than
 	once to specify them in the order they should be tried.
 	If there is no `-s` option, a built-in list of strategies
 	is used instead (`git-merge-recursive` when merging a single
 	head, `git-merge-octopus` otherwise).  This implies --merge.
 
--v, \--verbose::
+-v::
+--verbose::
 	Display a diffstat of what changed upstream since the last rebase.
 
 -C<n>::
@@ -238,12 +241,14 @@
 	This flag is passed to the `git-apply` program
 	(see linkgit:git-apply[1]) that applies the patch.
 
--i, \--interactive::
+-i::
+--interactive::
 	Make a list of the commits which are about to be rebased.  Let the
 	user edit that list before rebasing.  This mode can also be used to
 	split commits (see SPLITTING COMMITS below).
 
--p, \--preserve-merges::
+-p::
+--preserve-merges::
 	Instead of ignoring merges, try to recreate them.  This option
 	only works in interactive mode.
 
@@ -392,7 +397,7 @@
 
 Authors
 ------
-Written by Junio C Hamano <junkio@cox.net> and
+Written by Junio C Hamano <gitster@pobox.com> and
 Johannes E. Schindelin <johannes.schindelin@gmx.de>
 
 Documentation
@@ -401,4 +406,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-receive-pack.txt b/Documentation/git-receive-pack.txt
index 4111434..a70c716 100644
--- a/Documentation/git-receive-pack.txt
+++ b/Documentation/git-receive-pack.txt
@@ -162,4 +162,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-reflog.txt b/Documentation/git-reflog.txt
index 047e3ce..c9c25f3 100644
--- a/Documentation/git-reflog.txt
+++ b/Documentation/git-reflog.txt
@@ -94,7 +94,7 @@
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -102,4 +102,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-relink.txt b/Documentation/git-relink.txt
index 1b024de..f6dafd4 100644
--- a/Documentation/git-relink.txt
+++ b/Documentation/git-relink.txt
@@ -34,4 +34,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index 2cbd1f7..345943a 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -9,11 +9,11 @@
 SYNOPSIS
 --------
 [verse]
-'git-remote'
+'git-remote' [-v | --verbose]
 'git-remote' add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
 'git-remote' rm <name>
-'git-remote' show <name>
-'git-remote' prune <name>
+'git-remote' show [-n] <name>
+'git-remote' prune [-n | --dry-run] <name>
 'git-remote' update [group]
 
 DESCRIPTION
@@ -22,6 +22,14 @@
 Manage the set of repositories ("remotes") whose branches you track.
 
 
+OPTIONS
+-------
+
+-v::
+--verbose::
+	Be a little more verbose and show remote url after name.
+
+
 COMMANDS
 --------
 
@@ -47,9 +55,11 @@
 up to point at remote's `<master>` branch instead of whatever
 branch the `HEAD` at the remote repository actually points at.
 +
-In mirror mode, enabled with `--mirror`, the refs will not be stored
+In mirror mode, enabled with `\--mirror`, the refs will not be stored
 in the 'refs/remotes/' namespace, but in 'refs/heads/'.  This option
-only makes sense in bare repositories.
+only makes sense in bare repositories.  If a remote uses mirror
+mode, furthermore, `git push` will always behave as if `\--mirror`
+was passed.
 
 'rm'::
 
@@ -70,9 +80,8 @@
 referenced by <name>, but are still locally available in
 "remotes/<name>".
 +
-With `-n` option, the remote heads are not confirmed first with `git
-ls-remote <name>`; cached information is used instead.  Use with
-caution.
+With `--dry-run` option, report what branches will be pruned, but do no
+actually prune them.
 
 'update'::
 
@@ -126,7 +135,7 @@
 ------------
 
 
-See Also
+SEE ALSO
 --------
 linkgit:git-fetch[1]
 linkgit:git-branch[1]
@@ -144,4 +153,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index d14ab51..04d6f1f 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -8,7 +8,7 @@
 
 SYNOPSIS
 --------
-'git-repack' [-a] [-d] [-f] [-l] [-n] [-q] [--window=N] [--depth=N]
+'git-repack' [-a] [-A] [-d] [-f] [-l] [-n] [-q] [--window=N] [--depth=N]
 
 DESCRIPTION
 -----------
@@ -37,6 +37,18 @@
 	leaves behind, but `git fsck --full` shows as
 	dangling.
 
+-A::
+	Same as `-a`, but any unreachable objects in a previous
+	pack become loose, unpacked objects, instead of being
+	left in the old pack.  Unreachable objects are never
+	intentionally added to a pack, even when repacking.
+	When used with '-d', this option
+	prevents unreachable objects from being immediately
+	deleted by way of being left in the old pack and then
+	removed.  Instead, the loose unreachable objects
+	will be pruned according to normal expiry rules
+	with the next linkgit:git-gc[1].
+
 -d::
 	After packing, if the newly created packs make some
 	existing packs redundant, remove the redundant packs.
@@ -61,7 +73,8 @@
 	this repository (or a direct copy of it)
 	over HTTP or FTP.  See gitlink:git-update-server-info[1].
 
---window=[N], --depth=[N]::
+--window=[N]::
+--depth=[N]::
 	These two options affect how the objects contained in the pack are
 	stored using delta compression. The objects are first internally
 	sorted by type, size and optionally names and compared against the
@@ -110,11 +123,11 @@
 --------------
 Documentation by Ryan Anderson <ryan@michonline.com>
 
-See Also
+SEE ALSO
 --------
 linkgit:git-pack-objects[1]
 linkgit:git-prune-packed[1]
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-request-pull.txt b/Documentation/git-request-pull.txt
index 9a14c04..70810c0 100644
--- a/Documentation/git-request-pull.txt
+++ b/Documentation/git-request-pull.txt
@@ -28,7 +28,7 @@
 
 Author
 ------
-Written by Ryan Anderson <ryan@michonline.com> and Junio C Hamano <junkio@cox.net>
+Written by Ryan Anderson <ryan@michonline.com> and Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -36,4 +36,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-rerere.txt b/Documentation/git-rerere.txt
index a53858e..8f12dc9 100644
--- a/Documentation/git-rerere.txt
+++ b/Documentation/git-rerere.txt
@@ -90,15 +90,15 @@
 
 The commits marked with `*` touch the same area in the same
 file; you need to resolve the conflicts when creating the commit
-marked with `+`.  Then you can test the result to make sure your
+marked with `{plus}`.  Then you can test the result to make sure your
 work-in-progress still works with what is in the latest master.
 
 After this test merge, there are two ways to continue your work
 on the topic.  The easiest is to build on top of the test merge
-commit `+`, and when your work in the topic branch is finally
+commit `{plus}`, and when your work in the topic branch is finally
 ready, pull the topic branch into master, and/or ask the
 upstream to pull from you.  By that time, however, the master or
-the upstream might have been advanced since the test merge `+`,
+the upstream might have been advanced since the test merge `{plus}`,
 in which case the final commit graph would look like this:
 
 ------------
@@ -204,8 +204,8 @@
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index fac59c9..0b368b3 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -195,7 +195,7 @@
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net> and Linus Torvalds <torvalds@osdl.org>
+Written by Junio C Hamano <gitster@pobox.com> and Linus Torvalds <torvalds@osdl.org>
 
 Documentation
 --------------
@@ -203,4 +203,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index d80cdf5..c9b0950 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -109,4 +109,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 5981c79..9082fc9 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -52,6 +52,12 @@
 	The parameter given must be usable as a single, valid
 	object name.  Otherwise barf and abort.
 
+-q::
+--quiet::
+	Only meaningful in `--verify` mode. Do not output an error
+	message if the first argument is not a valid object name;
+	instead exit with non-zero status silently.
+
 --sq::
 	Usually the output is made one line per flag and
 	parameter.  This option makes output a single line,
@@ -114,16 +120,19 @@
 --is-bare-repository::
 	When the repository is bare print "true", otherwise "false".
 
---short, --short=number::
+--short::
+--short=number::
 	Instead of outputting the full SHA1 values of object names try to
 	abbreviate them to a shorter unique name. When no length is specified
 	7 is used. The minimum length is 4.
 
---since=datestring, --after=datestring::
+--since=datestring::
+--after=datestring::
 	Parses the date string, and outputs corresponding
 	--max-age= parameter for git-rev-list command.
 
---until=datestring, --before=datestring::
+--until=datestring::
+--before=datestring::
 	Parses the date string, and outputs corresponding
 	--min-age= parameter for git-rev-list command.
 
@@ -175,7 +184,10 @@
   second ago\}' or '\{1979-02-26 18:30:00\}') to specify the value
   of the ref at a prior point in time.  This suffix may only be
   used immediately following a ref name and the ref must have an
-  existing log ($GIT_DIR/logs/<ref>).
+  existing log ($GIT_DIR/logs/<ref>). Note that this looks up the state
+  of your *local* ref at a given time; e.g., what was in your local
+  `master` branch last week. If you want to look at commits made during
+  certain times, see `--since` and `--until`.
 
 * A ref followed by the suffix '@' with an ordinal specification
   enclosed in a brace pair (e.g. '\{1\}', '\{15\}') to specify
@@ -289,9 +301,9 @@
 `r1` or `r2` but not from both.
 
 Two other shorthands for naming a set that is formed by a commit
-and its parent commits exists.  `r1{caret}@` notation means all
+and its parent commits exist.  The `r1{caret}@` notation means all
 parents of `r1`.  `r1{caret}!` includes commit `r1` but excludes
-its all parents.
+all of its parents.
 
 Here are a handful of examples:
 
@@ -344,7 +356,7 @@
 
 	* Use `*` to mean that this option should not be listed in the usage
 	  generated for the `-h` argument. It's shown for `--help-all` as
-	  documented in linkgit:gitcli[5].
+	  documented in linkgit:gitcli[7].
 
 	* Use `!` to not make the corresponding negated long option available.
 
@@ -375,11 +387,36 @@
 eval `echo "$OPTS_SPEC" | git-rev-parse --parseopt -- "$@" || echo exit $?`
 ------------
 
+EXAMPLES
+--------
+
+* Print the object name of the current commit:
++
+------------
+$ git rev-parse --verify HEAD
+------------
+
+* Print the commit object name from the revision in the $REV shell variable:
++
+------------
+$ git rev-parse --verify $REV
+------------
++
+This will error out if $REV is empty or not a valid revision.
+
+* Same as above:
++
+------------
+$ git rev-parse --default master --verify $REV
+------------
++
+but if $REV is empty, the commit object name from master will be printed.
+
 
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org> .
-Junio C Hamano <junkio@cox.net> and Pierre Habouzit <madcoder@debian.org>
+Junio C Hamano <gitster@pobox.com> and Pierre Habouzit <madcoder@debian.org>
 
 Documentation
 --------------
@@ -387,4 +424,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 93e20f7..5fdeaff 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -7,7 +7,7 @@
 
 SYNOPSIS
 --------
-'git-revert' [--edit | --no-edit] [-n] [-m parent-number] <commit>
+'git-revert' [--edit | --no-edit] [-n] [-m parent-number] [-s] <commit>
 
 DESCRIPTION
 -----------
@@ -22,12 +22,14 @@
 	For a more complete list of ways to spell commit names, see
 	"SPECIFYING REVISIONS" section in linkgit:git-rev-parse[1].
 
--e|--edit::
+-e::
+--edit::
 	With this option, `git-revert` will let you edit the commit
 	message prior to committing the revert. This is the default if
 	you run the command from a terminal.
 
--m parent-number|--mainline parent-number::
+-m parent-number::
+--mainline parent-number::
 	Usually you cannot revert a merge because you do not know which
 	side of the merge should be considered the mainline.  This
 	option specifies the parent number (starting from 1) of
@@ -38,23 +40,28 @@
 	With this option, `git-revert` will not start the commit
 	message editor.
 
--n|--no-commit::
+-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::
+	Add Signed-off-by line at the end of the commit message.
 
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -62,4 +69,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.txt
index 9c81b72..d88554b 100644
--- a/Documentation/git-rm.txt
+++ b/Documentation/git-rm.txt
@@ -38,7 +38,8 @@
 -f::
 	Override the up-to-date check.
 
--n, \--dry-run::
+-n::
+--dry-run::
 	Don't actually remove any file(s).  Instead, just show
 	if they exist in the index and would otherwise be removed
 	by the command.
@@ -52,15 +53,16 @@
 	the list of files, (useful when filenames might be mistaken
 	for command-line options).
 
-\--cached::
+--cached::
 	Use this option to unstage and remove paths only from the index.
 	Working tree files, whether modified or not, will be
 	left alone.
 
-\--ignore-unmatch::
+--ignore-unmatch::
 	Exit with a zero status even if no files matched.
 
--q, \--quiet::
+-q::
+--quiet::
 	git-rm normally outputs one line (in the form of an "rm" command)
 	for each file removed. This option suppresses that output.
 
@@ -93,7 +95,7 @@
 	(i.e. you are listing the files explicitly), it
 	does not remove `subdir/git-foo.sh`.
 
-See Also
+SEE ALSO
 --------
 linkgit:git-add[1]
 
@@ -107,4 +109,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index 9d0a10c..251d661 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -40,7 +40,8 @@
 	Output of this command must be single email address per line.
 	Default is the value of 'sendemail.cccmd' configuration value.
 
---chain-reply-to, --no-chain-reply-to::
+--chain-reply-to::
+--no-chain-reply-to::
 	If this is set, each email will be sent as a reply to the previous
 	email sent.  If disabled with "--no-chain-reply-to", all emails after
 	the first will be sent as replies to the first email sent.  When using
@@ -65,7 +66,8 @@
 	Only necessary if --compose is also set.  If --compose
 	is not set, this will be prompted for.
 
---signed-off-by-cc, --no-signed-off-by-cc::
+--signed-off-by-cc::
+--no-signed-off-by-cc::
         If this is set, add emails found in Signed-off-by: or Cc: lines to the
         cc list.
         Default is the value of 'sendemail.signedoffcc' configuration value;
@@ -141,7 +143,8 @@
 	Only necessary if --compose is also set.  If --compose
 	is not set, this will be prompted for.
 
---suppress-from, --no-suppress-from::
+--suppress-from::
+--no-suppress-from::
         If this is set, do not add the From: address to the cc: list.
         Default is the value of 'sendemail.suppressfrom' configuration value;
         if that is unspecified, default to --no-suppress-from.
@@ -157,7 +160,8 @@
 	if that is unspecified, default to 'self' if --suppress-from is
 	specified, as well as 'sob' if --no-signed-off-cc is specified.
 
---thread, --no-thread::
+--thread::
+--no-thread::
 	If this is set, the In-Reply-To header will be set on each email sent.
 	If disabled with "--no-thread", no emails will have the In-Reply-To
 	header set.
@@ -241,4 +245,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt
index 777515b..ba2fdae 100644
--- a/Documentation/git-send-pack.txt
+++ b/Documentation/git-send-pack.txt
@@ -21,33 +21,33 @@
 
 OPTIONS
 -------
-\--receive-pack=<git-receive-pack>::
+--receive-pack=<git-receive-pack>::
 	Path to the 'git-receive-pack' program on the remote
 	end.  Sometimes useful when pushing to a remote
 	repository over ssh, and you do not have the program in
 	a directory on the default $PATH.
 
-\--exec=<git-receive-pack>::
+--exec=<git-receive-pack>::
 	Same as \--receive-pack=<git-receive-pack>.
 
-\--all::
+--all::
 	Instead of explicitly specifying which refs to update,
 	update all heads that locally exist.
 
-\--dry-run::
+--dry-run::
 	Do everything except actually send the updates.
 
-\--force::
+--force::
 	Usually, the command refuses to update a remote ref that
 	is not an ancestor of the local ref used to overwrite it.
 	This flag disables the check.  What this means is that
 	the remote repository can lose commits; use it with
 	care.
 
-\--verbose::
+--verbose::
 	Run verbosely.
 
-\--thin::
+--thin::
 	Spend extra cycles to minimize the number of objects to be sent.
 	Use it on slower connection.
 
@@ -125,4 +125,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-sh-setup.txt b/Documentation/git-sh-setup.txt
index 16b8b75..c543170 100644
--- a/Documentation/git-sh-setup.txt
+++ b/Documentation/git-sh-setup.txt
@@ -77,4 +77,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-shell.txt b/Documentation/git-shell.txt
index bc031e0..bd09196 100644
--- a/Documentation/git-shell.txt
+++ b/Documentation/git-shell.txt
@@ -31,4 +31,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt
index d7cb4c0..daa64d4 100644
--- a/Documentation/git-shortlog.txt
+++ b/Documentation/git-shortlog.txt
@@ -22,17 +22,21 @@
 OPTIONS
 -------
 
--h, \--help::
+-h::
+--help::
 	Print a short usage message and exit.
 
--n, \--numbered::
+-n::
+--numbered::
 	Sort output according to the number of commits per author instead
 	of author alphabetic order.
 
--s, \--summary::
+-s::
+--summary::
 	Suppress commit description and provide a commit count summary only.
 
--e, \--email::
+-e::
+--email::
 	Show the email address of each author.
 
 -w[<width>[,<indent1>[,<indent2>]]]::
@@ -65,4 +69,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt
index 0bb8250..6f4a2c4 100644
--- a/Documentation/git-show-branch.txt
+++ b/Documentation/git-show-branch.txt
@@ -38,10 +38,12 @@
 	branches under $GIT_DIR/refs/heads/topic, giving
 	`topic/*` would show all of them.
 
--r|--remotes::
+-r::
+--remotes::
 	Show the remote-tracking branches.
 
--a|--all::
+-a::
+--all::
 	Show both remote-tracking branches and local branches.
 
 --current::
@@ -180,7 +182,7 @@
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 
 Documentation
@@ -190,4 +192,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-show-index.txt b/Documentation/git-show-index.txt
index 535a884..891f0ef 100644
--- a/Documentation/git-show-index.txt
+++ b/Documentation/git-show-index.txt
@@ -31,4 +31,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt
index ce0e643..6b99529 100644
--- a/Documentation/git-show-ref.txt
+++ b/Documentation/git-show-ref.txt
@@ -29,22 +29,26 @@
 OPTIONS
 -------
 
--h, --head::
+-h::
+--head::
 
 	Show the HEAD reference.
 
---tags, --heads::
+--tags::
+--heads::
 
 	Limit to only "refs/heads" and "refs/tags", respectively.  These
 	options are not mutually exclusive; when given both, references stored
 	in "refs/heads" and "refs/tags" are displayed.
 
--d, --dereference::
+-d::
+--dereference::
 
 	Dereference tags into object IDs as well. They will be shown with "^{}"
 	appended.
 
--s, --hash::
+-s::
+--hash::
 
 	Only show the SHA1 hash, not the reference name. When also using
 	--dereference the dereferenced tag will still be shown after the SHA1.
@@ -55,17 +59,20 @@
 	Aside from returning an error code of 1, it will also print an error
 	message if '--quiet' was not specified.
 
---abbrev, --abbrev=len::
+--abbrev::
+--abbrev=len::
 
 	Abbreviate the object name.  When using `--hash`, you do
 	not have to say `--hash --abbrev`; `--hash=len` would do.
 
--q, --quiet::
+-q::
+--quiet::
 
 	Do not print any results to stdout. When combined with '--verify' this
 	can be used to silently check if a reference exists.
 
---exclude-existing, --exclude-existing=pattern::
+--exclude-existing::
+--exclude-existing=pattern::
 
 	Make git-show-ref act as a filter that reads refs from stdin of the
 	form "^(?:<anything>\s)?<refname>(?:\^\{\})?$" and performs the
@@ -169,4 +176,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt
index 29ed0ac..1017391 100644
--- a/Documentation/git-show.txt
+++ b/Documentation/git-show.txt
@@ -71,7 +71,7 @@
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org> and
-Junio C Hamano <junkio@cox.net>.  Significantly enhanced by
+Junio C Hamano <gitster@pobox.com>.  Significantly enhanced by
 Johannes Schindelin <Johannes.Schindelin@gmx.de>.
 
 
@@ -81,4 +81,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index 8dc35d4..baa4f55 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -182,4 +182,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index 3ea269a..6026e8b 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -52,14 +52,19 @@
 paths shown are relative to the repository root, not to the current
 directory.
 
-See Also
+If `status.submodulesummary` is set to a non zero number or true (identical
+to -1 or an unlimited number), the submodule summary will be enabled and a
+summary of commits for modified submodules will be shown (see --summary-limit
+option of linkgit:git-submodule[1]).
+
+SEE ALSO
 --------
 linkgit:gitignore[5]
 
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org> and
-Junio C Hamano <junkio@cox.net>.
+Junio C Hamano <gitster@pobox.com>.
 
 Documentation
 --------------
@@ -67,4 +72,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-stripspace.txt b/Documentation/git-stripspace.txt
index fc56875..8421a39 100644
--- a/Documentation/git-stripspace.txt
+++ b/Documentation/git-stripspace.txt
@@ -16,7 +16,8 @@
 
 OPTIONS
 -------
--s|--strip-comments::
+-s::
+--strip-comments::
 	In addition to empty lines, also strip lines starting with '#'.
 
 <stream>::
@@ -32,4 +33,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index 6ffd896..441ae14 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -11,7 +11,8 @@
 [verse]
 'git-submodule' [--quiet] add [-b branch] [--] <repository> [<path>]
 'git-submodule' [--quiet] status [--cached] [--] [<path>...]
-'git-submodule' [--quiet] [init|update] [--] [<path>...]
+'git-submodule' [--quiet] init [--] [<path>...]
+'git-submodule' [--quiet] update [--init] [--] [<path>...]
 'git-submodule' [--quiet] summary [--summary-limit <n>] [commit] [--] [<path>...]
 
 
@@ -47,6 +48,10 @@
 	Update the registered submodules, i.e. clone missing submodules and
 	checkout the commit specified in the index of the containing repository.
 	This will make the submodules HEAD be detached.
++
+If the submodule is not yet initialized, and you just want to use the
+setting as stored in .gitmodules, you can automatically initialize the
+submodule with the --init option.
 
 summary::
 	Show commit summary between the given commit (defaults to HEAD) and
@@ -56,10 +61,12 @@
 
 OPTIONS
 -------
--q, --quiet::
+-q::
+--quiet::
 	Only print error messages.
 
--b, --branch::
+-b::
+--branch::
 	Branch of repository to add as submodule.
 
 --cached::
@@ -67,7 +74,8 @@
 	commands typically use the commit found in the submodule HEAD, but
 	with this option, the commit stored in the index is used instead.
 
--n, --summary-limit::
+-n::
+--summary-limit::
 	This option is only valid for the summary command.
 	Limit the summary size (number of commits shown in total).
 	Giving 0 will disable the summary; a negative number means unlimited
@@ -93,4 +101,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index bec9acc..c350ad0 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -61,6 +61,16 @@
 	Set the 'useSvnsyncProps' option in the [svn-remote] config.
 --rewrite-root=<URL>;;
 	Set the 'rewriteRoot' option in the [svn-remote] config.
+--use-log-author;;
+	When retrieving svn commits into git (as part of fetch, rebase, or
+	dcommit operations), look for the first From: or Signed-off-by: line
+	in the log message and use that as the author string.
+--add-author-from;;
+	When committing to svn from git (as part of commit or dcommit
+	operations), if the existing log message doesn't already have a
+	From: or Signed-off-by: line, append a From: line based on the
+	git commit's author string.  If you use this, then --use-log-author
+	will retrieve a valid author string for all commits.
 --username=<USER>;;
 	For transports that SVN handles authentication for (http,
 	https, and plain svn), specify the username.  For other
@@ -166,11 +176,18 @@
 Any other arguments are passed directly to `git log'
 
 'blame'::
-       Show what revision and author last modified each line of a file. This is
-       identical to `git blame', but SVN revision numbers are shown instead of git
-       commit hashes.
+       Show what revision and author last modified each line of a file. The
+       output of this mode is format-compatible with the output of
+       `svn blame' by default. Like the SVN blame command,
+       local uncommitted changes in the working copy are ignored;
+       the version of the file in the HEAD revision is annotated. Unknown
+       arguments are passed directly to git-blame.
 +
-All arguments are passed directly to `git blame'.
+--git-format;;
+	Produce output in the same format as `git blame', but with
+	SVN revision numbers instead of git commit hashes. In this mode,
+	changes that haven't been committed to SVN (including local
+	working-copy edits) are shown as revision 0.
 
 --
 'find-rev'::
@@ -188,6 +205,12 @@
 	commit.  All merging is assumed to have taken place
 	independently of git-svn functions.
 
+'create-ignore'::
+	Recursively finds the svn:ignore property on directories and
+	creates matching .gitignore files. The resulting files are staged to
+	be committed, but are not committed. Use -r/--revision to refer to a
+	specfic revision.
+
 'show-ignore'::
 	Recursively finds and lists the svn:ignore property on
 	directories.  The output is suitable for appending to
@@ -210,6 +233,19 @@
 	argument.  Use the --url option to output only the value of the
 	'URL:' field.
 
+'proplist'::
+	Lists the properties stored in the Subversion repository about a
+	given file or directory.  Use -r/--revision to refer to a specific
+	Subversion revision.
+
+'propget'::
+	Gets the Subversion property given as the first argument, for a
+	file.  A specific revision can be specified with -r/--revision.
+
+'show-externals'::
+	Shows the Subversion externals.  Use -r/--revision to specify a
+	specific revision.
+
 --
 
 OPTIONS
@@ -329,11 +365,15 @@
 -n::
 --dry-run::
 
-This is only used with the 'dcommit' command.
+This can be used with the 'dcommit' and 'rebase' commands.
 
-Print out the series of git arguments that would show
+For 'dcommit', print out the series of git arguments that would show
 which diffs would be committed to SVN.
 
+For 'rebase', display the local branch associated with the upstream svn
+repository associated with the current branch and the URL of svn
+repository that will be fetched from.
+
 --
 
 ADVANCED OPTIONS
@@ -408,6 +448,8 @@
 	the repository with a public http:// or svn:// URL in the
 	metadata so users of it will see the public URL.
 
+--
+
 Since the noMetadata, rewriteRoot, useSvnsyncProps and useSvmProps
 options all affect the metadata generated and used by git-svn; they
 *must* be set in the configuration file before any history is imported
@@ -416,7 +458,6 @@
 Additionally, only one of these four options can be used per-svn-remote
 section because they affect the 'git-svn-id:' metadata line.
 
---
 
 BASIC EXAMPLES
 --------------
@@ -472,7 +513,7 @@
 	cd project
 	git-init
 	git remote add origin server:/pub/project
-	git config --add remote.origin.fetch=+refs/remotes/*:refs/remotes/*
+	git config --add remote.origin.fetch '+refs/remotes/*:refs/remotes/*'
 	git fetch
 # Initialize git-svn locally (be sure to use the same URL and -T/-b/-t options as were used on server)
 	git-svn init http://svn.foo.org/project
diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt
index a5b40f3..5709dee 100644
--- a/Documentation/git-symbolic-ref.txt
+++ b/Documentation/git-symbolic-ref.txt
@@ -26,7 +26,8 @@
 OPTIONS
 -------
 
--q, --quiet::
+-q::
+--quiet::
 	Do not issue an error message if the <name> is not a
 	symbolic ref but a detached HEAD; instead exit with
 	non-zero status silently.
@@ -54,8 +55,8 @@
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 9712392..6cf11ce 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -247,7 +247,7 @@
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>,
-Junio C Hamano <junkio@cox.net> and Chris Wright <chrisw@osdl.org>.
+Junio C Hamano <gitster@pobox.com> and Chris Wright <chrisw@osdl.org>.
 
 Documentation
 --------------
@@ -255,4 +255,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-tar-tree.txt b/Documentation/git-tar-tree.txt
index 65c6817..74ed065 100644
--- a/Documentation/git-tar-tree.txt
+++ b/Documentation/git-tar-tree.txt
@@ -86,4 +86,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-unpack-file.txt b/Documentation/git-unpack-file.txt
index 1864d13..d0552b2 100644
--- a/Documentation/git-unpack-file.txt
+++ b/Documentation/git-unpack-file.txt
@@ -32,4 +32,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-unpack-objects.txt b/Documentation/git-unpack-objects.txt
index b79be3f..b9c4279 100644
--- a/Documentation/git-unpack-objects.txt
+++ b/Documentation/git-unpack-objects.txt
@@ -8,7 +8,7 @@
 
 SYNOPSIS
 --------
-'git-unpack-objects' [-n] [-q] [-r] <pack-file
+'git-unpack-objects' [-n] [-q] [-r] [--strict] <pack-file
 
 
 DESCRIPTION
@@ -40,6 +40,9 @@
 	and make the best effort to recover as many objects as
 	possible.
 
+--strict::
+	Don't write objects with broken content or links.
+
 
 Author
 ------
@@ -51,4 +54,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index 66be18e..bbb0a6a 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -15,6 +15,7 @@
 	     [--cacheinfo <mode> <object> <file>]\*
 	     [--chmod=(+|-)x]
 	     [--assume-unchanged | --no-assume-unchanged]
+	     [--ignore-submodules]
 	     [--really-refresh] [--unresolve] [--again | -g]
 	     [--info-only] [--index-info]
 	     [-z] [--stdin]
@@ -54,6 +55,10 @@
         default behavior is to error out.  This option makes
         git-update-index continue anyway.
 
+--ignore-submodules:
+	Do not try to update submodules.  This option is only respected
+	when passed before --refresh.
+
 --unmerged::
         If --refresh finds unmerged changes in the index, the default
         behavior is to error out.  This option makes git-update-index
@@ -71,7 +76,8 @@
 --chmod=(+|-)x::
         Set the execute permissions on the updated files.
 
---assume-unchanged, --no-assume-unchanged::
+--assume-unchanged::
+--no-assume-unchanged::
 	When these flags are specified, the object name recorded
 	for the paths are not updated.  Instead, these options
 	sets and unsets the "assume unchanged" bit for the
@@ -83,7 +89,8 @@
 	filesystem that has very slow lstat(2) system call
 	(e.g. cifs).
 
---again, -g::
+-g::
+--again::
 	Runs `git-update-index` itself on the paths whose index
 	entries are different from those from the `HEAD` commit.
 
@@ -307,7 +314,7 @@
 'Using "assume unchanged" bit' section above.
 
 
-See Also
+SEE ALSO
 --------
 linkgit:git-config[1],
 linkgit:git-add[1]
@@ -323,4 +330,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt
index 4dc4759..7f7e3d1 100644
--- a/Documentation/git-update-ref.txt
+++ b/Documentation/git-update-ref.txt
@@ -90,4 +90,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-update-server-info.txt b/Documentation/git-update-server-info.txt
index 1cf89fd..4fd7b5e 100644
--- a/Documentation/git-update-server-info.txt
+++ b/Documentation/git-update-server-info.txt
@@ -22,7 +22,8 @@
 OPTIONS
 -------
 
--f|--force::
+-f::
+--force::
 	Update the info files from scratch.
 
 
@@ -30,8 +31,8 @@
 ------
 
 Currently the command updates the following files.  Please see
-link:repository-layout.html[repository-layout] for description
-of what they are for:
+linkgit:gitrepository-layout[5][repository-layout] for description of
+what they are for:
 
 * objects/info/packs
 
@@ -46,7 +47,7 @@
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -54,4 +55,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-upload-archive.txt b/Documentation/git-upload-archive.txt
index c1ef144..e49f68f 100644
--- a/Documentation/git-upload-archive.txt
+++ b/Documentation/git-upload-archive.txt
@@ -34,4 +34,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-upload-pack.txt b/Documentation/git-upload-pack.txt
index 2330d13..bac465e 100644
--- a/Documentation/git-upload-pack.txt
+++ b/Documentation/git-upload-pack.txt
@@ -24,10 +24,10 @@
 OPTIONS
 -------
 
-\--strict::
+--strict::
 	Do not try <directory>/.git/ if <directory> is no git directory.
 
-\--timeout=<n>::
+--timeout=<n>::
 	Interrupt transfer after <n> seconds of inactivity.
 
 <directory>::
@@ -43,4 +43,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-var.txt b/Documentation/git-var.txt
index 2980283..67e8e1f 100644
--- a/Documentation/git-var.txt
+++ b/Documentation/git-var.txt
@@ -45,7 +45,7 @@
 Your sysadmin must hate you!::
     The password(5) name field is longer than a giant static buffer.
 
-See Also
+SEE ALSO
 --------
 linkgit:git-commit-tree[1]
 linkgit:git-tag[1]
@@ -61,4 +61,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-verify-pack.txt b/Documentation/git-verify-pack.txt
index ba2a157..ff704bd 100644
--- a/Documentation/git-verify-pack.txt
+++ b/Documentation/git-verify-pack.txt
@@ -42,7 +42,7 @@
 
 Author
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <gitster@pobox.com>
 
 Documentation
 --------------
@@ -50,4 +50,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-verify-tag.txt b/Documentation/git-verify-tag.txt
index 7e9c1ed..dffba89 100644
--- a/Documentation/git-verify-tag.txt
+++ b/Documentation/git-verify-tag.txt
@@ -28,4 +28,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-web--browse.txt b/Documentation/git-web--browse.txt
index ddbae5b..e80a7c1 100644
--- a/Documentation/git-web--browse.txt
+++ b/Documentation/git-web--browse.txt
@@ -20,7 +20,7 @@
 
 * firefox (this is the default under X Window when not using KDE)
 * iceweasel
-* konqueror (this is the default under KDE)
+* konqueror (this is the default under KDE, see 'Note about konqueror' below)
 * w3m (this is the default outside graphical environments)
 * links
 * lynx
@@ -31,14 +31,17 @@
 
 OPTIONS
 -------
--b BROWSER|--browser=BROWSER::
+-b BROWSER::
+--browser=BROWSER::
 	Use the specified BROWSER. It must be in the list of supported
 	browsers.
 
--t BROWSER|--tool=BROWSER::
+-t BROWSER::
+--tool=BROWSER::
 	Same as above.
 
--c CONF.VAR|--config=CONF.VAR::
+-c CONF.VAR::
+--config=CONF.VAR::
 	CONF.VAR is looked up in the git config files. If it's set,
 	then its value specify the browser that should be used.
 
@@ -71,6 +74,28 @@
 as a custom command and will use a shell eval to run the command with
 the URLs passed as arguments.
 
+Note about konqueror
+--------------------
+
+When 'konqueror' is specified by the a command line option or a
+configuration variable, we launch 'kfmclient' to try to open the HTML
+man page on an already opened konqueror in a new tab if possible.
+
+For consistency, we also try such a trick if 'browser.konqueror.path' is
+set to something like 'A_PATH_TO/konqueror'. That means we will try to
+launch 'A_PATH_TO/kfmclient' instead.
+
+If you really want to use 'konqueror', then you can use something like
+the following:
+
+------------------------------------------------
+	[web]
+		browser = konq
+
+	[browser "konq"]
+		cmd = A_PATH_TO/konqueror
+------------------------------------------------
+
 Note about git config --global
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -96,4 +121,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-whatchanged.txt b/Documentation/git-whatchanged.txt
index a6e7bd4..fb672ea 100644
--- a/Documentation/git-whatchanged.txt
+++ b/Documentation/git-whatchanged.txt
@@ -67,7 +67,7 @@
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org> and
-Junio C Hamano <junkio@cox.net>
+Junio C Hamano <gitster@pobox.com>
 
 
 Documentation
@@ -76,4 +76,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-write-tree.txt b/Documentation/git-write-tree.txt
index 461c813..8744f65 100644
--- a/Documentation/git-write-tree.txt
+++ b/Documentation/git-write-tree.txt
@@ -46,4 +46,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 615c307..0f55f80 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -1,4 +1,4 @@
-git(7)
+git(1)
 ======
 
 NAME
@@ -20,10 +20,10 @@
 unusually rich command set that provides both high-level operations
 and full access to internals.
 
-See this link:tutorial.html[tutorial] to get started, then see
+See this linkgit:gittutorial[7][tutorial] to get started, then see
 link:everyday.html[Everyday Git] for a useful minimum set of commands, and
 "man git-commandname" for documentation of each command.  CVS users may
-also want to read link:cvs-migration.html[CVS migration].  See
+also want to read linkgit:gitcvs-migration[7][CVS migration].  See
 link:user-manual.html[Git User's Manual] for a more in-depth
 introduction.
 
@@ -43,7 +43,17 @@
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.5.5/git.html[documentation for release 1.5.5]
+* link:v1.5.6.5/git.html[documentation for release 1.5.6.5]
+
+* release notes for
+  link:RelNotes-1.5.6.5.txt[1.5.6.5],
+  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]
 
 * release notes for
   link:RelNotes-1.5.5.4.txt[1.5.5.4],
@@ -52,8 +62,6 @@
   link:RelNotes-1.5.5.1.txt[1.5.5.1],
   link:RelNotes-1.5.5.txt[1.5.5].
 
-* link:v1.5.5.4/git.html[documentation for release 1.5.5.4]
-
 * link:v1.5.4.5/git.html[documentation for release 1.5.4.5]
 
 * release notes for
@@ -77,6 +85,8 @@
   link:RelNotes-1.5.3.1.txt[1.5.3.1],
   link:RelNotes-1.5.3.txt[1.5.3].
 
+* link:v1.5.2.5/git.html[documentation for release 1.5.2.5]
+
 * release notes for
   link:RelNotes-1.5.2.5.txt[1.5.2.5],
   link:RelNotes-1.5.2.4.txt[1.5.2.4],
@@ -138,7 +148,8 @@
 	environment variable. If no path is given 'git' will print
 	the current setting and then exit.
 
--p|--paginate::
+-p::
+--paginate::
 	Pipe all output into 'less' (or if set, $PAGER).
 
 --no-pager::
@@ -146,7 +157,8 @@
 
 --git-dir=<path>::
 	Set the path to the repository. This can also be controlled by
-	setting the GIT_DIR environment variable.
+	setting the GIT_DIR environment variable. It can be an absolute
+	path or relative path to current working directory.
 
 --work-tree=<path>::
 	Set the path to the working tree.  The value will not be
@@ -154,7 +166,12 @@
 	a .git directory (i.e. $GIT_DIR is not set).
 	This can also be controlled by setting the GIT_WORK_TREE
 	environment variable and the core.worktree configuration
-	variable.
+	variable. It can be an absolute path or relative path to
+	the directory specified by --git-dir or GIT_DIR.
+	Note: If --git-dir or GIT_DIR are specified but none of
+	--work-tree, GIT_WORK_TREE and core.worktree is specified,
+	the current working directory is regarded as the top directory
+	of your working tree.
 
 --bare::
 	Treat the repository as a bare repository.  If GIT_DIR
@@ -169,7 +186,7 @@
 probably more detail than necessary for a first-time user.
 
 The link:user-manual.html#git-concepts[git concepts chapter of the
-user-manual] and the link:core-tutorial.html[Core tutorial] both provide
+user-manual] and the linkgit:gitcore-tutorial[7][Core tutorial] both provide
 introductions to the underlying git architecture.
 
 See also the link:howto-index.html[howto] documents for some useful
@@ -359,9 +376,10 @@
 File/Directory Structure
 ------------------------
 
-Please see the link:repository-layout.html[repository layout] document.
+Please see the linkgit:gitrepository-layout[5][repository layout]
+document.
 
-Read link:hooks.html[hooks] for more details about each hook.
+Read linkgit:githooks[5][hooks] for more details about each hook.
 
 Higher level SCMs may provide and manage additional information in the
 `$GIT_DIR`.
@@ -369,7 +387,7 @@
 
 Terminology
 -----------
-Please see the link:glossary.html[glossary] document.
+Please see the linkgit:gitglossary[7][glossary] document.
 
 
 Environment Variables
@@ -513,7 +531,7 @@
 
 More detail on the following is available from the
 link:user-manual.html#git-concepts[git concepts chapter of the
-user-manual] and the link:core-tutorial.html[Core tutorial].
+user-manual] and the linkgit:gitcore-tutorial[7][Core tutorial].
 
 A git project normally consists of a working directory with a ".git"
 subdirectory at the top level.  The .git directory contains, among other
@@ -574,6 +592,13 @@
 <david@dgreaves.com>, and later enhanced greatly by the
 contributors on the git-list <git@vger.kernel.org>.
 
+SEE ALSO
+--------
+linkgit:gittutorial[7], linkgit:gittutorial-2[7],
+linkgit:giteveryday[7], linkgit:gitcvs-migration[7],
+linkgit:gitglossary[7], linkgit:gitcore-tutorial[7],
+link:user-manual.html[The Git User's Manual]
+
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 04ca63c..ef06d94 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -265,7 +265,7 @@
 attribute set to `jcdiff`, it calls the command you specified
 with the above configuration, i.e. `j-c-diff`, with 7
 parameters, just like `GIT_EXTERNAL_DIFF` program is called.
-See linkgit:git[7] for details.
+See linkgit:git[1] for details.
 
 
 Defining a custom hunk-header
@@ -450,6 +450,23 @@
 	variable.
 
 
+Creating an archive
+~~~~~~~~~~~~~~~~~~~
+
+`export-subst`
+^^^^^^^^^^^^^^
+
+If the attribute `export-subst` is set for a file then git will expand
+several placeholders when adding this file to an archive.  The
+expansion depends on the availability of a commit ID, i.e. if
+linkgit:git-archive[1] has been given a tree instead of a commit or a
+tag then no replacement will be done.  The placeholders are the same
+as those for the option `--pretty=format:` of linkgit:git-log[1],
+except that they need to be wrapped like this: `$Format:PLACEHOLDERS$`
+in the file.  E.g. the string `$Format:%H$` will be replaced by the
+commit hash.
+
+
 EXAMPLE
 -------
 
@@ -499,23 +516,7 @@
 ----------------------------------------------------------------
 
 
-Creating an archive
-~~~~~~~~~~~~~~~~~~~
-
-`export-subst`
-^^^^^^^^^^^^^^
-
-If the attribute `export-subst` is set for a file then git will expand
-several placeholders when adding this file to an archive.  The
-expansion depends on the availability of a commit ID, i.e. if
-linkgit:git-archive[1] has been given a tree instead of a commit or a
-tag then no replacement will be done.  The placeholders are the same
-as those for the option `--pretty=format:` of linkgit:git-log[1],
-except that they need to be wrapped like this: `$Format:PLACEHOLDERS$`
-in the file.  E.g. the string `$Format:%H$` will be replaced by the
-commit hash.
-
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt
index 7ee5ce3..8fb5d88 100644
--- a/Documentation/gitcli.txt
+++ b/Documentation/gitcli.txt
@@ -1,4 +1,4 @@
-gitcli(5)
+gitcli(7)
 =========
 
 NAME
@@ -110,4 +110,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/core-tutorial.txt b/Documentation/gitcore-tutorial.txt
similarity index 99%
rename from Documentation/core-tutorial.txt
rename to Documentation/gitcore-tutorial.txt
index 5a55312..cb4ec40 100644
--- a/Documentation/core-tutorial.txt
+++ b/Documentation/gitcore-tutorial.txt
@@ -1,14 +1,22 @@
-A git core tutorial for developers
-==================================
+gitcore-tutorial(7)
+===================
 
-Introduction
-------------
+NAME
+----
+gitcore-tutorial - A git core tutorial for developers
+
+SYNOPSIS
+--------
+git *
+
+DESCRIPTION
+-----------
 
 This tutorial explains how to use the "core" git programs to set up and
 work with a git repository.
 
 If you just need to use git as a revision control system you may prefer
-to start with link:tutorial.html[a tutorial introduction to git] or
+to start with linkgit:gittutorial[7][a tutorial introduction to git] or
 link:user-manual.html[the git user manual].
 
 However, an understanding of these low-level tools can be helpful if
@@ -101,7 +109,7 @@
 
 [NOTE]
 An advanced user may want to take a look at the
-link:repository-layout.html[repository layout] document
+linkgit:gitrepository-layout[5][repository layout] document
 after finishing this tutorial.
 
 You have now created your first git repository. Of course, since it's
@@ -1581,7 +1589,7 @@
 have to worry. git supports "shared public repository" style of
 cooperation you are probably more familiar with as well.
 
-See link:cvs-migration.html[git for CVS users] for the details.
+See linkgit:gitcvs-migration[7][git for CVS users] for the details.
 
 Bundling your work together
 ---------------------------
@@ -1679,3 +1687,13 @@
 and the reason why you preferred changes made in one side over
 the other.  Otherwise it would make the project history harder
 to follow, not easier.
+
+SEE ALSO
+--------
+linkgit:gittutorial[7], linkgit:gittutorial-2[7],
+linkgit:giteveryday[7], linkgit:gitcvs-migration[7],
+link:user-manual.html[The Git User's Manual]
+
+GIT
+---
+Part of the linkgit:git[1] suite.
diff --git a/Documentation/cvs-migration.txt b/Documentation/gitcvs-migration.txt
similarity index 88%
rename from Documentation/cvs-migration.txt
rename to Documentation/gitcvs-migration.txt
index 00f2e36..0325d67 100644
--- a/Documentation/cvs-migration.txt
+++ b/Documentation/gitcvs-migration.txt
@@ -1,5 +1,16 @@
-git for CVS users
-=================
+gitcvs-migration(7)
+===================
+
+NAME
+----
+gitcvs-migration - git for CVS users
+
+SYNOPSIS
+--------
+git cvsimport *
+
+DESCRIPTION
+-----------
 
 Git differs from CVS in that every working tree contains a repository with
 a full copy of the project history, and no repository is inherently more
@@ -8,8 +19,8 @@
 this document explains how to do that.
 
 Some basic familiarity with git is required.  This
-link:tutorial.html[tutorial introduction to git] and the
-link:glossary.html[git glossary] should be sufficient.
+linkgit:gittutorial[7][tutorial introduction to git] and the
+linkgit:gitglossary[7][git glossary] should be sufficient.
 
 Developing against a shared repository
 --------------------------------------
@@ -71,7 +82,7 @@
 
 We assume you have already created a git repository for your project,
 possibly created from scratch or from a tarball (see the
-link:tutorial.html[tutorial]), or imported from an already existing CVS
+linkgit:gittutorial[7][tutorial]), or imported from an already existing CVS
 repository (see the next section).
 
 Assume your existing repo is at /home/alice/myproject.  Create a new "bare"
@@ -132,12 +143,17 @@
 branches for your own changes, and merge in the imported branches as
 necessary.
 
+If you want a shared repository, you will need to make a bare clone
+of the imported directory, as described above. Then treat the imported
+directory as another development clone for purposes of merging
+incremental imports.
+
 Advanced Shared Repository Management
 -------------------------------------
 
 Git allows you to specify scripts called "hooks" to be run at certain
 points.  You can use these, for example, to send all commits to the shared
-repository to a mailing list.  See link:hooks.html[Hooks used by git].
+repository to a mailing list.  See linkgit:githooks[5][Hooks used by git].
 
 You can enforce finer grained permissions using update hooks.  See
 link:howto/update-hook-example.txt[Controlling access to branches using
@@ -170,3 +186,16 @@
 
 With a small group, developers may just pull changes from each other's
 repositories without the need for a central maintainer.
+
+SEE ALSO
+--------
+linkgit:gittutorial[7],
+linkgit:gittutorial-2[7],
+linkgit:gitcore-tutorial[7],
+linkgit:gitglossary[7],
+link:everyday.html[Everyday Git],
+link:user-manual.html[The Git User's Manual]
+
+GIT
+---
+Part of the linkgit:git[1] suite.
diff --git a/Documentation/diffcore.txt b/Documentation/gitdiffcore.txt
similarity index 96%
rename from Documentation/diffcore.txt
rename to Documentation/gitdiffcore.txt
index c6a983a..4d56c85 100644
--- a/Documentation/diffcore.txt
+++ b/Documentation/gitdiffcore.txt
@@ -1,10 +1,16 @@
-Tweaking diff output
-====================
-June 2005
+gitdiffcore(7)
+==============
 
+NAME
+----
+gitdiffcore - Tweaking diff output (June 2005)
 
-Introduction
-------------
+SYNOPSIS
+--------
+git diff *
+
+DESCRIPTION
+-----------
 
 The diff commands git-diff-index, git-diff-files, and git-diff-tree
 can be told to manipulate differences they find in
@@ -269,3 +275,18 @@
 *.c
 t
 ------------------------------------------------
+
+SEE ALSO
+--------
+linkgit:git-diff[1],
+linkgit:git-diff-files[1],
+linkgit:git-diff-index[1],
+linkgit:git-diff-tree[1],
+linkgit:git-format-patch[1],
+linkgit:git-log[1],
+linkgit:gitglossary[7],
+link:user-manual.html[The Git User's Manual]
+
+GIT
+---
+Part of the linkgit:git[1] suite.
diff --git a/Documentation/gitglossary.txt b/Documentation/gitglossary.txt
new file mode 100644
index 0000000..5c5c31d
--- /dev/null
+++ b/Documentation/gitglossary.txt
@@ -0,0 +1,25 @@
+gitglossary(7)
+==============
+
+NAME
+----
+gitglossary - A GIT Glossary
+
+SYNOPSIS
+--------
+*
+
+DESCRIPTION
+-----------
+
+include::glossary-content.txt[]
+
+SEE ALSO
+--------
+linkgit:gittutorial[7], linkgit:gittutorial-2[7],
+linkgit:giteveryday[7], linkgit:gitcvs-migration[7],
+link:user-manual.html[The Git User's Manual]
+
+GIT
+---
+Part of the linkgit:git[1] suite.
diff --git a/Documentation/hooks.txt b/Documentation/githooks.txt
similarity index 93%
rename from Documentation/hooks.txt
rename to Documentation/githooks.txt
index 76b8d77..4f06ae0 100644
--- a/Documentation/hooks.txt
+++ b/Documentation/githooks.txt
@@ -1,5 +1,17 @@
-Hooks used by git
-=================
+githooks(5)
+===========
+
+NAME
+----
+githooks - Hooks used by git
+
+SYNOPSIS
+--------
+$GIT_DIR/hooks/*
+
+
+DESCRIPTION
+-----------
 
 Hooks are little scripts you can place in `$GIT_DIR/hooks`
 directory to trigger action at certain points.  When
@@ -28,10 +40,11 @@
 pre-applypatch
 --------------
 
-This hook is invoked by `git-am`.  It takes no parameter,
-and is invoked after the patch is applied, but before a commit
-is made.  Exiting with non-zero status causes the working tree
-after application of the patch not committed.
+This hook is invoked by `git-am`.  It takes no parameter, and is
+invoked after the patch is applied, but before a commit is made.
+
+If it exits with non-zero status, then the working tree will not be
+committed after applying the patch.
 
 It can be used to inspect the current working tree and refuse to
 make a commit if it does not pass certain test.
@@ -136,7 +149,8 @@
 This hook is invoked by `git-merge`, which happens when a `git pull`
 is done on a local repository.  The hook takes a single parameter, a status
 flag specifying whether or not the merge being done was a squash merge.
-This hook cannot affect the outcome of `git-merge`.
+This hook cannot affect the outcome of `git-merge` and is not executed,
+if the merge failed due to conflicts.
 
 This hook can be used in conjunction with a corresponding pre-commit hook to
 save and restore any form of metadata associated with the working tree
@@ -276,3 +290,14 @@
 Both standard output and standard error output are forwarded to
 `git-send-pack` on the other end, so you can simply `echo` messages
 for the user.
+
+pre-auto-gc
+-----------
+
+This hook is invoked by `git-gc --auto`. It takes no parameter, and
+exiting with non-zero status from this script causes the `git-gc --auto`
+to abort.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index 613dca0..2881c9c 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -138,4 +138,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitk.txt b/Documentation/gitk.txt
index ed3ba83..f843f39 100644
--- a/Documentation/gitk.txt
+++ b/Documentation/gitk.txt
@@ -25,7 +25,8 @@
 the linkgit:git-rev-list[1] command. This manual page describes only the most
 frequently used options.
 
--n <number>, --max-count=<number>::
+-n <number>::
+--max-count=<number>::
 
 	Limits the number of commits to show.
 
@@ -41,6 +42,12 @@
 
 	Show all branches.
 
+--merge::
+
+	After an attempt to merge stops with conflicts, show the commits on
+	the history between two branches (i.e. the HEAD and the MERGE_HEAD)
+	that modify the conflicted files.
+
 <revs>::
 
 	Limit the revisions to show. This can be either a single revision
@@ -79,7 +86,7 @@
 Gitk creates the .gitk file in your $HOME directory to store preferences
 such as display options, font, and colors.
 
-See Also
+SEE ALSO
 --------
 'qgit(1)'::
 	A repository browser written in C++ using Qt.
@@ -103,4 +110,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt
index cc95b69..f8d122a 100644
--- a/Documentation/gitmodules.txt
+++ b/Documentation/gitmodules.txt
@@ -59,4 +59,4 @@
 
 GIT
 ---
-Part of the linkgit:git[7] suite
+Part of the linkgit:git[1] suite
diff --git a/Documentation/repository-layout.txt b/Documentation/gitrepository-layout.txt
similarity index 89%
rename from Documentation/repository-layout.txt
rename to Documentation/gitrepository-layout.txt
index 6939130..03c52ff 100644
--- a/Documentation/repository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -1,9 +1,23 @@
-git repository layout
-=====================
+gitrepository-layout(5)
+=======================
+
+NAME
+----
+gitrepository-layout - Git Repository Layout
+
+SYNOPSIS
+--------
+$GIT_DIR/*
+
+DESCRIPTION
+-----------
 
 You may find these things in your git repository (`.git`
 directory for a repository associated with your working tree, or
-`'project'.git` directory for a public 'bare' repository).
+`<project>.git` directory for a public 'bare' repository. It is
+also possible to have a working tree where `.git` is a plain
+ascii file containing `gitdir: <path>`, i.e. the path to the
+real git repository).
 
 objects::
 	Object store associated with this repository.  Usually
@@ -112,7 +126,7 @@
 branches::
 	A slightly deprecated way to store shorthands to be used
 	to specify URL to `git fetch`, `git pull` and `git push`
-	commands is to store a file in `branches/'name'` and
+	commands is to store a file in `branches/<name>` and
 	give 'name' to these commands in place of 'repository'
 	argument.
 
@@ -121,7 +135,7 @@
 	commands.  A handful of sample hooks are installed when
 	`git init` is run, but all of them are disabled by
 	default.  To enable, they need to be made executable.
-	Read link:hooks.html[hooks] for more details about
+	Read linkgit:githooks[5][hooks] for more details about
 	each hook.
 
 index::
@@ -177,3 +191,18 @@
 	This is similar to `info/grafts` but is internally used
 	and maintained by shallow clone mechanism.  See `--depth`
 	option to linkgit:git-clone[1] and linkgit:git-fetch[1].
+
+SEE ALSO
+--------
+linkgit:git-init[1],
+linkgit:git-clone[1],
+linkgit:git-fetch[1],
+linkgit:git-pack-refs[1],
+linkgit:git-gc[1],
+linkgit:git-checkout[1],
+linkgit:gitglossary[7],
+link:user-manual.html[The Git User's Manual]
+
+GIT
+---
+Part of the linkgit:git[1] suite.
diff --git a/Documentation/tutorial-2.txt b/Documentation/gittutorial-2.txt
similarity index 94%
rename from Documentation/tutorial-2.txt
rename to Documentation/gittutorial-2.txt
index 7fac47d..e3d5c1f 100644
--- a/Documentation/tutorial-2.txt
+++ b/Documentation/gittutorial-2.txt
@@ -1,7 +1,18 @@
-A tutorial introduction to git: part two
-========================================
+gittutorial-2(7)
+================
 
-You should work through link:tutorial.html[A tutorial introduction to
+NAME
+----
+gittutorial-2 - A tutorial introduction to git: part two
+
+SYNOPSIS
+--------
+git *
+
+DESCRIPTION
+-----------
+
+You should work through linkgit:gittutorial[7][A tutorial introduction to
 git] before reading this tutorial.
 
 The goal of this tutorial is to introduce two fundamental pieces of
@@ -379,7 +390,7 @@
 In addition to being the staging area for new commits, the index file
 is also populated from the object database when checking out a
 branch, and is used to hold the trees involved in a merge operation.
-See the link:core-tutorial.html[core tutorial] and the relevant man
+See the linkgit:gitcore-tutorial[7][core tutorial] and the relevant man
 pages for details.
 
 What next?
@@ -389,18 +400,31 @@
 pages for any of the git commands; one good place to start would be
 with the commands mentioned in link:everyday.html[Everyday git].  You
 should be able to find any unknown jargon in the
-link:glossary.html[Glossary].
+linkgit:gitglossary[7][Glossary].
 
 The link:user-manual.html[Git User's Manual] provides a more
 comprehensive introduction to git.
 
-The link:cvs-migration.html[CVS migration] document explains how to
+The linkgit:gitcvs-migration[7][CVS migration] document explains how to
 import a CVS repository into git, and shows how to use git in a
 CVS-like way.
 
 For some interesting examples of git use, see the
 link:howto-index.html[howtos].
 
-For git developers, the link:core-tutorial.html[Core tutorial] goes
+For git developers, the linkgit:gitcore-tutorial[7][Core tutorial] goes
 into detail on the lower-level git mechanisms involved in, for
 example, creating a new commit.
+
+SEE ALSO
+--------
+linkgit:gittutorial[7],
+linkgit:gitcvs-migration[7],
+linkgit:gitcore-tutorial[7],
+linkgit:gitglossary[7],
+link:everyday.html[Everyday git],
+link:user-manual.html[The Git User's Manual]
+
+GIT
+---
+Part of the linkgit:git[1] suite.
diff --git a/Documentation/tutorial.txt b/Documentation/gittutorial.txt
similarity index 97%
rename from Documentation/tutorial.txt
rename to Documentation/gittutorial.txt
index a8c5efb..d465aab 100644
--- a/Documentation/tutorial.txt
+++ b/Documentation/gittutorial.txt
@@ -1,5 +1,16 @@
-A tutorial introduction to git (for version 1.5.1 or newer)
-===========================================================
+gittutorial(7)
+==============
+
+NAME
+----
+gittutorial - A tutorial introduction to git (for version 1.5.1 or newer)
+
+SYNOPSIS
+--------
+git *
+
+DESCRIPTION
+-----------
 
 This tutorial explains how to import a new project into git, make
 changes to it, and share changes with other developers.
@@ -381,7 +392,7 @@
 
 Git can also be used in a CVS-like mode, with a central repository
 that various users push changes to; see linkgit:git-push[1] and
-link:cvs-migration.html[git for CVS users].
+linkgit:gitcvs-migration[7][git for CVS users].
 
 Exploring history
 -----------------
@@ -560,7 +571,7 @@
     used to create commits, check out working directories, and
     hold the various trees involved in a merge.
 
-link:tutorial-2.html[Part two of this tutorial] explains the object
+linkgit:gittutorial-2[7][Part two of this tutorial] explains the object
 database, the index file, and a few other odds and ends that you'll
 need to make the most of git.
 
@@ -581,4 +592,17 @@
 
   * link:everyday.html[Everyday GIT with 20 Commands Or So]
 
-  * link:cvs-migration.html[git for CVS users].
+  * linkgit:gitcvs-migration[7][git for CVS users].
+
+SEE ALSO
+--------
+linkgit:gittutorial-2[7],
+linkgit:gitcvs-migration[7],
+linkgit:gitcore-tutorial[7],
+linkgit:gitglossary[7],
+link:everyday.html[Everyday git],
+link:user-manual.html[The Git User's Manual]
+
+GIT
+---
+Part of the linkgit:git[1] suite.
diff --git a/Documentation/glossary.txt b/Documentation/glossary-content.txt
similarity index 97%
rename from Documentation/glossary.txt
rename to Documentation/glossary-content.txt
index 51b6353..9b4a4f4 100644
--- a/Documentation/glossary.txt
+++ b/Documentation/glossary-content.txt
@@ -1,6 +1,3 @@
-GIT Glossary
-============
-
 [[def_alternate_object_database]]alternate object database::
 	Via the alternates mechanism, a <<def_repository,repository>>
 	can inherit part of its <<def_object_database,object database>>
@@ -90,11 +87,10 @@
 	source code management tools.
 
 [[def_DAG]]DAG::
-	Directed acyclic graph. The <<def_commit,commit>> objects form a
+	Directed acyclic graph. The <<def_commit_object,commit objects>> form a
 	directed acyclic graph, because they have parents (directed), and the
-	graph of commit objects is acyclic (there is no
-	<<def_chain,chain>> which begins and ends with the same
-	<<def_object,object>>).
+	graph of commit objects is acyclic (there is no <<def_chain,chain>>
+	which begins and ends with the same <<def_object,object>>).
 
 [[def_dangling_object]]dangling object::
 	An <<def_unreachable_object,unreachable object>> which is not
@@ -250,9 +246,10 @@
 	the <<def_hash,hash>> of the object.
 
 [[def_object_type]]object type::
-	One of the identifiers
-	"<<def_commit,commit>>","<<def_tree,tree>>","<<def_tag,tag>>" or "<<def_blob_object,blob>>"
-	describing the type of an <<def_object,object>>.
+	One of the identifiers "<<def_commit_object,commit>>",
+	"<<def_tree_object,tree>>", "<<def_tag_object,tag>>" or
+	"<<def_blob_object,blob>>" describing the type of an
+	<<def_object,object>>.
 
 [[def_octopus]]octopus::
 	To <<def_merge,merge>> more than two <<def_branch,branches>>. Also denotes an
diff --git a/Documentation/howto/rebase-from-internal-branch.txt b/Documentation/howto/rebase-from-internal-branch.txt
index 7a76045..d214d4b 100644
--- a/Documentation/howto/rebase-from-internal-branch.txt
+++ b/Documentation/howto/rebase-from-internal-branch.txt
@@ -1,4 +1,4 @@
-From:	Junio C Hamano <junkio@cox.net>
+From:	Junio C Hamano <gitster@pobox.com>
 To:	git@vger.kernel.org
 Cc:	Petr Baudis <pasky@suse.cz>, Linus Torvalds <torvalds@osdl.org>
 Subject: Re: sending changesets from the middle of a git tree
diff --git a/Documentation/howto/rebuild-from-update-hook.txt b/Documentation/howto/rebuild-from-update-hook.txt
index 8d55dfb..48c6756 100644
--- a/Documentation/howto/rebuild-from-update-hook.txt
+++ b/Documentation/howto/rebuild-from-update-hook.txt
@@ -1,6 +1,6 @@
 Subject: [HOWTO] Using post-update hook
 Message-ID: <7vy86o6usx.fsf@assigned-by-dhcp.cox.net>
-From: Junio C Hamano <junkio@cox.net>
+From: Junio C Hamano <gitster@pobox.com>
 Date: Fri, 26 Aug 2005 18:19:10 -0700
 Abstract: In this how-to article, JC talks about how he
  uses the post-update hook to automate git documentation page
diff --git a/Documentation/howto/revert-branch-rebase.txt b/Documentation/howto/revert-branch-rebase.txt
index 865a666..e70d8a3 100644
--- a/Documentation/howto/revert-branch-rebase.txt
+++ b/Documentation/howto/revert-branch-rebase.txt
@@ -1,4 +1,4 @@
-From: Junio C Hamano <junkio@cox.net>
+From: Junio C Hamano <gitster@pobox.com>
 To: git@vger.kernel.org
 Subject: [HOWTO] Reverting an existing commit
 Abstract: In this article, JC gives a small real-life example of using
diff --git a/Documentation/howto/separating-topic-branches.txt b/Documentation/howto/separating-topic-branches.txt
index 0d73b31..6d3eb8e 100644
--- a/Documentation/howto/separating-topic-branches.txt
+++ b/Documentation/howto/separating-topic-branches.txt
@@ -1,4 +1,4 @@
-From: Junio C Hamano <junkio@cox.net>
+From: Junio C Hamano <gitster@pobox.com>
 Subject: Separating topic branches
 Abstract: In this article, JC describes how to separate topic branches.
 
diff --git a/Documentation/howto/setup-git-server-over-http.txt b/Documentation/howto/setup-git-server-over-http.txt
index b7d09c1..4032748 100644
--- a/Documentation/howto/setup-git-server-over-http.txt
+++ b/Documentation/howto/setup-git-server-over-http.txt
@@ -186,7 +186,7 @@
 ------------------------
 
 Make sure that you have HTTP support, i.e. your git was built with
-curl (version more recent than 7.10). The command 'git http-push' with
+libcurl (version more recent than 7.10). The command 'git http-push' with
 no argument should display a usage message.
 
 Then, add the following to your $HOME/.netrc (you can do without, but will be
diff --git a/Documentation/howto/update-hook-example.txt b/Documentation/howto/update-hook-example.txt
index 88765b5..3ef7c0d 100644
--- a/Documentation/howto/update-hook-example.txt
+++ b/Documentation/howto/update-hook-example.txt
@@ -1,4 +1,4 @@
-From: Junio C Hamano <junkio@cox.net> and Carl Baldwin <cnb@fc.hp.com>
+From: Junio C Hamano <gitster@pobox.com> and Carl Baldwin <cnb@fc.hp.com>
 Subject: control access to branches.
 Date: Thu, 17 Nov 2005 23:55:32 -0800
 Message-ID: <7vfypumlu3.fsf@assigned-by-dhcp.cox.net>
@@ -68,7 +68,7 @@
 # - Branches should only be fast-forwarded.
 case "$1" in
   refs/tags/*)
-    [ -f "$GIT_DIR/$1" ] &&
+    git rev-parse --verify -q "$1" &&
     deny >/dev/null "You can't overwrite an existing tag"
     ;;
   refs/heads/*)
diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt
new file mode 100644
index 0000000..48ce747
--- /dev/null
+++ b/Documentation/merge-config.txt
@@ -0,0 +1,40 @@
+merge.stat::
+	Whether to print the diffstat berween ORIG_HEAD and merge result
+	at the end of the merge.  True by default.
+
+merge.log::
+	Whether to include summaries of merged commits in newly created
+	merge commit messages. False by default.
+
+merge.renameLimit::
+	The number of files to consider when performing rename detection
+	during a merge; if not specified, defaults to the value of
+	diff.renameLimit.
+
+merge.tool::
+	Controls which merge resolution program is used by
+	linkgit:git-mergetool[1].  Valid built-in values are: "kdiff3",
+	"tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and
+	"opendiff".  Any other value is treated is custom merge tool
+	and there must be a corresponing mergetool.<tool>.cmd option.
+
+merge.verbosity::
+	Controls the amount of output shown by the recursive merge
+	strategy.  Level 0 outputs nothing except a final error
+	message if conflicts were detected. Level 1 outputs only
+	conflicts, 2 outputs conflicts and file changes.  Level 5 and
+	above outputs debugging information.  The default is level 2.
+	Can be overridden by 'GIT_MERGE_VERBOSITY' environment variable.
+
+merge.<driver>.name::
+	Defines a human readable name for a custom low-level
+	merge driver.  See linkgit:gitattributes[5] for details.
+
+merge.<driver>.driver::
+	Defines the command that implements a custom low-level
+	merge driver.  See linkgit:gitattributes[5] for details.
+
+merge.<driver>.recursive::
+	Names a low-level merge driver to be used when
+	performing an internal merge between common ancestors.
+	See linkgit:gitattributes[5] for details.
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 9f1fc82..ffbc6e9 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -1,10 +1,25 @@
---summary::
+--stat::
 	Show a diffstat at the end of the merge. The diffstat is also
-	controlled by the configuration option merge.diffstat.
+	controlled by the configuration option merge.stat.
 
--n, \--no-summary::
+-n::
+--no-stat::
 	Do not show diffstat at the end of the merge.
 
+--summary::
+--no-summary::
+	Synonyms to --stat and --no-stat; these are deprecated and will be
+	removed in the future.
+
+--log::
+	In addition to branch names, populate the log message with
+	one-line descriptions from the actual commits that are being
+	merged.
+
+--no-log::
+	Do not list one-line descriptions from the actual commits being
+	merged.
+
 --no-commit::
 	Perform the merge but pretend the merge failed and do
 	not autocommit, to give the user a chance to inspect and
@@ -36,7 +51,8 @@
 	a fast-forward, only update the branch pointer. This is
 	the default behavior of git-merge.
 
--s <strategy>, \--strategy=<strategy>::
+-s <strategy>::
+--strategy=<strategy>::
 	Use the given merge strategy; can be supplied more than
 	once to specify them in the order they should be tried.
 	If there is no `-s` option, a built-in list of strategies
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 0193c3c..c11d495 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -30,7 +30,7 @@
 
 	  commit <sha1>
 	  Author: <author>
-	  Date: <date>
+	  Date: <author date>
 
 	      <title line>
 
@@ -50,9 +50,9 @@
 
 	  commit <sha1>
 	  Author: <author>
-	  AuthorDate: <date & time>
+	  AuthorDate: <author date>
 	  Commit: <committer>
-	  CommitDate: <date & time>
+	  CommitDate: <committer date>
 
 	       <title line>
 
@@ -62,7 +62,7 @@
 
 	  From <sha1> <date>
 	  From: <author>
-	  Date: <date & time>
+	  Date: <author date>
 	  Subject: [PATCH] <title line>
 
 	  <full commit message>
@@ -101,6 +101,7 @@
 - '%P': parent hashes
 - '%p': abbreviated parent hashes
 - '%an': author name
+- '%aN': author name (respecting .mailmap)
 - '%ae': author email
 - '%ad': author date
 - '%aD': author date, RFC2822 style
@@ -108,6 +109,7 @@
 - '%at': author date, UNIX timestamp
 - '%ai': author date, ISO 8601 format
 - '%cn': committer name
+- '%cN': committer name (respecting .mailmap)
 - '%ce': committer email
 - '%cd': committer date
 - '%cD': committer date, RFC2822 style
@@ -123,3 +125,26 @@
 - '%Creset': reset color
 - '%m': left, right or boundary mark
 - '%n': newline
+- '%x00': print a byte from a hex code
+
+* 'tformat:'
++
+The 'tformat:' format works exactly like 'format:', except that it
+provides "terminator" semantics instead of "separator" semantics. In
+other words, each commit has the message terminator character (usually a
+newline) appended, rather than a separator placed between entries.
+This means that the final entry of a single-line format will be properly
+terminated with a new line, just as the "oneline" format does.
+For example:
++
+---------------------
+$ git log -2 --pretty=format:%h 4da45bef \
+  | perl -pe '$_ .= " -- NO NEWLINE\n" unless /\n/'
+4da45be
+7134973 -- NO NEWLINE
+
+$ git log -2 --pretty=tformat:%h 4da45bef \
+  | perl -pe '$_ .= " -- NO NEWLINE\n" unless /\n/'
+4da45be
+7134973
+---------------------
diff --git a/Documentation/pull-fetch-param.txt b/Documentation/pull-fetch-param.txt
index b6eb7fc..f157738 100644
--- a/Documentation/pull-fetch-param.txt
+++ b/Documentation/pull-fetch-param.txt
@@ -1,10 +1,12 @@
 <repository>::
 	The "remote" repository that is the source of a fetch
-	or pull operation.  See the section <<URLS,GIT URLS>> below.
+	or pull operation.  This parameter can be either a URL
+	(see the section <<URLS,GIT URLS>> below) or the name
+	of a remote (see the section <<REMOTES,REMOTES>> below).
 
 <refspec>::
 	The canonical format of a <refspec> parameter is
-	`+?<src>:<dst>`; that is, an optional plus `+`, followed
+	`+?<src>:<dst>`; that is, an optional plus `{plus}`, followed
 	by the source ref, followed by a colon `:`, followed by
 	the destination ref.
 +
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 9cd6771..abf3420 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -16,7 +16,8 @@
 --date={relative,local,default,iso,rfc,short}::
 
 	Only takes effect for dates shown in human-readable format, such
-	as when using "--pretty".
+	as when using "--pretty". `log.date` config variable sets a default
+	value for log command's --date option.
 +
 `--date=relative` shows dates relative to the current time,
 e.g. "2 hours ago".
@@ -33,17 +34,21 @@
 `--date=default` shows timestamps in the original timezone
 (either committer's or author's).
 
+ifdef::git-rev-list[]
 --header::
 
 	Print the contents of the commit in raw-format; each record is
 	separated with a NUL character.
+endif::git-rev-list[]
 
 --parents::
 
 	Print the parents of the commit.
 
+ifdef::git-rev-list[]
 --timestamp::
 	Print the raw commit timestamp.
+endif::git-rev-list[]
 
 --left-right::
 
@@ -75,6 +80,17 @@
 	-xxxxxxx... 1st on a
 -----------------------------------------------------------------------
 
+--graph::
+
+	Draw a text-based graphical representation of the commit history
+	on the left hand side of the output.  This may cause extra lines
+	to be printed in between commits, in order for the graph history
+	to be drawn properly.
++
+This implies the '--topo-order' option by default, but the
+'--date-order' option may also be specified.
+
+ifndef::git-rev-list[]
 Diff Formatting
 ~~~~~~~~~~~~~~~
 
@@ -93,9 +109,9 @@
 --cc::
 
 	This flag implies the '-c' options and further compresses the
-	patch output by omitting hunks that show differences from only
-	one parent, or show the same change from all but one parent for
-	an Octopus merge.
+	patch output by omitting uninteresting hunks whose contents in
+	the parents have only two variants and the merge result picks
+	one of them without modification.
 
 -r::
 
@@ -104,6 +120,7 @@
 -t::
 
 	Show the tree objects in the diff output. This implies '-r'.
+endif::git-rev-list[]
 
 Commit Limiting
 ~~~~~~~~~~~~~~~
@@ -114,7 +131,8 @@
 
 --
 
--n 'number', --max-count='number'::
+-n 'number'::
+--max-count='number'::
 
 	Limit the number of commits output.
 
@@ -122,21 +140,25 @@
 
 	Skip 'number' commits before starting to show the commit output.
 
---since='date', --after='date'::
+--since='date'::
+--after='date'::
 
 	Show commits more recent than a specific date.
 
---until='date', --before='date'::
+--until='date'::
+--before='date'::
 
 	Show commits older than a specific date.
 
 ifdef::git-rev-list[]
---max-age='timestamp', --min-age='timestamp'::
+--max-age='timestamp'::
+--min-age='timestamp'::
 
 	Limit the commits output to specified time range.
 endif::git-rev-list[]
 
---author='pattern', --committer='pattern'::
+--author='pattern'::
+--committer='pattern'::
 
 	Limit the commits output to ones with author/committer
 	header lines that match the specified pattern (regular expression).
@@ -146,16 +168,19 @@
 	Limit the commits output to ones with log message that
 	matches the specified pattern (regular expression).
 
--i, --regexp-ignore-case::
+-i::
+--regexp-ignore-case::
 
 	Match the regexp limiting patterns without regard to letters case.
 
--E, --extended-regexp::
+-E::
+--extended-regexp::
 
 	Consider the limiting patterns to be extended regular expressions
 	instead of the default basic regular expressions.
 
--F, --fixed-strings::
+-F::
+--fixed-strings::
 
 	Consider the limiting patterns to be fixed strings (don't interpret
 	pattern as a regular expression).
@@ -195,6 +220,7 @@
 	Pretend as if all the refs in `$GIT_DIR/refs/` are listed on the
 	command line as '<commit>'.
 
+ifdef::git-rev-list[]
 --stdin::
 
 	In addition to the '<commit>' listed on the command
@@ -207,6 +233,7 @@
 	test the exit status to see if a range of objects is fully
 	connected (or not).  It is faster than redirecting stdout
 	to /dev/null as the output does not have to be formatted.
+endif::git-rev-list[]
 
 --cherry-pick::
 
@@ -222,7 +249,8 @@
 from branch A).  With this option, such pairs of commits are
 excluded from the output.
 
--g, --walk-reflogs::
+-g::
+--walk-reflogs::
 
 	Instead of walking the commit ancestry chain, walk
 	reflog entries from the most recent one to older ones.
@@ -234,11 +262,10 @@
 this causes the output to have two extra lines of information
 taken from the reflog.  By default, 'commit@\{Nth}' notation is
 used in the output.  When the starting commit is specified as
-'commit@{now}', output also uses 'commit@\{timestamp}' notation
+'commit@\{now}', output also uses 'commit@\{timestamp}' notation
 instead.  Under '\--pretty=oneline', the commit message is
 prefixed with this information on the same line.
-
-Cannot be combined with '\--reverse'.
+This option cannot be combined with '\--reverse'.
 See also linkgit:git-reflog[1].
 
 --merge::
@@ -251,7 +278,8 @@
 	Output uninteresting commits at the boundary, which are usually
 	not shown.
 
---dense, --sparse::
+--dense::
+--sparse::
 
 When optional paths are given, the default behaviour ('--dense') is to
 only output commits that changes at least one of them, and also ignore
diff --git a/Documentation/technical/api-builtin.txt b/Documentation/technical/api-builtin.txt
index 52cdb4c..7ede1e6 100644
--- a/Documentation/technical/api-builtin.txt
+++ b/Documentation/technical/api-builtin.txt
@@ -4,7 +4,7 @@
 Adding a new built-in
 ---------------------
 
-There are 4 things to do to add a bulit-in command implementation to
+There are 4 things to do to add a built-in command implementation to
 git:
 
 . Define the implementation of the built-in command `foo` with
@@ -18,8 +18,8 @@
   defined in `git.c`.  The entry should look like:
 
 	{ "foo", cmd_foo, <options> },
-
-  where options is the bitwise-or of:
++
+where options is the bitwise-or of:
 
 `RUN_SETUP`::
 
@@ -33,6 +33,12 @@
 	If the standard output is connected to a tty, spawn a pager and
 	feed our output to it.
 
+`NEED_WORK_TREE`::
+
+	Make sure there is a work tree, i.e. the command cannot act
+	on bare repositories.
+	This makes only sense when `RUN_SETUP` is also set.
+
 . Add `builtin-foo.o` to `BUILTIN_OBJS` in `Makefile`.
 
 Additionally, if `foo` is a new command, there are 3 more things to do:
@@ -41,8 +47,7 @@
 
 . Write documentation in `Documentation/git-foo.txt`.
 
-. Add an entry for `git-foo` to the list at the end of
-  `Documentation/cmd-list.perl`.
+. Add an entry for `git-foo` to `command-list.txt`.
 
 
 How a built-in is called
diff --git a/Documentation/technical/api-history-graph.txt b/Documentation/technical/api-history-graph.txt
new file mode 100644
index 0000000..e955979
--- /dev/null
+++ b/Documentation/technical/api-history-graph.txt
@@ -0,0 +1,179 @@
+history graph API
+=================
+
+The graph API is used to draw a text-based representation of the commit
+history.  The API generates the graph in a line-by-line fashion.
+
+Functions
+---------
+
+Core functions:
+
+* `graph_init()` creates a new `struct git_graph`
+
+* `graph_release()` destroys a `struct git_graph`, and frees the memory
+  associated with it.
+
+* `graph_update()` moves the graph to a new commit.
+
+* `graph_next_line()` outputs the next line of the graph into a strbuf.  It
+  does not add a terminating newline.
+
+* `graph_padding_line()` outputs a line of vertical padding in the graph.  It
+  is similar to `graph_next_line()`, but is guaranteed to never print the line
+  containing the current commit.  Where `graph_next_line()` would print the
+  commit line next, `graph_padding_line()` prints a line that simply extends
+  all branch lines downwards one row, leaving their positions unchanged.
+
+* `graph_is_commit_finished()` determines if the graph has output all lines
+  necessary for the current commit.  If `graph_update()` is called before all
+  lines for the current commit have been printed, the next call to
+  `graph_next_line()` will output an ellipsis, to indicate that a portion of
+  the graph was omitted.
+
+The following utility functions are wrappers around `graph_next_line()` and
+`graph_is_commit_finished()`.  They always print the output to stdout.
+They can all be called with a NULL graph argument, in which case no graph
+output will be printed.
+
+* `graph_show_commit()` calls `graph_next_line()` until it returns non-zero.
+  This prints all graph lines up to, and including, the line containing this
+  commit.  Output is printed to stdout.  The last line printed does not contain
+  a terminating newline.  This should not be called if the commit line has
+  already been printed, or it will loop forever.
+
+* `graph_show_oneline()` calls `graph_next_line()` and prints the result to
+  stdout.  The line printed does not contain a terminating newline.
+
+* `graph_show_padding()` calls `graph_padding_line()` and prints the result to
+  stdout.  The line printed does not contain a terminating newline.
+
+* `graph_show_remainder()` calls `graph_next_line()` until
+  `graph_is_commit_finished()` returns non-zero.  Output is printed to stdout.
+  The last line printed does not contain a terminating newline.  Returns 1 if
+  output was printed, and 0 if no output was necessary.
+
+* `graph_show_strbuf()` prints the specified strbuf to stdout, prefixing all
+  lines but the first with a graph line.  The caller is responsible for
+  ensuring graph output for the first line has already been printed to stdout.
+  (This can be done with `graph_show_commit()` or `graph_show_oneline()`.)  If
+  a NULL graph is supplied, the strbuf is printed as-is.
+
+* `graph_show_commit_msg()` is similar to `graph_show_strbuf()`, but it also
+  prints the remainder of the graph, if more lines are needed after the strbuf
+  ends.  It is better than directly calling `graph_show_strbuf()` followed by
+  `graph_show_remainder()` since it properly handles buffers that do not end in
+  a terminating newline.  The output printed by `graph_show_commit_msg()` will
+  end in a newline if and only if the strbuf ends in a newline.
+
+Data structure
+--------------
+`struct git_graph` is an opaque data type used to store the current graph
+state.
+
+Calling sequence
+----------------
+
+* Create a `struct git_graph` by calling `graph_init()`.  When using the
+  revision walking API, this is done automatically by `setup_revisions()` if
+  the '--graph' option is supplied.
+
+* Use the revision walking API to walk through a group of contiguous commits.
+  The `get_revision()` function automatically calls `graph_update()` each time
+  it is invoked.
+
+* For each commit, call `graph_next_line()` repeatedly, until
+  `graph_is_commit_finished()` returns non-zero.  Each call go
+  `graph_next_line()` will output a single line of the graph.  The resulting
+  lines will not contain any newlines.  `graph_next_line()` returns 1 if the
+  resulting line contains the current commit, or 0 if this is merely a line
+  needed to adjust the graph before or after the current commit.  This return
+  value can be used to determine where to print the commit summary information
+  alongside the graph output.
+
+Limitations
+-----------
+
+* `graph_update()` must be called with commits in topological order.  It should
+  not be called on a commit if it has already been invoked with an ancestor of
+  that commit, or the graph output will be incorrect.
+
+* `graph_update()` must be called on a contiguous group of commits.  If
+  `graph_update()` is called on a particular commit, it should later be called
+  on all parents of that commit.  Parents must not be skipped, or the graph
+  output will appear incorrect.
++
+`graph_update()` may be used on a pruned set of commits only if the parent list
+has been rewritten so as to include only ancestors from the pruned set.
+
+* The graph API does not currently support reverse commit ordering.  In
+  order to implement reverse ordering, the graphing API needs an
+  (efficient) mechanism to find the children of a commit.
+
+Sample usage
+------------
+
+------------
+struct commit *commit;
+struct git_graph *graph = graph_init(opts);
+
+while ((commit = get_revision(opts)) != NULL) {
+	graph_update(graph, commit);
+	while (!graph_is_commit_finished(graph))
+	{
+		struct strbuf sb;
+		int is_commit_line;
+
+		strbuf_init(&sb, 0);
+		is_commit_line = graph_next_line(graph, &sb);
+		fputs(sb.buf, stdout);
+
+		if (is_commit_line)
+			log_tree_commit(opts, commit);
+		else
+			putchar(opts->diffopt.line_termination);
+	}
+}
+
+graph_release(graph);
+------------
+
+Sample output
+-------------
+
+The following is an example of the output from the graph API.  This output does
+not include any commit summary information--callers are responsible for
+outputting that information, if desired.
+
+------------
+*
+*
+M
+|\
+* |
+| | *
+| \ \
+|  \ \
+M-. \ \
+|\ \ \ \
+| | * | |
+| | | | | *
+| | | | | *
+| | | | | M
+| | | | | |\
+| | | | | | *
+| * | | | | |
+| | | | | M  \
+| | | | | |\  |
+| | | | * | | |
+| | | | * | | |
+* | | | | | | |
+| |/ / / / / /
+|/| / / / / /
+* | | | | | |
+|/ / / / / /
+* | | | | |
+| | | | | *
+| | | | |/
+| | | | *
+------------
diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index b7cda94..539863b 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -1,6 +1,206 @@
 parse-options API
 =================
 
-Talk about <parse-options.h>
+The parse-options API is used to parse and massage options in git
+and to provide a usage help with consistent look.
 
-(Pierre)
+Basics
+------
+
+The argument vector `argv[]` may usually contain mandatory or optional
+'non-option arguments', e.g. a filename or a branch, and 'options'.
+Options are optional arguments that start with a dash and
+that allow to change the behavior of a command.
+
+* There are basically three types of options:
+  'boolean' options,
+  options with (mandatory) 'arguments' and
+  options with 'optional arguments'
+  (i.e. a boolean option that can be adjusted).
+
+* There are basically two forms of options:
+  'Short options' consist of one dash (`-`) and one alphanumeric
+  character.
+  'Long options' begin with two dashes (`\--`) and some
+  alphanumeric characters.
+
+* Options are case-sensitive.
+  Please define 'lower-case long options' only.
+
+The parse-options API allows:
+
+* 'sticked' and 'separate form' of options with arguments.
+  `-oArg` is sticked, `-o Arg` is separate form.
+  `\--option=Arg` is sticked, `\--option Arg` is separate form.
+
+* Long options may be 'abbreviated', as long as the abbreviation
+  is unambiguous.
+
+* Short options may be bundled, e.g. `-a -b` can be specified as `-ab`.
+
+* Boolean long options can be 'negated' (or 'unset') by prepending
+  `no-`, e.g. `\--no-abbrev` instead of `\--abbrev`.
+
+* Options and non-option arguments can clearly be separated using the `\--`
+  option, e.g. `-a -b \--option \-- \--this-is-a-file` indicates that
+  `\--this-is-a-file` must not be processed as an option.
+
+Steps to parse options
+----------------------
+
+. `#include "parse-options.h"`
+
+. define a NULL-terminated
+  `static const char * const builtin_foo_usage[]` array
+  containing alternative usage strings
+
+. define `builtin_foo_options` array as described below
+  in section 'Data Structure'.
+
+. in `cmd_foo(int argc, const char **argv, const char *prefix)`
+  call
+
+	argc = parse_options(argc, argv, builtin_foo_options, builtin_foo_usage, flags);
++
+`parse_options()` will filter out the processed options of `argv[]` and leave the
+non-option arguments in `argv[]`.
+`argc` is updated appropriately because of the assignment.
++
+Flags are the bitwise-or of:
+
+`PARSE_OPT_KEEP_DASHDASH`::
+	Keep the `\--` that usually separates options from
+	non-option arguments.
+
+`PARSE_OPT_STOP_AT_NON_OPTION`::
+	Usually the whole argument vector is massaged and reordered.
+	Using this flag, processing is stopped at the first non-option
+	argument.
+
+Data Structure
+--------------
+
+The main data structure is an array of the `option` struct,
+say `static struct option builtin_add_options[]`.
+There are some macros to easily define options:
+
+`OPT__ABBREV(&int_var)`::
+	Add `\--abbrev[=<n>]`.
+
+`OPT__DRY_RUN(&int_var)`::
+	Add `-n, \--dry-run`.
+
+`OPT__QUIET(&int_var)`::
+	Add `-q, \--quiet`.
+
+`OPT__VERBOSE(&int_var)`::
+	Add `-v, \--verbose`.
+
+`OPT_GROUP(description)`::
+	Start an option group. `description` is a short string that
+	describes the group or an empty string.
+	Start the description with an upper-case letter.
+
+`OPT_BOOLEAN(short, long, &int_var, description)`::
+	Introduce a boolean option.
+	`int_var` is incremented on each use.
+
+`OPT_BIT(short, long, &int_var, description, mask)`::
+	Introduce a boolean option.
+	If used, `int_var` is bitwise-ored with `mask`.
+
+`OPT_SET_INT(short, long, &int_var, description, integer)`::
+	Introduce a boolean option.
+	If used, set `int_var` to `integer`.
+
+`OPT_SET_PTR(short, long, &ptr_var, description, ptr)`::
+	Introduce a boolean option.
+	If used, set `ptr_var` to `ptr`.
+
+`OPT_STRING(short, long, &str_var, arg_str, description)`::
+	Introduce an option with string argument.
+	The string argument is put into `str_var`.
+
+`OPT_INTEGER(short, long, &int_var, description)`::
+	Introduce an option with integer argument.
+	The integer is put into `int_var`.
+
+`OPT_DATE(short, long, &int_var, description)`::
+	Introduce an option with date argument, see `approxidate()`.
+	The timestamp is put into `int_var`.
+
+`OPT_CALLBACK(short, long, &var, arg_str, description, func_ptr)`::
+	Introduce an option with argument.
+	The argument will be fed into the function given by `func_ptr`
+	and the result will be put into `var`.
+	See 'Option Callbacks' below for a more elaborate description.
+
+`OPT_ARGUMENT(long, description)`::
+	Introduce a long-option argument that will be kept in `argv[]`.
+
+
+The last element of the array must be `OPT_END()`.
+
+If not stated otherwise, interpret the arguments as follows:
+
+* `short` is a character for the short option
+  (e.g. `\'e\'` for `-e`, use `0` to omit),
+
+* `long` is a string for the long option
+  (e.g. `"example"` for `\--example`, use `NULL` to omit),
+
+* `int_var` is an integer variable,
+
+* `str_var` is a string variable (`char *`),
+
+* `arg_str` is the string that is shown as argument
+  (e.g. `"branch"` will result in `<branch>`).
+  If set to `NULL`, three dots (`...`) will be displayed.
+
+* `description` is a short string to describe the effect of the option.
+  It shall begin with a lower-case letter and a full stop (`.`) shall be
+  omitted at the end.
+
+Option Callbacks
+----------------
+
+The function must be defined in this form:
+
+	int func(const struct option *opt, const char *arg, int unset)
+
+The callback mechanism is as follows:
+
+* Inside `funct`, the only interesting member of the structure
+  given by `opt` is the void pointer `opt->value`.
+  `\*opt->value` will be the value that is saved into `var`, if you
+  use `OPT_CALLBACK()`.
+  For example, do `*(unsigned long *)opt->value = 42;` to get 42
+  into an `unsigned long` variable.
+
+* Return value `0` indicates success and non-zero return
+  value will invoke `usage_with_options()` and, thus, die.
+
+* If the user negates the option, `arg` is `NULL` and `unset` is 1.
+
+Sophisticated option parsing
+----------------------------
+
+If you need, for example, option callbacks with optional arguments
+or without arguments at all, or if you need other special cases,
+that are not handled by the macros above, you need to specify the
+members of the `option` structure manually.
+
+This is not covered in this document, but well documented
+in `parse-options.h` itself.
+
+Examples
+--------
+
+See `test-parse-options.c` and
+`builtin-add.c`,
+`builtin-clone.c`,
+`builtin-commit.c`,
+`builtin-fetch.c`,
+`builtin-fsck.c`,
+`builtin-rm.c`
+for real-world examples.
diff --git a/Documentation/technical/api-path-list.txt b/Documentation/technical/api-path-list.txt
index d077683..9dbedd0 100644
--- a/Documentation/technical/api-path-list.txt
+++ b/Documentation/technical/api-path-list.txt
@@ -1,9 +1,126 @@
 path-list API
 =============
 
-Talk about <path-list.h>, things like
+The path_list API offers a data structure and functions to handle sorted
+and unsorted string lists.
 
-* it is not just paths but strings in general;
-* the calling sequence.
+The name is a bit misleading, a path_list may store not only paths but
+strings in general.
 
-(Dscho)
+The caller:
+
+. Allocates and clears a `struct path_list` variable.
+
+. Initializes the members. You might want to set the flag `strdup_paths`
+  if the strings should be strdup()ed. For example, this is necessary
+  when you add something like git_path("..."), since that function returns
+  a static buffer that will change with the next call to git_path().
++
+If you need something advanced, you can manually malloc() the `items`
+member (you need this if you add things later) and you should set the
+`nr` and `alloc` members in that case, too.
+
+. Adds new items to the list, using `path_list_append` or `path_list_insert`.
+
+. Can check if a string is in the list using `path_list_has_path` or
+  `unsorted_path_list_has_path` and get it from the list using
+  `path_list_lookup` for sorted lists.
+
+. Can sort an unsorted list using `sort_path_list`.
+
+. Finally it should free the list using `path_list_clear`.
+
+Example:
+
+----
+struct path_list list;
+int i;
+
+memset(&list, 0, sizeof(struct path_list));
+path_list_append("foo", &list);
+path_list_append("bar", &list);
+for (i = 0; i < list.nr; i++)
+	printf("%s\n", list.items[i].path)
+----
+
+NOTE: It is more efficient to build an unsorted list and sort it
+afterwards, instead of building a sorted list (`O(n log n)` instead of
+`O(n^2)`).
++
+However, if you use the list to check if a certain string was added
+already, you should not do that (using unsorted_path_list_has_path()),
+because the complexity would be quadratic again (but with a worse factor).
+
+Functions
+---------
+
+* General ones (works with sorted and unsorted lists as well)
+
+`print_path_list`::
+
+	Dump a path_list to stdout, useful mainly for debugging purposes. It
+	can take an optional header argument and it writes out the
+	string-pointer pairs of the path_list, each one in its own line.
+
+`path_list_clear`::
+
+	Free a path_list. The `path` pointer of the items will be freed in case
+	the `strdup_paths` member of the path_list is set. The second parameter
+	controls if the `util` pointer of the items should be freed or not.
+
+* Functions for sorted lists only
+
+`path_list_has_path`::
+
+	Determine if the path_list has a given string or not.
+
+`path_list_insert`::
+
+	Insert a new element to the path_list. The returned pointer can be handy
+	if you want to write something to the `util` pointer of the
+	path_list_item containing the just added string.
++
+Since this function uses xrealloc() (which die()s if it fails) if the
+list needs to grow, it is safe not to check the pointer. I.e. you may
+write `path_list_insert(...)->util = ...;`.
+
+`path_list_lookup`::
+
+	Look up a given string in the path_list, returning the containing
+	path_list_item. If the string is not found, NULL is returned.
+
+* Functions for unsorted lists only
+
+`path_list_append`::
+
+	Append a new string to the end of the path_list.
+
+`sort_path_list`::
+
+	Make an unsorted list sorted.
+
+`unsorted_path_list_has_path`::
+
+	It's like `path_list_has_path()` but for unsorted lists.
++
+This function needs to look through all items, as opposed to its
+counterpart for sorted lists, which performs a binary search.
+
+Data structures
+---------------
+
+* `struct path_list_item`
+
+Represents an item of the list. The `path` member is a pointer to the
+string, and you may use the `util` member for any purpose, if you want.
+
+* `struct path_list`
+
+Represents the list itself.
+
+. The array of items are available via the `items` member.
+. The `nr` member contains the number of items stored in the list.
+. The `alloc` member is used to avoid reallocating at every insertion.
+  You should not tamper with it.
+. Setting the `strdup_paths` member to 1 will strdup() the strings
+  before adding them, see above.
diff --git a/Documentation/technical/api-revision-walking.txt b/Documentation/technical/api-revision-walking.txt
index 01a2455..996da05 100644
--- a/Documentation/technical/api-revision-walking.txt
+++ b/Documentation/technical/api-revision-walking.txt
@@ -1,9 +1,67 @@
 revision walking API
 ====================
 
+The revision walking API offers functions to build a list of revisions
+and then iterate over that list.
+
+Calling sequence
+----------------
+
+The walking API has a given calling sequence: first you need to
+initialize a rev_info structure, then add revisions to control what kind
+of revision list do you want to get, finally you can iterate over the
+revision list.
+
+Functions
+---------
+
+`init_revisions`::
+
+	Initialize a rev_info structure with default values. The second
+	parameter may be NULL or can be prefix path, and then the `.prefix`
+	variable will be set to it. This is typically the first function you
+	want to call when you want to deal with a revision list. After calling
+	this function, you are free to customize options, like set
+	`.ignore_merges` to 0 if you don't want to ignore merges, and so on. See
+	`revision.h` for a complete list of available options.
+
+`add_pending_object`::
+
+	This function can be used if you want to add commit objects as revision
+	information. You can use the `UNINTERESTING` object flag to indicate if
+	you want to include or exclude the given commit (and commits reachable
+	from the given commit) from the revision list.
++
+NOTE: If you have the commits as a string list then you probably want to
+use setup_revisions(), instead of parsing each string and using this
+function.
+
+`setup_revisions`::
+
+	Parse revision information, filling in the `rev_info` structure, and
+	removing the used arguments from the argument list. Returns the number
+	of arguments left that weren't recognized, which are also moved to the
+	head of the argument list. The last parameter is used in case no
+	parameter given by the first two arguments.
+
+`prepare_revision_walk`::
+
+	Prepares the rev_info structure for a walk. You should check if it
+	returns any error (non-zero return code) and if it does not, you can
+	start using get_revision() to do the iteration.
+
+`get_revision`::
+
+	Takes a pointer to a `rev_info` structure and iterates over it,
+	returning a `struct commit *` each time you call it. The end of the
+	revision list is indicated by returning a NULL pointer.
+
+Data structures
+---------------
+
 Talk about <revision.h>, things like:
 
 * two diff_options, one for path limiting, another for output;
-* calling sequence: init_revisions(), setup_revsions(), get_revision();
+* remaining functions;
 
 (Linus, JC, Dscho)
diff --git a/Documentation/technical/api-run-command.txt b/Documentation/technical/api-run-command.txt
index c364a22..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
@@ -63,7 +63,7 @@
 
 The caller:
 
-1. allocates and clears (memset(&chld, '0', sizeof(chld));) a
+1. allocates and clears (memset(&chld, 0, sizeof(chld));) a
    struct child_process variable;
 2. initializes the members;
 3. calls start_command();
@@ -136,7 +136,7 @@
 
 The caller:
 
-1. allocates and clears (memset(&asy, '0', sizeof(asy));) a
+1. allocates and clears (memset(&asy, 0, sizeof(asy));) a
    struct async variable;
 2. initializes .proc and .data;
 3. calls start_async();
diff --git a/Documentation/technical/api-strbuf.txt b/Documentation/technical/api-strbuf.txt
index a52e4f3..a9668e5 100644
--- a/Documentation/technical/api-strbuf.txt
+++ b/Documentation/technical/api-strbuf.txt
@@ -1,6 +1,241 @@
 strbuf API
 ==========
 
-Talk about <strbuf.h>
+strbuf's are meant to be used with all the usual C string and memory
+APIs. Given that the length of the buffer is known, it's often better to
+use the mem* functions than a str* one (memchr vs. strchr e.g.).
+Though, one has to be careful about the fact that str* functions often
+stop on NULs and that strbufs may have embedded NULs.
 
-(Pierre, JC)
+An strbuf is NUL terminated for convenience, but no function in the
+strbuf API actually relies on the string being free of NULs.
+
+strbufs has some invariants that are very important to keep in mind:
+
+. The `buf` member is never NULL, so you it can be used in any usual C
+string operations safely. strbuf's _have_ to be initialized either by
+`strbuf_init()` or by `= STRBUF_INIT` before the invariants, though.
++
+Do *not* assume anything on what `buf` really is (e.g. if it is
+allocated memory or not), use `strbuf_detach()` to unwrap a memory
+buffer from its strbuf shell in a safe way. That is the sole supported
+way. This will give you a malloced buffer that you can later `free()`.
++
+However, it it totally safe to modify anything in the string pointed by
+the `buf` member, between the indices `0` and `len-1` (inclusive).
+
+. The `buf` member is a byte array that has at least `len + 1` bytes
+  allocated. The extra byte is used to store a `'\0'`, allowing the
+  `buf` member to be a valid C-string. Every strbuf function ensure this
+  invariant is preserved.
++
+NOTE: It is OK to "play" with the buffer directly if you work it this
+      way:
++
+----
+strbuf_grow(sb, SOME_SIZE); <1>
+strbuf_setlen(sb, sb->len + SOME_OTHER_SIZE);
+----
+<1> Here, the memory array starting at `sb->buf`, and of length
+`strbuf_avail(sb)` is all yours, and you can be sure that
+`strbuf_avail(sb)` is at least `SOME_SIZE`.
++
+NOTE: `SOME_OTHER_SIZE` must be smaller or equal to `strbuf_avail(sb)`.
++
+Doing so is safe, though if it has to be done in many places, adding the
+missing API to the strbuf module is the way to go.
++
+WARNING: Do _not_ assume that the area that is yours is of size `alloc
+- 1` even if it's true in the current implementation. Alloc is somehow a
+"private" member that should not be messed with. Use `strbuf_avail()`
+instead.
+
+Data structures
+---------------
+
+* `struct strbuf`
+
+This is string buffer structure. The `len` member can be used to
+determine the current length of the string, and `buf` member provides access to
+the string itself.
+
+Functions
+---------
+
+* Life cycle
+
+`strbuf_init`::
+
+	Initialize the structure. The second parameter can be zero or a bigger
+	number to allocate memory, in case you want to prevent further reallocs.
+
+`strbuf_release`::
+
+	Release a string buffer and the memory it used. You should not use the
+	string buffer after using this function, unless you initialize it again.
+
+`strbuf_detach`::
+
+	Detach the string from the strbuf and returns it; you now own the
+	storage the string occupies and it is your responsibility from then on
+	to release it with `free(3)` when you are done with it.
+
+`strbuf_attach`::
+
+	Attach a string to a buffer. You should specify the string to attach,
+	the current length of the string and the amount of allocated memory.
+	The amount must be larger than the string length, because the string you
+	pass is supposed to be a NUL-terminated string.  This string _must_ be
+	malloc()ed, and after attaching, the pointer cannot be relied upon
+	anymore, and neither be free()d directly.
+
+`strbuf_swap`::
+
+	Swap the contents of two string buffers.
+
+* Related to the size of the buffer
+
+`strbuf_avail`::
+
+	Determine the amount of allocated but unused memory.
+
+`strbuf_grow`::
+
+	Ensure that at least this amount of unused memory is available after
+	`len`. This is used when you know a typical size for what you will add
+	and want to avoid repetitive automatic resizing of the underlying buffer.
+	This is never a needed operation, but can be critical for performance in
+	some cases.
+
+`strbuf_setlen`::
+
+	Set the length of the buffer to a given value. This function does *not*
+	allocate new memory, so you should not perform a `strbuf_setlen()` to a
+	length that is larger than `len + strbuf_avail()`. `strbuf_setlen()` is
+	just meant as a 'please fix invariants from this strbuf I just messed
+	with'.
+
+`strbuf_reset`::
+
+	Empty the buffer by setting the size of it to zero.
+
+* Related to the contents of the buffer
+
+`strbuf_rtrim`::
+
+	Strip whitespace from the end of a string.
+
+`strbuf_cmp`::
+
+	Compare two buffers. Returns an integer less than, equal to, or greater
+	than zero if the first buffer is found, respectively, to be less than,
+	to match, or be greater than the second buffer.
+
+* Adding data to the buffer
+
+NOTE: All of these functions in this section will grow the buffer as
+      necessary.
+
+`strbuf_addch`::
+
+	Add a single character to the buffer.
+
+`strbuf_insert`::
+
+	Insert data to the given position of the buffer. The remaining contents
+	will be shifted, not overwritten.
+
+`strbuf_remove`::
+
+	Remove given amount of data from a given position of the buffer.
+
+`strbuf_splice`::
+
+	Remove the bytes between `pos..pos+len` and replace it with the given
+	data.
+
+`strbuf_add`::
+
+	Add data of given length to the buffer.
+
+`strbuf_addstr`::
+
+Add a NUL-terminated string to the buffer.
++
+NOTE: This function will *always* be implemented as an inline or a macro
+that expands to:
++
+----
+strbuf_add(..., s, strlen(s));
+----
++
+Meaning that this is efficient to write things like:
++
+----
+strbuf_addstr(sb, "immediate string");
+----
+
+`strbuf_addbuf`::
+
+	Copy the contents of an other buffer at the end of the current one.
+
+`strbuf_adddup`::
+
+	Copy part of the buffer from a given position till a given length to the
+	end of the buffer.
+
+`strbuf_expand`::
+
+	This function can be used to expand a format string containing
+	placeholders. To that end, it parses the string and calls the specified
+	function for every percent sign found.
++
+The callback function is given a pointer to the character after the `%`
+and a pointer to the struct strbuf.  It is expected to add the expanded
+version of the placeholder to the strbuf, e.g. to add a newline
+character if the letter `n` appears after a `%`.  The function returns
+the length of the placeholder recognized and `strbuf_expand()` skips
+over it.
++
+All other characters (non-percent and not skipped ones) are copied
+verbatim to the strbuf.  If the callback returned zero, meaning that the
+placeholder is unknown, then the percent sign is copied, too.
++
+In order to facilitate caching and to make it possible to give
+parameters to the callback, `strbuf_expand()` passes a context pointer,
+which can be used by the programmer of the callback as she sees fit.
+
+`strbuf_addf`::
+
+	Add a formatted string to the buffer.
+
+`strbuf_fread`::
+
+	Read a given size of data from a FILE* pointer to the buffer.
++
+NOTE: The buffer is rewinded if the read fails. If -1 is returned,
+`errno` must be consulted, like you would do for `read(3)`.
+`strbuf_read()`, `strbuf_read_file()` and `strbuf_getline()` has the
+same behaviour as well.
+
+`strbuf_read`::
+
+	Read the contents of a given file descriptor. The third argument can be
+	used to give a hint about the file size, to avoid reallocs.
+
+`strbuf_read_file`::
+
+	Read the contents of a file, specified by its path. The third argument
+	can be used to give a hint about the file size, to avoid reallocs.
+
+`strbuf_getline`::
+
+	Read a line from a FILE* pointer. The second argument specifies the line
+	terminator character, typically `'\n'`.
+
+`stripspace`::
+
+	Strip whitespace from a buffer. The second parameter controls if
+	comments are considered contents to be removed or not.
+
+`launch_editor`::
diff --git a/Documentation/urls-remotes.txt b/Documentation/urls-remotes.txt
index 5dd1f83..9975300 100644
--- a/Documentation/urls-remotes.txt
+++ b/Documentation/urls-remotes.txt
@@ -1,11 +1,46 @@
 include::urls.txt[]
 
-REMOTES
--------
+REMOTES[[REMOTES]]
+------------------
 
-In addition to the above, as a short-hand, the name of a
-file in `$GIT_DIR/remotes` directory can be given; the
-named file should be in the following format:
+The name of one of the following can be used instead
+of a URL as `<repository>` argument:
+
+* a remote in the git configuration file: `$GIT_DIR/config`,
+* a file in the `$GIT_DIR/remotes` directory, or
+* a file in the `$GIT_DIR/branches` directory.
+
+All of these also allow you to omit the refspec from the command line
+because they each contain a refspec which git will use by default.
+
+Named remote in configuration file
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can choose to provide the name of a remote which you had previously
+configured using linkgit:git-remote[1], linkgit:git-config[1]
+or even by a manual edit to the `$GIT_DIR/config` file.  The URL of
+this remote will be used to access the repository.  The refspec
+of this remote will be used by default when you do
+not provide a refspec on the command line.  The entry in the
+config file would appear like this:
+
+------------
+	[remote "<name>"]
+		url = <url>
+		push = <refspec>
+		fetch = <refspec>
+------------
+
+
+Named file in `$GIT_DIR/remotes`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can choose to provide the name of a
+file in `$GIT_DIR/remotes`.  The URL
+in this file will be used to access the repository.  The refspec
+in this file will be used as default when you do not
+provide a refspec on the command line.  This file should have the
+following format:
 
 ------------
 	URL: one of the above URL format
@@ -14,42 +49,34 @@
 
 ------------
 
-Then such a short-hand is specified in place of
-<repository> without <refspec> parameters on the command
-line, <refspec> specified on `Push:` lines or `Pull:`
-lines are used for `git-push` and `git-fetch`/`git-pull`,
-respectively.  Multiple `Push:` and `Pull:` lines may
+`Push:` lines are used by `git-push` and
+`Pull:` lines are used by `git-pull` and `git-fetch`.
+Multiple `Push:` and `Pull:` lines may
 be specified for additional branch mappings.
 
-Or, equivalently, in the `$GIT_DIR/config` (note the use
-of `fetch` instead of `Pull:`):
+Named file in `$GIT_DIR/branches`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can choose to provide the name of a
+file in `$GIT_DIR/branches`.
+The URL in this file will be used to access the repository.
+This file should have the following format:
+
 
 ------------
-	[remote "<remote>"]
-		url = <url>
-		push = <refspec>
-		fetch = <refspec>
-
+	<url>#<head>
 ------------
 
-The name of a file in `$GIT_DIR/branches` directory can be
-specified as an older notation short-hand; the named
-file should contain a single line, a URL in one of the
-above formats, optionally followed by a hash `#` and the
-name of remote head (URL fragment notation).
-`$GIT_DIR/branches/<remote>` file that stores a <url>
-without the fragment is equivalent to have this in the
-corresponding file in the `$GIT_DIR/remotes/` directory.
+`<url>` is required; `#<head>` is optional.
+When you do not provide a refspec on the command line,
+git will use the following refspec, where `<head>` defaults to `master`,
+and `<repository>` is the name of this file
+you provided in the command line.
 
 ------------
-	URL: <url>
-	Pull: refs/heads/master:<remote>
-
+	refs/heads/<head>:<repository>
 ------------
 
-while having `<url>#<head>` is equivalent to
 
-------------
-	URL: <url>
-	Pull: refs/heads/<head>:<remote>
-------------
+
+
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index 86b91a5..49a4a89 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -1254,16 +1254,15 @@
 
 -------------------------------------------------
 $ git show :1:file.txt	# the file in a common ancestor of both branches
-$ git show :2:file.txt	# the version from HEAD, but including any
-			# nonconflicting changes from MERGE_HEAD
-$ git show :3:file.txt	# the version from MERGE_HEAD, but including any
-			# nonconflicting changes from HEAD.
+$ git show :2:file.txt	# the version from HEAD.
+$ git show :3:file.txt	# the version from MERGE_HEAD.
 -------------------------------------------------
 
-Since the stage 2 and stage 3 versions have already been updated with
-nonconflicting changes, the only remaining differences between them are
-the important ones; thus linkgit:git-diff[1] can use the information in
-the index to show only those conflicts.
+When you ask linkgit:git-diff[1] to show the conflicts, it runs a
+three-way diff between the conflicted merge results in the work tree with
+stages 2 and 3 to show only hunks whose contents come from both sides,
+mixed (in other words, when a hunk's merge results come only from stage 2,
+that part is not conflicting and is not shown.  Same for stage 3).
 
 The diff above shows the differences between the working-tree version of
 file.txt and the stage 2 and stage 3 versions.  So instead of preceding
@@ -1881,7 +1880,7 @@
 
 (For an explanation of the last two lines, see
 linkgit:git-update-server-info[1], and the documentation
-link:hooks.html[Hooks used by git].)
+linkgit:githooks[5][Hooks used by git].)
 
 Advertise the URL of proj.git.  Anybody else should then be able to
 clone or pull from that URL, for example with a command line like:
@@ -1993,7 +1992,7 @@
 solution is to retry the push after first updating your work by either a
 pull or a fetch followed by a rebase; see the
 <<setting-up-a-shared-repository,next section>> and
-link:cvs-migration.html[git for CVS users] for more.
+linkgit:gitcvs-migration[7][git for CVS users] for more.
 
 [[setting-up-a-shared-repository]]
 Setting up a shared repository
@@ -2002,7 +2001,7 @@
 Another way to collaborate is by using a model similar to that
 commonly used in CVS, where several developers with special rights
 all push to and pull from a single shared repository.  See
-link:cvs-migration.html[git for CVS users] for instructions on how to
+linkgit:gitcvs-migration[7][git for CVS users] for instructions on how to
 set this up.
 
 However, while there is nothing wrong with git's support for shared
@@ -2813,7 +2812,7 @@
 -------------------------------------------------
 
 Don't do this unless you're sure you won't mind "git fetch" possibly
-throwing away commits on mybranch.
+throwing away commits on 'example/master'.
 
 Also note that all of the above configuration can be performed by
 directly editing the file .git/config instead of using
@@ -4252,7 +4251,10 @@
 itself!
 
 [[glossary]]
-include::glossary.txt[]
+GIT Glossary
+============
+
+include::glossary-content.txt[]
 
 [[git-quick-start]]
 Appendix A: Git Quick Reference
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index af9d78d..445dca3 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.5.5.5.GIT
+DEF_VER=v1.5.6.5.GIT
 
 LF='
 '
@@ -11,7 +11,7 @@
 if test -f version
 then
 	VN=$(cat version) || VN="$DEF_VER"
-elif test -d .git &&
+elif test -d .git -o -f .git &&
 	VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
 	case "$VN" in
 	*$LF*) (exit 1) ;;
diff --git a/INSTALL b/INSTALL
index 6f3bcb4..4a4e13f 100644
--- a/INSTALL
+++ b/INSTALL
@@ -38,6 +38,10 @@
    has been actively developed since 1997, and people have moved over to
    graphical file managers.
 
+   NOTE: As of gnuit-4.9.2, the GNU interactive tools package has been
+         renamed. You can compile gnuit with the --disable-transition
+         option and then it will not conflict with git.
+
  - You can use git after building but without installing if you
    wanted to.  Various git commands need to find other git
    commands and scripts to do their work, so you would need to
@@ -63,10 +67,10 @@
 	  that come with git (git includes the one from Mozilla, and has
 	  its own PowerPC and ARM optimized ones too - see the Makefile).
 
-	- "libcurl" and "curl" executable.  git-http-fetch and
-	  git-fetch use them.  If you do not use http
-	  transfer, you are probably OK if you do not have
-	  them.
+	- libcurl library; git-http-fetch and git-fetch use them.  You
+	  might also want the "curl" executable for debugging purposes.
+	  If you do not use http transfer, you are probably OK if you
+	  do not have them.
 
 	- expat library; git-http-push uses it for remote lock
 	  management over DAV.  Similar to "curl" above, this is optional.
@@ -79,9 +83,6 @@
 	- "perl" and POSIX-compliant shells are needed to use most of
 	  the barebone Porcelainish scripts.
 
-	- "cpio" is used by git-clone when doing a local (possibly
-	  hardlinked) clone.
-
  - Some platform specific issues are dealt with Makefile rules,
    but depending on your specific installation, you may not
    have all the libraries/tools needed, or you may have
diff --git a/Makefile b/Makefile
index 7c70b00..f13184b 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@
 # Define NO_OPENSSL environment variable if you do not have OpenSSL.
 # This also implies MOZILLA_SHA1.
 #
-# Define NO_CURL if you do not have curl installed.  git-http-pull and
+# Define NO_CURL if you do not have libcurl installed.  git-http-pull and
 # git-http-push are not built, and you cannot use http:// and https://
 # transports.
 #
@@ -189,6 +189,7 @@
 
 # default configuration for gitweb
 GITWEB_CONFIG = gitweb_config.perl
+GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf
 GITWEB_HOME_LINK_STR = projects
 GITWEB_SITENAME =
 GITWEB_PROJECTROOT = /pub/git
@@ -234,7 +235,6 @@
 
 SCRIPT_SH += git-am.sh
 SCRIPT_SH += git-bisect.sh
-SCRIPT_SH += git-clone.sh
 SCRIPT_SH += git-filter-branch.sh
 SCRIPT_SH += git-lost-found.sh
 SCRIPT_SH += git-merge-octopus.sh
@@ -345,6 +345,7 @@
 LIB_H += dir.h
 LIB_H += fsck.h
 LIB_H += git-compat-util.h
+LIB_H += graph.h
 LIB_H += grep.h
 LIB_H += hash.h
 LIB_H += list-objects.h
@@ -365,6 +366,7 @@
 LIB_H += remote.h
 LIB_H += revision.h
 LIB_H += run-command.h
+LIB_H += sha1-lookup.h
 LIB_H += sideband.h
 LIB_H += strbuf.h
 LIB_H += tag.h
@@ -373,6 +375,7 @@
 LIB_H += tree-walk.h
 LIB_H += unpack-trees.h
 LIB_H += utf8.h
+LIB_H += wt-status.h
 
 LIB_OBJS += alias.o
 LIB_OBJS += alloc.o
@@ -402,6 +405,7 @@
 LIB_OBJS += diffcore-pickaxe.o
 LIB_OBJS += diffcore-rename.o
 LIB_OBJS += diff-delta.o
+LIB_OBJS += diff-no-index.o
 LIB_OBJS += diff-lib.o
 LIB_OBJS += diff.o
 LIB_OBJS += dir.o
@@ -409,6 +413,7 @@
 LIB_OBJS += environment.o
 LIB_OBJS += exec_cmd.o
 LIB_OBJS += fsck.o
+LIB_OBJS += graph.o
 LIB_OBJS += grep.o
 LIB_OBJS += hash.o
 LIB_OBJS += help.o
@@ -421,6 +426,7 @@
 LIB_OBJS += mailmap.o
 LIB_OBJS += match-trees.o
 LIB_OBJS += merge-file.o
+LIB_OBJS += name-hash.o
 LIB_OBJS += object.o
 LIB_OBJS += pack-check.o
 LIB_OBJS += pack-revindex.o
@@ -445,6 +451,7 @@
 LIB_OBJS += server-info.o
 LIB_OBJS += setup.o
 LIB_OBJS += sha1_file.o
+LIB_OBJS += sha1-lookup.o
 LIB_OBJS += sha1_name.o
 LIB_OBJS += shallow.o
 LIB_OBJS += sideband.o
@@ -478,6 +485,7 @@
 BUILTIN_OBJS += builtin-checkout-index.o
 BUILTIN_OBJS += builtin-checkout.o
 BUILTIN_OBJS += builtin-clean.o
+BUILTIN_OBJS += builtin-clone.o
 BUILTIN_OBJS += builtin-commit-tree.o
 BUILTIN_OBJS += builtin-commit.o
 BUILTIN_OBJS += builtin-config.o
@@ -556,6 +564,45 @@
 ifeq ($(uname_S),GNU/kFreeBSD)
 	NO_STRLCPY = YesPlease
 endif
+ifeq ($(uname_S),UnixWare)
+	CC = cc
+	NEEDS_SOCKET = YesPlease
+	NEEDS_NSL = YesPlease
+	NEEDS_SSL_WITH_CRYPTO = YesPlease
+	NEEDS_LIBICONV = YesPlease
+	SHELL_PATH = /usr/local/bin/bash
+	NO_IPV6 = YesPlease
+	NO_HSTRERROR = YesPlease
+	BASIC_CFLAGS += -Kthread
+	BASIC_CFLAGS += -I/usr/local/include
+	BASIC_LDFLAGS += -L/usr/local/lib
+	INSTALL = ginstall
+	TAR = gtar
+	NO_STRCASESTR = YesPlease
+	NO_MEMMEM = YesPlease
+endif
+ifeq ($(uname_S),SCO_SV)
+	ifeq ($(uname_R),3.2)
+		CFLAGS = -O2
+	endif
+	ifeq ($(uname_R),5)
+		CC = cc
+		BASIC_CFLAGS += -Kthread
+	endif
+	NEEDS_SOCKET = YesPlease
+	NEEDS_NSL = YesPlease
+	NEEDS_SSL_WITH_CRYPTO = YesPlease
+	NEEDS_LIBICONV = YesPlease
+	SHELL_PATH = /usr/bin/bash
+	NO_IPV6 = YesPlease
+	NO_HSTRERROR = YesPlease
+	BASIC_CFLAGS += -I/usr/local/include
+	BASIC_LDFLAGS += -L/usr/local/lib
+	NO_STRCASESTR = YesPlease
+	NO_MEMMEM = YesPlease
+	INSTALL = ginstall
+	TAR = gtar
+endif
 ifeq ($(uname_S),Darwin)
 	NEEDS_SSL_WITH_CRYPTO = YesPlease
 	NEEDS_LIBICONV = YesPlease
@@ -632,8 +679,12 @@
 ifeq ($(uname_S),AIX)
 	NO_STRCASESTR=YesPlease
 	NO_MEMMEM = YesPlease
+	NO_MKDTEMP = YesPlease
 	NO_STRLCPY = YesPlease
+	FREAD_READS_DIRECTORIES = UnfortunatelyYes
+	INTERNAL_QSORT = UnfortunatelyYes
 	NEEDS_LIBICONV=YesPlease
+	BASIC_CFLAGS += -D_LARGE_FILES
 endif
 ifeq ($(uname_S),GNU)
 	# GNU/Hurd
@@ -1034,6 +1085,7 @@
 	    -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
 	    -e 's|++GIT_BINDIR++|$(bindir)|g' \
 	    -e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
+	    -e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \
 	    -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
 	    -e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
 	    -e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
@@ -1158,8 +1210,12 @@
 		echo "$$FLAGS" >GIT-CFLAGS; \
             fi
 
+# We need to apply sq twice, once to protect from the shell
+# that runs GIT-BUILD-OPTIONS, and then again to protect it
+# and the first level quoting from the shell that runs "echo".
 GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS
-	@echo SHELL_PATH=\''$(SHELL_PATH_SQ)'\' >$@
+	@echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
+	@echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
 
 ### Detect Tck/Tk interpreter path changes
 ifndef NO_TCLTK
@@ -1360,6 +1416,14 @@
 		documented,gitmodules | \
 		documented,gitcli | \
 		documented,git-tools | \
+		documented,gitcore-tutorial | \
+		documented,gitcvs-migration | \
+		documented,gitdiffcore | \
+		documented,gitglossary | \
+		documented,githooks | \
+		documented,gitrepository-layout | \
+		documented,gittutorial | \
+		documented,gittutorial-2 | \
 		sentinel,not,matching,is,ok ) continue ;; \
 		esac; \
 		case " $(ALL_PROGRAMS) $(BUILT_INS) git gitk " in \
diff --git a/RelNotes b/RelNotes
index d94e742..6ca1d5b 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes-1.5.5.6.txt
\ No newline at end of file
+Documentation/RelNotes-1.5.6.6.txt
\ No newline at end of file
diff --git a/alias.c b/alias.c
index 116cac8..995f3e6 100644
--- a/alias.c
+++ b/alias.c
@@ -2,7 +2,8 @@
 
 static const char *alias_key;
 static char *alias_val;
-static int alias_lookup_cb(const char *k, const char *v)
+
+static int alias_lookup_cb(const char *k, const char *v, void *cb)
 {
 	if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) {
 		if (!v)
@@ -17,6 +18,6 @@
 {
 	alias_key = alias;
 	alias_val = NULL;
-	git_config(alias_lookup_cb);
+	git_config(alias_lookup_cb, NULL);
 	return alias_val;
 }
diff --git a/archive-tar.c b/archive-tar.c
index 4add802..d7598f9 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -220,7 +220,7 @@
 	strbuf_release(&ext_header);
 }
 
-static int git_tar_config(const char *var, const char *value)
+static int git_tar_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "tar.umask")) {
 		if (value && !strcmp(value, "user")) {
@@ -231,7 +231,7 @@
 		}
 		return 0;
 	}
-	return git_default_config(var, value);
+	return git_default_config(var, value, cb);
 }
 
 static int write_tar_entry(const unsigned char *sha1,
@@ -268,7 +268,7 @@
 {
 	int plen = args->base ? strlen(args->base) : 0;
 
-	git_config(git_tar_config);
+	git_config(git_tar_config, NULL);
 
 	archive_time = args->time;
 	verbose = args->verbose;
diff --git a/attr.c b/attr.c
index 1a15fad..17f6a4d 100644
--- a/attr.c
+++ b/attr.c
@@ -438,11 +438,13 @@
 		elem->prev = attr_stack;
 		attr_stack = elem;
 
-		elem = read_attr(GITATTRIBUTES_FILE, 1);
-		elem->origin = strdup("");
-		elem->prev = attr_stack;
-		attr_stack = elem;
-		debug_push(elem);
+		if (!is_bare_repository()) {
+			elem = read_attr(GITATTRIBUTES_FILE, 1);
+			elem->origin = strdup("");
+			elem->prev = attr_stack;
+			attr_stack = elem;
+			debug_push(elem);
+		}
 
 		elem = read_attr_from_file(git_path(INFOATTRIBUTES_FILE), 1);
 		if (!elem)
@@ -457,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
@@ -501,22 +505,25 @@
 	/*
 	 * Read from parent directories and push them down
 	 */
-	while (1) {
-		char *cp;
+	if (!is_bare_repository()) {
+		while (1) {
+			char *cp;
 
-		len = strlen(attr_stack->origin);
-		if (dirlen <= len)
-			break;
-		memcpy(pathbuf, path, dirlen);
-		memcpy(pathbuf + dirlen, "/", 2);
-		cp = strchr(pathbuf + len + 1, '/');
-		strcpy(cp + 1, GITATTRIBUTES_FILE);
-		elem = read_attr(pathbuf, 0);
-		*cp = '\0';
-		elem->origin = strdup(pathbuf);
-		elem->prev = attr_stack;
-		attr_stack = elem;
-		debug_push(elem);
+			len = strlen(attr_stack->origin);
+			if (dirlen <= len)
+				break;
+			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.buf, 0);
+			*cp = '\0';
+			elem->origin = strdup(pathbuf.buf);
+			elem->prev = attr_stack;
+			attr_stack = elem;
+			debug_push(elem);
+		}
 	}
 
 	/*
diff --git a/branch.c b/branch.c
index daf862e..56e9492 100644
--- a/branch.c
+++ b/branch.c
@@ -32,6 +32,21 @@
 	return 0;
 }
 
+static int should_setup_rebase(const struct tracking *tracking)
+{
+	switch (autorebase) {
+	case AUTOREBASE_NEVER:
+		return 0;
+	case AUTOREBASE_LOCAL:
+		return tracking->remote == NULL;
+	case AUTOREBASE_REMOTE:
+		return tracking->remote != NULL;
+	case AUTOREBASE_ALWAYS:
+		return 1;
+	}
+	return 0;
+}
+
 /*
  * This is called when new_ref is branched off of orig_ref, and tries
  * to infer the settings for branch.<new_ref>.{remote,merge} from the
@@ -69,9 +84,14 @@
 	git_config_set(key, tracking.remote ?  tracking.remote : ".");
 	sprintf(key, "branch.%s.merge", new_ref);
 	git_config_set(key, tracking.src ? tracking.src : orig_ref);
-	free(tracking.src);
 	printf("Branch %s set up to track %s branch %s.\n", new_ref,
 		tracking.remote ? "remote" : "local", orig_ref);
+	if (should_setup_rebase(&tracking)) {
+		sprintf(key, "branch.%s.rebase", new_ref);
+		git_config_set(key, "true");
+		printf("This branch will rebase on pull.\n");
+	}
+	free(tracking.src);
 
 	return 0;
 }
diff --git a/builtin-add.c b/builtin-add.c
index 4a91e3e..9930cf5 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -79,12 +79,18 @@
 		prune_directory(dir, pathspec, baselen);
 }
 
+struct update_callback_data
+{
+	int flags;
+	int add_errors;
+};
+
 static void update_callback(struct diff_queue_struct *q,
 			    struct diff_options *opt, void *cbdata)
 {
-	int i, verbose;
+	int i;
+	struct update_callback_data *data = cbdata;
 
-	verbose = *((int *)cbdata);
 	for (i = 0; i < q->nr; i++) {
 		struct diff_filepair *p = q->queue[i];
 		const char *path = p->one->path;
@@ -94,27 +100,36 @@
 		case DIFF_STATUS_UNMERGED:
 		case DIFF_STATUS_MODIFIED:
 		case DIFF_STATUS_TYPE_CHANGED:
-			add_file_to_cache(path, verbose);
+			if (add_file_to_cache(path, data->flags)) {
+				if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
+					die("updating files failed");
+				data->add_errors++;
+			}
 			break;
 		case DIFF_STATUS_DELETED:
-			remove_file_from_cache(path);
-			if (verbose)
+			if (!(data->flags & ADD_CACHE_PRETEND))
+				remove_file_from_cache(path);
+			if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE))
 				printf("remove '%s'\n", path);
 			break;
 		}
 	}
 }
 
-void add_files_to_cache(int verbose, const char *prefix, const char **pathspec)
+int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
 {
+	struct update_callback_data data;
 	struct rev_info rev;
 	init_revisions(&rev, prefix);
 	setup_revisions(0, NULL, &rev, NULL);
 	rev.prune_data = pathspec;
 	rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
 	rev.diffopt.format_callback = update_callback;
-	rev.diffopt.format_callback_data = &verbose;
+	data.flags = flags;
+	data.add_errors = 0;
+	rev.diffopt.format_callback_data = &data;
 	run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
+	return !!data.add_errors;
 }
 
 static void refresh(int verbose, const char **pathspec)
@@ -177,6 +192,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 struct option builtin_add_options[] = {
 	OPT__DRY_RUN(&show_only),
@@ -184,17 +200,29 @@
 	OPT_GROUP(""),
 	OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
 	OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
-	OPT_BOOLEAN('f', NULL, &ignored_too, "allow adding otherwise ignored files"),
-	OPT_BOOLEAN('u', NULL, &take_worktree_changes, "update tracked files"),
+	OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored files"),
+	OPT_BOOLEAN('u', "update", &take_worktree_changes, "update 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(),
 };
 
+static int add_config(const char *var, const char *value, void *cb)
+{
+	if (!strcasecmp(var, "add.ignore-errors")) {
+		ignore_add_errors = git_config_bool(var, value);
+		return 0;
+	}
+	return git_default_config(var, value, cb);
+}
+
 int cmd_add(int argc, const char **argv, const char *prefix)
 {
+	int exit_status = 0;
 	int i, newfd;
 	const char **pathspec;
 	struct dir_struct dir;
+	int flags;
 
 	argc = parse_options(argc, argv, builtin_add_options,
 			  builtin_add_usage, 0);
@@ -203,16 +231,20 @@
 	if (add_interactive)
 		exit(interactive_add(argc, argv, prefix));
 
-	git_config(git_default_config);
+	git_config(add_config, NULL);
 
 	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);
-		add_files_to_cache(verbose, prefix, pathspec);
+		exit_status = add_files_to_cache(prefix, pathspec, flags);
 		goto finish;
 	}
 
@@ -230,17 +262,6 @@
 
 	fill_directory(&dir, pathspec, ignored_too);
 
-	if (show_only) {
-		const char *sep = "", *eof = "";
-		for (i = 0; i < dir.nr; i++) {
-			printf("%s%s", sep, dir.entries[i]->name);
-			sep = " ";
-			eof = "\n";
-		}
-		fputs(eof, stdout);
-		return 0;
-	}
-
 	if (read_cache() < 0)
 		die("index file corrupt");
 
@@ -254,7 +275,11 @@
 	}
 
 	for (i = 0; i < dir.nr; i++)
-		add_file_to_cache(dir.entries[i]->name, verbose);
+		if (add_file_to_cache(dir.entries[i]->name, flags)) {
+			if (!ignore_add_errors)
+				die("adding files failed");
+			exit_status = 1;
+		}
 
  finish:
 	if (active_cache_changed) {
@@ -263,5 +288,5 @@
 			die("Unable to write new index file");
 	}
 
-	return 0;
+	return exit_status;
 }
diff --git a/builtin-apply.c b/builtin-apply.c
index 30d26e5..c497889 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -418,7 +418,7 @@
 }
 
 /*
- * Get the name etc info from the --/+++ lines of a traditional patch header
+ * Get the name etc info from the ---/+++ lines of a traditional patch header
  *
  * FIXME! The end-of-filename heuristics are kind of screwy. For existing
  * files, we can happily check the index for a match, but for creating a
@@ -1143,21 +1143,6 @@
 	if (patch->is_delete < 0 &&
 	    (newlines || (patch->fragments && patch->fragments->next)))
 		patch->is_delete = 0;
-	if (!unidiff_zero || context) {
-		/* If the user says the patch is not generated with
-		 * --unified=0, or if we have seen context lines,
-		 * then not having oldlines means the patch is creation,
-		 * and not having newlines means the patch is deletion.
-		 */
-		if (patch->is_new < 0 && !oldlines) {
-			patch->is_new = 1;
-			patch->old_name = NULL;
-		}
-		if (patch->is_delete < 0 && !newlines) {
-			patch->is_delete = 1;
-			patch->new_name = NULL;
-		}
-	}
 
 	if (0 < patch->is_new && oldlines)
 		die("new file %s depends on old contents", patch->new_name);
@@ -2247,7 +2232,7 @@
 		 * In such a case, path "new_name" does not exist as
 		 * far as git is concerned.
 		 */
-		if (has_symlink_leading_path(new_name, NULL))
+		if (has_symlink_leading_path(strlen(new_name), new_name))
 			return 0;
 
 		return error("%s: already exists in working directory", new_name);
@@ -2267,6 +2252,79 @@
 	return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID);
 }
 
+static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)
+{
+	const char *old_name = patch->old_name;
+	int stat_ret = 0;
+	unsigned st_mode = 0;
+
+	/*
+	 * Make sure that we do not have local modifications from the
+	 * index when we are looking at the index.  Also make sure
+	 * we have the preimage file to be patched in the work tree,
+	 * unless --cached, which tells git to apply only in the index.
+	 */
+	if (!old_name)
+		return 0;
+
+	assert(patch->is_new <= 0);
+	if (!cached) {
+		stat_ret = lstat(old_name, st);
+		if (stat_ret && errno != ENOENT)
+			return error("%s: %s", old_name, strerror(errno));
+	}
+	if (check_index) {
+		int pos = cache_name_pos(old_name, strlen(old_name));
+		if (pos < 0) {
+			if (patch->is_new < 0)
+				goto is_new;
+			return error("%s: does not exist in index", old_name);
+		}
+		*ce = active_cache[pos];
+		if (stat_ret < 0) {
+			struct checkout costate;
+			/* checkout */
+			costate.base_dir = "";
+			costate.base_dir_len = 0;
+			costate.force = 0;
+			costate.quiet = 0;
+			costate.not_new = 0;
+			costate.refresh_cache = 1;
+			if (checkout_entry(*ce, &costate, NULL) ||
+			    lstat(old_name, st))
+				return -1;
+		}
+		if (!cached && verify_index_match(*ce, st))
+			return error("%s: does not match index", old_name);
+		if (cached)
+			st_mode = (*ce)->ce_mode;
+	} else if (stat_ret < 0) {
+		if (patch->is_new < 0)
+			goto is_new;
+		return error("%s: %s", old_name, strerror(errno));
+	}
+
+	if (!cached)
+		st_mode = ce_mode_from_stat(*ce, st->st_mode);
+
+	if (patch->is_new < 0)
+		patch->is_new = 0;
+	if (!patch->old_mode)
+		patch->old_mode = st_mode;
+	if ((st_mode ^ patch->old_mode) & S_IFMT)
+		return error("%s: wrong type", old_name);
+	if (st_mode != patch->old_mode)
+		fprintf(stderr, "warning: %s has type %o, expected %o\n",
+			old_name, st_mode, patch->old_mode);
+	return 0;
+
+ is_new:
+	patch->is_new = 1;
+	patch->is_delete = 0;
+	patch->old_name = NULL;
+	return 0;
+}
+
 static int check_patch(struct patch *patch, struct patch *prev_patch)
 {
 	struct stat st;
@@ -2275,66 +2333,14 @@
 	const char *name = old_name ? old_name : new_name;
 	struct cache_entry *ce = NULL;
 	int ok_if_exists;
+	int status;
 
 	patch->rejected = 1; /* we will drop this after we succeed */
 
-	/*
-	 * Make sure that we do not have local modifications from the
-	 * index when we are looking at the index.  Also make sure
-	 * we have the preimage file to be patched in the work tree,
-	 * unless --cached, which tells git to apply only in the index.
-	 */
-	if (old_name) {
-		int stat_ret = 0;
-		unsigned st_mode = 0;
-
-		if (!cached)
-			stat_ret = lstat(old_name, &st);
-		if (check_index) {
-			int pos = cache_name_pos(old_name, strlen(old_name));
-			if (pos < 0)
-				return error("%s: does not exist in index",
-					     old_name);
-			ce = active_cache[pos];
-			if (stat_ret < 0) {
-				struct checkout costate;
-				if (errno != ENOENT)
-					return error("%s: %s", old_name,
-						     strerror(errno));
-				/* checkout */
-				costate.base_dir = "";
-				costate.base_dir_len = 0;
-				costate.force = 0;
-				costate.quiet = 0;
-				costate.not_new = 0;
-				costate.refresh_cache = 1;
-				if (checkout_entry(ce,
-						   &costate,
-						   NULL) ||
-				    lstat(old_name, &st))
-					return -1;
-			}
-			if (!cached && verify_index_match(ce, &st))
-				return error("%s: does not match index",
-					     old_name);
-			if (cached)
-				st_mode = ce->ce_mode;
-		} else if (stat_ret < 0)
-			return error("%s: %s", old_name, strerror(errno));
-
-		if (!cached)
-			st_mode = ce_mode_from_stat(ce, st.st_mode);
-
-		if (patch->is_new < 0)
-			patch->is_new = 0;
-		if (!patch->old_mode)
-			patch->old_mode = st_mode;
-		if ((st_mode ^ patch->old_mode) & S_IFMT)
-			return error("%s: wrong type", old_name);
-		if (st_mode != patch->old_mode)
-			fprintf(stderr, "warning: %s has type %o, expected %o\n",
-				old_name, st_mode, patch->old_mode);
-	}
+	status = check_preimage(patch, &ce, &st);
+	if (status)
+		return status;
+	old_name = patch->old_name;
 
 	if (new_name && prev_patch && 0 < prev_patch->is_delete &&
 	    !strcmp(prev_patch->old_name, new_name))
@@ -2979,15 +2985,11 @@
 	return 0;
 }
 
-static int git_apply_config(const char *var, const char *value)
+static int git_apply_config(const char *var, const char *value, void *cb)
 {
-	if (!strcmp(var, "apply.whitespace")) {
-		if (!value)
-			return config_error_nonbool(var);
-		apply_default_whitespace = xstrdup(value);
-		return 0;
-	}
-	return git_default_config(var, value);
+	if (!strcmp(var, "apply.whitespace"))
+		return git_config_string(&apply_default_whitespace, var, value);
+	return git_default_config(var, value, cb);
 }
 
 
@@ -3003,7 +3005,7 @@
 
 	prefix = setup_git_directory_gently(&is_not_gitdir);
 	prefix_length = prefix ? strlen(prefix) : 0;
-	git_config(git_apply_config);
+	git_config(git_apply_config, NULL);
 	if (apply_default_whitespace)
 		parse_whitespace_option(apply_default_whitespace);
 
diff --git a/builtin-blame.c b/builtin-blame.c
index bfd562d..b451f6c 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -1993,7 +1993,7 @@
 		usage(blame_usage);
 }
 
-static int git_blame_config(const char *var, const char *value)
+static int git_blame_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "blame.showroot")) {
 		show_root = git_config_bool(var, value);
@@ -2003,7 +2003,7 @@
 		blank_boundary = git_config_bool(var, value);
 		return 0;
 	}
-	return git_default_config(var, value);
+	return git_default_config(var, value, cb);
 }
 
 static struct commit *fake_working_tree_commit(const char *path, const char *contents_from)
@@ -2141,7 +2141,7 @@
 
 	cmd_is_annotate = !strcmp(argv[0], "annotate");
 
-	git_config(git_blame_config);
+	git_config(git_blame_config, NULL);
 	save_commit_buffer = 0;
 
 	opt = 0;
diff --git a/builtin-branch.c b/builtin-branch.c
index 5bc4526..d279702 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -15,7 +15,7 @@
 #include "branch.h"
 
 static const char * const builtin_branch_usage[] = {
-	"git-branch [options] [-r | -a]",
+	"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>",
@@ -46,6 +46,8 @@
 	COLOR_BRANCH_CURRENT = 4,
 };
 
+static int mergefilter = -1;
+
 static int parse_branch_color_slot(const char *var, int ofs)
 {
 	if (!strcasecmp(var+ofs, "plain"))
@@ -61,7 +63,7 @@
 	die("bad config variable '%s'", var);
 }
 
-static int git_branch_config(const char *var, const char *value)
+static int git_branch_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "color.branch")) {
 		branch_use_color = git_config_colorbool(var, value, -1);
@@ -74,7 +76,7 @@
 		color_parse(value, var, branch_colors[slot]);
 		return 0;
 	}
-	return git_color_default_config(var, value);
+	return git_color_default_config(var, value, cb);
 }
 
 static const char *branch_get_color(enum color_branch ix)
@@ -210,6 +212,7 @@
 	struct ref_item *newitem;
 	int kind = REF_UNKNOWN_TYPE;
 	int len;
+	static struct commit_list branch;
 
 	/* Detect kind */
 	if (!prefixcmp(refname, "refs/heads/")) {
@@ -231,6 +234,16 @@
 	if ((kind & ref_list->kinds) == 0)
 		return 0;
 
+	if (mergefilter > -1) {
+		branch.item = lookup_commit_reference_gently(sha1, 1);
+		if (!branch.item)
+			die("Unable to lookup tip of branch %s", refname);
+		if (mergefilter == 0 && has_commit(head_sha1, &branch))
+			return 0;
+		if (mergefilter == 1 && !has_commit(head_sha1, &branch))
+			return 0;
+	}
+
 	/* Resize buffer */
 	if (ref_list->index >= ref_list->alloc) {
 		ref_list->alloc = alloc_nr(ref_list->alloc);
@@ -444,10 +457,11 @@
 		OPT_BIT('M', NULL, &rename, "move/rename a branch, even if target exists", 2),
 		OPT_BOOLEAN('l', NULL, &reflog, "create the branch's reflog"),
 		OPT_BOOLEAN('f', NULL, &force_create, "force creation (when already exists)"),
+		OPT_SET_INT(0, "merged", &mergefilter, "list only merged branches", 1),
 		OPT_END(),
 	};
 
-	git_config(git_branch_config);
+	git_config(git_branch_config, NULL);
 
 	if (branch_use_color == -1)
 		branch_use_color = git_use_color_default;
diff --git a/builtin-cat-file.c b/builtin-cat-file.c
index f132d58..880e75a 100644
--- a/builtin-cat-file.c
+++ b/builtin-cat-file.c
@@ -8,6 +8,10 @@
 #include "tag.h"
 #include "tree.h"
 #include "builtin.h"
+#include "parse-options.h"
+
+#define BATCH 1
+#define BATCH_CHECK 2
 
 static void pprint_tag(const unsigned char *sha1, const char *buf, unsigned long size)
 {
@@ -76,31 +80,16 @@
 		write_or_die(1, cp, endp - cp);
 }
 
-int cmd_cat_file(int argc, const char **argv, const char *prefix)
+static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
 {
 	unsigned char sha1[20];
 	enum object_type type;
 	void *buf;
 	unsigned long size;
-	int opt;
-	const char *exp_type, *obj_name;
-
-	git_config(git_default_config);
-	if (argc != 3)
-		usage("git-cat-file [-t|-s|-e|-p|<type>] <sha1>");
-	exp_type = argv[1];
-	obj_name = argv[2];
 
 	if (get_sha1(obj_name, sha1))
 		die("Not a valid object name %s", obj_name);
 
-	opt = 0;
-	if ( exp_type[0] == '-' ) {
-		opt = exp_type[1];
-		if ( !opt || exp_type[2] )
-			opt = -1; /* Not a single character option */
-	}
-
 	buf = NULL;
 	switch (opt) {
 	case 't':
@@ -157,3 +146,113 @@
 	write_or_die(1, buf, size);
 	return 0;
 }
+
+static int batch_one_object(const char *obj_name, int print_contents)
+{
+	unsigned char sha1[20];
+	enum object_type type = 0;
+	unsigned long size;
+	void *contents = contents;
+
+	if (!obj_name)
+	   return 1;
+
+	if (get_sha1(obj_name, sha1)) {
+		printf("%s missing\n", obj_name);
+		fflush(stdout);
+		return 0;
+	}
+
+	if (print_contents == BATCH)
+		contents = read_sha1_file(sha1, &type, &size);
+	else
+		type = sha1_object_info(sha1, &size);
+
+	if (type <= 0) {
+		printf("%s missing\n", obj_name);
+		fflush(stdout);
+		return 0;
+	}
+
+	printf("%s %s %lu\n", sha1_to_hex(sha1), typename(type), size);
+	fflush(stdout);
+
+	if (print_contents == BATCH) {
+		write_or_die(1, contents, size);
+		printf("\n");
+		fflush(stdout);
+		free(contents);
+	}
+
+	return 0;
+}
+
+static int batch_objects(int print_contents)
+{
+	struct strbuf buf;
+
+	strbuf_init(&buf, 0);
+	while (strbuf_getline(&buf, stdin, '\n') != EOF) {
+		int error = batch_one_object(buf.buf, print_contents);
+		if (error)
+			return error;
+	}
+
+	return 0;
+}
+
+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>",
+	NULL
+};
+
+int cmd_cat_file(int argc, const char **argv, const char *prefix)
+{
+	int opt = 0, batch = 0;
+	const char *exp_type = NULL, *obj_name = NULL;
+
+	const struct option options[] = {
+		OPT_GROUP("<type> can be one of: blob, tree, commit, tag"),
+		OPT_SET_INT('t', NULL, &opt, "show object type", 't'),
+		OPT_SET_INT('s', NULL, &opt, "show object size", 's'),
+		OPT_SET_INT('e', NULL, &opt,
+			    "exit with zero when there's no error", 'e'),
+		OPT_SET_INT('p', NULL, &opt, "pretty-print object's content", 'p'),
+		OPT_SET_INT(0, "batch", &batch,
+			    "show info and content of objects feeded on stdin", BATCH),
+		OPT_SET_INT(0, "batch-check", &batch,
+			    "show info about objects feeded on stdin",
+			    BATCH_CHECK),
+		OPT_END()
+	};
+
+	git_config(git_default_config, NULL);
+
+	if (argc != 3 && argc != 2)
+		usage_with_options(cat_file_usage, options);
+
+	argc = parse_options(argc, argv, options, cat_file_usage, 0);
+
+	if (opt) {
+		if (argc == 1)
+			obj_name = argv[0];
+		else
+			usage_with_options(cat_file_usage, options);
+	}
+	if (!opt && !batch) {
+		if (argc == 2) {
+			exp_type = argv[0];
+			obj_name = argv[1];
+		} else
+			usage_with_options(cat_file_usage, options);
+	}
+	if (batch && (opt || argc)) {
+		usage_with_options(cat_file_usage, options);
+	}
+
+	if (batch)
+		return batch_objects(batch);
+
+	return cat_one_file(opt, exp_type, obj_name);
+}
diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c
index 7e42024..eb1fc9a 100644
--- a/builtin-checkout-index.c
+++ b/builtin-checkout-index.c
@@ -166,7 +166,7 @@
 	int read_from_stdin = 0;
 	int prefix_length;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	state.base_dir = "";
 	prefix_length = prefix ? strlen(prefix) : 0;
 
diff --git a/builtin-checkout.c b/builtin-checkout.c
index cf9875c..aec2bc6 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -84,6 +84,7 @@
 	unsigned char rev[20];
 	int flag;
 	struct commit *head;
+	int errs = 0;
 
 	int newfd;
 	struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
@@ -106,13 +107,14 @@
 	if (report_path_error(ps_matched, pathspec, 0))
 		return 1;
 
+	/* Now we are committed to check them out */
 	memset(&state, 0, sizeof(state));
 	state.force = 1;
 	state.refresh_cache = 1;
 	for (pos = 0; pos < active_nr; pos++) {
 		struct cache_entry *ce = active_cache[pos];
 		if (pathspec_match(pathspec, NULL, ce->name, 0)) {
-			checkout_entry(ce, &state, NULL);
+			errs |= checkout_entry(ce, &state, NULL);
 		}
 	}
 
@@ -123,7 +125,8 @@
 	resolve_ref("HEAD", rev, 0, &flag);
 	head = lookup_commit_reference_gently(rev, 1);
 
-	return post_checkout_hook(head, head, 0);
+	errs |= post_checkout_hook(head, head, 0);
+	return errs;
 }
 
 static void show_local_changes(struct object *head)
@@ -148,57 +151,50 @@
 	strbuf_release(&sb);
 }
 
-static int reset_to_new(struct tree *tree, int quiet)
-{
-	struct unpack_trees_options opts;
-	struct tree_desc tree_desc;
-
-	memset(&opts, 0, sizeof(opts));
-	opts.head_idx = -1;
-	opts.update = 1;
-	opts.reset = 1;
-	opts.merge = 1;
-	opts.fn = oneway_merge;
-	opts.verbose_update = !quiet;
-	opts.src_index = &the_index;
-	opts.dst_index = &the_index;
-	parse_tree(tree);
-	init_tree_desc(&tree_desc, tree->buffer, tree->size);
-	if (unpack_trees(1, &tree_desc, &opts))
-		return 128;
-	return 0;
-}
-
-static void reset_clean_to_new(struct tree *tree, int quiet)
-{
-	struct unpack_trees_options opts;
-	struct tree_desc tree_desc;
-
-	memset(&opts, 0, sizeof(opts));
-	opts.head_idx = -1;
-	opts.skip_unmerged = 1;
-	opts.reset = 1;
-	opts.merge = 1;
-	opts.fn = oneway_merge;
-	opts.verbose_update = !quiet;
-	opts.src_index = &the_index;
-	opts.dst_index = &the_index;
-	parse_tree(tree);
-	init_tree_desc(&tree_desc, tree->buffer, tree->size);
-	if (unpack_trees(1, &tree_desc, &opts))
-		exit(128);
-}
-
 struct checkout_opts {
 	int quiet;
 	int merge;
 	int force;
+	int writeout_error;
 
 	char *new_branch;
 	int new_branch_log;
 	enum branch_track track;
 };
 
+static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree)
+{
+	struct unpack_trees_options opts;
+	struct tree_desc tree_desc;
+
+	memset(&opts, 0, sizeof(opts));
+	opts.head_idx = -1;
+	opts.update = worktree;
+	opts.skip_unmerged = !worktree;
+	opts.reset = 1;
+	opts.merge = 1;
+	opts.fn = oneway_merge;
+	opts.verbose_update = !o->quiet;
+	opts.src_index = &the_index;
+	opts.dst_index = &the_index;
+	parse_tree(tree);
+	init_tree_desc(&tree_desc, tree->buffer, tree->size);
+	switch (unpack_trees(1, &tree_desc, &opts)) {
+	case -2:
+		o->writeout_error = 1;
+		/*
+		 * We return 0 nevertheless, as the index is all right
+		 * and more importantly we have made best efforts to
+		 * update paths in the work tree, and we cannot revert
+		 * them.
+		 */
+	case 0:
+		return 0;
+	default:
+		return 128;
+	}
+}
+
 struct branch_info {
 	const char *name; /* The short name used */
 	const char *path; /* The full name of a real branch */
@@ -223,7 +219,7 @@
 	read_cache();
 
 	if (opts->force) {
-		ret = reset_to_new(new->commit->tree, opts->quiet);
+		ret = reset_tree(new->commit->tree, opts, 1);
 		if (ret)
 			return ret;
 	} else {
@@ -236,6 +232,8 @@
 		topts.src_index = &the_index;
 		topts.dst_index = &the_index;
 
+		topts.msgs.not_uptodate_file = "You have local changes to '%s'; cannot switch branches.";
+
 		refresh_cache(REFRESH_QUIET);
 
 		if (unmerged_cache()) {
@@ -257,7 +255,8 @@
 		tree = parse_tree_indirect(new->commit->object.sha1);
 		init_tree_desc(&trees[1], tree->buffer, tree->size);
 
-		if (unpack_trees(2, trees, &topts)) {
+		ret = unpack_trees(2, trees, &topts);
+		if (ret == -1) {
 			/*
 			 * Unpack couldn't do a trivial merge; either
 			 * give up or do a real merge, depending on
@@ -282,15 +281,17 @@
 			 * entries in the index.
 			 */
 
-			add_files_to_cache(0, NULL, NULL);
+			add_files_to_cache(NULL, NULL, 0);
 			work = write_tree_from_memory();
 
-			ret = reset_to_new(new->commit->tree, opts->quiet);
+			ret = reset_tree(new->commit->tree, opts, 1);
 			if (ret)
 				return ret;
 			merge_trees(new->commit->tree, work, old->commit->tree,
 				    new->name, "local", &result);
-			reset_clean_to_new(new->commit->tree, opts->quiet);
+			ret = reset_tree(new->commit->tree, opts, 0);
+			if (ret)
+				return ret;
 		}
 	}
 
@@ -490,7 +491,8 @@
 
 	update_refs_for_switch(opts, &old, new);
 
-	return post_checkout_hook(old.commit, new->commit, 1);
+	ret = post_checkout_hook(old.commit, new->commit, 1);
+	return ret || opts->writeout_error;
 }
 
 int cmd_checkout(int argc, const char **argv, const char *prefix)
@@ -504,7 +506,7 @@
 		OPT__QUIET(&opts.quiet),
 		OPT_STRING('b', NULL, &opts.new_branch, "new branch", "branch"),
 		OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "log for new branch"),
-		OPT_SET_INT( 0 , "track",  &opts.track, "track",
+		OPT_SET_INT('t', "track",  &opts.track, "track",
 			BRANCH_TRACK_EXPLICIT),
 		OPT_BOOLEAN('f', NULL, &opts.force, "force"),
 		OPT_BOOLEAN('m', NULL, &opts.merge, "merge"),
@@ -514,11 +516,12 @@
 	memset(&opts, 0, sizeof(opts));
 	memset(&new, 0, sizeof(new));
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	opts.track = git_branch_track;
 
-	argc = parse_options(argc, argv, options, checkout_usage, 0);
+	argc = parse_options(argc, argv, options, checkout_usage,
+			     PARSE_OPT_KEEP_DASHDASH);
 	if (argc) {
 		arg = argv[0];
 		if (get_sha1(arg, rev))
diff --git a/builtin-clean.c b/builtin-clean.c
index 6778a03..80a7ff9 100644
--- a/builtin-clean.c
+++ b/builtin-clean.c
@@ -19,11 +19,11 @@
 	NULL
 };
 
-static int git_clean_config(const char *var, const char *value)
+static int git_clean_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "clean.requireforce"))
 		force = !git_config_bool(var, value);
-	return git_default_config(var, value);
+	return git_default_config(var, value, cb);
 }
 
 int cmd_clean(int argc, const char **argv, const char *prefix)
@@ -50,7 +50,7 @@
 		OPT_END()
 	};
 
-	git_config(git_clean_config);
+	git_config(git_clean_config, NULL);
 	if (force < 0)
 		force = 0;
 	else
diff --git a/builtin-clone.c b/builtin-clone.c
new file mode 100644
index 0000000..863b22e
--- /dev/null
+++ b/builtin-clone.c
@@ -0,0 +1,572 @@
+/*
+ * Builtin "git clone"
+ *
+ * Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>,
+ *		 2008 Daniel Barkalow <barkalow@iabervon.org>
+ * Based on git-commit.sh by Junio C Hamano and Linus Torvalds
+ *
+ * Clone a repository into a different directory that does not yet exist.
+ */
+
+#include "cache.h"
+#include "parse-options.h"
+#include "fetch-pack.h"
+#include "refs.h"
+#include "tree.h"
+#include "tree-walk.h"
+#include "unpack-trees.h"
+#include "transport.h"
+#include "strbuf.h"
+#include "dir.h"
+
+/*
+ * Overall FIXMEs:
+ *  - respect DB_ENVIRONMENT for .git/objects.
+ *
+ * Implementation notes:
+ *  - dropping use-separate-remote and no-separate-remote compatibility
+ *
+ */
+static const char * const builtin_clone_usage[] = {
+	"git-clone [options] [--] <repo> [<dir>]",
+	NULL
+};
+
+static int option_quiet, option_no_checkout, option_bare;
+static int option_local, option_no_hardlinks, option_shared;
+static char *option_template, *option_reference, *option_depth;
+static char *option_origin = NULL;
+static char *option_upload_pack = "git-upload-pack";
+
+static struct option builtin_clone_options[] = {
+	OPT__QUIET(&option_quiet),
+	OPT_BOOLEAN('n', "no-checkout", &option_no_checkout,
+		    "don't create a checkout"),
+	OPT_BOOLEAN(0, "bare", &option_bare, "create a bare repository"),
+	OPT_BOOLEAN(0, "naked", &option_bare, "create a bare repository"),
+	OPT_BOOLEAN('l', "local", &option_local,
+		    "to clone from a local repository"),
+	OPT_BOOLEAN(0, "no-hardlinks", &option_no_hardlinks,
+		    "don't use local hardlinks, always copy"),
+	OPT_BOOLEAN('s', "shared", &option_shared,
+		    "setup as shared repository"),
+	OPT_STRING(0, "template", &option_template, "path",
+		   "path the template repository"),
+	OPT_STRING(0, "reference", &option_reference, "repo",
+		   "reference repository"),
+	OPT_STRING('o', "origin", &option_origin, "branch",
+		   "use <branch> instead or 'origin' to track upstream"),
+	OPT_STRING('u', "upload-pack", &option_upload_pack, "path",
+		   "path to git-upload-pack on the remote"),
+	OPT_STRING(0, "depth", &option_depth, "depth",
+		    "create a shallow clone of that depth"),
+
+	OPT_END()
+};
+
+static char *get_repo_path(const char *repo, int *is_bundle)
+{
+	static char *suffix[] = { "/.git", ".git", "" };
+	static char *bundle_suffix[] = { ".bundle", "" };
+	struct stat st;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(suffix); i++) {
+		const char *path;
+		path = mkpath("%s%s", repo, suffix[i]);
+		if (!stat(path, &st) && S_ISDIR(st.st_mode)) {
+			*is_bundle = 0;
+			return xstrdup(make_nonrelative_path(path));
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(bundle_suffix); i++) {
+		const char *path;
+		path = mkpath("%s%s", repo, bundle_suffix[i]);
+		if (!stat(path, &st) && S_ISREG(st.st_mode)) {
+			*is_bundle = 1;
+			return xstrdup(make_nonrelative_path(path));
+		}
+	}
+
+	return NULL;
+}
+
+static char *guess_dir_name(const char *repo, int is_bundle)
+{
+	const char *p, *start, *end, *limit;
+	int after_slash_or_colon;
+
+	/* Guess dir name from repository: strip trailing '/',
+	 * strip trailing '[:/]*.{git,bundle}', strip leading '.*[/:]'. */
+
+	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;
+		}
+	}
+
+	return xstrndup(start, end - start);
+}
+
+static int is_directory(const char *path)
+{
+	struct stat buf;
+
+	return !stat(path, &buf) && S_ISDIR(buf.st_mode);
+}
+
+static void setup_reference(const char *repo)
+{
+	const char *ref_git;
+	char *ref_git_copy;
+
+	struct remote *remote;
+	struct transport *transport;
+	const struct ref *extra;
+
+	ref_git = make_absolute_path(option_reference);
+
+	if (is_directory(mkpath("%s/.git/objects", ref_git)))
+		ref_git = mkpath("%s/.git", ref_git);
+	else if (!is_directory(mkpath("%s/objects", ref_git)))
+		die("reference repository '%s' is not a local directory.",
+		    option_reference);
+
+	ref_git_copy = xstrdup(ref_git);
+
+	add_to_alternates_file(ref_git_copy);
+
+	remote = remote_get(ref_git_copy);
+	transport = transport_get(remote, ref_git_copy);
+	for (extra = transport_get_remote_refs(transport); extra;
+	     extra = extra->next)
+		add_extra_ref(extra->name, extra->old_sha1, 0);
+
+	transport_disconnect(transport);
+
+	free(ref_git_copy);
+}
+
+static void copy_or_link_directory(char *src, char *dest)
+{
+	struct dirent *de;
+	struct stat buf;
+	int src_len, dest_len;
+	DIR *dir;
+
+	dir = opendir(src);
+	if (!dir)
+		die("failed to open %s\n", src);
+
+	if (mkdir(dest, 0777)) {
+		if (errno != EEXIST)
+			die("failed to create directory %s\n", dest);
+		else if (stat(dest, &buf))
+			die("failed to stat %s\n", dest);
+		else if (!S_ISDIR(buf.st_mode))
+			die("%s exists and is not a directory\n", dest);
+	}
+
+	src_len = strlen(src);
+	src[src_len] = '/';
+	dest_len = strlen(dest);
+	dest[dest_len] = '/';
+
+	while ((de = readdir(dir)) != NULL) {
+		strcpy(src + src_len + 1, de->d_name);
+		strcpy(dest + dest_len + 1, de->d_name);
+		if (stat(src, &buf)) {
+			warning ("failed to stat %s\n", src);
+			continue;
+		}
+		if (S_ISDIR(buf.st_mode)) {
+			if (de->d_name[0] != '.')
+				copy_or_link_directory(src, dest);
+			continue;
+		}
+
+		if (unlink(dest) && errno != ENOENT)
+			die("failed to unlink %s\n", dest);
+		if (!option_no_hardlinks) {
+			if (!link(src, dest))
+				continue;
+			if (option_local)
+				die("failed to create link %s\n", dest);
+			option_no_hardlinks = 1;
+		}
+		if (copy_file(dest, src, 0666))
+			die("failed to copy file to %s\n", dest);
+	}
+	closedir(dir);
+}
+
+static const struct ref *clone_local(const char *src_repo,
+				     const char *dest_repo)
+{
+	const struct ref *ret;
+	char src[PATH_MAX];
+	char dest[PATH_MAX];
+	struct remote *remote;
+	struct transport *transport;
+
+	if (option_shared)
+		add_to_alternates_file(src_repo);
+	else {
+		snprintf(src, PATH_MAX, "%s/objects", src_repo);
+		snprintf(dest, PATH_MAX, "%s/objects", dest_repo);
+		copy_or_link_directory(src, dest);
+	}
+
+	remote = remote_get(src_repo);
+	transport = transport_get(remote, src_repo);
+	ret = transport_get_remote_refs(transport);
+	transport_disconnect(transport);
+	return ret;
+}
+
+static const char *junk_work_tree;
+static const char *junk_git_dir;
+pid_t junk_pid;
+
+static void remove_junk(void)
+{
+	struct strbuf sb;
+	if (getpid() != junk_pid)
+		return;
+	strbuf_init(&sb, 0);
+	if (junk_git_dir) {
+		strbuf_addstr(&sb, junk_git_dir);
+		remove_dir_recursively(&sb, 0);
+		strbuf_reset(&sb);
+	}
+	if (junk_work_tree) {
+		strbuf_addstr(&sb, junk_work_tree);
+		remove_dir_recursively(&sb, 0);
+		strbuf_reset(&sb);
+	}
+}
+
+static void remove_junk_on_signal(int signo)
+{
+	remove_junk();
+	signal(SIGINT, SIG_DFL);
+	raise(signo);
+}
+
+static const struct ref *locate_head(const struct ref *refs,
+				     const struct ref *mapped_refs,
+				     const struct ref **remote_head_p)
+{
+	const struct ref *remote_head = NULL;
+	const struct ref *remote_master = NULL;
+	const struct ref *r;
+	for (r = refs; r; r = r->next)
+		if (!strcmp(r->name, "HEAD"))
+			remote_head = r;
+
+	for (r = mapped_refs; r; r = r->next)
+		if (!strcmp(r->name, "refs/heads/master"))
+			remote_master = r;
+
+	if (remote_head_p)
+		*remote_head_p = remote_head;
+
+	/* If there's no HEAD value at all, never mind. */
+	if (!remote_head)
+		return NULL;
+
+	/* If refs/heads/master could be right, it is. */
+	if (remote_master && !hashcmp(remote_master->old_sha1,
+				      remote_head->old_sha1))
+		return remote_master;
+
+	/* Look for another ref that points there */
+	for (r = mapped_refs; r; r = r->next)
+		if (r != remote_head &&
+		    !hashcmp(r->old_sha1, remote_head->old_sha1))
+			return r;
+
+	/* Nothing is the same */
+	return NULL;
+}
+
+static struct ref *write_remote_refs(const struct ref *refs,
+		struct refspec *refspec, const char *reflog)
+{
+	struct ref *local_refs = NULL;
+	struct ref **tail = &local_refs;
+	struct ref *r;
+
+	get_fetch_map(refs, refspec, &tail, 0);
+	get_fetch_map(refs, tag_refspec, &tail, 0);
+
+	for (r = local_refs; r; r = r->next)
+		update_ref(reflog,
+			   r->peer_ref->name, r->old_sha1, NULL, 0, DIE_ON_ERR);
+	return local_refs;
+}
+
+int cmd_clone(int argc, const char **argv, const char *prefix)
+{
+	int use_local_hardlinks = 1;
+	int use_separate_remote = 1;
+	int is_bundle = 0;
+	struct stat buf;
+	const char *repo_name, *repo, *work_tree, *git_dir;
+	char *path, *dir;
+	const struct ref *refs, *head_points_at, *remote_head, *mapped_refs;
+	char branch_top[256], key[256], value[256];
+	struct strbuf reflog_msg;
+	struct transport *transport = NULL;
+
+	struct refspec refspec;
+
+	junk_pid = getpid();
+
+	argc = parse_options(argc, argv, builtin_clone_options,
+			     builtin_clone_usage, 0);
+
+	if (argc == 0)
+		die("You must specify a repository to clone.");
+
+	if (option_no_hardlinks)
+		use_local_hardlinks = 0;
+
+	if (option_bare) {
+		if (option_origin)
+			die("--bare and --origin %s options are incompatible.",
+			    option_origin);
+		option_no_checkout = 1;
+		use_separate_remote = 0;
+	}
+
+	if (!option_origin)
+		option_origin = "origin";
+
+	repo_name = argv[0];
+
+	path = get_repo_path(repo_name, &is_bundle);
+	if (path)
+		repo = path;
+	else if (!strchr(repo_name, ':'))
+		repo = xstrdup(make_absolute_path(repo_name));
+	else
+		repo = repo_name;
+
+	if (argc == 2)
+		dir = xstrdup(argv[1]);
+	else
+		dir = guess_dir_name(repo_name, is_bundle);
+
+	if (!stat(dir, &buf))
+		die("destination directory '%s' already exists.", dir);
+
+	strbuf_init(&reflog_msg, 0);
+	strbuf_addf(&reflog_msg, "clone: from %s", repo);
+
+	if (option_bare)
+		work_tree = NULL;
+	else {
+		work_tree = getenv("GIT_WORK_TREE");
+		if (work_tree && !stat(work_tree, &buf))
+			die("working tree '%s' already exists.", work_tree);
+	}
+
+	if (option_bare || work_tree)
+		git_dir = xstrdup(dir);
+	else {
+		work_tree = dir;
+		git_dir = xstrdup(mkpath("%s/.git", dir));
+	}
+
+	if (!option_bare) {
+		junk_work_tree = work_tree;
+		if (safe_create_leading_directories_const(work_tree) < 0)
+			die("could not create leading directories of '%s'",
+					work_tree);
+		if (mkdir(work_tree, 0755))
+			die("could not create work tree dir '%s'.", work_tree);
+		set_git_work_tree(work_tree);
+	}
+	junk_git_dir = git_dir;
+	atexit(remove_junk);
+	signal(SIGINT, remove_junk_on_signal);
+
+	setenv(CONFIG_ENVIRONMENT, xstrdup(mkpath("%s/config", git_dir)), 1);
+
+	if (safe_create_leading_directories_const(git_dir) < 0)
+		die("could not create leading directories of '%s'", git_dir);
+	set_git_dir(make_absolute_path(git_dir));
+
+	init_db(option_template, option_quiet ? INIT_DB_QUIET : 0);
+
+	/*
+	 * At this point, the config exists, so we do not need the
+	 * environment variable.  We actually need to unset it, too, to
+	 * re-enable parsing of the global configs.
+	 */
+	unsetenv(CONFIG_ENVIRONMENT);
+
+	if (option_reference)
+		setup_reference(git_dir);
+
+	git_config(git_default_config, NULL);
+
+	if (option_bare) {
+		strcpy(branch_top, "refs/heads/");
+
+		git_config_set("core.bare", "true");
+	} else {
+		snprintf(branch_top, sizeof(branch_top),
+			 "refs/remotes/%s/", option_origin);
+
+		/* Configure the remote */
+		snprintf(key, sizeof(key), "remote.%s.url", option_origin);
+		git_config_set(key, repo);
+
+		snprintf(key, sizeof(key), "remote.%s.fetch", option_origin);
+		snprintf(value, sizeof(value),
+				"+refs/heads/*:%s*", branch_top);
+		git_config_set_multivar(key, value, "^$", 0);
+	}
+
+	refspec.force = 0;
+	refspec.pattern = 1;
+	refspec.src = "refs/heads/";
+	refspec.dst = branch_top;
+
+	if (path && !is_bundle)
+		refs = clone_local(path, git_dir);
+	else {
+		struct remote *remote = remote_get(argv[0]);
+		transport = transport_get(remote, remote->url[0]);
+
+		if (!transport->get_refs_list || !transport->fetch)
+			die("Don't know how to clone %s", transport->url);
+
+		transport_set_option(transport, TRANS_OPT_KEEP, "yes");
+
+		if (option_depth)
+			transport_set_option(transport, TRANS_OPT_DEPTH,
+					     option_depth);
+
+		if (option_quiet)
+			transport->verbose = -1;
+
+		if (option_upload_pack)
+			transport_set_option(transport, TRANS_OPT_UPLOADPACK,
+					     option_upload_pack);
+
+		refs = transport_get_remote_refs(transport);
+		transport_fetch_refs(transport, refs);
+	}
+
+	clear_extra_refs();
+
+	mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf);
+
+	head_points_at = locate_head(refs, mapped_refs, &remote_head);
+
+	if (head_points_at) {
+		/* Local default branch link */
+		create_symref("HEAD", head_points_at->name, NULL);
+
+		if (!option_bare) {
+			struct strbuf head_ref;
+			const char *head = head_points_at->name;
+
+			if (!prefixcmp(head, "refs/heads/"))
+				head += 11;
+
+			/* Set up the initial local branch */
+
+			/* Local branch initial value */
+			update_ref(reflog_msg.buf, "HEAD",
+				   head_points_at->old_sha1,
+				   NULL, 0, DIE_ON_ERR);
+
+			strbuf_init(&head_ref, 0);
+			strbuf_addstr(&head_ref, branch_top);
+			strbuf_addstr(&head_ref, "HEAD");
+
+			/* Remote branch link */
+			create_symref(head_ref.buf,
+				      head_points_at->peer_ref->name,
+				      reflog_msg.buf);
+
+			snprintf(key, sizeof(key), "branch.%s.remote", head);
+			git_config_set(key, option_origin);
+			snprintf(key, sizeof(key), "branch.%s.merge", head);
+			git_config_set(key, head_points_at->name);
+		}
+	} else if (remote_head) {
+		/* Source had detached HEAD pointing somewhere. */
+		if (!option_bare)
+			update_ref(reflog_msg.buf, "HEAD",
+				   remote_head->old_sha1,
+				   NULL, REF_NODEREF, DIE_ON_ERR);
+	} else {
+		/* Nothing to checkout out */
+		if (!option_no_checkout)
+			warning("remote HEAD refers to nonexistent ref, "
+				"unable to checkout.\n");
+		option_no_checkout = 1;
+	}
+
+	if (transport)
+		transport_unlock_pack(transport);
+
+	if (!option_no_checkout) {
+		struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
+		struct unpack_trees_options opts;
+		struct tree *tree;
+		struct tree_desc t;
+		int fd;
+
+		/* We need to be in the new work tree for the checkout */
+		setup_work_tree();
+
+		fd = hold_locked_index(lock_file, 1);
+
+		memset(&opts, 0, sizeof opts);
+		opts.update = 1;
+		opts.merge = 1;
+		opts.fn = oneway_merge;
+		opts.verbose_update = !option_quiet;
+		opts.src_index = &the_index;
+		opts.dst_index = &the_index;
+
+		tree = parse_tree_indirect(remote_head->old_sha1);
+		parse_tree(tree);
+		init_tree_desc(&t, tree->buffer, tree->size);
+		unpack_trees(1, &t, &opts);
+
+		if (write_cache(fd, active_cache, active_nr) ||
+		    commit_locked_index(lock_file))
+			die("unable to write new index file");
+	}
+
+	strbuf_release(&reflog_msg);
+	junk_pid = 0;
+	return 0;
+}
diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c
index 6610d18..e5e4bdb 100644
--- a/builtin-commit-tree.c
+++ b/builtin-commit-tree.c
@@ -60,7 +60,7 @@
 	struct strbuf buffer;
 	int encoding_is_utf8;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	if (argc < 2)
 		usage(commit_tree_usage);
diff --git a/builtin-commit.c b/builtin-commit.c
index b0fe69e..0c6d1f4 100644
--- a/builtin-commit.c
+++ b/builtin-commit.c
@@ -45,8 +45,10 @@
 	COMMIT_PARTIAL,
 } commit_style;
 
-static char *logfile, *force_author, *template_file;
+static const char *logfile, *force_author;
+static const char *template_file;
 static char *edit_message, *use_message;
+static char *author_name, *author_email, *author_date;
 static int all, edit_flag, also, interactive, only, amend, signoff;
 static int quiet, verbose, untracked_files, no_verify, allow_empty;
 /*
@@ -175,10 +177,13 @@
 {
 	int i;
 	for (i = 0; i < list->nr; i++) {
+		struct stat st;
 		struct path_list_item *p = &(list->items[i]);
-		if (file_exists(p->path))
-			add_file_to_cache(p->path, 0);
-		else
+
+		if (!lstat(p->path, &st)) {
+			if (add_to_cache(p->path, &st, 0))
+				die("updating files failed");
+		} else
 			remove_file_from_cache(p->path);
 	}
 }
@@ -245,7 +250,7 @@
 	 */
 	if (all || (also && pathspec && *pathspec)) {
 		int fd = hold_locked_index(&index_lock, 1);
-		add_files_to_cache(0, also ? prefix : NULL, pathspec);
+		add_files_to_cache(also ? prefix : NULL, pathspec, 0);
 		refresh_cache(REFRESH_QUIET);
 		if (write_cache(fd, active_cache, active_nr) ||
 		    close_lock_file(&index_lock))
@@ -397,6 +402,47 @@
 
 static const char sign_off_header[] = "Signed-off-by: ";
 
+static void determine_author_info(void)
+{
+	char *name, *email, *date;
+
+	name = getenv("GIT_AUTHOR_NAME");
+	email = getenv("GIT_AUTHOR_EMAIL");
+	date = getenv("GIT_AUTHOR_DATE");
+
+	if (use_message) {
+		const char *a, *lb, *rb, *eol;
+
+		a = strstr(use_message_buffer, "\nauthor ");
+		if (!a)
+			die("invalid commit: %s", use_message);
+
+		lb = strstr(a + 8, " <");
+		rb = strstr(a + 8, "> ");
+		eol = strchr(a + 8, '\n');
+		if (!lb || !rb || !eol)
+			die("invalid commit: %s", use_message);
+
+		name = xstrndup(a + 8, lb - (a + 8));
+		email = xstrndup(lb + 2, rb - (lb + 2));
+		date = xstrndup(rb + 2, eol - (rb + 2));
+	}
+
+	if (force_author) {
+		const char *lb = strstr(force_author, " <");
+		const char *rb = strchr(force_author, '>');
+
+		if (!lb || !rb)
+			die("malformed --author parameter");
+		name = xstrndup(force_author, lb - force_author);
+		email = xstrndup(lb + 2, rb - (lb + 2));
+	}
+
+	author_name = name;
+	author_email = email;
+	author_date = date;
+}
+
 static int prepare_to_commit(const char *index_file, const char *prefix)
 {
 	struct stat statbuf;
@@ -406,6 +452,7 @@
 	FILE *fp;
 	const char *hook_arg1 = NULL;
 	const char *hook_arg2 = NULL;
+	int ident_shown = 0;
 
 	if (!no_verify && run_hook(index_file, "pre-commit", NULL))
 		return 0;
@@ -485,7 +532,14 @@
 
 	strbuf_release(&sb);
 
+	determine_author_info();
+
+	/* This checks if committer ident is explicitly given */
+	git_committer_info(0);
 	if (use_editor) {
+		char *author_ident;
+		const char *committer_ident;
+
 		if (in_merge)
 			fprintf(fp,
 				"#\n"
@@ -508,6 +562,27 @@
 		if (only_include_assumed)
 			fprintf(fp, "# %s\n", only_include_assumed);
 
+		author_ident = xstrdup(fmt_name(author_name, author_email));
+		committer_ident = fmt_name(getenv("GIT_COMMITTER_NAME"),
+					   getenv("GIT_COMMITTER_EMAIL"));
+		if (strcmp(author_ident, committer_ident))
+			fprintf(fp,
+				"%s"
+				"# Author:    %s\n",
+				ident_shown++ ? "" : "#\n",
+				author_ident);
+		free(author_ident);
+
+		if (!user_ident_explicitly_given)
+			fprintf(fp,
+				"%s"
+				"# Committer: %s\n",
+				ident_shown++ ? "" : "#\n",
+				committer_ident);
+
+		if (ident_shown)
+			fprintf(fp, "#\n");
+
 		saved_color_setting = wt_status_use_color;
 		wt_status_use_color = 0;
 		commitable = run_status(fp, index_file, prefix, 1);
@@ -624,51 +699,15 @@
 	return 1;
 }
 
-static void determine_author_info(struct strbuf *sb)
-{
-	char *name, *email, *date;
-
-	name = getenv("GIT_AUTHOR_NAME");
-	email = getenv("GIT_AUTHOR_EMAIL");
-	date = getenv("GIT_AUTHOR_DATE");
-
-	if (use_message) {
-		const char *a, *lb, *rb, *eol;
-
-		a = strstr(use_message_buffer, "\nauthor ");
-		if (!a)
-			die("invalid commit: %s", use_message);
-
-		lb = strstr(a + 8, " <");
-		rb = strstr(a + 8, "> ");
-		eol = strchr(a + 8, '\n');
-		if (!lb || !rb || !eol)
-			die("invalid commit: %s", use_message);
-
-		name = xstrndup(a + 8, lb - (a + 8));
-		email = xstrndup(lb + 2, rb - (lb + 2));
-		date = xstrndup(rb + 2, eol - (rb + 2));
-	}
-
-	if (force_author) {
-		const char *lb = strstr(force_author, " <");
-		const char *rb = strchr(force_author, '>');
-
-		if (!lb || !rb)
-			die("malformed --author parameter");
-		name = xstrndup(force_author, lb - force_author);
-		email = xstrndup(lb + 2, rb - (lb + 2));
-	}
-
-	strbuf_addf(sb, "author %s\n", fmt_ident(name, email, date, IDENT_ERROR_ON_NO_NAME));
-}
-
 static int parse_and_validate_options(int argc, const char *argv[],
-				      const char * const usage[])
+				      const char * const usage[],
+				      const char *prefix)
 {
 	int f = 0;
 
 	argc = parse_options(argc, argv, builtin_commit_options, usage, 0);
+	logfile = parse_options_fix_filename(prefix, logfile);
+	template_file = parse_options_fix_filename(prefix, template_file);
 
 	if (logfile || message.len || use_message)
 		use_editor = 0;
@@ -747,10 +786,8 @@
 		die("No paths with --include/--only does not make sense.");
 	if (argc == 0 && only && amend)
 		only_include_assumed = "Clever... amending the last one with dirty index.";
-	if (argc > 0 && !also && !only) {
+	if (argc > 0 && !also && !only)
 		only_include_assumed = "Explicit paths specified without -i nor -o; assuming --only paths...";
-		also = 0;
-	}
 	if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
 		cleanup_mode = use_editor ? CLEANUP_ALL : CLEANUP_SPACE;
 	else if (!strcmp(cleanup_arg, "verbatim"))
@@ -775,12 +812,12 @@
 	const char *index_file;
 	int commitable;
 
-	git_config(git_status_config);
+	git_config(git_status_config, NULL);
 
 	if (wt_status_use_color == -1)
 		wt_status_use_color = git_use_color_default;
 
-	argc = parse_and_validate_options(argc, argv, builtin_status_usage);
+	argc = parse_and_validate_options(argc, argv, builtin_status_usage, prefix);
 
 	index_file = prepare_index(argc, argv, prefix);
 
@@ -812,7 +849,7 @@
 
 	rev.verbose_header = 1;
 	rev.show_root_diff = 1;
-	rev.commit_format = get_commit_format("format:%h: %s");
+	get_commit_format("format:%h: %s", &rev);
 	rev.always_show_header = 0;
 	rev.diffopt.detect_rename = 1;
 	rev.diffopt.rename_limit = 100;
@@ -829,16 +866,12 @@
 	}
 }
 
-int git_commit_config(const char *k, const char *v)
+int git_commit_config(const char *k, const char *v, void *cb)
 {
-	if (!strcmp(k, "commit.template")) {
-		if (!v)
-			return config_error_nonbool(v);
-		template_file = xstrdup(v);
-		return 0;
-	}
+	if (!strcmp(k, "commit.template"))
+		return git_config_string(&template_file, k, v);
 
-	return git_status_config(k, v);
+	return git_status_config(k, v, cb);
 }
 
 static const char commit_utf8_warn[] =
@@ -850,10 +883,19 @@
 {
 	struct object *obj = parse_object(sha1);
 	const char *parent = sha1_to_hex(sha1);
+	const char *cp;
+
 	if (!obj)
 		die("Unable to find commit parent %s", parent);
 	if (obj->type != OBJ_COMMIT)
 		die("Parent %s isn't a proper commit", parent);
+
+	for (cp = sb->buf; cp && (cp = strstr(cp, "\nparent ")); cp += 8) {
+		if (!memcmp(cp + 8, parent, 40) && cp[48] == '\n') {
+			error("duplicate parent %s ignored", parent);
+			return;
+		}
+	}
 	strbuf_addf(sb, "parent %s\n", parent);
 }
 
@@ -866,9 +908,9 @@
 	unsigned char commit_sha1[20];
 	struct ref_lock *ref_lock;
 
-	git_config(git_commit_config);
+	git_config(git_commit_config, NULL);
 
-	argc = parse_and_validate_options(argc, argv, builtin_commit_usage);
+	argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix);
 
 	index_file = prepare_index(argc, argv, prefix);
 
@@ -924,7 +966,8 @@
 		strbuf_addf(&sb, "parent %s\n", sha1_to_hex(head_sha1));
 	}
 
-	determine_author_info(&sb);
+	strbuf_addf(&sb, "author %s\n",
+		    fmt_ident(author_name, author_email, author_date, IDENT_ERROR_ON_NO_NAME));
 	strbuf_addf(&sb, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME));
 	if (!is_encoding_utf8(git_commit_encoding))
 		strbuf_addf(&sb, "encoding %s\n", git_commit_encoding);
diff --git a/builtin-config.c b/builtin-config.c
index c34bc8b..3a441ef 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 ] [ -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;
@@ -16,9 +16,9 @@
 static char delim = '=';
 static char key_delim = ' ';
 static char term = '\n';
-static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
+static enum { T_RAW, T_INT, T_BOOL, T_BOOL_OR_INT } type = T_RAW;
 
-static int show_all_config(const char *key_, const char *value_)
+static int show_all_config(const char *key_, const char *value_, void *cb)
 {
 	if (value_)
 		printf("%s%c%s%c", key_, delim, value_, term);
@@ -27,7 +27,7 @@
 	return 0;
 }
 
-static int show_config(const char* key_, const char* value_)
+static int show_config(const char* key_, const char* value_, void *cb)
 {
 	char value[256];
 	const char *vptr = value;
@@ -53,6 +53,14 @@
 		sprintf(value, "%d", git_config_int(key_, value_?value_:""));
 	else if (type == T_BOOL)
 		vptr = git_config_bool(key_, value_) ? "true" : "false";
+	else if (type == T_BOOL_OR_INT) {
+		int is_bool, v;
+		v = git_config_bool_or_int(key_, value_, &is_bool);
+		if (is_bool)
+			vptr = v ? "true" : "false";
+		else
+			sprintf(value, "%d", v);
+	}
 	else
 		vptr = value_?value_:"";
 	seen++;
@@ -113,14 +121,14 @@
 	}
 
 	if (do_all && system_wide)
-		git_config_from_file(show_config, system_wide);
+		git_config_from_file(show_config, system_wide, NULL);
 	if (do_all && global)
-		git_config_from_file(show_config, global);
-	git_config_from_file(show_config, local);
+		git_config_from_file(show_config, global, NULL);
+	git_config_from_file(show_config, local, NULL);
 	if (!do_all && !seen && global)
-		git_config_from_file(show_config, global);
+		git_config_from_file(show_config, global, NULL);
 	if (!do_all && !seen && system_wide)
-		git_config_from_file(show_config, system_wide);
+		git_config_from_file(show_config, system_wide, NULL);
 
 	free(key);
 	if (regexp) {
@@ -157,6 +165,14 @@
 		else if (type == T_BOOL)
 			sprintf(normalized, "%s",
 				git_config_bool(key, value) ? "true" : "false");
+		else if (type == T_BOOL_OR_INT) {
+			int is_bool, v;
+			v = git_config_bool_or_int(key, value, &is_bool);
+			if (!is_bool)
+				sprintf(normalized, "%d", v);
+			else
+				sprintf(normalized, "%s", v ? "true" : "false");
+		}
 	}
 
 	return normalized;
@@ -166,7 +182,7 @@
 static const char *get_color_slot;
 static char parsed_color[COLOR_MAXLEN];
 
-static int git_get_color_config(const char *var, const char *value)
+static int git_get_color_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, get_color_slot)) {
 		if (!value)
@@ -202,7 +218,7 @@
 
 	get_color_found = 0;
 	parsed_color[0] = '\0';
-	git_config(git_get_color_config);
+	git_config(git_get_color_config, NULL);
 
 	if (!get_color_found && def_color)
 		color_parse(def_color, "command line", parsed_color);
@@ -214,7 +230,8 @@
 static int stdout_is_tty;
 static int get_colorbool_found;
 static int get_diff_color_found;
-static int git_get_colorbool_config(const char *var, const char *value)
+static int git_get_colorbool_config(const char *var, const char *value,
+		void *cb)
 {
 	if (!strcmp(var, get_color_slot)) {
 		get_colorbool_found =
@@ -224,6 +241,10 @@
 		get_diff_color_found =
 			git_config_colorbool(var, value, stdout_is_tty);
 	}
+	if (!strcmp(var, "color.ui")) {
+		git_use_color_default = git_config_colorbool(var, value, stdout_is_tty);
+		return 0;
+	}
 	return 0;
 }
 
@@ -245,13 +266,13 @@
 	get_colorbool_found = -1;
 	get_diff_color_found = -1;
 	get_color_slot = argv[0];
-	git_config(git_get_colorbool_config);
+	git_config(git_get_colorbool_config, NULL);
 
 	if (get_colorbool_found < 0) {
 		if (!strcmp(get_color_slot, "color.diff"))
 			get_colorbool_found = get_diff_color_found;
 		if (get_colorbool_found < 0)
-			get_colorbool_found = 0;
+			get_colorbool_found = git_use_color_default;
 	}
 
 	if (argc == 1) {
@@ -273,10 +294,13 @@
 			type = T_INT;
 		else if (!strcmp(argv[1], "--bool"))
 			type = T_BOOL;
+		else if (!strcmp(argv[1], "--bool-or-int"))
+			type = T_BOOL_OR_INT;
 		else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) {
 			if (argc != 2)
 				usage(git_config_set_usage);
-			if (git_config(show_all_config) < 0 && file && errno)
+			if (git_config(show_all_config, NULL) < 0 &&
+					file && errno)
 				die("unable to read config file %s: %s", file,
 				    strerror(errno));
 			return 0;
diff --git a/builtin-describe.c b/builtin-describe.c
index 3da99c1..e515f9c 100644
--- a/builtin-describe.c
+++ b/builtin-describe.c
@@ -204,7 +204,7 @@
 		 */
 		display_name(n);
 		if (longformat)
-			show_suffix(0, n->tag->tagged->sha1);
+			show_suffix(0, n->tag ? n->tag->tagged->sha1 : sha1);
 		printf("\n");
 		return;
 	}
diff --git a/builtin-diff-files.c b/builtin-diff-files.c
index e2306c1..384d871 100644
--- a/builtin-diff-files.c
+++ b/builtin-diff-files.c
@@ -10,26 +10,54 @@
 #include "builtin.h"
 
 static const char diff_files_usage[] =
-"git-diff-files [-q] [-0/-1/2/3 |-c|--cc|--no-index] [<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)
 {
 	struct rev_info rev;
-	int nongit;
 	int result;
+	unsigned options = 0;
 
-	prefix = setup_git_directory_gently(&nongit);
 	init_revisions(&rev, prefix);
-	git_config(git_diff_basic_config); /* no "diff" UI options */
+	git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
 	rev.abbrev = 0;
 
-	if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
-		argc = 0;
-	else
-		argc = setup_revisions(argc, argv, &rev, NULL);
+	argc = setup_revisions(argc, argv, &rev, NULL);
+	while (1 < argc && argv[1][0] == '-') {
+		if (!strcmp(argv[1], "--base"))
+			rev.max_count = 1;
+		else if (!strcmp(argv[1], "--ours"))
+			rev.max_count = 2;
+		else if (!strcmp(argv[1], "--theirs"))
+			rev.max_count = 3;
+		else if (!strcmp(argv[1], "-q"))
+			options |= DIFF_SILENT_ON_REMOVED;
+		else
+			usage(diff_files_usage);
+		argv++; argc--;
+	}
 	if (!rev.diffopt.output_format)
 		rev.diffopt.output_format = DIFF_FORMAT_RAW;
-	result = run_diff_files_cmd(&rev, argc, argv);
+
+	/*
+	 * Make sure there are NO revision (i.e. pending object) parameter,
+	 * rev.max_count is reasonable (0 <= n <= 3), and
+	 * there is no other revision filtering parameters.
+	 */
+	if (rev.pending.nr ||
+	    rev.min_age != -1 || rev.max_age != -1 ||
+	    3 < rev.max_count)
+		usage(diff_files_usage);
+
+	if (rev.max_count == -1 &&
+	    (rev.diffopt.output_format & DIFF_FORMAT_PATCH))
+		rev.combine_merges = rev.dense_combined_merges = 1;
+
+	if (read_cache() < 0) {
+		perror("read_cache");
+		return -1;
+	}
+	result = run_diff_files(&rev, options);
 	return diff_result_code(&rev.diffopt, result);
 }
diff --git a/builtin-diff-index.c b/builtin-diff-index.c
index 2b955de..2f44ebf 100644
--- a/builtin-diff-index.c
+++ b/builtin-diff-index.c
@@ -17,7 +17,7 @@
 	int result;
 
 	init_revisions(&rev, prefix);
-	git_config(git_diff_basic_config); /* no "diff" UI options */
+	git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
 	rev.abbrev = 0;
 
 	argc = setup_revisions(argc, argv, &rev, NULL);
diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c
index 832797f..9d2a48f 100644
--- a/builtin-diff-tree.c
+++ b/builtin-diff-tree.c
@@ -68,7 +68,7 @@
 	int read_stdin = 0;
 
 	init_revisions(opt, prefix);
-	git_config(git_diff_basic_config); /* no "diff" UI options */
+	git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
 	nr_sha1 = 0;
 	opt->abbrev = 0;
 	opt->diff = 1;
diff --git a/builtin-diff.c b/builtin-diff.c
index 7c2a841..4c289e7 100644
--- a/builtin-diff.c
+++ b/builtin-diff.c
@@ -202,6 +202,37 @@
 	rollback_lock_file(lock_file);
 }
 
+static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
+{
+	int result;
+	unsigned int options = 0;
+
+	while (1 < argc && argv[1][0] == '-') {
+		if (!strcmp(argv[1], "--base"))
+			revs->max_count = 1;
+		else if (!strcmp(argv[1], "--ours"))
+			revs->max_count = 2;
+		else if (!strcmp(argv[1], "--theirs"))
+			revs->max_count = 3;
+		else if (!strcmp(argv[1], "-q"))
+			options |= DIFF_SILENT_ON_REMOVED;
+		else
+			return error("invalid option: %s", argv[1]);
+		argv++; argc--;
+	}
+
+	if (revs->max_count == -1 &&
+	    (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
+		revs->combine_merges = revs->dense_combined_merges = 1;
+
+	if (read_cache() < 0) {
+		perror("read_cache");
+		return -1;
+	}
+	result = run_diff_files(revs, options);
+	return diff_result_code(&revs->diffopt, result);
+}
+
 int cmd_diff(int argc, const char **argv, const char *prefix)
 {
 	int i;
@@ -230,31 +261,34 @@
 	 * N=2, M=0:
 	 *      tree vs tree (diff-tree)
 	 *
+	 * N=0, M=0, P=2:
+	 *      compare two filesystem entities (aka --no-index).
+	 *
 	 * Other cases are errors.
 	 */
 
 	prefix = setup_git_directory_gently(&nongit);
-	git_config(git_diff_ui_config);
+	git_config(git_diff_ui_config, NULL);
 
 	if (diff_use_color_default == -1)
 		diff_use_color_default = git_use_color_default;
 
 	init_revisions(&rev, prefix);
+
+	/* If this is a no-index diff, just run it and exit there. */
+	diff_no_index(&rev, argc, argv, nongit, prefix);
+
+	/* Otherwise, we are doing the usual "git" diff */
 	rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
 
-	if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
-		argc = 0;
-	else
-		argc = setup_revisions(argc, argv, &rev, NULL);
+	if (nongit)
+		die("Not a git repository");
+	argc = setup_revisions(argc, argv, &rev, NULL);
 	if (!rev.diffopt.output_format) {
 		rev.diffopt.output_format = DIFF_FORMAT_PATCH;
 		if (diff_setup_done(&rev.diffopt) < 0)
 			die("diff_setup_done failed");
 	}
-	if (rev.diffopt.prefix && nongit) {
-		rev.diffopt.prefix = NULL;
-		rev.diffopt.prefix_length = 0;
-	}
 	DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
 	DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
 
@@ -265,7 +299,8 @@
 	if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
 		setup_pager();
 
-	/* Do we have --cached and not have a pending object, then
+	/*
+	 * Do we have --cached and not have a pending object, then
 	 * default to HEAD by hand.  Eek.
 	 */
 	if (!rev.pending.nr) {
@@ -333,7 +368,7 @@
 	if (!ents) {
 		switch (blobs) {
 		case 0:
-			result = run_diff_files_cmd(&rev, argc, argv);
+			result = builtin_diff_files(&rev, argc, argv);
 			break;
 		case 1:
 			if (paths != 1)
diff --git a/builtin-fast-export.c b/builtin-fast-export.c
index 4ab93fc..d0a462f 100644
--- a/builtin-fast-export.c
+++ b/builtin-fast-export.c
@@ -188,6 +188,8 @@
 	mark_object(&commit->object);
 	if (!is_encoding_utf8(encoding))
 		reencoded = reencode_string(message, "UTF-8", encoding);
+	if (!commit->parents)
+		printf("reset %s\n", (const char*)commit->util);
 	printf("commit %s\nmark :%d\n%.*s\n%.*s\ndata %u\n%s",
 	       (const char *)commit->util, last_idnum,
 	       (int)(author_end - author), author,
@@ -368,7 +370,7 @@
 	};
 
 	/* we handle encodings */
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	init_revisions(&revs, prefix);
 	argc = setup_revisions(argc, argv, &revs, NULL);
diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c
index c97a427..6e98caf 100644
--- a/builtin-fetch-pack.c
+++ b/builtin-fetch-pack.c
@@ -309,7 +309,8 @@
 		}
 		flushes--;
 	}
-	return retval;
+	/* it is no error to fetch into a completely empty repo */
+	return count ? retval : 0;
 }
 
 static struct commit_list *complete;
@@ -635,7 +636,7 @@
 	return dst;
 }
 
-static int fetch_pack_config(const char *var, const char *value)
+static int fetch_pack_config(const char *var, const char *value, void *cb)
 {
 	if (strcmp(var, "fetch.unpacklimit") == 0) {
 		fetch_unpack_limit = git_config_int(var, value);
@@ -647,7 +648,7 @@
 		return 0;
 	}
 
-	return git_default_config(var, value);
+	return git_default_config(var, value, cb);
 }
 
 static struct lock_file lock;
@@ -657,7 +658,7 @@
 	static int did_setup;
 	if (did_setup)
 		return;
-	git_config(fetch_pack_config);
+	git_config(fetch_pack_config, NULL);
 	if (0 <= transfer_unpack_limit)
 		unpack_limit = transfer_unpack_limit;
 	else if (0 <= fetch_unpack_limit)
diff --git a/builtin-fetch.c b/builtin-fetch.c
index 167f948..97fdc51 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -127,14 +127,8 @@
 		/* Merge everything on the command line, but not --tags */
 		for (rm = ref_map; rm; rm = rm->next)
 			rm->merge = 1;
-		if (tags == TAGS_SET) {
-			struct refspec refspec;
-			refspec.src = "refs/tags/";
-			refspec.dst = "refs/tags/";
-			refspec.pattern = 1;
-			refspec.force = 0;
-			get_fetch_map(remote_refs, &refspec, &tail, 0);
-		}
+		if (tags == TAGS_SET)
+			get_fetch_map(remote_refs, tag_refspec, &tail, 0);
 	} else {
 		/* Use the defaults */
 		struct remote *remote = transport->remote;
@@ -187,9 +181,9 @@
 	lock = lock_any_ref_for_update(ref->name,
 				       check_old ? ref->old_sha1 : NULL, 0);
 	if (!lock)
-		return 1;
+		return 2;
 	if (write_ref_sha1(lock, ref->new_sha1, msg) < 0)
-		return 1;
+		return 2;
 	return 0;
 }
 
@@ -239,10 +233,12 @@
 
 	if (!is_null_sha1(ref->old_sha1) &&
 	    !prefixcmp(ref->name, "refs/tags/")) {
-		sprintf(display, "- %-*s %-*s -> %s",
+		int r;
+		r = s_update_ref("updating tag", ref, 0);
+		sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '-',
 			SUMMARY_WIDTH, "[tag update]", REFCOL_WIDTH, remote,
-			pretty_ref);
-		return s_update_ref("updating tag", ref, 0);
+			pretty_ref, r ? "  (unable to update local ref)" : "");
+		return r;
 	}
 
 	current = lookup_commit_reference_gently(ref->old_sha1, 1);
@@ -250,6 +246,7 @@
 	if (!current || !updated) {
 		const char *msg;
 		const char *what;
+		int r;
 		if (!strncmp(ref->name, "refs/tags/", 10)) {
 			msg = "storing tag";
 			what = "[new tag]";
@@ -259,27 +256,36 @@
 			what = "[new branch]";
 		}
 
-		sprintf(display, "* %-*s %-*s -> %s", SUMMARY_WIDTH, what,
-			REFCOL_WIDTH, remote, pretty_ref);
-		return s_update_ref(msg, ref, 0);
+		r = s_update_ref(msg, ref, 0);
+		sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '*',
+			SUMMARY_WIDTH, what, REFCOL_WIDTH, remote, pretty_ref,
+			r ? "  (unable to update local ref)" : "");
+		return r;
 	}
 
 	if (in_merge_bases(current, &updated, 1)) {
 		char quickref[83];
+		int r;
 		strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
 		strcat(quickref, "..");
 		strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
-		sprintf(display, "  %-*s %-*s -> %s", SUMMARY_WIDTH, quickref,
-			REFCOL_WIDTH, remote, pretty_ref);
-		return s_update_ref("fast forward", ref, 1);
+		r = s_update_ref("fast forward", ref, 1);
+		sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : ' ',
+			SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
+			pretty_ref, r ? "  (unable to update local ref)" : "");
+		return r;
 	} else if (force || ref->force) {
 		char quickref[84];
+		int r;
 		strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
 		strcat(quickref, "...");
 		strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
-		sprintf(display, "+ %-*s %-*s -> %s  (forced update)",
-			SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, pretty_ref);
-		return s_update_ref("forced-update", ref, 1);
+		r = s_update_ref("forced-update", ref, 1);
+		sprintf(display, "%c %-*s %-*s -> %s  (%s)", r ? '!' : '+',
+			SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
+			pretty_ref,
+			r ? "unable to update local ref" : "forced update");
+		return r;
 	} else {
 		sprintf(display, "! %-*s %-*s -> %s  (non fast forward)",
 			SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote,
@@ -288,11 +294,12 @@
 	}
 }
 
-static int store_updated_refs(const char *url, struct ref *ref_map)
+static int store_updated_refs(const char *url, const char *remote_name,
+		struct ref *ref_map)
 {
 	FILE *fp;
 	struct commit *commit;
-	int url_len, i, note_len, shown_url = 0;
+	int url_len, i, note_len, shown_url = 0, rc = 0;
 	char note[1024];
 	const char *what, *kind;
 	struct ref *rm;
@@ -359,13 +366,11 @@
 			note);
 
 		if (ref)
-			update_local_ref(ref, what, verbose, note);
-		else if (verbose)
+			rc |= update_local_ref(ref, what, verbose, note);
+		else
 			sprintf(note, "* %-*s %-*s -> FETCH_HEAD",
 				SUMMARY_WIDTH, *kind ? kind : "branch",
 				 REFCOL_WIDTH, *what ? what : "HEAD");
-		else
-			*note = '\0';
 		if (*note) {
 			if (!shown_url) {
 				fprintf(stderr, "From %.*s\n",
@@ -376,7 +381,11 @@
 		}
 	}
 	fclose(fp);
-	return 0;
+	if (rc & 2)
+		error("some local refs could not be updated; try running\n"
+		      " 'git remote prune %s' to remove any old, conflicting "
+		      "branches", remote_name);
+	return rc;
 }
 
 /*
@@ -446,7 +455,9 @@
 	if (ret)
 		ret = transport_fetch_refs(transport, ref_map);
 	if (!ret)
-		ret |= store_updated_refs(transport->url, ref_map);
+		ret |= store_updated_refs(transport->url,
+				transport->remote->name,
+				ref_map);
 	transport_unlock_pack(transport);
 	return ret;
 }
@@ -510,10 +521,8 @@
 		     will_fetch(head, ref->old_sha1))) {
 			path_list_insert(ref_name, &new_refs);
 
-			rm = alloc_ref(strlen(ref_name) + 1);
-			strcpy(rm->name, ref_name);
-			rm->peer_ref = alloc_ref(strlen(ref_name) + 1);
-			strcpy(rm->peer_ref->name, ref_name);
+			rm = alloc_ref_from_str(ref_name);
+			rm->peer_ref = alloc_ref_from_str(ref_name);
 			hashcpy(rm->old_sha1, ref_sha1);
 
 			**tail = rm;
diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c
index 7077d52..b892621 100644
--- a/builtin-fmt-merge-msg.c
+++ b/builtin-fmt-merge-msg.c
@@ -6,13 +6,18 @@
 #include "tag.h"
 
 static const char *fmt_merge_msg_usage =
-	"git-fmt-merge-msg [--summary] [--no-summary] [--file <file>]";
+	"git-fmt-merge-msg [--log] [--no-log] [--file <file>]";
 
 static int merge_summary;
 
-static int fmt_merge_msg_config(const char *key, const char *value)
+static int fmt_merge_msg_config(const char *key, const char *value, void *cb)
 {
-	if (!strcmp("merge.summary", key))
+	static int found_merge_log = 0;
+	if (!strcmp("merge.log", key)) {
+		found_merge_log = 1;
+		merge_summary = git_config_bool(key, value);
+	}
+	if (!found_merge_log && !strcmp("merge.summary", key))
 		merge_summary = git_config_bool(key, value);
 	return 0;
 }
@@ -255,12 +260,13 @@
 	unsigned char head_sha1[20];
 	const char *current_branch;
 
-	git_config(fmt_merge_msg_config);
+	git_config(fmt_merge_msg_config, NULL);
 
 	while (argc > 1) {
-		if (!strcmp(argv[1], "--summary"))
+		if (!strcmp(argv[1], "--log") || !strcmp(argv[1], "--summary"))
 			merge_summary = 1;
-		else if (!strcmp(argv[1], "--no-summary"))
+		else if (!strcmp(argv[1], "--no-log")
+				|| !strcmp(argv[1], "--no-summary"))
 			merge_summary = 0;
 		else if (!strcmp(argv[1], "-F") || !strcmp(argv[1], "--file")) {
 			if (argc < 3)
diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c
index 07d9c57..fef93d7 100644
--- a/builtin-for-each-ref.c
+++ b/builtin-for-each-ref.c
@@ -234,6 +234,13 @@
 			name++;
 		if (!strcmp(name, "tag"))
 			v->s = tag->tag;
+		else if (!strcmp(name, "type") && tag->tagged)
+			v->s = typename(tag->tagged->type);
+		else if (!strcmp(name, "object") && tag->tagged) {
+			char *s = xmalloc(41);
+			strcpy(s, sha1_to_hex(tag->tagged->sha1));
+			v->s = s;
+		}
 	}
 }
 
diff --git a/builtin-gc.c b/builtin-gc.c
index 8cef36f..f5625bb 100644
--- a/builtin-gc.c
+++ b/builtin-gc.c
@@ -35,7 +35,7 @@
 static const char *argv_prune[] = {"prune", "--expire", NULL, NULL};
 static const char *argv_rerere[] = {"rerere", "gc", NULL};
 
-static int gc_config(const char *var, const char *value)
+static int gc_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "gc.packrefs")) {
 		if (value && !strcmp(value, "notbare"))
@@ -67,7 +67,7 @@
 		prune_expire = xstrdup(value);
 		return 0;
 	}
-	return git_default_config(var, value);
+	return git_default_config(var, value, cb);
 }
 
 static void append_option(const char **cmd, const char *opt, int max_length)
@@ -157,6 +157,34 @@
 	return gc_auto_pack_limit <= cnt;
 }
 
+static int run_hook(void)
+{
+	const char *argv[2];
+	struct child_process hook;
+	int ret;
+
+	argv[0] = git_path("hooks/pre-auto-gc");
+	argv[1] = NULL;
+
+	if (access(argv[0], X_OK) < 0)
+		return 0;
+
+	memset(&hook, 0, sizeof(hook));
+	hook.argv = argv;
+	hook.no_stdin = 1;
+	hook.stdout_to_stderr = 1;
+
+	ret = start_command(&hook);
+	if (ret) {
+		warning("Could not spawn %s", argv[0]);
+		return ret;
+	}
+	ret = finish_command(&hook);
+	if (ret == -ERR_RUN_COMMAND_WAITPID_SIGNAL)
+		warning("%s exited due to uncaught signal", argv[0]);
+	return ret;
+}
+
 static int need_to_gc(void)
 {
 	/*
@@ -176,6 +204,9 @@
 		append_option(argv_repack, "-A", MAX_ADD);
 	else if (!too_many_loose_objects())
 		return 0;
+
+	if (run_hook())
+		return 0;
 	return 1;
 }
 
@@ -188,14 +219,14 @@
 	char buf[80];
 
 	struct option builtin_gc_options[] = {
-		OPT_BOOLEAN(0, "prune", &prune, "prune unreferenced objects"),
+		OPT_BOOLEAN(0, "prune", &prune, "prune unreferenced objects (deprecated)"),
 		OPT_BOOLEAN(0, "aggressive", &aggressive, "be more thorough (increased runtime)"),
 		OPT_BOOLEAN(0, "auto", &auto_gc, "enable auto-gc mode"),
 		OPT_BOOLEAN('q', "quiet", &quiet, "suppress progress reports"),
 		OPT_END()
 	};
 
-	git_config(gc_config);
+	git_config(gc_config, NULL);
 
 	if (pack_refs < 0)
 		pack_refs = !is_bare_repository();
@@ -218,24 +249,14 @@
 		/*
 		 * Auto-gc should be least intrusive as possible.
 		 */
-		prune = 0;
 		if (!need_to_gc())
 			return 0;
 		fprintf(stderr, "Auto packing your repository for optimum "
 			"performance. You may also\n"
 			"run \"git gc\" manually. See "
 			"\"git help gc\" for more information.\n");
-	} else {
-		/*
-		 * Use safer (for shared repos) "-A" option to
-		 * repack when not pruning. Auto-gc makes its
-		 * own decision.
-		 */
-		if (prune)
-			append_option(argv_repack, "-a", MAX_ADD);
-		else
-			append_option(argv_repack, "-A", MAX_ADD);
-	}
+	} else
+		append_option(argv_repack, "-A", MAX_ADD);
 
 	if (pack_refs && run_command_v_opt(argv_pack_refs, RUN_GIT_CMD))
 		return error(FAILED_RUN, argv_pack_refs[0]);
diff --git a/builtin-grep.c b/builtin-grep.c
index ef29910..d8b06ce 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-http-fetch.c b/builtin-http-fetch.c
index b1f3389..3a06248 100644
--- a/builtin-http-fetch.c
+++ b/builtin-http-fetch.c
@@ -18,7 +18,7 @@
 	int get_verbosely = 0;
 	int get_recover = 0;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	while (arg < argc && argv[arg][0] == '-') {
 		if (argv[arg][1] == 't') {
diff --git a/builtin-init-db.c b/builtin-init-db.c
index 2854868..c68a3b1 100644
--- a/builtin-init-db.c
+++ b/builtin-init-db.c
@@ -104,12 +104,14 @@
 	}
 }
 
-static void copy_templates(const char *git_dir, int len, const char *template_dir)
+static void copy_templates(const char *template_dir)
 {
 	char path[PATH_MAX];
 	char template_path[PATH_MAX];
 	int template_len;
 	DIR *dir;
+	const char *git_dir = get_git_dir();
+	int len = strlen(git_dir);
 
 	if (!template_dir)
 		template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
@@ -125,6 +127,8 @@
 			template_dir = strbuf_detach(&d, NULL);
 		}
 	}
+	if (!template_dir[0])
+		return;
 	strcpy(template_path, template_dir);
 	template_len = strlen(template_path);
 	if (template_path[template_len-1] != '/') {
@@ -142,7 +146,7 @@
 	strcpy(template_path + template_len, "config");
 	repository_format_version = 0;
 	git_config_from_file(check_repository_format_version,
-			     template_path);
+			     template_path, NULL);
 	template_path[template_len] = 0;
 
 	if (repository_format_version &&
@@ -156,6 +160,8 @@
 	}
 
 	memcpy(path, git_dir, len);
+	if (len && path[len - 1] != '/')
+		path[len++] = '/';
 	path[len] = 0;
 	copy_templates_1(path, len,
 			 template_path, template_len,
@@ -163,8 +169,9 @@
 	closedir(dir);
 }
 
-static int create_default_files(const char *git_dir, const char *template_path)
+static int create_default_files(const char *template_path)
 {
+	const char *git_dir = get_git_dir();
 	unsigned len = strlen(git_dir);
 	static char path[PATH_MAX];
 	struct stat st1;
@@ -183,35 +190,27 @@
 	/*
 	 * Create .git/refs/{heads,tags}
 	 */
-	strcpy(path + len, "refs");
-	safe_create_dir(path, 1);
-	strcpy(path + len, "refs/heads");
-	safe_create_dir(path, 1);
-	strcpy(path + len, "refs/tags");
-	safe_create_dir(path, 1);
+	safe_create_dir(git_path("refs"), 1);
+	safe_create_dir(git_path("refs/heads"), 1);
+	safe_create_dir(git_path("refs/tags"), 1);
 
 	/* First copy the templates -- we might have the default
 	 * config file there, in which case we would want to read
 	 * from it after installing.
 	 */
-	path[len] = 0;
-	copy_templates(path, len, template_path);
+	copy_templates(template_path);
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	/*
 	 * We would have created the above under user's umask -- under
 	 * shared-repository settings, we would need to fix them up.
 	 */
 	if (shared_repository) {
-		path[len] = 0;
-		adjust_shared_perm(path);
-		strcpy(path + len, "refs");
-		adjust_shared_perm(path);
-		strcpy(path + len, "refs/heads");
-		adjust_shared_perm(path);
-		strcpy(path + len, "refs/tags");
-		adjust_shared_perm(path);
+		adjust_shared_perm(get_git_dir());
+		adjust_shared_perm(git_path("refs"));
+		adjust_shared_perm(git_path("refs/heads"));
+		adjust_shared_perm(git_path("refs/tags"));
 	}
 
 	/*
@@ -251,12 +250,14 @@
 		/* allow template config file to override the default */
 		if (log_all_ref_updates == -1)
 		    git_config_set("core.logallrefupdates", "true");
-		if (work_tree != git_work_tree_cfg)
+		if (prefixcmp(git_dir, work_tree) ||
+		    strcmp(git_dir + strlen(work_tree), "/.git")) {
 			git_config_set("core.worktree", work_tree);
+		}
 	}
 
-	/* Check if symlink is supported in the work tree */
 	if (!reinit) {
+		/* Check if symlink is supported in the work tree */
 		path[len] = 0;
 		strcpy(path + len, "tXXXXXX");
 		if (!close(xmkstemp(path)) &&
@@ -267,51 +268,105 @@
 			unlink(path); /* good */
 		else
 			git_config_set("core.symlinks", "false");
+
+		/* Check if the filesystem is case-insensitive */
+		path[len] = 0;
+		strcpy(path + len, "CoNfIg");
+		if (!access(path, F_OK))
+			git_config_set("core.ignorecase", "true");
 	}
 
 	return reinit;
 }
 
-static void guess_repository_type(const char *git_dir)
+int init_db(const char *template_dir, unsigned int flags)
+{
+	const char *sha1_dir;
+	char *path;
+	int len, reinit;
+
+	safe_create_dir(get_git_dir(), 0);
+
+	/* Check to see if the repository version is right.
+	 * Note that a newly created repository does not have
+	 * config file, so this will not fail.  What we are catching
+	 * is an attempt to reinitialize new repository with an old tool.
+	 */
+	check_repository_format();
+
+	reinit = create_default_files(template_dir);
+
+	sha1_dir = get_object_directory();
+	len = strlen(sha1_dir);
+	path = xmalloc(len + 40);
+	memcpy(path, sha1_dir, len);
+
+	safe_create_dir(sha1_dir, 1);
+	strcpy(path+len, "/pack");
+	safe_create_dir(path, 1);
+	strcpy(path+len, "/info");
+	safe_create_dir(path, 1);
+
+	if (shared_repository) {
+		char buf[10];
+		/* We do not spell "group" and such, so that
+		 * the configuration can be read by older version
+		 * of git. Note, we use octal numbers for new share modes,
+		 * and compatibility values for PERM_GROUP and
+		 * PERM_EVERYBODY.
+		 */
+		if (shared_repository == PERM_GROUP)
+			sprintf(buf, "%d", OLD_PERM_GROUP);
+		else if (shared_repository == PERM_EVERYBODY)
+			sprintf(buf, "%d", OLD_PERM_EVERYBODY);
+		else
+			sprintf(buf, "0%o", shared_repository);
+		git_config_set("core.sharedrepository", buf);
+		git_config_set("receive.denyNonFastforwards", "true");
+	}
+
+	if (!(flags & INIT_DB_QUIET))
+		printf("%s%s Git repository in %s/\n",
+		       reinit ? "Reinitialized existing" : "Initialized empty",
+		       shared_repository ? " shared" : "",
+		       get_git_dir());
+
+	return 0;
+}
+
+static int guess_repository_type(const char *git_dir)
 {
 	char cwd[PATH_MAX];
 	const char *slash;
 
-	if (0 <= is_bare_repository_cfg)
-		return;
-	if (!git_dir)
-		return;
-
 	/*
 	 * "GIT_DIR=. git init" is always bare.
 	 * "GIT_DIR=`pwd` git init" too.
 	 */
 	if (!strcmp(".", git_dir))
-		goto force_bare;
+		return 1;
 	if (!getcwd(cwd, sizeof(cwd)))
 		die("cannot tell cwd");
 	if (!strcmp(git_dir, cwd))
-		goto force_bare;
+		return 1;
 	/*
 	 * "GIT_DIR=.git or GIT_DIR=something/.git is usually not.
 	 */
 	if (!strcmp(git_dir, ".git"))
-		return;
+		return 0;
 	slash = strrchr(git_dir, '/');
 	if (slash && !strcmp(slash, "/.git"))
-		return;
+		return 0;
 
 	/*
 	 * Otherwise it is often bare.  At this point
 	 * we are just guessing.
 	 */
- force_bare:
-	is_bare_repository_cfg = 1;
-	return;
+	return 1;
 }
 
 static const char init_db_usage[] =
-"git-init [-q | --quiet] [--template=<template-directory>] [--shared]";
+"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.
@@ -322,22 +377,25 @@
 int cmd_init_db(int argc, const char **argv, const char *prefix)
 {
 	const char *git_dir;
-	const char *sha1_dir;
 	const char *template_dir = NULL;
-	char *path;
-	int len, i, reinit;
-	int quiet = 0;
+	unsigned int flags = 0;
+	int i;
 
 	for (i = 1; i < argc; i++, argv++) {
 		const char *arg = argv[1];
 		if (!prefixcmp(arg, "--template="))
 			template_dir = arg+11;
-		else if (!strcmp(arg, "--shared"))
+		else if (!strcmp(arg, "--bare")) {
+			static char git_dir[PATH_MAX+1];
+			is_bare_repository_cfg = 1;
+			setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir,
+						sizeof(git_dir)), 0);
+		} else if (!strcmp(arg, "--shared"))
 			shared_repository = PERM_GROUP;
 		else if (!prefixcmp(arg, "--shared="))
 			shared_repository = git_config_perm("arg", arg+9);
 		else if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet"))
-		        quiet = 1;
+			flags |= INIT_DB_QUIET;
 		else
 			usage(init_db_usage);
 	}
@@ -354,64 +412,35 @@
 		    GIT_WORK_TREE_ENVIRONMENT,
 		    GIT_DIR_ENVIRONMENT);
 
-	guess_repository_type(git_dir);
+	/*
+	 * Set up the default .git directory contents
+	 */
+	if (!git_dir)
+		git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
 
-	if (is_bare_repository_cfg <= 0) {
-		git_work_tree_cfg = xcalloc(PATH_MAX, 1);
-		if (!getcwd(git_work_tree_cfg, PATH_MAX))
-			die ("Cannot access current working directory.");
+	if (is_bare_repository_cfg < 0)
+		is_bare_repository_cfg = guess_repository_type(git_dir);
+
+	if (!is_bare_repository_cfg) {
+		if (git_dir) {
+			const char *git_dir_parent = strrchr(git_dir, '/');
+			if (git_dir_parent) {
+				char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
+				git_work_tree_cfg = xstrdup(make_absolute_path(rel));
+				free(rel);
+			}
+		}
+		if (!git_work_tree_cfg) {
+			git_work_tree_cfg = xcalloc(PATH_MAX, 1);
+			if (!getcwd(git_work_tree_cfg, PATH_MAX))
+				die ("Cannot access current working directory.");
+		}
 		if (access(get_git_work_tree(), X_OK))
 			die ("Cannot access work tree '%s'",
 			     get_git_work_tree());
 	}
 
-	/*
-	 * Set up the default .git directory contents
-	 */
-	git_dir = getenv(GIT_DIR_ENVIRONMENT);
-	if (!git_dir)
-		git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
-	safe_create_dir(git_dir, 0);
+	set_git_dir(make_absolute_path(git_dir));
 
-	/* Check to see if the repository version is right.
-	 * Note that a newly created repository does not have
-	 * config file, so this will not fail.  What we are catching
-	 * is an attempt to reinitialize new repository with an old tool.
-	 */
-	check_repository_format();
-
-	reinit = create_default_files(git_dir, template_dir);
-
-	/*
-	 * And set up the object store.
-	 */
-	sha1_dir = get_object_directory();
-	len = strlen(sha1_dir);
-	path = xmalloc(len + 40);
-	memcpy(path, sha1_dir, len);
-
-	safe_create_dir(sha1_dir, 1);
-	strcpy(path+len, "/pack");
-	safe_create_dir(path, 1);
-	strcpy(path+len, "/info");
-	safe_create_dir(path, 1);
-
-	if (shared_repository) {
-		char buf[10];
-		/* We do not spell "group" and such, so that
-		 * the configuration can be read by older version
-		 * of git.
-		 */
-		sprintf(buf, "%d", shared_repository);
-		git_config_set("core.sharedrepository", buf);
-		git_config_set("receive.denyNonFastforwards", "true");
-	}
-
-	if (!quiet)
-		printf("%s%s Git repository in %s/\n",
-		       reinit ? "Reinitialized existing" : "Initialized empty",
-		       shared_repository ? " shared" : "",
-		       git_dir);
-
-	return 0;
+	return init_db(template_dir, flags);
 }
diff --git a/builtin-log.c b/builtin-log.c
index 5c00725..430d876 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -18,6 +18,9 @@
 #include "run-command.h"
 #include "shortlog.h"
 
+/* Set a default date-time format for git log ("log.date" config variable) */
+static const char *default_date_mode = NULL;
+
 static int default_show_root = 1;
 static const char *fmt_patch_subject_prefix = "PATCH";
 static const char *fmt_pretty;
@@ -56,12 +59,17 @@
 	rev->abbrev = DEFAULT_ABBREV;
 	rev->commit_format = CMIT_FMT_DEFAULT;
 	if (fmt_pretty)
-		rev->commit_format = get_commit_format(fmt_pretty);
+		get_commit_format(fmt_pretty, rev);
 	rev->verbose_header = 1;
 	DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
 	rev->show_root_diff = default_show_root;
 	rev->subject_prefix = fmt_patch_subject_prefix;
+
+	if (default_date_mode)
+		rev->date_mode = parse_date_format(default_date_mode);
+
 	argc = setup_revisions(argc, argv, rev, "HEAD");
+
 	if (rev->diffopt.pickaxe || rev->diffopt.filter)
 		rev->always_show_header = 0;
 	if (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) {
@@ -222,28 +230,26 @@
 	return 0;
 }
 
-static int git_log_config(const char *var, const char *value)
+static int git_log_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "format.pretty"))
 		return git_config_string(&fmt_pretty, var, value);
-	if (!strcmp(var, "format.subjectprefix")) {
-		if (!value)
-			config_error_nonbool(var);
-		fmt_patch_subject_prefix = xstrdup(value);
-		return 0;
-	}
+	if (!strcmp(var, "format.subjectprefix"))
+		return git_config_string(&fmt_patch_subject_prefix, var, value);
+	if (!strcmp(var, "log.date"))
+		return git_config_string(&default_date_mode, var, value);
 	if (!strcmp(var, "log.showroot")) {
 		default_show_root = git_config_bool(var, value);
 		return 0;
 	}
-	return git_diff_ui_config(var, value);
+	return git_diff_ui_config(var, value, cb);
 }
 
 int cmd_whatchanged(int argc, const char **argv, const char *prefix)
 {
 	struct rev_info rev;
 
-	git_config(git_log_config);
+	git_config(git_log_config, NULL);
 
 	if (diff_use_color_default == -1)
 		diff_use_color_default = git_use_color_default;
@@ -319,7 +325,7 @@
 	struct object_array_entry *objects;
 	int i, count, ret = 0;
 
-	git_config(git_log_config);
+	git_config(git_log_config, NULL);
 
 	if (diff_use_color_default == -1)
 		diff_use_color_default = git_use_color_default;
@@ -350,7 +356,7 @@
 					t->tag,
 					diff_get_color_opt(&rev.diffopt, DIFF_RESET));
 			ret = show_object(o->sha1, 1, &rev);
-			objects[i].item = (struct object *)t->tagged;
+			objects[i].item = parse_object(t->tagged->sha1);
 			i--;
 			break;
 		}
@@ -383,7 +389,7 @@
 {
 	struct rev_info rev;
 
-	git_config(git_log_config);
+	git_config(git_log_config, NULL);
 
 	if (diff_use_color_default == -1)
 		diff_use_color_default = git_use_color_default;
@@ -400,6 +406,7 @@
 	 * allow us to set a different default.
 	 */
 	rev.commit_format = CMIT_FMT_ONELINE;
+	rev.use_terminator = 1;
 	rev.always_show_header = 1;
 
 	/*
@@ -415,7 +422,7 @@
 {
 	struct rev_info rev;
 
-	git_config(git_log_config);
+	git_config(git_log_config, NULL);
 
 	if (diff_use_color_default == -1)
 		diff_use_color_default = git_use_color_default;
@@ -470,7 +477,7 @@
 	extra_hdr[extra_hdr_nr++] = xstrndup(value, len);
 }
 
-static int git_format_config(const char *var, const char *value)
+static int git_format_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "format.headers")) {
 		if (!value)
@@ -478,10 +485,13 @@
 		add_header(value);
 		return 0;
 	}
-	if (!strcmp(var, "format.suffix")) {
+	if (!strcmp(var, "format.suffix"))
+		return git_config_string(&fmt_patch_suffix, var, value);
+	if (!strcmp(var, "format.cc")) {
 		if (!value)
 			return config_error_nonbool(var);
-		fmt_patch_suffix = xstrdup(value);
+		ALLOC_GROW(extra_cc, extra_cc_nr + 1, extra_cc_alloc);
+		extra_cc[extra_cc_nr++] = xstrdup(value);
 		return 0;
 	}
 	if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
@@ -496,7 +506,7 @@
 		return 0;
 	}
 
-	return git_log_config(var, value);
+	return git_log_config(var, value, cb);
 }
 
 
@@ -756,20 +766,20 @@
 	int thread = 0;
 	int cover_letter = 0;
 	int boundary_count = 0;
+	int no_binary_diff = 0;
 	struct commit *origin = NULL, *head = NULL;
 	const char *in_reply_to = NULL;
 	struct patch_ids ids;
 	char *add_signoff = NULL;
 	struct strbuf buf;
 
-	git_config(git_format_config);
+	git_config(git_format_config, NULL);
 	init_revisions(&rev, prefix);
 	rev.commit_format = CMIT_FMT_EMAIL;
 	rev.verbose_header = 1;
 	rev.diff = 1;
 	rev.combine_merges = 0;
 	rev.ignore_merges = 1;
-	rev.diffopt.msg_sep = "";
 	DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
 
 	rev.subject_prefix = fmt_patch_subject_prefix;
@@ -862,6 +872,8 @@
 			fmt_patch_suffix = argv[i] + 9;
 		else if (!strcmp(argv[i], "--cover-letter"))
 			cover_letter = 1;
+		else if (!strcmp(argv[i], "--no-binary"))
+			no_binary_diff = 1;
 		else
 			argv[j++] = argv[i];
 	}
@@ -914,7 +926,7 @@
 	if (!rev.diffopt.output_format)
 		rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SUMMARY | DIFF_FORMAT_PATCH;
 
-	if (!DIFF_OPT_TST(&rev.diffopt, TEXT))
+	if (!DIFF_OPT_TST(&rev.diffopt, TEXT) && !no_binary_diff)
 		DIFF_OPT_SET(&rev.diffopt, BINARY);
 
 	if (!output_directory && !use_stdout)
diff --git a/builtin-ls-files.c b/builtin-ls-files.c
index dc7eab8..75ba422 100644
--- a/builtin-ls-files.c
+++ b/builtin-ls-files.c
@@ -437,7 +437,7 @@
 	memset(&dir, 0, sizeof(dir));
 	if (prefix)
 		prefix_offset = strlen(prefix);
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
diff --git a/builtin-ls-tree.c b/builtin-ls-tree.c
index 7abe333..f4a75dd 100644
--- a/builtin-ls-tree.c
+++ b/builtin-ls-tree.c
@@ -122,7 +122,7 @@
 	unsigned char sha1[20];
 	struct tree *tree;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	ls_tree_prefix = prefix;
 	if (prefix && *prefix)
 		chomp_prefix = strlen(prefix);
diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
index 11f154b..13f0502 100644
--- a/builtin-mailinfo.c
+++ b/builtin-mailinfo.c
@@ -334,7 +334,9 @@
 		return 1;
 	if (!memcmp("[PATCH]", line, 7) && isspace(line[7])) {
 		for (i = 0; header[i]; i++) {
-			if (!memcmp("Subject: ", header[i], 9)) {
+			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;
 				}
@@ -434,6 +436,7 @@
 
 static int decode_q_segment(char *in, char *ot, unsigned otsize, char *ep, int rfc2047)
 {
+	char *otbegin = ot;
 	char *otend = ot + otsize;
 	int c;
 	while ((c = *in++) != 0 && (in <= ep)) {
@@ -453,13 +456,14 @@
 		*ot++ = c;
 	}
 	*ot = 0;
-	return 0;
+	return (ot - otbegin);
 }
 
 static int decode_b_segment(char *in, char *ot, unsigned otsize, char *ep)
 {
 	/* Decode in..ep, possibly in-place to ot */
 	int c, pos = 0, acc = 0;
+	char *otbegin = ot;
 	char *otend = ot + otsize;
 
 	while ((c = *in++) != 0 && (in <= ep)) {
@@ -505,7 +509,7 @@
 		}
 	}
 	*ot = 0;
-	return 0;
+	return (ot - otbegin);
 }
 
 /*
@@ -623,25 +627,24 @@
 		convert_to_utf8(it, itsize, "");
 }
 
-static void decode_transfer_encoding(char *line, unsigned linesize)
+static int decode_transfer_encoding(char *line, unsigned linesize, int inputlen)
 {
 	char *ep;
 
 	switch (transfer_encoding) {
 	case TE_QP:
-		ep = line + strlen(line);
-		decode_q_segment(line, line, linesize, ep, 0);
-		break;
+		ep = line + inputlen;
+		return decode_q_segment(line, line, linesize, ep, 0);
 	case TE_BASE64:
-		ep = line + strlen(line);
-		decode_b_segment(line, line, linesize, ep);
-		break;
+		ep = line + inputlen;
+		return decode_b_segment(line, line, linesize, ep);
 	case TE_DONTCARE:
-		break;
+	default:
+		return inputlen;
 	}
 }
 
-static int handle_filter(char *line, unsigned linesize);
+static int handle_filter(char *line, unsigned linesize, int linelen);
 
 static int find_boundary(void)
 {
@@ -669,7 +672,7 @@
 					"can't recover\n");
 			exit(1);
 		}
-		handle_filter(newline, sizeof(newline));
+		handle_filter(newline, sizeof(newline), strlen(newline));
 
 		/* skip to the next boundary */
 		if (!find_boundary())
@@ -759,14 +762,14 @@
 	return 0;
 }
 
-static int handle_patch(char *line)
+static int handle_patch(char *line, int len)
 {
-	fputs(line, patchfile);
+	fwrite(line, 1, len, patchfile);
 	patch_lines++;
 	return 0;
 }
 
-static int handle_filter(char *line, unsigned linesize)
+static int handle_filter(char *line, unsigned linesize, int linelen)
 {
 	static int filter = 0;
 
@@ -779,7 +782,7 @@
 			break;
 		filter++;
 	case 1:
-		if (!handle_patch(line))
+		if (!handle_patch(line, linelen))
 			break;
 		filter++;
 	default:
@@ -794,6 +797,7 @@
 	int rc = 0;
 	static char newline[2000];
 	static char *np = newline;
+	int len = strlen(line);
 
 	/* Skip up to the first boundary */
 	if (content_top->boundary) {
@@ -805,16 +809,20 @@
 		/* process any boundary lines */
 		if (content_top->boundary && is_multipart_boundary(line)) {
 			/* flush any leftover */
-			if ((transfer_encoding == TE_BASE64)  &&
-			    (np != newline)) {
-				handle_filter(newline, sizeof(newline));
-			}
+			if (np != newline)
+				handle_filter(newline, sizeof(newline),
+					      np - newline);
 			if (!handle_boundary())
 				return;
+			len = strlen(line);
 		}
 
 		/* Unwrap transfer encoding */
-		decode_transfer_encoding(line, sizeof(line));
+		len = decode_transfer_encoding(line, sizeof(line), len);
+		if (len < 0) {
+			error("Malformed input line");
+			return;
+		}
 
 		switch (transfer_encoding) {
 		case TE_BASE64:
@@ -824,39 +832,40 @@
 
 			/* binary data most likely doesn't have newlines */
 			if (message_type != TYPE_TEXT) {
-				rc = handle_filter(line, sizeof(newline));
+				rc = handle_filter(line, sizeof(line), len);
 				break;
 			}
 
-			/* this is a decoded line that may contain
+			/*
+			 * This is a decoded line that may contain
 			 * multiple new lines.  Pass only one chunk
 			 * at a time to handle_filter()
 			 */
-
 			do {
-				while (*op != '\n' && *op != 0)
+				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));
+					rc = handle_filter(newline, sizeof(newline), np - newline);
 					np = newline;
 				}
-			} while (*op != 0);
-			/* the partial chunk is saved in newline and
-			 * will be appended by the next iteration of fgets
+			} while (op < line + len);
+			/*
+			 * The partial chunk is saved in newline and will be
+			 * appended by the next iteration of read_line_with_nul().
 			 */
 			break;
 		}
 		default:
-			rc = handle_filter(line, sizeof(newline));
+			rc = handle_filter(line, sizeof(line), len);
 		}
 		if (rc)
 			/* nothing left to filter */
 			break;
-	} while (fgets(line, sizeof(line), fin));
+	} while ((len = read_line_with_nul(line, sizeof(line), fin)));
 
 	return;
 }
@@ -953,7 +962,7 @@
 }
 
 static const char mailinfo_usage[] =
-	"git-mailinfo [-k] [-u | --encoding=<encoding>] 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)
 {
@@ -962,7 +971,7 @@
 	/* NEEDSWORK: might want to do the optional .git/ directory
 	 * discovery
 	 */
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	def_charset = (git_commit_encoding ? git_commit_encoding : "utf-8");
 	metainfo_charset = def_charset;
diff --git a/builtin-mailsplit.c b/builtin-mailsplit.c
index 46b27cd..ae2b4cb 100644
--- a/builtin-mailsplit.c
+++ b/builtin-mailsplit.c
@@ -45,6 +45,24 @@
 /* Could be as small as 64, enough to hold a Unix "From " line. */
 static char buf[4096];
 
+/* We cannot use fgets() because our lines can contain NULs */
+int read_line_with_nul(char *buf, int size, FILE *in)
+{
+	int len = 0, c;
+
+	for (;;) {
+		c = getc(in);
+		if (c == EOF)
+			break;
+		buf[len++] = c;
+		if (c == '\n' || len + 1 >= size)
+			break;
+	}
+	buf[len] = '\0';
+
+	return len;
+}
+
 /* Called with the first line (potentially partial)
  * already in buf[] -- normally that should begin with
  * the Unix "From " line.  Write it into the specified
@@ -70,19 +88,19 @@
 	 * "From " and having something that looks like a date format.
 	 */
 	for (;;) {
-		int is_partial = (buf[len-1] != '\n');
+		int is_partial = len && buf[len-1] != '\n';
 
-		if (fputs(buf, output) == EOF)
+		if (fwrite(buf, 1, len, output) != len)
 			die("cannot write output");
 
-		if (fgets(buf, sizeof(buf), mbox) == NULL) {
+		len = read_line_with_nul(buf, sizeof(buf), mbox);
+		if (len == 0) {
 			if (feof(mbox)) {
 				status = 1;
 				break;
 			}
 			die("cannot read mbox");
 		}
-		len = strlen(buf);
 		if (!is_partial && !is_bare && is_from_line(buf, len))
 			break; /* done with one message */
 	}
diff --git a/builtin-merge-base.c b/builtin-merge-base.c
index 0108e22..bcf9395 100644
--- a/builtin-merge-base.c
+++ b/builtin-merge-base.c
@@ -28,7 +28,7 @@
 	unsigned char rev1key[20], rev2key[20];
 	int show_all = 0;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	while (1 < argc && argv[1][0] == '-') {
 		const char *arg = argv[1];
diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c
index 910c0d2..43bf6aa 100644
--- a/builtin-merge-recursive.c
+++ b/builtin-merge-recursive.c
@@ -92,7 +92,8 @@
 
 static int call_depth = 0;
 static int verbosity = 2;
-static int rename_limit = -1;
+static int diff_rename_limit = -1;
+static int merge_rename_limit = -1;
 static int buffer_output = 1;
 static struct strbuf obuf = STRBUF_INIT;
 
@@ -361,7 +362,10 @@
 	diff_setup(&opts);
 	DIFF_OPT_SET(&opts, RECURSIVE);
 	opts.detect_rename = DIFF_DETECT_RENAME;
-	opts.rename_limit = rename_limit;
+	opts.rename_limit = merge_rename_limit >= 0 ? merge_rename_limit :
+			    diff_rename_limit >= 0 ? diff_rename_limit :
+			    500;
+	opts.warn_on_too_large_rename = 1;
 	opts.output_format = DIFF_FORMAT_NO_OUTPUT;
 	if (diff_setup_done(&opts) < 0)
 		die("diff setup failed");
@@ -477,15 +481,6 @@
 	return newpath;
 }
 
-static int mkdir_p(const char *path, unsigned long mode)
-{
-	/* path points to cache entries, so xstrdup before messing with it */
-	char *buf = xstrdup(path);
-	int result = safe_create_leading_directories(buf);
-	free(buf);
-	return result;
-}
-
 static void flush_buffer(int fd, const char *buf, unsigned long size)
 {
 	while (size > 0) {
@@ -508,7 +503,7 @@
 	int status;
 	const char *msg = "failed to create path '%s'%s";
 
-	status = mkdir_p(path, 0777);
+	status = safe_create_leading_directories_const(path);
 	if (status) {
 		if (status == -3) {
 			/* something else exists */
@@ -551,9 +546,19 @@
 			die("cannot read object %s '%s'", sha1_to_hex(sha), path);
 		if (type != OBJ_BLOB)
 			die("blob expected for %s '%s'", sha1_to_hex(sha), path);
+		if (S_ISREG(mode)) {
+			struct strbuf strbuf;
+			strbuf_init(&strbuf, 0);
+			if (convert_to_working_tree(path, buf, size, &strbuf)) {
+				free(buf);
+				size = strbuf.len;
+				buf = strbuf_detach(&strbuf, NULL);
+			}
+		}
 
 		if (make_room_for_path(path) < 0) {
 			update_wd = 0;
+			free(buf);
 			goto update_index;
 		}
 		if (S_ISREG(mode) || (!has_symlinks && S_ISLNK(mode))) {
@@ -569,13 +574,14 @@
 			close(fd);
 		} else if (S_ISLNK(mode)) {
 			char *lnk = xmemdupz(buf, size);
-			mkdir_p(path, 0777);
+			safe_create_leading_directories_const(path);
 			unlink(path);
 			symlink(lnk, path);
 			free(lnk);
 		} else
 			die("do not know what to do with %06o %s '%s'",
 			    mode, sha1_to_hex(sha), path);
+		free(buf);
 	}
  update_index:
 	if (update_cache)
@@ -1336,17 +1342,21 @@
 	return (struct commit *)object;
 }
 
-static int merge_config(const char *var, const char *value)
+static int merge_config(const char *var, const char *value, void *cb)
 {
 	if (!strcasecmp(var, "merge.verbosity")) {
 		verbosity = git_config_int(var, value);
 		return 0;
 	}
 	if (!strcasecmp(var, "diff.renamelimit")) {
-		rename_limit = git_config_int(var, value);
+		diff_rename_limit = git_config_int(var, value);
 		return 0;
 	}
-	return git_default_config(var, value);
+	if (!strcasecmp(var, "merge.renamelimit")) {
+		merge_rename_limit = git_config_int(var, value);
+		return 0;
+	}
+	return git_default_config(var, value, cb);
 }
 
 int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
@@ -1367,7 +1377,7 @@
 			subtree_merge = 1;
 	}
 
-	git_config(merge_config);
+	git_config(merge_config, NULL);
 	if (getenv("GIT_MERGE_VERBOSITY"))
 		verbosity = strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10);
 
diff --git a/builtin-mv.c b/builtin-mv.c
index 94f6dd2..5530e11 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -81,7 +81,7 @@
 	struct path_list deleted = {NULL, 0, 0, 0};
 	struct path_list changed = {NULL, 0, 0, 0};
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	newfd = hold_locked_index(&lock_file, 1);
 	if (read_cache() < 0)
@@ -256,7 +256,8 @@
 
 		for (i = 0; i < added.nr; i++) {
 			const char *path = added.items[i].path;
-			add_file_to_cache(path, verbose);
+			if (add_file_to_cache(path, verbose ? ADD_CACHE_VERBOSE : 0))
+				die("updating index entries failed");
 		}
 
 		for (i = 0; i < deleted.nr; i++)
diff --git a/builtin-name-rev.c b/builtin-name-rev.c
index 521f061..5352bc8 100644
--- a/builtin-name-rev.c
+++ b/builtin-name-rev.c
@@ -176,6 +176,48 @@
 	NULL
 };
 
+static void name_rev_line(char *p, struct name_ref_data *data)
+{
+	int forty = 0;
+	char *p_start;
+	for (p_start = p; *p; p++) {
+#define ishex(x) (isdigit((x)) || ((x) >= 'a' && (x) <= 'f'))
+		if (!ishex(*p))
+			forty = 0;
+		else if (++forty == 40 &&
+			 !ishex(*(p+1))) {
+			unsigned char sha1[40];
+			const char *name = NULL;
+			char c = *(p+1);
+			int p_len = p - p_start + 1;
+
+			forty = 0;
+
+			*(p+1) = 0;
+			if (!get_sha1(p - 39, sha1)) {
+				struct object *o =
+					lookup_object(sha1);
+				if (o)
+					name = get_rev_name(o);
+			}
+			*(p+1) = c;
+
+			if (!name)
+				continue;
+
+			if (data->name_only)
+				printf("%.*s%s", p_len - 40, p_start, name);
+			else
+				printf("%.*s (%s)", p_len, p_start, name);
+			p_start = p + 1;
+		}
+	}
+
+	/* flush */
+	if (p_start != p)
+		fwrite(p_start, p - p_start, 1, stdout);
+}
+
 int cmd_name_rev(int argc, const char **argv, const char *prefix)
 {
 	struct object_array revs = { 0, 0, NULL };
@@ -195,7 +237,7 @@
 		OPT_END(),
 	};
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	argc = parse_options(argc, argv, opts, name_rev_usage, 0);
 	if (!!all + !!transform_stdin + !!argc > 1) {
 		error("Specify either a list, or --all, not both!");
@@ -234,47 +276,12 @@
 
 	if (transform_stdin) {
 		char buffer[2048];
-		char *p, *p_start;
 
 		while (!feof(stdin)) {
-			int forty = 0;
-			p = fgets(buffer, sizeof(buffer), stdin);
+			char *p = fgets(buffer, sizeof(buffer), stdin);
 			if (!p)
 				break;
-
-			for (p_start = p; *p; p++) {
-#define ishex(x) (isdigit((x)) || ((x) >= 'a' && (x) <= 'f'))
-				if (!ishex(*p))
-					forty = 0;
-				else if (++forty == 40 &&
-						!ishex(*(p+1))) {
-					unsigned char sha1[40];
-					const char *name = NULL;
-					char c = *(p+1);
-
-					forty = 0;
-
-					*(p+1) = 0;
-					if (!get_sha1(p - 39, sha1)) {
-						struct object *o =
-							lookup_object(sha1);
-						if (o)
-							name = get_rev_name(o);
-					}
-					*(p+1) = c;
-
-					if (!name)
-						continue;
-
-					fwrite(p_start, p - p_start + 1, 1, stdout);
-					printf(" (%s)", name);
-					p_start = p + 1;
-				}
-			}
-
-			/* flush */
-			if (p_start != p)
-				fwrite(p_start, p - p_start, 1, stdout);
+			name_rev_line(p, &data);
 		}
 	} else if (all) {
 		int i, max;
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 777f272..447d492 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -28,7 +28,8 @@
 	[--window=N] [--window-memory=N] [--depth=N] \n\
 	[--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\
 	[--threads=N] [--non-empty] [--revs [--unpacked | --all]*] [--reflog] \n\
-	[--stdout | base-name] [--include-tag] [--keep-unreachable] \n\
+	[--stdout | base-name] [--include-tag] \n\
+	[--keep-unreachable | --unpack-unreachable] \n\
 	[<ref-list | <object-list]";
 
 struct object_entry {
@@ -43,6 +44,7 @@
 					     */
 	void *delta_data;	/* cached delta (uncompressed) */
 	unsigned long delta_size;	/* delta data size (uncompressed) */
+	unsigned long z_delta_size;	/* delta data size (compressed) */
 	unsigned int hash;	/* name hint hash */
 	enum object_type type;
 	enum object_type in_pack_type;	/* could be delta */
@@ -65,7 +67,8 @@
 static uint32_t nr_objects, nr_alloc, nr_result, nr_written;
 
 static int non_empty;
-static int no_reuse_delta, no_reuse_object, keep_unreachable, include_tag;
+static int reuse_delta = 1, reuse_object = 1;
+static int keep_unreachable, unpack_unreachable, include_tag;
 static int local;
 static int incremental;
 static int allow_ofs_delta;
@@ -102,24 +105,53 @@
 static uint32_t reused, reused_delta;
 
 
-static void *delta_against(void *buf, unsigned long size, struct object_entry *entry)
+static void *get_delta(struct object_entry *entry)
 {
-	unsigned long othersize, delta_size;
+	unsigned long size, base_size, delta_size;
+	void *buf, *base_buf, *delta_buf;
 	enum object_type type;
-	void *otherbuf = read_sha1_file(entry->delta->idx.sha1, &type, &othersize);
-	void *delta_buf;
 
-	if (!otherbuf)
+	buf = read_sha1_file(entry->idx.sha1, &type, &size);
+	if (!buf)
+		die("unable to read %s", sha1_to_hex(entry->idx.sha1));
+	base_buf = read_sha1_file(entry->delta->idx.sha1, &type, &base_size);
+	if (!base_buf)
 		die("unable to read %s", sha1_to_hex(entry->delta->idx.sha1));
-        delta_buf = diff_delta(otherbuf, othersize,
+	delta_buf = diff_delta(base_buf, base_size,
 			       buf, size, &delta_size, 0);
-        if (!delta_buf || delta_size != entry->delta_size)
+	if (!delta_buf || delta_size != entry->delta_size)
 		die("delta size changed");
-        free(buf);
-        free(otherbuf);
+	free(buf);
+	free(base_buf);
 	return delta_buf;
 }
 
+static unsigned long do_compress(void **pptr, unsigned long size)
+{
+	z_stream stream;
+	void *in, *out;
+	unsigned long maxsize;
+
+	memset(&stream, 0, sizeof(stream));
+	deflateInit(&stream, pack_compression_level);
+	maxsize = deflateBound(&stream, size);
+
+	in = *pptr;
+	out = xmalloc(maxsize);
+	*pptr = out;
+
+	stream.next_in = in;
+	stream.avail_in = size;
+	stream.next_out = out;
+	stream.avail_out = maxsize;
+	while (deflate(&stream, Z_FINISH) == Z_OK)
+		; /* nothing */
+	deflateEnd(&stream);
+
+	free(in);
+	return stream.total_out;
+}
+
 /*
  * The per-object header is a pretty dense thing, which is
  *  - first byte: low four bits are "size", then three bits of "type",
@@ -222,42 +254,42 @@
 				  struct object_entry *entry,
 				  off_t write_offset)
 {
-	unsigned long size;
-	enum object_type type;
+	unsigned long size, limit, datalen;
 	void *buf;
-	unsigned char header[10];
-	unsigned char dheader[10];
+	unsigned char header[10], dheader[10];
 	unsigned hdrlen;
-	off_t datalen;
-	enum object_type obj_type;
-	int to_reuse = 0;
-	/* write limit if limited packsize and not first object */
-	unsigned long limit = pack_size_limit && nr_written ?
-				pack_size_limit - write_offset : 0;
-				/* no if no delta */
-	int usable_delta =	!entry->delta ? 0 :
-				/* yes if unlimited packfile */
-				!pack_size_limit ? 1 :
-				/* no if base written to previous pack */
-				entry->delta->idx.offset == (off_t)-1 ? 0 :
-				/* otherwise double-check written to this
-				 * pack,  like we do below
-				 */
-				entry->delta->idx.offset ? 1 : 0;
+	enum object_type type;
+	int usable_delta, to_reuse;
 
 	if (!pack_to_stdout)
 		crc32_begin(f);
 
-	obj_type = entry->type;
-	if (no_reuse_object)
+	type = entry->type;
+
+	/* write limit if limited packsize and not first object */
+	limit = pack_size_limit && nr_written ?
+			pack_size_limit - write_offset : 0;
+
+	if (!entry->delta)
+		usable_delta = 0;	/* no delta */
+	else if (!pack_size_limit)
+	       usable_delta = 1;	/* unlimited packfile */
+	else if (entry->delta->idx.offset == (off_t)-1)
+		usable_delta = 0;	/* base was written to another pack */
+	else if (entry->delta->idx.offset)
+		usable_delta = 1;	/* base already exists in this pack */
+	else
+		usable_delta = 0;	/* base could end up in another pack */
+
+	if (!reuse_object)
 		to_reuse = 0;	/* explicit */
 	else if (!entry->in_pack)
 		to_reuse = 0;	/* can't reuse what we don't have */
-	else if (obj_type == OBJ_REF_DELTA || obj_type == OBJ_OFS_DELTA)
+	else if (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA)
 				/* check_object() decided it for us ... */
 		to_reuse = usable_delta;
 				/* ... but pack split may override that */
-	else if (obj_type != entry->in_pack_type)
+	else if (type != entry->in_pack_type)
 		to_reuse = 0;	/* pack has delta which is unusable */
 	else if (entry->delta)
 		to_reuse = 0;	/* we want to pack afresh */
@@ -267,50 +299,42 @@
 				 */
 
 	if (!to_reuse) {
-		z_stream stream;
-		unsigned long maxsize;
-		void *out;
 		if (!usable_delta) {
-			buf = read_sha1_file(entry->idx.sha1, &obj_type, &size);
+			buf = read_sha1_file(entry->idx.sha1, &type, &size);
 			if (!buf)
 				die("unable to read %s", sha1_to_hex(entry->idx.sha1));
+			/*
+			 * make sure no cached delta data remains from a
+			 * previous attempt before a pack split occured.
+			 */
+			free(entry->delta_data);
+			entry->delta_data = NULL;
+			entry->z_delta_size = 0;
 		} else if (entry->delta_data) {
 			size = entry->delta_size;
 			buf = entry->delta_data;
 			entry->delta_data = NULL;
-			obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
+			type = (allow_ofs_delta && entry->delta->idx.offset) ?
 				OBJ_OFS_DELTA : OBJ_REF_DELTA;
 		} else {
-			buf = read_sha1_file(entry->idx.sha1, &type, &size);
-			if (!buf)
-				die("unable to read %s", sha1_to_hex(entry->idx.sha1));
-			buf = delta_against(buf, size, entry);
+			buf = get_delta(entry);
 			size = entry->delta_size;
-			obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
+			type = (allow_ofs_delta && entry->delta->idx.offset) ?
 				OBJ_OFS_DELTA : OBJ_REF_DELTA;
 		}
-		/* compress the data to store and put compressed length in datalen */
-		memset(&stream, 0, sizeof(stream));
-		deflateInit(&stream, pack_compression_level);
-		maxsize = deflateBound(&stream, size);
-		out = xmalloc(maxsize);
-		/* Compress it */
-		stream.next_in = buf;
-		stream.avail_in = size;
-		stream.next_out = out;
-		stream.avail_out = maxsize;
-		while (deflate(&stream, Z_FINISH) == Z_OK)
-			/* nothing */;
-		deflateEnd(&stream);
-		datalen = stream.total_out;
+
+		if (entry->z_delta_size)
+			datalen = entry->z_delta_size;
+		else
+			datalen = do_compress(&buf, size);
 
 		/*
 		 * The object header is a byte of 'type' followed by zero or
 		 * more bytes of length.
 		 */
-		hdrlen = encode_header(obj_type, size, header);
+		hdrlen = encode_header(type, size, header);
 
-		if (obj_type == OBJ_OFS_DELTA) {
+		if (type == OBJ_OFS_DELTA) {
 			/*
 			 * Deltas with relative base contain an additional
 			 * encoding of the relative offset for the delta
@@ -322,20 +346,18 @@
 			while (ofs >>= 7)
 				dheader[--pos] = 128 | (--ofs & 127);
 			if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
-				free(out);
 				free(buf);
 				return 0;
 			}
 			sha1write(f, header, hdrlen);
 			sha1write(f, dheader + pos, sizeof(dheader) - pos);
 			hdrlen += sizeof(dheader) - pos;
-		} else if (obj_type == OBJ_REF_DELTA) {
+		} else if (type == OBJ_REF_DELTA) {
 			/*
 			 * Deltas with a base reference contain
 			 * an additional 20 bytes for the base sha1.
 			 */
 			if (limit && hdrlen + 20 + datalen + 20 >= limit) {
-				free(out);
 				free(buf);
 				return 0;
 			}
@@ -344,14 +366,12 @@
 			hdrlen += 20;
 		} else {
 			if (limit && hdrlen + datalen + 20 >= limit) {
-				free(out);
 				free(buf);
 				return 0;
 			}
 			sha1write(f, header, hdrlen);
 		}
-		sha1write(f, out, datalen);
-		free(out);
+		sha1write(f, buf, datalen);
 		free(buf);
 	}
 	else {
@@ -361,11 +381,11 @@
 		off_t offset;
 
 		if (entry->delta) {
-			obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
+			type = (allow_ofs_delta && entry->delta->idx.offset) ?
 				OBJ_OFS_DELTA : OBJ_REF_DELTA;
 			reused_delta++;
 		}
-		hdrlen = encode_header(obj_type, entry->size, header);
+		hdrlen = encode_header(type, entry->size, header);
 		offset = entry->in_pack_offset;
 		revidx = find_pack_revindex(p, offset);
 		datalen = revidx[1].offset - offset;
@@ -374,7 +394,7 @@
 			die("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
 		offset += entry->in_pack_header_size;
 		datalen -= entry->in_pack_header_size;
-		if (obj_type == OBJ_OFS_DELTA) {
+		if (type == OBJ_OFS_DELTA) {
 			off_t ofs = entry->idx.offset - entry->delta->idx.offset;
 			unsigned pos = sizeof(dheader) - 1;
 			dheader[pos] = ofs & 127;
@@ -385,7 +405,7 @@
 			sha1write(f, header, hdrlen);
 			sha1write(f, dheader + pos, sizeof(dheader) - pos);
 			hdrlen += sizeof(dheader) - pos;
-		} else if (obj_type == OBJ_REF_DELTA) {
+		} else if (type == OBJ_REF_DELTA) {
 			if (limit && hdrlen + 20 + datalen + 20 >= limit)
 				return 0;
 			sha1write(f, header, hdrlen);
@@ -452,11 +472,10 @@
 	struct sha1file *f;
 	off_t offset, offset_one, last_obj_offset = 0;
 	struct pack_header hdr;
-	int do_progress = progress >> pack_to_stdout;
 	uint32_t nr_remaining = nr_result;
 	time_t last_mtime = 0;
 
-	if (do_progress)
+	if (progress > pack_to_stdout)
 		progress_state = start_progress("Writing objects", nr_result);
 	written_list = xmalloc(nr_objects * sizeof(*written_list));
 
@@ -495,11 +514,14 @@
 		 * Did we write the wrong # entries in the header?
 		 * If so, rewrite it like in fast-import
 		 */
-		if (pack_to_stdout || nr_written == nr_remaining) {
-			sha1close(f, sha1, 1);
+		if (pack_to_stdout) {
+			sha1close(f, sha1, CSUM_CLOSE);
+		} else if (nr_written == nr_remaining) {
+			sha1close(f, sha1, CSUM_FSYNC);
 		} else {
 			int fd = sha1close(f, NULL, 0);
 			fixup_pack_header_footer(fd, sha1, pack_tmp_name, nr_written);
+			fsync_or_die(fd, pack_tmp_name);
 			close(fd);
 		}
 
@@ -1022,7 +1044,7 @@
 			unuse_pack(&w_curs);
 			return;
 		case OBJ_REF_DELTA:
-			if (!no_reuse_delta && !entry->preferred_base)
+			if (reuse_delta && !entry->preferred_base)
 				base_ref = use_pack(p, &w_curs,
 						entry->in_pack_offset + used, NULL);
 			entry->in_pack_header_size = used + 20;
@@ -1045,7 +1067,7 @@
 				die("delta base offset out of bound for %s",
 				    sha1_to_hex(entry->idx.sha1));
 			ofs = entry->in_pack_offset - ofs;
-			if (!no_reuse_delta && !entry->preferred_base) {
+			if (reuse_delta && !entry->preferred_base) {
 				struct revindex_entry *revidx;
 				revidx = find_pack_revindex(p, ofs);
 				base_ref = nth_packed_object_sha1(p, revidx->nr);
@@ -1233,7 +1255,7 @@
 	 * We do not bother to try a delta that we discarded
 	 * on an earlier try, but only when reusing delta data.
 	 */
-	if (!no_reuse_delta && trg_entry->in_pack &&
+	if (reuse_delta && trg_entry->in_pack &&
 	    trg_entry->in_pack == src_entry->in_pack &&
 	    trg_entry->in_pack_type != OBJ_REF_DELTA &&
 	    trg_entry->in_pack_type != OBJ_OFS_DELTA)
@@ -1441,11 +1463,34 @@
 				best_base = other_idx;
 		}
 
+		/*
+		 * If we decided to cache the delta data, then it is best
+		 * to compress it right away.  First because we have to do
+		 * it anyway, and doing it here while we're threaded will
+		 * save a lot of time in the non threaded write phase,
+		 * as well as allow for caching more deltas within
+		 * the same cache size limit.
+		 * ...
+		 * But only if not writing to stdout, since in that case
+		 * the network is most likely throttling writes anyway,
+		 * and therefore it is best to go to the write phase ASAP
+		 * instead, as we can afford spending more time compressing
+		 * between writes at that moment.
+		 */
+		if (entry->delta_data && !pack_to_stdout) {
+			entry->z_delta_size = do_compress(&entry->delta_data,
+							  entry->delta_size);
+			cache_lock();
+			delta_cache_size -= entry->delta_size;
+			delta_cache_size += entry->z_delta_size;
+			cache_unlock();
+		}
+
 		/* if we made n a delta, and if n is already at max
 		 * depth, leaving it in the window is pointless.  we
 		 * should evict it first.
 		 */
-		if (entry->delta && depth <= n->depth)
+		if (entry->delta && max_depth <= n->depth)
 			continue;
 
 		/*
@@ -1688,7 +1733,7 @@
 
 		if (entry->delta)
 			/* This happens if we decided to reuse existing
-			 * delta from a pack.  "!no_reuse_delta &&" is implied.
+			 * delta from a pack.  "reuse_delta &&" is implied.
 			 */
 			continue;
 
@@ -1718,7 +1763,7 @@
 	free(delta_list);
 }
 
-static int git_pack_config(const char *k, const char *v)
+static int git_pack_config(const char *k, const char *v, void *cb)
 {
 	if(!strcmp(k, "pack.window")) {
 		window = git_config_int(k, v);
@@ -1771,7 +1816,7 @@
 		pack_size_limit_cfg = git_config_ulong(k, v);
 		return 0;
 	}
-	return git_default_config(k, v);
+	return git_default_config(k, v, cb);
 }
 
 static void read_object_list_from_stdin(void)
@@ -1905,6 +1950,32 @@
 	free(in_pack.array);
 }
 
+static void loosen_unused_packed_objects(struct rev_info *revs)
+{
+	struct packed_git *p;
+	uint32_t i;
+	const unsigned char *sha1;
+
+	for (p = packed_git; p; p = p->next) {
+		for (i = 0; i < revs->num_ignore_packed; i++) {
+			if (matches_pack_name(p, revs->ignore_packed[i]))
+				break;
+		}
+		if (revs->num_ignore_packed <= i)
+			continue;
+
+		if (open_pack_index(p))
+			die("cannot open pack index");
+
+		for (i = 0; i < p->num_objects; i++) {
+			sha1 = nth_packed_object_sha1(p, i);
+			if (!locate_object_entry(sha1))
+				if (force_object_loose(sha1, p->mtime))
+					die("unable to force loose object");
+		}
+	}
+}
+
 static void get_object_list(int ac, const char **av)
 {
 	struct rev_info revs;
@@ -1939,6 +2010,8 @@
 
 	if (keep_unreachable)
 		add_objects_in_unpacked_packs(&revs);
+	if (unpack_unreachable)
+		loosen_unused_packed_objects(&revs);
 }
 
 static int adjust_perm(const char *path, mode_t mode)
@@ -1963,7 +2036,7 @@
 	rp_av[1] = "--objects"; /* --thin will make it --objects-edge */
 	rp_ac = 2;
 
-	git_config(git_pack_config);
+	git_config(git_pack_config, NULL);
 	if (!pack_compression_seen && core_compression_seen)
 		pack_compression_level = core_compression_level;
 
@@ -2050,11 +2123,11 @@
 			continue;
 		}
 		if (!strcmp("--no-reuse-delta", arg)) {
-			no_reuse_delta = 1;
+			reuse_delta = 0;
 			continue;
 		}
 		if (!strcmp("--no-reuse-object", arg)) {
-			no_reuse_object = no_reuse_delta = 1;
+			reuse_object = reuse_delta = 0;
 			continue;
 		}
 		if (!strcmp("--delta-base-offset", arg)) {
@@ -2073,6 +2146,10 @@
 			keep_unreachable = 1;
 			continue;
 		}
+		if (!strcmp("--unpack-unreachable", arg)) {
+			unpack_unreachable = 1;
+			continue;
+		}
 		if (!strcmp("--include-tag", arg)) {
 			include_tag = 1;
 			continue;
@@ -2138,6 +2215,9 @@
 	if (!pack_to_stdout && thin)
 		die("--thin cannot be used to build an indexable pack.");
 
+	if (keep_unreachable && unpack_unreachable)
+		die("--keep-unreachable and --unpack-unreachable are incompatible.");
+
 #ifdef THREADED_DELTA_SEARCH
 	if (!delta_search_threads)	/* --threads=0 means autodetect */
 		delta_search_threads = online_cpus();
diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c
index 23faf31..241afbb 100644
--- a/builtin-prune-packed.c
+++ b/builtin-prune-packed.c
@@ -85,7 +85,6 @@
 		/* Handle arguments here .. */
 		usage(prune_packed_usage);
 	}
-	sync();
 	prune_packed_objects(opts);
 	return 0;
 }
diff --git a/builtin-prune.c b/builtin-prune.c
index 25f9304..bd3d2f6 100644
--- a/builtin-prune.c
+++ b/builtin-prune.c
@@ -156,7 +156,6 @@
 	mark_reachable_objects(&revs, 1);
 	prune_object_dir(get_object_directory());
 
-	sync();
 	prune_packed_objects(show_only);
 	remove_temporary_files();
 	return 0;
diff --git a/builtin-push.c b/builtin-push.c
index b68c681..b35aad6 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -56,6 +56,17 @@
 	if (!remote)
 		die("bad repository '%s'", repo);
 
+	if (remote->mirror)
+		flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
+
+	if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) && refspec)
+		return -1;
+
+	if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==
+				(TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {
+		return error("--all and --mirror are incompatible");
+	}
+
 	if (!refspec
 		&& !(flags & TRANSPORT_PUSH_ALL)
 		&& remote->push_refspec_nr) {
@@ -95,6 +106,7 @@
 	int dry_run = 0;
 	int force = 0;
 	int tags = 0;
+	int rc;
 	const char *repo = NULL;	/* default repository */
 
 	struct option options[] = {
@@ -130,14 +142,10 @@
 		repo = argv[0];
 		set_refspecs(argv + 1, argc - 1);
 	}
-	if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) && refspec)
-		usage_with_options(push_usage, options);
 
-	if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==
-				(TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {
-		error("--all and --mirror are incompatible");
+	rc = do_push(repo, flags);
+	if (rc == -1)
 		usage_with_options(push_usage, options);
-	}
-
-	return do_push(repo, flags);
+	else
+		return rc;
 }
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index e9cfd2b..5a09e17 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -40,7 +40,7 @@
 	for (i = 0; i < active_nr; i++) {
 		struct cache_entry *ce = active_cache[i];
 		if (ce_stage(ce)) {
-			remove_index_entry(ce);
+			remove_name_hash(ce);
 			if (last && !strcmp(ce->name, last->name))
 				continue;
 			cache_tree_invalidate_path(active_cache_tree, ce->name);
@@ -104,12 +104,10 @@
 	opts.src_index = &the_index;
 	opts.dst_index = &the_index;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	newfd = hold_locked_index(&lock_file, 1);
 
-	git_config(git_default_config);
-
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 
diff --git a/builtin-reflog.c b/builtin-reflog.c
index 280e24e..7d7047d 100644
--- a/builtin-reflog.c
+++ b/builtin-reflog.c
@@ -269,7 +269,9 @@
 	int status = 0;
 
 	memset(&cb, 0, sizeof(cb));
-	/* we take the lock for the ref itself to prevent it from
+
+	/*
+	 * we take the lock for the ref itself to prevent it from
 	 * getting updated.
 	 */
 	lock = lock_any_ref_for_update(ref, sha1, 0);
@@ -307,6 +309,8 @@
 			unlink(newlog_path);
 		} else if (cmd->updateref && commit_ref(lock)) {
 			status |= error("Couldn't set %s", lock->ref_name);
+		} else {
+			adjust_shared_perm(log_file);
 		}
 	}
 	free(newlog_path);
@@ -329,21 +333,130 @@
 	return 0;
 }
 
-static int reflog_expire_config(const char *var, const char *value)
+static struct reflog_expire_cfg {
+	struct reflog_expire_cfg *next;
+	unsigned long expire_total;
+	unsigned long expire_unreachable;
+	size_t len;
+	char pattern[FLEX_ARRAY];
+} *reflog_expire_cfg, **reflog_expire_cfg_tail;
+
+static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)
 {
-	if (!strcmp(var, "gc.reflogexpire")) {
-		if (!value)
-			config_error_nonbool(var);
-		default_reflog_expire = approxidate(value);
+	struct reflog_expire_cfg *ent;
+
+	if (!reflog_expire_cfg_tail)
+		reflog_expire_cfg_tail = &reflog_expire_cfg;
+
+	for (ent = reflog_expire_cfg; ent; ent = ent->next)
+		if (ent->len == len &&
+		    !memcmp(ent->pattern, pattern, len))
+			return ent;
+
+	ent = xcalloc(1, (sizeof(*ent) + len));
+	memcpy(ent->pattern, pattern, len);
+	ent->len = len;
+	*reflog_expire_cfg_tail = ent;
+	reflog_expire_cfg_tail = &(ent->next);
+	return ent;
+}
+
+static int parse_expire_cfg_value(const char *var, const char *value, unsigned long *expire)
+{
+	if (!value)
+		return config_error_nonbool(var);
+	if (!strcmp(value, "never") || !strcmp(value, "false")) {
+		*expire = 0;
 		return 0;
 	}
-	if (!strcmp(var, "gc.reflogexpireunreachable")) {
-		if (!value)
-			config_error_nonbool(var);
-		default_reflog_expire_unreachable = approxidate(value);
+	*expire = approxidate(value);
+	return 0;
+}
+
+/* expiry timer slot */
+#define EXPIRE_TOTAL   01
+#define EXPIRE_UNREACH 02
+
+static int reflog_expire_config(const char *var, const char *value, void *cb)
+{
+	const char *lastdot = strrchr(var, '.');
+	unsigned long expire;
+	int slot;
+	struct reflog_expire_cfg *ent;
+
+	if (!lastdot || prefixcmp(var, "gc."))
+		return git_default_config(var, value, cb);
+
+	if (!strcmp(lastdot, ".reflogexpire")) {
+		slot = EXPIRE_TOTAL;
+		if (parse_expire_cfg_value(var, value, &expire))
+			return -1;
+	} else if (!strcmp(lastdot, ".reflogexpireunreachable")) {
+		slot = EXPIRE_UNREACH;
+		if (parse_expire_cfg_value(var, value, &expire))
+			return -1;
+	} else
+		return git_default_config(var, value, cb);
+
+	if (lastdot == var + 2) {
+		switch (slot) {
+		case EXPIRE_TOTAL:
+			default_reflog_expire = expire;
+			break;
+		case EXPIRE_UNREACH:
+			default_reflog_expire_unreachable = expire;
+			break;
+		}
 		return 0;
 	}
-	return git_default_config(var, value);
+
+	ent = find_cfg_ent(var + 3, lastdot - (var+3));
+	if (!ent)
+		return -1;
+	switch (slot) {
+	case EXPIRE_TOTAL:
+		ent->expire_total = expire;
+		break;
+	case EXPIRE_UNREACH:
+		ent->expire_unreachable = expire;
+		break;
+	}
+	return 0;
+}
+
+static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, const char *ref)
+{
+	struct reflog_expire_cfg *ent;
+
+	if (slot == (EXPIRE_TOTAL|EXPIRE_UNREACH))
+		return; /* both given explicitly -- nothing to tweak */
+
+	for (ent = reflog_expire_cfg; ent; ent = ent->next) {
+		if (!fnmatch(ent->pattern, ref, 0)) {
+			if (!(slot & EXPIRE_TOTAL))
+				cb->expire_total = ent->expire_total;
+			if (!(slot & EXPIRE_UNREACH))
+				cb->expire_unreachable = ent->expire_unreachable;
+			return;
+		}
+	}
+
+	/*
+	 * If unconfigured, make stash never expire
+	 */
+	if (!strcmp(ref, "refs/stash")) {
+		if (!(slot & EXPIRE_TOTAL))
+			cb->expire_total = 0;
+		if (!(slot & EXPIRE_UNREACH))
+			cb->expire_unreachable = 0;
+		return;
+	}
+
+	/* Nothing matched -- use the default value */
+	if (!(slot & EXPIRE_TOTAL))
+		cb->expire_total = default_reflog_expire;
+	if (!(slot & EXPIRE_UNREACH))
+		cb->expire_unreachable = default_reflog_expire_unreachable;
 }
 
 static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
@@ -351,8 +464,9 @@
 	struct cmd_reflog_expire_cb cb;
 	unsigned long now = time(NULL);
 	int i, status, do_all;
+	int explicit_expiry = 0;
 
-	git_config(reflog_expire_config);
+	git_config(reflog_expire_config, NULL);
 
 	save_commit_buffer = 0;
 	do_all = status = 0;
@@ -365,20 +479,18 @@
 	cb.expire_total = default_reflog_expire;
 	cb.expire_unreachable = default_reflog_expire_unreachable;
 
-	/*
-	 * We can trust the commits and objects reachable from refs
-	 * even in older repository.  We cannot trust what's reachable
-	 * from reflog if the repository was pruned with older git.
-	 */
-
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 		if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
 			cb.dry_run = 1;
-		else if (!prefixcmp(arg, "--expire="))
+		else if (!prefixcmp(arg, "--expire=")) {
 			cb.expire_total = approxidate(arg + 9);
-		else if (!prefixcmp(arg, "--expire-unreachable="))
+			explicit_expiry |= EXPIRE_TOTAL;
+		}
+		else if (!prefixcmp(arg, "--expire-unreachable=")) {
 			cb.expire_unreachable = approxidate(arg + 21);
+			explicit_expiry |= EXPIRE_UNREACH;
+		}
 		else if (!strcmp(arg, "--stale-fix"))
 			cb.stalefix = 1;
 		else if (!strcmp(arg, "--rewrite"))
@@ -398,6 +510,12 @@
 		else
 			break;
 	}
+
+	/*
+	 * We can trust the commits and objects reachable from refs
+	 * even in older repository.  We cannot trust what's reachable
+	 * from reflog if the repository was pruned with older git.
+	 */
 	if (cb.stalefix) {
 		init_revisions(&cb.revs, prefix);
 		if (cb.verbose)
@@ -415,6 +533,7 @@
 		for_each_reflog(collect_reflog, &collected);
 		for (i = 0; i < collected.nr; i++) {
 			struct collected_reflog *e = collected.e[i];
+			set_reflog_expiry_param(&cb, explicit_expiry, e->reflog);
 			status |= expire_reflog(e->reflog, e->sha1, 0, &cb);
 			free(e);
 		}
@@ -428,6 +547,7 @@
 			status |= error("%s points nowhere!", ref);
 			continue;
 		}
+		set_reflog_expiry_param(&cb, explicit_expiry, ref);
 		status |= expire_reflog(ref, sha1, 0, &cb);
 	}
 	return status;
@@ -484,8 +604,8 @@
 			continue;
 		}
 
-		if (!dwim_ref(argv[i], spec - argv[i], sha1, &ref)) {
-			status |= error("%s points nowhere!", argv[i]);
+		if (!dwim_log(argv[i], spec - argv[i], sha1, &ref)) {
+			status |= error("no reflog for '%s'", argv[i]);
 			continue;
 		}
 
diff --git a/builtin-remote.c b/builtin-remote.c
index 4149f3b..145dd85 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -19,6 +19,8 @@
 
 static int verbose;
 
+static int show_all(void);
+
 static inline int postfixcmp(const char *string, const char *postfix)
 {
 	int len1 = strlen(string), len2 = strlen(postfix);
@@ -116,6 +118,13 @@
 			return 1;
 	}
 
+	if (mirror) {
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "remote.%s.mirror", name);
+		if (git_config_set(buf.buf, "yes"))
+			return 1;
+	}
+
 	if (fetch && fetch_remote(name))
 		return 1;
 
@@ -144,7 +153,7 @@
 
 static struct path_list branch_list;
 
-static int config_read_branches(const char *key, const char *value)
+static int config_read_branches(const char *key, const char *value, void *cb)
 {
 	if (!prefixcmp(key, "branch.")) {
 		char *name;
@@ -191,13 +200,12 @@
 {
 	if (branch_list.nr)
 		return;
-	git_config(config_read_branches);
+	git_config(config_read_branches, NULL);
 	sort_path_list(&branch_list);
 }
 
 struct ref_states {
 	struct remote *remote;
-	struct strbuf remote_prefix;
 	struct path_list new, stale, tracked;
 };
 
@@ -253,36 +261,72 @@
 	}
 	free_refs(fetch_map);
 
-	strbuf_addf(&states->remote_prefix,
-		"refs/remotes/%s/", states->remote->name);
 	for_each_ref(handle_one_branch, states);
 	sort_path_list(&states->stale);
 
 	return 0;
 }
 
+struct known_remote {
+	struct known_remote *next;
+	struct remote *remote;
+};
+
+struct known_remotes {
+	struct remote *to_delete;
+	struct known_remote *list;
+};
+
+static int add_known_remote(struct remote *remote, void *cb_data)
+{
+	struct known_remotes *all = cb_data;
+	struct known_remote *r;
+
+	if (!strcmp(all->to_delete->name, remote->name))
+		return 0;
+
+	r = xmalloc(sizeof(*r));
+	r->remote = remote;
+	r->next = all->list;
+	all->list = r;
+	return 0;
+}
+
 struct branches_for_remote {
-	const char *prefix;
+	struct remote *remote;
 	struct path_list *branches;
+	struct known_remotes *keep;
 };
 
 static int add_branch_for_removal(const char *refname,
 	const unsigned char *sha1, int flags, void *cb_data)
 {
 	struct branches_for_remote *branches = cb_data;
+	struct refspec refspec;
+	struct path_list_item *item;
+	struct known_remote *kr;
 
-	if (!prefixcmp(refname, branches->prefix)) {
-		struct path_list_item *item;
+	memset(&refspec, 0, sizeof(refspec));
+	refspec.dst = (char *)refname;
+	if (remote_find_tracking(branches->remote, &refspec))
+		return 0;
 
-		/* make sure that symrefs are deleted */
-		if (flags & REF_ISSYMREF)
-			return unlink(git_path(refname));
-
-		item = path_list_append(refname, branches->branches);
-		item->util = xmalloc(20);
-		hashcpy(item->util, sha1);
+	/* don't delete a branch if another remote also uses it */
+	for (kr = branches->keep->list; kr; kr = kr->next) {
+		memset(&refspec, 0, sizeof(refspec));
+		refspec.dst = (char *)refname;
+		if (!remote_find_tracking(kr->remote, &refspec))
+			return 0;
 	}
 
+	/* make sure that symrefs are deleted */
+	if (flags & REF_ISSYMREF)
+		return unlink(git_path(refname));
+
+	item = path_list_append(refname, branches->branches);
+	item->util = xmalloc(20);
+	hashcpy(item->util, sha1);
+
 	return 0;
 }
 
@@ -307,8 +351,9 @@
 	};
 	struct remote *remote;
 	struct strbuf buf;
+	struct known_remotes known_remotes = { NULL, NULL };
 	struct path_list branches = { NULL, 0, 0, 1 };
-	struct branches_for_remote cb_data = { NULL, &branches };
+	struct branches_for_remote cb_data = { NULL, &branches, &known_remotes };
 	int i;
 
 	if (argc != 2)
@@ -318,6 +363,9 @@
 	if (!remote)
 		die("No such remote: %s", argv[1]);
 
+	known_remotes.to_delete = remote;
+	for_each_remote(add_known_remote, &known_remotes);
+
 	strbuf_init(&buf, 0);
 	strbuf_addf(&buf, "remote.%s", remote->name);
 	if (git_config_rename_section(buf.buf, NULL) < 1)
@@ -346,9 +394,7 @@
 	 * the branches one by one, since for_each_ref() relies on cached
 	 * refs, which are invalidated when deleting a branch.
 	 */
-	strbuf_reset(&buf);
-	strbuf_addf(&buf, "refs/remotes/%s/", remote->name);
-	cb_data.prefix = buf.buf;
+	cb_data.remote = remote;
 	i = for_each_ref(add_branch_for_removal, &cb_data);
 	strbuf_release(&buf);
 
@@ -373,12 +419,53 @@
 	printf("\n");
 }
 
-static int show_or_prune(int argc, const char **argv, int prune)
+static int get_remote_ref_states(const char *name,
+				 struct ref_states *states,
+				 int query)
 {
-	int dry_run = 0, result = 0;
+	struct transport *transport;
+	const struct ref *ref;
+
+	states->remote = remote_get(name);
+	if (!states->remote)
+		return error("No such remote: %s", name);
+
+	read_branches();
+
+	if (query) {
+		transport = transport_get(NULL, states->remote->url_nr > 0 ?
+			states->remote->url[0] : NULL);
+		ref = transport_get_remote_refs(transport);
+		transport_disconnect(transport);
+
+		get_ref_states(ref, states);
+	}
+
+	return 0;
+}
+
+static int append_ref_to_tracked_list(const char *refname,
+	const unsigned char *sha1, int flags, void *cb_data)
+{
+	struct ref_states *states = cb_data;
+	struct refspec refspec;
+
+	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);
+	}
+
+	return 0;
+}
+
+static int show(int argc, const char **argv)
+{
+	int no_query = 0, result = 0;
 	struct option options[] = {
 		OPT_GROUP("show specific options"),
-		OPT__DRY_RUN(&dry_run),
+		OPT_BOOLEAN('n', NULL, &no_query, "do not query remotes"),
 		OPT_END()
 	};
 	struct ref_states states;
@@ -386,53 +473,14 @@
 	argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
 
 	if (argc < 1)
-		usage_with_options(builtin_remote_usage, options);
+		return show_all();
 
 	memset(&states, 0, sizeof(states));
 	for (; argc; argc--, argv++) {
-		struct transport *transport;
-		const struct ref *ref;
 		struct strbuf buf;
-		int i, got_states;
+		int i;
 
-		states.remote = remote_get(*argv);
-		if (!states.remote)
-			return error("No such remote: %s", *argv);
-		transport = transport_get(NULL, states.remote->url_nr > 0 ?
-			states.remote->url[0] : NULL);
-		ref = transport_get_remote_refs(transport);
-		transport_disconnect(transport);
-
-		read_branches();
-		got_states = get_ref_states(ref, &states);
-		if (got_states)
-			result = error("Error getting local info for '%s'",
-					states.remote->name);
-
-		if (prune) {
-			struct strbuf buf;
-			int prefix_len;
-
-			strbuf_init(&buf, 0);
-			if (states.remote->fetch_refspec_nr == 1 &&
-					states.remote->fetch->pattern &&
-					!strcmp(states.remote->fetch->src,
-						states.remote->fetch->dst))
-				/* handle --mirror remote */
-				strbuf_addstr(&buf, "refs/heads/");
-			else
-				strbuf_addf(&buf, "refs/remotes/%s/", *argv);
-			prefix_len = buf.len;
-
-			for (i = 0; i < states.stale.nr; i++) {
-				strbuf_setlen(&buf, prefix_len);
-				strbuf_addstr(&buf, states.stale.items[i].path);
-				result |= delete_ref(buf.buf, NULL);
-			}
-
-			strbuf_release(&buf);
-			goto cleanup_states;
-		}
+		get_remote_ref_states(*argv, &states, !no_query);
 
 		printf("* remote %s\n  URL: %s\n", *argv,
 			states.remote->url_nr > 0 ?
@@ -454,17 +502,19 @@
 			printf("\n");
 		}
 
-		if (got_states)
-			continue;
-		strbuf_init(&buf, 0);
-		strbuf_addf(&buf, "  New remote branch%%s (next fetch will "
-			"store in remotes/%s)", states.remote->name);
-		show_list(buf.buf, &states.new);
-		strbuf_release(&buf);
-		show_list("  Stale tracking branch%s (use 'git remote prune')",
-				&states.stale);
-		show_list("  Tracked remote branch%s",
-				&states.tracked);
+		if (!no_query) {
+			strbuf_init(&buf, 0);
+			strbuf_addf(&buf, "  New remote branch%%s (next fetch "
+				"will store in remotes/%s)", states.remote->name);
+			show_list(buf.buf, &states.new);
+			strbuf_release(&buf);
+			show_list("  Stale tracking branch%s (use 'git remote "
+				"prune')", &states.stale);
+		}
+
+		if (no_query)
+			for_each_ref(append_ref_to_tracked_list, &states);
+		show_list("  Tracked remote branch%s", &states.tracked);
 
 		if (states.remote->push_refspec_nr) {
 			printf("  Local branch%s pushed with 'git push'\n   ",
@@ -479,7 +529,55 @@
 			}
 			printf("\n");
 		}
-cleanup_states:
+
+		/* NEEDSWORK: free remote */
+		path_list_clear(&states.new, 0);
+		path_list_clear(&states.stale, 0);
+		path_list_clear(&states.tracked, 0);
+	}
+
+	return result;
+}
+
+static int prune(int argc, const char **argv)
+{
+	int dry_run = 0, result = 0;
+	struct option options[] = {
+		OPT_GROUP("prune specific options"),
+		OPT__DRY_RUN(&dry_run),
+		OPT_END()
+	};
+	struct ref_states states;
+
+	argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
+
+	if (argc < 1)
+		usage_with_options(builtin_remote_usage, options);
+
+	memset(&states, 0, sizeof(states));
+	for (; argc; argc--, argv++) {
+		int i;
+
+		get_remote_ref_states(*argv, &states, 1);
+
+		if (states.stale.nr) {
+			printf("Pruning %s\n", *argv);
+			printf("URL: %s\n",
+			       states.remote->url_nr
+			       ? states.remote->url[0]
+			       : "(no URL)");
+		}
+
+		for (i = 0; i < states.stale.nr; i++) {
+			const char *refname = states.stale.items[i].util;
+
+			if (!dry_run)
+				result |= delete_ref(refname, NULL);
+
+			printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned",
+			       skip_prefix(refname, "refs/remotes/"));
+		}
+
 		/* NEEDSWORK: free remote */
 		path_list_clear(&states.new, 0);
 		path_list_clear(&states.stale, 0);
@@ -502,7 +600,7 @@
 	struct path_list *list;
 } remote_group;
 
-static int get_remote_group(const char *key, const char *value)
+static int get_remote_group(const char *key, const char *value, void *cb)
 {
 	if (!prefixcmp(key, "remotes.") &&
 			!strcmp(key + 8, remote_group.name)) {
@@ -534,7 +632,7 @@
 	remote_group.list = &list;
 	for (i = 1; i < argc; i++) {
 		remote_group.name = argv[i];
-		result = git_config(get_remote_group);
+		result = git_config(get_remote_group, NULL);
 	}
 
 	if (!result && !list.nr  && argc == 2 && !strcmp(argv[1], "default"))
@@ -600,9 +698,9 @@
 	else if (!strcmp(argv[0], "rm"))
 		result = rm(argc, argv);
 	else if (!strcmp(argv[0], "show"))
-		result = show_or_prune(argc, argv, 0);
+		result = show(argc, argv);
 	else if (!strcmp(argv[0], "prune"))
-		result = show_or_prune(argc, argv, 1);
+		result = prune(argc, argv);
 	else if (!strcmp(argv[0], "update"))
 		result = update(argc, argv);
 	else {
diff --git a/builtin-rerere.c b/builtin-rerere.c
index c607aad..85222d9 100644
--- a/builtin-rerere.c
+++ b/builtin-rerere.c
@@ -43,7 +43,7 @@
 			; /* do nothing */
 		if (i == sizeof(buf))
 			die("filename too long");
-		path_list_insert(buf, rr)->util = xstrdup(name);
+		path_list_insert(buf, rr)->util = name;
 	}
 	fclose(in);
 }
@@ -339,7 +339,7 @@
 	return write_rr(rr, fd);
 }
 
-static int git_rerere_config(const char *var, const char *value)
+static int git_rerere_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "gc.rerereresolved"))
 		cutoff_resolve = git_config_int(var, value);
@@ -348,7 +348,7 @@
 	else if (!strcmp(var, "rerere.enabled"))
 		rerere_enabled = git_config_bool(var, value);
 	else
-		return git_default_config(var, value);
+		return git_default_config(var, value, cb);
 	return 0;
 }
 
@@ -376,7 +376,7 @@
 {
 	int fd;
 
-	git_config(git_rerere_config);
+	git_config(git_rerere_config, NULL);
 	if (!is_rerere_enabled())
 		return -1;
 
diff --git a/builtin-reset.c b/builtin-reset.c
index 79424bb..a032169 100644
--- a/builtin-reset.c
+++ b/builtin-reset.c
@@ -49,13 +49,14 @@
 	return !access(git_path("MERGE_HEAD"), F_OK);
 }
 
-static int reset_index_file(const unsigned char *sha1, int is_hard_reset)
+static int reset_index_file(const unsigned char *sha1, int is_hard_reset, int quiet)
 {
 	int i = 0;
 	const char *args[6];
 
 	args[i++] = "read-tree";
-	args[i++] = "-v";
+	if (!quiet)
+		args[i++] = "-v";
 	args[i++] = "--reset";
 	if (is_hard_reset)
 		args[i++] = "-u";
@@ -182,19 +183,51 @@
 		OPT_SET_INT(0, "hard", &reset_type,
 				"reset HEAD, index and working tree", HARD),
 		OPT_BOOLEAN('q', NULL, &quiet,
-				"disable showing new HEAD in hard reset"),
+				"disable showing new HEAD in hard reset and progress message"),
 		OPT_END()
 	};
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	argc = parse_options(argc, argv, options, git_reset_usage,
 						PARSE_OPT_KEEP_DASHDASH);
 	reflog_action = args_to_str(argv);
 	setenv("GIT_REFLOG_ACTION", reflog_action, 0);
 
-	if (i < argc && strcmp(argv[i], "--"))
-		rev = argv[i++];
+	/*
+	 * Possible arguments are:
+	 *
+	 * git reset [-opts] <rev> <paths>...
+	 * git reset [-opts] <rev> -- <paths>...
+	 * git reset [-opts] -- <paths>...
+	 * git reset [-opts] <paths>...
+	 *
+	 * At this point, argv[i] points immediately after [-opts].
+	 */
+
+	if (i < argc) {
+		if (!strcmp(argv[i], "--")) {
+			i++; /* reset to HEAD, possibly with paths */
+		} else if (i + 1 < argc && !strcmp(argv[i+1], "--")) {
+			rev = argv[i];
+			i += 2;
+		}
+		/*
+		 * Otherwise, argv[i] could be either <rev> or <paths> and
+		 * has to be unambigous.
+		 */
+		else if (!get_sha1(argv[i], sha1)) {
+			/*
+			 * Ok, argv[i] looks like a rev; it should not
+			 * be a filename.
+			 */
+			verify_non_filename(prefix, argv[i]);
+			rev = argv[i++];
+		} else {
+			/* Otherwise we treat this as a filename */
+			verify_filename(prefix, argv[i]);
+		}
+	}
 
 	if (get_sha1(rev, sha1))
 		die("Failed to resolve '%s' as a valid ref.", rev);
@@ -204,9 +237,6 @@
 		die("Could not parse object '%s'.", rev);
 	hashcpy(sha1, commit->object.sha1);
 
-	if (i < argc && !strcmp(argv[i], "--"))
-		i++;
-
 	/* git reset tree [--] paths... can be used to
 	 * load chosen paths from the tree into the index without
 	 * affecting the working tree nor HEAD. */
@@ -231,7 +261,7 @@
 		if (is_merge() || read_cache() < 0 || unmerged_cache())
 			die("Cannot do a soft reset in the middle of a merge.");
 	}
-	else if (reset_index_file(sha1, (reset_type == HARD)))
+	else if (reset_index_file(sha1, (reset_type == HARD), quiet))
 		die("Could not reset index file to revision '%s'.", rev);
 
 	/* Any resets update HEAD to the head being switched to,
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index edc0bd3..39ec61c 100644
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
@@ -10,6 +10,7 @@
 #include "list-objects.h"
 #include "builtin.h"
 #include "log-tree.h"
+#include "graph.h"
 
 /* bits #0-15 in revision.h */
 
@@ -58,26 +59,31 @@
 static void finish_commit(struct commit *commit);
 static void show_commit(struct commit *commit)
 {
+	graph_show_commit(revs.graph);
+
 	if (show_timestamp)
 		printf("%lu ", commit->date);
 	if (header_prefix)
 		fputs(header_prefix, stdout);
-	if (commit->object.flags & BOUNDARY)
-		putchar('-');
-	else if (commit->object.flags & UNINTERESTING)
-		putchar('^');
-	else if (revs.left_right) {
-		if (commit->object.flags & SYMMETRIC_LEFT)
-			putchar('<');
-		else
-			putchar('>');
+
+	if (!revs.graph) {
+		if (commit->object.flags & BOUNDARY)
+			putchar('-');
+		else if (commit->object.flags & UNINTERESTING)
+			putchar('^');
+		else if (revs.left_right) {
+			if (commit->object.flags & SYMMETRIC_LEFT)
+				putchar('<');
+			else
+				putchar('>');
+		}
 	}
 	if (revs.abbrev_commit && revs.abbrev)
 		fputs(find_unique_abbrev(commit->object.sha1, revs.abbrev),
 		      stdout);
 	else
 		fputs(sha1_to_hex(commit->object.sha1), stdout);
-	if (revs.parents) {
+	if (revs.print_parents) {
 		struct commit_list *parents = commit->parents;
 		while (parents) {
 			printf(" %s", sha1_to_hex(parents->item->object.sha1));
@@ -96,9 +102,48 @@
 		pretty_print_commit(revs.commit_format, commit,
 				    &buf, revs.abbrev, NULL, NULL,
 				    revs.date_mode, 0);
-		if (buf.len)
-			printf("%s%c", buf.buf, hdr_termination);
+		if (revs.graph) {
+			if (buf.len) {
+				if (revs.commit_format != CMIT_FMT_ONELINE)
+					graph_show_oneline(revs.graph);
+
+				graph_show_commit_msg(revs.graph, &buf);
+
+				/*
+				 * Add a newline after the commit message.
+				 *
+				 * Usually, this newline produces a blank
+				 * padding line between entries, in which case
+				 * we need to add graph padding on this line.
+				 *
+				 * However, the commit message may not end in a
+				 * newline.  In this case the newline simply
+				 * ends the last line of the commit message,
+				 * and we don't need any graph output.  (This
+				 * always happens with CMIT_FMT_ONELINE, and it
+				 * happens with CMIT_FMT_USERFORMAT when the
+				 * format doesn't explicitly end in a newline.)
+				 */
+				if (buf.len && buf.buf[buf.len - 1] == '\n')
+					graph_show_padding(revs.graph);
+				putchar('\n');
+			} else {
+				/*
+				 * If the message buffer is empty, just show
+				 * the rest of the graph output for this
+				 * commit.
+				 */
+				if (graph_show_remainder(revs.graph))
+					putchar('\n');
+			}
+		} else {
+			if (buf.len)
+				printf("%s%c", buf.buf, hdr_termination);
+		}
 		strbuf_release(&buf);
+	} else {
+		if (graph_show_remainder(revs.graph))
+			putchar('\n');
 	}
 	maybe_flush_or_die(stdout, "stdout");
 	finish_commit(commit);
@@ -546,12 +591,13 @@
 	int bisect_find_all = 0;
 	int quiet = 0;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	init_revisions(&revs, prefix);
 	revs.abbrev = 0;
 	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];
 
@@ -583,10 +629,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 00b6078..a7860ed 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -28,8 +28,6 @@
 static int abbrev;
 static int output_sq;
 
-static int revs_count;
-
 /*
  * Some arguments are relevant "revision" arguments,
  * others are about output format or other details.
@@ -110,7 +108,6 @@
 	if (!(filter & DO_REVS))
 		return;
 	def = NULL;
-	revs_count++;
 
 	if (symbolic && name) {
 		if (symbolic == SHOW_SYMBOLIC_FULL) {
@@ -156,7 +153,7 @@
 	return 0;
 }
 
-static void show_default(void)
+static int show_default(void)
 {
 	const char *s = def;
 
@@ -166,9 +163,10 @@
 		def = NULL;
 		if (!get_sha1(s, sha1)) {
 			show_rev(NORMAL, sha1, s);
-			return;
+			return 1;
 		}
 	}
+	return 0;
 }
 
 static int show_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
@@ -371,16 +369,25 @@
 	return 0;
 }
 
+static void die_no_single_rev(int quiet)
+{
+	if (quiet)
+		exit(1);
+	else
+		die("Needed a single revision");
+}
+
 int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 {
-	int i, as_is = 0, verify = 0;
+	int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
 	unsigned char sha1[20];
+	const char *name = NULL;
 
 	if (argc > 1 && !strcmp("--parseopt", argv[1]))
 		return cmd_parseopt(argc - 1, argv + 1, prefix);
 
 	prefix = setup_git_directory();
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 
@@ -438,6 +445,10 @@
 				verify = 1;
 				continue;
 			}
+			if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
+				quiet = 1;
+				continue;
+			}
 			if (!strcmp(arg, "--short") ||
 			    !prefixcmp(arg, "--short=")) {
 				filter &= ~(DO_FLAGS|DO_NOREV);
@@ -555,30 +566,41 @@
 				continue;
 			}
 			if (show_flag(arg) && verify)
-				die("Needed a single revision");
+				die_no_single_rev(quiet);
 			continue;
 		}
 
 		/* Not a flag argument */
 		if (try_difference(arg))
 			continue;
-		if (!get_sha1(arg, sha1)) {
-			show_rev(NORMAL, sha1, arg);
+		name = arg;
+		type = NORMAL;
+		if (*arg == '^') {
+			name++;
+			type = REVERSED;
+		}
+		if (!get_sha1(name, sha1)) {
+			if (verify)
+				revs_count++;
+			else
+				show_rev(type, sha1, name);
 			continue;
 		}
-		if (*arg == '^' && !get_sha1(arg+1, sha1)) {
-			show_rev(REVERSED, sha1, arg+1);
-			continue;
-		}
+		if (verify)
+			die_no_single_rev(quiet);
 		as_is = 1;
 		if (!show_file(arg))
 			continue;
-		if (verify)
-			die("Needed a single revision");
 		verify_filename(prefix, arg);
 	}
-	show_default();
-	if (verify && revs_count != 1)
-		die("Needed a single revision");
+	if (verify) {
+		if (revs_count == 1) {
+			show_rev(type, sha1, name);
+			return 0;
+		} else if (revs_count == 0 && show_default())
+			return 0;
+		die_no_single_rev(quiet);
+	} else
+		show_default();
 	return 0;
 }
diff --git a/builtin-revert.c b/builtin-revert.c
index 607a2f0..bde28b2 100644
--- a/builtin-revert.c
+++ b/builtin-revert.c
@@ -33,7 +33,7 @@
 	NULL
 };
 
-static int edit, no_replay, no_commit, mainline;
+static int edit, no_replay, no_commit, mainline, signoff;
 static enum { REVERT, CHERRY_PICK } action;
 static struct commit *commit;
 
@@ -53,6 +53,7 @@
 		OPT_BOOLEAN('e', "edit", &edit, "edit the commit message"),
 		OPT_BOOLEAN('x', NULL, &no_replay, "append commit name when cherry-picking"),
 		OPT_BOOLEAN('r', NULL, &noop, "no-op (backward compatibility)"),
+		OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
 		OPT_INTEGER('m', "mainline", &mainline, "parent number"),
 		OPT_END(),
 	};
@@ -179,7 +180,7 @@
 			email++;
 			timestamp = strchr(email, '>');
 			if (!timestamp)
-				die ("Could not extract author email from %s",
+				die ("Could not extract author time from %s",
 					sha1_to_hex(commit->object.sha1));
 			*timestamp = '\0';
 			for (timestamp++; *timestamp && isspace(*timestamp);
@@ -268,7 +269,7 @@
 	const char *message, *encoding;
 	const char *defmsg = xstrdup(git_path("MERGE_MSG"));
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	me = action == REVERT ? "revert" : "cherry-pick";
 	setenv(GIT_REFLOG_ACTION, me, 0);
 	parse_args(argc, argv);
@@ -404,10 +405,19 @@
 	 */
 
 	if (!no_commit) {
-		if (edit)
-			return execl_git_cmd("commit", "-n", NULL);
-		else
-			return execl_git_cmd("commit", "-n", "-F", defmsg, NULL);
+		/* 6 is max possible length of our args array including NULL */
+		const char *args[6];
+		int i = 0;
+		args[i++] = "commit";
+		args[i++] = "-n";
+		if (signoff)
+			args[i++] = "-s";
+		if (!edit) {
+			args[i++] = "-F";
+			args[i++] = defmsg;
+		}
+		args[i] = NULL;
+		return execv_git_cmd(args);
 	}
 	free(reencoded_message);
 
diff --git a/builtin-rm.c b/builtin-rm.c
index c0a8bb6..abdab7f 100644
--- a/builtin-rm.c
+++ b/builtin-rm.c
@@ -144,12 +144,7 @@
 	const char **pathspec;
 	char *seen;
 
-	git_config(git_default_config);
-
-	newfd = hold_locked_index(&lock_file, 1);
-
-	if (read_cache() < 0)
-		die("index file corrupt");
+	git_config(git_default_config, NULL);
 
 	argc = parse_options(argc, argv, builtin_rm_options, builtin_rm_usage, 0);
 	if (!argc)
@@ -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 bb9c33a..a708d0a 100644
--- a/builtin-send-pack.c
+++ b/builtin-send-pack.c
@@ -226,8 +226,7 @@
 		if (args.verbose)
 			fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
 		if (ref->deletion) {
-			if (delete_ref(rs.dst, NULL))
-				error("Failed to delete");
+			delete_ref(rs.dst, NULL);
 		} else
 			update_ref("update by push", rs.dst,
 					ref->new_sha1, NULL, 0, 0);
@@ -537,9 +536,17 @@
 	int i;
 
 	for (i = 0; i < nr_heads; i++) {
+		const char *local = heads[i];
 		const char *remote = strrchr(heads[i], ':');
 
-		remote = remote ? (remote + 1) : heads[i];
+		if (*local == '+')
+			local++;
+
+		/* A matching refspec is okay.  */
+		if (remote == local && remote[1] == '\0')
+			continue;
+
+		remote = remote ? (remote + 1) : local;
 		switch (check_ref_format(remote)) {
 		case 0: /* ok */
 		case CHECK_REF_FORMAT_ONELEVEL:
diff --git a/builtin-show-branch.c b/builtin-show-branch.c
index a383323..93047f5 100644
--- a/builtin-show-branch.c
+++ b/builtin-show-branch.c
@@ -533,7 +533,7 @@
 	die("bad sha1 reference %s", av);
 }
 
-static int git_show_branch_config(const char *var, const char *value)
+static int git_show_branch_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "showbranch.default")) {
 		if (!value)
@@ -547,7 +547,7 @@
 		return 0;
 	}
 
-	return git_default_config(var, value);
+	return git_default_config(var, value, cb);
 }
 
 static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
@@ -611,7 +611,7 @@
 	int reflog = 0;
 	const char *reflog_base = NULL;
 
-	git_config(git_show_branch_config);
+	git_config(git_show_branch_config, NULL);
 
 	/* If nothing is specified, try the default first */
 	if (ac == 1 && default_num) {
diff --git a/builtin-symbolic-ref.c b/builtin-symbolic-ref.c
index d33982b..b49bdb6 100644
--- a/builtin-symbolic-ref.c
+++ b/builtin-symbolic-ref.c
@@ -35,7 +35,7 @@
 		OPT_END(),
 	};
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	argc = parse_options(argc, argv, options, git_symbolic_ref_usage, 0);
 	if (msg &&!*msg)
 		die("Refusing to perform update with empty message");
diff --git a/builtin-tag.c b/builtin-tag.c
index 129ff57..3bd019c 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -256,16 +256,16 @@
 		die("signing key value too long (%.10s...)", value);
 }
 
-static int git_tag_config(const char *var, const char *value)
+static int git_tag_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "user.signingkey")) {
 		if (!value)
-			return config_error_nonbool(value);
+			return config_error_nonbool(var);
 		set_signingkey(value);
 		return 0;
 	}
 
-	return git_default_config(var, value);
+	return git_default_config(var, value, cb);
 }
 
 static void write_tag_body(int fd, const unsigned char *sha1)
@@ -385,7 +385,7 @@
 
 	int annotate = 0, sign = 0, force = 0, lines = 0,
 		list = 0, delete = 0, verify = 0;
-	char *msgfile = NULL, *keyid = NULL;
+	const char *msgfile = NULL, *keyid = NULL;
 	struct msg_arg msg = { 0, STRBUF_INIT };
 	struct option options[] = {
 		OPT_BOOLEAN('l', NULL, &list, "list tag names"),
@@ -408,9 +408,10 @@
 		OPT_END()
 	};
 
-	git_config(git_tag_config);
+	git_config(git_tag_config, NULL);
 
 	argc = parse_options(argc, argv, options, git_tag_usage, 0);
+	msgfile = parse_options_fix_filename(prefix, msgfile);
 
 	if (keyid) {
 		sign = 1;
diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c
index 50e07fa..85043d1 100644
--- a/builtin-unpack-objects.c
+++ b/builtin-unpack-objects.c
@@ -7,11 +7,13 @@
 #include "commit.h"
 #include "tag.h"
 #include "tree.h"
+#include "tree-walk.h"
 #include "progress.h"
 #include "decorate.h"
+#include "fsck.h"
 
-static int dry_run, quiet, recover, has_errors;
-static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] < pack-file";
+static int dry_run, quiet, recover, has_errors, strict;
+static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
 
 /* We always read in 4kB chunks. */
 static unsigned char buffer[4096];
@@ -19,6 +21,11 @@
 static off_t consumed_bytes;
 static SHA_CTX ctx;
 
+/*
+ * When running under --strict mode, objects whose reachability are
+ * suspect are kept in core without getting written in the object
+ * store.
+ */
 struct obj_buffer {
 	char *buffer;
 	unsigned long size;
@@ -31,6 +38,16 @@
 	return lookup_decoration(&obj_decorate, base);
 }
 
+static void add_object_buffer(struct object *object, char *buffer, unsigned long size)
+{
+	struct obj_buffer *obj;
+	obj = xcalloc(1, sizeof(struct obj_buffer));
+	obj->buffer = buffer;
+	obj->size = size;
+	if (add_decoration(&obj_decorate, object, obj))
+		die("object %s tried to add buffer twice!", sha1_to_hex(object->sha1));
+}
+
 /*
  * Make sure at least "min" bytes are available in the buffer, and
  * return the pointer to the buffer.
@@ -134,19 +151,110 @@
 struct obj_info {
 	off_t offset;
 	unsigned char sha1[20];
+	struct object *obj;
 };
 
+#define FLAG_OPEN (1u<<20)
+#define FLAG_WRITTEN (1u<<21)
+
 static struct obj_info *obj_list;
+unsigned nr_objects;
+
+/*
+ * Called only from check_object() after it verified this object
+ * is Ok.
+ */
+static void write_cached_object(struct object *obj)
+{
+	unsigned char sha1[20];
+	struct obj_buffer *obj_buf = lookup_object_buffer(obj);
+	if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), sha1) < 0)
+		die("failed to write object %s", sha1_to_hex(obj->sha1));
+	obj->flags |= FLAG_WRITTEN;
+}
+
+/*
+ * At the very end of the processing, write_rest() scans the objects
+ * that have reachability requirements and calls this function.
+ * Verify its reachability and validity recursively and write it out.
+ */
+static int check_object(struct object *obj, int type, void *data)
+{
+	if (!obj)
+		return 0;
+
+	if (obj->flags & FLAG_WRITTEN)
+		return 1;
+
+	if (type != OBJ_ANY && obj->type != type)
+		die("object type mismatch");
+
+	if (!(obj->flags & FLAG_OPEN)) {
+		unsigned long size;
+		int type = sha1_object_info(obj->sha1, &size);
+		if (type != obj->type || type <= 0)
+			die("object of unexpected type");
+		obj->flags |= FLAG_WRITTEN;
+		return 1;
+	}
+
+	if (fsck_object(obj, 1, fsck_error_function))
+		die("Error in object");
+	if (!fsck_walk(obj, check_object, 0))
+		die("Error on reachable objects of %s", sha1_to_hex(obj->sha1));
+	write_cached_object(obj);
+	return 1;
+}
+
+static void write_rest(void)
+{
+	unsigned i;
+	for (i = 0; i < nr_objects; i++)
+		check_object(obj_list[i].obj, OBJ_ANY, 0);
+}
 
 static void added_object(unsigned nr, enum object_type type,
 			 void *data, unsigned long size);
 
+/*
+ * Write out nr-th object from the list, now we know the contents
+ * of it.  Under --strict, this buffers structured objects in-core,
+ * to be checked at the end.
+ */
 static void write_object(unsigned nr, enum object_type type,
 			 void *buf, unsigned long size)
 {
-	if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
-		die("failed to write object");
-	added_object(nr, type, buf, size);
+	if (!strict) {
+		if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
+			die("failed to write object");
+		added_object(nr, type, buf, size);
+		free(buf);
+		obj_list[nr].obj = NULL;
+	} else if (type == OBJ_BLOB) {
+		struct blob *blob;
+		if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
+			die("failed to write object");
+		added_object(nr, type, buf, size);
+		free(buf);
+
+		blob = lookup_blob(obj_list[nr].sha1);
+		if (blob)
+			blob->object.flags |= FLAG_WRITTEN;
+		else
+			die("invalid blob object");
+		obj_list[nr].obj = NULL;
+	} else {
+		struct object *obj;
+		int eaten;
+		hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1);
+		added_object(nr, type, buf, size);
+		obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten);
+		if (!obj)
+			die("invalid %s", typename(type));
+		add_object_buffer(obj, buf, size);
+		obj->flags |= FLAG_OPEN;
+		obj_list[nr].obj = obj;
+	}
 }
 
 static void resolve_delta(unsigned nr, enum object_type type,
@@ -163,9 +271,12 @@
 		die("failed to apply delta");
 	free(delta);
 	write_object(nr, type, result, result_size);
-	free(result);
 }
 
+/*
+ * We now know the contents of an object (which is nr-th in the pack);
+ * resolve all the deltified objects that are based on it.
+ */
 static void added_object(unsigned nr, enum object_type type,
 			 void *data, unsigned long size)
 {
@@ -193,7 +304,24 @@
 
 	if (!dry_run && buf)
 		write_object(nr, type, buf, size);
-	free(buf);
+	else
+		free(buf);
+}
+
+static int resolve_against_held(unsigned nr, const unsigned char *base,
+				void *delta_data, unsigned long delta_size)
+{
+	struct object *obj;
+	struct obj_buffer *obj_buffer;
+	obj = lookup_object(base);
+	if (!obj)
+		return 0;
+	obj_buffer = lookup_object_buffer(obj);
+	if (!obj_buffer)
+		return 0;
+	resolve_delta(nr, obj->type, obj_buffer->buffer,
+		      obj_buffer->size, delta_data, delta_size);
+	return 1;
 }
 
 static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
@@ -202,7 +330,6 @@
 	void *delta_data, *base;
 	unsigned long base_size;
 	unsigned char base_sha1[20];
-	struct object *obj;
 
 	if (type == OBJ_REF_DELTA) {
 		hashcpy(base_sha1, fill(20));
@@ -212,7 +339,13 @@
 			free(delta_data);
 			return;
 		}
-		if (!has_sha1_file(base_sha1)) {
+		if (has_sha1_file(base_sha1))
+			; /* Ok we have this one */
+		else if (resolve_against_held(nr, base_sha1,
+					      delta_data, delta_size))
+			return; /* we are done */
+		else {
+			/* cannot resolve yet --- queue it */
 			hashcpy(obj_list[nr].sha1, null_sha1);
 			add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size);
 			return;
@@ -258,22 +391,18 @@
 			}
 		}
 		if (!base_found) {
-			/* The delta base object is itself a delta that
-			   has not been	resolved yet. */
+			/*
+			 * The delta base object is itself a delta that
+			 * has not been resolved yet.
+			 */
 			hashcpy(obj_list[nr].sha1, null_sha1);
 			add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size);
 			return;
 		}
 	}
 
-	obj = lookup_object(base_sha1);
-	if (obj) {
-		struct obj_buffer *obj_buf = lookup_object_buffer(obj);
-		if (obj_buf) {
-			resolve_delta(nr, obj->type, obj_buf->buffer, obj_buf->size, delta_data, delta_size);
-			return;
-		}
-	}
+	if (resolve_against_held(nr, base_sha1, delta_data, delta_size))
+		return;
 
 	base = read_sha1_file(base_sha1, &type, &base_size);
 	if (!base) {
@@ -336,7 +465,8 @@
 	int i;
 	struct progress *progress = NULL;
 	struct pack_header *hdr = fill(sizeof(struct pack_header));
-	unsigned nr_objects = ntohl(hdr->hdr_entries);
+
+	nr_objects = ntohl(hdr->hdr_entries);
 
 	if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE)
 		die("bad pack file");
@@ -347,6 +477,7 @@
 	if (!quiet)
 		progress = start_progress("Unpacking objects", nr_objects);
 	obj_list = xmalloc(nr_objects * sizeof(*obj_list));
+	memset(obj_list, 0, nr_objects * sizeof(*obj_list));
 	for (i = 0; i < nr_objects; i++) {
 		unpack_one(i);
 		display_progress(progress, i + 1);
@@ -362,7 +493,7 @@
 	int i;
 	unsigned char sha1[20];
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	quiet = !isatty(2);
 
@@ -382,6 +513,10 @@
 				recover = 1;
 				continue;
 			}
+			if (!strcmp(arg, "--strict")) {
+				strict = 1;
+				continue;
+			}
 			if (!prefixcmp(arg, "--pack_header=")) {
 				struct pack_header *hdr;
 				char *c;
@@ -407,6 +542,8 @@
 	unpack_all();
 	SHA1_Update(&ctx, buffer, offset);
 	SHA1_Final(sha1, &ctx);
+	if (strict)
+		write_rest();
 	if (hashcmp(fill(20), sha1))
 		die("final sha1 did not match");
 	use(20);
diff --git a/builtin-update-index.c b/builtin-update-index.c
index a8795d3..9e0d7ab 100644
--- a/builtin-update-index.c
+++ b/builtin-update-index.c
@@ -567,7 +567,7 @@
 	int lock_error = 0;
 	struct lock_file *lock_file;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	/* We can't free this memory, it becomes part of a linked list parsed atexit() */
 	lock_file = xcalloc(1, sizeof(struct lock_file));
@@ -593,6 +593,10 @@
 				refresh_flags |= REFRESH_QUIET;
 				continue;
 			}
+			if (!strcmp(path, "--ignore-submodules")) {
+				refresh_flags |= REFRESH_IGNORE_SUBMODULES;
+				continue;
+			}
 			if (!strcmp(path, "--add")) {
 				allow_add = 1;
 				continue;
diff --git a/builtin-update-ref.c b/builtin-update-ref.c
index e90737c..93c1271 100644
--- a/builtin-update-ref.c
+++ b/builtin-update-ref.c
@@ -22,7 +22,7 @@
 		OPT_END(),
 	};
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	argc = parse_options(argc, argv, options, git_update_ref_usage, 0);
 	if (msg && !*msg)
 		die("Refusing to perform update with empty message.");
diff --git a/builtin-upload-archive.c b/builtin-upload-archive.c
index 48ae09e..371400d 100644
--- a/builtin-upload-archive.c
+++ b/builtin-upload-archive.c
@@ -30,7 +30,7 @@
 	if (argc != 2)
 		usage(upload_archive_usage);
 
-	if (strlen(argv[1]) > sizeof(buf))
+	if (strlen(argv[1]) + 1 > sizeof(buf))
 		die("insanely long repository name");
 
 	strcpy(buf, argv[1]); /* enter-repo smudges its argument */
diff --git a/builtin-verify-pack.c b/builtin-verify-pack.c
index 4958bbb..4c515a0 100644
--- a/builtin-verify-pack.c
+++ b/builtin-verify-pack.c
@@ -55,7 +55,7 @@
 	int no_more_options = 0;
 	int nothing_done = 1;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	while (1 < argc) {
 		if (!no_more_options && argv[1][0] == '-') {
 			if (!strcmp("-v", argv[1]))
diff --git a/builtin-verify-tag.c b/builtin-verify-tag.c
index db81496..92eaa89 100644
--- a/builtin-verify-tag.c
+++ b/builtin-verify-tag.c
@@ -90,7 +90,7 @@
 {
 	int i = 1, verbose = 0, had_error = 0;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	if (argc == 1)
 		usage(builtin_verify_tag_usage);
diff --git a/builtin-write-tree.c b/builtin-write-tree.c
index e838d01..c218799 100644
--- a/builtin-write-tree.c
+++ b/builtin-write-tree.c
@@ -18,7 +18,7 @@
 	unsigned char sha1[20];
 	const char *me = "git-write-tree";
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	while (1 < argc) {
 		const char *arg = argv[1];
 		if (!strcmp(arg, "--missing-ok"))
diff --git a/builtin.h b/builtin.h
index 95126fd..b460b2d 100644
--- a/builtin.h
+++ b/builtin.h
@@ -5,10 +5,12 @@
 
 extern const char git_version_string[];
 extern const char git_usage_string[];
+extern const char git_more_info_string[];
 
 extern void list_common_cmds_help(void);
 extern void help_unknown_cmd(const char *cmd);
 extern void prune_packed_objects(int);
+extern int read_line_with_nul(char *buf, int size, FILE *file);
 
 extern int cmd_add(int argc, const char **argv, const char *prefix);
 extern int cmd_annotate(int argc, const char **argv, const char *prefix);
@@ -24,6 +26,7 @@
 extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
 extern int cmd_cherry(int argc, const char **argv, const char *prefix);
 extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
+extern int cmd_clone(int argc, const char **argv, const char *prefix);
 extern int cmd_clean(int argc, const char **argv, const char *prefix);
 extern int cmd_commit(int argc, const char **argv, const char *prefix);
 extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
diff --git a/cache.h b/cache.h
index 2a1e7ec..8822651 100644
--- a/cache.h
+++ b/cache.h
@@ -133,6 +133,7 @@
 #define CE_UPDATE    (0x10000)
 #define CE_REMOVE    (0x20000)
 #define CE_UPTODATE  (0x40000)
+#define CE_ADDED     (0x80000)
 
 #define CE_HASHED    (0x100000)
 #define CE_UNHASHED  (0x200000)
@@ -153,20 +154,6 @@
 	dst->ce_flags = (dst->ce_flags & ~CE_STATE_MASK) | state;
 }
 
-/*
- * We don't actually *remove* it, we can just mark it invalid so that
- * we won't find it in lookups.
- *
- * Not only would we have to search the lists (simple enough), but
- * we'd also have to rehash other hash buckets in case this makes the
- * hash bucket empty (common). So it's much better to just mark
- * it.
- */
-static inline void remove_index_entry(struct cache_entry *ce)
-{
-	ce->ce_flags |= CE_UNHASHED;
-}
-
 static inline unsigned create_ce_flags(size_t len, unsigned stage)
 {
 	if (len >= CE_NAMEMASK)
@@ -241,6 +228,23 @@
 
 extern struct index_state the_index;
 
+/* Name hashing */
+extern void add_name_hash(struct index_state *istate, struct cache_entry *ce);
+/*
+ * We don't actually *remove* it, we can just mark it invalid so that
+ * we won't find it in lookups.
+ *
+ * Not only would we have to search the lists (simple enough), but
+ * we'd also have to rehash other hash buckets in case this makes the
+ * hash bucket empty (common). So it's much better to just mark
+ * it.
+ */
+static inline void remove_name_hash(struct cache_entry *ce)
+{
+	ce->ce_flags |= CE_UNHASHED;
+}
+
+
 #ifndef NO_THE_INDEX_COMPATIBILITY_MACROS
 #define active_cache (the_index.cache)
 #define active_nr (the_index.cache_nr)
@@ -257,11 +261,12 @@
 #define add_cache_entry(ce, option) add_index_entry(&the_index, (ce), (option))
 #define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos))
 #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
-#define add_file_to_cache(path, verbose) add_file_to_index(&the_index, (path), (verbose))
+#define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags))
+#define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags))
 #define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL)
 #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
 #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
-#define cache_name_exists(name, namelen) index_name_exists(&the_index, (name), (namelen))
+#define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
 #endif
 
 enum object_type {
@@ -311,6 +316,8 @@
 extern char *get_graft_file(void);
 extern int set_git_dir(const char *path);
 extern const char *get_git_work_tree(void);
+extern const char *read_gitfile_gently(const char *path);
+extern void set_git_work_tree(const char *tree);
 
 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
 
@@ -323,6 +330,10 @@
 extern void verify_filename(const char *prefix, const char *name);
 extern void verify_non_filename(const char *prefix, const char *name);
 
+#define INIT_DB_QUIET 0x0001
+
+extern int init_db(const char *template_dir, unsigned int flags);
+
 #define alloc_nr(x) (((x)+16)*3/2)
 
 /*
@@ -350,7 +361,7 @@
 extern int discard_index(struct index_state *);
 extern int unmerged_index(const struct index_state *);
 extern int verify_path(const char *path);
-extern int index_name_exists(struct index_state *istate, const char *name, int namelen);
+extern struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int igncase);
 extern int index_name_pos(const struct index_state *, const char *name, int namelen);
 #define ADD_CACHE_OK_TO_ADD 1		/* Ok to add */
 #define ADD_CACHE_OK_TO_REPLACE 2	/* Ok to replace file/directory */
@@ -360,7 +371,11 @@
 extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
 extern int remove_index_entry_at(struct index_state *, int pos);
 extern int remove_file_from_index(struct index_state *, const char *path);
-extern int add_file_to_index(struct index_state *, const char *path, int verbose);
+#define ADD_CACHE_VERBOSE 1
+#define ADD_CACHE_PRETEND 2
+#define ADD_CACHE_IGNORE_ERRORS	4
+extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
+extern int add_file_to_index(struct index_state *, const char *path, int flags);
 extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
 extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
 
@@ -381,6 +396,7 @@
 #define REFRESH_UNMERGED	0x0002	/* allow unmerged */
 #define REFRESH_QUIET		0x0004	/* be quiet about it */
 #define REFRESH_IGNORE_MISSING	0x0008	/* ignore non-existent */
+#define REFRESH_IGNORE_SUBMODULES	0x0010	/* ignore submodules */
 extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen);
 
 struct lock_file {
@@ -391,6 +407,7 @@
 	char filename[PATH_MAX];
 };
 extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
+extern int hold_lock_file_for_append(struct lock_file *, const char *path, int);
 extern int commit_lock_file(struct lock_file *);
 
 extern int hold_locked_index(struct lock_file *, int);
@@ -404,6 +421,7 @@
 extern int trust_executable_bit;
 extern int quote_path_fully;
 extern int has_symlinks;
+extern int ignore_case;
 extern int assume_unchanged;
 extern int prefer_symlink_refs;
 extern int log_all_ref_updates;
@@ -417,6 +435,7 @@
 extern size_t packed_git_limit;
 extern size_t delta_base_cache_limit;
 extern int auto_crlf;
+extern int fsync_object_files;
 
 enum safe_crlf {
 	SAFE_CRLF_FALSE = 0,
@@ -433,7 +452,15 @@
 	BRANCH_TRACK_EXPLICIT,
 };
 
+enum rebase_setup_type {
+	AUTOREBASE_NEVER = 0,
+	AUTOREBASE_LOCAL,
+	AUTOREBASE_REMOTE,
+	AUTOREBASE_ALWAYS,
+};
+
 extern enum branch_track git_branch_track;
+extern enum rebase_setup_type autorebase;
 
 #define GIT_REPO_VERSION 0
 extern int repository_format_version;
@@ -474,20 +501,33 @@
 
 int git_mkstemp(char *path, size_t n, const char *template);
 
+/*
+ * NOTE NOTE NOTE!!
+ *
+ * PERM_UMASK, OLD_PERM_GROUP and OLD_PERM_EVERYBODY enumerations must
+ * not be changed. Old repositories have core.sharedrepository written in
+ * numeric format, and therefore these values are preserved for compatibility
+ * reasons.
+ */
 enum sharedrepo {
-	PERM_UMASK = 0,
-	PERM_GROUP,
-	PERM_EVERYBODY
+	PERM_UMASK          = 0,
+	OLD_PERM_GROUP      = 1,
+	OLD_PERM_EVERYBODY  = 2,
+	PERM_GROUP          = 0660,
+	PERM_EVERYBODY      = 0664,
 };
 int git_config_perm(const char *var, const char *value);
 int adjust_shared_perm(const char *path);
 int safe_create_leading_directories(char *path);
+int safe_create_leading_directories_const(const char *path);
 char *enter_repo(char *path, int strict);
 static inline int is_absolute_path(const char *path)
 {
 	return path[0] == '/';
 }
 const char *make_absolute_path(const char *path);
+const char *make_nonrelative_path(const char *path);
+const char *make_relative_path(const char *abs, const char *base);
 
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 extern int sha1_object_info(const unsigned char *, unsigned long *);
@@ -495,12 +535,10 @@
 extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
 extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
 extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
+extern int force_object_loose(const unsigned char *sha1, time_t mtime);
 
 extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
 
-extern int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
-			      size_t bufsize, size_t *bufposn);
-extern int write_sha1_to_fd(int fd, const unsigned char *sha1);
 extern int move_temp_to_file(const char *tmpfile, const char *filename);
 
 extern int has_sha1_pack(const unsigned char *sha1, const char **ignore);
@@ -580,7 +618,7 @@
 };
 
 extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
-extern int has_symlink_leading_path(const char *name, char *last_symlink);
+extern int has_symlink_leading_path(int len, const char *name);
 
 extern struct alternate_object_database {
 	struct alternate_object_database *next;
@@ -588,6 +626,7 @@
 	char base[FLEX_ARRAY]; /* more */
 } *alt_odb_list;
 extern void prepare_alt_odb(void);
+extern void add_to_alternates_file(const char *reference);
 
 struct pack_window {
 	struct pack_window *next;
@@ -624,6 +663,7 @@
 	struct ref *next;
 	unsigned char old_sha1[20];
 	unsigned char new_sha1[20];
+	char *symref;
 	unsigned int force:1,
 		merge:1,
 		nonfastforward:1,
@@ -657,8 +697,6 @@
 extern int server_supports(const char *feature);
 
 extern struct packed_git *parse_pack_index(unsigned char *sha1);
-extern struct packed_git *parse_pack_index_file(const unsigned char *sha1,
-						const char *idx_path);
 
 extern void prepare_packed_git(void);
 extern void reprepare_packed_git(void);
@@ -684,21 +722,22 @@
 /* Dumb servers support */
 extern int update_server_info(int);
 
-typedef int (*config_fn_t)(const char *, const char *);
-extern int git_default_config(const char *, const char *);
-extern int git_config_from_file(config_fn_t fn, const char *);
-extern int git_config(config_fn_t fn);
+typedef int (*config_fn_t)(const char *, const char *, void *);
+extern int git_default_config(const char *, const char *, void *);
+extern int git_config_from_file(config_fn_t fn, const char *, void *);
+extern int git_config(config_fn_t fn, void *);
 extern int git_parse_long(const char *, long *);
 extern int git_parse_ulong(const char *, unsigned long *);
 extern int git_config_int(const char *, const char *);
 extern unsigned long git_config_ulong(const char *, const char *);
+extern int git_config_bool_or_int(const char *, const char *, int *);
 extern int git_config_bool(const char *, const char *);
 extern int git_config_string(const char **, const char *, const char *);
 extern int git_config_set(const char *, const char *);
 extern int git_config_set_multivar(const char *, const char *, const char *, int);
 extern int git_config_rename_section(const char *, const char *);
 extern const char *git_etc_gitconfig(void);
-extern int check_repository_format_version(const char *var, const char *value);
+extern int check_repository_format_version(const char *var, const char *value, void *cb);
 extern int git_env_bool(const char *, int);
 extern int git_config_system(void);
 extern int git_config_global(void);
@@ -707,6 +746,7 @@
 #define MAX_GITNAME (1000)
 extern char git_default_email[MAX_GITNAME];
 extern char git_default_name[MAX_GITNAME];
+extern int user_ident_explicitly_given;
 
 extern const char *git_commit_encoding;
 extern const char *git_log_output_encoding;
@@ -715,11 +755,12 @@
 extern void maybe_flush_or_die(FILE *, const char *);
 extern int copy_fd(int ifd, int ofd);
 extern int copy_file(const char *dst, const char *src, int mode);
-extern int read_in_full(int fd, void *buf, size_t count);
-extern int write_in_full(int fd, const void *buf, size_t count);
+extern ssize_t read_in_full(int fd, void *buf, size_t count);
+extern ssize_t write_in_full(int fd, const void *buf, size_t count);
 extern void write_or_die(int fd, const void *buf, size_t count);
 extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
 extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
+extern void fsync_or_die(int fd, const char *);
 
 /* pager.c */
 extern void setup_pager(void);
@@ -753,7 +794,11 @@
 extern int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst);
 
 /* add */
-void add_files_to_cache(int verbose, const char *prefix, const char **pathspec);
+/*
+ * return 0 if success, 1 - if addition of a file failed and
+ * ADD_FILES_IGNORE_ERRORS was specified in flags
+ */
+int add_files_to_cache(const char *prefix, const char **pathspec, int flags);
 
 /* diff.c */
 extern int diff_auto_refresh_index;
diff --git a/color.c b/color.c
index 12a6453..fc0b72a 100644
--- a/color.c
+++ b/color.c
@@ -145,14 +145,14 @@
 	return 0;
 }
 
-int git_color_default_config(const char *var, const char *value)
+int git_color_default_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "color.ui")) {
 		git_use_color_default = git_config_colorbool(var, value, -1);
 		return 0;
 	}
 
-	return git_default_config(var, value);
+	return git_default_config(var, value, cb);
 }
 
 static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
diff --git a/color.h b/color.h
index ecda556..6cf5c88 100644
--- a/color.h
+++ b/color.h
@@ -13,7 +13,7 @@
 /*
  * Use this instead of git_default_config if you need the value of color.ui.
  */
-int git_color_default_config(const char *var, const char *value);
+int git_color_default_config(const char *var, const char *value, void *cb);
 
 int git_config_colorbool(const char *var, const char *value, int stdout_is_tty);
 void color_parse(const char *var, const char *value, char *dst);
diff --git a/combine-diff.c b/combine-diff.c
index 0e19cba..9f80a1c 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -84,6 +84,7 @@
 	/* bit 0 up to (N-1) are on if the parent has this line (i.e.
 	 * we did not change it).
 	 * bit N is used for "interesting" lines, including context.
+	 * bit (N+1) is used for "do not show deletion before this".
 	 */
 	unsigned long flag;
 	unsigned long *p_lno;
@@ -308,6 +309,7 @@
 {
 	unsigned long all_mask = (1UL<<num_parent) - 1;
 	unsigned long mark = (1UL<<num_parent);
+	unsigned long no_pre_delete = (2UL<<num_parent);
 	unsigned long i;
 
 	/* Two groups of interesting lines may have a short gap of
@@ -329,7 +331,7 @@
 
 		/* Paint a few lines before the first interesting line. */
 		while (j < i)
-			sline[j++].flag |= mark;
+			sline[j++].flag |= mark | no_pre_delete;
 
 	again:
 		/* we know up to i is to be included.  where does the
@@ -502,6 +504,7 @@
 		       int use_color)
 {
 	unsigned long mark = (1UL<<num_parent);
+	unsigned long no_pre_delete = (2UL<<num_parent);
 	int i;
 	unsigned long lno = 0;
 	const char *c_frag = diff_get_color(use_color, DIFF_FRAGINFO);
@@ -581,7 +584,7 @@
 			int j;
 			unsigned long p_mask;
 			sl = &sline[lno++];
-			ll = sl->lost_head;
+			ll = (sl->flag & no_pre_delete) ? NULL : sl->lost_head;
 			while (ll) {
 				fputs(c_old, stdout);
 				for (j = 0; j < num_parent; j++) {
@@ -701,7 +704,7 @@
 		else if (0 <= (fd = open(elem->path, O_RDONLY)) &&
 			 !fstat(fd, &st)) {
 			size_t len = xsize_t(st.st_size);
-			size_t sz = 0;
+			ssize_t done;
 			int is_file, i;
 
 			elem->mode = canon_mode(st.st_mode);
@@ -716,14 +719,13 @@
 
 			result_size = len;
 			result = xmalloc(len + 1);
-			while (sz < len) {
-				ssize_t done = xread(fd, result+sz, len-sz);
-				if (done == 0)
-					break;
-				if (done < 0)
-					die("read error '%s'", elem->path);
-				sz += done;
-			}
+
+			done = read_in_full(fd, result, len);
+			if (done < 0)
+				die("read error '%s'", elem->path);
+			else if (done < len)
+				die("early EOF '%s'", elem->path);
+
 			result[len] = 0;
 		}
 		else {
@@ -798,7 +800,7 @@
 		int deleted = 0;
 
 		if (rev->loginfo && !rev->no_commit_id)
-			show_log(rev, opt->msg_sep);
+			show_log(rev);
 		dump_quoted_path(dense ? "diff --cc " : "diff --combined ",
 				 "", elem->path, c_meta, c_reset);
 		printf("%sindex ", c_meta);
@@ -881,7 +883,7 @@
 		inter_name_termination = 0;
 
 	if (rev->loginfo && !rev->no_commit_id)
-		show_log(rev, opt->msg_sep);
+		show_log(rev);
 
 	if (opt->output_format & DIFF_FORMAT_RAW) {
 		offset = strlen(COLONS) - num_parent;
@@ -962,7 +964,7 @@
 		paths = intersect_paths(paths, i, num_parent);
 
 		if (show_log_first && i == 0) {
-			show_log(rev, opt->msg_sep);
+			show_log(rev);
 			if (rev->verbose_header && opt->output_format)
 				putchar(opt->line_termination);
 		}
diff --git a/commit.c b/commit.c
index 94d5b3d..09cf167 100644
--- a/commit.c
+++ b/commit.c
@@ -243,7 +243,6 @@
 	unsigned char parent[20];
 	struct commit_list **pptr;
 	struct commit_graft *graft;
-	unsigned n_refs = 0;
 
 	if (item->object.parsed)
 		return 0;
@@ -255,8 +254,6 @@
 		return error("bad tree pointer in commit %s",
 			     sha1_to_hex(item->object.sha1));
 	item->tree = lookup_tree(parent);
-	if (item->tree)
-		n_refs++;
 	bufptr += 46; /* "tree " + "hex sha1" + "\n" */
 	pptr = &item->parents;
 
@@ -272,10 +269,8 @@
 		if (graft)
 			continue;
 		new_parent = lookup_commit(parent);
-		if (new_parent) {
+		if (new_parent)
 			pptr = &commit_list_insert(new_parent, pptr)->next;
-			n_refs++;
-		}
 	}
 	if (graft) {
 		int i;
@@ -285,7 +280,6 @@
 			if (!new_parent)
 				continue;
 			pptr = &commit_list_insert(new_parent, pptr)->next;
-			n_refs++;
 		}
 	}
 	item->date = parse_commit_date(bufptr, tail);
@@ -434,8 +428,7 @@
 	/* Mark them and clear the indegree */
 	for (next = orig; next; next = next->next) {
 		struct commit *commit = next->item;
-		commit->object.flags |= TOPOSORT;
-		commit->indegree = 0;
+		commit->indegree = 1;
 	}
 
 	/* update the indegree */
@@ -444,7 +437,7 @@
 		while (parents) {
 			struct commit *parent = parents->item;
 
-			if (parent->object.flags & TOPOSORT)
+			if (parent->indegree)
 				parent->indegree++;
 			parents = parents->next;
 		}
@@ -462,7 +455,7 @@
 	for (next = orig; next; next = next->next) {
 		struct commit *commit = next->item;
 
-		if (!commit->indegree)
+		if (commit->indegree == 1)
 			insert = &commit_list_insert(commit, insert)->next;
 	}
 
@@ -484,7 +477,7 @@
 		for (parents = commit->parents; parents ; parents = parents->next) {
 			struct commit *parent=parents->item;
 
-			if (!(parent->object.flags & TOPOSORT))
+			if (!parent->indegree)
 				continue;
 
 			/*
@@ -492,7 +485,7 @@
 			 * when all their children have been emitted thereby
 			 * guaranteeing topological order.
 			 */
-			if (!--parent->indegree) {
+			if (--parent->indegree == 1) {
 				if (!lifo)
 					insert_by_date(parent, &work);
 				else
@@ -503,7 +496,7 @@
 		 * work_item is a commit all of whose children
 		 * have already been emitted. we can emit it now.
 		 */
-		commit->object.flags &= ~TOPOSORT;
+		commit->indegree = 0;
 		*pptr = work_item;
 		pptr = &work_item->next;
 	}
diff --git a/commit.h b/commit.h
index 2f63bc8..2d94d41 100644
--- a/commit.h
+++ b/commit.h
@@ -63,7 +63,8 @@
 };
 
 extern int non_ascii(int);
-extern enum cmit_fmt get_commit_format(const char *arg);
+struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
+extern void get_commit_format(const char *arg, struct rev_info *);
 extern void format_commit_message(const struct commit *commit,
                                   const void *format, struct strbuf *sb);
 extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit*,
diff --git a/compat/fopen.c b/compat/fopen.c
index ccb9e89..b5ca142 100644
--- a/compat/fopen.c
+++ b/compat/fopen.c
@@ -1,5 +1,16 @@
+/*
+ *  The order of the following two lines is important.
+ *
+ *  FREAD_READS_DIRECTORIES is undefined before including git-compat-util.h
+ *  to avoid the redefinition of fopen within git-compat-util.h. This is
+ *  necessary since fopen is a macro on some platforms which may be set
+ *  based on compiler options. For example, on AIX fopen is set to fopen64
+ *  when _LARGE_FILES is defined. The previous technique of merely undefining
+ *  fopen after including git-compat-util.h is inadequate in this case.
+ */
+#undef FREAD_READS_DIRECTORIES
 #include "../git-compat-util.h"
-#undef fopen
+
 FILE *git_fopen(const char *path, const char *mode)
 {
 	FILE *fp;
diff --git a/config.c b/config.c
index 0624494..b2d5b4e 100644
--- a/config.c
+++ b/config.c
@@ -111,7 +111,7 @@
 	return isalnum(c) || c == '-';
 }
 
-static int get_value(config_fn_t fn, char *name, unsigned int len)
+static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
 {
 	int c;
 	char *value;
@@ -139,7 +139,7 @@
 		if (!value)
 			return -1;
 	}
-	return fn(name, value);
+	return fn(name, value, data);
 }
 
 static int get_extended_base_var(char *name, int baselen, int c)
@@ -197,7 +197,7 @@
 	}
 }
 
-static int git_parse_file(config_fn_t fn)
+static int git_parse_file(config_fn_t fn, void *data)
 {
 	int comment = 0;
 	int baselen = 0;
@@ -228,7 +228,7 @@
 		if (!isalpha(c))
 			break;
 		var[baselen] = tolower(c);
-		if (get_value(fn, var, baselen+1) < 0)
+		if (get_value(fn, data, var, baselen+1) < 0)
 			break;
 	}
 	die("bad config file line %d in %s", config_linenr, config_file_name);
@@ -303,8 +303,9 @@
 	return ret;
 }
 
-int git_config_bool(const char *name, const char *value)
+int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
 {
+	*is_bool = 1;
 	if (!value)
 		return 1;
 	if (!*value)
@@ -313,7 +314,14 @@
 		return 1;
 	if (!strcasecmp(value, "false") || !strcasecmp(value, "no"))
 		return 0;
-	return git_config_int(name, value) != 0;
+	*is_bool = 0;
+	return git_config_int(name, value);
+}
+
+int git_config_bool(const char *name, const char *value)
+{
+	int discard;
+	return !!git_config_bool_or_int(name, value, &discard);
 }
 
 int git_config_string(const char **dest, const char *var, const char *value)
@@ -324,7 +332,7 @@
 	return 0;
 }
 
-int git_default_config(const char *var, const char *value)
+static int git_default_core_config(const char *var, const char *value)
 {
 	/* This needs a better name */
 	if (!strcmp(var, "core.filemode")) {
@@ -342,6 +350,11 @@
 		return 0;
 	}
 
+	if (!strcmp(var, "core.ignorecase")) {
+		ignore_case = git_config_bool(var, value);
+		return 0;
+	}
+
 	if (!strcmp(var, "core.bare")) {
 		is_bare_repository_cfg = git_config_bool(var, value);
 		return 0;
@@ -431,31 +444,6 @@
 		return 0;
 	}
 
-	if (!strcmp(var, "user.name")) {
-		if (!value)
-			return config_error_nonbool(var);
-		strlcpy(git_default_name, value, sizeof(git_default_name));
-		return 0;
-	}
-
-	if (!strcmp(var, "user.email")) {
-		if (!value)
-			return config_error_nonbool(var);
-		strlcpy(git_default_email, value, sizeof(git_default_email));
-		return 0;
-	}
-
-	if (!strcmp(var, "i18n.commitencoding"))
-		return git_config_string(&git_commit_encoding, var, value);
-
-	if (!strcmp(var, "i18n.logoutputencoding"))
-		return git_config_string(&git_log_output_encoding, var, value);
-
-	if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
-		pager_use_color = git_config_bool(var,value);
-		return 0;
-	}
-
 	if (!strcmp(var, "core.pager"))
 		return git_config_string(&pager_program, var, value);
 
@@ -471,6 +459,54 @@
 		whitespace_rule_cfg = parse_whitespace_rule(value);
 		return 0;
 	}
+
+	if (!strcmp(var, "core.fsyncobjectfiles")) {
+		fsync_object_files = git_config_bool(var, value);
+		return 0;
+	}
+
+	/* Add other config variables here and to Documentation/config.txt. */
+	return 0;
+}
+
+static int git_default_user_config(const char *var, const char *value)
+{
+	if (!strcmp(var, "user.name")) {
+		if (!value)
+			return config_error_nonbool(var);
+		strlcpy(git_default_name, value, sizeof(git_default_name));
+		if (git_default_email[0])
+			user_ident_explicitly_given = 1;
+		return 0;
+	}
+
+	if (!strcmp(var, "user.email")) {
+		if (!value)
+			return config_error_nonbool(var);
+		strlcpy(git_default_email, value, sizeof(git_default_email));
+		if (git_default_name[0])
+			user_ident_explicitly_given = 1;
+		return 0;
+	}
+
+	/* Add other config variables here and to Documentation/config.txt. */
+	return 0;
+}
+
+static int git_default_i18n_config(const char *var, const char *value)
+{
+	if (!strcmp(var, "i18n.commitencoding"))
+		return git_config_string(&git_commit_encoding, var, value);
+
+	if (!strcmp(var, "i18n.logoutputencoding"))
+		return git_config_string(&git_log_output_encoding, var, value);
+
+	/* Add other config variables here and to Documentation/config.txt. */
+	return 0;
+}
+
+static int git_default_branch_config(const char *var, const char *value)
+{
 	if (!strcmp(var, "branch.autosetupmerge")) {
 		if (value && !strcasecmp(value, "always")) {
 			git_branch_track = BRANCH_TRACK_ALWAYS;
@@ -479,12 +515,50 @@
 		git_branch_track = git_config_bool(var, value);
 		return 0;
 	}
+	if (!strcmp(var, "branch.autosetuprebase")) {
+		if (!value)
+			return config_error_nonbool(var);
+		else if (!strcmp(value, "never"))
+			autorebase = AUTOREBASE_NEVER;
+		else if (!strcmp(value, "local"))
+			autorebase = AUTOREBASE_LOCAL;
+		else if (!strcmp(value, "remote"))
+			autorebase = AUTOREBASE_REMOTE;
+		else if (!strcmp(value, "always"))
+			autorebase = AUTOREBASE_ALWAYS;
+		else
+			return error("Malformed value for %s", var);
+		return 0;
+	}
 
 	/* Add other config variables here and to Documentation/config.txt. */
 	return 0;
 }
 
-int git_config_from_file(config_fn_t fn, const char *filename)
+int git_default_config(const char *var, const char *value, void *dummy)
+{
+	if (!prefixcmp(var, "core."))
+		return git_default_core_config(var, value);
+
+	if (!prefixcmp(var, "user."))
+		return git_default_user_config(var, value);
+
+	if (!prefixcmp(var, "i18n."))
+		return git_default_i18n_config(var, value);
+
+	if (!prefixcmp(var, "branch."))
+		return git_default_branch_config(var, value);
+
+	if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
+		pager_use_color = git_config_bool(var,value);
+		return 0;
+	}
+
+	/* Add other config variables here and to Documentation/config.txt. */
+	return 0;
+}
+
+int git_config_from_file(config_fn_t fn, const char *filename, void *data)
 {
 	int ret;
 	FILE *f = fopen(filename, "r");
@@ -495,7 +569,7 @@
 		config_file_name = filename;
 		config_linenr = 1;
 		config_file_eof = 0;
-		ret = git_parse_file(fn);
+		ret = git_parse_file(fn, data);
 		fclose(f);
 		config_file_name = NULL;
 	}
@@ -533,7 +607,7 @@
 	return !git_env_bool("GIT_CONFIG_NOGLOBAL", 0);
 }
 
-int git_config(config_fn_t fn)
+int git_config(config_fn_t fn, void *data)
 {
 	int ret = 0;
 	char *repo_config = NULL;
@@ -546,7 +620,8 @@
 	filename = getenv(CONFIG_ENVIRONMENT);
 	if (!filename) {
 		if (git_config_system() && !access(git_etc_gitconfig(), R_OK))
-			ret += git_config_from_file(fn, git_etc_gitconfig());
+			ret += git_config_from_file(fn, git_etc_gitconfig(),
+				data);
 		home = getenv("HOME");
 		filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
 		if (!filename)
@@ -556,11 +631,11 @@
 	if (git_config_global() && home) {
 		char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 		if (!access(user_config, R_OK))
-			ret = git_config_from_file(fn, user_config);
+			ret = git_config_from_file(fn, user_config, data);
 		free(user_config);
 	}
 
-	ret += git_config_from_file(fn, filename);
+	ret += git_config_from_file(fn, filename, data);
 	free(repo_config);
 	return ret;
 }
@@ -590,7 +665,7 @@
 		  !regexec(store.value_regex, value, 0, NULL, 0)));
 }
 
-static int store_aux(const char* key, const char* value)
+static int store_aux(const char* key, const char* value, void *cb)
 {
 	const char *ep;
 	size_t section_len;
@@ -599,11 +674,9 @@
 	case KEY_SEEN:
 		if (matches(key, value)) {
 			if (store.seen == 1 && store.multi_replace == 0) {
-				fprintf(stderr,
-					"Warning: %s has multiple values\n",
-					key);
+				warning("%s has multiple values", key);
 			} else if (store.seen >= MAX_MATCHES) {
-				fprintf(stderr, "Too many matches\n");
+				error("too many matches for %s", key);
 				return 1;
 			}
 
@@ -653,9 +726,9 @@
 	return 0;
 }
 
-static int write_error(void)
+static int write_error(const char *filename)
 {
-	fprintf(stderr, "Failed to write new configuration file\n");
+	error("failed to write new configuration file %s", filename);
 
 	/* Same error code as "failed to rename". */
 	return 4;
@@ -672,7 +745,7 @@
 	if (dot) {
 		strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
 		for (i = dot - key + 1; i < store.baselen; i++) {
-			if (key[i] == '"')
+			if (key[i] == '"' || key[i] == '\\')
 				strbuf_addch(&sb, '\\');
 			strbuf_addch(&sb, key[i]);
 		}
@@ -814,7 +887,7 @@
 	 */
 
 	if (last_dot == NULL) {
-		fprintf(stderr, "key does not contain a section: %s\n", key);
+		error("key does not contain a section: %s", key);
 		ret = 2;
 		goto out_free;
 	}
@@ -834,14 +907,14 @@
 		/* Leave the extended basename untouched.. */
 		if (!dot || i > store.baselen) {
 			if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
-				fprintf(stderr, "invalid key: %s\n", key);
+				error("invalid key: %s", key);
 				free(store.key);
 				ret = 1;
 				goto out_free;
 			}
 			c = tolower(c);
 		} else if (c == '\n') {
-			fprintf(stderr, "invalid key (newline): %s\n", key);
+			error("invalid key (newline): %s", key);
 			free(store.key);
 			ret = 1;
 			goto out_free;
@@ -857,7 +930,7 @@
 	lock = xcalloc(sizeof(struct lock_file), 1);
 	fd = hold_lock_file_for_update(lock, config_filename, 0);
 	if (fd < 0) {
-		fprintf(stderr, "could not lock config file\n");
+		error("could not lock config file %s", config_filename);
 		free(store.key);
 		ret = -1;
 		goto out_free;
@@ -904,8 +977,7 @@
 			store.value_regex = (regex_t*)xmalloc(sizeof(regex_t));
 			if (regcomp(store.value_regex, value_regex,
 					REG_EXTENDED)) {
-				fprintf(stderr, "Invalid pattern: %s\n",
-					value_regex);
+				error("invalid pattern: %s", value_regex);
 				free(store.value_regex);
 				ret = 6;
 				goto out_free;
@@ -922,8 +994,8 @@
 		 * As a side effect, we make sure to transform only a valid
 		 * existing config file.
 		 */
-		if (git_config_from_file(store_aux, config_filename)) {
-			fprintf(stderr, "invalid config file\n");
+		if (git_config_from_file(store_aux, config_filename, NULL)) {
+			error("invalid config file %s", config_filename);
 			free(store.key);
 			if (store.value_regex != NULL) {
 				regfree(store.value_regex);
@@ -1002,7 +1074,7 @@
 	}
 
 	if (commit_lock_file(lock) < 0) {
-		fprintf(stderr, "Cannot commit config file!\n");
+		error("could not commit config file %s", config_filename);
 		ret = 4;
 		goto out_free;
 	}
@@ -1023,7 +1095,7 @@
 	return ret;
 
 write_err_out:
-	ret = write_error();
+	ret = write_error(lock->filename);
 	goto out_free;
 
 }
@@ -1073,7 +1145,7 @@
 	config_filename = xstrdup(config_filename);
 	out_fd = hold_lock_file_for_update(lock, config_filename, 0);
 	if (out_fd < 0) {
-		ret = error("Could not lock config file!");
+		ret = error("could not lock config file %s", config_filename);
 		goto out;
 	}
 
@@ -1097,7 +1169,7 @@
 				}
 				store.baselen = strlen(new_name);
 				if (!store_write_section(out_fd, new_name)) {
-					ret = write_error();
+					ret = write_error(lock->filename);
 					goto out;
 				}
 				continue;
@@ -1108,14 +1180,14 @@
 			continue;
 		length = strlen(buf);
 		if (write_in_full(out_fd, buf, length) != length) {
-			ret = write_error();
+			ret = write_error(lock->filename);
 			goto out;
 		}
 	}
 	fclose(config_file);
  unlock_and_out:
 	if (commit_lock_file(lock) < 0)
-			ret = error("Cannot commit config file!");
+		ret = error("could not commit config file %s", config_filename);
  out:
 	free(config_filename);
 	return ret;
diff --git a/configure.ac b/configure.ac
index 82584e9..7c2856e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -158,7 +158,7 @@
 AC_SUBST(NEEDS_SSL_WITH_CRYPTO)
 AC_SUBST(NO_OPENSSL)
 #
-# Define NO_CURL if you do not have curl installed.  git-http-pull and
+# Define NO_CURL if you do not have libcurl installed.  git-http-pull and
 # git-http-push are not built, and you cannot use http:// and https://
 # transports.
 AC_CHECK_LIB([curl], [curl_global_init],
diff --git a/connect.c b/connect.c
index d12b105..e92af29 100644
--- a/connect.c
+++ b/connect.c
@@ -360,7 +360,8 @@
 static const char *rhost_name;
 static int rhost_len;
 
-static int git_proxy_command_options(const char *var, const char *value)
+static int git_proxy_command_options(const char *var, const char *value,
+		void *cb)
 {
 	if (!strcmp(var, "core.gitproxy")) {
 		const char *for_pos;
@@ -404,7 +405,7 @@
 		return 0;
 	}
 
-	return git_default_config(var, value);
+	return git_default_config(var, value, cb);
 }
 
 static int git_use_proxy(const char *host)
@@ -412,7 +413,7 @@
 	rhost_name = host;
 	rhost_len = strlen(host);
 	git_proxy_command = getenv("GIT_PROXY_COMMAND");
-	git_config(git_proxy_command_options);
+	git_config(git_proxy_command_options, NULL);
 	rhost_name = NULL;
 	return (git_proxy_command && *git_proxy_command);
 }
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 6949cac..72f02f2 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -45,6 +45,11 @@
 #       git@vger.kernel.org
 #
 
+case "$COMP_WORDBREAKS" in
+*:*) : great ;;
+*)   COMP_WORDBREAKS="$COMP_WORDBREAKS:"
+esac
+
 __gitdir ()
 {
 	if [ -z "$1" ]; then
@@ -114,9 +119,20 @@
 	fi
 }
 
+__gitcomp_1 ()
+{
+	local c IFS=' '$'\t'$'\n'
+	for c in $1; do
+		case "$c$2" in
+		--*=*) printf %s$'\n' "$c$2" ;;
+		*.)    printf %s$'\n' "$c$2" ;;
+		*)     printf %s$'\n' "$c$2 " ;;
+		esac
+	done
+}
+
 __gitcomp ()
 {
-	local all c s=$'\n' IFS=' '$'\t'$'\n'
 	local cur="${COMP_WORDS[COMP_CWORD]}"
 	if [ $# -gt 2 ]; then
 		cur="$3"
@@ -124,21 +140,14 @@
 	case "$cur" in
 	--*=)
 		COMPREPLY=()
-		return
 		;;
 	*)
-		for c in $1; do
-			case "$c$4" in
-			--*=*) all="$all$c$4$s" ;;
-			*.)    all="$all$c$4$s" ;;
-			*)     all="$all$c$4 $s" ;;
-			esac
-		done
+		local IFS=$'\n'
+		COMPREPLY=($(compgen -P "$2" \
+			-W "$(__gitcomp_1 "$1" "$4")" \
+			-- "$cur"))
 		;;
 	esac
-	IFS=$s
-	COMPREPLY=($(compgen -P "$2" -W "$all" -- "$cur"))
-	return
 }
 
 __git_heads ()
@@ -152,7 +161,7 @@
 		done
 		return
 	fi
-	for i in $(git-ls-remote "$1" 2>/dev/null); do
+	for i in $(git ls-remote "$1" 2>/dev/null); do
 		case "$is_hash,$i" in
 		y,*) is_hash=n ;;
 		n,*^{}) is_hash=y ;;
@@ -173,7 +182,7 @@
 		done
 		return
 	fi
-	for i in $(git-ls-remote "$1" 2>/dev/null); do
+	for i in $(git ls-remote "$1" 2>/dev/null); do
 		case "$is_hash,$i" in
 		y,*) is_hash=n ;;
 		n,*^{}) is_hash=y ;;
@@ -200,7 +209,7 @@
 		done
 		return
 	fi
-	for i in $(git-ls-remote "$dir" 2>/dev/null); do
+	for i in $(git ls-remote "$dir" 2>/dev/null); do
 		case "$is_hash,$i" in
 		y,*) is_hash=n ;;
 		n,*^{}) is_hash=y ;;
@@ -223,7 +232,7 @@
 __git_refs_remotes ()
 {
 	local cmd i is_hash=y
-	for i in $(git-ls-remote "$1" 2>/dev/null); do
+	for i in $(git ls-remote "$1" 2>/dev/null); do
 		case "$is_hash,$i" in
 		n,refs/heads/*)
 			is_hash=y
@@ -290,9 +299,23 @@
 			ls="$ref"
 			;;
 	    esac
+
+		case "$COMP_WORDBREAKS" in
+		*:*) : great ;;
+		*)   pfx="$ref:$pfx" ;;
+		esac
+
+		local IFS=$'\n'
 		COMPREPLY=($(compgen -P "$pfx" \
 			-W "$(git --git-dir="$(__gitdir)" ls-tree "$ls" \
-				| sed '/^100... blob /s,^.*	,,
+				| sed '/^100... blob /{
+				           s,^.*	,,
+				           s,$, ,
+				       }
+				       /^120000 blob /{
+				           s,^.*	,,
+				           s,$, ,
+				       }
 				       /^040000 tree /{
 				           s,^.*	,,
 				           s,$,/,
@@ -320,9 +343,6 @@
 		cur="${cur#*..}"
 		__gitcomp "$(__git_refs)" "$pfx" "$cur"
 		;;
-	*.)
-		__gitcomp "$cur."
-		;;
 	*)
 		__gitcomp "$(__git_refs)"
 		;;
@@ -451,6 +471,18 @@
 	done
 }
 
+__git_has_doubledash ()
+{
+	local c=1
+	while [ $c -lt $COMP_CWORD ]; do
+		if [ "--" = "${COMP_WORDS[c]}" ]; then
+			return 0
+		fi
+		c=$((++c))
+	done
+	return 1
+}
+
 __git_whitespacelist="nowarn warn error error-all strip"
 
 _git_am ()
@@ -497,10 +529,15 @@
 
 _git_add ()
 {
+	__git_has_doubledash && return
+
 	local cur="${COMP_WORDS[COMP_CWORD]}"
 	case "$cur" in
 	--*)
-		__gitcomp "--interactive --refresh"
+		__gitcomp "
+			--interactive --refresh --patch --update --dry-run
+			--ignore-errors
+			"
 		return
 	esac
 	COMPREPLY=()
@@ -508,6 +545,8 @@
 
 _git_bisect ()
 {
+	__git_has_doubledash && return
+
 	local subcommands="start bad good reset visualize replay log"
 	local subcommand="$(__git_find_subcommand "$subcommands")"
 	if [ -z "$subcommand" ]; then
@@ -610,6 +649,8 @@
 
 _git_commit ()
 {
+	__git_has_doubledash && return
+
 	local cur="${COMP_WORDS[COMP_CWORD]}"
 	case "$cur" in
 	--*)
@@ -629,6 +670,8 @@
 
 _git_diff ()
 {
+	__git_has_doubledash && return
+
 	local cur="${COMP_WORDS[COMP_CWORD]}"
 	case "$cur" in
 	--*)
@@ -668,7 +711,12 @@
 	*)
 		case "$cur" in
 		*:*)
-			__gitcomp "$(__git_refs)" "" "${cur#*:}"
+			local pfx=""
+			case "$COMP_WORDBREAKS" in
+			*:*) : great ;;
+			*)   pfx="${cur%%:*}:" ;;
+			esac
+			__gitcomp "$(__git_refs)" "$pfx" "${cur#*:}"
 			;;
 		*)
 			local remote
@@ -731,6 +779,8 @@
 
 _git_log ()
 {
+	__git_has_doubledash && return
+
 	local cur="${COMP_WORDS[COMP_CWORD]}"
 	case "$cur" in
 	--pretty=*)
@@ -758,6 +808,7 @@
 			--pretty= --name-status --name-only --raw
 			--not --all
 			--left-right --cherry-pick
+			--graph
 			"
 		return
 		;;
@@ -780,7 +831,7 @@
 		;;
 	--*)
 		__gitcomp "
-			--no-commit --no-summary --squash --strategy
+			--no-commit --no-stat --log --no-log --squash --strategy
 			"
 		return
 	esac
@@ -838,7 +889,14 @@
 			git-push)  remote="${COMP_WORDS[1]}" ;;
 			git)       remote="${COMP_WORDS[2]}" ;;
 			esac
-			__gitcomp "$(__git_refs "$remote")" "" "${cur#*:}"
+
+			local pfx=""
+			case "$COMP_WORDBREAKS" in
+			*:*) : great ;;
+			*)   pfx="${cur%%:*}:" ;;
+			esac
+
+			__gitcomp "$(__git_refs "$remote")" "$pfx" "${cur#*:}"
 			;;
 		+*)
 			__gitcomp "$(__git_refs)" + "${cur#+}"
@@ -1053,6 +1111,7 @@
 	local subcommands="add rm show prune update"
 	local subcommand="$(__git_find_subcommand "$subcommands")"
 	if [ -z "$subcommand" ]; then
+		__gitcomp "$subcommands"
 		return
 	fi
 
@@ -1080,6 +1139,8 @@
 
 _git_reset ()
 {
+	__git_has_doubledash && return
+
 	local cur="${COMP_WORDS[COMP_CWORD]}"
 	case "$cur" in
 	--*)
@@ -1092,6 +1153,8 @@
 
 _git_shortlog ()
 {
+	__git_has_doubledash && return
+
 	local cur="${COMP_WORDS[COMP_CWORD]}"
 	case "$cur" in
 	--*)
@@ -1138,6 +1201,8 @@
 
 _git_submodule ()
 {
+	__git_has_doubledash && return
+
 	local subcommands="add status init update"
 	if [ -z "$(__git_find_subcommand "$subcommands")" ]; then
 		local cur="${COMP_WORDS[COMP_CWORD]}"
@@ -1344,10 +1409,17 @@
 
 _gitk ()
 {
+	__git_has_doubledash && return
+
 	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local g="$(git rev-parse --git-dir 2>/dev/null)"
+	local merge=""
+	if [ -f $g/MERGE_HEAD ]; then
+		merge="--merge"
+	fi
 	case "$cur" in
 	--*)
-		__gitcomp "--not --all"
+		__gitcomp "--not --all $merge"
 		return
 		;;
 	esac
diff --git a/git-clone.sh b/contrib/examples/git-clone.sh
similarity index 97%
rename from git-clone.sh
rename to contrib/examples/git-clone.sh
index 8c7fc7f..547228e 100755
--- a/git-clone.sh
+++ b/contrib/examples/git-clone.sh
@@ -240,7 +240,6 @@
 D=
 W=
 cleanup() {
-	err=$?
 	test -z "$D" && rm -rf "$dir"
 	test -z "$W" && test -n "$GIT_WORK_TREE" && rm -rf "$GIT_WORK_TREE"
 	cd ..
@@ -248,7 +247,7 @@
 	test -n "$W" && rm -rf "$W"
 	exit $err
 }
-trap cleanup 0
+trap 'err=$?; cleanup' 0
 mkdir -p "$dir" && D=$(cd "$dir" && pwd) || usage
 test -n "$GIT_WORK_TREE" && mkdir -p "$GIT_WORK_TREE" &&
 W=$(cd "$GIT_WORK_TREE" && pwd) && GIT_WORK_TREE="$W" && export GIT_WORK_TREE
@@ -334,7 +333,10 @@
 			fi
 		fi &&
 		cd "$repo" &&
-		find objects -depth -print | cpio $cpio_quiet_flag -pumd$l "$GIT_DIR/" || \
+		# Create dirs using umask and permissions and destination
+		find objects -type d -print | (cd "$GIT_DIR" && xargs mkdir -p) &&
+		# Copy existing 0444 permissions on content
+		find objects ! -type d -print | cpio $cpio_quiet_flag -pumd$l "$GIT_DIR/" || \
 			exit 1
 	fi
 	git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1
diff --git a/contrib/hg-to-git/hg-to-git.py b/contrib/hg-to-git/hg-to-git.py
index d72ffbb..f68ef72 100755
--- a/contrib/hg-to-git/hg-to-git.py
+++ b/contrib/hg-to-git/hg-to-git.py
@@ -46,6 +46,7 @@
                          for incrementals
     -n, --nrepack=INT:   number of changesets that will trigger
                          a repack (default=0, -1 to deactivate)
+    -v, --verbose:       be verbose
 
 required:
     hgprj:  name of the HG project to import (directory)
@@ -75,15 +76,18 @@
 
 state = ''
 opt_nrepack = 0
+verbose = False
 
 try:
-    opts, args = getopt.getopt(sys.argv[1:], 's:t:n:', ['gitstate=', 'tempdir=', 'nrepack='])
+    opts, args = getopt.getopt(sys.argv[1:], 's:t:n:v', ['gitstate=', 'tempdir=', 'nrepack=', 'verbose'])
     for o, a in opts:
         if o in ('-s', '--gitstate'):
             state = a
             state = os.path.abspath(state)
         if o in ('-n', '--nrepack'):
             opt_nrepack = int(a)
+        if o in ('-v', '--verbose'):
+            verbose = True
     if len(args) != 1:
         raise('params')
 except:
@@ -95,17 +99,20 @@
 
 if state:
     if os.path.exists(state):
-        print 'State does exist, reading'
+        if verbose:
+            print 'State does exist, reading'
         f = open(state, 'r')
         hgvers = pickle.load(f)
     else:
         print 'State does not exist, first run'
 
 tip = os.popen('hg tip --template "{rev}"').read()
-print 'tip is', tip
+if verbose:
+    print 'tip is', tip
 
 # Calculate the branches
-print 'analysing the branches...'
+if verbose:
+    print 'analysing the branches...'
 hgchildren["0"] = ()
 hgparents["0"] = (None, None)
 hgbranch["0"] = "master"
@@ -232,7 +239,8 @@
 
 # write the state for incrementals
 if state:
-    print 'Writing state'
+    if verbose:
+        print 'Writing state'
     f = open(state, 'w')
     pickle.dump(hgvers, f)
 
diff --git a/contrib/hooks/pre-auto-gc-battery b/contrib/hooks/pre-auto-gc-battery
new file mode 100644
index 0000000..0096f57
--- /dev/null
+++ b/contrib/hooks/pre-auto-gc-battery
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# An example hook script to verify if you are on battery, in case you
+# are running Linux. Called by git-gc --auto with no arguments. The hook
+# should exit with non-zero status after issuing an appropriate message
+# if it wants to stop the auto repacking.
+#
+# This hook is stored in the contrib/hooks directory. Your distribution
+# may have put this somewhere else. If you want to use this hook, you
+# should make this script executable then link to it in the repository
+# you would like to use it in.
+#
+# For example, if the hook is stored in
+# /usr/share/git-core/contrib/hooks/pre-auto-gc-battery:
+#
+# chmod a+x pre-auto-gc-battery
+# cd /path/to/your/repository.git
+# ln -sf /usr/share/git-core/contrib/hooks/pre-auto-gc-battery \
+#	hooks/pre-auto-gc
+
+if test -x /sbin/on_ac_power && /sbin/on_ac_power
+then
+	exit 0
+elif test "$(cat /sys/class/power_supply/AC/online 2>/dev/null)" = 1
+then
+	exit 0
+elif grep -q 'on-line' /proc/acpi/ac_adapter/AC/state 2>/dev/null
+then
+	exit 0
+elif grep -q '0x01$' /proc/apm 2>/dev/null
+then
+	exit 0
+fi
+
+echo "Auto packing deferred; not on AC"
+exit 1
diff --git a/contrib/hooks/update-paranoid b/contrib/hooks/update-paranoid
index 068fa37..d18b317 100644
--- a/contrib/hooks/update-paranoid
+++ b/contrib/hooks/update-paranoid
@@ -136,6 +136,7 @@
 	local $ENV{GIT_DIR} = shift;
 	my $br = shift;
 	my $fn = shift;
+	return unless git_value('rev-list','--max-count=1',$br,'--',$fn);
 	info "Loading $br:$fn";
 	open(I,'-|','git','cat-file','blob',"$br:$fn");
 	my $section = '';
@@ -225,14 +226,12 @@
 		local $/ = "\0";
 		my %this_diff;
 		if ($base =~ /^0{40}$/) {
-			open(T,'-|','git','ls-tree',
-				'-r','--name-only','-z',
-				$new) or return undef;
-			while (<T>) {
-				chop;
-				$this_diff{$_} = 'A';
-			}
-			close T or return undef;
+			# Don't load the diff at all; we are making the
+			# branch and have no base to compare to in this
+			# case.  A file level ACL makes no sense in this
+			# context.  Having an empty diff will allow the
+			# branch creation.
+			#
 		} else {
 			open(T,'-|','git','diff-tree',
 				'-r','--name-status','-z',
@@ -260,6 +259,7 @@
 deny "Bad old value $old" unless $old =~ /^[a-z0-9]{40}$/;
 deny "Bad new value $new" unless $new =~ /^[a-z0-9]{40}$/;
 deny "Cannot determine who you are." unless $this_user;
+grant "No change requested." if $old eq $new;
 
 $repository_name = File::Spec->rel2abs($git_dir);
 $repository_name =~ m,/([^/]+)(?:\.git|/\.git)$,;
diff --git a/convert.c b/convert.c
index d8c94cb..352b69d 100644
--- a/convert.c
+++ b/convert.c
@@ -319,11 +319,11 @@
 static struct convert_driver {
 	const char *name;
 	struct convert_driver *next;
-	char *smudge;
-	char *clean;
+	const char *smudge;
+	const char *clean;
 } *user_convert, **user_convert_tail;
 
-static int read_convert_config(const char *var, const char *value)
+static int read_convert_config(const char *var, const char *value, void *cb)
 {
 	const char *ep, *name;
 	int namelen;
@@ -358,19 +358,12 @@
 	 * The command-line will not be interpolated in any way.
 	 */
 
-	if (!strcmp("smudge", ep)) {
-		if (!value)
-			return config_error_nonbool(var);
-		drv->smudge = strdup(value);
-		return 0;
-	}
+	if (!strcmp("smudge", ep))
+		return git_config_string(&drv->smudge, var, value);
 
-	if (!strcmp("clean", ep)) {
-		if (!value)
-			return config_error_nonbool(var);
-		drv->clean = strdup(value);
-		return 0;
-	}
+	if (!strcmp("clean", ep))
+		return git_config_string(&drv->clean, var, value);
+
 	return 0;
 }
 
@@ -385,7 +378,7 @@
 		attr_ident = git_attr("ident", 5);
 		attr_filter = git_attr("filter", 6);
 		user_convert_tail = &user_convert;
-		git_config(read_convert_config);
+		git_config(read_convert_config, NULL);
 	}
 	check[0].attr = attr_crlf;
 	check[1].attr = attr_ident;
@@ -576,7 +569,7 @@
 	struct git_attr_check check[3];
 	int crlf = CRLF_GUESS;
 	int ident = 0, ret = 0;
-	char *filter = NULL;
+	const char *filter = NULL;
 
 	setup_convert_check(check);
 	if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
@@ -606,7 +599,7 @@
 	struct git_attr_check check[3];
 	int crlf = CRLF_GUESS;
 	int ident = 0, ret = 0;
-	char *filter = NULL;
+	const char *filter = NULL;
 
 	setup_convert_check(check);
 	if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
diff --git a/csum-file.c b/csum-file.c
index 9728a99..ace64f1 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -32,21 +32,24 @@
 	}
 }
 
-int sha1close(struct sha1file *f, unsigned char *result, int final)
+int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags)
 {
 	int fd;
 	unsigned offset = f->offset;
+
 	if (offset) {
 		SHA1_Update(&f->ctx, f->buffer, offset);
 		sha1flush(f, offset);
 		f->offset = 0;
 	}
-	if (final) {
+	if (flags & (CSUM_CLOSE | CSUM_FSYNC)) {
 		/* write checksum and close fd */
 		SHA1_Final(f->buffer, &f->ctx);
 		if (result)
 			hashcpy(result, f->buffer);
 		sha1flush(f, 20);
+		if (flags & CSUM_FSYNC)
+			fsync_or_die(f->fd, f->name);
 		if (close(f->fd))
 			die("%s: sha1 file error on close (%s)",
 			    f->name, strerror(errno));
diff --git a/csum-file.h b/csum-file.h
index 1af7656..72c9487 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -16,9 +16,13 @@
 	unsigned char buffer[8192];
 };
 
+/* sha1close flags */
+#define CSUM_CLOSE	1
+#define CSUM_FSYNC	2
+
 extern struct sha1file *sha1fd(int fd, const char *name);
 extern struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp);
-extern int sha1close(struct sha1file *, unsigned char *, int);
+extern int sha1close(struct sha1file *, unsigned char *, unsigned int);
 extern int sha1write(struct sha1file *, void *, unsigned int);
 extern void crc32_begin(struct sha1file *);
 extern uint32_t crc32_end(struct sha1file *);
diff --git a/daemon.c b/daemon.c
index 2b4a6f1..ce3a6f5 100644
--- a/daemon.c
+++ b/daemon.c
@@ -306,7 +306,7 @@
 static struct daemon_service *service_looking_at;
 static int service_enabled;
 
-static int git_daemon_config(const char *var, const char *value)
+static int git_daemon_config(const char *var, const char *value, void *cb)
 {
 	if (!prefixcmp(var, "daemon.") &&
 	    !strcmp(var + 7, service_looking_at->config_name)) {
@@ -356,7 +356,7 @@
 	if (service->overridable) {
 		service_looking_at = service;
 		service_enabled = -1;
-		git_config(git_daemon_config);
+		git_config(git_daemon_config, NULL);
 		if (0 <= service_enabled)
 			enabled = service_enabled;
 	}
@@ -694,23 +694,47 @@
 	}
 }
 
+static void check_dead_children(void)
+{
+	unsigned spawned, reaped, deleted;
+
+	spawned = children_spawned;
+	reaped = children_reaped;
+	deleted = children_deleted;
+
+	while (deleted < reaped) {
+		pid_t pid = dead_child[deleted % MAX_CHILDREN];
+		const char *dead = pid < 0 ? " (with error)" : "";
+
+		if (pid < 0)
+			pid = -pid;
+
+		/* XXX: Custom logging, since we don't wanna getpid() */
+		if (verbose) {
+			if (log_syslog)
+				syslog(LOG_INFO, "[%d] Disconnected%s",
+						pid, dead);
+			else
+				fprintf(stderr, "[%d] Disconnected%s\n",
+						pid, dead);
+		}
+		remove_child(pid, deleted, spawned);
+		deleted++;
+	}
+	children_deleted = deleted;
+}
+
 static void check_max_connections(void)
 {
 	for (;;) {
 		int active;
-		unsigned spawned, reaped, deleted;
+		unsigned spawned, deleted;
+
+		check_dead_children();
 
 		spawned = children_spawned;
-		reaped = children_reaped;
 		deleted = children_deleted;
 
-		while (deleted < reaped) {
-			pid_t pid = dead_child[deleted % MAX_CHILDREN];
-			remove_child(pid, deleted, spawned);
-			deleted++;
-		}
-		children_deleted = deleted;
-
 		active = spawned - deleted;
 		if (active <= max_connections)
 			break;
@@ -760,18 +784,10 @@
 
 		if (pid > 0) {
 			unsigned reaped = children_reaped;
+			if (!WIFEXITED(status) || WEXITSTATUS(status) > 0)
+				pid = -pid;
 			dead_child[reaped % MAX_CHILDREN] = pid;
 			children_reaped = reaped + 1;
-			/* XXX: Custom logging, since we don't wanna getpid() */
-			if (verbose) {
-				const char *dead = "";
-				if (!WIFEXITED(status) || WEXITSTATUS(status) > 0)
-					dead = " (with error)";
-				if (log_syslog)
-					syslog(LOG_INFO, "[%d] Disconnected%s", pid, dead);
-				else
-					fprintf(stderr, "[%d] Disconnected%s\n", pid, dead);
-			}
 			continue;
 		}
 		break;
@@ -928,8 +944,18 @@
 
 	for (;;) {
 		int i;
+		int timeout;
 
-		if (poll(pfd, socknum, -1) < 0) {
+		/*
+		 * This 1-sec timeout could lead to idly looping but it is
+		 * here so that children culled in child_handler() are reported
+		 * without too much delay.  We could probably set up a pipe
+		 * to ourselves that we poll, and write to the fd from child_handler()
+		 * to wake us up (and consume it when the poll() returns...
+		 */
+		timeout = (children_spawned != children_deleted) ? 1000 : -1;
+		i = poll(pfd, socknum, timeout);
+		if (i < 0) {
 			if (errno != EINTR) {
 				error("poll failed, resuming: %s",
 				      strerror(errno));
@@ -937,6 +963,10 @@
 			}
 			continue;
 		}
+		if (i == 0) {
+			check_dead_children();
+			continue;
+		}
 
 		for (i = 0; i < socknum; i++) {
 			if (pfd[i].revents & POLLIN) {
diff --git a/date.c b/date.c
index a74ed86..1a4eb87 100644
--- a/date.c
+++ b/date.c
@@ -682,10 +682,8 @@
 
 static void date_never(struct tm *tm, int *num)
 {
-	tm->tm_mon = tm->tm_wday = tm->tm_yday
-		= tm->tm_hour = tm->tm_min = tm->tm_sec = 0;
-	tm->tm_year = 70;
-	tm->tm_mday = 1;
+	time_t n = 0;
+	localtime_r(&n, tm);
 }
 
 static const struct special {
diff --git a/diff-lib.c b/diff-lib.c
index 069e450..e7eaff9 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -8,7 +8,6 @@
 #include "diffcore.h"
 #include "revision.h"
 #include "cache-tree.h"
-#include "path-list.h"
 #include "unpack-trees.h"
 #include "refs.h"
 
@@ -16,340 +15,40 @@
  * diff-files
  */
 
-static int read_directory(const char *path, struct path_list *list)
-{
-	DIR *dir;
-	struct dirent *e;
-
-	if (!(dir = opendir(path)))
-		return error("Could not open directory %s", path);
-
-	while ((e = readdir(dir)))
-		if (strcmp(".", e->d_name) && strcmp("..", e->d_name))
-			path_list_insert(e->d_name, list);
-
-	closedir(dir);
-	return 0;
-}
-
-static int get_mode(const char *path, int *mode)
-{
-	struct stat st;
-
-	if (!path || !strcmp(path, "/dev/null"))
-		*mode = 0;
-	else if (!strcmp(path, "-"))
-		*mode = create_ce_mode(0666);
-	else if (stat(path, &st))
-		return error("Could not access '%s'", path);
-	else
-		*mode = st.st_mode;
-	return 0;
-}
-
-static int queue_diff(struct diff_options *o,
-		const char *name1, const char *name2)
-{
-	int mode1 = 0, mode2 = 0;
-
-	if (get_mode(name1, &mode1) || get_mode(name2, &mode2))
-		return -1;
-
-	if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2))
-		return error("file/directory conflict: %s, %s", name1, name2);
-
-	if (S_ISDIR(mode1) || S_ISDIR(mode2)) {
-		char buffer1[PATH_MAX], buffer2[PATH_MAX];
-		struct path_list p1 = {NULL, 0, 0, 1}, p2 = {NULL, 0, 0, 1};
-		int len1 = 0, len2 = 0, i1, i2, ret = 0;
-
-		if (name1 && read_directory(name1, &p1))
-			return -1;
-		if (name2 && read_directory(name2, &p2)) {
-			path_list_clear(&p1, 0);
-			return -1;
-		}
-
-		if (name1) {
-			len1 = strlen(name1);
-			if (len1 > 0 && name1[len1 - 1] == '/')
-				len1--;
-			memcpy(buffer1, name1, len1);
-			buffer1[len1++] = '/';
-		}
-
-		if (name2) {
-			len2 = strlen(name2);
-			if (len2 > 0 && name2[len2 - 1] == '/')
-				len2--;
-			memcpy(buffer2, name2, len2);
-			buffer2[len2++] = '/';
-		}
-
-		for (i1 = i2 = 0; !ret && (i1 < p1.nr || i2 < p2.nr); ) {
-			const char *n1, *n2;
-			int comp;
-
-			if (i1 == p1.nr)
-				comp = 1;
-			else if (i2 == p2.nr)
-				comp = -1;
-			else
-				comp = strcmp(p1.items[i1].path,
-					p2.items[i2].path);
-
-			if (comp > 0)
-				n1 = NULL;
-			else {
-				n1 = buffer1;
-				strncpy(buffer1 + len1, p1.items[i1++].path,
-						PATH_MAX - len1);
-			}
-
-			if (comp < 0)
-				n2 = NULL;
-			else {
-				n2 = buffer2;
-				strncpy(buffer2 + len2, p2.items[i2++].path,
-						PATH_MAX - len2);
-			}
-
-			ret = queue_diff(o, n1, n2);
-		}
-		path_list_clear(&p1, 0);
-		path_list_clear(&p2, 0);
-
-		return ret;
-	} else {
-		struct diff_filespec *d1, *d2;
-
-		if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
-			unsigned tmp;
-			const char *tmp_c;
-			tmp = mode1; mode1 = mode2; mode2 = tmp;
-			tmp_c = name1; name1 = name2; name2 = tmp_c;
-		}
-
-		if (!name1)
-			name1 = "/dev/null";
-		if (!name2)
-			name2 = "/dev/null";
-		d1 = alloc_filespec(name1);
-		d2 = alloc_filespec(name2);
-		fill_filespec(d1, null_sha1, mode1);
-		fill_filespec(d2, null_sha1, mode2);
-
-		diff_queue(&diff_queued_diff, d1, d2);
-		return 0;
-	}
-}
-
 /*
- * Does the path name a blob in the working tree, or a directory
- * in the working tree?
+ * Has the work tree entity been removed?
+ *
+ * Return 1 if it was removed from the work tree, 0 if an entity to be
+ * compared with the cache entry ce still exists (the latter includes
+ * the case where a directory that is not a submodule repository
+ * exists for ce that is a submodule -- it is a submodule that is not
+ * checked out).  Return negative for an error.
  */
-static int is_in_index(const char *path)
-{
-	int len, pos;
-	struct cache_entry *ce;
-
-	len = strlen(path);
-	while (path[len-1] == '/')
-		len--;
-	if (!len)
-		return 1; /* "." */
-	pos = cache_name_pos(path, len);
-	if (0 <= pos)
-		return 1;
-	pos = -1 - pos;
-	while (pos < active_nr) {
-		ce = active_cache[pos++];
-		if (ce_namelen(ce) <= len ||
-		    strncmp(ce->name, path, len) ||
-		    (ce->name[len] > '/'))
-			break; /* path cannot be a prefix */
-		if (ce->name[len] == '/')
-			return 1;
-	}
-	return 0;
-}
-
-static int handle_diff_files_args(struct rev_info *revs,
-				  int argc, const char **argv,
-				  unsigned int *options)
-{
-	*options = 0;
-
-	/* revs->max_count == -2 means --no-index */
-	while (1 < argc && argv[1][0] == '-') {
-		if (!strcmp(argv[1], "--base"))
-			revs->max_count = 1;
-		else if (!strcmp(argv[1], "--ours"))
-			revs->max_count = 2;
-		else if (!strcmp(argv[1], "--theirs"))
-			revs->max_count = 3;
-		else if (!strcmp(argv[1], "-n") ||
-				!strcmp(argv[1], "--no-index")) {
-			revs->max_count = -2;
-			DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
-			DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
-		}
-		else if (!strcmp(argv[1], "-q"))
-			*options |= DIFF_SILENT_ON_REMOVED;
-		else
-			return error("invalid option: %s", argv[1]);
-		argv++; argc--;
-	}
-
-	if (revs->max_count == -1 && revs->diffopt.nr_paths == 2) {
-		/*
-		 * If two files are specified, and at least one is untracked,
-		 * default to no-index.
-		 */
-		read_cache();
-		if (!is_in_index(revs->diffopt.paths[0]) ||
-					!is_in_index(revs->diffopt.paths[1])) {
-			revs->max_count = -2;
-			DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
-		}
-	}
-
-	/*
-	 * Make sure there are NO revision (i.e. pending object) parameter,
-	 * rev.max_count is reasonable (0 <= n <= 3),
-	 * there is no other revision filtering parameters.
-	 */
-	if (revs->pending.nr || revs->max_count > 3 ||
-	    revs->min_age != -1 || revs->max_age != -1)
-		return error("no revision allowed with diff-files");
-
-	if (revs->max_count == -1 &&
-	    (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
-		revs->combine_merges = revs->dense_combined_merges = 1;
-
-	return 0;
-}
-
-static int is_outside_repo(const char *path, int nongit, const char *prefix)
-{
-	int i;
-	if (nongit || !strcmp(path, "-") || is_absolute_path(path))
-		return 1;
-	if (prefixcmp(path, "../"))
-		return 0;
-	if (!prefix)
-		return 1;
-	for (i = strlen(prefix); !prefixcmp(path, "../"); ) {
-		while (i > 0 && prefix[i - 1] != '/')
-			i--;
-		if (--i < 0)
-			return 1;
-		path += 3;
-	}
-	return 0;
-}
-
-int setup_diff_no_index(struct rev_info *revs,
-		int argc, const char ** argv, int nongit, const char *prefix)
-{
-	int i;
-	for (i = 1; i < argc; i++)
-		if (argv[i][0] != '-' || argv[i][1] == '\0')
-			break;
-		else if (!strcmp(argv[i], "--")) {
-			i++;
-			break;
-		} else if (i < argc - 3 && !strcmp(argv[i], "--no-index")) {
-			i = argc - 3;
-			DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
-			break;
-		}
-	if (argc != i + 2 || (!is_outside_repo(argv[i + 1], nongit, prefix) &&
-				!is_outside_repo(argv[i], nongit, prefix)))
-		return -1;
-
-	diff_setup(&revs->diffopt);
-	for (i = 1; i < argc - 2; )
-		if (!strcmp(argv[i], "--no-index"))
-			i++;
-		else {
-			int j = diff_opt_parse(&revs->diffopt,
-					argv + i, argc - i);
-			if (!j)
-				die("invalid diff option/value: %s", argv[i]);
-			i += j;
-		}
-
-	if (prefix) {
-		int len = strlen(prefix);
-
-		revs->diffopt.paths = xcalloc(2, sizeof(char*));
-		for (i = 0; i < 2; i++) {
-			const char *p = argv[argc - 2 + i];
-			/*
-			 * stdin should be spelled as '-'; if you have
-			 * path that is '-', spell it as ./-.
-			 */
-			p = (strcmp(p, "-")
-			     ? xstrdup(prefix_filename(prefix, len, p))
-			     : p);
-			revs->diffopt.paths[i] = p;
-		}
-	}
-	else
-		revs->diffopt.paths = argv + argc - 2;
-	revs->diffopt.nr_paths = 2;
-	DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
-	revs->max_count = -2;
-	if (diff_setup_done(&revs->diffopt) < 0)
-		die("diff_setup_done failed");
-	return 0;
-}
-
-int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
-{
-	unsigned int options;
-
-	if (handle_diff_files_args(revs, argc, argv, &options))
-		return -1;
-
-	if (DIFF_OPT_TST(&revs->diffopt, NO_INDEX)) {
-		if (revs->diffopt.nr_paths != 2)
-			return error("need two files/directories with --no-index");
-		if (queue_diff(&revs->diffopt, revs->diffopt.paths[0],
-				revs->diffopt.paths[1]))
-			return -1;
-		diffcore_std(&revs->diffopt);
-		diff_flush(&revs->diffopt);
-		/*
-		 * The return code for --no-index imitates diff(1):
-		 * 0 = no changes, 1 = changes, else error
-		 */
-		return revs->diffopt.found_changes;
-	}
-
-	if (read_cache() < 0) {
-		perror("read_cache");
-		return -1;
-	}
-	return run_diff_files(revs, options);
-}
-/*
- * See if work tree has an entity that can be staged.  Return 0 if so,
- * return 1 if not and return -1 if error.
- */
-static int check_work_tree_entity(const struct cache_entry *ce, struct stat *st, char *symcache)
+static int check_removed(const struct cache_entry *ce, struct stat *st)
 {
 	if (lstat(ce->name, st) < 0) {
 		if (errno != ENOENT && errno != ENOTDIR)
 			return -1;
 		return 1;
 	}
-	if (has_symlink_leading_path(ce->name, symcache))
+	if (has_symlink_leading_path(ce_namelen(ce), ce->name))
 		return 1;
 	if (S_ISDIR(st->st_mode)) {
 		unsigned char sub[20];
-		if (resolve_gitlink_ref(ce->name, "HEAD", sub))
+
+		/*
+		 * If ce is already a gitlink, we can have a plain
+		 * directory (i.e. the submodule is not checked out),
+		 * or a checked out submodule.  Either case this is not
+		 * a case where something was removed from the work tree,
+		 * so we will return 0.
+		 *
+		 * Otherwise, if the directory is not a submodule
+		 * repository, that means ce which was a blob turned into
+		 * a directory --- the blob was removed!
+		 */
+		if (!S_ISGITLINK(ce->ce_mode) &&
+		    resolve_gitlink_ref(ce->name, "HEAD", sub))
 			return 1;
 	}
 	return 0;
@@ -399,7 +98,7 @@
 			memset(&(dpath->parent[0]), 0,
 			       sizeof(struct combine_diff_parent)*5);
 
-			changed = check_work_tree_entity(ce, &st, symcache);
+			changed = check_removed(ce, &st);
 			if (!changed)
 				dpath->mode = ce_mode_from_stat(ce, st.st_mode);
 			else {
@@ -463,7 +162,7 @@
 		if (ce_uptodate(ce))
 			continue;
 
-		changed = check_work_tree_entity(ce, &st, symcache);
+		changed = check_removed(ce, &st);
 		if (changed) {
 			if (changed < 0) {
 				perror(ce->name);
@@ -472,17 +171,20 @@
 			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);
-		if (!changed && !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
-			continue;
+		if (!changed) {
+			ce_mark_uptodate(ce);
+			if (!DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
+				continue;
+		}
 		oldmode = ce->ce_mode;
 		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);
@@ -506,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,
@@ -521,7 +223,7 @@
 	if (!cached) {
 		int changed;
 		struct stat st;
-		changed = check_work_tree_entity(ce, &st, cbdata->symcache);
+		changed = check_removed(ce, &st);
 		if (changed < 0)
 			return -1;
 		else if (changed) {
@@ -610,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-no-index.c b/diff-no-index.c
new file mode 100644
index 0000000..f6994cf
--- /dev/null
+++ b/diff-no-index.c
@@ -0,0 +1,263 @@
+/*
+ * "diff --no-index" support
+ * Copyright (c) 2007 by Johannes Schindelin
+ * Copyright (c) 2008 by Junio C Hamano
+ */
+
+#include "cache.h"
+#include "color.h"
+#include "commit.h"
+#include "blob.h"
+#include "tag.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "revision.h"
+#include "log-tree.h"
+#include "builtin.h"
+#include "path-list.h"
+
+static int read_directory(const char *path, struct path_list *list)
+{
+	DIR *dir;
+	struct dirent *e;
+
+	if (!(dir = opendir(path)))
+		return error("Could not open directory %s", path);
+
+	while ((e = readdir(dir)))
+		if (strcmp(".", e->d_name) && strcmp("..", e->d_name))
+			path_list_insert(e->d_name, list);
+
+	closedir(dir);
+	return 0;
+}
+
+static int get_mode(const char *path, int *mode)
+{
+	struct stat st;
+
+	if (!path || !strcmp(path, "/dev/null"))
+		*mode = 0;
+	else if (!strcmp(path, "-"))
+		*mode = create_ce_mode(0666);
+	else if (stat(path, &st))
+		return error("Could not access '%s'", path);
+	else
+		*mode = st.st_mode;
+	return 0;
+}
+
+static int queue_diff(struct diff_options *o,
+		const char *name1, const char *name2)
+{
+	int mode1 = 0, mode2 = 0;
+
+	if (get_mode(name1, &mode1) || get_mode(name2, &mode2))
+		return -1;
+
+	if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2))
+		return error("file/directory conflict: %s, %s", name1, name2);
+
+	if (S_ISDIR(mode1) || S_ISDIR(mode2)) {
+		char buffer1[PATH_MAX], buffer2[PATH_MAX];
+		struct path_list p1 = {NULL, 0, 0, 1}, p2 = {NULL, 0, 0, 1};
+		int len1 = 0, len2 = 0, i1, i2, ret = 0;
+
+		if (name1 && read_directory(name1, &p1))
+			return -1;
+		if (name2 && read_directory(name2, &p2)) {
+			path_list_clear(&p1, 0);
+			return -1;
+		}
+
+		if (name1) {
+			len1 = strlen(name1);
+			if (len1 > 0 && name1[len1 - 1] == '/')
+				len1--;
+			memcpy(buffer1, name1, len1);
+			buffer1[len1++] = '/';
+		}
+
+		if (name2) {
+			len2 = strlen(name2);
+			if (len2 > 0 && name2[len2 - 1] == '/')
+				len2--;
+			memcpy(buffer2, name2, len2);
+			buffer2[len2++] = '/';
+		}
+
+		for (i1 = i2 = 0; !ret && (i1 < p1.nr || i2 < p2.nr); ) {
+			const char *n1, *n2;
+			int comp;
+
+			if (i1 == p1.nr)
+				comp = 1;
+			else if (i2 == p2.nr)
+				comp = -1;
+			else
+				comp = strcmp(p1.items[i1].path,
+					p2.items[i2].path);
+
+			if (comp > 0)
+				n1 = NULL;
+			else {
+				n1 = buffer1;
+				strncpy(buffer1 + len1, p1.items[i1++].path,
+						PATH_MAX - len1);
+			}
+
+			if (comp < 0)
+				n2 = NULL;
+			else {
+				n2 = buffer2;
+				strncpy(buffer2 + len2, p2.items[i2++].path,
+						PATH_MAX - len2);
+			}
+
+			ret = queue_diff(o, n1, n2);
+		}
+		path_list_clear(&p1, 0);
+		path_list_clear(&p2, 0);
+
+		return ret;
+	} else {
+		struct diff_filespec *d1, *d2;
+
+		if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
+			unsigned tmp;
+			const char *tmp_c;
+			tmp = mode1; mode1 = mode2; mode2 = tmp;
+			tmp_c = name1; name1 = name2; name2 = tmp_c;
+		}
+
+		if (!name1)
+			name1 = "/dev/null";
+		if (!name2)
+			name2 = "/dev/null";
+		d1 = alloc_filespec(name1);
+		d2 = alloc_filespec(name2);
+		fill_filespec(d1, null_sha1, mode1);
+		fill_filespec(d2, null_sha1, mode2);
+
+		diff_queue(&diff_queued_diff, d1, d2);
+		return 0;
+	}
+}
+
+static int path_outside_repo(const char *path)
+{
+	/*
+	 * We have already done setup_git_directory_gently() so we
+	 * know we are inside a git work tree already.
+	 */
+	const char *work_tree;
+	size_t len;
+
+	if (!is_absolute_path(path))
+		return 0;
+	work_tree = get_git_work_tree();
+	len = strlen(work_tree);
+	if (strncmp(path, work_tree, len) ||
+	    (path[len] != '\0' && path[len] != '/'))
+		return 1;
+	return 0;
+}
+
+void diff_no_index(struct rev_info *revs,
+		   int argc, const char **argv,
+		   int nongit, const char *prefix)
+{
+	int i;
+	int no_index = 0;
+	unsigned options = 0;
+
+	/* Were we asked to do --no-index explicitly? */
+	for (i = 1; i < argc; i++) {
+		if (!strcmp(argv[i], "--"))
+			return;
+		if (!strcmp(argv[i], "--no-index"))
+			no_index = 1;
+		if (argv[i][0] != '-')
+			break;
+	}
+
+	if (!no_index && !nongit) {
+		/*
+		 * Inside a git repository, without --no-index.  Only
+		 * when a path outside the repository is given,
+		 * e.g. "git diff /var/tmp/[12]", or "git diff
+		 * Makefile /var/tmp/Makefile", allow it to be used as
+		 * a colourful "diff" replacement.
+		 */
+		if ((argc != i + 2) ||
+		    (!path_outside_repo(argv[i]) &&
+		     !path_outside_repo(argv[i+1])))
+			return;
+	}
+	if (argc != i + 2)
+		die("git diff %s takes two paths",
+		    no_index ? "--no-index" : "[--no-index]");
+
+	/*
+	 * If the user asked for our exit code then don't start a
+	 * pager or we would end up reporting its exit code instead.
+	 */
+	if (!DIFF_OPT_TST(&revs->diffopt, EXIT_WITH_STATUS))
+		setup_pager();
+
+	diff_setup(&revs->diffopt);
+	if (!revs->diffopt.output_format)
+		revs->diffopt.output_format = DIFF_FORMAT_PATCH;
+	for (i = 1; i < argc - 2; ) {
+		int j;
+		if (!strcmp(argv[i], "--no-index"))
+			i++;
+		else if (!strcmp(argv[1], "-q"))
+			options |= DIFF_SILENT_ON_REMOVED;
+		else {
+			j = diff_opt_parse(&revs->diffopt, argv + i, argc - i);
+			if (!j)
+				die("invalid diff option/value: %s", argv[i]);
+			i += j;
+		}
+	}
+
+	if (prefix) {
+		int len = strlen(prefix);
+
+		revs->diffopt.paths = xcalloc(2, sizeof(char*));
+		for (i = 0; i < 2; i++) {
+			const char *p = argv[argc - 2 + i];
+			/*
+			 * stdin should be spelled as '-'; if you have
+			 * path that is '-', spell it as ./-.
+			 */
+			p = (strcmp(p, "-")
+			     ? xstrdup(prefix_filename(prefix, len, p))
+			     : p);
+			revs->diffopt.paths[i] = p;
+		}
+	}
+	else
+		revs->diffopt.paths = argv + argc - 2;
+	revs->diffopt.nr_paths = 2;
+
+	DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
+	DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
+
+	revs->max_count = -2;
+	if (diff_setup_done(&revs->diffopt) < 0)
+		die("diff_setup_done failed");
+
+	if (queue_diff(&revs->diffopt, revs->diffopt.paths[0],
+		       revs->diffopt.paths[1]))
+		exit(1);
+	diffcore_std(&revs->diffopt);
+	diff_flush(&revs->diffopt);
+
+	/*
+	 * The return code for --no-index imitates diff(1):
+	 * 0 = no changes, 1 = changes, else error
+	 */
+	exit(revs->diffopt.found_changes);
+}
diff --git a/diff.c b/diff.c
index 20135cb..342733b 100644
--- a/diff.c
+++ b/diff.c
@@ -19,7 +19,7 @@
 #endif
 
 static int diff_detect_rename_default;
-static int diff_rename_limit_default = 100;
+static int diff_rename_limit_default = 200;
 int diff_use_color_default = -1;
 static const char *external_diff_cmd_cfg;
 int diff_auto_refresh_index = 1;
@@ -129,12 +129,8 @@
  * never be affected by the setting of diff.renames
  * the user happens to have in the configuration file.
  */
-int git_diff_ui_config(const char *var, const char *value)
+int git_diff_ui_config(const char *var, const char *value, void *cb)
 {
-	if (!strcmp(var, "diff.renamelimit")) {
-		diff_rename_limit_default = git_config_int(var, value);
-		return 0;
-	}
 	if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
 		diff_use_color_default = git_config_colorbool(var, value, -1);
 		return 0;
@@ -153,12 +149,8 @@
 		diff_auto_refresh_index = git_config_bool(var, value);
 		return 0;
 	}
-	if (!strcmp(var, "diff.external")) {
-		if (!value)
-			return config_error_nonbool(var);
-		external_diff_cmd_cfg = xstrdup(value);
-		return 0;
-	}
+	if (!strcmp(var, "diff.external"))
+		return git_config_string(&external_diff_cmd_cfg, var, value);
 	if (!prefixcmp(var, "diff.")) {
 		const char *ep = strrchr(var, '.');
 
@@ -166,11 +158,16 @@
 			return parse_lldiff_command(var, ep, value);
 	}
 
-	return git_diff_basic_config(var, value);
+	return git_diff_basic_config(var, value, cb);
 }
 
-int git_diff_basic_config(const char *var, const char *value)
+int git_diff_basic_config(const char *var, const char *value, void *cb)
 {
+	if (!strcmp(var, "diff.renamelimit")) {
+		diff_rename_limit_default = git_config_int(var, value);
+		return 0;
+	}
+
 	if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
 		int slot = parse_diff_color_slot(var, 11);
 		if (!value)
@@ -190,7 +187,7 @@
 		}
 	}
 
-	return git_color_default_config(var, value);
+	return git_color_default_config(var, value, cb);
 }
 
 static char *quote_two(const char *one, const char *two)
@@ -997,18 +994,23 @@
 	}
 }
 
-struct diffstat_dir {
-	struct diffstat_file **files;
-	int nr, percent, cumulative;
+struct dirstat_file {
+	const char *name;
+	unsigned long changed;
 };
 
-static long gather_dirstat(FILE *file, struct diffstat_dir *dir, unsigned long changed, const char *base, int baselen)
+struct dirstat_dir {
+	struct dirstat_file *files;
+	int alloc, nr, percent, cumulative;
+};
+
+static long gather_dirstat(FILE *file, struct dirstat_dir *dir, unsigned long changed, const char *base, int baselen)
 {
 	unsigned long this_dir = 0;
 	unsigned int sources = 0;
 
 	while (dir->nr) {
-		struct diffstat_file *f = *dir->files;
+		struct dirstat_file *f = dir->files;
 		int namelen = strlen(f->name);
 		unsigned long this;
 		char *slash;
@@ -1023,10 +1025,7 @@
 			this = gather_dirstat(file, dir, changed, f->name, newbaselen);
 			sources++;
 		} else {
-			if (f->is_unmerged || f->is_binary)
-				this = 0;
-			else
-				this = f->added + f->deleted;
+			this = f->changed;
 			dir->files++;
 			dir->nr--;
 			sources += 2;
@@ -1054,19 +1053,58 @@
 	return this_dir;
 }
 
-static void show_dirstat(struct diffstat_t *data, struct diff_options *options)
+static void show_dirstat(struct diff_options *options)
 {
 	int i;
 	unsigned long changed;
-	struct diffstat_dir dir;
+	struct dirstat_dir dir;
+	struct diff_queue_struct *q = &diff_queued_diff;
 
-	/* Calculate total changes */
+	dir.files = NULL;
+	dir.alloc = 0;
+	dir.nr = 0;
+	dir.percent = options->dirstat_percent;
+	dir.cumulative = options->output_format & DIFF_FORMAT_CUMULATIVE;
+
 	changed = 0;
-	for (i = 0; i < data->nr; i++) {
-		if (data->files[i]->is_binary || data->files[i]->is_unmerged)
+	for (i = 0; i < q->nr; i++) {
+		struct diff_filepair *p = q->queue[i];
+		const char *name;
+		unsigned long copied, added, damage;
+
+		name = p->one->path ? p->one->path : p->two->path;
+
+		if (DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) {
+			diff_populate_filespec(p->one, 0);
+			diff_populate_filespec(p->two, 0);
+			diffcore_count_changes(p->one, p->two, NULL, NULL, 0,
+					       &copied, &added);
+			diff_free_filespec_data(p->one);
+			diff_free_filespec_data(p->two);
+		} else if (DIFF_FILE_VALID(p->one)) {
+			diff_populate_filespec(p->one, 1);
+			copied = added = 0;
+			diff_free_filespec_data(p->one);
+		} else if (DIFF_FILE_VALID(p->two)) {
+			diff_populate_filespec(p->two, 1);
+			copied = 0;
+			added = p->two->size;
+			diff_free_filespec_data(p->two);
+		} else
 			continue;
-		changed += data->files[i]->added;
-		changed += data->files[i]->deleted;
+
+		/*
+		 * Original minus copied is the removed material,
+		 * added is the new material.  They are both damages
+		 * made to the preimage.
+		 */
+		damage = (p->one->size - copied) + added;
+
+		ALLOC_GROW(dir.files, dir.nr + 1, dir.alloc);
+		dir.files[dir.nr].name = name;
+		dir.files[dir.nr].changed = damage;
+		changed += damage;
+		dir.nr++;
 	}
 
 	/* This can happen even with many files, if everything was renames */
@@ -1074,10 +1112,6 @@
 		return;
 
 	/* Show all directories with more than x% of the changes */
-	dir.files = data->files;
-	dir.nr = data->nr;
-	dir.percent = options->dirstat_percent;
-	dir.cumulative = options->output_format & DIFF_FORMAT_CUMULATIVE;
 	gather_dirstat(options->file, &dir, changed, "", 0);
 }
 
@@ -1113,12 +1147,14 @@
 	char *err;
 
 	if (line[0] == '+') {
+		unsigned bad;
 		data->lineno++;
-		data->status = check_and_emit_line(line + 1, len - 1,
+		bad = check_and_emit_line(line + 1, len - 1,
 		    data->ws_rule, NULL, NULL, NULL, NULL);
-		if (!data->status)
+		if (!bad)
 			return;
-		err = whitespace_error_string(data->status);
+		data->status |= bad;
+		err = whitespace_error_string(bad);
 		fprintf(data->file, "%s:%d: %s.\n", data->filename, data->lineno, err);
 		free(err);
 		emit_line(data->file, set, reset, line, 1);
@@ -2189,7 +2225,6 @@
 	options->rename_limit = -1;
 	options->dirstat_percent = 3;
 	options->context = 3;
-	options->msg_sep = "";
 
 	options->change = diff_change;
 	options->add_remove = diff_addremove;
@@ -2466,6 +2501,8 @@
 		DIFF_OPT_SET(options, ALLOW_EXTERNAL);
 	else if (!strcmp(arg, "--no-ext-diff"))
 		DIFF_OPT_CLR(options, ALLOW_EXTERNAL);
+	else if (!strcmp(arg, "--ignore-submodules"))
+		DIFF_OPT_SET(options, IGNORE_SUBMODULES);
 
 	/* misc options */
 	else if (!strcmp(arg, "-z"))
@@ -3101,7 +3138,7 @@
 		separator++;
 	}
 
-	if (output_format & (DIFF_FORMAT_DIFFSTAT|DIFF_FORMAT_SHORTSTAT|DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIRSTAT)) {
+	if (output_format & (DIFF_FORMAT_DIFFSTAT|DIFF_FORMAT_SHORTSTAT|DIFF_FORMAT_NUMSTAT)) {
 		struct diffstat_t diffstat;
 
 		memset(&diffstat, 0, sizeof(struct diffstat_t));
@@ -3111,8 +3148,6 @@
 			if (check_pair_status(p))
 				diff_flush_stat(p, options, &diffstat);
 		}
-		if (output_format & DIFF_FORMAT_DIRSTAT)
-			show_dirstat(&diffstat, options);
 		if (output_format & DIFF_FORMAT_NUMSTAT)
 			show_numstat(&diffstat, options);
 		if (output_format & DIFF_FORMAT_DIFFSTAT)
@@ -3122,6 +3157,8 @@
 		free_diffstat_info(&diffstat);
 		separator++;
 	}
+	if (output_format & DIFF_FORMAT_DIRSTAT)
+		show_dirstat(options);
 
 	if (output_format & DIFF_FORMAT_SUMMARY && !is_summary_empty(q)) {
 		for (i = 0; i < q->nr; i++)
@@ -3320,11 +3357,13 @@
 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))
+		return;
+
 	/* This may look odd, but it is a preparation for
 	 * feeding "there are unchanged files which should
 	 * not produce diffs, but when you are doing copy
@@ -3341,9 +3380,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;
@@ -3364,19 +3400,20 @@
 		 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)
+			&& S_ISGITLINK(new_mode))
+		return;
+
 	if (DIFF_OPT_TST(options, REVERSE_DIFF)) {
 		unsigned tmp;
 		const unsigned char *tmp_c;
 		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 f2c7739..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);
@@ -63,6 +63,7 @@
 #define DIFF_OPT_REVERSE_DIFF        (1 << 15)
 #define DIFF_OPT_CHECK_FAILED        (1 << 16)
 #define DIFF_OPT_RELATIVE_NAME       (1 << 17)
+#define DIFF_OPT_IGNORE_SUBMODULES   (1 << 18)
 #define DIFF_OPT_TST(opts, flag)    ((opts)->flags & DIFF_OPT_##flag)
 #define DIFF_OPT_SET(opts, flag)    ((opts)->flags |= DIFF_OPT_##flag)
 #define DIFF_OPT_CLR(opts, flag)    ((opts)->flags &= ~DIFF_OPT_##flag)
@@ -83,12 +84,12 @@
 	int pickaxe_opts;
 	int rename_score;
 	int rename_limit;
+	int warn_on_too_large_rename;
 	int dirstat_percent;
 	int setup;
 	int abbrev;
 	const char *prefix;
 	int prefix_length;
-	const char *msg_sep;
 	const char *stat_sep;
 	long xdl_opts;
 
@@ -163,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,
@@ -181,8 +181,8 @@
 #define DIFF_SETUP_USE_CACHE		2
 #define DIFF_SETUP_USE_SIZE_CACHE	4
 
-extern int git_diff_basic_config(const char *var, const char *value);
-extern int git_diff_ui_config(const char *var, const char *value);
+extern int git_diff_basic_config(const char *var, const char *value, void *cb);
+extern int git_diff_ui_config(const char *var, const char *value, void *cb);
 extern int diff_use_color_default;
 extern void diff_setup(struct diff_options *);
 extern int diff_opt_parse(struct diff_options *, const char **, int);
@@ -250,10 +250,6 @@
 /* report racily-clean paths as modified */
 #define DIFF_RACY_IS_MODIFIED 02
 extern int run_diff_files(struct rev_info *revs, unsigned int option);
-extern int setup_diff_no_index(struct rev_info *revs,
-		int argc, const char ** argv, int nongit, const char *prefix);
-extern int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv);
-
 extern int run_diff_index(struct rev_info *revs, int cached);
 
 extern int do_diff_cache(const unsigned char *, struct diff_options *);
@@ -261,4 +257,6 @@
 
 extern int diff_result_code(struct diff_options *, int);
 
+extern void diff_no_index(struct rev_info *, int, const char **, int, const char *);
+
 #endif /* DIFF_H */
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 31941bc..1b2ebb4 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -112,8 +112,8 @@
 struct diff_score {
 	int src; /* index in rename_src */
 	int dst; /* index in rename_dst */
-	int score;
-	int name_score;
+	unsigned short score;
+	short name_score;
 };
 
 static int estimate_similarity(struct diff_filespec *src,
@@ -223,6 +223,12 @@
 {
 	const struct diff_score *a = a_, *b = b_;
 
+	/* sink the unused ones to the bottom */
+	if (a->dst < 0)
+		return (0 <= b->dst);
+	else if (b->dst < 0)
+		return -1;
+
 	if (a->score == b->score)
 		return b->name_score - a->name_score;
 
@@ -387,6 +393,22 @@
 	return i;
 }
 
+#define NUM_CANDIDATE_PER_DST 4
+static void record_if_better(struct diff_score m[], struct diff_score *o)
+{
+	int i, worst;
+
+	/* find the worst one */
+	worst = 0;
+	for (i = 1; i < NUM_CANDIDATE_PER_DST; i++)
+		if (score_compare(&m[i], &m[worst]) > 0)
+			worst = i;
+
+	/* is it better than the worst one? */
+	if (score_compare(&m[worst], o) > 0)
+		m[worst] = *o;
+}
+
 void diffcore_rename(struct diff_options *options)
 {
 	int detect_rename = options->detect_rename;
@@ -470,51 +492,66 @@
 		rename_limit = 32767;
 	if ((num_create > rename_limit && num_src > rename_limit) ||
 	    (num_create * num_src > rename_limit * rename_limit)) {
-		warning("too many files, skipping inexact rename detection");
+		if (options->warn_on_too_large_rename)
+			warning("too many files, skipping inexact rename detection");
 		goto cleanup;
 	}
 
-	mx = xmalloc(sizeof(*mx) * num_create * num_src);
+	mx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx));
 	for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
-		int base = dst_cnt * num_src;
 		struct diff_filespec *two = rename_dst[i].two;
+		struct diff_score *m;
+
 		if (rename_dst[i].pair)
 			continue; /* dealt with exact match already. */
+
+		m = &mx[dst_cnt * NUM_CANDIDATE_PER_DST];
+		for (j = 0; j < NUM_CANDIDATE_PER_DST; j++)
+			m[j].dst = -1;
+
 		for (j = 0; j < rename_src_nr; j++) {
 			struct diff_filespec *one = rename_src[j].one;
-			struct diff_score *m = &mx[base+j];
-			m->src = j;
-			m->dst = i;
-			m->score = estimate_similarity(one, two,
-						       minimum_score);
-			m->name_score = basename_same(one, two);
+			struct diff_score this_src;
+			this_src.score = estimate_similarity(one, two,
+							     minimum_score);
+			this_src.name_score = basename_same(one, two);
+			this_src.dst = i;
+			this_src.src = j;
+			record_if_better(m, &this_src);
 			diff_free_filespec_blob(one);
 		}
 		/* We do not need the text anymore */
 		diff_free_filespec_blob(two);
 		dst_cnt++;
 	}
+
 	/* cost matrix sorted by most to least similar pair */
-	qsort(mx, num_create * num_src, sizeof(*mx), score_compare);
-	for (i = 0; i < num_create * num_src; i++) {
-		struct diff_rename_dst *dst = &rename_dst[mx[i].dst];
-		struct diff_filespec *src;
+	qsort(mx, dst_cnt * NUM_CANDIDATE_PER_DST, sizeof(*mx), score_compare);
+
+	for (i = 0; i < dst_cnt * NUM_CANDIDATE_PER_DST; i++) {
+		struct diff_rename_dst *dst;
+
+		if ((mx[i].dst < 0) ||
+		    (mx[i].score < minimum_score))
+			break; /* there is no more usable pair. */
+		dst = &rename_dst[mx[i].dst];
 		if (dst->pair)
 			continue; /* already done, either exact or fuzzy. */
-		if (mx[i].score < minimum_score)
-			break; /* there is no more usable pair. */
-		src = rename_src[mx[i].src].one;
-		if (src->rename_used)
+		if (rename_src[mx[i].src].one->rename_used)
 			continue;
 		record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
 		rename_count++;
 	}
-	for (i = 0; i < num_create * num_src; i++) {
-		struct diff_rename_dst *dst = &rename_dst[mx[i].dst];
+
+	for (i = 0; i < dst_cnt * NUM_CANDIDATE_PER_DST; i++) {
+		struct diff_rename_dst *dst;
+
+		if ((mx[i].dst < 0) ||
+		    (mx[i].score < minimum_score))
+			break; /* there is no more usable pair. */
+		dst = &rename_dst[mx[i].dst];
 		if (dst->pair)
 			continue; /* already done, either exact or fuzzy. */
-		if (mx[i].score < minimum_score)
-			break; /* there is no more usable pair. */
 		record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
 		rename_count++;
 	}
diff --git a/dir.c b/dir.c
index d79762c..109e05b 100644
--- a/dir.c
+++ b/dir.c
@@ -52,6 +52,11 @@
 	return prefix;
 }
 
+static inline int special_char(unsigned char c1)
+{
+	return !c1 || c1 == '*' || c1 == '[' || c1 == '?' || c1 == '\\';
+}
+
 /*
  * Does 'match' matches the given name?
  * A match is found if
@@ -69,14 +74,27 @@
 	int matchlen;
 
 	/* If the match was just the prefix, we matched */
-	matchlen = strlen(match);
-	if (!matchlen)
+	if (!*match)
 		return MATCHED_RECURSIVELY;
 
+	for (;;) {
+		unsigned char c1 = *match;
+		unsigned char c2 = *name;
+		if (special_char(c1))
+			break;
+		if (c1 != c2)
+			return 0;
+		match++;
+		name++;
+		namelen--;
+	}
+
+
 	/*
 	 * If we don't match the matchstring exactly,
 	 * we need to match by fnmatch
 	 */
+	matchlen = strlen(match);
 	if (strncmp(match, name, matchlen))
 		return !fnmatch(match, name, 0) ? MATCHED_FNMATCH : 0;
 
@@ -371,7 +389,7 @@
 
 struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
 {
-	if (cache_name_exists(pathname, len))
+	if (cache_name_exists(pathname, len, ignore_case))
 		return NULL;
 
 	ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
diff --git a/environment.c b/environment.c
index 6739a3f..d5c3e29 100644
--- a/environment.c
+++ b/environment.c
@@ -11,9 +11,11 @@
 
 char git_default_email[MAX_GITNAME];
 char git_default_name[MAX_GITNAME];
+int user_ident_explicitly_given;
 int trust_executable_bit = 1;
 int quote_path_fully = 1;
 int has_symlinks = 1;
+int ignore_case;
 int assume_unchanged;
 int prefer_symlink_refs;
 int is_bare_repository_cfg = -1; /* unspecified */
@@ -27,6 +29,7 @@
 int zlib_compression_level = Z_BEST_SPEED;
 int core_compression_level;
 int core_compression_seen;
+int fsync_object_files;
 size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
 size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
 size_t delta_base_cache_limit = 16 * 1024 * 1024;
@@ -38,10 +41,11 @@
 enum safe_crlf safe_crlf = SAFE_CRLF_WARN;
 unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
 enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;
+enum rebase_setup_type autorebase = AUTOREBASE_NEVER;
 
 /* This is set by setup_git_dir_gently() and/or git_default_config() */
 char *git_work_tree_cfg;
-static const char *work_tree;
+static char *work_tree;
 
 static const char *git_dir;
 static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;
@@ -50,6 +54,8 @@
 {
 	git_dir = getenv(GIT_DIR_ENVIRONMENT);
 	if (!git_dir)
+		git_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
+	if (!git_dir)
 		git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
 	git_object_dir = getenv(DB_ENVIRONMENT);
 	if (!git_object_dir) {
@@ -81,10 +87,26 @@
 	return git_dir;
 }
 
+static int git_work_tree_initialized;
+
+/*
+ * Note.  This works only before you used a work tree.  This was added
+ * primarily to support git-clone to work in a new repository it just
+ * created, and is not meant to flip between different work trees.
+ */
+void set_git_work_tree(const char *new_work_tree)
+{
+	if (is_bare_repository_cfg >= 0)
+		die("cannot set work tree after initialization");
+	git_work_tree_initialized = 1;
+	free(work_tree);
+	work_tree = xstrdup(make_absolute_path(new_work_tree));
+	is_bare_repository_cfg = 0;
+}
+
 const char *get_git_work_tree(void)
 {
-	static int initialized = 0;
-	if (!initialized) {
+	if (!git_work_tree_initialized) {
 		work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);
 		/* core.bare = true overrides implicit and config work tree */
 		if (!work_tree && is_bare_repository_cfg < 1) {
@@ -94,7 +116,7 @@
 				work_tree = xstrdup(make_absolute_path(git_path(work_tree)));
 		} else if (work_tree)
 			work_tree = xstrdup(make_absolute_path(work_tree));
-		initialized = 1;
+		git_work_tree_initialized = 1;
 		if (work_tree)
 			is_bare_repository_cfg = 0;
 	}
diff --git a/fast-import.c b/fast-import.c
index 73e5439..e72b286 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -890,7 +890,7 @@
 		SHA1_Update(&ctx, (*c)->sha1, 20);
 	}
 	sha1write(f, pack_data->sha1, sizeof(pack_data->sha1));
-	sha1close(f, NULL, 1);
+	sha1close(f, NULL, CSUM_FSYNC);
 	free(idx);
 	SHA1_Final(pack_data->sha1, &ctx);
 	return tmpfile;
@@ -1690,7 +1690,7 @@
 		ungetc(term_char, stdin);
 }
 
-static void cmd_mark(void)
+static void parse_mark(void)
 {
 	if (!prefixcmp(command_buf.buf, "mark :")) {
 		next_mark = strtoumax(command_buf.buf + 6, NULL, 10);
@@ -1700,7 +1700,7 @@
 		next_mark = 0;
 }
 
-static void cmd_data(struct strbuf *sb)
+static void parse_data(struct strbuf *sb)
 {
 	strbuf_reset(sb);
 
@@ -1798,13 +1798,13 @@
 	return ident;
 }
 
-static void cmd_new_blob(void)
+static void parse_new_blob(void)
 {
 	static struct strbuf buf = STRBUF_INIT;
 
 	read_next_command();
-	cmd_mark();
-	cmd_data(&buf);
+	parse_mark();
+	parse_data(&buf);
 	store_object(OBJ_BLOB, &buf, &last_blob, NULL, next_mark);
 }
 
@@ -1908,7 +1908,7 @@
 			p = uq.buf;
 		}
 		read_next_command();
-		cmd_data(&buf);
+		parse_data(&buf);
 		store_object(OBJ_BLOB, &buf, &last_blob, sha1, 0);
 	} else if (oe) {
 		if (oe->type != OBJ_BLOB)
@@ -1995,7 +1995,7 @@
 	load_tree(&b->branch_tree);
 }
 
-static void cmd_from_commit(struct branch *b, char *buf, unsigned long size)
+static void parse_from_commit(struct branch *b, char *buf, unsigned long size)
 {
 	if (!buf || size < 46)
 		die("Not a valid commit: %s", sha1_to_hex(b->sha1));
@@ -2006,7 +2006,7 @@
 		b->branch_tree.versions[1].sha1);
 }
 
-static void cmd_from_existing(struct branch *b)
+static void parse_from_existing(struct branch *b)
 {
 	if (is_null_sha1(b->sha1)) {
 		hashclr(b->branch_tree.versions[0].sha1);
@@ -2017,12 +2017,12 @@
 
 		buf = read_object_with_reference(b->sha1,
 			commit_type, &size, b->sha1);
-		cmd_from_commit(b, buf, size);
+		parse_from_commit(b, buf, size);
 		free(buf);
 	}
 }
 
-static int cmd_from(struct branch *b)
+static int parse_from(struct branch *b)
 {
 	const char *from;
 	struct branch *s;
@@ -2053,12 +2053,12 @@
 		if (oe->pack_id != MAX_PACK_ID) {
 			unsigned long size;
 			char *buf = gfi_unpack_entry(oe, &size);
-			cmd_from_commit(b, buf, size);
+			parse_from_commit(b, buf, size);
 			free(buf);
 		} else
-			cmd_from_existing(b);
+			parse_from_existing(b);
 	} else if (!get_sha1(from, b->sha1))
-		cmd_from_existing(b);
+		parse_from_existing(b);
 	else
 		die("Invalid ref name or SHA1 expression: %s", from);
 
@@ -2066,7 +2066,7 @@
 	return 1;
 }
 
-static struct hash_list *cmd_merge(unsigned int *count)
+static struct hash_list *parse_merge(unsigned int *count)
 {
 	struct hash_list *list = NULL, *n, *e = e;
 	const char *from;
@@ -2107,7 +2107,7 @@
 	return list;
 }
 
-static void cmd_new_commit(void)
+static void parse_new_commit(void)
 {
 	static struct strbuf msg = STRBUF_INIT;
 	struct branch *b;
@@ -2124,7 +2124,7 @@
 		b = new_branch(sp);
 
 	read_next_command();
-	cmd_mark();
+	parse_mark();
 	if (!prefixcmp(command_buf.buf, "author ")) {
 		author = parse_ident(command_buf.buf + 7);
 		read_next_command();
@@ -2135,10 +2135,10 @@
 	}
 	if (!committer)
 		die("Expected committer but didn't get one");
-	cmd_data(&msg);
+	parse_data(&msg);
 	read_next_command();
-	cmd_from(b);
-	merge_list = cmd_merge(&merge_count);
+	parse_from(b);
+	merge_list = parse_merge(&merge_count);
 
 	/* ensure the branch is active/loaded */
 	if (!b->branch_tree.tree || !max_active_branches) {
@@ -2196,7 +2196,7 @@
 	b->last_commit = object_count_by_type[OBJ_COMMIT];
 }
 
-static void cmd_new_tag(void)
+static void parse_new_tag(void)
 {
 	static struct strbuf msg = STRBUF_INIT;
 	char *sp;
@@ -2253,7 +2253,7 @@
 
 	/* tag payload/message */
 	read_next_command();
-	cmd_data(&msg);
+	parse_data(&msg);
 
 	/* build the tag object */
 	strbuf_reset(&new_data);
@@ -2273,7 +2273,7 @@
 		t->pack_id = pack_id;
 }
 
-static void cmd_reset_branch(void)
+static void parse_reset_branch(void)
 {
 	struct branch *b;
 	char *sp;
@@ -2293,12 +2293,12 @@
 	else
 		b = new_branch(sp);
 	read_next_command();
-	cmd_from(b);
+	parse_from(b);
 	if (command_buf.len > 0)
 		unread_command_buf = 1;
 }
 
-static void cmd_checkpoint(void)
+static void parse_checkpoint(void)
 {
 	if (object_count) {
 		cycle_packfile();
@@ -2309,7 +2309,7 @@
 	skip_optional_lf();
 }
 
-static void cmd_progress(void)
+static void parse_progress(void)
 {
 	fwrite(command_buf.buf, 1, command_buf.len, stdout);
 	fputc('\n', stdout);
@@ -2352,7 +2352,7 @@
 	fclose(f);
 }
 
-static int git_pack_config(const char *k, const char *v)
+static int git_pack_config(const char *k, const char *v, void *cb)
 {
 	if (!strcmp(k, "pack.depth")) {
 		max_depth = git_config_int(k, v);
@@ -2370,7 +2370,7 @@
 		pack_compression_seen = 1;
 		return 0;
 	}
-	return git_default_config(k, v);
+	return git_default_config(k, v, cb);
 }
 
 static const char fast_import_usage[] =
@@ -2381,7 +2381,7 @@
 	unsigned int i, show_stats = 1;
 
 	setup_git_directory();
-	git_config(git_pack_config);
+	git_config(git_pack_config, NULL);
 	if (!pack_compression_seen && core_compression_seen)
 		pack_compression_level = core_compression_level;
 
@@ -2449,17 +2449,17 @@
 	set_die_routine(die_nicely);
 	while (read_next_command() != EOF) {
 		if (!strcmp("blob", command_buf.buf))
-			cmd_new_blob();
+			parse_new_blob();
 		else if (!prefixcmp(command_buf.buf, "commit "))
-			cmd_new_commit();
+			parse_new_commit();
 		else if (!prefixcmp(command_buf.buf, "tag "))
-			cmd_new_tag();
+			parse_new_tag();
 		else if (!prefixcmp(command_buf.buf, "reset "))
-			cmd_reset_branch();
+			parse_reset_branch();
 		else if (!strcmp("checkpoint", command_buf.buf))
-			cmd_checkpoint();
+			parse_checkpoint();
 		else if (!prefixcmp(command_buf.buf, "progress "))
-			cmd_progress();
+			parse_progress();
 		else
 			die("Unsupported command: %s", command_buf.buf);
 	}
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index a0a81f1..709caa9 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -394,9 +394,9 @@
 			if ($choice =~ s/^-//) {
 				$choose = 0;
 			}
-			# A range can be specified like 5-7
-			if ($choice =~ /^(\d+)-(\d+)$/) {
-				($bottom, $top) = ($1, $2);
+			# A range can be specified like 5-7 or 5-.
+			if ($choice =~ /^(\d+)-(\d*)$/) {
+				($bottom, $top) = ($1, length($2) ? $2 : 1 + @stuff);
 			}
 			elsif ($choice =~ /^\d+$/) {
 				$bottom = $top = $choice;
@@ -550,6 +550,21 @@
 	return @hunk;
 }
 
+sub parse_diff_header {
+	my $src = shift;
+
+	my $head = { TEXT => [], DISPLAY => [] };
+	my $mode = { TEXT => [], DISPLAY => [] };
+
+	for (my $i = 0; $i < @{$src->{TEXT}}; $i++) {
+		my $dest = $src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ?
+			$mode : $head;
+		push @{$dest->{TEXT}}, $src->{TEXT}->[$i];
+		push @{$dest->{DISPLAY}}, $src->{DISPLAY}->[$i];
+	}
+	return ($head, $mode);
+}
+
 sub hunk_splittable {
 	my ($text) = @_;
 
@@ -795,9 +810,40 @@
 	my ($ix, $num);
 	my $path = shift;
 	my ($head, @hunk) = parse_diff($path);
+	($head, my $mode) = parse_diff_header($head);
 	for (@{$head->{DISPLAY}}) {
 		print;
 	}
+
+	if (@{$mode->{TEXT}}) {
+		while (1) {
+			print @{$mode->{DISPLAY}};
+			print colored $prompt_color,
+				"Stage mode change [y/n/a/d/?]? ";
+			my $line = <STDIN>;
+			if ($line =~ /^y/i) {
+				$mode->{USE} = 1;
+				last;
+			}
+			elsif ($line =~ /^n/i) {
+				$mode->{USE} = 0;
+				last;
+			}
+			elsif ($line =~ /^a/i) {
+				$_->{USE} = 1 foreach ($mode, @hunk);
+				last;
+			}
+			elsif ($line =~ /^d/i) {
+				$_->{USE} = 0 foreach ($mode, @hunk);
+				last;
+			}
+			else {
+				help_patch_cmd('');
+				next;
+			}
+		}
+	}
+
 	$num = scalar @hunk;
 	$ix = 0;
 
@@ -920,6 +966,9 @@
 
 	my $n_lofs = 0;
 	my @result = ();
+	if ($mode->{USE}) {
+		push @result, @{$mode->{TEXT}};
+	}
 	for (@hunk) {
 		my $text = $_->{TEXT};
 		my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) =
diff --git a/git-am.sh b/git-am.sh
index b48096e..83b277a 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -30,7 +30,8 @@
 require_work_tree
 cd_to_toplevel
 
-git var GIT_COMMITTER_IDENT >/dev/null || exit
+git var GIT_COMMITTER_IDENT >/dev/null ||
+	die "You need to set your committer info first"
 
 stop_here () {
     echo "$1" >"$dotest/next"
@@ -421,7 +422,7 @@
 	else
 	    action=yes
 	fi
-	FIRSTLINE=$(head -1 "$dotest/final-commit")
+	FIRSTLINE=$(sed 1q "$dotest/final-commit")
 
 	if test $action = skip
 	then
diff --git a/git-bisect.sh b/git-bisect.sh
index b1800ed..6c6c3de 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -1,7 +1,9 @@
 #!/bin/sh
 
-USAGE='[start|bad|good|skip|next|reset|visualize|replay|log|run]'
-LONG_USAGE='git bisect start [<bad> [<good>...]] [--] [<pathspec>...]
+USAGE='[help|start|bad|good|skip|next|reset|visualize|replay|log|run]'
+LONG_USAGE='git bisect help
+        print this long help message.
+git bisect start [<bad> [<good>...]] [--] [<pathspec>...]
         reset bisect state and start bisection.
 git bisect bad [<rev>]
         mark <rev> a known-bad revision.
@@ -20,7 +22,9 @@
 git bisect log
         show bisect log.
 git bisect run <cmd>...
-        use <cmd>... to automatically bisect.'
+        use <cmd>... to automatically bisect.
+
+Please use "git help bisect" to get the full man page.'
 
 OPTIONS_SPEC=
 . git-sh-setup
@@ -40,7 +44,7 @@
 }
 
 bisect_autostart() {
-	test -f "$GIT_DIR/BISECT_NAMES" || {
+	test -s "$GIT_DIR/BISECT_START" || {
 		echo >&2 'You need to start by "git bisect start"'
 		if test -t 0
 		then
@@ -59,42 +63,42 @@
 
 bisect_start() {
 	#
-	# Verify HEAD. If we were bisecting before this, reset to the
-	# top-of-line master first!
+	# Verify HEAD.
 	#
 	head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD) ||
 	head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) ||
 	die "Bad HEAD - I need a HEAD"
-	#
-	# Check that we either already have BISECT_START, or that the
-	# branches bisect, new-bisect don't exist, to not override them.
-	#
-	test -s "$GIT_DIR/BISECT_START" ||
-		if git show-ref --verify -q refs/heads/bisect ||
-		    git show-ref --verify -q refs/heads/new-bisect; then
-			die 'The branches "bisect" and "new-bisect" must not exist.'
-		fi
-	start_head=''
-	case "$head" in
-	refs/heads/bisect)
-		branch=`cat "$GIT_DIR/BISECT_START"`
-		git checkout $branch || exit
-		;;
-	refs/heads/*|$_x40)
-		# This error message should only be triggered by cogito usage,
-		# and cogito users should understand it relates to cg-seek.
-		[ -s "$GIT_DIR/head-name" ] && die "won't bisect on seeked tree"
-		start_head="${head#refs/heads/}"
-		;;
-	*)
-		die "Bad HEAD - strange symbolic ref"
-		;;
-	esac
 
 	#
-	# Get rid of any old bisect state
+	# Check if we are bisecting.
 	#
-	bisect_clean_state
+	start_head=''
+	if test -s "$GIT_DIR/BISECT_START"
+	then
+		# Reset to the rev from where we started.
+		start_head=$(cat "$GIT_DIR/BISECT_START")
+		git checkout "$start_head" || exit
+	else
+		# Get rev from where we start.
+		case "$head" in
+		refs/heads/*|$_x40)
+			# This error message should only be triggered by
+			# cogito usage, and cogito users should understand
+			# it relates to cg-seek.
+			[ -s "$GIT_DIR/head-name" ] &&
+				die "won't bisect on seeked tree"
+			start_head="${head#refs/heads/}"
+			;;
+		*)
+			die "Bad HEAD - strange symbolic ref"
+			;;
+		esac
+	fi
+
+	#
+	# Get rid of any old bisect state.
+	#
+	bisect_clean_state || exit
 
 	#
 	# Check for one bad and then some good revisions.
@@ -114,7 +118,7 @@
 		break
 		;;
 	    *)
-		rev=$(git rev-parse --verify "$arg^{commit}" 2>/dev/null) || {
+		rev=$(git rev-parse -q --verify "$arg^{commit}") || {
 		    test $has_double_dash -eq 1 &&
 		        die "'$arg' does not appear to be a valid revision"
 		    break
@@ -129,11 +133,29 @@
 	    esac
 	done
 
-	sq "$@" >"$GIT_DIR/BISECT_NAMES"
-	test -n "$start_head" && echo "$start_head" >"$GIT_DIR/BISECT_START"
-	eval "$eval"
-	echo "git-bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG"
+	#
+	# Change state.
+	# In case of mistaken revs or checkout error, or signals received,
+	# "bisect_auto_next" below may exit or misbehave.
+	# We have to trap this to be able to clean up using
+	# "bisect_clean_state".
+	#
+	trap 'bisect_clean_state' 0
+	trap 'exit 255' 1 2 3 15
+
+	#
+	# Write new start state.
+	#
+	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
+	#
+	# Check if we can proceed to the next bisect state.
+	#
 	bisect_auto_next
+
+	trap '-' 0
 }
 
 bisect_write() {
@@ -145,9 +167,9 @@
 		good|skip)	tag="$state"-"$rev" ;;
 		*)		die "Bad bisect_write argument: $state" ;;
 	esac
-	git update-ref "refs/bisect/$tag" "$rev"
+	git update-ref "refs/bisect/$tag" "$rev" || exit
 	echo "# $state: $(git show-branch $rev)" >>"$GIT_DIR/BISECT_LOG"
-	test -z "$nolog" && echo "git-bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
+	test -n "$nolog" || echo "git-bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
 }
 
 bisect_state() {
@@ -198,13 +220,14 @@
 		if test -t 0
 		then
 			printf >&2 'Are you sure [Y/n]? '
-			case "$(read yesno)" in [Nn]*) exit 1 ;; esac
+			read yesno
+			case "$yesno" in [Nn]*) exit 1 ;; esac
 		fi
 		: bisect without good...
 		;;
 	*)
 		THEN=''
-		test -f "$GIT_DIR/BISECT_NAMES" || {
+		test -s "$GIT_DIR/BISECT_START" || {
 			echo >&2 'You need to start by "git bisect start".'
 			THEN='then '
 		}
@@ -344,9 +367,7 @@
 	exit_if_skipped_commits "$bisect_rev"
 
 	echo "Bisecting: $bisect_nr revisions left to test after this"
-	git branch -D new-bisect 2> /dev/null
-	git checkout -q -b new-bisect "$bisect_rev" || exit
-	git branch -M new-bisect bisect
+	git checkout -q "$bisect_rev" || exit
 	git show-branch "$bisect_rev"
 }
 
@@ -372,40 +393,35 @@
 }
 
 bisect_reset() {
-	test -f "$GIT_DIR/BISECT_NAMES" || {
+	test -s "$GIT_DIR/BISECT_START" || {
 		echo "We are not bisecting."
 		return
 	}
 	case "$#" in
-	0) if [ -s "$GIT_DIR/BISECT_START" ]; then
-	       branch=`cat "$GIT_DIR/BISECT_START"`
-	   else
-	       branch=master
-	   fi ;;
+	0) branch=$(cat "$GIT_DIR/BISECT_START") ;;
 	1) git show-ref --verify --quiet -- "refs/heads/$1" ||
 	       die "$1 does not seem to be a valid branch"
 	   branch="$1" ;;
 	*)
 	    usage ;;
 	esac
-	if git checkout "$branch"; then
-		# Cleanup head-name if it got left by an old version of git-bisect
-		rm -f "$GIT_DIR/head-name"
-		rm -f "$GIT_DIR/BISECT_START"
-		bisect_clean_state
-	fi
+	git checkout "$branch" && bisect_clean_state
 }
 
 bisect_clean_state() {
 	# There may be some refs packed during bisection.
-	git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* refs/heads/bisect |
+	git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* |
 	while read ref hash
 	do
-		git update-ref -d $ref $hash
+		git update-ref -d $ref $hash || exit
 	done
-	rm -f "$GIT_DIR/BISECT_LOG"
-	rm -f "$GIT_DIR/BISECT_NAMES"
-	rm -f "$GIT_DIR/BISECT_RUN"
+	rm -f "$GIT_DIR/BISECT_LOG" &&
+	rm -f "$GIT_DIR/BISECT_NAMES" &&
+	rm -f "$GIT_DIR/BISECT_RUN" &&
+	# Cleanup head-name if it got left by an old version of git-bisect
+	rm -f "$GIT_DIR/head-name" &&
+
+	rm -f "$GIT_DIR/BISECT_START"
 }
 
 bisect_replay () {
@@ -487,6 +503,8 @@
     cmd="$1"
     shift
     case "$cmd" in
+    help)
+        git bisect -h ;;
     start)
         bisect_start "$@" ;;
     bad|good|skip)
diff --git a/git-compat-util.h b/git-compat-util.h
index a18235e..c04e8ba 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -39,7 +39,7 @@
 /* Approximation of the length of the decimal representation of this type. */
 #define decimal_length(x)	((int)(sizeof(x) * 2.56 + 0.5) + 1)
 
-#if !defined(__APPLE__) && !defined(__FreeBSD__)
+#if !defined(__APPLE__) && !defined(__FreeBSD__)  && !defined(__USLC__) && !defined(_M_UNIX)
 #define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
 #define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
 #endif
@@ -206,6 +206,9 @@
 #endif
 
 #ifdef FREAD_READS_DIRECTORIES
+#ifdef fopen
+#undef fopen
+#endif
 #define fopen(a,b) git_fopen(a,b)
 extern FILE *git_fopen(const char*, const char*);
 #endif
@@ -268,6 +271,12 @@
 	return ret;
 }
 
+/*
+ * xmemdupz() allocates (len + 1) bytes of memory, duplicates "len" bytes of
+ * "data" to the allocated memory, zero terminates the allocated memory,
+ * and returns a pointer to the allocated memory. If the allocation fails,
+ * the program dies.
+ */
 static inline void *xmemdupz(const void *data, size_t len)
 {
 	char *p = xmalloc(len + 1);
@@ -329,6 +338,11 @@
 	return ret;
 }
 
+/*
+ * xread() is the same a read(), but it automatically restarts read()
+ * operations with a recoverable error (EAGAIN and EINTR). xread()
+ * DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
+ */
 static inline ssize_t xread(int fd, void *buf, size_t len)
 {
 	ssize_t nr;
@@ -340,6 +354,11 @@
 	}
 }
 
+/*
+ * xwrite() is the same a write(), but it automatically restarts write()
+ * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
+ * GUARANTEE that "len" bytes is written even if the operation is successful.
+ */
 static inline ssize_t xwrite(int fd, const void *buf, size_t len)
 {
 	ssize_t nr;
diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl
index b6036bd..c6c70e9 100755
--- a/git-cvsexportcommit.perl
+++ b/git-cvsexportcommit.perl
@@ -6,16 +6,21 @@
 use Data::Dumper;
 use File::Basename qw(basename dirname);
 use File::Spec;
+use Git;
 
-our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d, $opt_u, $opt_w);
+our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d, $opt_u, $opt_w, $opt_W);
 
-getopts('uhPpvcfam:d:w:');
+getopts('uhPpvcfam:d:w:W');
 
 $opt_h && usage();
 
 die "Need at least one commit identifier!" unless @ARGV;
 
-if ($opt_w) {
+# Get git-config settings
+my $repo = Git->repository();
+$opt_w = $repo->config('cvsexportcommit.cvsdir') unless defined $opt_w;
+
+if ($opt_w || $opt_W) {
 	# Remember where GIT_DIR is before changing to CVS checkout
 	unless ($ENV{GIT_DIR}) {
 		# No GIT_DIR set. Figure it out for ourselves
@@ -25,7 +30,9 @@
 	}
 	# Make sure GIT_DIR is absolute
 	$ENV{GIT_DIR} = File::Spec->rel2abs($ENV{GIT_DIR});
+}
 
+if ($opt_w) {
 	if (! -d $opt_w."/CVS" ) {
 		die "$opt_w is not a CVS checkout";
 	}
@@ -116,6 +123,15 @@
     }
 }
 
+my $go_back_to = 0;
+
+if ($opt_W) {
+    $opt_v && print "Resetting to $parent\n";
+    $go_back_to = `git symbolic-ref HEAD 2> /dev/null ||
+	git rev-parse HEAD` || die "Could not determine current branch";
+    system("git checkout -q $parent^0") && die "Could not check out $parent^0";
+}
+
 $opt_v && print "Applying to CVS commit $commit from parent $parent\n";
 
 # grab the commit message
@@ -210,7 +226,8 @@
 	my $basename = basename($name);
 
 	$basename = "no file " . $basename if (exists($added{$basename}));
-	chomp($basename);
+	$basename =~ s/^\s+//;
+	$basename =~ s/\s+$//;
 
 	if (!exists($fullname{$basename})) {
 	  $fullname{$basename} = $name;
@@ -259,7 +276,11 @@
 }
 
 print "Applying\n";
-`GIT_DIR= git-apply $context --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch";
+if ($opt_W) {
+    system("git checkout -q $commit^0") && die "cannot patch";
+} else {
+    `GIT_DIR= git-apply $context --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch";
+}
 
 print "Patch applied successfully. Adding new files and directories to CVS\n";
 my $dirtypatch = 0;
@@ -312,7 +333,9 @@
     print "using a patch program. After applying the patch and resolving the\n";
     print "problems you may commit using:";
     print "\n    cd \"$opt_w\"" if $opt_w;
-    print "\n    $cmd\n\n";
+    print "\n    $cmd\n";
+    print "\n    git checkout $go_back_to\n" if $go_back_to;
+    print "\n";
     exit(1);
 }
 
@@ -332,6 +355,14 @@
 # clean up
 unlink(".cvsexportcommit.diff");
 
+if ($opt_W) {
+    system("git checkout $go_back_to") && die "cannot move back to $go_back_to";
+    if (!($go_back_to =~ /^[0-9a-fA-F]{40}$/)) {
+	system("git symbolic-ref HEAD $go_back_to") &&
+	    die "cannot move back to $go_back_to";
+    }
+}
+
 # CVS version 1.11.x and 1.12.x sleeps the wrong way to ensure the timestamp
 # used by CVS and the one set by subsequence file modifications are different.
 # If they are not different CVS will not detect changes.
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index bdac5d5..7e95fb3 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -227,6 +227,7 @@
 				$proxyport = $1;
 			}
 		}
+		$repo ||= '/';
 
 		# if username is not explicit in CVSROOT, then use current user, as cvs would
 		$user=(getlogin() || $ENV{'LOGNAME'} || $ENV{'USER'} || "anonymous") unless $user;
@@ -780,6 +781,7 @@
 		$xtag =~ s/\s+\*\*.*$//; # Remove stuff like ** INVALID ** and ** FUNKY **
 		$xtag =~ tr/_/\./ if ( $opt_u );
 		$xtag =~ s/[\/]/$opt_s/g;
+		$xtag =~ s/\[//g;
 
 		system('git-tag', '-f', $xtag, $cid) == 0
 			or die "Cannot create tag $xtag: $!\n";
@@ -950,7 +952,7 @@
 	} elsif (/^-+$/) { # end of unknown-line processing
 		$state = 1;
 	} elsif ($state != 11) { # ignore stuff when skipping
-		print "* UNKNOWN LINE * $_\n";
+		print STDERR "* UNKNOWN LINE * $_\n";
 	}
 }
 commit() if $branch and $state != 11;
diff --git a/git-cvsserver.perl b/git-cvsserver.perl
index 29dbfc9..b00d1c2 100755
--- a/git-cvsserver.perl
+++ b/git-cvsserver.perl
@@ -21,6 +21,7 @@
 
 use Fcntl;
 use File::Temp qw/tempdir tempfile/;
+use File::Path qw/rmtree/;
 use File::Basename;
 use Getopt::Long qw(:config require_order no_ignore_case);
 
@@ -86,6 +87,17 @@
 # $state holds all the bits of information the clients sends us that could
 # potentially be useful when it comes to actually _doing_ something.
 my $state = { prependdir => '' };
+
+# Work is for managing temporary working directory
+my $work =
+    {
+        state => undef,  # undef, 1 (empty), 2 (with stuff)
+        workDir => undef,
+        index => undef,
+        emptyDir => undef,
+        tmpDir => undef
+    };
+
 $log->info("--------------- STARTING -----------------");
 
 my $usage =
@@ -189,6 +201,9 @@
 $log->debug("Processing time : user=" . (times)[0] . " system=" . (times)[1]);
 $log->info("--------------- FINISH -----------------");
 
+chdir '/';
+exit 0;
+
 # Magic catchall method.
 #    This is the method that will handle all commands we haven't yet
 #    implemented. It simply sends a warning to the log file indicating a
@@ -487,7 +502,7 @@
                 print $state->{CVSROOT} . "/$state->{module}/$filename\n";
 
                 # this is an "entries" line
-                my $kopts = kopts_from_path($filepart);
+                my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash});
                 $log->debug("/$filepart/1.$meta->{revision}//$kopts/");
                 print "/$filepart/1.$meta->{revision}//$kopts/\n";
                 # permissions
@@ -518,9 +533,26 @@
 
         print "Checked-in $dirpart\n";
         print "$filename\n";
-        my $kopts = kopts_from_path($filepart);
+        my $kopts = kopts_from_path($filename,"file",
+                        $state->{entries}{$filename}{modified_filename});
         print "/$filepart/0//$kopts/\n";
 
+        my $requestedKopts = $state->{opt}{k};
+        if(defined($requestedKopts))
+        {
+            $requestedKopts = "-k$requestedKopts";
+        }
+        else
+        {
+            $requestedKopts = "";
+        }
+        if( $kopts ne $requestedKopts )
+        {
+            $log->warn("Ignoring requested -k='$requestedKopts'"
+                        . " for '$filename'; detected -k='$kopts' instead");
+            #TODO: Also have option to send warning to user?
+        }
+
         $addcount++;
     }
 
@@ -600,7 +632,7 @@
 
         print "Checked-in $dirpart\n";
         print "$filename\n";
-        my $kopts = kopts_from_path($filepart);
+        my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash});
         print "/$filepart/-1.$wrev//$kopts/\n";
 
         $rmcount++;
@@ -770,6 +802,7 @@
     argsplit("co");
 
     my $module = $state->{args}[0];
+    $state->{module} = $module;
     my $checkout_path = $module;
 
     # use the user specified directory if we're given it
@@ -847,6 +880,7 @@
         # Don't want to check out deleted files
         next if ( $git->{filehash} eq "deleted" );
 
+        my $fullName = $git->{name};
         ( $git->{name}, $git->{dir} ) = filenamesplit($git->{name});
 
        if (length($git->{dir}) && $git->{dir} ne './'
@@ -877,7 +911,7 @@
        print $state->{CVSROOT} . "/$module/" . ( defined ( $git->{dir} ) and $git->{dir} ne "./" ? $git->{dir} . "/" : "" ) . "$git->{name}\n";
 
         # this is an "entries" line
-        my $kopts = kopts_from_path($git->{name});
+        my $kopts = kopts_from_path($fullName,"sha1",$git->{filehash});
         print "/$git->{name}/1.$git->{revision}//$kopts/\n";
         # permissions
         print "u=$git->{mode},g=$git->{mode},o=$git->{mode}\n";
@@ -1086,7 +1120,7 @@
 		print $state->{CVSROOT} . "/$state->{module}/$filename\n";
 
 		# this is an "entries" line
-		my $kopts = kopts_from_path($filepart);
+		my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash});
 		$log->debug("/$filepart/1.$meta->{revision}//$kopts/");
 		print "/$filepart/1.$meta->{revision}//$kopts/\n";
 
@@ -1101,10 +1135,10 @@
             $log->info("Updating '$filename'");
             my ( $filepart, $dirpart ) = filenamesplit($meta->{name},1);
 
-            my $dir = tempdir( DIR => $TEMP_DIR, CLEANUP => 1 ) . "/";
+            my $mergeDir = setupTmpDir();
 
-            chdir $dir;
             my $file_local = $filepart . ".mine";
+            my $mergedFile = "$mergeDir/$file_local";
             system("ln","-s",$state->{entries}{$filename}{modified_filename}, $file_local);
             my $file_old = $filepart . "." . $oldmeta->{revision};
             transmitfile($oldmeta->{filehash}, { targetfile => $file_old });
@@ -1115,11 +1149,13 @@
             $log->info("Merging $file_local, $file_old, $file_new");
             print "M Merging differences between 1.$oldmeta->{revision} and 1.$meta->{revision} into $filename\n";
 
-            $log->debug("Temporary directory for merge is $dir");
+            $log->debug("Temporary directory for merge is $mergeDir");
 
             my $return = system("git", "merge-file", $file_local, $file_old, $file_new);
             $return >>= 8;
 
+            cleanupTmpDir();
+
             if ( $return == 0 )
             {
                 $log->info("Merged successfully");
@@ -1132,7 +1168,8 @@
                     print "Merged $dirpart\n";
                     $log->debug($state->{CVSROOT} . "/$state->{module}/$filename");
                     print $state->{CVSROOT} . "/$state->{module}/$filename\n";
-                    my $kopts = kopts_from_path($filepart);
+                    my $kopts = kopts_from_path("$dirpart/$filepart",
+                                                "file",$mergedFile);
                     $log->debug("/$filepart/1.$meta->{revision}//$kopts/");
                     print "/$filepart/1.$meta->{revision}//$kopts/\n";
                 }
@@ -1148,7 +1185,8 @@
                 {
                     print "Merged $dirpart\n";
                     print $state->{CVSROOT} . "/$state->{module}/$filename\n";
-                    my $kopts = kopts_from_path($filepart);
+                    my $kopts = kopts_from_path("$dirpart/$filepart",
+                                                "file",$mergedFile);
                     print "/$filepart/1.$meta->{revision}/+/$kopts/\n";
                 }
             }
@@ -1168,13 +1206,11 @@
                 # transmit file, format is single integer on a line by itself (file
                 # size) followed by the file contents
                 # TODO : we should copy files in blocks
-                my $data = `cat $file_local`;
+                my $data = `cat $mergedFile`;
                 $log->debug("File size : " . length($data));
                 print length($data) . "\n";
                 print $data;
             }
-
-            chdir "/";
         }
 
     }
@@ -1195,6 +1231,7 @@
     if ( $state->{method} eq 'pserver')
     {
         print "error 1 pserver access cannot commit\n";
+        cleanupWorkTree();
         exit;
     }
 
@@ -1202,6 +1239,7 @@
     {
         $log->warn("file 'index' already exists in the git repository");
         print "error 1 Index already exists in git repo\n";
+        cleanupWorkTree();
         exit;
     }
 
@@ -1209,31 +1247,20 @@
     my $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log);
     $updater->update();
 
-    my $tmpdir = tempdir ( DIR => $TEMP_DIR );
-    my ( undef, $file_index ) = tempfile ( DIR => $TEMP_DIR, OPEN => 0 );
-    $log->info("Lockless commit start, basing commit on '$tmpdir', index file is '$file_index'");
-
-    $ENV{GIT_DIR} = $state->{CVSROOT} . "/";
-    $ENV{GIT_WORK_TREE} = ".";
-    $ENV{GIT_INDEX_FILE} = $file_index;
-
     # Remember where the head was at the beginning.
     my $parenthash = `git show-ref -s refs/heads/$state->{module}`;
     chomp $parenthash;
     if ($parenthash !~ /^[0-9a-f]{40}$/) {
 	    print "error 1 pserver cannot find the current HEAD of module";
+	    cleanupWorkTree();
 	    exit;
     }
 
-    chdir $tmpdir;
+    setupWorkTree($parenthash);
 
-    # populate the temporary index
-    system("git-read-tree", $parenthash);
-    unless ($? == 0)
-    {
-	die "Error running git-read-tree $state->{module} $file_index $!";
-    }
-    $log->info("Created index '$file_index' for head $state->{module} - exit status $?");
+    $log->info("Lockless commit start, basing commit on '$work->{workDir}', index file is '$work->{index}'");
+
+    $log->info("Created index '$work->{index}' for head $state->{module} - exit status $?");
 
     my @committedfiles = ();
     my %oldmeta;
@@ -1271,7 +1298,7 @@
         {
             # fail everything if an up to date check fails
             print "error 1 Up to date check failed for $filename\n";
-            chdir "/";
+            cleanupWorkTree();
             exit;
         }
 
@@ -1313,7 +1340,7 @@
     {
         print "E No files to commit\n";
         print "ok\n";
-        chdir "/";
+        cleanupWorkTree();
         return;
     }
 
@@ -1336,7 +1363,7 @@
     {
         $log->warn("Commit failed (Invalid commit hash)");
         print "error 1 Commit failed (unknown reason)\n";
-        chdir "/";
+        cleanupWorkTree();
         exit;
     }
 
@@ -1348,7 +1375,7 @@
 		{
 			$log->warn("Commit failed (update hook declined to update ref)");
 			print "error 1 Commit failed (update hook declined)\n";
-			chdir "/";
+			cleanupWorkTree();
 			exit;
 		}
 	}
@@ -1358,6 +1385,7 @@
 			"refs/heads/$state->{module}", $commithash, $parenthash)) {
 		$log->warn("update-ref for $state->{module} failed.");
 		print "error 1 Cannot commit -- update first\n";
+		cleanupWorkTree();
 		exit;
 	}
 
@@ -1409,12 +1437,12 @@
             }
             print "Checked-in $dirpart\n";
             print "$filename\n";
-            my $kopts = kopts_from_path($filepart);
+            my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash});
             print "/$filepart/1.$meta->{revision}//$kopts/\n";
         }
     }
 
-    chdir "/";
+    cleanupWorkTree();
     print "ok\n";
 }
 
@@ -1757,15 +1785,9 @@
     argsfromdir($updater);
 
     # we'll need a temporary checkout dir
-    my $tmpdir = tempdir ( DIR => $TEMP_DIR );
-    my ( undef, $file_index ) = tempfile ( DIR => $TEMP_DIR, OPEN => 0 );
-    $log->info("Temp checkoutdir creation successful, basing annotate session work on '$tmpdir', index file is '$file_index'");
+    setupWorkTree();
 
-    $ENV{GIT_DIR} = $state->{CVSROOT} . "/";
-    $ENV{GIT_WORK_TREE} = ".";
-    $ENV{GIT_INDEX_FILE} = $file_index;
-
-    chdir $tmpdir;
+    $log->info("Temp checkoutdir creation successful, basing annotate session work on '$work->{workDir}', index file is '$ENV{GIT_INDEX_FILE}'");
 
     # foreach file specified on the command line ...
     foreach my $filename ( @{$state->{args}} )
@@ -1789,10 +1811,10 @@
 	system("git-read-tree", $lastseenin);
 	unless ($? == 0)
 	{
-	    print "E error running git-read-tree $lastseenin $file_index $!\n";
+	    print "E error running git-read-tree $lastseenin $ENV{GIT_INDEX_FILE} $!\n";
 	    return;
 	}
-	$log->info("Created index '$file_index' with commit $lastseenin - exit status $?");
+	$log->info("Created index '$ENV{GIT_INDEX_FILE}' with commit $lastseenin - exit status $?");
 
         # do a checkout of the file
         system('git-checkout-index', '-f', '-u', $filename);
@@ -1808,7 +1830,7 @@
         # git-jsannotate telling us about commits we are hiding
         # from the client.
 
-        my $a_hints = "$tmpdir/.annotate_hints";
+        my $a_hints = "$work->{workDir}/.annotate_hints";
         if (!open(ANNOTATEHINTS, '>', $a_hints)) {
             print "E failed to open '$a_hints' for writing: $!\n";
             return;
@@ -1862,7 +1884,7 @@
     }
 
     # done; get out of the tempdir
-    chdir "/";
+    cleanupWorkTree();
 
     print "ok\n";
 
@@ -2115,26 +2137,388 @@
     return $filename;
 }
 
+sub validateGitDir
+{
+    if( !defined($state->{CVSROOT}) )
+    {
+        print "error 1 CVSROOT not specified\n";
+        cleanupWorkTree();
+        exit;
+    }
+    if( $ENV{GIT_DIR} ne ($state->{CVSROOT} . '/') )
+    {
+        print "error 1 Internally inconsistent CVSROOT\n";
+        cleanupWorkTree();
+        exit;
+    }
+}
+
+# Setup working directory in a work tree with the requested version
+# loaded in the index.
+sub setupWorkTree
+{
+    my ($ver) = @_;
+
+    validateGitDir();
+
+    if( ( defined($work->{state}) && $work->{state} != 1 ) ||
+        defined($work->{tmpDir}) )
+    {
+        $log->warn("Bad work tree state management");
+        print "error 1 Internal setup multiple work trees without cleanup\n";
+        cleanupWorkTree();
+        exit;
+    }
+
+    $work->{workDir} = tempdir ( DIR => $TEMP_DIR );
+
+    if( !defined($work->{index}) )
+    {
+        (undef, $work->{index}) = tempfile ( DIR => $TEMP_DIR, OPEN => 0 );
+    }
+
+    chdir $work->{workDir} or
+        die "Unable to chdir to $work->{workDir}\n";
+
+    $log->info("Setting up GIT_WORK_TREE as '.' in '$work->{workDir}', index file is '$work->{index}'");
+
+    $ENV{GIT_WORK_TREE} = ".";
+    $ENV{GIT_INDEX_FILE} = $work->{index};
+    $work->{state} = 2;
+
+    if($ver)
+    {
+        system("git","read-tree",$ver);
+        unless ($? == 0)
+        {
+            $log->warn("Error running git-read-tree");
+            die "Error running git-read-tree $ver in $work->{workDir} $!\n";
+        }
+    }
+    # else # req_annotate reads tree for each file
+}
+
+# Ensure current directory is in some kind of working directory,
+# with a recent version loaded in the index.
+sub ensureWorkTree
+{
+    if( defined($work->{tmpDir}) )
+    {
+        $log->warn("Bad work tree state management [ensureWorkTree()]");
+        print "error 1 Internal setup multiple dirs without cleanup\n";
+        cleanupWorkTree();
+        exit;
+    }
+    if( $work->{state} )
+    {
+        return;
+    }
+
+    validateGitDir();
+
+    if( !defined($work->{emptyDir}) )
+    {
+        $work->{emptyDir} = tempdir ( DIR => $TEMP_DIR, OPEN => 0);
+    }
+    chdir $work->{emptyDir} or
+        die "Unable to chdir to $work->{emptyDir}\n";
+
+    my $ver = `git show-ref -s refs/heads/$state->{module}`;
+    chomp $ver;
+    if ($ver !~ /^[0-9a-f]{40}$/)
+    {
+        $log->warn("Error from git show-ref -s refs/head$state->{module}");
+        print "error 1 cannot find the current HEAD of module";
+        cleanupWorkTree();
+        exit;
+    }
+
+    if( !defined($work->{index}) )
+    {
+        (undef, $work->{index}) = tempfile ( DIR => $TEMP_DIR, OPEN => 0 );
+    }
+
+    $ENV{GIT_WORK_TREE} = ".";
+    $ENV{GIT_INDEX_FILE} = $work->{index};
+    $work->{state} = 1;
+
+    system("git","read-tree",$ver);
+    unless ($? == 0)
+    {
+        die "Error running git-read-tree $ver $!\n";
+    }
+}
+
+# Cleanup working directory that is not needed any longer.
+sub cleanupWorkTree
+{
+    if( ! $work->{state} )
+    {
+        return;
+    }
+
+    chdir "/" or die "Unable to chdir '/'\n";
+
+    if( defined($work->{workDir}) )
+    {
+        rmtree( $work->{workDir} );
+        undef $work->{workDir};
+    }
+    undef $work->{state};
+}
+
+# Setup a temporary directory (not a working tree), typically for
+# merging dirty state as in req_update.
+sub setupTmpDir
+{
+    $work->{tmpDir} = tempdir ( DIR => $TEMP_DIR );
+    chdir $work->{tmpDir} or die "Unable to chdir $work->{tmpDir}\n";
+
+    return $work->{tmpDir};
+}
+
+# Clean up a previously setupTmpDir.  Restore previous work tree if
+# appropriate.
+sub cleanupTmpDir
+{
+    if ( !defined($work->{tmpDir}) )
+    {
+        $log->warn("cleanup tmpdir that has not been setup");
+        die "Cleanup tmpDir that has not been setup\n";
+    }
+    if( defined($work->{state}) )
+    {
+        if( $work->{state} == 1 )
+        {
+            chdir $work->{emptyDir} or
+                die "Unable to chdir to $work->{emptyDir}\n";
+        }
+        elsif( $work->{state} == 2 )
+        {
+            chdir $work->{workDir} or
+                die "Unable to chdir to $work->{emptyDir}\n";
+        }
+        else
+        {
+            $log->warn("Inconsistent work dir state");
+            die "Inconsistent work dir state\n";
+        }
+    }
+    else
+    {
+        chdir "/" or die "Unable to chdir '/'\n";
+    }
+}
+
 # Given a path, this function returns a string containing the kopts
 # that should go into that path's Entries line.  For example, a binary
 # file should get -kb.
 sub kopts_from_path
 {
-	my ($path) = @_;
+    my ($path, $srcType, $name) = @_;
 
-	# Once it exists, the git attributes system should be used to look up
-	# what attributes apply to this path.
-
-	# Until then, take the setting from the config file
-    unless ( defined ( $cfg->{gitcvs}{allbinary} ) and $cfg->{gitcvs}{allbinary} =~ /^\s*(1|true|yes)\s*$/i )
+    if ( defined ( $cfg->{gitcvs}{usecrlfattr} ) and
+         $cfg->{gitcvs}{usecrlfattr} =~ /\s*(1|true|yes)\s*$/i )
     {
-		# Return "" to give no special treatment to any path
-		return "";
-    } else {
-		# Alternatively, to have all files treated as if they are binary (which
-		# is more like git itself), always return the "-kb" option
-		return "-kb";
+        my ($val) = check_attr( "crlf", $path );
+        if ( $val eq "set" )
+        {
+            return "";
+        }
+        elsif ( $val eq "unset" )
+        {
+            return "-kb"
+        }
+        else
+        {
+            $log->info("Unrecognized check_attr crlf $path : $val");
+        }
     }
+
+    if ( defined ( $cfg->{gitcvs}{allbinary} ) )
+    {
+        if( ($cfg->{gitcvs}{allbinary} =~ /^\s*(1|true|yes)\s*$/i) )
+        {
+            return "-kb";
+        }
+        elsif( ($cfg->{gitcvs}{allbinary} =~ /^\s*guess\s*$/i) )
+        {
+            if( $srcType eq "sha1Or-k" &&
+                !defined($name) )
+            {
+                my ($ret)=$state->{entries}{$path}{options};
+                if( !defined($ret) )
+                {
+                    $ret=$state->{opt}{k};
+                    if(defined($ret))
+                    {
+                        $ret="-k$ret";
+                    }
+                    else
+                    {
+                        $ret="";
+                    }
+                }
+                if( ! ($ret=~/^(|-kb|-kkv|-kkvl|-kk|-ko|-kv)$/) )
+                {
+                    print "E Bad -k option\n";
+                    $log->warn("Bad -k option: $ret");
+                    die "Error: Bad -k option: $ret\n";
+                }
+
+                return $ret;
+            }
+            else
+            {
+                if( is_binary($srcType,$name) )
+                {
+                    $log->debug("... as binary");
+                    return "-kb";
+                }
+                else
+                {
+                    $log->debug("... as text");
+                }
+            }
+        }
+    }
+    # Return "" to give no special treatment to any path
+    return "";
+}
+
+sub check_attr
+{
+    my ($attr,$path) = @_;
+    ensureWorkTree();
+    if ( open my $fh, '-|', "git", "check-attr", $attr, "--", $path )
+    {
+        my $val = <$fh>;
+        close $fh;
+        $val =~ s/.*: ([^:\r\n]*)\s*$/$1/;
+        return $val;
+    }
+    else
+    {
+        return undef;
+    }
+}
+
+# This should have the same heuristics as convert.c:is_binary() and related.
+# Note that the bare CR test is done by callers in convert.c.
+sub is_binary
+{
+    my ($srcType,$name) = @_;
+    $log->debug("is_binary($srcType,$name)");
+
+    # Minimize amount of interpreted code run in the inner per-character
+    # loop for large files, by totalling each character value and
+    # then analyzing the totals.
+    my @counts;
+    my $i;
+    for($i=0;$i<256;$i++)
+    {
+        $counts[$i]=0;
+    }
+
+    my $fh = open_blob_or_die($srcType,$name);
+    my $line;
+    while( defined($line=<$fh>) )
+    {
+        # Any '\0' and bare CR are considered binary.
+        if( $line =~ /\0|(\r[^\n])/ )
+        {
+            close($fh);
+            return 1;
+        }
+
+        # Count up each character in the line:
+        my $len=length($line);
+        for($i=0;$i<$len;$i++)
+        {
+            $counts[ord(substr($line,$i,1))]++;
+        }
+    }
+    close $fh;
+
+    # Don't count CR and LF as either printable/nonprintable
+    $counts[ord("\n")]=0;
+    $counts[ord("\r")]=0;
+
+    # Categorize individual character count into printable and nonprintable:
+    my $printable=0;
+    my $nonprintable=0;
+    for($i=0;$i<256;$i++)
+    {
+        if( $i < 32 &&
+            $i != ord("\b") &&
+            $i != ord("\t") &&
+            $i != 033 &&       # ESC
+            $i != 014 )        # FF
+        {
+            $nonprintable+=$counts[$i];
+        }
+        elsif( $i==127 )  # DEL
+        {
+            $nonprintable+=$counts[$i];
+        }
+        else
+        {
+            $printable+=$counts[$i];
+        }
+    }
+
+    return ($printable >> 7) < $nonprintable;
+}
+
+# Returns open file handle.  Possible invocations:
+#  - open_blob_or_die("file",$filename);
+#  - open_blob_or_die("sha1",$filehash);
+sub open_blob_or_die
+{
+    my ($srcType,$name) = @_;
+    my ($fh);
+    if( $srcType eq "file" )
+    {
+        if( !open $fh,"<",$name )
+        {
+            $log->warn("Unable to open file $name: $!");
+            die "Unable to open file $name: $!\n";
+        }
+    }
+    elsif( $srcType eq "sha1" || $srcType eq "sha1Or-k" )
+    {
+        unless ( defined ( $name ) and $name =~ /^[a-zA-Z0-9]{40}$/ )
+        {
+            $log->warn("Need filehash");
+            die "Need filehash\n";
+        }
+
+        my $type = `git cat-file -t $name`;
+        chomp $type;
+
+        unless ( defined ( $type ) and $type eq "blob" )
+        {
+            $log->warn("Invalid type '$type' for '$name'");
+            die ( "Invalid type '$type' (expected 'blob')" )
+        }
+
+        my $size = `git cat-file -s $name`;
+        chomp $size;
+
+        $log->debug("open_blob_or_die($name) size=$size, type=$type");
+
+        unless( open $fh, '-|', "git", "cat-file", "blob", $name )
+        {
+            $log->warn("Unable to open sha1 $name");
+            die "Unable to open sha1 $name\n";
+        }
+    }
+    else
+    {
+        $log->warn("Unknown type of blob source: $srcType");
+        die "Unknown type of blob source: $srcType\n";
+    }
+    return $fh;
 }
 
 # Generate a CVS author name from Git author information, by taking
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index d846cd9..d04c346 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -406,8 +406,22 @@
 		echo "$ref -> $new_ref ($sha1 -> $new_sha1)"
 
 		if [ "$type" = "tag" ]; then
-			# Warn that we are not rewriting the tag object itself.
-			warn "unreferencing tag object $sha1t"
+			new_sha1=$(git cat-file tag "$ref" |
+				sed -n \
+				    -e "1,/^$/{
+					  s/^object .*/object $new_sha1/
+					  s/^type .*/type commit/
+					  s/^tag .*/tag $new_ref/
+					}" \
+				    -e '/^-----BEGIN PGP SIGNATURE-----/q' \
+				    -e 'p' |
+				git mktag) ||
+				die "Could not create new tag object for $ref"
+			if git cat-file tag "$ref" | \
+			   grep '^-----BEGIN PGP SIGNATURE-----' >/dev/null 2>&1
+			then
+				warn "gpg signature stripped from tag object $sha1t"
+			fi
 		fi
 
 		git update-ref "refs/tags/$new_ref" "$new_sha1" ||
@@ -421,11 +435,17 @@
 trap - 0
 
 unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE
-test -z "$ORIG_GIT_DIR" || GIT_DIR="$ORIG_GIT_DIR" && export GIT_DIR
-test -z "$ORIG_GIT_WORK_TREE" || GIT_WORK_TREE="$ORIG_GIT_WORK_TREE" &&
+test -z "$ORIG_GIT_DIR" || {
+	GIT_DIR="$ORIG_GIT_DIR" && export GIT_DIR
+}
+test -z "$ORIG_GIT_WORK_TREE" || {
+	GIT_WORK_TREE="$ORIG_GIT_WORK_TREE" &&
 	export GIT_WORK_TREE
-test -z "$ORIG_GIT_INDEX_FILE" || GIT_INDEX_FILE="$ORIG_GIT_INDEX_FILE" &&
+}
+test -z "$ORIG_GIT_INDEX_FILE" || {
+	GIT_INDEX_FILE="$ORIG_GIT_INDEX_FILE" &&
 	export GIT_INDEX_FILE
+}
 git read-tree -u -m HEAD
 
 exit $ret
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 7c25bb9..e6e8890 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -122,6 +122,14 @@
 set _iscygwin {}
 set _search_path {}
 
+set _trace [lsearch -exact $argv --trace]
+if {$_trace >= 0} {
+	set argv [lreplace $argv $_trace $_trace]
+	set _trace 1
+} else {
+	set _trace 0
+}
+
 proc appname {} {
 	global _appname
 	return $_appname
@@ -245,6 +253,21 @@
 ##
 ## handy utils
 
+proc _trace_exec {cmd} {
+	if {!$::_trace} return
+	set d {}
+	foreach v $cmd {
+		if {$d ne {}} {
+			append d { }
+		}
+		if {[regexp {[ \t\r\n'"$?*]} $v]} {
+			set v [sq $v]
+		}
+		append d $v
+	}
+	puts stderr $d
+}
+
 proc _git_cmd {name} {
 	global _git_cmd_path
 
@@ -339,7 +362,7 @@
 }
 
 proc git {args} {
-	set opt [list exec]
+	set opt [list]
 
 	while {1} {
 		switch -- [lindex $args 0] {
@@ -359,12 +382,18 @@
 	set cmdp [_git_cmd [lindex $args 0]]
 	set args [lrange $args 1 end]
 
-	return [eval $opt $cmdp $args]
+	_trace_exec [concat $opt $cmdp $args]
+	set result [eval exec $opt $cmdp $args]
+	if {$::_trace} {
+		puts stderr "< $result"
+	}
+	return $result
 }
 
 proc _open_stdout_stderr {cmd} {
+	_trace_exec $cmd
 	if {[catch {
-			set fd [open $cmd r]
+			set fd [open [concat [list | ] $cmd] r]
 		} err]} {
 		if {   [lindex $cmd end] eq {2>@1}
 		    && $err eq {can not find channel named "1"}
@@ -375,6 +404,7 @@
 			# to try to start it a second time.
 			#
 			set fd [open [concat \
+				[list | ] \
 				[lrange $cmd 0 end-1] \
 				[list |& cat] \
 				] r]
@@ -387,7 +417,7 @@
 }
 
 proc git_read {args} {
-	set opt [list |]
+	set opt [list]
 
 	while {1} {
 		switch -- [lindex $args 0] {
@@ -415,7 +445,7 @@
 }
 
 proc git_write {args} {
-	set opt [list |]
+	set opt [list]
 
 	while {1} {
 		switch -- [lindex $args 0] {
@@ -435,7 +465,8 @@
 	set cmdp [_git_cmd [lindex $args 0]]
 	set args [lrange $args 1 end]
 
-	return [open [concat $opt $cmdp $args] w]
+	_trace_exec [concat $opt $cmdp $args]
+	return [open [concat [list | ] $opt $cmdp $args] w]
 }
 
 proc githook_read {hook_name args} {
@@ -455,12 +486,12 @@
 		}
 
 		set scr {if test -x "$1";then exec "$@";fi}
-		set sh_c [list | $interp -c $scr $interp $pchook]
+		set sh_c [list $interp -c $scr $interp $pchook]
 		return [_open_stdout_stderr [concat $sh_c $args]]
 	}
 
 	if {[file executable $pchook]} {
-		return [_open_stdout_stderr [concat [list | $pchook] $args]]
+		return [_open_stdout_stderr [concat [list $pchook] $args]]
 	}
 
 	return {}
@@ -601,6 +632,7 @@
 	}
 }
 
+set default_config(branch.autosetupmerge) true
 set default_config(merge.diffstat) true
 set default_config(merge.summary) false
 set default_config(merge.verbosity) 2
@@ -1095,27 +1127,18 @@
 }
 
 if {[is_Cygwin]} {
-	set is_git_info_link {}
 	set is_git_info_exclude {}
 	proc have_info_exclude {} {
-		global is_git_info_link is_git_info_exclude
+		global is_git_info_exclude
 
-		if {$is_git_info_link eq {}} {
-			set is_git_info_link [file isfile [gitdir info.lnk]]
-		}
-
-		if {$is_git_info_link} {
-			if {$is_git_info_exclude eq {}} {
-				if {[catch {exec test -f [gitdir info exclude]}]} {
-					set is_git_info_exclude 0
-				} else {
-					set is_git_info_exclude 1
-				}
+		if {$is_git_info_exclude eq {}} {
+			if {[catch {exec test -f [gitdir info exclude]}]} {
+				set is_git_info_exclude 0
+			} else {
+				set is_git_info_exclude 1
 			}
-			return $is_git_info_exclude
-		} else {
-			return [file readable [gitdir info exclude]]
 		}
+		return $is_git_info_exclude
 	}
 } else {
 	proc have_info_exclude {} {
diff --git a/git-gui/lib/branch_create.tcl b/git-gui/lib/branch_create.tcl
index 53dfb4c..3817771 100644
--- a/git-gui/lib/branch_create.tcl
+++ b/git-gui/lib/branch_create.tcl
@@ -183,6 +183,9 @@
 	if {$spec ne {} && $opt_fetch} {
 		$co enable_fetch $spec
 	}
+	if {$spec ne {}} {
+		$co remote_source $spec
+	}
 
 	if {[$co run]} {
 		destroy $w
diff --git a/git-gui/lib/branch_delete.tcl b/git-gui/lib/branch_delete.tcl
index 86c4f73..ef1930b 100644
--- a/git-gui/lib/branch_delete.tcl
+++ b/git-gui/lib/branch_delete.tcl
@@ -127,7 +127,7 @@
 	foreach i $to_delete {
 		set b [lindex $i 0]
 		set o [lindex $i 1]
-		if {[catch {git update-ref -d "refs/heads/$b" $o} err]} {
+		if {[catch {git branch -D $b} err]} {
 			append failed " - $b: $err\n"
 		}
 	}
diff --git a/git-gui/lib/checkout_op.tcl b/git-gui/lib/checkout_op.tcl
index 6e14117..caca888 100644
--- a/git-gui/lib/checkout_op.tcl
+++ b/git-gui/lib/checkout_op.tcl
@@ -16,6 +16,7 @@
 field fetch_spec   {}; # refetch tracking branch if used?
 field checkout      1; # actually checkout the branch?
 field create        0; # create the branch if it doesn't exist?
+field remote_source {}; # same as fetch_spec, to setup tracking
 
 field reset_ok      0; # did the user agree to reset?
 field fetch_ok      0; # did the fetch succeed?
@@ -44,6 +45,10 @@
 	set fetch_spec $spec
 }
 
+method remote_source {spec} {
+	set remote_source $spec
+}
+
 method enable_checkout {co} {
 	set checkout $co
 }
@@ -145,7 +150,7 @@
 }
 
 method _update_ref {} {
-	global null_sha1 current_branch
+	global null_sha1 current_branch repo_config
 
 	set ref $new_ref
 	set new $new_hash
@@ -172,6 +177,23 @@
 
 		set reflog_msg "branch: Created from $new_expr"
 		set cur $null_sha1
+
+		if {($repo_config(branch.autosetupmerge) eq {true}
+			|| $repo_config(branch.autosetupmerge) eq {always})
+			&& $remote_source ne {}
+			&& "refs/heads/$newbranch" eq $ref} {
+
+			set c_remote [lindex $remote_source 1]
+			set c_merge [lindex $remote_source 2]
+			if {[catch {
+					git config branch.$newbranch.remote $c_remote
+					git config branch.$newbranch.merge  $c_merge
+				} err]} {
+				_error $this [strcat \
+				[mc "Failed to configure simplified git-pull for '%s'." $newbranch] \
+				"\n\n$err"]
+			}
+		}
 	} elseif {$create && $merge_type eq {none}} {
 		# We were told to create it, but not do a merge.
 		# Bad.  Name shouldn't have existed.
diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl
index ae4a4cd..3180786 100644
--- a/git-gui/lib/choose_repository.tcl
+++ b/git-gui/lib/choose_repository.tcl
@@ -388,9 +388,7 @@
 		-command [cb _new_local_path]
 	set w_localpath $w_body.where.t
 
-	pack $w_body.where.b -side right
-	pack $w_body.where.l -side left
-	pack $w_body.where.t -fill x
+	grid $w_body.where.l $w_body.where.t $w_body.where.b -sticky ew
 	pack $w_body.where -fill x
 
 	trace add variable @local_path write [cb _write_local_path]
@@ -987,9 +985,7 @@
 		-text [mc "Browse"] \
 		-command [cb _open_local_path]
 
-	pack $w_body.where.b -side right
-	pack $w_body.where.l -side left
-	pack $w_body.where.t -fill x
+	grid $w_body.where.l $w_body.where.t $w_body.where.b -sticky ew
 	pack $w_body.where -fill x
 
 	trace add variable @local_path write [cb _write_local_path]
diff --git a/git-gui/lib/database.tcl b/git-gui/lib/database.tcl
index d66aa3f..a18ac8b 100644
--- a/git-gui/lib/database.tcl
+++ b/git-gui/lib/database.tcl
@@ -102,8 +102,8 @@
 		*]]
 
 	if {$objects_current >= $object_limit} {
-		set objects_current [expr {$objects_current * 256}]
-		set object_limit    [expr {$object_limit    * 256}]
+		set objects_current [expr {$objects_current * 250}]
+		set object_limit    [expr {$object_limit    * 250}]
 		if {[ask_popup \
 			[mc "This repository currently has approximately %i loose objects.
 
diff --git a/git-gui/lib/spellcheck.tcl b/git-gui/lib/spellcheck.tcl
index 9be7486..78f344f 100644
--- a/git-gui/lib/spellcheck.tcl
+++ b/git-gui/lib/spellcheck.tcl
@@ -84,13 +84,19 @@
 	regexp \
 		{International Ispell Version .* \(but really (Aspell .*?)\)$} \
 		$s_version _junk s_version
+	regexp {^Aspell (\d)+\.(\d+)} $s_version _junk major minor
 
 	puts $pipe_fd !             ; # enable terse mode
-	puts $pipe_fd {$$cr master} ; # fetch the language
-	flush $pipe_fd
 
-	gets $pipe_fd s_lang
-	regexp {[/\\]([^/\\]+)\.[^\.]+$} $s_lang _ s_lang
+	# fetch the language
+	if {$major > 0 || ($major == 0 && $minor >= 60)} {
+		puts $pipe_fd {$$cr master}
+		flush $pipe_fd
+		gets $pipe_fd s_lang
+		regexp {[/\\]([^/\\]+)\.[^\.]+$} $s_lang _ s_lang
+	} else {
+		set s_lang {}
+	}
 
 	if {$::default_config(gui.spellingdictionary) eq {}
 	 && [get_config gui.spellingdictionary] eq {}} {
diff --git a/git-gui/po/de.po b/git-gui/po/de.po
index 022b816..f20955c 100644
--- a/git-gui/po/de.po
+++ b/git-gui/po/de.po
@@ -8,7 +8,7 @@
 "Project-Id-Version: git-gui\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2008-03-14 07:18+0100\n"
-"PO-Revision-Date: 2008-02-16 21:52+0100\n"
+"PO-Revision-Date: 2008-05-01 11:51+0200\n"
 "Last-Translator: Christian Stimming <stimming@tuhh.de>\n"
 "Language-Team: German\n"
 "MIME-Version: 1.0\n"
@@ -1754,9 +1754,8 @@
 msgstr "Anzahl der Kontextzeilen beim Vergleich"
 
 #: lib/option.tcl:127
-#, fuzzy
 msgid "Commit Message Text Width"
-msgstr "Versionsbeschreibung:"
+msgstr "Textbreite der Versionsbeschreibung"
 
 #: lib/option.tcl:128
 msgid "New Branch Name Template"
@@ -1895,40 +1894,36 @@
 
 #: lib/spellcheck.tcl:57
 msgid "Unsupported spell checker"
-msgstr ""
+msgstr "Rechtschreibprüfungsprogramm nicht unterstützt"
 
 #: lib/spellcheck.tcl:65
-#, fuzzy
 msgid "Spell checking is unavailable"
-msgstr "Rechtschreibprüfung fehlgeschlagen"
+msgstr "Rechtschreibprüfung nicht verfügbar"
 
 #: lib/spellcheck.tcl:68
 msgid "Invalid spell checking configuration"
-msgstr ""
+msgstr "Unbenutzbare Konfiguration der Rechtschreibprüfung"
 
 #: lib/spellcheck.tcl:70
 #, tcl-format
 msgid "Reverting dictionary to %s."
-msgstr ""
+msgstr "Wörterbuch auf %s zurückgesetzt."
 
 #: lib/spellcheck.tcl:73
-#, fuzzy
 msgid "Spell checker silently failed on startup"
-msgstr "Rechtschreibprüfung fehlgeschlagen"
+msgstr "Rechtschreibprüfungsprogramm mit Fehler abgebrochen"
 
 #: lib/spellcheck.tcl:80
-#, fuzzy
 msgid "Unrecognized spell checker"
-msgstr "Unbekannte Version von »aspell«"
+msgstr "Unbekanntes Rechtschreibprüfungsprogramm"
 
 #: lib/spellcheck.tcl:180
 msgid "No Suggestions"
 msgstr "Keine Vorschläge"
 
 #: lib/spellcheck.tcl:381
-#, fuzzy
 msgid "Unexpected EOF from spell checker"
-msgstr "Unerwartetes EOF von »aspell«"
+msgstr "Unerwartetes EOF vom Rechtschreibprüfungsprogramm"
 
 #: lib/spellcheck.tcl:385
 msgid "Spell Checker Failed"
@@ -2002,6 +1997,3 @@
 #: lib/transport.tcl:168
 msgid "Include tags"
 msgstr "Mit Markierungen übertragen"
-
-#~ msgid "Not connected to aspell"
-#~ msgstr "Keine Verbindung zu »aspell«"
diff --git a/git-instaweb.sh b/git-instaweb.sh
index 6f91c8f..af0fde5 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -22,10 +22,10 @@
 . git-sh-setup
 
 fqgitdir="$GIT_DIR"
-local="`git config --bool --get instaweb.local`"
-httpd="`git config --get instaweb.httpd`"
-port=`git config --get instaweb.port`
-module_path="`git config --get instaweb.modulepath`"
+local="$(git config --bool --get instaweb.local)"
+httpd="$(git config --get instaweb.httpd)"
+port=$(git config --get instaweb.port)
+module_path="$(git config --get instaweb.modulepath)"
 
 conf="$GIT_DIR/gitweb/httpd.conf"
 
@@ -37,11 +37,21 @@
 # any untaken local port will do...
 test -z "$port" && port=1234
 
-start_httpd () {
-	httpd_only="`echo $httpd | cut -f1 -d' '`"
+resolve_full_httpd () {
+	case "$httpd" in
+	*apache2*|*lighttpd*)
+		# ensure that the apache2/lighttpd command ends with "-f"
+		if ! echo "$httpd" | grep -- '-f *$' >/dev/null 2>&1
+		then
+			httpd="$httpd -f"
+		fi
+		;;
+	esac
+
+	httpd_only="$(echo $httpd | cut -f1 -d' ')"
 	if case "$httpd_only" in /*) : ;; *) which $httpd_only >/dev/null;; esac
 	then
-		$httpd "$fqgitdir/gitweb/httpd.conf"
+		full_httpd=$httpd
 	else
 		# many httpds are installed in /usr/sbin or /usr/local/sbin
 		# these days and those are not in most users $PATHs
@@ -51,16 +61,23 @@
 		do
 			if test -x "$i/$httpd_only"
 			then
-				# don't quote $httpd, there can be
-				# arguments to it (-f)
-				$i/$httpd "$fqgitdir/gitweb/httpd.conf"
+				full_httpd=$i/$httpd
 				return
 			fi
 		done
-		echo "$httpd_only not found. Install $httpd_only or use" \
-		     "--httpd to specify another http daemon."
+
+		echo >&2 "$httpd_only not found. Install $httpd_only or use" \
+		     "--httpd to specify another httpd daemon."
 		exit 1
 	fi
+}
+
+start_httpd () {
+	# here $httpd should have a meaningful value
+	resolve_full_httpd
+
+	# don't quote $full_httpd, there can be arguments to it (-f)
+	$full_httpd "$fqgitdir/gitweb/httpd.conf"
 	if test $? != 0; then
 		echo "Could not execute http daemon $httpd."
 		exit 1
@@ -68,7 +85,7 @@
 }
 
 stop_httpd () {
-	test -f "$fqgitdir/pid" && kill `cat "$fqgitdir/pid"`
+	test -f "$fqgitdir/pid" && kill $(cat "$fqgitdir/pid")
 }
 
 while test $# != 0
@@ -116,7 +133,7 @@
 done
 
 mkdir -p "$GIT_DIR/gitweb/tmp"
-GIT_EXEC_PATH="`git --exec-path`"
+GIT_EXEC_PATH="$(git --exec-path)"
 GIT_DIR="$fqgitdir"
 export GIT_EXEC_PATH GIT_DIR
 
@@ -215,7 +232,8 @@
 EOF
 	else
 		# plain-old CGI
-		list_mods=`echo "$httpd" | sed "s/-f$/-l/"`
+		resolve_full_httpd
+		list_mods=$(echo "$full_httpd" | sed "s/-f$/-l/")
 		$list_mods | grep 'mod_cgi\.c' >/dev/null 2>&1 || \
 		echo "LoadModule cgi_module $module_path/mod_cgi.so" >> "$conf"
 		cat >> "$conf" <<EOF
diff --git a/git-merge.sh b/git-merge.sh
index 7dbbb1d..8026ccf 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -8,10 +8,12 @@
 git-merge [options] <remote>...
 git-merge [options] <msg> HEAD <remote>
 --
-summary              show a diffstat at the end of the merge
-n,no-summary         don't show a diffstat at the end of the merge
+stat                 show a diffstat at the end of the merge
+n                    don't show a diffstat at the end of the merge
+summary              (synonym to --stat)
+log                  add list of one-line log to merge commit message
 squash               create a single commit instead of doing a merge
-commit               perform a commit if the merge sucesses (default)
+commit               perform a commit if the merge succeeds (default)
 ff                   allow fast forward (default)
 s,strategy=          merge strategy to use
 m,message=           message to be used for the merge commit (if any)
@@ -37,7 +39,7 @@
 
 allow_fast_forward=t
 allow_trivial_merge=t
-squash= no_commit=
+squash= no_commit= log_arg=
 
 dropsave() {
 	rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" \
@@ -148,10 +150,12 @@
 parse_config () {
 	while test $# != 0; do
 		case "$1" in
-		-n|--no-summary)
+		-n|--no-stat|--no-summary)
 			show_diffstat=false ;;
-		--summary)
+		--stat|--summary)
 			show_diffstat=t ;;
+		--log|--no-log)
+			log_arg=$1 ;;
 		--squash)
 			test "$allow_fast_forward" = t ||
 				die "You cannot combine --squash with --no-ff."
@@ -210,6 +214,7 @@
 
 if test -z "$show_diffstat"; then
     test "$(git config --bool merge.diffstat)" = false && show_diffstat=false
+    test "$(git config --bool merge.stat)" = false && show_diffstat=false
     test -z "$show_diffstat" && show_diffstat=t
 fi
 
@@ -258,7 +263,7 @@
 	merge_name=$(for remote
 		do
 			merge_name "$remote"
-		done | git fmt-merge-msg
+		done | git fmt-merge-msg $log_arg
 	)
 	merge_msg="${merge_msg:+$merge_msg$LF$LF}$merge_name"
 fi
diff --git a/git-mergetool.sh b/git-mergetool.sh
index 5c86f69..fcdec4a 100755
--- a/git-mergetool.sh
+++ b/git-mergetool.sh
@@ -237,9 +237,9 @@
 	ecmerge)
 	    touch "$BACKUP"
 	    if base_present; then
-		"$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --mode=merge3 --to="$MERGED"
+		"$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --default --mode=merge3 --to="$MERGED"
 	    else
-		"$merge_tool_path" "$LOCAL" "$REMOTE" --mode=merge2 --to="$MERGED"
+		"$merge_tool_path" "$LOCAL" "$REMOTE" --default --mode=merge2 --to="$MERGED"
 	    fi
 	    check_unchanged
 	    ;;
diff --git a/git-pull.sh b/git-pull.sh
index 3ce32b5..809e537 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -4,7 +4,7 @@
 #
 # Fetch one or more remote refs and merge it/them into the current HEAD.
 
-USAGE='[-n | --no-summary] [--[no-]commit] [--[no-]squash] [--[no-]ff] [-s strategy]... [<fetch-options>] <repo> <head>...'
+USAGE='[-n | --no-stat] [--[no-]commit] [--[no-]squash] [--[no-]ff] [-s strategy]... [<fetch-options>] <repo> <head>...'
 LONG_USAGE='Fetch one or more remote refs and merge it/them into the current HEAD.'
 SUBDIRECTORY_OK=Yes
 OPTIONS_SPEC=
@@ -16,19 +16,19 @@
 test -z "$(git ls-files -u)" ||
 	die "You are in the middle of a conflicted merge."
 
-strategy_args= no_summary= no_commit= squash= no_ff=
+strategy_args= no_stat= no_commit= squash= no_ff= log_arg=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short=$(echo "$curr_branch" | sed "s|refs/heads/||")
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
 while :
 do
 	case "$1" in
-	-n|--n|--no|--no-|--no-s|--no-su|--no-sum|--no-summ|\
-		--no-summa|--no-summar|--no-summary)
-		no_summary=-n ;;
-	--summary)
-		no_summary=$1
-		;;
+	-n|--no-stat|--no-summary)
+		no_stat=-n ;;
+	--stat|--summary)
+		no_stat=$1 ;;
+	--log|--no-log)
+		log_arg=$1 ;;
 	--no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit)
 		no_commit=--no-commit ;;
 	--c|--co|--com|--comm|--commi|--commit)
@@ -107,6 +107,11 @@
 }
 
 test true = "$rebase" && {
+	git update-index --refresh &&
+	git diff-files --quiet &&
+	git diff-index --cached --quiet HEAD -- ||
+	die "refusing to pull with rebase: your working tree is not up-to-date"
+
 	. git-parse-remote &&
 	origin="$1"
 	test -z "$origin" && origin=$(get_default_remote)
@@ -172,9 +177,9 @@
 	exit
 fi
 
-merge_name=$(git fmt-merge-msg <"$GIT_DIR/FETCH_HEAD") || exit
+merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 test true = "$rebase" &&
 	exec git-rebase $strategy_args --onto $merge_head \
 	${oldremoteref:-$merge_head}
-exec git-merge $no_summary $no_commit $squash $no_ff $strategy_args \
+exec git-merge $no_stat $no_commit $squash $no_ff $log_arg $strategy_args \
 	"$merge_name" HEAD $merge_head
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 8aa7371..e3f65bd 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -56,9 +56,9 @@
 require_clean_work_tree () {
 	# test if working tree is dirty
 	git rev-parse --verify HEAD > /dev/null &&
-	git update-index --refresh &&
-	git diff-files --quiet &&
-	git diff-index --cached --quiet HEAD -- ||
+	git update-index --ignore-submodules --refresh &&
+	git diff-files --quiet --ignore-submodules &&
+	git diff-index --cached --quiet HEAD --ignore-submodules -- ||
 	die "Working tree is dirty"
 }
 
@@ -162,6 +162,8 @@
 				new_parents="$new_parents $new_p"
 				;;
 			esac
+		else
+			new_parents="$new_parents $p"
 		fi
 	done
 	case $fast_forward in
@@ -377,11 +379,12 @@
 		# Sanity check
 		git rev-parse --verify HEAD >/dev/null ||
 			die "Cannot read HEAD"
-		git update-index --refresh && git diff-files --quiet ||
+		git update-index --ignore-submodules --refresh &&
+			git diff-files --quiet --ignore-submodules ||
 			die "Working tree is dirty"
 
 		# do we have anything to commit?
-		if git diff-index --cached --quiet HEAD --
+		if git diff-index --cached --quiet --ignore-submodules HEAD --
 		then
 			: Nothing to commit -- skip this
 		else
@@ -474,6 +477,9 @@
 
 		require_clean_work_tree
 
+		UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base"
+		test -z "$ONTO" && ONTO=$UPSTREAM
+
 		if test ! -z "$2"
 		then
 			output git show-ref --verify --quiet "refs/heads/$2" ||
@@ -483,12 +489,8 @@
 		fi
 
 		HEAD=$(git rev-parse --verify HEAD) || die "No HEAD?"
-		UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base"
-
 		mkdir "$DOTEST" || die "Could not create temporary $DOTEST"
 
-		test -z "$ONTO" && ONTO=$UPSTREAM
-
 		: > "$DOTEST"/interactive || die "Could not mark as interactive"
 		git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null ||
 			echo "detached HEAD" > "$DOTEST"/head-name
@@ -530,9 +532,9 @@
 # Rebase $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO
 #
 # Commands:
-#  pick = use commit
-#  edit = use commit, but stop for amending
-#  squash = use commit, but meld into previous commit
+#  p, pick = use commit
+#  e, edit = use commit, but stop for amending
+#  s, squash = use commit, but meld into previous commit
 #
 # If you remove a line here THAT COMMIT WILL BE LOST.
 # However, if you remove everything, the rebase will be aborted.
diff --git a/git-rebase.sh b/git-rebase.sh
index 60c458f..e2d85ee 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -60,7 +60,7 @@
 	fi
 
 	cmt=`cat "$dotest/current"`
-	if ! git diff-index --quiet HEAD --
+	if ! git diff-index --quiet --ignore-submodules HEAD --
 	then
 		if ! git commit --no-verify -C "$cmt"
 		then
@@ -150,7 +150,10 @@
 do
 	case "$1" in
 	--continue)
-		git diff-files --quiet || {
+		test -d "$dotest" -o -d .dotest ||
+			die "No rebase in progress?"
+
+		git diff-files --quiet --ignore-submodules || {
 			echo "You must edit all merge conflicts and then"
 			echo "mark them as resolved using git add"
 			exit 1
@@ -178,6 +181,9 @@
 		exit
 		;;
 	--skip)
+		test -d "$dotest" -o -d .dotest ||
+			die "No rebase in progress?"
+
 		git reset --hard HEAD || exit $?
 		if test -d "$dotest"
 		then
@@ -203,18 +209,18 @@
 		exit
 		;;
 	--abort)
+		test -d "$dotest" -o -d .dotest ||
+			die "No rebase in progress?"
+
 		git rerere clear
 		if test -d "$dotest"
 		then
 			move_to_original_branch
-		elif test -d .dotest
-		then
+		else
 			dotest=.dotest
 			move_to_original_branch
-		else
-			die "No rebase in progress?"
 		fi
-		git reset --hard $(cat $dotest/orig-head)
+		git reset --hard $(cat "$dotest/orig-head")
 		rm -r "$dotest"
 		exit
 		;;
@@ -282,8 +288,8 @@
 fi
 
 # The tree must be really really clean.
-git update-index --refresh || exit
-diff=$(git diff-index --cached --name-status -r HEAD --)
+git update-index --ignore-submodules --refresh || exit
+diff=$(git diff-index --cached --name-status -r --ignore-submodules HEAD --)
 case "$diff" in
 ?*)	echo "cannot rebase: your index is not up-to-date"
 	echo "$diff"
@@ -309,22 +315,42 @@
 	}
 fi
 
-# If the branch to rebase is given, first switch to it.
+# If the branch to rebase is given, that is the branch we will rebase
+# $branch_name -- branch being rebased, or HEAD (already detached)
+# $orig_head -- commit object name of tip of the branch before rebasing
+# $head_name -- refs/heads/<that-branch> or "detached HEAD"
+switch_to=
 case "$#" in
 2)
+	# Is it "rebase other $branchname" or "rebase other $commit"?
 	branch_name="$2"
-	git-checkout "$2" || usage
-	;;
-*)
-	if branch_name=`git symbolic-ref -q HEAD`
+	switch_to="$2"
+
+	if git show-ref --verify --quiet -- "refs/heads/$2" &&
+	   branch=$(git rev-parse --verify "refs/heads/$2" 2>/dev/null)
 	then
-		branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
+		head_name="refs/heads/$2"
+	elif branch=$(git rev-parse --verify "$2" 2>/dev/null)
+	then
+		head_name="detached HEAD"
 	else
-		branch_name=HEAD ;# detached
+		usage
 	fi
 	;;
+*)
+	# Do not need to switch branches, we are already on it.
+	if branch_name=`git symbolic-ref -q HEAD`
+	then
+		head_name=$branch_name
+		branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
+	else
+		head_name="detached HEAD"
+		branch_name=HEAD ;# detached
+	fi
+	branch=$(git rev-parse --verify "${branch_name}^0") || exit
+	;;
 esac
-branch=$(git rev-parse --verify "${branch_name}^0") || exit
+orig_head=$branch
 
 # Now we are rebasing commits $upstream..$branch on top of $onto
 
@@ -333,8 +359,10 @@
 mb=$(git merge-base "$onto" "$branch")
 if test "$upstream" = "$onto" && test "$mb" = "$onto" &&
 	# linear history?
-	! git rev-list --parents "$onto".."$branch" | grep " .* " > /dev/null
+	! (git rev-list --parents "$onto".."$branch" | grep " .* ") > /dev/null
 then
+	# Lazily switch to the target branch if needed...
+	test -z "$switch_to" || git checkout "$switch_to"
 	echo >&2 "Current branch $branch_name is up to date."
 	exit 0
 fi
@@ -346,22 +374,11 @@
 	GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
 fi
 
-# move to a detached HEAD
-orig_head=$(git rev-parse HEAD^0)
-head_name=$(git symbolic-ref HEAD 2> /dev/null)
-case "$head_name" in
-'')
-	head_name="detached HEAD"
-	;;
-*)
-	git checkout "$orig_head" > /dev/null 2>&1 ||
-		die "could not detach HEAD"
-	;;
-esac
-
-# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
+# Detach HEAD and reset the tree
 echo "First, rewinding head to replay your work on top of it..."
-git-reset --hard "$onto"
+git checkout "$onto^0" >/dev/null 2>&1 ||
+	die "could not detach HEAD"
+# git reset --hard "$onto^0"
 
 # If the $onto is a proper descendant of the tip of the branch, then
 # we just fast forwarded.
@@ -374,7 +391,8 @@
 
 if test -z "$do_merge"
 then
-	git format-patch -k --stdout --full-index --ignore-if-in-upstream "$upstream"..ORIG_HEAD |
+	git format-patch -k --stdout --full-index --ignore-if-in-upstream \
+		"$upstream..$orig_head" |
 	git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
 	move_to_original_branch
 	ret=$?
@@ -397,7 +415,7 @@
 echo "$head_name" > "$dotest/head-name"
 
 msgnum=0
-for cmt in `git rev-list --reverse --no-merges "$upstream"..ORIG_HEAD`
+for cmt in `git rev-list --reverse --no-merges "$upstream..$orig_head"`
 do
 	msgnum=$(($msgnum + 1))
 	echo "$cmt" > "$dotest/cmt.$msgnum"
diff --git a/git-repack.sh b/git-repack.sh
index 501519a..072d1b4 100755
--- a/git-repack.sh
+++ b/git-repack.sh
@@ -8,7 +8,7 @@
 git-repack [options]
 --
 a               pack everything in a single pack
-A               same as -a, and keep unreachable objects too
+A               same as -a, and turn unreachable objects loose
 d               remove redundant packs, and run git-prune-packed
 f               pass --no-reuse-delta to git-pack-objects
 n               do not run git-update-server-info
@@ -23,7 +23,7 @@
 SUBDIRECTORY_OK='Yes'
 . git-sh-setup
 
-no_update_info= all_into_one= remove_redundant= keep_unreachable=
+no_update_info= all_into_one= remove_redundant= unpack_unreachable=
 local= quiet= no_reuse= extra=
 while test $# != 0
 do
@@ -31,7 +31,7 @@
 	-n)	no_update_info=t ;;
 	-a)	all_into_one=t ;;
 	-A)	all_into_one=t
-		keep_unreachable=--keep-unreachable ;;
+		unpack_unreachable=--unpack-unreachable ;;
 	-d)	remove_redundant=t ;;
 	-q)	quiet=-q ;;
 	-f)	no_reuse=--no-reuse-object ;;
@@ -79,9 +79,9 @@
 	if test -z "$args"
 	then
 		args='--unpacked --incremental'
-	elif test -n "$keep_unreachable"
+	elif test -n "$unpack_unreachable"
 	then
-		args="$args $keep_unreachable"
+		args="$args $unpack_unreachable"
 	fi
 	;;
 esac
@@ -125,7 +125,6 @@
 	# We know $existing are all redundant.
 	if [ -n "$existing" ]
 	then
-		sync
 		( cd "$PACKDIR" &&
 		  for e in $existing
 		  do
diff --git a/git-send-email.perl b/git-send-email.perl
index c6bba47..385ff7c 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -168,7 +168,8 @@
 # Example reply to:
 #$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
 
-my $repo = Git->repository();
+my $repo = eval { Git->repository() };
+my @repo = $repo ? ($repo) : ();
 my $term = eval {
 	$ENV{"GIT_SEND_EMAIL_NOTTY"}
 		? new Term::ReadLine 'git-send-email', \*STDIN, \*STDOUT
@@ -202,11 +203,13 @@
     "smtpuser" => \$smtp_authuser,
     "smtppass" => \$smtp_authpass,
     "to" => \@to,
+    "cc" => \@initial_cc,
     "cccmd" => \$cc_cmd,
     "aliasfiletype" => \$aliasfiletype,
     "bcc" => \@bcclist,
     "aliasesfile" => \@alias_files,
     "suppresscc" => \@suppress_cc,
+    "envelopesender" => \$envelope_sender,
 );
 
 # Handle Uncouth Termination
@@ -271,25 +274,25 @@
 
 	foreach my $setting (keys %config_bool_settings) {
 		my $target = $config_bool_settings{$setting}->[0];
-		$$target = $repo->config_bool("$prefix.$setting") unless (defined $$target);
+		$$target = Git::config_bool(@repo, "$prefix.$setting") unless (defined $$target);
 	}
 
 	foreach my $setting (keys %config_settings) {
 		my $target = $config_settings{$setting};
 		if (ref($target) eq "ARRAY") {
 			unless (@$target) {
-				my @values = $repo->config("$prefix.$setting");
+				my @values = Git::config(@repo, "$prefix.$setting");
 				@$target = @values if (@values && defined $values[0]);
 			}
 		}
 		else {
-			$$target = $repo->config("$prefix.$setting") unless (defined $$target);
+			$$target = Git::config(@repo, "$prefix.$setting") unless (defined $$target);
 		}
 	}
 }
 
 # read configuration from [sendemail "$identity"], fall back on [sendemail]
-$identity = $repo->config("sendemail.identity") unless (defined $identity);
+$identity = Git::config(@repo, "sendemail.identity") unless (defined $identity);
 read_config("sendemail.$identity") if (defined $identity);
 read_config("sendemail");
 
@@ -327,8 +330,9 @@
 	}
 }
 
-my ($repoauthor) = $repo->ident_person('author');
-my ($repocommitter) = $repo->ident_person('committer');
+my ($repoauthor, $repocommitter);
+($repoauthor) = Git::ident_person(@repo, 'author');
+($repocommitter) = Git::ident_person(@repo, 'committer');
 
 # Verify the user input
 
@@ -415,7 +419,7 @@
 
 my $prompting = 0;
 if (!defined $sender) {
-	$sender = $repoauthor || $repocommitter;
+	$sender = $repoauthor || $repocommitter || '';
 
 	while (1) {
 		$_ = $term->readline("Who should the emails appear to be from? [$sender] ");
@@ -438,7 +442,7 @@
 	}
 
 	my $to = $_;
-	push @to, split /,/, $to;
+	push @to, split /,\s*/, $to;
 	$prompting++;
 }
 
@@ -509,8 +513,8 @@
 EOT
 	close(C);
 
-	my $editor = $ENV{GIT_EDITOR} || $repo->config("core.editor") || $ENV{VISUAL} || $ENV{EDITOR} || "vi";
-	system('sh', '-c', '$0 $@', $editor, $compose_filename);
+	my $editor = $ENV{GIT_EDITOR} || Git::config(@repo, "core.editor") || $ENV{VISUAL} || $ENV{EDITOR} || "vi";
+	system('sh', '-c', $editor.' "$@"', $editor, $compose_filename);
 
 	open(C2,">",$compose_filename . ".final")
 		or die "Failed to open $compose_filename.final : " . $!;
@@ -846,7 +850,7 @@
 				}
 				elsif (/^Content-type:/i) {
 					$has_content_type = 1;
-					if (/charset="?[^ "]+/) {
+					if (/charset="?([^ "]+)/) {
 						$body_encoding = $1;
 					}
 					push @xh, $_;
diff --git a/git-stash.sh b/git-stash.sh
index c2b6820..4938ade 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -15,8 +15,8 @@
 ref_stash=refs/stash
 
 no_changes () {
-	git diff-index --quiet --cached HEAD -- &&
-	git diff-files --quiet
+	git diff-index --quiet --cached HEAD --ignore-submodules -- &&
+	git diff-files --quiet --ignore-submodules
 }
 
 clear_stash () {
@@ -130,7 +130,7 @@
 }
 
 apply_stash () {
-	git diff-files --quiet ||
+	git diff-files --quiet --ignore-submodules ||
 		die 'Cannot restore on top of a dirty state'
 
 	unstash_index=
diff --git a/git-submodule.sh b/git-submodule.sh
index a745e42..21e5b5b 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -5,7 +5,7 @@
 # Copyright (c) 2007 Lars Hjemli
 
 USAGE="[--quiet] [--cached] \
-[add <repo> [-b branch]|status|init|update|summary [-n|--summary-limit <n>] [<commit>]] \
+[add <repo> [-b branch]|status|init|update [-i|--init]|summary [-n|--summary-limit <n>] [<commit>]] \
 [--] [<path>...]"
 OPTIONS_SPEC=
 . git-sh-setup
@@ -45,8 +45,8 @@
 	branch="$(git symbolic-ref HEAD 2>/dev/null)"
 	remote="$(git config branch.${branch#refs/heads/}.remote)"
 	remote="${remote:-origin}"
-	remoteurl="$(git config remote.$remote.url)" ||
-		die "remote ($remote) does not have a url in .git/config"
+	remoteurl=$(git config "remote.$remote.url") ||
+		die "remote ($remote) does not have a url defined in .git/config"
 	url="$1"
 	while test -n "$url"
 	do
@@ -73,9 +73,8 @@
 module_name()
 {
 	# Do we have "submodule.<something>.path = $1" defined in .gitmodules file?
-	re=$(printf '%s' "$1" | sed -e 's/[].[^$\\*]/\\&/g')
-	name=$( GIT_CONFIG=.gitmodules \
-		git config --get-regexp '^submodule\..*\.path$' |
+	re=$(printf '%s\n' "$1" | sed -e 's/[].[^$\\*]/\\&/g')
+	name=$( git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
 		sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
        test -z "$name" &&
        die "No submodule mapping found in .gitmodules for path '$path'"
@@ -168,8 +167,7 @@
 	# perhaps the path exists and is already a git repo, else clone it
 	if test -e "$path"
 	then
-		if test -d "$path/.git" &&
-		test "$(unset GIT_DIR; cd $path; git rev-parse --git-dir)" = ".git"
+		if test -d "$path"/.git -o -f "$path"/.git
 		then
 			echo "Adding existing repo at '$path' to the index"
 		else
@@ -179,7 +177,8 @@
 		case "$repo" in
 		./*|../*)
 			# dereference source url relative to parent's url
-			realrepo="$(resolve_relative_url $repo)" ;;
+			realrepo=$(resolve_relative_url "$repo") || exit
+			;;
 		*)
 			# Turn the source into an absolute path if
 			# it is local
@@ -198,8 +197,8 @@
 	git add "$path" ||
 	die "Failed to add submodule '$path'"
 
-	GIT_CONFIG=.gitmodules git config submodule."$path".path "$path" &&
-	GIT_CONFIG=.gitmodules git config submodule."$path".url "$repo" &&
+	git config -f .gitmodules submodule."$path".path "$path" &&
+	git config -f .gitmodules submodule."$path".url "$repo" &&
 	git add .gitmodules ||
 	die "Failed to register submodule '$path'"
 }
@@ -240,14 +239,14 @@
 		url=$(git config submodule."$name".url)
 		test -z "$url" || continue
 
-		url=$(GIT_CONFIG=.gitmodules git config submodule."$name".url)
+		url=$(git config -f .gitmodules submodule."$name".url)
 		test -z "$url" &&
 		die "No url found for submodule path '$path' in .gitmodules"
 
 		# Possibly a url relative to parent
 		case "$url" in
 		./*|../*)
-			url="$(resolve_relative_url "$url")"
+			url=$(resolve_relative_url "$url") || exit
 			;;
 		esac
 
@@ -270,8 +269,13 @@
 	do
 		case "$1" in
 		-q|--quiet)
+			shift
 			quiet=1
 			;;
+		-i|--init)
+			shift
+			cmd_init "$@" || return
+			;;
 		--)
 			shift
 			break
@@ -283,7 +287,6 @@
 			break
 			;;
 		esac
-		shift
 	done
 
 	git ls-files --stage -- "$@" | grep '^160000 ' |
@@ -297,10 +300,11 @@
 			# path have been specified
 			test "$#" != "0" &&
 			say "Submodule path '$path' not initialized"
+			say "Maybe you want to use 'update --init'?"
 			continue
 		fi
 
-		if ! test -d "$path"/.git
+		if ! test -d "$path"/.git -o -f "$path"/.git
 		then
 			module_clone "$path" "$url" || exit
 			subsha1=
@@ -343,6 +347,7 @@
 #
 cmd_summary() {
 	summary_limit=-1
+	for_status=
 
 	# parse $args after "submodule ... summary".
 	while test $# -ne 0
@@ -351,6 +356,9 @@
 		--cached)
 			cached="$1"
 			;;
+		--for-status)
+			for_status="$1"
+			;;
 		-n|--summary-limit)
 			if summary_limit=$(($2 + 0)) 2>/dev/null && test "$summary_limit" = "$2"
 			then
@@ -398,7 +406,8 @@
 		done
 	)
 
-	test -n "$modules" &&
+	test -z "$modules" && return
+
 	git diff-index $cached --raw $head -- $modules |
 	grep -e '^:160000' -e '^:[0-7]* 160000' |
 	cut -c2- |
@@ -500,7 +509,14 @@
 			echo
 		fi
 		echo
-	done
+	done |
+	if test -n "$for_status"; then
+		echo "# Modified submodules:"
+		echo "#"
+		sed -e 's|^|# |' -e 's|^# $|#|'
+	else
+		cat
+	fi
 }
 #
 # List all submodules, prefixed with:
@@ -543,7 +559,7 @@
 	do
 		name=$(module_name "$path") || exit
 		url=$(git config submodule."$name".url)
-		if test -z "$url" || ! test -d "$path"/.git
+		if test -z "$url" || ! test -d "$path"/.git -o -f "$path"/.git
 		then
 			say "-$sha1 $path"
 			continue;
diff --git a/git-svn.perl b/git-svn.perl
index b151049..a366c89 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -4,7 +4,7 @@
 use warnings;
 use strict;
 use vars qw/	$AUTHOR $VERSION
-		$sha1 $sha1_short $_revision
+		$sha1 $sha1_short $_revision $_repository
 		$_q $_authors %users/;
 $AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
 $VERSION = '@@GIT_VERSION@@';
@@ -65,7 +65,8 @@
 	$_template, $_shared,
 	$_version, $_fetch_all, $_no_rebase,
 	$_merge, $_strategy, $_dry_run, $_local,
-	$_prefix, $_no_checkout, $_url, $_verbose);
+	$_prefix, $_no_checkout, $_url, $_verbose,
+	$_git_format);
 $Git::SVN::_follow_parent = 1;
 my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
                     'config-dir=s' => \$Git::SVN::Ra::config_dir,
@@ -82,6 +83,7 @@
 		'repack-flags|repack-args|repack-opts=s' =>
 		   \$Git::SVN::_repack_flags,
 		'use-log-author' => \$Git::SVN::_use_log_author,
+		'add-author-from' => \$Git::SVN::_add_author_from,
 		%remote_opts );
 
 my ($_trunk, $_tags, $_branches, $_stdlayout);
@@ -175,6 +177,7 @@
 			  'strategy|s=s' => \$_strategy,
 			  'local|l' => \$_local,
 			  'fetch-all|all' => \$_fetch_all,
+			  'dry-run|n' => \$_dry_run,
 			  %fc_opts } ],
 	'commit-diff' => [ \&cmd_commit_diff,
 	                   'Commit a diff between two trees',
@@ -188,7 +191,7 @@
 		    { 'url' => \$_url, } ],
 	'blame' => [ \&Git::SVN::Log::cmd_blame,
 	            "Show what revision and author last modified each line of a file",
-	            {} ],
+		    { 'git-format' => \$_git_format } ],
 );
 
 my $cmd;
@@ -220,12 +223,13 @@
 		}
 		$ENV{GIT_DIR} = $git_dir;
 	}
+	$_repository = Git->repository(Repository => $ENV{GIT_DIR});
 }
 
 my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd);
 
 read_repo_config(\%opts);
-Getopt::Long::Configure('pass_through') if ($cmd && $cmd eq 'log');
+Getopt::Long::Configure('pass_through') if ($cmd && ($cmd eq 'log' || $cmd eq 'blame'));
 my $rv = GetOptions(%opts, 'help|H|h' => \$_help, 'version|V' => \$_version,
                     'minimize-connections' => \$Git::SVN::Migration::_minimize,
                     'id|i=s' => \$Git::SVN::default_ref_id,
@@ -301,6 +305,7 @@
 			}
 		}
 		command_noisy(@init_db);
+		$_repository = Git->repository(Repository => ".git");
 	}
 	my $set;
 	my $pfx = "svn-remote.$Git::SVN::default_repo_id";
@@ -317,6 +322,7 @@
 	mkpath([$repo_path]) unless -d $repo_path;
 	chdir $repo_path or die "Couldn't chdir to $repo_path: $!\n";
 	$ENV{GIT_DIR} = '.git';
+	$_repository = Git->repository(Repository => $ENV{GIT_DIR});
 }
 
 sub cmd_clone {
@@ -410,10 +416,12 @@
 	$head ||= 'HEAD';
 	my @refs;
 	my ($url, $rev, $uuid, $gs) = working_head_info($head, \@refs);
-	print "Committing to $url ...\n";
+	if ($url) {
+		print "Committing to $url ...\n";
+	}
 	unless ($gs) {
 		die "Unable to determine upstream SVN information from ",
-		    "$head history\n";
+		    "$head history.\nPerhaps the repository is empty.";
 	}
 	my $last_rev;
 	my ($linear_refs, $parents) = linearize_history($gs, \@refs);
@@ -550,6 +558,11 @@
 		die "Unable to determine upstream SVN information from ",
 		    "working tree history\n";
 	}
+	if ($_dry_run) {
+		print "Remote Branch: " . $gs->refname . "\n";
+		print "SVN URL: " . $url . "\n";
+		return;
+	}
 	if (command(qw/diff-index HEAD --/)) {
 		print STDERR "Cannot rebase with uncommited changes:\n";
 		command_noisy('status');
@@ -612,7 +625,7 @@
 		print GITIGNORE "$s\n";
 		close(GITIGNORE)
 		  or fatal("Failed to close `$ignore': $!");
-		command_noisy('add', $ignore);
+		command_noisy('add', '-f', $ignore);
 	});
 }
 
@@ -630,6 +643,8 @@
 	$path =~ s#/[^/]+/\.\.##g;
 	$path =~ s#/$##g;
 	$path =~ s#^\./## if $dot_slash_added;
+	$path =~ s#^/##;
+	$path =~ s#^\.$##;
 	return $path;
 }
 
@@ -738,7 +753,7 @@
 	my $usage = "Usage: $0 commit-diff -r<revision> ".
 	            "<tree-ish> <tree-ish> [<URL>]";
 	fatal($usage) if (!defined $ta || !defined $tb);
-	my $svn_path;
+	my $svn_path = '';
 	if (!defined $url) {
 		my $gs = eval { Git::SVN->new };
 		if (!$gs) {
@@ -762,7 +777,6 @@
 		$_message ||= get_commit_entry($tb)->{log};
 	}
 	my $ra ||= Git::SVN::Ra->new($url);
-	$svn_path ||= $ra->{svn_path};
 	my $r = $_revision;
 	if ($r eq 'HEAD') {
 		$r = $ra->get_latest_revnum;
@@ -1009,17 +1023,30 @@
 		my ($msg_fh, $ctx) = command_output_pipe('cat-file',
 		                                         $type, $treeish);
 		my $in_msg = 0;
+		my $author;
+		my $saw_from = 0;
+		my $msgbuf = "";
 		while (<$msg_fh>) {
 			if (!$in_msg) {
 				$in_msg = 1 if (/^\s*$/);
+				$author = $1 if (/^author (.*>)/);
 			} elsif (/^git-svn-id: /) {
 				# skip this for now, we regenerate the
 				# correct one on re-fetch anyways
 				# TODO: set *:merge properties or like...
 			} else {
-				print $log_fh $_ or croak $!;
+				if (/^From:/ || /^Signed-off-by:/) {
+					$saw_from = 1;
+				}
+				$msgbuf .= $_;
 			}
 		}
+		$msgbuf =~ s/\s+$//s;
+		if ($Git::SVN::_add_author_from && defined($author)
+		    && !$saw_from) {
+			$msgbuf .= "\n\nFrom: $author";
+		}
+		print $log_fh $msgbuf or croak $!;
 		command_close_pipe($msg_fh, $ctx);
 	}
 	close $log_fh or croak $!;
@@ -1246,7 +1273,7 @@
 use vars qw/$default_repo_id $default_ref_id $_no_metadata $_follow_parent
             $_repack $_repack_flags $_use_svm_props $_head
             $_use_svnsync_props $no_reuse_existing $_minimize_url
-	    $_use_log_author/;
+	    $_use_log_author $_add_author_from/;
 use Carp qw/croak/;
 use File::Path qw/mkpath/;
 use File::Copy qw/copy/;
@@ -1437,13 +1464,6 @@
 	}
 }
 
-# we allow more chars than remotes2config.sh...
-sub sanitize_remote_name {
-	my ($name) = @_;
-	$name =~ tr{A-Za-z0-9:,/+-}{.}c;
-	$name;
-}
-
 sub find_existing_remote {
 	my ($url, $remotes) = @_;
 	return undef if $no_reuse_existing;
@@ -1900,7 +1920,7 @@
 
 	foreach (sort keys %$dirent) {
 		next if $dirent->{$_}->{kind} != $SVN::Node::dir;
-		$self->prop_walk($p . $_, $rev, $sub);
+		$self->prop_walk($self->{path} . $p . $_, $rev, $sub);
 	}
 }
 
@@ -2426,13 +2446,15 @@
 			$name_field = $1;
 		}
 		if (!defined $name_field) {
-			#
+			if (!defined $email) {
+				$email = $name;
+			}
 		} elsif ($name_field =~ /(.*?)\s+<(.*)>/) {
 			($name, $email) = ($1, $2);
 		} elsif ($name_field =~ /(.*)@/) {
 			($name, $email) = ($1, $name_field);
 		} else {
-			($name, $email) = ($name_field, 'unknown');
+			($name, $email) = ($name_field, $name_field);
 		}
 	}
 	if (defined $headrev && $self->use_svm_props) {
@@ -2550,8 +2572,8 @@
 	my ($log, $ctx) =
 	    command_output_pipe(qw/rev-list --pretty=raw --no-color --reverse/,
 	                        $self->refname, '--');
-	my $full_url = $self->full_url;
-	remove_username($full_url);
+	my $metadata_url = $self->metadata_url;
+	remove_username($metadata_url);
 	my $svn_uuid = $self->ra_uuid;
 	my $c;
 	while (<$log>) {
@@ -2569,7 +2591,7 @@
 		# if we merged or otherwise started elsewhere, this is
 		# how we break out of it
 		if (($uuid ne $svn_uuid) ||
-		    ($full_url && $url && ($url ne $full_url))) {
+		    ($metadata_url && $url && ($url ne $metadata_url))) {
 			next;
 		}
 
@@ -2826,7 +2848,7 @@
 	unless (defined $ref_id && length $ref_id) {
 		$_[2] = $ref_id = $Git::SVN::default_ref_id;
 	}
-	$_[1] = $repo_id = sanitize_remote_name($repo_id);
+	$_[1] = $repo_id;
 	my $dir = "$ENV{GIT_DIR}/svn/$ref_id";
 	$_[3] = $path = '' unless (defined $path);
 	mkpath(["$ENV{GIT_DIR}/svn"]);
@@ -3013,6 +3035,7 @@
 use strict;
 use warnings;
 use Carp qw/croak/;
+use File::Temp qw/tempfile/;
 use IO::File qw//;
 
 # file baton members: path, mode_a, mode_b, pool, fh, blob, base
@@ -3168,14 +3191,9 @@
 	my $base = IO::File->new_tmpfile;
 	$base->autoflush(1);
 	if ($fb->{blob}) {
-		defined (my $pid = fork) or croak $!;
-		if (!$pid) {
-			open STDOUT, '>&', $base or croak $!;
-			print STDOUT 'link ' if ($fb->{mode_a} == 120000);
-			exec qw/git-cat-file blob/, $fb->{blob} or croak $!;
-		}
-		waitpid $pid, 0;
-		croak $? if $?;
+		print $base 'link ' if ($fb->{mode_a} == 120000);
+		my $size = $::_repository->cat_blob($fb->{blob}, $base);
+		die "Failed to read object $fb->{blob}" if ($size < 0);
 
 		if (defined $exp) {
 			seek $base, 0, 0 or croak $!;
@@ -3216,14 +3234,21 @@
 				sysseek($fh, 0, 0) or croak $!;
 			}
 		}
-		defined(my $pid = open my $out,'-|') or die "Can't fork: $!\n";
-		if (!$pid) {
-			open STDIN, '<&', $fh or croak $!;
-			exec qw/git-hash-object -w --stdin/ or croak $!;
+
+		my ($tmp_fh, $tmp_filename) = File::Temp::tempfile(UNLINK => 1);
+		my $result;
+		while ($result = sysread($fh, my $string, 1024)) {
+			my $wrote = syswrite($tmp_fh, $string, $result);
+			defined($wrote) && $wrote == $result
+				or croak("write $tmp_filename: $!\n");
 		}
-		chomp($hash = do { local $/; <$out> });
-		close $out or croak $!;
+		defined $result or croak $!;
+		close $tmp_fh or croak $!;
+
 		close $fh or croak $!;
+
+		$hash = $::_repository->hash_and_insert_object($tmp_filename);
+		unlink($tmp_filename);
 		$hash =~ /^[a-f\d]{40}$/ or die "not a sha1: $hash\n";
 		close $fb->{base} or croak $!;
 	} else {
@@ -3549,13 +3574,8 @@
 	} elsif ($m->{mode_a} =~ /^120/ && $m->{mode_b} !~ /^120/) {
 		$self->change_file_prop($fbat,'svn:special',undef);
 	}
-	defined(my $pid = fork) or croak $!;
-	if (!$pid) {
-		open STDOUT, '>&', $fh or croak $!;
-		exec qw/git-cat-file blob/, $m->{sha1_b} or croak $!;
-	}
-	waitpid $pid, 0;
-	croak $? if $?;
+	my $size = $::_repository->cat_blob($m->{sha1_b}, $fh);
+	croak "Failed to read object $m->{sha1_b}" if ($size < 0);
 	$fh->flush == 0 or croak $!;
 	seek $fh, 0, 0 or croak $!;
 
@@ -3669,7 +3689,7 @@
 	my ($uri) = @_;
 	my @tmp;
 	foreach (split m{/}, $uri) {
-		s/([^\w.%-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
+		s/([^\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
 		push @tmp, $_;
 	}
 	join('/', @tmp);
@@ -4464,19 +4484,51 @@
 }
 
 sub cmd_blame {
-	my $path = shift;
+	my $path = pop;
 
 	config_pager();
 	run_pager();
 
-	my ($fh, $ctx) = command_output_pipe('blame', @_, $path);
-	while (my $line = <$fh>) {
-		if ($line =~ /^\^?([[:xdigit:]]+)\s/) {
-			my (undef, $rev, undef) = ::cmt_metadata($1);
-			$rev = sprintf('%-10s', $rev);
-			$line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/;
+	my ($fh, $ctx, $rev);
+
+	if ($_git_format) {
+		($fh, $ctx) = command_output_pipe('blame', @_, $path);
+		while (my $line = <$fh>) {
+			if ($line =~ /^\^?([[:xdigit:]]+)\s/) {
+				# Uncommitted edits show up as a rev ID of
+				# all zeros, which we can't look up with
+				# cmt_metadata
+				if ($1 !~ /^0+$/) {
+					(undef, $rev, undef) =
+						::cmt_metadata($1);
+					$rev = '0' if (!$rev);
+				} else {
+					$rev = '0';
+				}
+				$rev = sprintf('%-10s', $rev);
+				$line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/;
+			}
+			print $line;
 		}
-		print $line;
+	} else {
+		($fh, $ctx) = command_output_pipe('blame', '-p', @_, 'HEAD',
+						  '--', $path);
+		my ($sha1);
+		my %authors;
+		while (my $line = <$fh>) {
+			if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) {
+				$sha1 = $1;
+				(undef, $rev, undef) = ::cmt_metadata($1);
+				$rev = '0' if (!$rev);
+			}
+			elsif ($line =~ /^author (.*)/) {
+				$authors{$rev} = $1;
+				$authors{$rev} =~ s/\s/_/g;
+			}
+			elsif ($line =~ /^\t(.*)$/) {
+				printf("%6s %10s %s\n", $rev, $authors{$rev}, $1);
+			}
+		}
 	}
 	command_close_pipe($fh, $ctx);
 }
@@ -4650,8 +4702,7 @@
 
 		# skip existing cases where we already connect to the root
 		if (($ra->{url} eq $ra->{repos_root}) ||
-		    (Git::SVN::sanitize_remote_name($ra->{repos_root}) eq
-		     $repo_id)) {
+		    ($ra->{repos_root} eq $repo_id)) {
 			$root_repos->{$ra->{url}} = $repo_id;
 			next;
 		}
@@ -4690,8 +4741,7 @@
 	foreach my $url (keys %$new_urls) {
 		# see if we can re-use an existing [svn-remote "repo_id"]
 		# instead of creating a(n ugly) new section:
-		my $repo_id = $root_repos->{$url} ||
-		              Git::SVN::sanitize_remote_name($url);
+		my $repo_id = $root_repos->{$url} || $url;
 
 		my $fetch = $new_urls->{$url};
 		foreach my $path (keys %$fetch) {
diff --git a/git.c b/git.c
index c4e4644b..59f0fcc 100644
--- a/git.c
+++ b/git.c
@@ -6,6 +6,9 @@
 const char git_usage_string[] =
 	"git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate|--no-pager] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]";
 
+const char git_more_info_string[] =
+	"See 'git help COMMAND' for more information on a specific command.";
+
 static int handle_options(const char*** argv, int* argc, int* envchanged)
 {
 	int handled = 0;
@@ -283,9 +286,10 @@
 		{ "checkout-index", cmd_checkout_index,
 			RUN_SETUP | NEED_WORK_TREE},
 		{ "check-ref-format", cmd_check_ref_format },
-		{ "check-attr", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },
+		{ "check-attr", cmd_check_attr, RUN_SETUP },
 		{ "cherry", cmd_cherry, RUN_SETUP },
 		{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
+		{ "clone", cmd_clone },
 		{ "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
 		{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
 		{ "commit-tree", cmd_commit_tree, RUN_SETUP },
@@ -293,7 +297,7 @@
 		{ "count-objects", cmd_count_objects, RUN_SETUP },
 		{ "describe", cmd_describe, RUN_SETUP },
 		{ "diff", cmd_diff },
-		{ "diff-files", cmd_diff_files },
+		{ "diff-files", cmd_diff_files, RUN_SETUP },
 		{ "diff-index", cmd_diff_index, RUN_SETUP },
 		{ "diff-tree", cmd_diff_tree, RUN_SETUP },
 		{ "fast-export", cmd_fast_export, RUN_SETUP },
@@ -347,7 +351,7 @@
 		{ "shortlog", cmd_shortlog, USE_PAGER },
 		{ "show-branch", cmd_show_branch, RUN_SETUP },
 		{ "show", cmd_show, RUN_SETUP | USE_PAGER },
-		{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
+		{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE | USE_PAGER },
 		{ "stripspace", cmd_stripspace },
 		{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
 		{ "tag", cmd_tag, RUN_SETUP },
@@ -426,6 +430,7 @@
 		/* The user didn't specify a command; give them help */
 		printf("usage: %s\n\n", git_usage_string);
 		list_common_cmds_help();
+		printf("\n%s\n", git_more_info_string);
 		exit(1);
 	}
 	cmd = argv[0];
diff --git a/git.spec.in b/git.spec.in
index 97a26be..3d7f3ef 100644
--- a/git.spec.in
+++ b/git.spec.in
@@ -12,7 +12,7 @@
 BuildRoot:	%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
 Requires:	perl-Git = %{version}-%{release}
-Requires:	zlib >= 1.2, rsync, curl, less, openssh-clients, expat
+Requires:	zlib >= 1.2, rsync, less, openssh-clients, expat
 Provides:	git-core = %{version}-%{release}
 Obsoletes:	git-core <= 1.5.4.2
 Obsoletes:	git-p4
@@ -187,6 +187,9 @@
 # No files for you!
 
 %changelog
+* Sun Jun 15 2008 Junio C Hamano <gitster@pobox.com>
+- Remove curl from Requires list.
+
 * Fri Feb 15 2008 Kristian Høgsberg <krh@redhat.com>
 - Rename git-core to just git and rename meta package from git to git-all.
 
diff --git a/gitk-git/Makefile b/gitk-git/Makefile
index f90dfab..e1b6045 100644
--- a/gitk-git/Makefile
+++ b/gitk-git/Makefile
@@ -40,9 +40,9 @@
 all:: gitk-wish $(ALL_MSGFILES)
 
 install:: all
-	$(INSTALL) gitk-wish '$(DESTDIR_SQ)$(bindir_SQ)'/gitk
-	$(INSTALL) -d '$(DESTDIR_SQ)$(msgsdir_SQ)'
-	$(foreach p,$(ALL_MSGFILES), $(INSTALL) $p '$(DESTDIR_SQ)$(msgsdir_SQ)' &&) true
+	$(INSTALL) -m 755 gitk-wish '$(DESTDIR_SQ)$(bindir_SQ)'/gitk
+	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(msgsdir_SQ)'
+	$(foreach p,$(ALL_MSGFILES), $(INSTALL) -m 644 $p '$(DESTDIR_SQ)$(msgsdir_SQ)' &&) true
 
 uninstall::
 	$(foreach p,$(ALL_MSGFILES), $(RM) '$(DESTDIR_SQ)$(msgsdir_SQ)'/$(notdir $p) &&) true
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 9a4d9c4..fddcb45 100644
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -2,7 +2,7 @@
 # Tcl ignores the next line -*- tcl -*- \
 exec wish "$0" -- "$@"
 
-# Copyright (C) 2005-2006 Paul Mackerras.  All rights reserved.
+# Copyright © 2005-2008 Paul Mackerras.  All rights reserved.
 # This program is free software; it may be used, copied, modified
 # and distributed under the terms of the GNU General Public Licence,
 # either version 2, or (at your option) any later version.
@@ -47,12 +47,24 @@
     lappend runq [list $fd $script]
 }
 
+proc nukefile {fd} {
+    global runq
+
+    for {set i 0} {$i < [llength $runq]} {} {
+	if {[lindex $runq $i 0] eq $fd} {
+	    set runq [lreplace $runq $i $i]
+	} else {
+	    incr i
+	}
+    }
+}
+
 proc dorunq {} {
     global isonrunq runq
 
     set tstart [clock clicks -milliseconds]
     set t0 $tstart
-    while {$runq ne {}} {
+    while {[llength $runq] > 0} {
 	set fd [lindex $runq 0 0]
 	set script [lindex $runq 0 1]
 	set repeat [eval $script]
@@ -78,77 +90,427 @@
     }
 }
 
-# Start off a git rev-list process and arrange to read its output
+proc unmerged_files {files} {
+    global nr_unmerged
+
+    # find the list of unmerged files
+    set mlist {}
+    set nr_unmerged 0
+    if {[catch {
+	set fd [open "| git ls-files -u" r]
+    } err]} {
+	show_error {} . "[mc "Couldn't get list of unmerged files:"] $err"
+	exit 1
+    }
+    while {[gets $fd line] >= 0} {
+	set i [string first "\t" $line]
+	if {$i < 0} continue
+	set fname [string range $line [expr {$i+1}] end]
+	if {[lsearch -exact $mlist $fname] >= 0} continue
+	incr nr_unmerged
+	if {$files eq {} || [path_filter $files $fname]} {
+	    lappend mlist $fname
+	}
+    }
+    catch {close $fd}
+    return $mlist
+}
+
+proc parseviewargs {n arglist} {
+    global vdatemode vmergeonly vflags vdflags vrevs vfiltered vorigargs
+
+    set vdatemode($n) 0
+    set vmergeonly($n) 0
+    set glflags {}
+    set diffargs {}
+    set nextisval 0
+    set revargs {}
+    set origargs $arglist
+    set allknown 1
+    set filtered 0
+    set i -1
+    foreach arg $arglist {
+	incr i
+	if {$nextisval} {
+	    lappend glflags $arg
+	    set nextisval 0
+	    continue
+	}
+	switch -glob -- $arg {
+	    "-d" -
+	    "--date-order" {
+		set vdatemode($n) 1
+		# remove from origargs in case we hit an unknown option
+		set origargs [lreplace $origargs $i $i]
+		incr i -1
+	    }
+	    # These request or affect diff output, which we don't want.
+	    # Some could be used to set our defaults for diff display.
+	    "-[puabwcrRBMC]" -
+	    "--no-renames" - "--full-index" - "--binary" - "--abbrev=*" -
+	    "--find-copies-harder" - "-l*" - "--ext-diff" - "--no-ext-diff" -
+	    "--src-prefix=*" - "--dst-prefix=*" - "--no-prefix" -
+	    "-O*" - "--text" - "--full-diff" - "--ignore-space-at-eol" -
+	    "--ignore-space-change" - "-U*" - "--unified=*" {
+		lappend diffargs $arg
+	    }
+	    # These cause our parsing of git log's output to fail, or else
+	    # they're options we want to set ourselves, so ignore them.
+	    "--raw" - "--patch-with-raw" - "--patch-with-stat" -
+	    "--name-only" - "--name-status" - "--color" - "--color-words" -
+	    "--log-size" - "--pretty=*" - "--decorate" - "--abbrev-commit" -
+	    "--cc" - "-z" - "--header" - "--parents" - "--boundary" -
+	    "--no-color" - "-g" - "--walk-reflogs" - "--no-walk" -
+	    "--timestamp" - "relative-date" - "--date=*" - "--stdin" -
+	    "--objects" - "--objects-edge" - "--reverse" {
+	    }
+	    # These are harmless, and some are even useful
+	    "--stat=*" - "--numstat" - "--shortstat" - "--summary" -
+	    "--check" - "--exit-code" - "--quiet" - "--topo-order" -
+	    "--full-history" - "--dense" - "--sparse" -
+	    "--follow" - "--left-right" - "--encoding=*" {
+		lappend glflags $arg
+	    }
+	    # These mean that we get a subset of the commits
+	    "--diff-filter=*" - "--no-merges" - "--unpacked" -
+	    "--max-count=*" - "--skip=*" - "--since=*" - "--after=*" -
+	    "--until=*" - "--before=*" - "--max-age=*" - "--min-age=*" -
+	    "--author=*" - "--committer=*" - "--grep=*" - "-[iE]" -
+	    "--remove-empty" - "--first-parent" - "--cherry-pick" -
+	    "-S*" - "--pickaxe-all" - "--pickaxe-regex" - {
+		set filtered 1
+		lappend glflags $arg
+	    }
+	    # This appears to be the only one that has a value as a
+	    # separate word following it
+	    "-n" {
+		set filtered 1
+		set nextisval 1
+		lappend glflags $arg
+	    }
+	    "--not" {
+		set notflag [expr {!$notflag}]
+		lappend revargs $arg
+	    }
+	    "--all" {
+		lappend revargs $arg
+	    }
+	    "--merge" {
+		set vmergeonly($n) 1
+		# git rev-parse doesn't understand --merge
+		lappend revargs --gitk-symmetric-diff-marker MERGE_HEAD...HEAD
+	    }
+	    # Other flag arguments including -<n>
+	    "-*" {
+		if {[string is digit -strict [string range $arg 1 end]]} {
+		    set filtered 1
+		} else {
+		    # a flag argument that we don't recognize;
+		    # that means we can't optimize
+		    set allknown 0
+		}
+		lappend glflags $arg
+	    }
+	    # Non-flag arguments specify commits or ranges of commits
+	    default {
+		if {[string match "*...*" $arg]} {
+		    lappend revargs --gitk-symmetric-diff-marker
+		}
+		lappend revargs $arg
+	    }
+	}
+    }
+    set vdflags($n) $diffargs
+    set vflags($n) $glflags
+    set vrevs($n) $revargs
+    set vfiltered($n) $filtered
+    set vorigargs($n) $origargs
+    return $allknown
+}
+
+proc parseviewrevs {view revs} {
+    global vposids vnegids
+
+    if {$revs eq {}} {
+	set revs HEAD
+    }
+    if {[catch {set ids [eval exec git rev-parse $revs]} err]} {
+	# we get stdout followed by stderr in $err
+	# for an unknown rev, git rev-parse echoes it and then errors out
+	set errlines [split $err "\n"]
+	set badrev {}
+	for {set l 0} {$l < [llength $errlines]} {incr l} {
+	    set line [lindex $errlines $l]
+	    if {!([string length $line] == 40 && [string is xdigit $line])} {
+		if {[string match "fatal:*" $line]} {
+		    if {[string match "fatal: ambiguous argument*" $line]
+			&& $badrev ne {}} {
+			if {[llength $badrev] == 1} {
+			    set err "unknown revision $badrev"
+			} else {
+			    set err "unknown revisions: [join $badrev ", "]"
+			}
+		    } else {
+			set err [join [lrange $errlines $l end] "\n"]
+		    }
+		    break
+		}
+		lappend badrev $line
+	    }
+	}		    
+	error_popup "Error parsing revisions: $err"
+	return {}
+    }
+    set ret {}
+    set pos {}
+    set neg {}
+    set sdm 0
+    foreach id [split $ids "\n"] {
+	if {$id eq "--gitk-symmetric-diff-marker"} {
+	    set sdm 4
+	} elseif {[string match "^*" $id]} {
+	    if {$sdm != 1} {
+		lappend ret $id
+		if {$sdm == 3} {
+		    set sdm 0
+		}
+	    }
+	    lappend neg [string range $id 1 end]
+	} else {
+	    if {$sdm != 2} {
+		lappend ret $id
+	    } else {
+		lset ret end [lindex $ret end]...$id
+	    }
+	    lappend pos $id
+	}
+	incr sdm -1
+    }
+    set vposids($view) $pos
+    set vnegids($view) $neg
+    return $ret
+}
+
+# Start off a git log process and arrange to read its output
 proc start_rev_list {view} {
-    global startmsecs
-    global commfd leftover tclencoding datemode
-    global viewargs viewargscmd viewfiles commitidx viewcomplete vnextroot
-    global showlocalchanges commitinterest mainheadid
-    global progressdirn progresscoords proglastnc curview
+    global startmsecs commitidx viewcomplete curview
+    global commfd leftover tclencoding
+    global viewargs viewargscmd viewfiles vfilelimit
+    global showlocalchanges commitinterest
+    global viewactive loginstance viewinstances vmergeonly
+    global pending_select mainheadid
+    global vcanopt vflags vrevs vorigargs
 
     set startmsecs [clock clicks -milliseconds]
     set commitidx($view) 0
-    set viewcomplete($view) 0
-    set vnextroot($view) 0
+    # these are set this way for the error exits
+    set viewcomplete($view) 1
+    set viewactive($view) 0
+    varcinit $view
+
     set args $viewargs($view)
     if {$viewargscmd($view) ne {}} {
 	if {[catch {
 	    set str [exec sh -c $viewargscmd($view)]
 	} err]} {
 	    error_popup "Error executing --argscmd command: $err"
-	    exit 1
+	    return 0
 	}
 	set args [concat $args [split $str "\n"]]
     }
-    set order "--topo-order"
-    if {$datemode} {
-	set order "--date-order"
+    set vcanopt($view) [parseviewargs $view $args]
+
+    set files $viewfiles($view)
+    if {$vmergeonly($view)} {
+	set files [unmerged_files $files]
+	if {$files eq {}} {
+	    global nr_unmerged
+	    if {$nr_unmerged == 0} {
+		error_popup [mc "No files selected: --merge specified but\
+			     no files are unmerged."]
+	    } else {
+		error_popup [mc "No files selected: --merge specified but\
+			     no unmerged files are within file limit."]
+	    }
+	    return 0
+	}
     }
+    set vfilelimit($view) $files
+
+    if {$vcanopt($view)} {
+	set revs [parseviewrevs $view $vrevs($view)]
+	if {$revs eq {}} {
+	    return 0
+	}
+	set args [concat $vflags($view) $revs]
+    } else {
+	set args $vorigargs($view)
+    }
+
     if {[catch {
-	set fd [open [concat | git log --no-color -z --pretty=raw $order --parents \
-			 --boundary $args "--" $viewfiles($view)] r]
+	set fd [open [concat | git log --no-color -z --pretty=raw --parents \
+			 --boundary $args "--" $files] r]
     } err]} {
-	error_popup "[mc "Error executing git rev-list:"] $err"
-	exit 1
+	error_popup "[mc "Error executing git log:"] $err"
+	return 0
     }
-    set commfd($view) $fd
-    set leftover($view) {}
-    if {$showlocalchanges} {
+    set i [incr loginstance]
+    set viewinstances($view) [list $i]
+    set commfd($i) $fd
+    set leftover($i) {}
+    if {$showlocalchanges && $mainheadid ne {}} {
 	lappend commitinterest($mainheadid) {dodiffindex}
     }
     fconfigure $fd -blocking 0 -translation lf -eofchar {}
     if {$tclencoding != {}} {
 	fconfigure $fd -encoding $tclencoding
     }
-    filerun $fd [list getcommitlines $fd $view]
+    filerun $fd [list getcommitlines $fd $i $view 0]
     nowbusy $view [mc "Reading"]
     if {$view == $curview} {
-	set progressdirn 1
-	set progresscoords {0 0}
-	set proglastnc 0
+	set pending_select $mainheadid
     }
+    set viewcomplete($view) 0
+    set viewactive($view) 1
+    return 1
 }
 
-proc stop_rev_list {} {
-    global commfd curview
+proc stop_rev_list {view} {
+    global commfd viewinstances leftover
 
-    if {![info exists commfd($curview)]} return
-    set fd $commfd($curview)
-    catch {
-	set pid [pid $fd]
-	exec kill $pid
+    foreach inst $viewinstances($view) {
+	set fd $commfd($inst)
+	catch {
+	    set pid [pid $fd]
+	    exec kill $pid
+	}
+	catch {close $fd}
+	nukefile $fd
+	unset commfd($inst)
+	unset leftover($inst)
     }
-    catch {close $fd}
-    unset commfd($curview)
+    set viewinstances($view) {}
 }
 
 proc getcommits {} {
-    global phase canv curview
+    global canv curview need_redisplay viewactive
 
-    set phase getcommits
     initlayout
-    start_rev_list $curview
-    show_status [mc "Reading commits..."]
+    if {[start_rev_list $curview]} {
+	show_status [mc "Reading commits..."]
+	set need_redisplay 1
+    } else {
+	show_status [mc "No commits selected"]
+    }
+}
+
+proc updatecommits {} {
+    global curview vcanopt vorigargs vfilelimit viewinstances
+    global viewactive viewcomplete loginstance tclencoding
+    global startmsecs commfd showneartags showlocalchanges leftover
+    global mainheadid pending_select
+    global isworktree
+    global varcid vposids vnegids vflags vrevs
+
+    set isworktree [expr {[exec git rev-parse --is-inside-work-tree] == "true"}]
+    set oldmainid $mainheadid
+    rereadrefs
+    if {$showlocalchanges} {
+	if {$mainheadid ne $oldmainid} {
+	    dohidelocalchanges
+	}
+	if {[commitinview $mainheadid $curview]} {
+	    dodiffindex
+	}
+    }
+    set view $curview
+    if {$vcanopt($view)} {
+	set oldpos $vposids($view)
+	set oldneg $vnegids($view)
+	set revs [parseviewrevs $view $vrevs($view)]
+	if {$revs eq {}} {
+	    return
+	}
+	# note: getting the delta when negative refs change is hard,
+	# and could require multiple git log invocations, so in that
+	# case we ask git log for all the commits (not just the delta)
+	if {$oldneg eq $vnegids($view)} {
+	    set newrevs {}
+	    set npos 0
+	    # take out positive refs that we asked for before or
+	    # that we have already seen
+	    foreach rev $revs {
+		if {[string length $rev] == 40} {
+		    if {[lsearch -exact $oldpos $rev] < 0
+			&& ![info exists varcid($view,$rev)]} {
+			lappend newrevs $rev
+			incr npos
+		    }
+		} else {
+		    lappend $newrevs $rev
+		}
+	    }
+	    if {$npos == 0} return
+	    set revs $newrevs
+	    set vposids($view) [lsort -unique [concat $oldpos $vposids($view)]]
+	}
+	set args [concat $vflags($view) $revs --not $oldpos]
+    } else {
+	set args $vorigargs($view)
+    }
+    if {[catch {
+	set fd [open [concat | git log --no-color -z --pretty=raw --parents \
+			  --boundary $args "--" $vfilelimit($view)] r]
+    } err]} {
+	error_popup "Error executing git log: $err"
+	return
+    }
+    if {$viewactive($view) == 0} {
+	set startmsecs [clock clicks -milliseconds]
+    }
+    set i [incr loginstance]
+    lappend viewinstances($view) $i
+    set commfd($i) $fd
+    set leftover($i) {}
+    fconfigure $fd -blocking 0 -translation lf -eofchar {}
+    if {$tclencoding != {}} {
+	fconfigure $fd -encoding $tclencoding
+    }
+    filerun $fd [list getcommitlines $fd $i $view 1]
+    incr viewactive($view)
+    set viewcomplete($view) 0
+    set pending_select $mainheadid
+    nowbusy $view "Reading"
+    if {$showneartags} {
+	getallcommits
+    }
+}
+
+proc reloadcommits {} {
+    global curview viewcomplete selectedline currentid thickerline
+    global showneartags treediffs commitinterest cached_commitrow
+    global targetid
+
+    if {!$viewcomplete($curview)} {
+	stop_rev_list $curview
+    }
+    resetvarcs $curview
+    set selectedline {}
+    catch {unset currentid}
+    catch {unset thickerline}
+    catch {unset treediffs}
+    readrefs
+    changedrefs
+    if {$showneartags} {
+	getallcommits
+    }
+    clear_display
+    catch {unset commitinterest}
+    catch {unset cached_commitrow}
+    catch {unset targetid}
+    setcanvscroll
+    getcommits
+    return 0
 }
 
 # This makes a string representation of a positive integer which
@@ -164,46 +526,759 @@
     return [format "z%.8x" $n]
 }
 
-proc getcommitlines {fd view}  {
-    global commitlisted commitinterest
-    global leftover commfd
-    global displayorder commitidx viewcomplete commitrow commitdata
-    global parentlist children curview hlview
-    global vparentlist vdisporder vcmitlisted
-    global ordertok vnextroot idpending
+# Procedures used in reordering commits from git log (without
+# --topo-order) into the order for display.
+
+proc varcinit {view} {
+    global varcstart vupptr vdownptr vleftptr vbackptr varctok varcrow
+    global vtokmod varcmod vrowmod varcix vlastins
+
+    set varcstart($view) {{}}
+    set vupptr($view) {0}
+    set vdownptr($view) {0}
+    set vleftptr($view) {0}
+    set vbackptr($view) {0}
+    set varctok($view) {{}}
+    set varcrow($view) {{}}
+    set vtokmod($view) {}
+    set varcmod($view) 0
+    set vrowmod($view) 0
+    set varcix($view) {{}}
+    set vlastins($view) {0}
+}
+
+proc resetvarcs {view} {
+    global varcid varccommits parents children vseedcount ordertok
+
+    foreach vid [array names varcid $view,*] {
+	unset varcid($vid)
+	unset children($vid)
+	unset parents($vid)
+    }
+    # some commits might have children but haven't been seen yet
+    foreach vid [array names children $view,*] {
+	unset children($vid)
+    }
+    foreach va [array names varccommits $view,*] {
+	unset varccommits($va)
+    }
+    foreach vd [array names vseedcount $view,*] {
+	unset vseedcount($vd)
+    }
+    catch {unset ordertok}
+}
+
+# returns a list of the commits with no children
+proc seeds {v} {
+    global vdownptr vleftptr varcstart
+
+    set ret {}
+    set a [lindex $vdownptr($v) 0]
+    while {$a != 0} {
+	lappend ret [lindex $varcstart($v) $a]
+	set a [lindex $vleftptr($v) $a]
+    }
+    return $ret
+}
+
+proc newvarc {view id} {
+    global varcid varctok parents children vdatemode
+    global vupptr vdownptr vleftptr vbackptr varcrow varcix varcstart
+    global commitdata commitinfo vseedcount varccommits vlastins
+
+    set a [llength $varctok($view)]
+    set vid $view,$id
+    if {[llength $children($vid)] == 0 || $vdatemode($view)} {
+	if {![info exists commitinfo($id)]} {
+	    parsecommit $id $commitdata($id) 1
+	}
+	set cdate [lindex $commitinfo($id) 4]
+	if {![string is integer -strict $cdate]} {
+	    set cdate 0
+	}
+	if {![info exists vseedcount($view,$cdate)]} {
+	    set vseedcount($view,$cdate) -1
+	}
+	set c [incr vseedcount($view,$cdate)]
+	set cdate [expr {$cdate ^ 0xffffffff}]
+	set tok "s[strrep $cdate][strrep $c]"
+    } else {
+	set tok {}
+    }
+    set ka 0
+    if {[llength $children($vid)] > 0} {
+	set kid [lindex $children($vid) end]
+	set k $varcid($view,$kid)
+	if {[string compare [lindex $varctok($view) $k] $tok] > 0} {
+	    set ki $kid
+	    set ka $k
+	    set tok [lindex $varctok($view) $k]
+	}
+    }
+    if {$ka != 0} {
+	set i [lsearch -exact $parents($view,$ki) $id]
+	set j [expr {[llength $parents($view,$ki)] - 1 - $i}]
+	append tok [strrep $j]
+    }
+    set c [lindex $vlastins($view) $ka]
+    if {$c == 0 || [string compare $tok [lindex $varctok($view) $c]] < 0} {
+	set c $ka
+	set b [lindex $vdownptr($view) $ka]
+    } else {
+	set b [lindex $vleftptr($view) $c]
+    }
+    while {$b != 0 && [string compare $tok [lindex $varctok($view) $b]] >= 0} {
+	set c $b
+	set b [lindex $vleftptr($view) $c]
+    }
+    if {$c == $ka} {
+	lset vdownptr($view) $ka $a
+	lappend vbackptr($view) 0
+    } else {
+	lset vleftptr($view) $c $a
+	lappend vbackptr($view) $c
+    }
+    lset vlastins($view) $ka $a
+    lappend vupptr($view) $ka
+    lappend vleftptr($view) $b
+    if {$b != 0} {
+	lset vbackptr($view) $b $a
+    }
+    lappend varctok($view) $tok
+    lappend varcstart($view) $id
+    lappend vdownptr($view) 0
+    lappend varcrow($view) {}
+    lappend varcix($view) {}
+    set varccommits($view,$a) {}
+    lappend vlastins($view) 0
+    return $a
+}
+
+proc splitvarc {p v} {
+    global varcid varcstart varccommits varctok
+    global vupptr vdownptr vleftptr vbackptr varcix varcrow vlastins
+
+    set oa $varcid($v,$p)
+    set ac $varccommits($v,$oa)
+    set i [lsearch -exact $varccommits($v,$oa) $p]
+    if {$i <= 0} return
+    set na [llength $varctok($v)]
+    # "%" sorts before "0"...
+    set tok "[lindex $varctok($v) $oa]%[strrep $i]"
+    lappend varctok($v) $tok
+    lappend varcrow($v) {}
+    lappend varcix($v) {}
+    set varccommits($v,$oa) [lrange $ac 0 [expr {$i - 1}]]
+    set varccommits($v,$na) [lrange $ac $i end]
+    lappend varcstart($v) $p
+    foreach id $varccommits($v,$na) {
+	set varcid($v,$id) $na
+    }
+    lappend vdownptr($v) [lindex $vdownptr($v) $oa]
+    lappend vlastins($v) [lindex $vlastins($v) $oa]
+    lset vdownptr($v) $oa $na
+    lset vlastins($v) $oa 0
+    lappend vupptr($v) $oa
+    lappend vleftptr($v) 0
+    lappend vbackptr($v) 0
+    for {set b [lindex $vdownptr($v) $na]} {$b != 0} {set b [lindex $vleftptr($v) $b]} {
+	lset vupptr($v) $b $na
+    }
+}
+
+proc renumbervarc {a v} {
+    global parents children varctok varcstart varccommits
+    global vupptr vdownptr vleftptr vbackptr vlastins varcid vtokmod vdatemode
+
+    set t1 [clock clicks -milliseconds]
+    set todo {}
+    set isrelated($a) 1
+    set kidchanged($a) 1
+    set ntot 0
+    while {$a != 0} {
+	if {[info exists isrelated($a)]} {
+	    lappend todo $a
+	    set id [lindex $varccommits($v,$a) end]
+	    foreach p $parents($v,$id) {
+		if {[info exists varcid($v,$p)]} {
+		    set isrelated($varcid($v,$p)) 1
+		}
+	    }
+	}
+	incr ntot
+	set b [lindex $vdownptr($v) $a]
+	if {$b == 0} {
+	    while {$a != 0} {
+		set b [lindex $vleftptr($v) $a]
+		if {$b != 0} break
+		set a [lindex $vupptr($v) $a]
+	    }
+	}
+	set a $b
+    }
+    foreach a $todo {
+	if {![info exists kidchanged($a)]} continue
+	set id [lindex $varcstart($v) $a]
+	if {[llength $children($v,$id)] > 1} {
+	    set children($v,$id) [lsort -command [list vtokcmp $v] \
+				      $children($v,$id)]
+	}
+	set oldtok [lindex $varctok($v) $a]
+	if {!$vdatemode($v)} {
+	    set tok {}
+	} else {
+	    set tok $oldtok
+	}
+	set ka 0
+	set kid [last_real_child $v,$id]
+	if {$kid ne {}} {
+	    set k $varcid($v,$kid)
+	    if {[string compare [lindex $varctok($v) $k] $tok] > 0} {
+		set ki $kid
+		set ka $k
+		set tok [lindex $varctok($v) $k]
+	    }
+	}
+	if {$ka != 0} {
+	    set i [lsearch -exact $parents($v,$ki) $id]
+	    set j [expr {[llength $parents($v,$ki)] - 1 - $i}]
+	    append tok [strrep $j]
+	}
+	if {$tok eq $oldtok} {
+	    continue
+	}
+	set id [lindex $varccommits($v,$a) end]
+	foreach p $parents($v,$id) {
+	    if {[info exists varcid($v,$p)]} {
+		set kidchanged($varcid($v,$p)) 1
+	    } else {
+		set sortkids($p) 1
+	    }
+	}
+	lset varctok($v) $a $tok
+	set b [lindex $vupptr($v) $a]
+	if {$b != $ka} {
+	    if {[string compare [lindex $varctok($v) $ka] $vtokmod($v)] < 0} {
+		modify_arc $v $ka
+	    }
+	    if {[string compare [lindex $varctok($v) $b] $vtokmod($v)] < 0} {
+		modify_arc $v $b
+	    }
+	    set c [lindex $vbackptr($v) $a]
+	    set d [lindex $vleftptr($v) $a]
+	    if {$c == 0} {
+		lset vdownptr($v) $b $d
+	    } else {
+		lset vleftptr($v) $c $d
+	    }
+	    if {$d != 0} {
+		lset vbackptr($v) $d $c
+	    }
+	    if {[lindex $vlastins($v) $b] == $a} {
+		lset vlastins($v) $b $c
+	    }
+	    lset vupptr($v) $a $ka
+	    set c [lindex $vlastins($v) $ka]
+	    if {$c == 0 || \
+		    [string compare $tok [lindex $varctok($v) $c]] < 0} {
+		set c $ka
+		set b [lindex $vdownptr($v) $ka]
+	    } else {
+		set b [lindex $vleftptr($v) $c]
+	    }
+	    while {$b != 0 && \
+		      [string compare $tok [lindex $varctok($v) $b]] >= 0} {
+		set c $b
+		set b [lindex $vleftptr($v) $c]
+	    }
+	    if {$c == $ka} {
+ 		lset vdownptr($v) $ka $a
+		lset vbackptr($v) $a 0
+	    } else {
+		lset vleftptr($v) $c $a
+		lset vbackptr($v) $a $c
+	    }
+	    lset vleftptr($v) $a $b
+	    if {$b != 0} {
+		lset vbackptr($v) $b $a
+	    }
+	    lset vlastins($v) $ka $a
+	}
+    }
+    foreach id [array names sortkids] {
+	if {[llength $children($v,$id)] > 1} {
+	    set children($v,$id) [lsort -command [list vtokcmp $v] \
+				      $children($v,$id)]
+	}
+    }
+    set t2 [clock clicks -milliseconds]
+    #puts "renumbervarc did [llength $todo] of $ntot arcs in [expr {$t2-$t1}]ms"
+}
+
+# Fix up the graph after we have found out that in view $v,
+# $p (a commit that we have already seen) is actually the parent
+# of the last commit in arc $a.
+proc fix_reversal {p a v} {
+    global varcid varcstart varctok vupptr
+
+    set pa $varcid($v,$p)
+    if {$p ne [lindex $varcstart($v) $pa]} {
+	splitvarc $p $v
+	set pa $varcid($v,$p)
+    }
+    # seeds always need to be renumbered
+    if {[lindex $vupptr($v) $pa] == 0 ||
+	[string compare [lindex $varctok($v) $a] \
+	     [lindex $varctok($v) $pa]] > 0} {
+	renumbervarc $pa $v
+    }
+}
+
+proc insertrow {id p v} {
+    global cmitlisted children parents varcid varctok vtokmod
+    global varccommits ordertok commitidx numcommits curview
+    global targetid targetrow
+
+    readcommit $id
+    set vid $v,$id
+    set cmitlisted($vid) 1
+    set children($vid) {}
+    set parents($vid) [list $p]
+    set a [newvarc $v $id]
+    set varcid($vid) $a
+    if {[string compare [lindex $varctok($v) $a] $vtokmod($v)] < 0} {
+	modify_arc $v $a
+    }
+    lappend varccommits($v,$a) $id
+    set vp $v,$p
+    if {[llength [lappend children($vp) $id]] > 1} {
+	set children($vp) [lsort -command [list vtokcmp $v] $children($vp)]
+	catch {unset ordertok}
+    }
+    fix_reversal $p $a $v
+    incr commitidx($v)
+    if {$v == $curview} {
+	set numcommits $commitidx($v)
+	setcanvscroll
+	if {[info exists targetid]} {
+	    if {![comes_before $targetid $p]} {
+		incr targetrow
+	    }
+	}
+    }
+}
+
+proc insertfakerow {id p} {
+    global varcid varccommits parents children cmitlisted
+    global commitidx varctok vtokmod targetid targetrow curview numcommits
+
+    set v $curview
+    set a $varcid($v,$p)
+    set i [lsearch -exact $varccommits($v,$a) $p]
+    if {$i < 0} {
+	puts "oops: insertfakerow can't find [shortids $p] on arc $a"
+	return
+    }
+    set children($v,$id) {}
+    set parents($v,$id) [list $p]
+    set varcid($v,$id) $a
+    lappend children($v,$p) $id
+    set cmitlisted($v,$id) 1
+    set numcommits [incr commitidx($v)]
+    # note we deliberately don't update varcstart($v) even if $i == 0
+    set varccommits($v,$a) [linsert $varccommits($v,$a) $i $id]
+    modify_arc $v $a $i
+    if {[info exists targetid]} {
+	if {![comes_before $targetid $p]} {
+	    incr targetrow
+	}
+    }
+    setcanvscroll
+    drawvisible
+}
+
+proc removefakerow {id} {
+    global varcid varccommits parents children commitidx
+    global varctok vtokmod cmitlisted currentid selectedline
+    global targetid curview numcommits
+
+    set v $curview
+    if {[llength $parents($v,$id)] != 1} {
+	puts "oops: removefakerow [shortids $id] has [llength $parents($v,$id)] parents"
+	return
+    }
+    set p [lindex $parents($v,$id) 0]
+    set a $varcid($v,$id)
+    set i [lsearch -exact $varccommits($v,$a) $id]
+    if {$i < 0} {
+	puts "oops: removefakerow can't find [shortids $id] on arc $a"
+	return
+    }
+    unset varcid($v,$id)
+    set varccommits($v,$a) [lreplace $varccommits($v,$a) $i $i]
+    unset parents($v,$id)
+    unset children($v,$id)
+    unset cmitlisted($v,$id)
+    set numcommits [incr commitidx($v) -1]
+    set j [lsearch -exact $children($v,$p) $id]
+    if {$j >= 0} {
+	set children($v,$p) [lreplace $children($v,$p) $j $j]
+    }
+    modify_arc $v $a $i
+    if {[info exist currentid] && $id eq $currentid} {
+	unset currentid
+	set selectedline {}
+    }
+    if {[info exists targetid] && $targetid eq $id} {
+	set targetid $p
+    }
+    setcanvscroll
+    drawvisible
+}
+
+proc first_real_child {vp} {
+    global children nullid nullid2
+
+    foreach id $children($vp) {
+	if {$id ne $nullid && $id ne $nullid2} {
+	    return $id
+	}
+    }
+    return {}
+}
+
+proc last_real_child {vp} {
+    global children nullid nullid2
+
+    set kids $children($vp)
+    for {set i [llength $kids]} {[incr i -1] >= 0} {} {
+	set id [lindex $kids $i]
+	if {$id ne $nullid && $id ne $nullid2} {
+	    return $id
+	}
+    }
+    return {}
+}
+
+proc vtokcmp {v a b} {
+    global varctok varcid
+
+    return [string compare [lindex $varctok($v) $varcid($v,$a)] \
+		[lindex $varctok($v) $varcid($v,$b)]]
+}
+
+# This assumes that if lim is not given, the caller has checked that
+# arc a's token is less than $vtokmod($v)
+proc modify_arc {v a {lim {}}} {
+    global varctok vtokmod varcmod varcrow vupptr curview vrowmod varccommits
+
+    if {$lim ne {}} {
+	set c [string compare [lindex $varctok($v) $a] $vtokmod($v)]
+	if {$c > 0} return
+	if {$c == 0} {
+	    set r [lindex $varcrow($v) $a]
+	    if {$r ne {} && $vrowmod($v) <= $r + $lim} return
+	}
+    }
+    set vtokmod($v) [lindex $varctok($v) $a]
+    set varcmod($v) $a
+    if {$v == $curview} {
+	while {$a != 0 && [lindex $varcrow($v) $a] eq {}} {
+	    set a [lindex $vupptr($v) $a]
+	    set lim {}
+	}
+	set r 0
+	if {$a != 0} {
+	    if {$lim eq {}} {
+		set lim [llength $varccommits($v,$a)]
+	    }
+	    set r [expr {[lindex $varcrow($v) $a] + $lim}]
+	}
+	set vrowmod($v) $r
+	undolayout $r
+    }
+}
+
+proc update_arcrows {v} {
+    global vtokmod varcmod vrowmod varcrow commitidx currentid selectedline
+    global varcid vrownum varcorder varcix varccommits
+    global vupptr vdownptr vleftptr varctok
+    global displayorder parentlist curview cached_commitrow
+
+    if {$vrowmod($v) == $commitidx($v)} return
+    if {$v == $curview} {
+	if {[llength $displayorder] > $vrowmod($v)} {
+	    set displayorder [lrange $displayorder 0 [expr {$vrowmod($v) - 1}]]
+	    set parentlist [lrange $parentlist 0 [expr {$vrowmod($v) - 1}]]
+	}
+	catch {unset cached_commitrow}
+    }
+    set narctot [expr {[llength $varctok($v)] - 1}]
+    set a $varcmod($v)
+    while {$a != 0 && [lindex $varcix($v) $a] eq {}} {
+	# go up the tree until we find something that has a row number,
+	# or we get to a seed
+	set a [lindex $vupptr($v) $a]
+    }
+    if {$a == 0} {
+	set a [lindex $vdownptr($v) 0]
+	if {$a == 0} return
+	set vrownum($v) {0}
+	set varcorder($v) [list $a]
+	lset varcix($v) $a 0
+	lset varcrow($v) $a 0
+	set arcn 0
+	set row 0
+    } else {
+	set arcn [lindex $varcix($v) $a]
+	if {[llength $vrownum($v)] > $arcn + 1} {
+	    set vrownum($v) [lrange $vrownum($v) 0 $arcn]
+	    set varcorder($v) [lrange $varcorder($v) 0 $arcn]
+	}
+	set row [lindex $varcrow($v) $a]
+    }
+    while {1} {
+	set p $a
+	incr row [llength $varccommits($v,$a)]
+	# go down if possible
+	set b [lindex $vdownptr($v) $a]
+	if {$b == 0} {
+	    # if not, go left, or go up until we can go left
+	    while {$a != 0} {
+		set b [lindex $vleftptr($v) $a]
+		if {$b != 0} break
+		set a [lindex $vupptr($v) $a]
+	    }
+	    if {$a == 0} break
+	}
+	set a $b
+	incr arcn
+	lappend vrownum($v) $row
+	lappend varcorder($v) $a
+	lset varcix($v) $a $arcn
+	lset varcrow($v) $a $row
+    }
+    set vtokmod($v) [lindex $varctok($v) $p]
+    set varcmod($v) $p
+    set vrowmod($v) $row
+    if {[info exists currentid]} {
+	set selectedline [rowofcommit $currentid]
+    }
+}
+
+# Test whether view $v contains commit $id
+proc commitinview {id v} {
+    global varcid
+
+    return [info exists varcid($v,$id)]
+}
+
+# Return the row number for commit $id in the current view
+proc rowofcommit {id} {
+    global varcid varccommits varcrow curview cached_commitrow
+    global varctok vtokmod
+
+    set v $curview
+    if {![info exists varcid($v,$id)]} {
+	puts "oops rowofcommit no arc for [shortids $id]"
+	return {}
+    }
+    set a $varcid($v,$id)
+    if {[string compare [lindex $varctok($v) $a] $vtokmod($v)] >= 0} {
+	update_arcrows $v
+    }
+    if {[info exists cached_commitrow($id)]} {
+	return $cached_commitrow($id)
+    }
+    set i [lsearch -exact $varccommits($v,$a) $id]
+    if {$i < 0} {
+	puts "oops didn't find commit [shortids $id] in arc $a"
+	return {}
+    }
+    incr i [lindex $varcrow($v) $a]
+    set cached_commitrow($id) $i
+    return $i
+}
+
+# Returns 1 if a is on an earlier row than b, otherwise 0
+proc comes_before {a b} {
+    global varcid varctok curview
+
+    set v $curview
+    if {$a eq $b || ![info exists varcid($v,$a)] || \
+	    ![info exists varcid($v,$b)]} {
+	return 0
+    }
+    if {$varcid($v,$a) != $varcid($v,$b)} {
+	return [expr {[string compare [lindex $varctok($v) $varcid($v,$a)] \
+			   [lindex $varctok($v) $varcid($v,$b)]] < 0}]
+    }
+    return [expr {[rowofcommit $a] < [rowofcommit $b]}]
+}
+
+proc bsearch {l elt} {
+    if {[llength $l] == 0 || $elt <= [lindex $l 0]} {
+	return 0
+    }
+    set lo 0
+    set hi [llength $l]
+    while {$hi - $lo > 1} {
+	set mid [expr {int(($lo + $hi) / 2)}]
+	set t [lindex $l $mid]
+	if {$elt < $t} {
+	    set hi $mid
+	} elseif {$elt > $t} {
+	    set lo $mid
+	} else {
+	    return $mid
+	}
+    }
+    return $lo
+}
+
+# Make sure rows $start..$end-1 are valid in displayorder and parentlist
+proc make_disporder {start end} {
+    global vrownum curview commitidx displayorder parentlist
+    global varccommits varcorder parents vrowmod varcrow
+    global d_valid_start d_valid_end
+
+    if {$end > $vrowmod($curview)} {
+	update_arcrows $curview
+    }
+    set ai [bsearch $vrownum($curview) $start]
+    set start [lindex $vrownum($curview) $ai]
+    set narc [llength $vrownum($curview)]
+    for {set r $start} {$ai < $narc && $r < $end} {incr ai} {
+	set a [lindex $varcorder($curview) $ai]
+	set l [llength $displayorder]
+	set al [llength $varccommits($curview,$a)]
+	if {$l < $r + $al} {
+	    if {$l < $r} {
+		set pad [ntimes [expr {$r - $l}] {}]
+		set displayorder [concat $displayorder $pad]
+		set parentlist [concat $parentlist $pad]
+	    } elseif {$l > $r} {
+		set displayorder [lrange $displayorder 0 [expr {$r - 1}]]
+		set parentlist [lrange $parentlist 0 [expr {$r - 1}]]
+	    }
+	    foreach id $varccommits($curview,$a) {
+		lappend displayorder $id
+		lappend parentlist $parents($curview,$id)
+	    }
+	} elseif {[lindex $displayorder [expr {$r + $al - 1}]] eq {}} {
+	    set i $r
+	    foreach id $varccommits($curview,$a) {
+		lset displayorder $i $id
+		lset parentlist $i $parents($curview,$id)
+		incr i
+	    }
+	}
+	incr r $al
+    }
+}
+
+proc commitonrow {row} {
+    global displayorder
+
+    set id [lindex $displayorder $row]
+    if {$id eq {}} {
+	make_disporder $row [expr {$row + 1}]
+	set id [lindex $displayorder $row]
+    }
+    return $id
+}
+
+proc closevarcs {v} {
+    global varctok varccommits varcid parents children
+    global cmitlisted commitidx commitinterest vtokmod
+
+    set missing_parents 0
+    set scripts {}
+    set narcs [llength $varctok($v)]
+    for {set a 1} {$a < $narcs} {incr a} {
+	set id [lindex $varccommits($v,$a) end]
+	foreach p $parents($v,$id) {
+	    if {[info exists varcid($v,$p)]} continue
+	    # add p as a new commit
+	    incr missing_parents
+	    set cmitlisted($v,$p) 0
+	    set parents($v,$p) {}
+	    if {[llength $children($v,$p)] == 1 &&
+		[llength $parents($v,$id)] == 1} {
+		set b $a
+	    } else {
+		set b [newvarc $v $p]
+	    }
+	    set varcid($v,$p) $b
+	    if {[string compare [lindex $varctok($v) $b] $vtokmod($v)] < 0} {
+		modify_arc $v $b
+	    }
+	    lappend varccommits($v,$b) $p
+	    incr commitidx($v)
+	    if {[info exists commitinterest($p)]} {
+		foreach script $commitinterest($p) {
+		    lappend scripts [string map [list "%I" $p] $script]
+		}
+		unset commitinterest($id)
+	    }
+	}
+    }
+    if {$missing_parents > 0} {
+	foreach s $scripts {
+	    eval $s
+	}
+    }
+}
+
+# Use $rwid as a substitute for $id, i.e. reparent $id's children to $rwid
+# Assumes we already have an arc for $rwid.
+proc rewrite_commit {v id rwid} {
+    global children parents varcid varctok vtokmod varccommits
+
+    foreach ch $children($v,$id) {
+	# make $rwid be $ch's parent in place of $id
+	set i [lsearch -exact $parents($v,$ch) $id]
+	if {$i < 0} {
+	    puts "oops rewrite_commit didn't find $id in parent list for $ch"
+	}
+	set parents($v,$ch) [lreplace $parents($v,$ch) $i $i $rwid]
+	# add $ch to $rwid's children and sort the list if necessary
+	if {[llength [lappend children($v,$rwid) $ch]] > 1} {
+	    set children($v,$rwid) [lsort -command [list vtokcmp $v] \
+					$children($v,$rwid)]
+	}
+	# fix the graph after joining $id to $rwid
+	set a $varcid($v,$ch)
+	fix_reversal $rwid $a $v
+	# parentlist is wrong for the last element of arc $a
+	# even if displayorder is right, hence the 3rd arg here
+	modify_arc $v $a [expr {[llength $varccommits($v,$a)] - 1}]
+    }
+}
+
+proc getcommitlines {fd inst view updating}  {
+    global cmitlisted commitinterest leftover
+    global commitidx commitdata vdatemode
+    global parents children curview hlview
+    global idpending ordertok
+    global varccommits varcid varctok vtokmod vfilelimit
 
     set stuff [read $fd 500000]
     # git log doesn't terminate the last commit with a null...
-    if {$stuff == {} && $leftover($view) ne {} && [eof $fd]} {
+    if {$stuff == {} && $leftover($inst) ne {} && [eof $fd]} {
 	set stuff "\0"
     }
     if {$stuff == {}} {
 	if {![eof $fd]} {
 	    return 1
 	}
-	# Check if we have seen any ids listed as parents that haven't
-	# appeared in the list
-	foreach vid [array names idpending "$view,*"] {
-	    # should only get here if git log is buggy
-	    set id [lindex [split $vid ","] 1]
-	    set commitrow($vid) $commitidx($view)
-	    incr commitidx($view)
-	    if {$view == $curview} {
-		lappend parentlist {}
-		lappend displayorder $id
-		lappend commitlisted 0
-	    } else {
-		lappend vparentlist($view) {}
-		lappend vdisporder($view) $id
-		lappend vcmitlisted($view) 0
-	    }
+	global commfd viewcomplete viewactive viewname
+	global viewinstances
+	unset commfd($inst)
+	set i [lsearch -exact $viewinstances($view) $inst]
+	if {$i >= 0} {
+	    set viewinstances($view) [lreplace $viewinstances($view) $i $i]
 	}
-	set viewcomplete($view) 1
-	global viewname progresscoords
-	unset commfd($view)
-	notbusy $view
-	set progresscoords {0 0}
-	adjustprogress
 	# set it blocking so we wait for the process to terminate
 	fconfigure $fd -blocking 1
 	if {[catch {close $fd} err]} {
@@ -213,10 +1288,10 @@
 	    }
 	    if {[string range $err 0 4] == "usage"} {
 		set err "Gitk: error reading commits$fv:\
-			bad arguments to git rev-list."
+			bad arguments to git log."
 		if {$viewname($view) eq "Command line"} {
 		    append err \
-			"  (Note: arguments to gitk are passed to git rev-list\
+			"  (Note: arguments to gitk are passed to git log\
 			 to allow selection of commits to be displayed.)"
 		}
 	    } else {
@@ -224,23 +1299,31 @@
 	    }
 	    error_popup $err
 	}
+	if {[incr viewactive($view) -1] <= 0} {
+	    set viewcomplete($view) 1
+	    # Check if we have seen any ids listed as parents that haven't
+	    # appeared in the list
+	    closevarcs $view
+	    notbusy $view
+	}
 	if {$view == $curview} {
-	    run chewcommits $view
+	    run chewcommits
 	}
 	return 0
     }
     set start 0
     set gotsome 0
+    set scripts {}
     while 1 {
 	set i [string first "\0" $stuff $start]
 	if {$i < 0} {
-	    append leftover($view) [string range $stuff $start end]
+	    append leftover($inst) [string range $stuff $start end]
 	    break
 	}
 	if {$start == 0} {
-	    set cmit $leftover($view)
+	    set cmit $leftover($inst)
 	    append cmit [string range $stuff 0 [expr {$i - 1}]]
-	    set leftover($view) {}
+	    set leftover($inst) {}
 	} else {
 	    set cmit [string range $stuff $start [expr {$i - 1}]]
 	}
@@ -276,121 +1359,127 @@
 	    exit 1
 	}
 	set id [lindex $ids 0]
-	if {![info exists ordertok($view,$id)]} {
-	    set otok "o[strrep $vnextroot($view)]"
-	    incr vnextroot($view)
-	    set ordertok($view,$id) $otok
-	} else {
-	    set otok $ordertok($view,$id)
-	    unset idpending($view,$id)
+	set vid $view,$id
+
+	if {!$listed && $updating && ![info exists varcid($vid)] &&
+	    $vfilelimit($view) ne {}} {
+	    # git log doesn't rewrite parents for unlisted commits
+	    # when doing path limiting, so work around that here
+	    # by working out the rewritten parent with git rev-list
+	    # and if we already know about it, using the rewritten
+	    # parent as a substitute parent for $id's children.
+	    if {![catch {
+		set rwid [exec git rev-list --first-parent --max-count=1 \
+			      $id -- $vfilelimit($view)]
+	    }]} {
+		if {$rwid ne {} && [info exists varcid($view,$rwid)]} {
+		    # use $rwid in place of $id
+		    rewrite_commit $view $id $rwid
+		    continue
+		}
+	    }
+	}
+
+	set a 0
+	if {[info exists varcid($vid)]} {
+	    if {$cmitlisted($vid) || !$listed} continue
+	    set a $varcid($vid)
 	}
 	if {$listed} {
 	    set olds [lrange $ids 1 end]
-	    if {[llength $olds] == 1} {
-		set p [lindex $olds 0]
-		lappend children($view,$p) $id
-		if {![info exists ordertok($view,$p)]} {
-		    set ordertok($view,$p) $ordertok($view,$id)
-		    set idpending($view,$p) 1
-		}
-	    } else {
-		set i 0
-		foreach p $olds {
-		    if {$i == 0 || [lsearch -exact $olds $p] >= $i} {
-			lappend children($view,$p) $id
-		    }
-		    if {![info exists ordertok($view,$p)]} {
-			set ordertok($view,$p) "$otok[strrep $i]]"
-			set idpending($view,$p) 1
-		    }
-		    incr i
-		}
-	    }
 	} else {
 	    set olds {}
 	}
-	if {![info exists children($view,$id)]} {
-	    set children($view,$id) {}
-	}
 	set commitdata($id) [string range $cmit [expr {$j + 1}] end]
-	set commitrow($view,$id) $commitidx($view)
-	incr commitidx($view)
-	if {$view == $curview} {
-	    lappend parentlist $olds
-	    lappend displayorder $id
-	    lappend commitlisted $listed
-	} else {
-	    lappend vparentlist($view) $olds
-	    lappend vdisporder($view) $id
-	    lappend vcmitlisted($view) $listed
+	set cmitlisted($vid) $listed
+	set parents($vid) $olds
+	if {![info exists children($vid)]} {
+	    set children($vid) {}
+	} elseif {$a == 0 && [llength $children($vid)] == 1} {
+	    set k [lindex $children($vid) 0]
+	    if {[llength $parents($view,$k)] == 1 &&
+		(!$vdatemode($view) ||
+		 $varcid($view,$k) == [llength $varctok($view)] - 1)} {
+		set a $varcid($view,$k)
+	    }
 	}
+	if {$a == 0} {
+	    # new arc
+	    set a [newvarc $view $id]
+	}
+	if {[string compare [lindex $varctok($view) $a] $vtokmod($view)] < 0} {
+	    modify_arc $view $a
+	}
+	if {![info exists varcid($vid)]} {
+	    set varcid($vid) $a
+	    lappend varccommits($view,$a) $id
+	    incr commitidx($view)
+	}
+
+	set i 0
+	foreach p $olds {
+	    if {$i == 0 || [lsearch -exact $olds $p] >= $i} {
+		set vp $view,$p
+		if {[llength [lappend children($vp) $id]] > 1 &&
+		    [vtokcmp $view [lindex $children($vp) end-1] $id] > 0} {
+		    set children($vp) [lsort -command [list vtokcmp $view] \
+					   $children($vp)]
+		    catch {unset ordertok}
+		}
+		if {[info exists varcid($view,$p)]} {
+		    fix_reversal $p $a $view
+		}
+	    }
+	    incr i
+	}
+
 	if {[info exists commitinterest($id)]} {
 	    foreach script $commitinterest($id) {
-		eval [string map [list "%I" $id] $script]
+		lappend scripts [string map [list "%I" $id] $script]
 	    }
 	    unset commitinterest($id)
 	}
 	set gotsome 1
     }
     if {$gotsome} {
-	run chewcommits $view
+	global numcommits hlview
+
 	if {$view == $curview} {
-	    # update progress bar
-	    global progressdirn progresscoords proglastnc
-	    set inc [expr {($commitidx($view) - $proglastnc) * 0.0002}]
-	    set proglastnc $commitidx($view)
-	    set l [lindex $progresscoords 0]
-	    set r [lindex $progresscoords 1]
-	    if {$progressdirn} {
-		set r [expr {$r + $inc}]
-		if {$r >= 1.0} {
-		    set r 1.0
-		    set progressdirn 0
-		}
-		if {$r > 0.2} {
-		    set l [expr {$r - 0.2}]
-		}
-	    } else {
-		set l [expr {$l - $inc}]
-		if {$l <= 0.0} {
-		    set l 0.0
-		    set progressdirn 1
-		}
-		set r [expr {$l + 0.2}]
-	    }
-	    set progresscoords [list $l $r]
-	    adjustprogress
+	    set numcommits $commitidx($view)
+	    run chewcommits
+	}
+	if {[info exists hlview] && $view == $hlview} {
+	    # we never actually get here...
+	    run vhighlightmore
+	}
+	foreach s $scripts {
+	    eval $s
 	}
     }
     return 2
 }
 
-proc chewcommits {view} {
+proc chewcommits {} {
     global curview hlview viewcomplete
-    global selectedline pending_select
+    global pending_select
 
-    if {$view == $curview} {
-	layoutmore
-	if {$viewcomplete($view)} {
-	    global displayorder commitidx phase
-	    global numcommits startmsecs
+    layoutmore
+    if {$viewcomplete($curview)} {
+	global commitidx varctok
+	global numcommits startmsecs
 
-	    if {[info exists pending_select]} {
-		set row [first_real_row]
-		selectline $row 1
-	    }
-	    if {$commitidx($curview) > 0} {
-		#set ms [expr {[clock clicks -milliseconds] - $startmsecs}]
-		#puts "overall $ms ms for $numcommits commits"
-	    } else {
-		show_status [mc "No commits selected"]
-	    }
-	    notbusy layout
-	    set phase {}
+	if {[info exists pending_select]} {
+	    set row [first_real_row]
+	    selectline $row 1
 	}
-    }
-    if {[info exists hlview] && $view == $hlview} {
-	vhighlightmore
+	if {$commitidx($curview) > 0} {
+	    #set ms [expr {[clock clicks -milliseconds] - $startmsecs}]
+	    #puts "overall $ms ms for $numcommits commits"
+	    #puts "[llength $varctok($view)] arcs, $commitidx($view) commits"
+	} else {
+	    show_status [mc "No commits selected"]
+	}
+	notbusy layout
     }
     return 0
 }
@@ -400,38 +1489,6 @@
     parsecommit $id $contents 0
 }
 
-proc updatecommits {} {
-    global viewdata curview phase displayorder ordertok idpending
-    global children commitrow selectedline thickerline showneartags
-    global isworktree
-
-    set isworktree [expr {[exec git rev-parse --is-inside-work-tree] == "true"}]
-
-    if {$phase ne {}} {
-	stop_rev_list
-	set phase {}
-    }
-    set n $curview
-    foreach id $displayorder {
-	catch {unset children($n,$id)}
-	catch {unset commitrow($n,$id)}
-	catch {unset ordertok($n,$id)}
-    }
-    foreach vid [array names idpending "$n,*"] {
-	unset idpending($vid)
-    }
-    set curview -1
-    catch {unset selectedline}
-    catch {unset thickerline}
-    catch {unset viewdata($n)}
-    readrefs
-    changedrefs
-    if {$showneartags} {
-	getallcommits
-    }
-    showview $n
-}
-
 proc parsecommit {id contents listed} {
     global commitinfo cdate
 
@@ -472,7 +1529,7 @@
 	set headline [string trimright [string range $headline 0 $i]]
     }
     if {!$listed} {
-	# git rev-list indents the comment by 4 spaces;
+	# git log indents the comment by 4 spaces;
 	# if we got this via git cat-file, add the indentation
 	set newcomment {}
 	foreach line [split $comment "\n"] {
@@ -546,22 +1603,20 @@
     set mainhead {}
     set mainheadid {}
     catch {
+	set mainheadid [exec git rev-parse HEAD]
 	set thehead [exec git symbolic-ref HEAD]
 	if {[string match "refs/heads/*" $thehead]} {
 	    set mainhead [string range $thehead 11 end]
-	    if {[info exists headids($mainhead)]} {
-		set mainheadid $headids($mainhead)
-	    }
 	}
     }
 }
 
 # skip over fake commits
 proc first_real_row {} {
-    global nullid nullid2 displayorder numcommits
+    global nullid nullid2 numcommits
 
     for {set row 0} {$row < $numcommits} {incr row} {
-	set id [lindex $displayorder $row]
+	set id [commitonrow $row]
 	if {$id ne $nullid && $id ne $nullid2} {
 	    break
 	}
@@ -641,7 +1696,7 @@
 }
 
 proc makewindow {} {
-    global canv canv2 canv3 linespc charspc ctext cflist
+    global canv canv2 canv3 linespc charspc ctext cflist cscroll
     global tabstop
     global findtype findtypemenu findloc findstring fstring geometry
     global entries sha1entry sha1string sha1but
@@ -654,13 +1709,14 @@
     global bgcolor fgcolor bglist fglist diffcolors selectbgcolor
     global headctxmenu progresscanv progressitem progresscoords statusw
     global fprogitem fprogcoord lastprogupdate progupdatepending
-    global rprogitem rprogcoord
+    global rprogitem rprogcoord rownumsel numcommits
     global have_tk85
 
     menu .bar
     .bar add cascade -label [mc "File"] -menu .bar.file
     menu .bar.file
     .bar.file add command -label [mc "Update"] -command updatecommits
+    .bar.file add command -label [mc "Reload"] -command reloadcommits
     .bar.file add command -label [mc "Reread references"] -command rereadrefs
     .bar.file add command -label [mc "List references"] -command showrefs
     .bar.file add command -label [mc "Quit"] -command doquit
@@ -769,6 +1825,18 @@
 	-state disabled -width 26
     pack .tf.bar.rightbut -side left -fill y
 
+    label .tf.bar.rowlabel -text [mc "Row"]
+    set rownumsel {}
+    label .tf.bar.rownum -width 7 -font textfont -textvariable rownumsel \
+	-relief sunken -anchor e
+    label .tf.bar.rowlabel2 -text "/"
+    label .tf.bar.numcommits -width 7 -font textfont -textvariable numcommits \
+	-relief sunken -anchor e
+    pack .tf.bar.rowlabel .tf.bar.rownum .tf.bar.rowlabel2 .tf.bar.numcommits \
+	-side left
+    global selectedline
+    trace add variable selectedline write selectedline_change
+
     # Status label and progress bar
     set statusw .tf.bar.status
     label $statusw -width 15 -relief sunken
@@ -1016,7 +2084,7 @@
     bindkey k "selnextline 1"
     bindkey j "goback"
     bindkey l "goforw"
-    bindkey b "$ctext yview scroll -1 pages"
+    bindkey b prevfile
     bindkey d "$ctext yview scroll 18 units"
     bindkey u "$ctext yview scroll -18 units"
     bindkey / {dofind 1 1}
@@ -1088,6 +2156,8 @@
 	-command {flist_hl 0}
     $flist_menu add command -label [mc "Highlight this only"] \
 	-command {flist_hl 1}
+    $flist_menu add command -label [mc "External diff"] \
+        -command {external_diff}
 }
 
 # Windows sends all mouse wheel events to the current focused window, not
@@ -1108,6 +2178,17 @@
     }
 }
 
+# Update row number label when selectedline changes
+proc selectedline_change {n1 n2 op} {
+    global selectedline rownumsel
+
+    if {$selectedline eq {}} {
+	set rownumsel {}
+    } else {
+	set rownumsel [expr {$selectedline + 1}]
+    }
+}
+
 # mouse-2 makes all windows scan vertically, but only the one
 # the cursor is in scans horizontally
 proc canvscan {op w x y} {
@@ -1123,7 +2204,7 @@
 
 proc scrollcanv {cscroll f0 f1} {
     $cscroll set $f0 $f1
-    drawfrac $f0 $f1
+    drawvisible
     flushhighlights
 }
 
@@ -1192,7 +2273,7 @@
     global viewname viewfiles viewargs viewargscmd viewperm nextviewnum
     global cmitmode wrapcomment datetimeformat limitdiffs
     global colors bgcolor fgcolor diffcolors diffcontext selectbgcolor
-    global autoselect
+    global autoselect extdifftool
 
     if {$stuffsaved} return
     if {![winfo viewable .]} return
@@ -1218,6 +2299,7 @@
 	puts $f [list set diffcolors $diffcolors]
 	puts $f [list set diffcontext $diffcontext]
 	puts $f [list set selectbgcolor $selectbgcolor]
+	puts $f [list set extdifftool $extdifftool]
 
 	puts $f "set geometry(main) [wm geometry .]"
 	puts $f "set geometry(topwidth) [winfo width .tf]"
@@ -1318,7 +2400,7 @@
     message $w.m -text [mc "
 Gitk - a commit viewer for git
 
-Copyright © 2005-2006 Paul Mackerras
+Copyright © 2005-2008 Paul Mackerras
 
 Use and redistribute under the terms of the GNU General Public License"] \
 	    -justify center -aspect 400 -border 2 -bg white -relief groove
@@ -1675,7 +2757,7 @@
     -data $rectdata -maskdata $rectmask
 
 proc init_flist {first} {
-    global cflist cflist_top selectedline difffilestart
+    global cflist cflist_top difffilestart
 
     $cflist conf -state normal
     $cflist delete 0.0 end
@@ -1768,6 +2850,12 @@
 	set e [lindex $treediffs($diffids) [expr {$l-2}]]
     }
     set flist_menu_file $e
+    set xdiffstate "normal"
+    if {$cmitmode eq "tree"} {
+	set xdiffstate "disabled"
+    }
+    # Disable "External diff" item in tree mode
+    $flist_menu entryconf 2 -state $xdiffstate
     tk_popup $flist_menu $X $Y
 }
 
@@ -1783,6 +2871,113 @@
     set gdttype [mc "touching paths:"]
 }
 
+proc save_file_from_commit {filename output what} {
+    global nullfile
+
+    if {[catch {exec git show $filename -- > $output} err]} {
+	if {[string match "fatal: bad revision *" $err]} {
+	    return $nullfile
+	}
+	error_popup "Error getting \"$filename\" from $what: $err"
+	return {}
+    }
+    return $output
+}
+
+proc external_diff_get_one_file {diffid filename diffdir} {
+    global nullid nullid2 nullfile
+    global gitdir
+
+    if {$diffid == $nullid} {
+        set difffile [file join [file dirname $gitdir] $filename]
+	if {[file exists $difffile]} {
+	    return $difffile
+	}
+	return $nullfile
+    }
+    if {$diffid == $nullid2} {
+        set difffile [file join $diffdir "\[index\] [file tail $filename]"]
+        return [save_file_from_commit :$filename $difffile index]
+    }
+    set difffile [file join $diffdir "\[$diffid\] [file tail $filename]"]
+    return [save_file_from_commit $diffid:$filename $difffile \
+	       "revision $diffid"]
+}
+
+proc external_diff {} {
+    global gitktmpdir nullid nullid2
+    global flist_menu_file
+    global diffids
+    global diffnum
+    global gitdir extdifftool
+
+    if {[llength $diffids] == 1} {
+        # no reference commit given
+        set diffidto [lindex $diffids 0]
+        if {$diffidto eq $nullid} {
+            # diffing working copy with index
+            set diffidfrom $nullid2
+        } elseif {$diffidto eq $nullid2} {
+            # diffing index with HEAD
+            set diffidfrom "HEAD"
+        } else {
+            # use first parent commit
+            global parentlist selectedline
+            set diffidfrom [lindex $parentlist $selectedline 0]
+        }
+    } else {
+        set diffidfrom [lindex $diffids 0]
+        set diffidto [lindex $diffids 1]
+    }
+
+    # make sure that several diffs wont collide
+    if {![info exists gitktmpdir]} {
+	set gitktmpdir [file join [file dirname $gitdir] \
+			    [format ".gitk-tmp.%s" [pid]]]
+	if {[catch {file mkdir $gitktmpdir} err]} {
+	    error_popup "Error creating temporary directory $gitktmpdir: $err"
+	    unset gitktmpdir
+	    return
+	}
+	set diffnum 0
+    }
+    incr diffnum
+    set diffdir [file join $gitktmpdir $diffnum]
+    if {[catch {file mkdir $diffdir} err]} {
+	error_popup "Error creating temporary directory $diffdir: $err"
+	return
+    }
+
+    # gather files to diff
+    set difffromfile [external_diff_get_one_file $diffidfrom $flist_menu_file $diffdir]
+    set difftofile [external_diff_get_one_file $diffidto $flist_menu_file $diffdir]
+
+    if {$difffromfile ne {} && $difftofile ne {}} {
+        set cmd [concat | [shellsplit $extdifftool] \
+		     [list $difffromfile $difftofile]]
+        if {[catch {set fl [open $cmd r]} err]} {
+            file delete -force $diffdir
+            error_popup [mc "$extdifftool: command failed: $err"]
+        } else {
+            fconfigure $fl -blocking 0
+            filerun $fl [list delete_at_eof $fl $diffdir]
+        }
+    }
+}
+
+# delete $dir when we see eof on $f (presumably because the child has exited)
+proc delete_at_eof {f dir} {
+    while {[gets $f line] >= 0} {}
+    if {[eof $f]} {
+	if {[catch {close $f} err]} {
+	    error_popup "External diff viewer failed: $err"
+	}
+	file delete -force $dir
+	return 0
+    }
+    return 1
+}
+
 # Functions for adding and removing shell-type quoting
 
 proc shellquote {str} {
@@ -1925,7 +3120,7 @@
 	-variable newviewperm($n)
     grid $top.perm - -pady 5 -sticky w
     message $top.al -aspect 1000 \
-	-text [mc "Commits to include (arguments to git rev-list):"]
+	-text [mc "Commits to include (arguments to git log):"]
     grid $top.al - -sticky w -pady 5
     entry $top.args -width 50 -textvariable newviewargs($n) \
 	-background $bgcolor
@@ -2028,7 +3223,7 @@
 	    set viewargs($n) $newargs
 	    set viewargscmd($n) $newviewargscmd($n)
 	    if {$curview == $n} {
-		run updatecommits
+		run reloadcommits
 	    }
 	}
     }
@@ -2036,7 +3231,7 @@
 }
 
 proc delview {} {
-    global curview viewdata viewperm hlview selectedhlview
+    global curview viewperm hlview selectedhlview
 
     if {$curview == 0} return
     if {[info exists hlview] && $hlview == $curview} {
@@ -2044,7 +3239,6 @@
 	unset hlview
     }
     allviewmenus $curview delete
-    set viewdata($curview) {}
     set viewperm($curview) 0
     showview 0
 }
@@ -2058,48 +3252,28 @@
     #	-command [list addvhighlight $n] -variable selectedhlview
 }
 
-proc flatten {var} {
-    global $var
-
-    set ret {}
-    foreach i [array names $var] {
-	lappend ret $i [set $var\($i\)]
-    }
-    return $ret
-}
-
-proc unflatten {var l} {
-    global $var
-
-    catch {unset $var}
-    foreach {i v} $l {
-	set $var\($i\) $v
-    }
-}
-
 proc showview {n} {
-    global curview viewdata viewfiles
+    global curview cached_commitrow ordertok
     global displayorder parentlist rowidlist rowisopt rowfinal
-    global colormap rowtextx commitrow nextcolor canvxmax
-    global numcommits commitlisted
+    global colormap rowtextx nextcolor canvxmax
+    global numcommits viewcomplete
     global selectedline currentid canv canvy0
     global treediffs
-    global pending_select phase
+    global pending_select mainheadid
     global commitidx
-    global commfd
-    global selectedview selectfirst
-    global vparentlist vdisporder vcmitlisted
+    global selectedview
     global hlview selectedhlview commitinterest
 
     if {$n == $curview} return
     set selid {}
-    if {[info exists selectedline]} {
+    set ymax [lindex [$canv cget -scrollregion] 3]
+    set span [$canv yview]
+    set ytop [expr {[lindex $span 0] * $ymax}]
+    set ybot [expr {[lindex $span 1] * $ymax}]
+    set yscreen [expr {($ybot - $ytop) / 2}]
+    if {$selectedline ne {}} {
 	set selid $currentid
 	set y [yc $selectedline]
-	set ymax [lindex [$canv cget -scrollregion] 3]
-	set span [$canv yview]
-	set ytop [expr {[lindex $span 0] * $ymax}]
-	set ybot [expr {[lindex $span 1] * $ymax}]
 	if {$ytop < $y && $y < $ybot} {
 	    set yscreen [expr {$y - $ytop}]
 	}
@@ -2109,17 +3283,6 @@
     }
     unselectline
     normalline
-    if {$curview >= 0} {
-	set vparentlist($curview) $parentlist
-	set vdisporder($curview) $displayorder
-	set vcmitlisted($curview) $commitlisted
-	if {$phase ne {} ||
-	    ![info exists viewdata($curview)] ||
-	    [lindex $viewdata($curview) 0] ne {}} {
-	    set viewdata($curview) \
-		[list $phase $rowidlist $rowisopt $rowfinal]
-	}
-    }
     catch {unset treediffs}
     clear_display
     if {[info exists hlview] && $hlview == $n} {
@@ -2127,6 +3290,8 @@
 	set selectedhlview [mc "None"]
     }
     catch {unset commitinterest}
+    catch {unset cached_commitrow}
+    catch {unset ordertok}
 
     set curview $n
     set selectedview $n
@@ -2134,7 +3299,7 @@
     .bar.view entryconf [mc "Delete view"] -state [expr {$n == 0? "disabled": "normal"}]
 
     run refill_reflist
-    if {![info exists viewdata($n)]} {
+    if {![info exists viewcomplete($n)]} {
 	if {$selid ne {}} {
 	    set pending_select $selid
 	}
@@ -2142,14 +3307,11 @@
 	return
     }
 
-    set v $viewdata($n)
-    set phase [lindex $v 0]
-    set displayorder $vdisporder($n)
-    set parentlist $vparentlist($n)
-    set commitlisted $vcmitlisted($n)
-    set rowidlist [lindex $v 1]
-    set rowisopt [lindex $v 2]
-    set rowfinal [lindex $v 3]
+    set displayorder {}
+    set parentlist {}
+    set rowidlist {}
+    set rowisopt {}
+    set rowfinal {}
     set numcommits $commitidx($n)
 
     catch {unset colormap}
@@ -2161,9 +3323,8 @@
     setcanvscroll
     set yf 0
     set row {}
-    set selectfirst 0
-    if {[info exists yscreen] && [info exists commitrow($n,$selid)]} {
-	set row $commitrow($n,$selid)
+    if {$selid ne {} && [commitinview $selid $n]} {
+	set row [rowofcommit $selid]
 	# try to get the selected row in the same position on the screen
 	set ymax [lindex [$canv cget -scrollregion] 3]
 	set ytop [expr {[yc $row] - $yscreen}]
@@ -2176,21 +3337,24 @@
     drawvisible
     if {$row ne {}} {
 	selectline $row 0
-    } elseif {$selid ne {}} {
-	set pending_select $selid
+    } elseif {$mainheadid ne {} && [commitinview $mainheadid $curview]} {
+	selectline [rowofcommit $mainheadid] 1
+    } elseif {!$viewcomplete($n)} {
+	if {$selid ne {}} {
+	    set pending_select $selid
+	} else {
+	    set pending_select $mainheadid
+	}
     } else {
 	set row [first_real_row]
 	if {$row < $numcommits} {
 	    selectline $row 0
-	} else {
-	    set selectfirst 1
 	}
     }
-    if {$phase ne {}} {
-	if {$phase eq "getcommits"} {
+    if {!$viewcomplete($n)} {
+	if {$numcommits == 0} {
 	    show_status [mc "Reading commits..."]
 	}
-	run chewcommits $n
     } elseif {$numcommits == 0} {
 	show_status [mc "No commits selected"]
     }
@@ -2198,20 +3362,20 @@
 
 # Stuff relating to the highlighting facility
 
-proc ishighlighted {row} {
+proc ishighlighted {id} {
     global vhighlights fhighlights nhighlights rhighlights
 
-    if {[info exists nhighlights($row)] && $nhighlights($row) > 0} {
-	return $nhighlights($row)
+    if {[info exists nhighlights($id)] && $nhighlights($id) > 0} {
+	return $nhighlights($id)
     }
-    if {[info exists vhighlights($row)] && $vhighlights($row) > 0} {
-	return $vhighlights($row)
+    if {[info exists vhighlights($id)] && $vhighlights($id) > 0} {
+	return $vhighlights($id)
     }
-    if {[info exists fhighlights($row)] && $fhighlights($row) > 0} {
-	return $fhighlights($row)
+    if {[info exists fhighlights($id)] && $fhighlights($id) > 0} {
+	return $fhighlights($id)
     }
-    if {[info exists rhighlights($row)] && $rhighlights($row) > 0} {
-	return $rhighlights($row)
+    if {[info exists rhighlights($id)] && $rhighlights($id) > 0} {
+	return $rhighlights($id)
     }
     return 0
 }
@@ -2221,7 +3385,7 @@
 
     lappend boldrows $row
     $canv itemconf $linehtag($row) -font $font
-    if {[info exists selectedline] && $row == $selectedline} {
+    if {$row == $selectedline} {
 	$canv delete secsel
 	set t [eval $canv create rect [$canv bbox $linehtag($row)] \
 		   -outline {{}} -tags secsel \
@@ -2235,7 +3399,7 @@
 
     lappend boldnamerows $row
     $canv2 itemconf $linentag($row) -font $font
-    if {[info exists selectedline] && $row == $selectedline} {
+    if {$row == $selectedline} {
 	$canv2 delete secsel
 	set t [eval $canv2 create rect [$canv2 bbox $linentag($row)] \
 		   -outline {{}} -tags secsel \
@@ -2249,7 +3413,7 @@
 
     set stillbold {}
     foreach row $boldrows {
-	if {![ishighlighted $row]} {
+	if {![ishighlighted [commitonrow $row]]} {
 	    bolden $row mainfont
 	} else {
 	    lappend stillbold $row
@@ -2259,17 +3423,13 @@
 }
 
 proc addvhighlight {n} {
-    global hlview curview viewdata vhl_done vhighlights commitidx
+    global hlview viewcomplete curview vhl_done commitidx
 
     if {[info exists hlview]} {
 	delvhighlight
     }
     set hlview $n
-    if {$n != $curview && ![info exists viewdata($n)]} {
-	set viewdata($n) [list getcommits {{}} 0 0 0]
-	set vparentlist($n) {}
-	set vdisporder($n) {}
-	set vcmitlisted($n) {}
+    if {$n != $curview && ![info exists viewcomplete($n)]} {
 	start_rev_list $n
     }
     set vhl_done $commitidx($hlview)
@@ -2288,43 +3448,38 @@
 }
 
 proc vhighlightmore {} {
-    global hlview vhl_done commitidx vhighlights
-    global displayorder vdisporder curview
+    global hlview vhl_done commitidx vhighlights curview
 
     set max $commitidx($hlview)
-    if {$hlview == $curview} {
-	set disp $displayorder
-    } else {
-	set disp $vdisporder($hlview)
-    }
     set vr [visiblerows]
     set r0 [lindex $vr 0]
     set r1 [lindex $vr 1]
     for {set i $vhl_done} {$i < $max} {incr i} {
-	set id [lindex $disp $i]
-	if {[info exists commitrow($curview,$id)]} {
-	    set row $commitrow($curview,$id)
+	set id [commitonrow $i $hlview]
+	if {[commitinview $id $curview]} {
+	    set row [rowofcommit $id]
 	    if {$r0 <= $row && $row <= $r1} {
 		if {![highlighted $row]} {
 		    bolden $row mainfontbold
 		}
-		set vhighlights($row) 1
+		set vhighlights($id) 1
 	    }
 	}
     }
     set vhl_done $max
+    return 0
 }
 
 proc askvhighlight {row id} {
-    global hlview vhighlights commitrow iddrawn
+    global hlview vhighlights iddrawn
 
-    if {[info exists commitrow($hlview,$id)]} {
-	if {[info exists iddrawn($id)] && ![ishighlighted $row]} {
+    if {[commitinview $id $hlview]} {
+	if {[info exists iddrawn($id)] && ![ishighlighted $id]} {
 	    bolden $row mainfontbold
 	}
-	set vhighlights($row) 1
+	set vhighlights($id) 1
     } else {
-	set vhighlights($row) 0
+	set vhighlights($id) 0
     }
 }
 
@@ -2462,12 +3617,12 @@
     global filehighlight fhighlights fhl_list
 
     lappend fhl_list $id
-    set fhighlights($row) -1
+    set fhighlights($id) -1
     puts $filehighlight $id
 }
 
 proc readfhighlight {} {
-    global filehighlight fhighlights commitrow curview iddrawn
+    global filehighlight fhighlights curview iddrawn
     global fhl_list find_dirn
 
     if {![info exists filehighlight]} {
@@ -2480,18 +3635,16 @@
 	if {$i < 0} continue
 	for {set j 0} {$j < $i} {incr j} {
 	    set id [lindex $fhl_list $j]
-	    if {[info exists commitrow($curview,$id)]} {
-		set fhighlights($commitrow($curview,$id)) 0
-	    }
+	    set fhighlights($id) 0
 	}
 	set fhl_list [lrange $fhl_list [expr {$i+1}] end]
 	if {$line eq {}} continue
-	if {![info exists commitrow($curview,$line)]} continue
-	set row $commitrow($curview,$line)
-	if {[info exists iddrawn($line)] && ![ishighlighted $row]} {
+	if {![commitinview $line $curview]} continue
+	set row [rowofcommit $line]
+	if {[info exists iddrawn($line)] && ![ishighlighted $line]} {
 	    bolden $row mainfontbold
 	}
-	set fhighlights($row) 1
+	set fhighlights($line) 1
     }
     if {[eof $filehighlight]} {
 	# strange...
@@ -2540,7 +3693,7 @@
 	}
     }
     if {$isbold && [info exists iddrawn($id)]} {
-	if {![ishighlighted $row]} {
+	if {![ishighlighted $id]} {
 	    bolden $row mainfontbold
 	    if {$isbold > 1} {
 		bolden_name $row mainfontbold
@@ -2550,7 +3703,7 @@
 	    markrowmatches $row $id
 	}
     }
-    set nhighlights($row) $isbold
+    set nhighlights($id) $isbold
 }
 
 proc markrowmatches {row id} {
@@ -2588,7 +3741,7 @@
 # prepare for testing whether commits are descendents or ancestors of a
 proc rhighlight_sel {a} {
     global descendent desc_todo ancestor anc_todo
-    global highlight_related rhighlights
+    global highlight_related
 
     catch {unset descendent}
     set desc_todo [list $a]
@@ -2608,16 +3761,16 @@
 }
 
 proc is_descendent {a} {
-    global curview children commitrow descendent desc_todo
+    global curview children descendent desc_todo
 
     set v $curview
-    set la $commitrow($v,$a)
+    set la [rowofcommit $a]
     set todo $desc_todo
     set leftover {}
     set done 0
     for {set i 0} {$i < [llength $todo]} {incr i} {
 	set do [lindex $todo $i]
-	if {$commitrow($v,$do) < $la} {
+	if {[rowofcommit $do] < $la} {
 	    lappend leftover $do
 	    continue
 	}
@@ -2640,20 +3793,20 @@
 }
 
 proc is_ancestor {a} {
-    global curview parentlist commitrow ancestor anc_todo
+    global curview parents ancestor anc_todo
 
     set v $curview
-    set la $commitrow($v,$a)
+    set la [rowofcommit $a]
     set todo $anc_todo
     set leftover {}
     set done 0
     for {set i 0} {$i < [llength $todo]} {incr i} {
 	set do [lindex $todo $i]
-	if {![info exists commitrow($v,$do)] || $commitrow($v,$do) > $la} {
+	if {![commitinview $do $v] || [rowofcommit $do] > $la} {
 	    lappend leftover $do
 	    continue
 	}
-	foreach np [lindex $parentlist $commitrow($v,$do)] {
+	foreach np $parents($v,$do) {
 	    if {![info exists ancestor($np)]} {
 		set ancestor($np) 1
 		lappend todo $np
@@ -2675,7 +3828,7 @@
     global descendent highlight_related iddrawn rhighlights
     global selectedline ancestor
 
-    if {![info exists selectedline]} return
+    if {$selectedline eq {}} return
     set isbold 0
     if {$highlight_related eq [mc "Descendant"] ||
 	$highlight_related eq [mc "Not descendant"]} {
@@ -2695,11 +3848,11 @@
 	}
     }
     if {[info exists iddrawn($id)]} {
-	if {$isbold && ![ishighlighted $row]} {
+	if {$isbold && ![ishighlighted $id]} {
 	    bolden $row mainfontbold
 	}
     }
-    set rhighlights($row) $isbold
+    set rhighlights($id) $isbold
 }
 
 # Graph layout functions
@@ -2730,40 +3883,81 @@
     return $ret
 }
 
+proc ordertoken {id} {
+    global ordertok curview varcid varcstart varctok curview parents children
+    global nullid nullid2
+
+    if {[info exists ordertok($id)]} {
+	return $ordertok($id)
+    }
+    set origid $id
+    set todo {}
+    while {1} {
+	if {[info exists varcid($curview,$id)]} {
+	    set a $varcid($curview,$id)
+	    set p [lindex $varcstart($curview) $a]
+	} else {
+	    set p [lindex $children($curview,$id) 0]
+	}
+	if {[info exists ordertok($p)]} {
+	    set tok $ordertok($p)
+	    break
+	}
+	set id [first_real_child $curview,$p]
+	if {$id eq {}} {
+	    # it's a root
+	    set tok [lindex $varctok($curview) $varcid($curview,$p)]
+	    break
+	}
+	if {[llength $parents($curview,$id)] == 1} {
+	    lappend todo [list $p {}]
+	} else {
+	    set j [lsearch -exact $parents($curview,$id) $p]
+	    if {$j < 0} {
+		puts "oops didn't find [shortids $p] in parents of [shortids $id]"
+	    }
+	    lappend todo [list $p [strrep $j]]
+	}
+    }
+    for {set i [llength $todo]} {[incr i -1] >= 0} {} {
+	set p [lindex $todo $i 0]
+	append tok [lindex $todo $i 1]
+	set ordertok($p) $tok
+    }
+    set ordertok($origid) $tok
+    return $tok
+}
+
 # Work out where id should go in idlist so that order-token
 # values increase from left to right
 proc idcol {idlist id {i 0}} {
-    global ordertok curview
-
-    set t $ordertok($curview,$id)
-    if {$i >= [llength $idlist] ||
-	$t < $ordertok($curview,[lindex $idlist $i])} {
+    set t [ordertoken $id]
+    if {$i < 0} {
+	set i 0
+    }
+    if {$i >= [llength $idlist] || $t < [ordertoken [lindex $idlist $i]]} {
 	if {$i > [llength $idlist]} {
 	    set i [llength $idlist]
 	}
-	while {[incr i -1] >= 0 &&
-	       $t < $ordertok($curview,[lindex $idlist $i])} {}
+	while {[incr i -1] >= 0 && $t < [ordertoken [lindex $idlist $i]]} {}
 	incr i
     } else {
-	if {$t > $ordertok($curview,[lindex $idlist $i])} {
+	if {$t > [ordertoken [lindex $idlist $i]]} {
 	    while {[incr i] < [llength $idlist] &&
-		   $t >= $ordertok($curview,[lindex $idlist $i])} {}
+		   $t >= [ordertoken [lindex $idlist $i]]} {}
 	}
     }
     return $i
 }
 
 proc initlayout {} {
-    global rowidlist rowisopt rowfinal displayorder commitlisted
+    global rowidlist rowisopt rowfinal displayorder parentlist
     global numcommits canvxmax canv
     global nextcolor
-    global parentlist
     global colormap rowtextx
-    global selectfirst
 
     set numcommits 0
     set displayorder {}
-    set commitlisted {}
     set parentlist {}
     set nextcolor 0
     set rowidlist {}
@@ -2772,16 +3966,19 @@
     set canvxmax [$canv cget -width]
     catch {unset colormap}
     catch {unset rowtextx}
-    set selectfirst 1
+    setcanvscroll
 }
 
 proc setcanvscroll {} {
     global canv canv2 canv3 numcommits linespc canvxmax canvy0
+    global lastscrollset lastscrollrows
 
     set ymax [expr {$canvy0 + ($numcommits - 0.5) * $linespc + 2}]
     $canv conf -scrollregion [list 0 0 $canvxmax $ymax]
     $canv2 conf -scrollregion [list 0 0 0 $ymax]
     $canv3 conf -scrollregion [list 0 0 0 $ymax]
+    set lastscrollset [clock clicks -milliseconds]
+    set lastscrollrows $numcommits
 }
 
 proc visiblerows {} {
@@ -2804,102 +4001,58 @@
 }
 
 proc layoutmore {} {
-    global commitidx viewcomplete numcommits
-    global uparrowlen downarrowlen mingaplen curview
+    global commitidx viewcomplete curview
+    global numcommits pending_select curview
+    global lastscrollset lastscrollrows commitinterest
 
-    set show $commitidx($curview)
-    if {$show > $numcommits || $viewcomplete($curview)} {
-	showstuff $show $viewcomplete($curview)
-    }
-}
-
-proc showstuff {canshow last} {
-    global numcommits commitrow pending_select selectedline curview
-    global mainheadid displayorder selectfirst
-    global lastscrollset commitinterest
-
-    if {$numcommits == 0} {
-	global phase
-	set phase "incrdraw"
-	allcanvs delete all
-    }
-    set r0 $numcommits
-    set prev $numcommits
-    set numcommits $canshow
-    set t [clock clicks -milliseconds]
-    if {$prev < 100 || $last || $t - $lastscrollset > 500} {
-	set lastscrollset $t
+    if {$lastscrollrows < 100 || $viewcomplete($curview) ||
+	[clock clicks -milliseconds] - $lastscrollset > 500} {
 	setcanvscroll
     }
-    set rows [visiblerows]
-    set r1 [lindex $rows 1]
-    if {$r1 >= $canshow} {
-	set r1 [expr {$canshow - 1}]
-    }
-    if {$r0 <= $r1} {
-	drawcommits $r0 $r1
-    }
     if {[info exists pending_select] &&
-	[info exists commitrow($curview,$pending_select)] &&
-	$commitrow($curview,$pending_select) < $numcommits} {
-	selectline $commitrow($curview,$pending_select) 1
+	[commitinview $pending_select $curview]} {
+	selectline [rowofcommit $pending_select] 1
     }
-    if {$selectfirst} {
-	if {[info exists selectedline] || [info exists pending_select]} {
-	    set selectfirst 0
-	} else {
-	    set l [first_real_row]
-	    selectline $l 1
-	    set selectfirst 0
-	}
-    }
+    drawvisible
 }
 
 proc doshowlocalchanges {} {
-    global curview mainheadid phase commitrow
+    global curview mainheadid
 
-    if {[info exists commitrow($curview,$mainheadid)] &&
-	($phase eq {} || $commitrow($curview,$mainheadid) < $numcommits - 1)} {
+    if {$mainheadid eq {}} return
+    if {[commitinview $mainheadid $curview]} {
 	dodiffindex
-    } elseif {$phase ne {}} {
-	lappend commitinterest($mainheadid) {}
+    } else {
+	lappend commitinterest($mainheadid) {dodiffindex}
     }
 }
 
 proc dohidelocalchanges {} {
-    global localfrow localirow lserial
+    global nullid nullid2 lserial curview
 
-    if {$localfrow >= 0} {
-	removerow $localfrow
-	set localfrow -1
-	if {$localirow > 0} {
-	    incr localirow -1
-	}
+    if {[commitinview $nullid $curview]} {
+	removefakerow $nullid
     }
-    if {$localirow >= 0} {
-	removerow $localirow
-	set localirow -1
+    if {[commitinview $nullid2 $curview]} {
+	removefakerow $nullid2
     }
     incr lserial
 }
 
 # spawn off a process to do git diff-index --cached HEAD
 proc dodiffindex {} {
-    global localirow localfrow lserial showlocalchanges
+    global lserial showlocalchanges
     global isworktree
 
     if {!$showlocalchanges || !$isworktree} return
     incr lserial
-    set localfrow -1
-    set localirow -1
     set fd [open "|git diff-index --cached HEAD" r]
     fconfigure $fd -blocking 0
     filerun $fd [list readdiffindex $fd $lserial]
 }
 
 proc readdiffindex {fd serial} {
-    global localirow commitrow mainheadid nullid2 curview
-    global commitinfo commitdata lserial
+    global mainheadid nullid nullid2 curview commitinfo commitdata lserial
 
     set isdiff 1
     if {[gets $fd line] < 0} {
@@ -2911,26 +4064,32 @@
     # we only need to see one line and we don't really care what it says...
     close $fd
 
-    # now see if there are any local changes not checked in to the index
-    if {$serial == $lserial} {
-	set fd [open "|git diff-files" r]
-	fconfigure $fd -blocking 0
-	filerun $fd [list readdifffiles $fd $serial]
+    if {$serial != $lserial} {
+	return 0
     }
 
-    if {$isdiff && $serial == $lserial && $localirow == -1} {
+    # now see if there are any local changes not checked in to the index
+    set fd [open "|git diff-files" r]
+    fconfigure $fd -blocking 0
+    filerun $fd [list readdifffiles $fd $serial]
+
+    if {$isdiff && ![commitinview $nullid2 $curview]} {
 	# add the line for the changes in the index to the graph
-	set localirow $commitrow($curview,$mainheadid)
 	set hl [mc "Local changes checked in to index but not committed"]
 	set commitinfo($nullid2) [list  $hl {} {} {} {} "    $hl\n"]
 	set commitdata($nullid2) "\n    $hl\n"
-	insertrow $localirow $nullid2
+	if {[commitinview $nullid $curview]} {
+	    removefakerow $nullid
+	}
+	insertfakerow $nullid2 $mainheadid
+    } elseif {!$isdiff && [commitinview $nullid2 $curview]} {
+	removefakerow $nullid2
     }
     return 0
 }
 
 proc readdifffiles {fd serial} {
-    global localirow localfrow commitrow mainheadid nullid curview
+    global mainheadid nullid nullid2 curview
     global commitinfo commitdata lserial
 
     set isdiff 1
@@ -2943,50 +4102,55 @@
     # we only need to see one line and we don't really care what it says...
     close $fd
 
-    if {$isdiff && $serial == $lserial && $localfrow == -1} {
+    if {$serial != $lserial} {
+	return 0
+    }
+
+    if {$isdiff && ![commitinview $nullid $curview]} {
 	# add the line for the local diff to the graph
-	if {$localirow >= 0} {
-	    set localfrow $localirow
-	    incr localirow
-	} else {
-	    set localfrow $commitrow($curview,$mainheadid)
-	}
 	set hl [mc "Local uncommitted changes, not checked in to index"]
 	set commitinfo($nullid) [list  $hl {} {} {} {} "    $hl\n"]
 	set commitdata($nullid) "\n    $hl\n"
-	insertrow $localfrow $nullid
+	if {[commitinview $nullid2 $curview]} {
+	    set p $nullid2
+	} else {
+	    set p $mainheadid
+	}
+	insertfakerow $nullid $p
+    } elseif {!$isdiff && [commitinview $nullid $curview]} {
+	removefakerow $nullid
     }
     return 0
 }
 
 proc nextuse {id row} {
-    global commitrow curview children
+    global curview children
 
     if {[info exists children($curview,$id)]} {
 	foreach kid $children($curview,$id) {
-	    if {![info exists commitrow($curview,$kid)]} {
+	    if {![commitinview $kid $curview]} {
 		return -1
 	    }
-	    if {$commitrow($curview,$kid) > $row} {
-		return $commitrow($curview,$kid)
+	    if {[rowofcommit $kid] > $row} {
+		return [rowofcommit $kid]
 	    }
 	}
     }
-    if {[info exists commitrow($curview,$id)]} {
-	return $commitrow($curview,$id)
+    if {[commitinview $id $curview]} {
+	return [rowofcommit $id]
     }
     return -1
 }
 
 proc prevuse {id row} {
-    global commitrow curview children
+    global curview children
 
     set ret -1
     if {[info exists children($curview,$id)]} {
 	foreach kid $children($curview,$id) {
-	    if {![info exists commitrow($curview,$kid)]} break
-	    if {$commitrow($curview,$kid) < $row} {
-		set ret $commitrow($curview,$kid)
+	    if {![commitinview $kid $curview]} break
+	    if {[rowofcommit $kid] < $row} {
+		set ret [rowofcommit $kid]
 	    }
 	}
     }
@@ -2995,7 +4159,7 @@
 
 proc make_idlist {row} {
     global displayorder parentlist uparrowlen downarrowlen mingaplen
-    global commitidx curview ordertok children commitrow
+    global commitidx curview children
 
     set r [expr {$row - $mingaplen - $downarrowlen - 1}]
     if {$r < 0} {
@@ -3009,6 +4173,7 @@
     if {$rb > $commitidx($curview)} {
 	set rb $commitidx($curview)
     }
+    make_disporder $r [expr {$rb + 1}]
     set ids {}
     for {} {$r < $ra} {incr r} {
 	set nextid [lindex $displayorder [expr {$r + 1}]]
@@ -3017,7 +4182,7 @@
 	    set rn [nextuse $p $r]
 	    if {$rn >= $row &&
 		$rn <= $r + $downarrowlen + $mingaplen + $uparrowlen} {
-		lappend ids [list $ordertok($curview,$p) $p]
+		lappend ids [list [ordertoken $p] $p]
 	    }
 	}
     }
@@ -3027,25 +4192,25 @@
 	    if {$p eq $nextid} continue
 	    set rn [nextuse $p $r]
 	    if {$rn < 0 || $rn >= $row} {
-		lappend ids [list $ordertok($curview,$p) $p]
+		lappend ids [list [ordertoken $p] $p]
 	    }
 	}
     }
     set id [lindex $displayorder $row]
-    lappend ids [list $ordertok($curview,$id) $id]
+    lappend ids [list [ordertoken $id] $id]
     while {$r < $rb} {
 	foreach p [lindex $parentlist $r] {
 	    set firstkid [lindex $children($curview,$p) 0]
-	    if {$commitrow($curview,$firstkid) < $row} {
-		lappend ids [list $ordertok($curview,$p) $p]
+	    if {[rowofcommit $firstkid] < $row} {
+		lappend ids [list [ordertoken $p] $p]
 	    }
 	}
 	incr r
 	set id [lindex $displayorder $r]
 	if {$id ne {}} {
 	    set firstkid [lindex $children($curview,$id) 0]
-	    if {$firstkid ne {} && $commitrow($curview,$firstkid) < $row} {
-		lappend ids [list $ordertok($curview,$id) $id]
+	    if {$firstkid ne {} && [rowofcommit $firstkid] < $row} {
+		lappend ids [list [ordertoken $id] $id]
 	    }
 	}
     }
@@ -3091,8 +4256,9 @@
     global rowidlist rowisopt rowfinal displayorder
     global uparrowlen downarrowlen maxwidth mingaplen
     global children parentlist
-    global commitidx viewcomplete curview commitrow
+    global commitidx viewcomplete curview
 
+    make_disporder [expr {$row - 1}] [expr {$endrow + $uparrowlen}]
     set idlist {}
     if {$row > 0} {
 	set rm1 [expr {$row - 1}]
@@ -3148,7 +4314,7 @@
 		foreach p [lindex $parentlist $r] {
 		    if {[lsearch -exact $idlist $p] >= 0} continue
 		    set fk [lindex $children($curview,$p) 0]
-		    if {$commitrow($curview,$fk) < $row} {
+		    if {[rowofcommit $fk] < $row} {
 			set x [idcol $idlist $p $x]
 			set idlist [linsert $idlist $x $p]
 		    }
@@ -3157,7 +4323,7 @@
 		    set p [lindex $displayorder $r]
 		    if {[lsearch -exact $idlist $p] < 0} {
 			set fk [lindex $children($curview,$p) 0]
-			if {$fk ne {} && $commitrow($curview,$fk) < $row} {
+			if {$fk ne {} && [rowofcommit $fk] < $row} {
 			    set x [idcol $idlist $p $x]
 			    set idlist [linsert $idlist $x $p]
 			}
@@ -3372,7 +4538,7 @@
 }
 
 proc rowranges {id} {
-    global commitrow curview children uparrowlen downarrowlen
+    global curview children uparrowlen downarrowlen
     global rowidlist
 
     set kids $children($curview,$id)
@@ -3382,13 +4548,13 @@
     set ret {}
     lappend kids $id
     foreach child $kids {
-	if {![info exists commitrow($curview,$child)]} break
-	set row $commitrow($curview,$child)
+	if {![commitinview $child $curview]} break
+	set row [rowofcommit $child]
 	if {![info exists prev]} {
 	    lappend ret [expr {$row + 1}]
 	} else {
 	    if {$row <= $prevrow} {
-		puts "oops children out of order [shortids $id] $row < [shortids $prev] $prevrow"
+		puts "oops children of [shortids $id] out of order [shortids $child] $row <= [shortids $prev] $prevrow"
 	    }
 	    # see if the line extends the whole way from prevrow to row
 	    if {$row > $prevrow + $uparrowlen + $downarrowlen &&
@@ -3421,7 +4587,7 @@
 	if {$child eq $id} {
 	    lappend ret $row
 	}
-	set prev $id
+	set prev $child
 	set prevrow $row
     }
     return $ret
@@ -3669,20 +4835,23 @@
 }
 
 proc drawcmittext {id row col} {
-    global linespc canv canv2 canv3 canvy0 fgcolor curview
-    global commitlisted commitinfo rowidlist parentlist
+    global linespc canv canv2 canv3 fgcolor curview
+    global cmitlisted commitinfo rowidlist parentlist
     global rowtextx idpos idtags idheads idotherrefs
     global linehtag linentag linedtag selectedline
-    global canvxmax boldrows boldnamerows fgcolor nullid nullid2
+    global canvxmax boldrows boldnamerows fgcolor
+    global mainheadid nullid nullid2 circleitem circlecolors
 
     # listed is 0 for boundary, 1 for normal, 2 for negative, 3 for left, 4 for right
-    set listed [lindex $commitlisted $row]
+    set listed $cmitlisted($curview,$id)
     if {$id eq $nullid} {
 	set ofill red
     } elseif {$id eq $nullid2} {
 	set ofill green
+    } elseif {$id eq $mainheadid} {
+	set ofill yellow
     } else {
-	set ofill [expr {$listed != 0 ? $listed == 2 ? "gray" : "blue" : "white"}]
+	set ofill [lindex $circlecolors $listed]
     }
     set x [xc $row $col]
     set y [yc $row]
@@ -3706,6 +4875,7 @@
 		   [expr {$x - $orad}] [expr {$y + $orad - 1}] \
 		   -fill $ofill -outline $fgcolor -width 1 -tags circle]
     }
+    set circleitem($row) $t
     $canv raise $t
     $canv bind $t <1> {selcanvline {} %x %y}
     set rmx [llength [lindex $rowidlist $row]]
@@ -3732,7 +4902,7 @@
     set date [formatdate $date]
     set font mainfont
     set nfont mainfont
-    set isbold [ishighlighted $row]
+    set isbold [ishighlighted $id]
     if {$isbold > 0} {
 	lappend boldrows $row
 	set font mainfontbold
@@ -3748,7 +4918,7 @@
 			    -text $name -font $nfont -tags text]
     set linedtag($row) [$canv3 create text 3 $y -anchor w -fill $fgcolor \
 			    -text $date -font mainfont -tags text]
-    if {[info exists selectedline] && $selectedline == $row} {
+    if {$selectedline == $row} {
 	make_secsel $row
     }
     set xr [expr {$xt + [font measure $font $headline]}]
@@ -3761,7 +4931,7 @@
 proc drawcmitrow {row} {
     global displayorder rowidlist nrows_drawn
     global iddrawn markingmatches
-    global commitinfo parentlist numcommits
+    global commitinfo numcommits
     global filehighlight fhighlights findpattern nhighlights
     global hlview vhighlights
     global highlight_related rhighlights
@@ -3769,16 +4939,16 @@
     if {$row >= $numcommits} return
 
     set id [lindex $displayorder $row]
-    if {[info exists hlview] && ![info exists vhighlights($row)]} {
+    if {[info exists hlview] && ![info exists vhighlights($id)]} {
 	askvhighlight $row $id
     }
-    if {[info exists filehighlight] && ![info exists fhighlights($row)]} {
+    if {[info exists filehighlight] && ![info exists fhighlights($id)]} {
 	askfilehighlight $row $id
     }
-    if {$findpattern ne {} && ![info exists nhighlights($row)]} {
+    if {$findpattern ne {} && ![info exists nhighlights($id)]} {
 	askfindhighlight $row $id
     }
-    if {$highlight_related ne [mc "None"] && ![info exists rhighlights($row)]} {
+    if {$highlight_related ne [mc "None"] && ![info exists rhighlights($id)]} {
 	askrelhighlight $row $id
     }
     if {![info exists iddrawn($id)]} {
@@ -3881,30 +5051,92 @@
     }
 }
 
-proc drawfrac {f0 f1} {
-    global canv linespc
+proc undolayout {row} {
+    global uparrowlen mingaplen downarrowlen
+    global rowidlist rowisopt rowfinal need_redisplay
 
-    set ymax [lindex [$canv cget -scrollregion] 3]
-    if {$ymax eq {} || $ymax == 0} return
-    set y0 [expr {int($f0 * $ymax)}]
-    set row [expr {int(($y0 - 3) / $linespc) - 1}]
-    set y1 [expr {int($f1 * $ymax)}]
-    set endrow [expr {int(($y1 - 3) / $linespc) + 1}]
-    drawcommits $row $endrow
+    set r [expr {$row - ($uparrowlen + $mingaplen + $downarrowlen)}]
+    if {$r < 0} {
+	set r 0
+    }
+    if {[llength $rowidlist] > $r} {
+	incr r -1
+	set rowidlist [lrange $rowidlist 0 $r]
+	set rowfinal [lrange $rowfinal 0 $r]
+	set rowisopt [lrange $rowisopt 0 $r]
+	set need_redisplay 1
+	run drawvisible
+    }
 }
 
 proc drawvisible {} {
-    global canv
-    eval drawfrac [$canv yview]
+    global canv linespc curview vrowmod selectedline targetrow targetid
+    global need_redisplay cscroll numcommits
+
+    set fs [$canv yview]
+    set ymax [lindex [$canv cget -scrollregion] 3]
+    if {$ymax eq {} || $ymax == 0 || $numcommits == 0} return
+    set f0 [lindex $fs 0]
+    set f1 [lindex $fs 1]
+    set y0 [expr {int($f0 * $ymax)}]
+    set y1 [expr {int($f1 * $ymax)}]
+
+    if {[info exists targetid]} {
+	if {[commitinview $targetid $curview]} {
+	    set r [rowofcommit $targetid]
+	    if {$r != $targetrow} {
+		# Fix up the scrollregion and change the scrolling position
+		# now that our target row has moved.
+		set diff [expr {($r - $targetrow) * $linespc}]
+		set targetrow $r
+		setcanvscroll
+		set ymax [lindex [$canv cget -scrollregion] 3]
+		incr y0 $diff
+		incr y1 $diff
+		set f0 [expr {$y0 / $ymax}]
+		set f1 [expr {$y1 / $ymax}]
+		allcanvs yview moveto $f0
+		$cscroll set $f0 $f1
+		set need_redisplay 1
+	    }
+	} else {
+	    unset targetid
+	}
+    }
+
+    set row [expr {int(($y0 - 3) / $linespc) - 1}]
+    set endrow [expr {int(($y1 - 3) / $linespc) + 1}]
+    if {$endrow >= $vrowmod($curview)} {
+	update_arcrows $curview
+    }
+    if {$selectedline ne {} &&
+	$row <= $selectedline && $selectedline <= $endrow} {
+	set targetrow $selectedline
+    } elseif {[info exists targetid]} {
+	set targetrow [expr {int(($row + $endrow) / 2)}]
+    }
+    if {[info exists targetrow]} {
+	if {$targetrow >= $numcommits} {
+	    set targetrow [expr {$numcommits - 1}]
+	}
+	set targetid [commitonrow $targetrow]
+    }
+    drawcommits $row $endrow
 }
 
 proc clear_display {} {
     global iddrawn linesegs need_redisplay nrows_drawn
     global vhighlights fhighlights nhighlights rhighlights
+    global linehtag linentag linedtag boldrows boldnamerows
 
     allcanvs delete all
     catch {unset iddrawn}
     catch {unset linesegs}
+    catch {unset linehtag}
+    catch {unset linentag}
+    catch {unset linedtag}
+    set boldrows {}
+    set boldnamerows {}
     catch {unset vhighlights}
     catch {unset fhighlights}
     catch {unset nhighlights}
@@ -3950,7 +5182,7 @@
 
 proc assigncolor {id} {
     global colormap colors nextcolor
-    global commitrow parentlist children children curview
+    global parents children children curview
 
     if {[info exists colormap($id)]} return
     set ncolors [llength $colors]
@@ -3962,7 +5194,7 @@
     if {[llength $kids] == 1} {
 	set child [lindex $kids 0]
 	if {[info exists colormap($child)]
-	    && [llength [lindex $parentlist $commitrow($curview,$child)]] == 1} {
+	    && [llength $parents($curview,$child)] == 1} {
 	    set colormap($id) $colormap($child)
 	    return
 	}
@@ -3990,7 +5222,7 @@
 		&& [lsearch -exact $badcolors $colormap($child)] < 0} {
 		lappend badcolors $colormap($child)
 	    }
-	    foreach p [lindex $parentlist $commitrow($curview,$child)] {
+	    foreach p $parents($curview,$child) {
 		if {[info exists colormap($p)]
 		    && [lsearch -exact $badcolors $colormap($p)] < 0} {
 		    lappend badcolors $colormap($p)
@@ -4023,7 +5255,7 @@
 proc drawtags {id x xt y1} {
     global idtags idheads idotherrefs mainhead
     global linespc lthickness
-    global canv commitrow rowtextx curview fgcolor bgcolor
+    global canv rowtextx curview fgcolor bgcolor
 
     set marks {}
     set ntags 0
@@ -4073,7 +5305,7 @@
 		       $xr $yt $xr $yb $xl $yb $x [expr {$yb - $delta}] \
 		       -width 1 -outline black -fill yellow -tags tag.$id]
 	    $canv bind $t <1> [list showtag $tag 1]
-	    set rowtextx($commitrow($curview,$id)) [expr {$xr + $linespc}]
+	    set rowtextx([rowofcommit $id]) [expr {$xr + $linespc}]
 	} else {
 	    # draw a head or other ref
 	    if {[incr nheads -1] >= 0} {
@@ -4127,103 +5359,6 @@
 	-tags text -fill $fgcolor
 }
 
-# Insert a new commit as the child of the commit on row $row.
-# The new commit will be displayed on row $row and the commits
-# on that row and below will move down one row.
-proc insertrow {row newcmit} {
-    global displayorder parentlist commitlisted children
-    global commitrow curview rowidlist rowisopt rowfinal numcommits
-    global numcommits
-    global selectedline commitidx ordertok
-
-    if {$row >= $numcommits} {
-	puts "oops, inserting new row $row but only have $numcommits rows"
-	return
-    }
-    set p [lindex $displayorder $row]
-    set displayorder [linsert $displayorder $row $newcmit]
-    set parentlist [linsert $parentlist $row $p]
-    set kids $children($curview,$p)
-    lappend kids $newcmit
-    set children($curview,$p) $kids
-    set children($curview,$newcmit) {}
-    set commitlisted [linsert $commitlisted $row 1]
-    set l [llength $displayorder]
-    for {set r $row} {$r < $l} {incr r} {
-	set id [lindex $displayorder $r]
-	set commitrow($curview,$id) $r
-    }
-    incr commitidx($curview)
-    set ordertok($curview,$newcmit) $ordertok($curview,$p)
-
-    if {$row < [llength $rowidlist]} {
-	set idlist [lindex $rowidlist $row]
-	if {$idlist ne {}} {
-	    if {[llength $kids] == 1} {
-		set col [lsearch -exact $idlist $p]
-		lset idlist $col $newcmit
-	    } else {
-		set col [llength $idlist]
-		lappend idlist $newcmit
-	    }
-	}
-	set rowidlist [linsert $rowidlist $row $idlist]
-	set rowisopt [linsert $rowisopt $row 0]
-	set rowfinal [linsert $rowfinal $row [lindex $rowfinal $row]]
-    }
-
-    incr numcommits
-
-    if {[info exists selectedline] && $selectedline >= $row} {
-	incr selectedline
-    }
-    redisplay
-}
-
-# Remove a commit that was inserted with insertrow on row $row.
-proc removerow {row} {
-    global displayorder parentlist commitlisted children
-    global commitrow curview rowidlist rowisopt rowfinal numcommits
-    global numcommits
-    global linesegends selectedline commitidx
-
-    if {$row >= $numcommits} {
-	puts "oops, removing row $row but only have $numcommits rows"
-	return
-    }
-    set rp1 [expr {$row + 1}]
-    set id [lindex $displayorder $row]
-    set p [lindex $parentlist $row]
-    set displayorder [lreplace $displayorder $row $row]
-    set parentlist [lreplace $parentlist $row $row]
-    set commitlisted [lreplace $commitlisted $row $row]
-    set kids $children($curview,$p)
-    set i [lsearch -exact $kids $id]
-    if {$i >= 0} {
-	set kids [lreplace $kids $i $i]
-	set children($curview,$p) $kids
-    }
-    set l [llength $displayorder]
-    for {set r $row} {$r < $l} {incr r} {
-	set id [lindex $displayorder $r]
-	set commitrow($curview,$id) $r
-    }
-    incr commitidx($curview) -1
-
-    if {$row < [llength $rowidlist]} {
-	set rowidlist [lreplace $rowidlist $row $row]
-	set rowisopt [lreplace $rowisopt $row $row]
-	set rowfinal [lreplace $rowfinal $row $row]
-    }
-
-    incr numcommits -1
-
-    if {[info exists selectedline] && $selectedline > $row} {
-	incr selectedline -1
-    }
-    redisplay
-}
-
 # Don't change the text pane cursor if it is currently the hand cursor,
 # showing that we are over a sha1 ID link.
 proc settextcursor {c} {
@@ -4296,7 +5431,7 @@
     }
     focus .
     if {$findstring eq {} || $numcommits == 0} return
-    if {![info exists selectedline]} {
+    if {$selectedline eq {}} {
 	set findstartline [lindex [visiblerows] [expr {$dirn < 0}]]
     } else {
 	set findstartline $selectedline
@@ -4326,9 +5461,9 @@
 
 proc findmore {} {
     global commitdata commitinfo numcommits findpattern findloc
-    global findstartline findcurline displayorder
+    global findstartline findcurline findallowwrap
     global find_dirn gdttype fhighlights fprogcoord
-    global findallowwrap
+    global curview varcorder vrownum varccommits vrowmod
 
     if {![info exists find_dirn]} {
 	return 0
@@ -4364,14 +5499,31 @@
 	set n 500
 	set moretodo 1
     }
+    if {$l + ($find_dirn > 0? $n: 1) > $vrowmod($curview)} {
+	update_arcrows $curview
+    }
     set found 0
     set domore 1
+    set ai [bsearch $vrownum($curview) $l]
+    set a [lindex $varcorder($curview) $ai]
+    set arow [lindex $vrownum($curview) $ai]
+    set ids [lindex $varccommits($curview,$a)]
+    set arowend [expr {$arow + [llength $ids]}]
     if {$gdttype eq [mc "containing:"]} {
 	for {} {$n > 0} {incr n -1; incr l $find_dirn} {
-	    set id [lindex $displayorder $l]
+	    if {$l < $arow || $l >= $arowend} {
+		incr ai $find_dirn
+		set a [lindex $varcorder($curview) $ai]
+		set arow [lindex $vrownum($curview) $ai]
+		set ids [lindex $varccommits($curview,$a)]
+		set arowend [expr {$arow + [llength $ids]}]
+	    }
+	    set id [lindex $ids [expr {$l - $arow}]]
 	    # shouldn't happen unless git log doesn't give all the commits...
-	    if {![info exists commitdata($id)]} continue
-	    if {![doesmatch $commitdata($id)]} continue
+	    if {![info exists commitdata($id)] ||
+		![doesmatch $commitdata($id)]} {
+		continue
+	    }
 	    if {![info exists commitinfo($id)]} {
 		getcommit $id
 	    }
@@ -4387,16 +5539,27 @@
 	}
     } else {
 	for {} {$n > 0} {incr n -1; incr l $find_dirn} {
-	    set id [lindex $displayorder $l]
-	    if {![info exists fhighlights($l)]} {
+	    if {$l < $arow || $l >= $arowend} {
+		incr ai $find_dirn
+		set a [lindex $varcorder($curview) $ai]
+		set arow [lindex $vrownum($curview) $ai]
+		set ids [lindex $varccommits($curview,$a)]
+		set arowend [expr {$arow + [llength $ids]}]
+	    }
+	    set id [lindex $ids [expr {$l - $arow}]]
+	    if {![info exists fhighlights($id)]} {
+		# this sets fhighlights($id) to -1
 		askfilehighlight $l $id
+	    }
+	    if {$fhighlights($id) > 0} {
+		set found $domore
+		break
+	    }
+	    if {$fhighlights($id) < 0} {
 		if {$domore} {
 		    set domore 0
 		    set findcurline [expr {$l - $find_dirn}]
 		}
-	    } elseif {$fhighlights($l)} {
-		set found $domore
-		break
 	    }
 	}
     }
@@ -4464,7 +5627,7 @@
 		   [expr {$x0+$xlen+2}] $y1 \
 		   -outline {} -tags [list match$l matches] -fill yellow]
 	$canv lower $t
-	if {[info exists selectedline] && $row == $selectedline} {
+	if {$row == $selectedline} {
 	    $canv raise $t secsel
 	}
     }
@@ -4490,7 +5653,9 @@
 	set l 0
     }
     if {$w eq $canv} {
-	if {![info exists rowtextx($l)] || $x < $rowtextx($l)} return
+	set xmax [lindex [$canv cget -scrollregion] 2]
+	set xleft [expr {[lindex [$canv xview] 0] * $xmax}]
+	if {![info exists rowtextx($l)] || $xleft + $x < $rowtextx($l)} return
     }
     unmarkmatches
     selectline $l 1
@@ -4511,7 +5676,7 @@
 # append some text to the ctext widget, and make any SHA1 ID
 # that we know about be a clickable link.
 proc appendwithlinks {text tags} {
-    global ctext commitrow linknum curview pendinglinks
+    global ctext linknum curview pendinglinks
 
     set start [$ctext index "end - 1c"]
     $ctext insert end $text $tags
@@ -4529,11 +5694,11 @@
 }
 
 proc setlink {id lk} {
-    global curview commitrow ctext pendinglinks commitinterest
+    global curview ctext pendinglinks commitinterest
 
-    if {[info exists commitrow($curview,$id)]} {
+    if {[commitinview $id $curview]} {
 	$ctext tag conf $lk -foreground blue -underline 1
-	$ctext tag bind $lk <1> [list selectline $commitrow($curview,$id) 1]
+	$ctext tag bind $lk <1> [list selectline [rowofcommit $id] 1]
 	$ctext tag bind $lk <Enter> {linkcursor %W 1}
 	$ctext tag bind $lk <Leave> {linkcursor %W -1}
     } else {
@@ -4584,7 +5749,7 @@
 # add a list of tag or branch names at position pos
 # returns the number of names inserted
 proc appendrefs {pos ids var} {
-    global ctext commitrow linknum curview $var maxrefs
+    global ctext linknum curview $var maxrefs
 
     if {[catch {$ctext index $pos}]} {
 	return 0
@@ -4621,7 +5786,7 @@
 proc dispneartags {delay} {
     global selectedline currentid showneartags tagphase
 
-    if {![info exists selectedline] || !$showneartags} return
+    if {$selectedline eq {} || !$showneartags} return
     after cancel dispnexttag
     if {$delay} {
 	after 200 dispnexttag
@@ -4635,7 +5800,7 @@
 proc dispnexttag {} {
     global selectedline currentid showneartags tagphase ctext
 
-    if {![info exists selectedline] || !$showneartags} return
+    if {$selectedline eq {} || !$showneartags} return
     switch -- $tagphase {
 	0 {
 	    set dtags [desctags $currentid]
@@ -4687,12 +5852,12 @@
 
 proc selectline {l isnew} {
     global canv ctext commitinfo selectedline
-    global displayorder
-    global canvy0 linespc parentlist children curview
+    global canvy0 linespc parents children curview
     global currentid sha1entry
     global commentend idtags linknum
     global mergemax numcommits pending_select
     global cmitmode showneartags allcommits
+    global targetrow targetid lastscrollrows
     global autoselect
 
     catch {unset pending_select}
@@ -4701,6 +5866,15 @@
     unsel_reflist
     stopfinding
     if {$l < 0 || $l >= $numcommits} return
+    set id [commitonrow $l]
+    set targetid $id
+    set targetrow $l
+    set selectedline $l
+    set currentid $id
+    if {$lastscrollrows < $numcommits} {
+	setcanvscroll
+    }
+
     set y [expr {$canvy0 + $l * $linespc}]
     set ymax [lindex [$canv cget -scrollregion] 3]
     set ytop [expr {$y - $linespc - 1}]
@@ -4740,13 +5914,9 @@
     make_secsel $l
 
     if {$isnew} {
-	addtohistory [list selectline $l 0]
+	addtohistory [list selbyid $id]
     }
 
-    set selectedline $l
-
-    set id [lindex $displayorder $l]
-    set currentid $id
     $sha1entry delete 0 end
     $sha1entry insert 0 $id
     if {$autoselect} {
@@ -4758,6 +5928,9 @@
     $ctext conf -state normal
     clear_ctext
     set linknum 0
+    if {![info exists commitinfo($id)]} {
+	getcommit $id
+    }
     set info $commitinfo($id)
     set date [formatdate [lindex $info 2]]
     $ctext insert end "[mc "Author"]: [lindex $info 1]  $date\n"
@@ -4772,7 +5945,7 @@
     }
 
     set headers {}
-    set olds [lindex $parentlist $l]
+    set olds $parents($curview,$id)
     if {[llength $olds] > 1} {
 	set np 0
 	foreach p $olds {
@@ -4830,7 +6003,7 @@
     } elseif {[llength $olds] <= 1} {
 	startdiff $id
     } else {
-	mergediff $id $l
+	mergediff $id
     }
 }
 
@@ -4849,7 +6022,7 @@
 proc selnextline {dir} {
     global selectedline
     focus .
-    if {![info exists selectedline]} return
+    if {$selectedline eq {}} return
     set l [expr {$selectedline + $dir}]
     unmarkmatches
     selectline $l 1
@@ -4864,7 +6037,7 @@
     }
     allcanvs yview scroll [expr {$dir * $lpp}] units
     drawvisible
-    if {![info exists selectedline]} return
+    if {$selectedline eq {}} return
     set l [expr {$selectedline + $dir * $lpp}]
     if {$l < 0} {
 	set l 0
@@ -4878,7 +6051,7 @@
 proc unselectline {} {
     global selectedline currentid
 
-    catch {unset selectedline}
+    set selectedline {}
     catch {unset currentid}
     allcanvs delete secsel
     rhighlight_none
@@ -4887,7 +6060,7 @@
 proc reselectline {} {
     global selectedline
 
-    if {[info exists selectedline]} {
+    if {$selectedline ne {}} {
 	selectline $selectedline 0
     }
 }
@@ -4992,11 +6165,12 @@
 	if {$diffids eq $nullid} {
 	    set fname $line
 	} else {
-	    if {$diffids ne $nullid2 && [lindex $line 1] ne "blob"} continue
 	    set i [string first "\t" $line]
 	    if {$i < 0} continue
-	    set sha1 [lindex $line 2]
 	    set fname [string range $line [expr {$i+1}] end]
+	    set line [string range $line 0 [expr {$i-1}]]
+	    if {$diffids ne $nullid2 && [lindex $line 1] ne "blob"} continue
+	    set sha1 [lindex $line 2]
 	    if {[string index $fname 0] eq "\""} {
 		set fname [lindex $fname 0]
 	    }
@@ -5075,19 +6249,19 @@
     return [expr {$nl >= 1000? 2: 1}]
 }
 
-proc mergediff {id l} {
+proc mergediff {id} {
     global diffmergeid mdifffd
     global diffids
+    global parents
     global diffcontext
-    global parentlist
-    global limitdiffs viewfiles curview
+    global limitdiffs vfilelimit curview
 
     set diffmergeid $id
     set diffids $id
     # this doesn't seem to actually affect anything...
     set cmd [concat | git diff-tree --no-commit-id --cc -U$diffcontext $id]
-    if {$limitdiffs && $viewfiles($curview) ne {}} {
-	set cmd [concat $cmd -- $viewfiles($curview)]
+    if {$limitdiffs && $vfilelimit($curview) ne {}} {
+	set cmd [concat $cmd -- $vfilelimit($curview)]
     }
     if {[catch {set mdf [open $cmd r]} err]} {
 	error_popup "[mc "Error getting merge diffs:"] $err"
@@ -5095,7 +6269,7 @@
     }
     fconfigure $mdf -blocking 0
     set mdifffd($id) $mdf
-    set np [llength [lindex $parentlist $l]]
+    set np [llength $parents($curview,$id)]
     settabs $np
     filerun $mdf [list getmergediffline $mdf $id $np]
 }
@@ -5265,7 +6439,7 @@
 
 proc gettreediffline {gdtf ids} {
     global treediff treediffs treepending diffids diffmergeid
-    global cmitmode viewfiles curview limitdiffs
+    global cmitmode vfilelimit curview limitdiffs
 
     set nr 0
     while {[incr nr] <= 1000 && [gets $gdtf line] >= 0} {
@@ -5282,10 +6456,10 @@
 	return [expr {$nr >= 1000? 2: 1}]
     }
     close $gdtf
-    if {$limitdiffs && $viewfiles($curview) ne {}} {
+    if {$limitdiffs && $vfilelimit($curview) ne {}} {
 	set flist {}
 	foreach f $treediff {
-	    if {[path_filter $viewfiles($curview) $f]} {
+	    if {[path_filter $vfilelimit($curview) $f]} {
 		lappend flist $f
 	    }
 	}
@@ -5331,14 +6505,14 @@
     global diffinhdr treediffs
     global diffcontext
     global ignorespace
-    global limitdiffs viewfiles curview
+    global limitdiffs vfilelimit curview
 
     set cmd [diffcmd $ids "-p -C --no-commit-id -U$diffcontext"]
     if {$ignorespace} {
 	append cmd " -w"
     }
-    if {$limitdiffs && $viewfiles($curview) ne {}} {
-	set cmd [concat $cmd -- $viewfiles($curview)]
+    if {$limitdiffs && $vfilelimit($curview) ne {}} {
+	set cmd [concat $cmd -- $vfilelimit($curview)]
     }
     if {[catch {set bdf [open $cmd r]} err]} {
 	puts "error getting diffs: $err"
@@ -5478,26 +6652,44 @@
     $ctext tag conf d1 -elide [lindex $diffelide 1]
 }
 
+proc highlightfile {loc cline} {
+    global ctext cflist cflist_top
+
+    $ctext yview $loc
+    $cflist tag remove highlight $cflist_top.0 "$cflist_top.0 lineend"
+    $cflist tag add highlight $cline.0 "$cline.0 lineend"
+    $cflist see $cline.0
+    set cflist_top $cline
+}
+
 proc prevfile {} {
-    global difffilestart ctext
-    set prev [lindex $difffilestart 0]
+    global difffilestart ctext cmitmode
+
+    if {$cmitmode eq "tree"} return
+    set prev 0.0
+    set prevline 1
     set here [$ctext index @0,0]
     foreach loc $difffilestart {
 	if {[$ctext compare $loc >= $here]} {
-	    $ctext yview $prev
+	    highlightfile $prev $prevline
 	    return
 	}
 	set prev $loc
+	incr prevline
     }
-    $ctext yview $prev
+    highlightfile $prev $prevline
 }
 
 proc nextfile {} {
-    global difffilestart ctext
+    global difffilestart ctext cmitmode
+
+    if {$cmitmode eq "tree"} return
     set here [$ctext index @0,0]
+    set line 1
     foreach loc $difffilestart {
+	incr line
 	if {[$ctext compare $loc > $here]} {
-	    $ctext yview $loc
+	    highlightfile $loc $line
 	    return
 	}
     }
@@ -5680,7 +6872,7 @@
     setcanvscroll
     allcanvs yview moveto [lindex $span 0]
     drawvisible
-    if {[info exists selectedline]} {
+    if {$selectedline ne {}} {
 	selectline $selectedline 0
 	allcanvs yview moveto [lindex $span 0]
     }
@@ -5731,7 +6923,7 @@
 }
 
 proc incrfont {inc} {
-    global mainfont textfont ctext canv phase cflist showrefstop
+    global mainfont textfont ctext canv cflist showrefstop
     global stopped entries fontattr
 
     unmarkmatches
@@ -5782,8 +6974,7 @@
 }
 
 proc gotocommit {} {
-    global sha1string currentid commitrow tagids headids
-    global displayorder numcommits curview
+    global sha1string tagids headids curview varcid
 
     if {$sha1string == {}
 	|| ([info exists currentid] && $sha1string == $currentid)} return
@@ -5794,23 +6985,18 @@
     } else {
 	set id [string tolower $sha1string]
 	if {[regexp {^[0-9a-f]{4,39}$} $id]} {
-	    set matches {}
-	    foreach i $displayorder {
-		if {[string match $id* $i]} {
-		    lappend matches $i
-		}
-	    }
+	    set matches [array names varcid "$curview,$id*"]
 	    if {$matches ne {}} {
 		if {[llength $matches] > 1} {
 		    error_popup [mc "Short SHA1 id %s is ambiguous" $id]
 		    return
 		}
-		set id [lindex $matches 0]
+		set id [lindex [split [lindex $matches 0] ","] 1]
 	    }
 	}
     }
-    if {[info exists commitrow($curview,$id)]} {
-	selectline $commitrow($curview,$id) 1
+    if {[commitinview $id $curview]} {
+	selectline [rowofcommit $id] 1
 	return
     }
     if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
@@ -5919,7 +7105,7 @@
 }
 
 proc lineclick {x y id isnew} {
-    global ctext commitinfo children canv thickerline curview commitrow
+    global ctext commitinfo children canv thickerline curview
 
     if {![info exists commitinfo($id)] && ![getcommit $id]} return
     unmarkmatches
@@ -5987,9 +7173,9 @@
 }
 
 proc selbyid {id} {
-    global commitrow curview
-    if {[info exists commitrow($curview,$id)]} {
-	selectline $commitrow($curview,$id) 1
+    global curview
+    if {[commitinview $id $curview]} {
+	selectline [rowofcommit $id] 1
     }
 }
 
@@ -6002,20 +7188,23 @@
 }
 
 proc rowmenu {x y id} {
-    global rowctxmenu commitrow selectedline rowmenuid curview
+    global rowctxmenu selectedline rowmenuid curview
     global nullid nullid2 fakerowmenu mainhead
 
     stopfinding
     set rowmenuid $id
-    if {![info exists selectedline]
-	|| $commitrow($curview,$id) eq $selectedline} {
+    if {$selectedline eq {} || [rowofcommit $id] eq $selectedline} {
 	set state disabled
     } else {
 	set state normal
     }
     if {$id ne $nullid && $id ne $nullid2} {
 	set menu $rowctxmenu
-	$menu entryconfigure 7 -label [mc "Reset %s branch to here" $mainhead]
+	if {$mainhead ne {}} {
+	    $menu entryconfigure 7 -label [mc "Reset %s branch to here" $mainhead]
+	} else {
+	    $menu entryconfigure 7 -label [mc "Detached head: can't reset" $mainhead] -state disabled
+	}
     } else {
 	set menu $fakerowmenu
     }
@@ -6026,15 +7215,15 @@
 }
 
 proc diffvssel {dirn} {
-    global rowmenuid selectedline displayorder
+    global rowmenuid selectedline
 
-    if {![info exists selectedline]} return
+    if {$selectedline eq {}} return
     if {$dirn} {
-	set oldid [lindex $displayorder $selectedline]
+	set oldid [commitonrow $selectedline]
 	set newid $rowmenuid
     } else {
 	set oldid $rowmenuid
-	set newid [lindex $displayorder $selectedline]
+	set newid [commitonrow $selectedline]
     }
     addtohistory [list doseldiff $oldid $newid]
     doseldiff $oldid $newid
@@ -6212,24 +7401,30 @@
 }
 
 proc redrawtags {id} {
-    global canv linehtag commitrow idpos selectedline curview
-    global canvxmax iddrawn
+    global canv linehtag idpos currentid curview cmitlisted
+    global canvxmax iddrawn circleitem mainheadid circlecolors
 
-    if {![info exists commitrow($curview,$id)]} return
+    if {![commitinview $id $curview]} return
     if {![info exists iddrawn($id)]} return
-    drawcommits $commitrow($curview,$id)
+    set row [rowofcommit $id]
+    if {$id eq $mainheadid} {
+	set ofill yellow
+    } else {
+	set ofill [lindex $circlecolors $cmitlisted($curview,$id)]
+    }
+    $canv itemconf $circleitem($row) -fill $ofill
     $canv delete tag.$id
     set xt [eval drawtags $id $idpos($id)]
-    $canv coords $linehtag($commitrow($curview,$id)) $xt [lindex $idpos($id) 2]
-    set text [$canv itemcget $linehtag($commitrow($curview,$id)) -text]
-    set xr [expr {$xt + [font measure mainfont $text]}]
+    $canv coords $linehtag($row) $xt [lindex $idpos($id) 2]
+    set text [$canv itemcget $linehtag($row) -text]
+    set font [$canv itemcget $linehtag($row) -font]
+    set xr [expr {$xt + [font measure $font $text]}]
     if {$xr > $canvxmax} {
 	set canvxmax $xr
 	setcanvscroll
     }
-    if {[info exists selectedline]
-	&& $selectedline == $commitrow($curview,$id)} {
-	selectline $selectedline 0
+    if {[info exists currentid] && $currentid == $id} {
+	make_secsel $row
     }
 }
 
@@ -6355,8 +7550,8 @@
 }
 
 proc cherrypick {} {
-    global rowmenuid curview commitrow
-    global mainhead
+    global rowmenuid curview
+    global mainhead mainheadid
 
     set oldhead [exec git rev-parse HEAD]
     set dheads [descheads $rowmenuid]
@@ -6382,20 +7577,22 @@
 	return
     }
     addnewchild $newhead $oldhead
-    if {[info exists commitrow($curview,$oldhead)]} {
-	insertrow $commitrow($curview,$oldhead) $newhead
+    if {[commitinview $oldhead $curview]} {
+	insertrow $newhead $oldhead $curview
 	if {$mainhead ne {}} {
 	    movehead $newhead $mainhead
 	    movedhead $newhead $mainhead
 	}
+	set mainheadid $newhead
 	redrawtags $oldhead
 	redrawtags $newhead
+	selbyid $newhead
     }
     notbusy cherrypick
 }
 
 proc resethead {} {
-    global mainheadid mainhead rowmenuid confirm_ok resettype
+    global mainhead rowmenuid confirm_ok resettype
 
     set confirm_ok 0
     set w ".confirmreset"
@@ -6428,12 +7625,13 @@
     tkwait window $w
     if {!$confirm_ok} return
     if {[catch {set fd [open \
-	    [list | sh -c "git reset --$resettype $rowmenuid 2>&1"] r]} err]} {
+	    [list | git reset --$resettype $rowmenuid 2>@1] r]} err]} {
 	error_popup $err
     } else {
 	dohidelocalchanges
 	filerun $fd [list readresetstat $fd]
 	nowbusy reset [mc "Resetting"]
+	selbyid $rowmenuid
     }
 }
 
@@ -6485,28 +7683,48 @@
 }
 
 proc cobranch {} {
-    global headmenuid headmenuhead mainhead headids
+    global headmenuid headmenuhead headids
     global showlocalchanges mainheadid
 
     # check the tree is clean first??
-    set oldmainhead $mainhead
     nowbusy checkout [mc "Checking out"]
     update
     dohidelocalchanges
     if {[catch {
-	exec git checkout -q $headmenuhead
+	set fd [open [list | git checkout $headmenuhead 2>@1] r]
     } err]} {
 	notbusy checkout
 	error_popup $err
-    } else {
-	notbusy checkout
-	set mainhead $headmenuhead
-	set mainheadid $headmenuid
-	if {[info exists headids($oldmainhead)]} {
-	    redrawtags $headids($oldmainhead)
+	if {$showlocalchanges} {
+	    dodiffindex
 	}
-	redrawtags $headmenuid
+    } else {
+	filerun $fd [list readcheckoutstat $fd $headmenuhead $headmenuid]
     }
+}
+
+proc readcheckoutstat {fd newhead newheadid} {
+    global mainhead mainheadid headids showlocalchanges progresscoords
+
+    if {[gets $fd line] >= 0} {
+	if {[regexp {([0-9]+)% \(([0-9]+)/([0-9]+)\)} $line match p m n]} {
+	    set progresscoords [list 0 [expr {1.0 * $m / $n}]]
+	    adjustprogress
+	}
+	return 1
+    }
+    set progresscoords {0 0}
+    adjustprogress
+    notbusy checkout
+    if {[catch {close $fd} err]} {
+	error_popup $err
+    }
+    set oldmainid $mainheadid
+    set mainhead $newhead
+    set mainheadid $newheadid
+    redrawtags $oldmainid
+    redrawtags $newheadid
+    selbyid $newheadid
     if {$showlocalchanges} {
 	dodiffindex
     }
@@ -6620,13 +7838,13 @@
 
 proc refill_reflist {} {
     global reflist reflistfilter showrefstop headids tagids otherrefids
-    global commitrow curview commitinterest
+    global curview commitinterest
 
     if {![info exists showrefstop] || ![winfo exists $showrefstop]} return
     set refs {}
     foreach n [array names headids] {
 	if {[string match $reflistfilter $n]} {
-	    if {[info exists commitrow($curview,$headids($n))]} {
+	    if {[commitinview $headids($n) $curview]} {
 		lappend refs [list $n H]
 	    } else {
 		set commitinterest($headids($n)) {run refill_reflist}
@@ -6635,7 +7853,7 @@
     }
     foreach n [array names tagids] {
 	if {[string match $reflistfilter $n]} {
-	    if {[info exists commitrow($curview,$tagids($n))]} {
+	    if {[commitinview $tagids($n) $curview]} {
 		lappend refs [list $n T]
 	    } else {
 		set commitinterest($tagids($n)) {run refill_reflist}
@@ -6644,7 +7862,7 @@
     }
     foreach n [array names otherrefids] {
 	if {[string match $reflistfilter $n]} {
-	    if {[info exists commitrow($curview,$otherrefids($n))]} {
+	    if {[commitinview $otherrefids($n) $curview]} {
 		lappend refs [list $n o]
 	    } else {
 		set commitinterest($otherrefids($n)) {run refill_reflist}
@@ -7788,7 +9006,7 @@
 }
 
 proc rereadrefs {} {
-    global idtags idheads idotherrefs mainhead
+    global idtags idheads idotherrefs mainheadid
 
     set refids [concat [array names idtags] \
 		    [array names idheads] [array names idotherrefs]]
@@ -7797,19 +9015,21 @@
 	    set ref($id) [listrefs $id]
 	}
     }
-    set oldmainhead $mainhead
+    set oldmainhead $mainheadid
     readrefs
     changedrefs
     set refids [lsort -unique [concat $refids [array names idtags] \
 			[array names idheads] [array names idotherrefs]]]
     foreach id $refids {
 	set v [listrefs $id]
-	if {![info exists ref($id)] || $ref($id) != $v ||
-	    ($id eq $oldmainhead && $id ne $mainhead) ||
-	    ($id eq $mainhead && $id ne $oldmainhead)} {
+	if {![info exists ref($id)] || $ref($id) != $v} {
 	    redrawtags $id
 	}
     }
+    if {$oldmainhead ne $mainheadid} {
+	redrawtags $oldmainhead
+	redrawtags $mainheadid
+    }
     run refill_reflist
 }
 
@@ -7858,9 +9078,15 @@
 
 proc doquit {} {
     global stopped
+    global gitktmpdir
+
     set stopped 100
     savestuff .
     destroy .
+
+    if {[info exists gitktmpdir]} {
+	catch {file delete -force $gitktmpdir}
+    }
 }
 
 proc mkfontdisp {font top which} {
@@ -7989,7 +9215,7 @@
     global maxwidth maxgraphpct
     global oldprefs prefstop showneartags showlocalchanges
     global bgcolor fgcolor ctext diffcolors selectbgcolor
-    global tabstop limitdiffs autoselect
+    global tabstop limitdiffs autoselect extdifftool
 
     set top .gitkprefs
     set prefstop $top
@@ -8041,6 +9267,15 @@
     pack $top.ldiff.b $top.ldiff.l -side left
     grid x $top.ldiff -sticky w
 
+    entry $top.extdifft -textvariable extdifftool
+    frame $top.extdifff
+    label $top.extdifff.l -text [mc "External diff tool" ] -font optionfont \
+	-padx 10
+    button $top.extdifff.b -text [mc "Choose..."] -font optionfont \
+	-command choose_extdiff
+    pack $top.extdifff.l $top.extdifff.b -side left
+    grid x $top.extdifff $top.extdifft -sticky w
+
     label $top.cdisp -text [mc "Colors: press to choose"]
     grid $top.cdisp - -sticky w -pady 10
     label $top.bg -padx 40 -relief sunk -background $bgcolor
@@ -8088,6 +9323,15 @@
     bind $top <Visibility> "focus $top.buts.ok"
 }
 
+proc choose_extdiff {} {
+    global extdifftool
+
+    set prog [tk_getOpenFile -title "External diff tool" -multiple false]
+    if {$prog ne {}} {
+	set extdifftool $prog
+    }
+}
+
 proc choosecolor {v vi w x cmd} {
     global $v
 
@@ -8479,7 +9723,6 @@
 }
 
 # defaults...
-set datemode 0
 set wrcomcmd "git diff-tree --stdin -p --pretty"
 
 set gitencoding {}
@@ -8516,6 +9759,8 @@
 set datetimeformat "%Y-%m-%d %H:%M:%S"
 set autoselect 1
 
+set extdifftool "meld"
+
 set colors {green red blue magenta darkgrey brown orange}
 set bgcolor white
 set fgcolor black
@@ -8524,6 +9769,8 @@
 set ignorespace 0
 set selectbgcolor gray85
 
+set circlecolors {white blue gray blue blue}
+
 ## For msgcat loading, first locate the installation location.
 if { [info exists ::env(GITK_MSGSDIR)] } {
     ## Msgsdir was manually set in the environment.
@@ -8570,7 +9817,6 @@
     exit 1
 }
 
-set mergeonly 0
 set revtreeargs {}
 set cmdline_files {}
 set i 0
@@ -8578,11 +9824,6 @@
 foreach arg $argv {
     switch -glob -- $arg {
 	"" { }
-	"-d" { set datemode 1 }
-	"--merge" {
-	    set mergeonly 1
-	    lappend revtreeargs $arg
-	}
 	"--" {
 	    set cmdline_files [lrange $argv [expr {$i + 1}] end]
 	    break
@@ -8598,7 +9839,7 @@
 }
 
 if {$i >= [llength $argv] && $revtreeargs ne {}} {
-    # no -- on command line, but some arguments (other than -d)
+    # no -- on command line, but some arguments (other than --argscmd)
     if {[catch {
 	set f [eval exec git rev-parse --no-revs --no-flags $revtreeargs]
 	set cmdline_files [split $f "\n"]
@@ -8626,42 +9867,9 @@
     }
 }
 
-if {$mergeonly} {
-    # find the list of unmerged files
-    set mlist {}
-    set nr_unmerged 0
-    if {[catch {
-	set fd [open "| git ls-files -u" r]
-    } err]} {
-	show_error {} . "[mc "Couldn't get list of unmerged files:"] $err"
-	exit 1
-    }
-    while {[gets $fd line] >= 0} {
-	set i [string first "\t" $line]
-	if {$i < 0} continue
-	set fname [string range $line [expr {$i+1}] end]
-	if {[lsearch -exact $mlist $fname] >= 0} continue
-	incr nr_unmerged
-	if {$cmdline_files eq {} || [path_filter $cmdline_files $fname]} {
-	    lappend mlist $fname
-	}
-    }
-    catch {close $fd}
-    if {$mlist eq {}} {
-	if {$nr_unmerged == 0} {
-	    show_error {} . [mc "No files selected: --merge specified but\
-			     no files are unmerged."]
-	} else {
-	    show_error {} . [mc "No files selected: --merge specified but\
-			     no unmerged files are within file limit."]
-	}
-	exit 1
-    }
-    set cmdline_files $mlist
-}
-
 set nullid "0000000000000000000000000000000000000000"
 set nullid2 "0000000000000000000000000000000000000001"
+set nullfile "/dev/null"
 
 set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
 
@@ -8693,12 +9901,13 @@
 set viewargs(0) {}
 set viewargscmd(0) {}
 
+set selectedline {}
+set numcommits 0
+set loginstance 0
 set cmdlineok 0
 set stopped 0
 set stuffsaved 0
 set patchnum 0
-set localirow -1
-set localfrow -1
 set lserial 0
 set isworktree [expr {[exec git rev-parse --is-inside-work-tree] == "true"}]
 setcoords
@@ -8718,6 +9927,7 @@
     set viewargs(1) $revtreeargs
     set viewargscmd(1) $revtreeargscmd
     set viewperm(1) 0
+    set vdatemode(1) 0
     addviewmenu 1
     .bar.view entryconf [mc "Edit view..."] -state normal
     .bar.view entryconf [mc "Delete view"] -state normal
diff --git a/gitk-git/po/de.po b/gitk-git/po/de.po
index 5ee2fca..b9867bf 100644
--- a/gitk-git/po/de.po
+++ b/gitk-git/po/de.po
@@ -7,249 +7,253 @@
 msgstr ""
 "Project-Id-Version: git-gui\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-01-09 22:20+0100\n"
-"PO-Revision-Date: 2008-01-09 22:21+0100\n"
+"POT-Creation-Date: 2008-05-01 11:54+0200\n"
+"PO-Revision-Date: 2008-05-02 21:12+0200\n"
 "Last-Translator: Christian Stimming <stimming@tuhh.de>\n"
 "Language-Team: German\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: gitk:101
+#: gitk:111
 msgid "Error executing git rev-list:"
 msgstr "Fehler beim Ausführen von git-rev-list:"
 
-#: gitk:114
+#: gitk:124
 msgid "Reading"
 msgstr "Lesen"
 
-#: gitk:141 gitk:2143
+#: gitk:151 gitk:2191
 msgid "Reading commits..."
 msgstr "Versionen lesen..."
 
-#: gitk:264
+#: gitk:275
 msgid "Can't parse git log output:"
-msgstr "Git log Ausgabe kann nicht erkannt werden:"
+msgstr "Ausgabe von git-log kann nicht erkannt werden:"
 
-#: gitk:375 gitk:2147
+#: gitk:386 gitk:2195
 msgid "No commits selected"
 msgstr "Keine Versionen ausgewählt."
 
-#: gitk:486
+#: gitk:500
 msgid "No commit information available"
 msgstr "Keine Versionsinformation verfügbar"
 
-#: gitk:585 gitk:607 gitk:1908 gitk:6366 gitk:7866 gitk:8020
+#: gitk:599 gitk:621 gitk:1955 gitk:6424 gitk:7924 gitk:8083
 msgid "OK"
 msgstr "Ok"
 
-#: gitk:609 gitk:1909 gitk:6046 gitk:6117 gitk:6218 gitk:6264 gitk:6368
-#: gitk:7867 gitk:8021
+#: gitk:623 gitk:1956 gitk:6108 gitk:6179 gitk:6276 gitk:6322 gitk:6426
+#: gitk:7925 gitk:8084
 msgid "Cancel"
 msgstr "Abbrechen"
 
-#: gitk:646
+#: gitk:661
 msgid "File"
 msgstr "Datei"
 
-#: gitk:648
+#: gitk:663
 msgid "Update"
 msgstr "Aktualisieren"
 
-#: gitk:649
+#: gitk:664
 msgid "Reread references"
 msgstr "Zweige neu laden"
 
-#: gitk:650
+#: gitk:665
 msgid "List references"
-msgstr "Zweige auflisten"
+msgstr "Zweige/Markierungen auflisten"
 
-#: gitk:651
+#: gitk:666
 msgid "Quit"
 msgstr "Beenden"
 
-#: gitk:653
+#: gitk:668
 msgid "Edit"
 msgstr "Bearbeiten"
 
-#: gitk:654
+#: gitk:669
 msgid "Preferences"
 msgstr "Einstellungen"
 
-#: gitk:657
+#: gitk:672 gitk:1892
 msgid "View"
 msgstr "Ansicht"
 
-#: gitk:658
+#: gitk:673
 msgid "New view..."
 msgstr "Neue Ansicht..."
 
-#: gitk:659 gitk:2085 gitk:8651
+#: gitk:674 gitk:2133 gitk:8723
 msgid "Edit view..."
 msgstr "Ansicht bearbeiten..."
 
-#: gitk:661 gitk:2086 gitk:8652
+#: gitk:676 gitk:2134 gitk:8724
 msgid "Delete view"
 msgstr "Ansicht löschen"
 
-#: gitk:663
+#: gitk:678
 msgid "All files"
 msgstr "Alle Dateien"
 
-#: gitk:667
+#: gitk:682
 msgid "Help"
 msgstr "Hilfe"
 
-#: gitk:668 gitk:1280
+#: gitk:683 gitk:1317
 msgid "About gitk"
 msgstr "Über gitk"
 
-#: gitk:669
+#: gitk:684
 msgid "Key bindings"
 msgstr "Tastenkürzel"
 
-#: gitk:726
+#: gitk:741
 msgid "SHA1 ID: "
 msgstr "SHA1:"
 
-#: gitk:776
+#: gitk:791
 msgid "Find"
 msgstr "Suche"
 
-#: gitk:777
+#: gitk:792
 msgid "next"
 msgstr "nächste"
 
-#: gitk:778
+#: gitk:793
 msgid "prev"
 msgstr "vorige"
 
-#: gitk:779
+#: gitk:794
 msgid "commit"
 msgstr "Version"
 
-#: gitk:782 gitk:784 gitk:2308 gitk:2331 gitk:2355 gitk:4257 gitk:4320
+#: gitk:797 gitk:799 gitk:2356 gitk:2379 gitk:2403 gitk:4306 gitk:4369
 msgid "containing:"
 msgstr "enthaltend:"
 
-#: gitk:785 gitk:1741 gitk:1746 gitk:2383
+#: gitk:800 gitk:1778 gitk:1783 gitk:2431
 msgid "touching paths:"
 msgstr "Pfad betreffend:"
 
-#: gitk:786 gitk:2388
+#: gitk:801 gitk:2436
 msgid "adding/removing string:"
-msgstr "String dazu/löschen:"
+msgstr "Zeichenkette ändernd:"
 
-#: gitk:795 gitk:797
+#: gitk:810 gitk:812
 msgid "Exact"
 msgstr "Exakt"
 
-#: gitk:797 gitk:2466 gitk:4225
+#: gitk:812 gitk:2514 gitk:4274
 msgid "IgnCase"
 msgstr "Kein Groß/Klein"
 
-#: gitk:797 gitk:2357 gitk:2464 gitk:4221
+#: gitk:812 gitk:2405 gitk:2512 gitk:4270
 msgid "Regexp"
 msgstr "Regexp"
 
-#: gitk:799 gitk:800 gitk:2485 gitk:2515 gitk:2522 gitk:4331 gitk:4387
+#: gitk:814 gitk:815 gitk:2533 gitk:2563 gitk:2570 gitk:4380 gitk:4436
 msgid "All fields"
 msgstr "Alle Felder"
 
-#: gitk:800 gitk:2483 gitk:2515 gitk:4287
+#: gitk:815 gitk:2531 gitk:2563 gitk:4336
 msgid "Headline"
 msgstr "Überschrift"
 
-#: gitk:801 gitk:2483 gitk:4287 gitk:4387 gitk:4775
+#: gitk:816 gitk:2531 gitk:4336 gitk:4436 gitk:4827
 msgid "Comments"
 msgstr "Beschreibung"
 
-#: gitk:801 gitk:2483 gitk:2487 gitk:2522 gitk:4287 gitk:4711 gitk:5895
-#: gitk:5910
+#: gitk:816 gitk:2531 gitk:2535 gitk:2570 gitk:4336 gitk:4763 gitk:5957
+#: gitk:5972
 msgid "Author"
 msgstr "Autor"
 
-#: gitk:801 gitk:2483 gitk:4287 gitk:4713
+#: gitk:816 gitk:2531 gitk:4336 gitk:4765
 msgid "Committer"
 msgstr "Eintragender"
 
-#: gitk:829
+#: gitk:845
 msgid "Search"
 msgstr "Suche"
 
-#: gitk:836
+#: gitk:852
 msgid "Diff"
 msgstr "Vergleich"
 
-#: gitk:838
+#: gitk:854
 msgid "Old version"
 msgstr "Alte Version"
 
-#: gitk:840
+#: gitk:856
 msgid "New version"
 msgstr "Neue Version"
 
-#: gitk:842
+#: gitk:858
 msgid "Lines of context"
 msgstr "Kontextzeilen"
 
-#: gitk:900
+#: gitk:868
+msgid "Ignore space change"
+msgstr "Leerzeichenänderungen ignorieren"
+
+#: gitk:926
 msgid "Patch"
 msgstr "Patch"
 
-#: gitk:902
+#: gitk:928
 msgid "Tree"
 msgstr "Baum"
 
-#: gitk:1018 gitk:1033 gitk:5961
+#: gitk:1053 gitk:1068 gitk:6023
 msgid "Diff this -> selected"
 msgstr "Vergleich diese -> gewählte"
 
-#: gitk:1020 gitk:1035 gitk:5962
+#: gitk:1055 gitk:1070 gitk:6024
 msgid "Diff selected -> this"
 msgstr "Vergleich gewählte -> diese"
 
-#: gitk:1022 gitk:1037 gitk:5963
+#: gitk:1057 gitk:1072 gitk:6025
 msgid "Make patch"
 msgstr "Patch erstellen"
 
-#: gitk:1023 gitk:6101
+#: gitk:1058 gitk:6163
 msgid "Create tag"
 msgstr "Markierung erstellen"
 
-#: gitk:1024 gitk:6198
+#: gitk:1059 gitk:6256
 msgid "Write commit to file"
 msgstr "Version in Datei schreiben"
 
-#: gitk:1025 gitk:6252
+#: gitk:1060 gitk:6310
 msgid "Create new branch"
 msgstr "Neuen Zweig erstellen"
 
-#: gitk:1026
+#: gitk:1061
 msgid "Cherry-pick this commit"
 msgstr "Diese Version pflücken"
 
-#: gitk:1028
+#: gitk:1063
 msgid "Reset HEAD branch to here"
 msgstr "HEAD-Zweig auf diese Version zurücksetzen"
 
-#: gitk:1044
+#: gitk:1079
 msgid "Check out this branch"
 msgstr "Auf diesen Zweig umstellen"
 
-#: gitk:1046
+#: gitk:1081
 msgid "Remove this branch"
 msgstr "Zweig löschen"
 
-#: gitk:1052
+#: gitk:1087
 msgid "Highlight this too"
 msgstr "Diesen auch hervorheben"
 
-#: gitk:1054
+#: gitk:1089
 msgid "Highlight this only"
 msgstr "Nur diesen hervorheben"
 
-#: gitk:1281
+#: gitk:1318
 msgid ""
 "\n"
 "Gitk - a commit viewer for git\n"
@@ -267,262 +271,425 @@
 "License\n"
 "        "
 
-#: gitk:1289 gitk:1350 gitk:6524
+#: gitk:1326 gitk:1387 gitk:6582
 msgid "Close"
 msgstr "Schließen"
 
-#: gitk:1308
+#: gitk:1345
 msgid "Gitk key bindings"
 msgstr "Gitk Tastaturbelegung"
 
-#: gitk:1858
+#: gitk:1347
+msgid "Gitk key bindings:"
+msgstr "Gitk Tastaturbelegung:"
+
+#: gitk:1349
+#, tcl-format
+msgid "<%s-Q>\t\tQuit"
+msgstr "<%s-Q>\t\tBeenden"
+
+#: gitk:1350
+msgid "<Home>\t\tMove to first commit"
+msgstr "<Pos1>\t\tZur neuesten Version springen"
+
+#: gitk:1351
+msgid "<End>\t\tMove to last commit"
+msgstr "<Ende>\t\tZur ältesten Version springen"
+
+#: gitk:1352
+msgid "<Up>, p, i\tMove up one commit"
+msgstr "<Hoch>, p, i\tNächste neuere Version"
+
+#: gitk:1353
+msgid "<Down>, n, k\tMove down one commit"
+msgstr "<Runter>, n, k\tNächste ältere Version"
+
+#: gitk:1354
+msgid "<Left>, z, j\tGo back in history list"
+msgstr "<Links>, z, j\tEine Version zurückgehen"
+
+#: gitk:1355
+msgid "<Right>, x, l\tGo forward in history list"
+msgstr "<Rechts>, x, l\tEine Version weitergehen"
+
+#: gitk:1356
+msgid "<PageUp>\tMove up one page in commit list"
+msgstr "<BildHoch>\tEine Seite nach oben blättern"
+
+#: gitk:1357
+msgid "<PageDown>\tMove down one page in commit list"
+msgstr "<BildRunter>\tEine Seite nach unten blättern"
+
+#: gitk:1358
+#, tcl-format
+msgid "<%s-Home>\tScroll to top of commit list"
+msgstr "<%s-Pos1>\tZum oberen Ende der Versionsliste blättern"
+
+#: gitk:1359
+#, tcl-format
+msgid "<%s-End>\tScroll to bottom of commit list"
+msgstr "<%s-Ende>\tZum unteren Ende der Versionsliste blättern"
+
+#: gitk:1360
+#, tcl-format
+msgid "<%s-Up>\tScroll commit list up one line"
+msgstr "<%s-Hoch>\tVersionsliste eine Zeile nach oben blättern"
+
+#: gitk:1361
+#, tcl-format
+msgid "<%s-Down>\tScroll commit list down one line"
+msgstr "<%s-Runter>\tVersionsliste eine Zeile nach unten blättern"
+
+#: gitk:1362
+#, tcl-format
+msgid "<%s-PageUp>\tScroll commit list up one page"
+msgstr "<%s-BildHoch>\tVersionsliste eine Seite hoch blättern"
+
+#: gitk:1363
+#, tcl-format
+msgid "<%s-PageDown>\tScroll commit list down one page"
+msgstr "<%s-BildRunter>\tVersionsliste eine Seite nach unten blättern"
+
+#: gitk:1364
+msgid "<Shift-Up>\tFind backwards (upwards, later commits)"
+msgstr "<Umschalt-Hoch>\tRückwärts suchen (nach oben; neuere Versionen)"
+
+#: gitk:1365
+msgid "<Shift-Down>\tFind forwards (downwards, earlier commits)"
+msgstr "<Umschalt-Runter> Suchen (nach unten; ältere Versionen)"
+
+#: gitk:1366
+msgid "<Delete>, b\tScroll diff view up one page"
+msgstr "<Entf>, b\t\tVergleich eine Seite nach oben blättern"
+
+#: gitk:1367
+msgid "<Backspace>\tScroll diff view up one page"
+msgstr "<Löschtaste>\tVergleich eine Seite nach oben blättern"
+
+#: gitk:1368
+msgid "<Space>\t\tScroll diff view down one page"
+msgstr "<Leertaste>\tVergleich eine Seite nach unten blättern"
+
+#: gitk:1369
+msgid "u\t\tScroll diff view up 18 lines"
+msgstr "u\t\tVergleich um 18 Zeilen nach oben (»up«) blättern"
+
+#: gitk:1370
+msgid "d\t\tScroll diff view down 18 lines"
+msgstr "d\t\tVergleich um 18 Zeilen nach unten (»down«) blättern"
+
+#: gitk:1371
+#, tcl-format
+msgid "<%s-F>\t\tFind"
+msgstr "<%s-F>\t\tSuchen"
+
+#: gitk:1372
+#, tcl-format
+msgid "<%s-G>\t\tMove to next find hit"
+msgstr "<%s-G>\t\tWeitersuchen"
+
+#: gitk:1373
+msgid "<Return>\tMove to next find hit"
+msgstr "<Eingabetaste>\tWeitersuchen"
+
+#: gitk:1374
+msgid "/\t\tMove to next find hit, or redo find"
+msgstr "/\t\tWeitersuchen oder neue Suche beginnen"
+
+#: gitk:1375
+msgid "?\t\tMove to previous find hit"
+msgstr "?\t\tRückwärts weitersuchen"
+
+#: gitk:1376
+msgid "f\t\tScroll diff view to next file"
+msgstr "f\t\tVergleich zur nächsten Datei (»file«) blättern"
+
+#: gitk:1377
+#, tcl-format
+msgid "<%s-S>\t\tSearch for next hit in diff view"
+msgstr "<%s-S>\t\tWeitersuchen im Vergleich"
+
+#: gitk:1378
+#, tcl-format
+msgid "<%s-R>\t\tSearch for previous hit in diff view"
+msgstr "<%s-R>\t\tRückwärts weitersuchen im Vergleich"
+
+#: gitk:1379
+#, tcl-format
+msgid "<%s-KP+>\tIncrease font size"
+msgstr "<%s-Nummerblock-Plus>\tSchriftgröße vergrößern"
+
+#: gitk:1380
+#, tcl-format
+msgid "<%s-plus>\tIncrease font size"
+msgstr "<%s-Plus>\tSchriftgröße vergrößern"
+
+#: gitk:1381
+#, tcl-format
+msgid "<%s-KP->\tDecrease font size"
+msgstr "<%s-Nummernblock-> Schriftgröße verkleinern"
+
+#: gitk:1382
+#, tcl-format
+msgid "<%s-minus>\tDecrease font size"
+msgstr "<%s-Minus>\tSchriftgröße verkleinern"
+
+#: gitk:1383
+msgid "<F5>\t\tUpdate"
+msgstr "<F5>\t\tAktualisieren"
+
+#: gitk:1896
 msgid "Gitk view definition"
 msgstr "Gitk Ansichten"
 
-#: gitk:1882
+#: gitk:1921
 msgid "Name"
 msgstr "Name"
 
-#: gitk:1885
+#: gitk:1924
 msgid "Remember this view"
 msgstr "Diese Ansicht speichern"
 
-#: gitk:1889
+#: gitk:1928
 msgid "Commits to include (arguments to git rev-list):"
 msgstr "Versionen anzeigen (Argumente von git-rev-list):"
 
-#: gitk:1895
+#: gitk:1935
+msgid "Command to generate more commits to include:"
+msgstr "Versionsliste durch folgendes Kommando erzeugen lassen:"
+
+#: gitk:1942
 msgid "Enter files and directories to include, one per line:"
 msgstr "Folgende Dateien und Verzeichnisse anzeigen (eine pro Zeile):"
 
-#: gitk:1942
+#: gitk:1989
 msgid "Error in commit selection arguments:"
 msgstr "Fehler in den ausgewählten Versionen:"
 
-#: gitk:1993 gitk:2079 gitk:2535 gitk:2549 gitk:3732 gitk:8620 gitk:8621
+#: gitk:2043 gitk:2127 gitk:2583 gitk:2597 gitk:3781 gitk:8689 gitk:8690
 msgid "None"
 msgstr "Keine"
 
-#: gitk:2483 gitk:4287 gitk:5897 gitk:5912
+#: gitk:2531 gitk:4336 gitk:5959 gitk:5974
 msgid "Date"
 msgstr "Datum"
 
-#: gitk:2483 gitk:4287
+#: gitk:2531 gitk:4336
 msgid "CDate"
 msgstr "Eintragedatum"
 
-#: gitk:2632 gitk:2637
+#: gitk:2680 gitk:2685
 msgid "Descendant"
 msgstr "Abkömmling"
 
-#: gitk:2633
+#: gitk:2681
 msgid "Not descendant"
 msgstr "Nicht Abkömmling"
 
-#: gitk:2640 gitk:2645
+#: gitk:2688 gitk:2693
 msgid "Ancestor"
 msgstr "Vorgänger"
 
-#: gitk:2641
+#: gitk:2689
 msgid "Not ancestor"
 msgstr "Nicht Vorgänger"
 
-#: gitk:2875
+#: gitk:2924
 msgid "Local changes checked in to index but not committed"
 msgstr "Lokale Änderungen bereitgestellt, aber nicht eingetragen"
 
-#: gitk:2905
+#: gitk:2954
 msgid "Local uncommitted changes, not checked in to index"
 msgstr "Lokale Änderungen, nicht bereitgestellt"
 
-#: gitk:4256
+#: gitk:4305
 msgid "Searching"
 msgstr "Suchen"
 
-#: gitk:4715
+#: gitk:4767
 msgid "Tags:"
 msgstr "Markierungen:"
 
-#: gitk:4732 gitk:4738 gitk:5890
+#: gitk:4784 gitk:4790 gitk:5952
 msgid "Parent"
 msgstr "Eltern"
 
-#: gitk:4743
+#: gitk:4795
 msgid "Child"
 msgstr "Kind"
 
-#: gitk:4752
+#: gitk:4804
 msgid "Branch"
 msgstr "Zweig"
 
-#: gitk:4755
+#: gitk:4807
 msgid "Follows"
 msgstr "Folgt auf"
 
-#: gitk:4758
+#: gitk:4810
 msgid "Precedes"
 msgstr "Vorgänger von"
 
-#: gitk:5040
+#: gitk:5094
 msgid "Error getting merge diffs:"
 msgstr "Fehler beim Laden des Vergleichs:"
 
-#: gitk:5717
+#: gitk:5779
 msgid "Goto:"
 msgstr "Gehe zu:"
 
-#: gitk:5719
+#: gitk:5781
 msgid "SHA1 ID:"
-msgstr "SHA1 Kennung:"
+msgstr "SHA1-Hashwert:"
 
-#: gitk:5744
+#: gitk:5806
 #, tcl-format
 msgid "Short SHA1 id %s is ambiguous"
-msgstr "Kurze SHA1-Kennung »%s« ist mehrdeutig"
+msgstr "Kurzer SHA1-Hashwert »%s« ist mehrdeutig"
 
-#: gitk:5756
+#: gitk:5818
 #, tcl-format
 msgid "SHA1 id %s is not known"
-msgstr "SHA1-Kennung »%s« unbekannt"
+msgstr "SHA1-Hashwert »%s« unbekannt"
 
-#: gitk:5758
+#: gitk:5820
 #, tcl-format
 msgid "Tag/Head %s is not known"
 msgstr "Markierung/Zweig »%s« ist unbekannt"
 
-#: gitk:5900
+#: gitk:5962
 msgid "Children"
 msgstr "Kinder"
 
-#: gitk:5957
+#: gitk:6019
 #, tcl-format
 msgid "Reset %s branch to here"
 msgstr "Zweig »%s« hierher zurücksetzen"
 
-#: gitk:5988
+#: gitk:6050
 msgid "Top"
 msgstr "Oben"
 
-#: gitk:5989
+#: gitk:6051
 msgid "From"
 msgstr "Von"
 
-#: gitk:5994
+#: gitk:6056
 msgid "To"
 msgstr "bis"
 
-#: gitk:6017
+#: gitk:6079
 msgid "Generate patch"
 msgstr "Patch erstellen"
 
-#: gitk:6019
+#: gitk:6081
 msgid "From:"
 msgstr "Von:"
 
-#: gitk:6028
+#: gitk:6090
 msgid "To:"
 msgstr "bis:"
 
-#: gitk:6037
+#: gitk:6099
 msgid "Reverse"
 msgstr "Umgekehrt"
 
-#: gitk:6039 gitk:6212
+#: gitk:6101 gitk:6270
 msgid "Output file:"
 msgstr "Ausgabedatei:"
 
-#: gitk:6045
+#: gitk:6107
 msgid "Generate"
 msgstr "Erzeugen"
 
-#: gitk:6081
+#: gitk:6143
 msgid "Error creating patch:"
 msgstr "Fehler beim Patch erzeugen:"
 
-#: gitk:6103 gitk:6200 gitk:6254
+#: gitk:6165 gitk:6258 gitk:6312
 msgid "ID:"
 msgstr "ID:"
 
-#: gitk:6112
+#: gitk:6174
 msgid "Tag name:"
 msgstr "Markierungsname:"
 
-#: gitk:6116 gitk:6263
+#: gitk:6178 gitk:6321
 msgid "Create"
 msgstr "Erstellen"
 
-#: gitk:6131
+#: gitk:6193
 msgid "No tag name specified"
 msgstr "Kein Markierungsname angegeben"
 
-#: gitk:6135
+#: gitk:6197
 #, tcl-format
 msgid "Tag \"%s\" already exists"
 msgstr "Markierung »%s« existiert bereits."
 
-#: gitk:6145
+#: gitk:6203
 msgid "Error creating tag:"
 msgstr "Fehler bei Markierung erstellen:"
 
-#: gitk:6209
+#: gitk:6267
 msgid "Command:"
 msgstr "Kommando:"
 
-#: gitk:6217
+#: gitk:6275
 msgid "Write"
 msgstr "Schreiben"
 
-#: gitk:6233
+#: gitk:6291
 msgid "Error writing commit:"
-msgstr "Fehler beim Version eintragen:"
+msgstr "Fehler beim Schreiben der Version:"
 
-#: gitk:6259
+#: gitk:6317
 msgid "Name:"
 msgstr "Name:"
 
-#: gitk:6278
+#: gitk:6336
 msgid "Please specify a name for the new branch"
 msgstr "Bitte geben Sie einen Namen für den neuen Zweig an."
 
-#: gitk:6307
+#: gitk:6365
 #, tcl-format
 msgid "Commit %s is already included in branch %s -- really re-apply it?"
 msgstr ""
 "Version »%s« ist bereits im Zweig »%s« enthalten -- trotzdem erneut "
 "eintragen?"
 
-#: gitk:6312
+#: gitk:6370
 msgid "Cherry-picking"
 msgstr "Version pflücken"
 
-#: gitk:6324
+#: gitk:6382
 msgid "No changes committed"
 msgstr "Keine Änderungen eingetragen"
 
-#: gitk:6347
+#: gitk:6405
 msgid "Confirm reset"
 msgstr "Zurücksetzen bestätigen"
 
-#: gitk:6349
+#: gitk:6407
 #, tcl-format
 msgid "Reset branch %s to %s?"
 msgstr "Zweig »%s« auf »%s« zurücksetzen?"
 
-#: gitk:6353
+#: gitk:6411
 msgid "Reset type:"
 msgstr "Art des Zurücksetzens:"
 
-#: gitk:6357
+#: gitk:6415
 msgid "Soft: Leave working tree and index untouched"
 msgstr "Harmlos: Arbeitskopie und Bereitstellung unverändert"
 
-#: gitk:6360
+#: gitk:6418
 msgid "Mixed: Leave working tree untouched, reset index"
 msgstr ""
 "Gemischt: Arbeitskopie unverändert,\n"
 "Bereitstellung zurückgesetzt"
 
-#: gitk:6363
+#: gitk:6421
 msgid ""
 "Hard: Reset working tree and index\n"
 "(discard ALL local changes)"
@@ -530,21 +697,21 @@
 "Hart: Arbeitskopie und Bereitstellung\n"
 "(Alle lokalen Änderungen werden gelöscht)"
 
-#: gitk:6379
+#: gitk:6437
 msgid "Resetting"
 msgstr "Zurücksetzen"
 
-#: gitk:6436
+#: gitk:6494
 msgid "Checking out"
 msgstr "Umstellen"
 
-#: gitk:6466
+#: gitk:6524
 msgid "Cannot delete the currently checked-out branch"
 msgstr ""
 "Der Zweig, auf den die Arbeitskopie momentan umgestellt ist, kann nicht "
 "gelöscht werden."
 
-#: gitk:6472
+#: gitk:6530
 #, tcl-format
 msgid ""
 "The commits on branch %s aren't on any other branch.\n"
@@ -553,16 +720,16 @@
 "Die Versionen auf Zweig »%s« existieren auf keinem anderen Zweig.\n"
 "Zweig »%s« trotzdem löschen?"
 
-#: gitk:6503
+#: gitk:6561
 #, tcl-format
 msgid "Tags and heads: %s"
 msgstr "Markierungen und Zweige: %s"
 
-#: gitk:6517
+#: gitk:6575
 msgid "Filter"
 msgstr "Filtern"
 
-#: gitk:6811
+#: gitk:6869
 msgid ""
 "Error reading commit topology information; branch and preceding/following "
 "tag information will be incomplete."
@@ -570,113 +737,117 @@
 "Fehler beim Lesen der Strukturinformationen; Zweige und Vorgänger/Nachfolger "
 "Informationen werden unvollständig sein."
 
-#: gitk:7795
+#: gitk:7853
 msgid "Tag"
 msgstr "Markierung"
 
-#: gitk:7795
+#: gitk:7853
 msgid "Id"
 msgstr "Id"
 
-#: gitk:7835
+#: gitk:7893
 msgid "Gitk font chooser"
 msgstr "Gitk Schriften wählen"
 
-#: gitk:7852
+#: gitk:7910
 msgid "B"
 msgstr "F"
 
-#: gitk:7855
+#: gitk:7913
 msgid "I"
 msgstr "K"
 
-#: gitk:7948
+#: gitk:8006
 msgid "Gitk preferences"
 msgstr "Gitk Einstellungen"
 
-#: gitk:7949
+#: gitk:8007
 msgid "Commit list display options"
 msgstr "Anzeige Versionsliste"
 
-#: gitk:7952
+#: gitk:8010
 msgid "Maximum graph width (lines)"
 msgstr "Maximale Graphenbreite (Zeilen)"
 
-#: gitk:7956
+#: gitk:8014
 #, tcl-format
 msgid "Maximum graph width (% of pane)"
 msgstr "Maximale Graphenbreite (% des Fensters)"
 
-#: gitk:7961
+#: gitk:8019
 msgid "Show local changes"
 msgstr "Lokale Änderungen anzeigen"
 
-#: gitk:7966
+#: gitk:8024
+msgid "Auto-select SHA1"
+msgstr "SHA1-Hashwert automatisch markieren"
+
+#: gitk:8029
 msgid "Diff display options"
 msgstr "Anzeige Vergleich"
 
-#: gitk:7968
+#: gitk:8031
 msgid "Tab spacing"
 msgstr "Tabulatorbreite"
 
-#: gitk:7972
+#: gitk:8035
 msgid "Display nearby tags"
 msgstr "Naheliegende Überschriften anzeigen"
 
-#: gitk:7977
+#: gitk:8040
 msgid "Limit diffs to listed paths"
 msgstr "Vergleich nur für angezeigte Pfade"
 
-#: gitk:7982
+#: gitk:8045
 msgid "Colors: press to choose"
 msgstr "Farben: Klicken zum Wählen"
 
-#: gitk:7985
+#: gitk:8048
 msgid "Background"
-msgstr "Vordergrund"
-
-#: gitk:7989
-msgid "Foreground"
 msgstr "Hintergrund"
 
-#: gitk:7993
+#: gitk:8052
+msgid "Foreground"
+msgstr "Vordergrund"
+
+#: gitk:8056
 msgid "Diff: old lines"
 msgstr "Vergleich: Alte Zeilen"
 
-#: gitk:7998
+#: gitk:8061
 msgid "Diff: new lines"
 msgstr "Vergleich: Neue Zeilen"
 
-#: gitk:8003
+#: gitk:8066
 msgid "Diff: hunk header"
 msgstr "Vergleich: Änderungstitel"
 
-#: gitk:8009
+#: gitk:8072
 msgid "Select bg"
 msgstr "Hintergrundfarbe Auswählen"
 
-#: gitk:8013
+#: gitk:8076
 msgid "Fonts: press to choose"
 msgstr "Schriftart: Klicken zum Wählen"
 
-#: gitk:8015
+#: gitk:8078
 msgid "Main font"
 msgstr "Programmschriftart"
 
-#: gitk:8016
+#: gitk:8079
 msgid "Diff display font"
 msgstr "Vergleich"
 
-#: gitk:8017
+#: gitk:8080
 msgid "User interface font"
 msgstr "Beschriftungen"
 
-#: gitk:8033
+#: gitk:8096
 #, tcl-format
 msgid "Gitk: choose color for %s"
 msgstr "Gitk: Farbe wählen für %s"
 
-#: gitk:8414
+#: gitk:8477
 msgid ""
 "Sorry, gitk cannot run with this version of Tcl/Tk.\n"
 " Gitk requires at least Tcl/Tk 8.4."
@@ -684,35 +855,33 @@
 "Gitk läuft nicht mit dieser Version von Tcl/Tk.\n"
 "Gitk benötigt mindestens Tcl/Tk 8.4."
 
-#: gitk:8501
+#: gitk:8566
 msgid "Cannot find a git repository here."
 msgstr "Kein Git-Projektarchiv gefunden."
 
-#: gitk:8505
+#: gitk:8570
 #, tcl-format
 msgid "Cannot find the git directory \"%s\"."
 msgstr "Git-Verzeichnis »%s« wurde nicht gefunden."
 
-#: gitk:8544
+#: gitk:8613
 #, tcl-format
 msgid "Ambiguous argument '%s': both revision and filename"
 msgstr "Mehrdeutige Angabe »%s«: Sowohl Version als auch Dateiname existiert."
 
-#: gitk:8556
+#: gitk:8625
 msgid "Bad arguments to gitk:"
 msgstr "Falsche Kommandozeilen-Parameter für gitk:"
 
-#: gitk:8568
+#: gitk:8637
 msgid "Couldn't get list of unmerged files:"
 msgstr "Liste der nicht-zusammengeführten Dateien nicht gefunden:"
 
-#: gitk:8584
+#: gitk:8653
 msgid "No files selected: --merge specified but no files are unmerged."
-msgstr ""
-"Keine Dateien ausgewähle: --merge angegeben, es existieren aber keine nicht-"
-"zusammengeführten Dateien."
+msgstr "Keine Dateien ausgewählt: --merge angegeben, es existieren aber keine nicht-zusammengeführten Dateien."
 
-#: gitk:8587
+#: gitk:8656
 msgid ""
 "No files selected: --merge specified but no unmerged files are within file "
 "limit."
@@ -720,6 +889,6 @@
 "Keine Dateien ausgewähle: --merge angegeben, aber keine nicht-"
 "zusammengeführten Dateien sind in der Dateiauswahl."
 
-#: gitk:8646
+#: gitk:8717
 msgid "Command line"
 msgstr "Kommandozeile"
diff --git a/gitk-git/po/es.po b/gitk-git/po/es.po
new file mode 100644
index 0000000..2cb1486
--- /dev/null
+++ b/gitk-git/po/es.po
@@ -0,0 +1,890 @@
+# Translation of gitk
+# Copyright (C) 2005-2008 Santiago Gala
+# This file is distributed under the same license as the gitk package.
+# Santiago Gala <santiago.gala@gmail.com>, 2008.
+#
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gitk\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-03-13 17:29+0100\n"
+"PO-Revision-Date: 2008-03-25 11:20+0100\n"
+"Last-Translator: Santiago Gala <santiago.gala@gmail.com>\n"
+"Language-Team: Spanish\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: gitk:111
+msgid "Error executing git rev-list:"
+msgstr "Error al ejecutar git rev-list:"
+
+#: gitk:124
+msgid "Reading"
+msgstr "Leyendo"
+
+#: gitk:151 gitk:2191
+msgid "Reading commits..."
+msgstr "Leyendo revisiones..."
+
+#: gitk:275
+msgid "Can't parse git log output:"
+msgstr "Error analizando la salida de git log:"
+
+#: gitk:386 gitk:2195
+msgid "No commits selected"
+msgstr "No se seleccionaron revisiones"
+
+#: gitk:500
+msgid "No commit information available"
+msgstr "Falta información sobre las revisiones"
+
+#: gitk:599 gitk:621 gitk:1955 gitk:6423 gitk:7923 gitk:8082
+msgid "OK"
+msgstr "Aceptar"
+
+#: gitk:623 gitk:1956 gitk:6107 gitk:6178 gitk:6275 gitk:6321 gitk:6425
+#: gitk:7924 gitk:8083
+msgid "Cancel"
+msgstr "Cancelar"
+
+#: gitk:661
+msgid "File"
+msgstr "Archivo"
+
+#: gitk:663
+msgid "Update"
+msgstr "Actualizar"
+
+#: gitk:664
+msgid "Reread references"
+msgstr "Releer referencias"
+
+#: gitk:665
+msgid "List references"
+msgstr "Lista de referencias"
+
+#: gitk:666
+msgid "Quit"
+msgstr "Salir"
+
+#: gitk:668
+msgid "Edit"
+msgstr "Editar"
+
+#: gitk:669
+msgid "Preferences"
+msgstr "Preferencias"
+
+#: gitk:672 gitk:1892
+msgid "View"
+msgstr "Vista"
+
+#: gitk:673
+msgid "New view..."
+msgstr "Nueva vista..."
+
+#: gitk:674 gitk:2133 gitk:8722
+msgid "Edit view..."
+msgstr "Modificar vista..."
+
+#: gitk:676 gitk:2134 gitk:8723
+msgid "Delete view"
+msgstr "Eliminar vista"
+
+#: gitk:678
+msgid "All files"
+msgstr "Todos los archivos"
+
+#: gitk:682
+msgid "Help"
+msgstr "Ayuda"
+
+#: gitk:683 gitk:1317
+msgid "About gitk"
+msgstr "Acerca de gitk"
+
+#: gitk:684
+msgid "Key bindings"
+msgstr "Combinaciones de teclas"
+
+#: gitk:741
+msgid "SHA1 ID: "
+msgstr "SHA1 ID: "
+
+#: gitk:791
+msgid "Find"
+msgstr "Buscar"
+
+#: gitk:792
+msgid "next"
+msgstr "<<"
+
+#: gitk:793
+msgid "prev"
+msgstr ">>"
+
+#: gitk:794
+msgid "commit"
+msgstr "revisión"
+
+#: gitk:797 gitk:799 gitk:2356 gitk:2379 gitk:2403 gitk:4306 gitk:4369
+msgid "containing:"
+msgstr "que contiene:"
+
+#: gitk:800 gitk:1778 gitk:1783 gitk:2431
+msgid "touching paths:"
+msgstr "que modifica la ruta:"
+
+#: gitk:801 gitk:2436
+msgid "adding/removing string:"
+msgstr "que añade/elimina cadena:"
+
+#: gitk:810 gitk:812
+msgid "Exact"
+msgstr "Exacto"
+
+#: gitk:812 gitk:2514 gitk:4274
+msgid "IgnCase"
+msgstr "NoMayús"
+
+#: gitk:812 gitk:2405 gitk:2512 gitk:4270
+msgid "Regexp"
+msgstr "Regex"
+
+#: gitk:814 gitk:815 gitk:2533 gitk:2563 gitk:2570 gitk:4380 gitk:4436
+msgid "All fields"
+msgstr "Todos los campos"
+
+#: gitk:815 gitk:2531 gitk:2563 gitk:4336
+msgid "Headline"
+msgstr "Título"
+
+#: gitk:816 gitk:2531 gitk:4336 gitk:4436 gitk:4827
+msgid "Comments"
+msgstr "Comentarios"
+
+#: gitk:816 gitk:2531 gitk:2535 gitk:2570 gitk:4336 gitk:4763 gitk:5956
+#: gitk:5971
+msgid "Author"
+msgstr "Autor"
+
+#: gitk:816 gitk:2531 gitk:4336 gitk:4765
+msgid "Committer"
+msgstr ""
+
+#: gitk:845
+msgid "Search"
+msgstr "Buscar"
+
+#: gitk:852
+msgid "Diff"
+msgstr "Diferencia"
+
+#: gitk:854
+msgid "Old version"
+msgstr "Versión antigua"
+
+#: gitk:856
+msgid "New version"
+msgstr "Versión nueva"
+
+#: gitk:858
+msgid "Lines of context"
+msgstr "Líneas de contexto"
+
+#: gitk:868
+msgid "Ignore space change"
+msgstr "Ignora cambios de espaciado"
+
+#: gitk:926
+msgid "Patch"
+msgstr "Parche"
+
+#: gitk:928
+msgid "Tree"
+msgstr "Árbol"
+
+#: gitk:1053 gitk:1068 gitk:6022
+msgid "Diff this -> selected"
+msgstr "Diferencia de esta -> seleccionada"
+
+#: gitk:1055 gitk:1070 gitk:6023
+msgid "Diff selected -> this"
+msgstr "Diferencia de seleccionada -> esta"
+
+#: gitk:1057 gitk:1072 gitk:6024
+msgid "Make patch"
+msgstr "Crear patch"
+
+#: gitk:1058 gitk:6162
+msgid "Create tag"
+msgstr "Crear etiqueta"
+
+#: gitk:1059 gitk:6255
+msgid "Write commit to file"
+msgstr "Escribir revisiones a archivo"
+
+#: gitk:1060 gitk:6309
+msgid "Create new branch"
+msgstr "Crear nueva rama"
+
+#: gitk:1061
+msgid "Cherry-pick this commit"
+msgstr "Añadir esta revisión a la rama actual (cherry-pick)"
+
+#: gitk:1063
+msgid "Reset HEAD branch to here"
+msgstr "Traer la rama HEAD aquí"
+
+#: gitk:1079
+msgid "Check out this branch"
+msgstr "Cambiar a esta rama"
+
+#: gitk:1081
+msgid "Remove this branch"
+msgstr "Eliminar esta rama"
+
+#: gitk:1087
+msgid "Highlight this too"
+msgstr "Seleccionar también"
+
+#: gitk:1089
+msgid "Highlight this only"
+msgstr "Seleccionar sólo"
+
+#: gitk:1318
+msgid ""
+"\n"
+"Gitk - a commit viewer for git\n"
+"\n"
+"Copyright © 2005-2006 Paul Mackerras\n"
+"\n"
+"Use and redistribute under the terms of the GNU General Public License"
+msgstr ""
+"\n"
+"Gitk - un visualizador de revisiones para git\n"
+"\n"
+"Copyright © 2005-2006 Paul Mackerras\n"
+"\n"
+"Uso y redistribución permitidos según los términos de la Licencia Pública General de "
+"GNU (GNU GPL)"
+
+#: gitk:1326 gitk:1387 gitk:6581
+msgid "Close"
+msgstr "Cerrar"
+
+#: gitk:1345
+msgid "Gitk key bindings"
+msgstr "Combinaciones de tecla de Gitk"
+
+#: gitk:1347
+msgid "Gitk key bindings:"
+msgstr "Combinaciones de tecla de Gitk:"
+
+#: gitk:1349
+#, tcl-format
+msgid "<%s-Q>\t\tQuit"
+msgstr "<%s-Q>\t\tSalir"
+
+#: gitk:1350
+msgid "<Home>\t\tMove to first commit"
+msgstr "<Home>\t\tIr a la primera revisión"
+
+#: gitk:1351
+msgid "<End>\t\tMove to last commit"
+msgstr "<End>\t\tIr a la última revisión"
+
+#: gitk:1352
+msgid "<Up>, p, i\tMove up one commit"
+msgstr "<Up>, p, i\tSubir una revisión"
+
+#: gitk:1353
+msgid "<Down>, n, k\tMove down one commit"
+msgstr "<Down>, n, k\tBajar una revisión"
+
+#: gitk:1354
+msgid "<Left>, z, j\tGo back in history list"
+msgstr "<Left>, z, j\tRetroceder en la historia"
+
+#: gitk:1355
+msgid "<Right>, x, l\tGo forward in history list"
+msgstr "<Right>, x, l\tAvanzar en la historia"
+
+#: gitk:1356
+msgid "<PageUp>\tMove up one page in commit list"
+msgstr "<PageUp>\tSubir una página en la lista de revisiones"
+
+#: gitk:1357
+msgid "<PageDown>\tMove down one page in commit list"
+msgstr "<PageDown>\tBajar una página en la lista de revisiones"
+
+#: gitk:1358
+#, tcl-format
+msgid "<%s-Home>\tScroll to top of commit list"
+msgstr "<%s-Home>\tDesplazarse al inicio de la lista de revisiones"
+
+#: gitk:1359
+#, tcl-format
+msgid "<%s-End>\tScroll to bottom of commit list"
+msgstr "<%s-End>\tDesplazarse al final de la lista de revisiones"
+
+#: gitk:1360
+#, tcl-format
+msgid "<%s-Up>\tScroll commit list up one line"
+msgstr "<%s-Up>\tDesplazar una línea hacia arriba la lista de revisiones"
+
+#: gitk:1361
+#, tcl-format
+msgid "<%s-Down>\tScroll commit list down one line"
+msgstr "<%s-Down>\tDesplazar una línea hacia abajo la lista de revisiones"
+
+#: gitk:1362
+#, tcl-format
+msgid "<%s-PageUp>\tScroll commit list up one page"
+msgstr "<%s-PageUp>\tDesplazar una página hacia arriba la lista de revisiones"
+
+#: gitk:1363
+#, tcl-format
+msgid "<%s-PageDown>\tScroll commit list down one page"
+msgstr "<%s-PageDown>\tDesplazar una página hacia abajo la lista de revisiones"
+
+#: gitk:1364
+msgid "<Shift-Up>\tFind backwards (upwards, later commits)"
+msgstr "<Shift-Up>\tBuscar hacia atrás (arriba, revisiones siguientes)"
+
+#: gitk:1365
+msgid "<Shift-Down>\tFind forwards (downwards, earlier commits)"
+msgstr "<Shift-Down>\tBuscar hacia adelante (abajo, revisiones anteriores)"
+
+#: gitk:1366
+msgid "<Delete>, b\tScroll diff view up one page"
+msgstr "<Delete>, b\tDesplaza hacia arriba una página la vista de diferencias"
+
+#: gitk:1367
+msgid "<Backspace>\tScroll diff view up one page"
+msgstr "<Backspace>\tDesplaza hacia arriba una página la vista de diferencias"
+
+#: gitk:1368
+msgid "<Space>\t\tScroll diff view down one page"
+msgstr "<Space>\t\tDesplaza hacia abajo una página la vista de diferencias"
+
+#: gitk:1369
+msgid "u\t\tScroll diff view up 18 lines"
+msgstr "u\t\tDesplaza hacia arriba 18 líneas la vista de diferencias"
+
+#: gitk:1370
+msgid "d\t\tScroll diff view down 18 lines"
+msgstr "d\t\tDesplaza hacia abajo 18 líneas la vista de diferencias"
+
+#: gitk:1371
+#, tcl-format
+msgid "<%s-F>\t\tFind"
+msgstr "<%s-F>\t\tBuscar"
+
+#: gitk:1372
+#, tcl-format
+msgid "<%s-G>\t\tMove to next find hit"
+msgstr "<%s-G>\t\tBuscar el siguiente"
+
+#: gitk:1373
+msgid "<Return>\tMove to next find hit"
+msgstr "<Return>\tBuscar el siguiente"
+
+#: gitk:1374
+msgid "/\t\tMove to next find hit, or redo find"
+msgstr "/\t\tBuscar el siguiente, o reiniciar la búsqueda"
+
+#: gitk:1375
+msgid "?\t\tMove to previous find hit"
+msgstr "?\t\tBuscar el anterior"
+
+#: gitk:1376
+msgid "f\t\tScroll diff view to next file"
+msgstr "f\t\tDesplazar la vista de diferencias al archivo siguiente"
+
+#: gitk:1377
+#, tcl-format
+msgid "<%s-S>\t\tSearch for next hit in diff view"
+msgstr "<%s-S>\t\tBuscar siguiente en la vista de diferencias"
+
+#: gitk:1378
+#, tcl-format
+msgid "<%s-R>\t\tSearch for previous hit in diff view"
+msgstr "<%s-R>\t\tBuscar anterior en la vista de diferencias"
+
+#: gitk:1379
+#, tcl-format
+msgid "<%s-KP+>\tIncrease font size"
+msgstr "<%s-KP+>\tAumentar tamaño del texto"
+
+#: gitk:1380
+#, tcl-format
+msgid "<%s-plus>\tIncrease font size"
+msgstr "<%s-plus>\tAumentar tamaño del texto"
+
+#: gitk:1381
+#, tcl-format
+msgid "<%s-KP->\tDecrease font size"
+msgstr "<%s-KP->\tDisminuir tamaño del texto"
+
+#: gitk:1382
+#, tcl-format
+msgid "<%s-minus>\tDecrease font size"
+msgstr "<%s-minus>\tDisminuir tamaño del texto"
+
+#: gitk:1383
+msgid "<F5>\t\tUpdate"
+msgstr "<F5>\t\tActualizar"
+
+#: gitk:1896
+msgid "Gitk view definition"
+msgstr "Definición de vistas de Gitk"
+
+#: gitk:1921
+msgid "Name"
+msgstr "Nombre"
+
+#: gitk:1924
+msgid "Remember this view"
+msgstr "Recordar esta vista"
+
+#: gitk:1928
+msgid "Commits to include (arguments to git rev-list):"
+msgstr "Revisiones a incluir (argumentos a git rev-list):"
+
+#: gitk:1935
+msgid "Command to generate more commits to include:"
+msgstr "Comando que genera más revisiones a incluir:"
+
+#: gitk:1942
+msgid "Enter files and directories to include, one per line:"
+msgstr "Introducir archivos y directorios a incluir, uno por línea:"
+
+#: gitk:1989
+msgid "Error in commit selection arguments:"
+msgstr "Error en los argumentos de selección de las revisiones:"
+
+#: gitk:2043 gitk:2127 gitk:2583 gitk:2597 gitk:3781 gitk:8688 gitk:8689
+msgid "None"
+msgstr "Ninguno"
+
+#: gitk:2531 gitk:4336 gitk:5958 gitk:5973
+msgid "Date"
+msgstr "Fecha"
+
+#: gitk:2531 gitk:4336
+msgid "CDate"
+msgstr "Fecha de creación"
+
+#: gitk:2680 gitk:2685
+msgid "Descendant"
+msgstr "Descendiente"
+
+#: gitk:2681
+msgid "Not descendant"
+msgstr "No descendiente"
+
+#: gitk:2688 gitk:2693
+msgid "Ancestor"
+msgstr "Antepasado"
+
+#: gitk:2689
+msgid "Not ancestor"
+msgstr "No antepasado"
+
+#: gitk:2924
+msgid "Local changes checked in to index but not committed"
+msgstr "Cambios locales añadidos al índice pero sin completar revisión"
+
+#: gitk:2954
+msgid "Local uncommitted changes, not checked in to index"
+msgstr "Cambios locales sin añadir al índice"
+
+#: gitk:4305
+msgid "Searching"
+msgstr "Buscando"
+
+#: gitk:4767
+msgid "Tags:"
+msgstr "Etiquetas:"
+
+#: gitk:4784 gitk:4790 gitk:5951
+msgid "Parent"
+msgstr "Padre"
+
+#: gitk:4795
+msgid "Child"
+msgstr "Hija"
+
+#: gitk:4804
+msgid "Branch"
+msgstr "Rama"
+
+#: gitk:4807
+msgid "Follows"
+msgstr "Sigue-a"
+
+#: gitk:4810
+msgid "Precedes"
+msgstr "Precede-a"
+
+#: gitk:5093
+msgid "Error getting merge diffs:"
+msgstr "Error al leer las diferencias de fusión:"
+
+#: gitk:5778
+msgid "Goto:"
+msgstr "Ir a:"
+
+#: gitk:5780
+msgid "SHA1 ID:"
+msgstr "SHA1 ID:"
+
+#: gitk:5805
+#, tcl-format
+msgid "Short SHA1 id %s is ambiguous"
+msgstr "La id SHA1 abreviada %s es ambigua"
+
+#: gitk:5817
+#, tcl-format
+msgid "SHA1 id %s is not known"
+msgstr "La id SHA1 %s es desconocida"
+
+#: gitk:5819
+#, tcl-format
+msgid "Tag/Head %s is not known"
+msgstr "La etiqueta/rama %s es deconocida"
+
+#: gitk:5961
+msgid "Children"
+msgstr "Hijas"
+
+#: gitk:6018
+#, tcl-format
+msgid "Reset %s branch to here"
+msgstr "Poner la rama %s en esta revisión"
+
+#: gitk:6049
+msgid "Top"
+msgstr "Origen"
+
+#: gitk:6050
+msgid "From"
+msgstr "De"
+
+#: gitk:6055
+msgid "To"
+msgstr "A"
+
+#: gitk:6078
+msgid "Generate patch"
+msgstr "Generar parche"
+
+#: gitk:6080
+msgid "From:"
+msgstr "De:"
+
+#: gitk:6089
+msgid "To:"
+msgstr "Para:"
+
+#: gitk:6098
+msgid "Reverse"
+msgstr "Invertir"
+
+#: gitk:6100 gitk:6269
+msgid "Output file:"
+msgstr "Escribir a archivo:"
+
+#: gitk:6106
+msgid "Generate"
+msgstr "Generar"
+
+#: gitk:6142
+msgid "Error creating patch:"
+msgstr "Error en la creación del parche:"
+
+#: gitk:6164 gitk:6257 gitk:6311
+msgid "ID:"
+msgstr "ID:"
+
+#: gitk:6173
+msgid "Tag name:"
+msgstr "Nombre de etiqueta:"
+
+#: gitk:6177 gitk:6320
+msgid "Create"
+msgstr "Crear"
+
+#: gitk:6192
+msgid "No tag name specified"
+msgstr "No se ha especificado etiqueta"
+
+#: gitk:6196
+#, tcl-format
+msgid "Tag \"%s\" already exists"
+msgstr "La etiqueta \"%s\" ya existe"
+
+#: gitk:6202
+msgid "Error creating tag:"
+msgstr "Error al crear la etiqueta:"
+
+#: gitk:6266
+msgid "Command:"
+msgstr "Comando:"
+
+#: gitk:6274
+msgid "Write"
+msgstr "Escribir"
+
+#: gitk:6290
+msgid "Error writing commit:"
+msgstr "Error al escribir revisión:"
+
+#: gitk:6316
+msgid "Name:"
+msgstr "Nombre:"
+
+#: gitk:6335
+msgid "Please specify a name for the new branch"
+msgstr "Especifique un nombre para la nueva rama"
+
+#: gitk:6364
+#, tcl-format
+msgid "Commit %s is already included in branch %s -- really re-apply it?"
+msgstr "La revisión %s ya está incluida en la rama %s -- ¿Volver a aplicarla?"
+
+#: gitk:6369
+msgid "Cherry-picking"
+msgstr "Eligiendo revisiones (cherry-picking)"
+
+#: gitk:6381
+msgid "No changes committed"
+msgstr "No se han guardado cambios"
+
+#: gitk:6404
+msgid "Confirm reset"
+msgstr "Confirmar git reset"
+
+#: gitk:6406
+#, tcl-format
+msgid "Reset branch %s to %s?"
+msgstr "¿Reponer la rama %s a %s?"
+
+#: gitk:6410
+msgid "Reset type:"
+msgstr "Tipo de reposición:"
+
+#: gitk:6414
+msgid "Soft: Leave working tree and index untouched"
+msgstr "Suave: No altera la copia de trabajo ni el índice"
+
+#: gitk:6417
+msgid "Mixed: Leave working tree untouched, reset index"
+msgstr "Mixta: Actualiza el índice, no altera la copia de trabajo"
+
+#: gitk:6420
+msgid ""
+"Hard: Reset working tree and index\n"
+"(discard ALL local changes)"
+msgstr ""
+"Dura: Actualiza el índice y la copia de trabajo\n"
+"(abandona TODAS las modificaciones locales)"
+
+#: gitk:6436
+msgid "Resetting"
+msgstr "Reponiendo"
+
+#: gitk:6493
+msgid "Checking out"
+msgstr "Creando copia de trabajo"
+
+#: gitk:6523
+msgid "Cannot delete the currently checked-out branch"
+msgstr "No se puede borrar la rama actual"
+
+#: gitk:6529
+#, tcl-format
+msgid ""
+"The commits on branch %s aren't on any other branch.\n"
+"Really delete branch %s?"
+msgstr ""
+"Las revisiones de la rama %s no están presentes en otras ramas.\n"
+"¿Borrar la rama %s?"
+
+#: gitk:6560
+#, tcl-format
+msgid "Tags and heads: %s"
+msgstr "Etiquetas y ramas: %s"
+
+#: gitk:6574
+msgid "Filter"
+msgstr "Filtro"
+
+#: gitk:6868
+msgid ""
+"Error reading commit topology information; branch and preceding/following "
+"tag information will be incomplete."
+msgstr ""
+"Error al leer la topología de revisiones: la información sobre "
+"las ramas y etiquetas precedentes y siguientes será incompleta."
+
+#: gitk:7852
+msgid "Tag"
+msgstr "Etiqueta"
+
+#: gitk:7852
+msgid "Id"
+msgstr "Id"
+
+#: gitk:7892
+msgid "Gitk font chooser"
+msgstr "Selector de tipografías gitk"
+
+#: gitk:7909
+msgid "B"
+msgstr "B"
+
+#: gitk:7912
+msgid "I"
+msgstr "I"
+
+#: gitk:8005
+msgid "Gitk preferences"
+msgstr "Preferencias de gitk"
+
+#: gitk:8006
+msgid "Commit list display options"
+msgstr "Opciones de visualización de la lista de revisiones"
+
+#: gitk:8009
+msgid "Maximum graph width (lines)"
+msgstr "Ancho máximo del gráfico (en líneas)"
+
+#: gitk:8013
+#, tcl-format
+msgid "Maximum graph width (% of pane)"
+msgstr "Ancho máximo del gráfico (en % del panel)"
+
+#: gitk:8018
+msgid "Show local changes"
+msgstr "Mostrar cambios locales"
+
+#: gitk:8023
+msgid "Auto-select SHA1"
+msgstr "Seleccionar automáticamente SHA1 hash"
+
+#: gitk:8028
+msgid "Diff display options"
+msgstr "Opciones de visualización de diferencias"
+
+#: gitk:8030
+msgid "Tab spacing"
+msgstr "Espaciado de tabulador"
+
+#: gitk:8034
+msgid "Display nearby tags"
+msgstr "Mostrar etiquetas cercanas"
+
+#: gitk:8039
+msgid "Limit diffs to listed paths"
+msgstr "Limitar las diferencias a las rutas seleccionadas"
+
+#: gitk:8044
+msgid "Colors: press to choose"
+msgstr "Colores: pulse para seleccionar"
+
+#: gitk:8047
+msgid "Background"
+msgstr "Fondo"
+
+#: gitk:8051
+msgid "Foreground"
+msgstr "Primer plano"
+
+#: gitk:8055
+msgid "Diff: old lines"
+msgstr "Diff: líneas viejas"
+
+#: gitk:8060
+msgid "Diff: new lines"
+msgstr "Diff: líneas nuevas"
+
+#: gitk:8065
+msgid "Diff: hunk header"
+msgstr "Diff: cabecera de fragmento"
+
+#: gitk:8071
+msgid "Select bg"
+msgstr "Color de fondo de la selección"
+
+#: gitk:8075
+msgid "Fonts: press to choose"
+msgstr "Tipografías: pulse para elegir"
+
+#: gitk:8077
+msgid "Main font"
+msgstr "Tipografía principal"
+
+#: gitk:8078
+msgid "Diff display font"
+msgstr "Tipografía para diferencias"
+
+#: gitk:8079
+msgid "User interface font"
+msgstr "Tipografía para interfaz de usuario"
+
+#: gitk:8095
+#, tcl-format
+msgid "Gitk: choose color for %s"
+msgstr "Gitk: elegir color para %s"
+
+#: gitk:8476
+msgid ""
+"Sorry, gitk cannot run with this version of Tcl/Tk.\n"
+" Gitk requires at least Tcl/Tk 8.4."
+msgstr ""
+"Esta versión de Tcl/Tk es demasiado antigua.\n"
+" Gitk requiere Tcl/Tk versión 8.4 o superior."
+
+#: gitk:8565
+msgid "Cannot find a git repository here."
+msgstr "No hay un repositorio git aquí."
+
+#: gitk:8569
+#, tcl-format
+msgid "Cannot find the git directory \"%s\"."
+msgstr "No hay directorio git \"%s\"."
+
+#: gitk:8612
+#, tcl-format
+msgid "Ambiguous argument '%s': both revision and filename"
+msgstr "Argumento ambiguo: '%s' es tanto una revisión como un nombre de archivo"
+
+#: gitk:8624
+msgid "Bad arguments to gitk:"
+msgstr "Argumentos incorrectos a Gitk:"
+
+#: gitk:8636
+msgid "Couldn't get list of unmerged files:"
+msgstr "Imposible obtener la lista de archivos pendientes de fusión:"
+
+#: gitk:8652
+msgid "No files selected: --merge specified but no files are unmerged."
+msgstr ""
+"No hay archivos seleccionados: se seleccionó la opción --merge pero no hay "
+"archivos pendientes de fusión."
+
+#: gitk:8655
+msgid ""
+"No files selected: --merge specified but no unmerged files are within file "
+"limit."
+msgstr ""
+"No hay archivos seleccionados: se seleccionó la opción --merge pero los archivos "
+"especificados no necesitan fusión."
+
+#: gitk:8716
+msgid "Command line"
+msgstr "Línea de comandos"
diff --git a/gitk-git/po/sv.po b/gitk-git/po/sv.po
new file mode 100644
index 0000000..f6b080d
--- /dev/null
+++ b/gitk-git/po/sv.po
@@ -0,0 +1,887 @@
+# Swedish translation for gitk
+# Copyright (C) 2005-2008 Paul Mackerras
+# This file is distributed under the same license as the gitk package.
+#
+# Peter Karlsson <peter@softwolves.pp.se>, 2008.
+msgid ""
+msgstr ""
+"Project-Id-Version: sv\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-03-14 15:03+0100\n"
+"PO-Revision-Date: 2008-03-14 16:06CET-1\n"
+"Last-Translator: Peter Karlsson <peter@softwolves.pp.se>\n"
+"Language-Team: Swedish <sv@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit"
+
+#: gitk:111
+msgid "Error executing git rev-list:"
+msgstr "Fel vid körning av git rev-list:"
+
+#: gitk:124
+msgid "Reading"
+msgstr "Läser"
+
+#: gitk:151 gitk:2191
+msgid "Reading commits..."
+msgstr "Läser incheckningar..."
+
+#: gitk:275
+msgid "Can't parse git log output:"
+msgstr "Kan inte tolka utdata från git log:"
+
+#: gitk:386 gitk:2195
+msgid "No commits selected"
+msgstr "Inga incheckningar markerade"
+
+#: gitk:500
+msgid "No commit information available"
+msgstr "Ingen incheckningsinformation är tillgänglig"
+
+#: gitk:599 gitk:621 gitk:1955 gitk:6423 gitk:7923 gitk:8082
+msgid "OK"
+msgstr "OK"
+
+#: gitk:623 gitk:1956 gitk:6107 gitk:6178 gitk:6275 gitk:6321 gitk:6425
+#: gitk:7924 gitk:8083
+msgid "Cancel"
+msgstr "Avbryt"
+
+#: gitk:661
+msgid "File"
+msgstr "Arkiv"
+
+#: gitk:663
+msgid "Update"
+msgstr "Uppdatera"
+
+#: gitk:664
+msgid "Reread references"
+msgstr "Läs om referenser"
+
+#: gitk:665
+msgid "List references"
+msgstr "Visa referenser"
+
+#: gitk:666
+msgid "Quit"
+msgstr "Avsluta"
+
+#: gitk:668
+msgid "Edit"
+msgstr "Redigera"
+
+#: gitk:669
+msgid "Preferences"
+msgstr "Inställningar"
+
+#: gitk:672 gitk:1892
+msgid "View"
+msgstr "Visa"
+
+#: gitk:673
+msgid "New view..."
+msgstr "Ny vy..."
+
+#: gitk:674 gitk:2133 gitk:8722
+msgid "Edit view..."
+msgstr "Ändra vy..."
+
+#: gitk:676 gitk:2134 gitk:8723
+msgid "Delete view"
+msgstr "Ta bort vy"
+
+#: gitk:678
+msgid "All files"
+msgstr "Alla filer"
+
+#: gitk:682
+msgid "Help"
+msgstr "Hjälp"
+
+#: gitk:683 gitk:1317
+msgid "About gitk"
+msgstr "Om gitk"
+
+#: gitk:684
+msgid "Key bindings"
+msgstr "Tangentbordsbindningar"
+
+#: gitk:741
+msgid "SHA1 ID: "
+msgstr "SHA1-id: "
+
+#: gitk:791
+msgid "Find"
+msgstr "Sök"
+
+#: gitk:792
+msgid "next"
+msgstr "nästa"
+
+#: gitk:793
+msgid "prev"
+msgstr "föreg"
+
+#: gitk:794
+msgid "commit"
+msgstr "incheckning"
+
+#: gitk:797 gitk:799 gitk:2356 gitk:2379 gitk:2403 gitk:4306 gitk:4369
+msgid "containing:"
+msgstr "som innehåller:"
+
+#: gitk:800 gitk:1778 gitk:1783 gitk:2431
+msgid "touching paths:"
+msgstr "som rör sökväg:"
+
+#: gitk:801 gitk:2436
+msgid "adding/removing string:"
+msgstr "som lägger/till tar bort sträng:"
+
+#: gitk:810 gitk:812
+msgid "Exact"
+msgstr "Exakt"
+
+#: gitk:812 gitk:2514 gitk:4274
+msgid "IgnCase"
+msgstr "IgnVersaler"
+
+#: gitk:812 gitk:2405 gitk:2512 gitk:4270
+msgid "Regexp"
+msgstr "Reg.uttr."
+
+#: gitk:814 gitk:815 gitk:2533 gitk:2563 gitk:2570 gitk:4380 gitk:4436
+msgid "All fields"
+msgstr "Alla fält"
+
+#: gitk:815 gitk:2531 gitk:2563 gitk:4336
+msgid "Headline"
+msgstr "Rubrik"
+
+#: gitk:816 gitk:2531 gitk:4336 gitk:4436 gitk:4827
+msgid "Comments"
+msgstr "Kommentarer"
+
+#: gitk:816 gitk:2531 gitk:2535 gitk:2570 gitk:4336 gitk:4763 gitk:5956
+#: gitk:5971
+msgid "Author"
+msgstr "Författare"
+
+#: gitk:816 gitk:2531 gitk:4336 gitk:4765
+msgid "Committer"
+msgstr "Incheckare"
+
+#: gitk:845
+msgid "Search"
+msgstr "Sök"
+
+#: gitk:852
+msgid "Diff"
+msgstr "Diff"
+
+#: gitk:854
+msgid "Old version"
+msgstr "Gammal version"
+
+#: gitk:856
+msgid "New version"
+msgstr "Ny version"
+
+#: gitk:858
+msgid "Lines of context"
+msgstr "Rader sammanhang"
+
+#: gitk:868
+msgid "Ignore space change"
+msgstr "Ignorera ändringar i blanksteg"
+
+#: gitk:926
+msgid "Patch"
+msgstr "Patch"
+
+#: gitk:928
+msgid "Tree"
+msgstr "Träd"
+
+#: gitk:1053 gitk:1068 gitk:6022
+msgid "Diff this -> selected"
+msgstr "Diff denna -> markerad"
+
+#: gitk:1055 gitk:1070 gitk:6023
+msgid "Diff selected -> this"
+msgstr "Diff markerad -> denna"
+
+#: gitk:1057 gitk:1072 gitk:6024
+msgid "Make patch"
+msgstr "Skapa patch"
+
+#: gitk:1058 gitk:6162
+msgid "Create tag"
+msgstr "Skapa tagg"
+
+#: gitk:1059 gitk:6255
+msgid "Write commit to file"
+msgstr "Skriv incheckning till fil"
+
+#: gitk:1060 gitk:6309
+msgid "Create new branch"
+msgstr "Skapa ny gren"
+
+#: gitk:1061
+msgid "Cherry-pick this commit"
+msgstr "Plocka denna incheckning"
+
+#: gitk:1063
+msgid "Reset HEAD branch to here"
+msgstr "Återställ HEAD-grenen hit"
+
+#: gitk:1079
+msgid "Check out this branch"
+msgstr "Checka ut denna gren"
+
+#: gitk:1081
+msgid "Remove this branch"
+msgstr "Ta bort denna gren"
+
+#: gitk:1087
+msgid "Highlight this too"
+msgstr "Markera även detta"
+
+#: gitk:1089
+msgid "Highlight this only"
+msgstr "Markera bara detta"
+
+#: gitk:1318
+msgid ""
+"\n"
+"Gitk - a commit viewer for git\n"
+"\n"
+"Copyright © 2005-2006 Paul Mackerras\n"
+"\n"
+"Use and redistribute under the terms of the GNU General Public License"
+msgstr ""
+"\n"
+"Gitk - en incheckningsvisare för git\n"
+"\n"
+"Copyright © 2005-2006 Paul Mackerras\n"
+"\n"
+"Använd och vidareförmedla enligt villkoren i GNU General Public License"
+
+#: gitk:1326 gitk:1387 gitk:6581
+msgid "Close"
+msgstr "Stäng"
+
+#: gitk:1345
+msgid "Gitk key bindings"
+msgstr "Tangentbordsbindningar för Gitk"
+
+#: gitk:1347
+msgid "Gitk key bindings:"
+msgstr "Tangentbordsbindningar för Gitk:"
+
+#: gitk:1349
+#, tcl-format
+msgid "<%s-Q>\t\tQuit"
+msgstr "<%s-Q>\t\tAvsluta"
+
+#: gitk:1350
+msgid "<Home>\t\tMove to first commit"
+msgstr "<Home>\t\tGå till första incheckning"
+
+#: gitk:1351
+msgid "<End>\t\tMove to last commit"
+msgstr "<End>\t\tGå till sista incheckning"
+
+#: gitk:1352
+msgid "<Up>, p, i\tMove up one commit"
+msgstr "<Upp>, p, i\tGå en incheckning upp"
+
+#: gitk:1353
+msgid "<Down>, n, k\tMove down one commit"
+msgstr "<Ned>, n, k\tGå en incheckning ned"
+
+#: gitk:1354
+msgid "<Left>, z, j\tGo back in history list"
+msgstr "<Vänster>, z, j\tGå bakåt i historiken"
+
+#: gitk:1355
+msgid "<Right>, x, l\tGo forward in history list"
+msgstr "<Höger>, x, l\tGå framåt i historiken"
+
+#: gitk:1356
+msgid "<PageUp>\tMove up one page in commit list"
+msgstr "<PageUp>\tGå upp en sida i incheckningslistan"
+
+#: gitk:1357
+msgid "<PageDown>\tMove down one page in commit list"
+msgstr "<PageDown>\tGå ned en sida i incheckningslistan"
+
+#: gitk:1358
+#, tcl-format
+msgid "<%s-Home>\tScroll to top of commit list"
+msgstr "<%s-Home>\tRulla till början av incheckningslistan"
+
+#: gitk:1359
+#, tcl-format
+msgid "<%s-End>\tScroll to bottom of commit list"
+msgstr "<%s-End>\tRulla till slutet av incheckningslistan"
+
+#: gitk:1360
+#, tcl-format
+msgid "<%s-Up>\tScroll commit list up one line"
+msgstr "<%s-Upp>\tRulla incheckningslistan upp ett steg"
+
+#: gitk:1361
+#, tcl-format
+msgid "<%s-Down>\tScroll commit list down one line"
+msgstr "<%s-Ned>\tRulla incheckningslistan ned ett steg"
+
+#: gitk:1362
+#, tcl-format
+msgid "<%s-PageUp>\tScroll commit list up one page"
+msgstr "<%s-PageUp>\tRulla incheckningslistan upp en sida"
+
+#: gitk:1363
+#, tcl-format
+msgid "<%s-PageDown>\tScroll commit list down one page"
+msgstr "<%s-PageDown>\tRulla incheckningslistan ned en sida"
+
+#: gitk:1364
+msgid "<Shift-Up>\tFind backwards (upwards, later commits)"
+msgstr "<Skift-Upp>\tSök bakåt (uppåt, senare incheckningar)"
+
+#: gitk:1365
+msgid "<Shift-Down>\tFind forwards (downwards, earlier commits)"
+msgstr "<Skift-Ned>\tSök framåt (nedåt, tidigare incheckningar)"
+
+#: gitk:1366
+msgid "<Delete>, b\tScroll diff view up one page"
+msgstr "<Delete>, b\tRulla diffvisningen upp en sida"
+
+#: gitk:1367
+msgid "<Backspace>\tScroll diff view up one page"
+msgstr "<Baksteg>\tRulla diffvisningen upp en sida"
+
+#: gitk:1368
+msgid "<Space>\t\tScroll diff view down one page"
+msgstr "<Blanksteg>\tRulla diffvisningen ned en sida"
+
+#: gitk:1369
+msgid "u\t\tScroll diff view up 18 lines"
+msgstr "u\t\tRulla diffvisningen upp 18 rader"
+
+#: gitk:1370
+msgid "d\t\tScroll diff view down 18 lines"
+msgstr "d\t\tRulla diffvisningen ned 18 rader"
+
+#: gitk:1371
+#, tcl-format
+msgid "<%s-F>\t\tFind"
+msgstr "<%s-F>\t\tSök"
+
+#: gitk:1372
+#, tcl-format
+msgid "<%s-G>\t\tMove to next find hit"
+msgstr "<%s-G>\t\tGå till nästa sökträff"
+
+#: gitk:1373
+msgid "<Return>\tMove to next find hit"
+msgstr "<Return>\t\tGå till nästa sökträff"
+
+#: gitk:1374
+msgid "/\t\tMove to next find hit, or redo find"
+msgstr "/\t\tGå till nästa sökträff, eller sök på nytt"
+
+#: gitk:1375
+msgid "?\t\tMove to previous find hit"
+msgstr "?\t\tGå till föregående sökträff"
+
+#: gitk:1376
+msgid "f\t\tScroll diff view to next file"
+msgstr "f\t\tRulla diffvisningen till nästa fil"
+
+#: gitk:1377
+#, tcl-format
+msgid "<%s-S>\t\tSearch for next hit in diff view"
+msgstr "<%s-S>\t\tGå till nästa sökträff i diffvisningen"
+
+#: gitk:1378
+#, tcl-format
+msgid "<%s-R>\t\tSearch for previous hit in diff view"
+msgstr "<%s-R>\t\tGå till föregående sökträff i diffvisningen"
+
+#: gitk:1379
+#, tcl-format
+msgid "<%s-KP+>\tIncrease font size"
+msgstr "<%s-Num+>\tÖka teckenstorlek"
+
+#: gitk:1380
+#, tcl-format
+msgid "<%s-plus>\tIncrease font size"
+msgstr "<%s-plus>\tÖka teckenstorlek"
+
+#: gitk:1381
+#, tcl-format
+msgid "<%s-KP->\tDecrease font size"
+msgstr "<%s-Num->\tMinska teckenstorlek"
+
+#: gitk:1382
+#, tcl-format
+msgid "<%s-minus>\tDecrease font size"
+msgstr "<%s-minus>\tMinska teckenstorlek"
+
+#: gitk:1383
+msgid "<F5>\t\tUpdate"
+msgstr "<F5>\t\tUppdatera"
+
+#: gitk:1896
+msgid "Gitk view definition"
+msgstr "Definition av Gitk-vy"
+
+#: gitk:1921
+msgid "Name"
+msgstr "Namn"
+
+#: gitk:1924
+msgid "Remember this view"
+msgstr "Spara denna vy"
+
+#: gitk:1928
+msgid "Commits to include (arguments to git rev-list):"
+msgstr "Incheckningar att ta med (argument till git rev-list):"
+
+#: gitk:1935
+msgid "Command to generate more commits to include:"
+msgstr "Kommando för att generera fler incheckningar att ta med:"
+
+#: gitk:1942
+msgid "Enter files and directories to include, one per line:"
+msgstr "Ange filer och kataloger att ta med, en per rad:"
+
+#: gitk:1989
+msgid "Error in commit selection arguments:"
+msgstr "Fel i argument för val av incheckningar:"
+
+#: gitk:2043 gitk:2127 gitk:2583 gitk:2597 gitk:3781 gitk:8688 gitk:8689
+msgid "None"
+msgstr "Inget"
+
+#: gitk:2531 gitk:4336 gitk:5958 gitk:5973
+msgid "Date"
+msgstr "Datum"
+
+#: gitk:2531 gitk:4336
+msgid "CDate"
+msgstr "Skapat datum"
+
+#: gitk:2680 gitk:2685
+msgid "Descendant"
+msgstr "Avkomling"
+
+#: gitk:2681
+msgid "Not descendant"
+msgstr "Inte avkomling"
+
+#: gitk:2688 gitk:2693
+msgid "Ancestor"
+msgstr "Förfader"
+
+#: gitk:2689
+msgid "Not ancestor"
+msgstr "Inte förfader"
+
+#: gitk:2924
+msgid "Local changes checked in to index but not committed"
+msgstr "Lokala ändringar sparade i indexet men inte incheckade"
+
+#: gitk:2954
+msgid "Local uncommitted changes, not checked in to index"
+msgstr "Lokala ändringar, ej sparade i indexet"
+
+#: gitk:4305
+msgid "Searching"
+msgstr "Söker"
+
+#: gitk:4767
+msgid "Tags:"
+msgstr "Taggar:"
+
+#: gitk:4784 gitk:4790 gitk:5951
+msgid "Parent"
+msgstr "Förälder"
+
+#: gitk:4795
+msgid "Child"
+msgstr "Barn"
+
+#: gitk:4804
+msgid "Branch"
+msgstr "Gren"
+
+#: gitk:4807
+msgid "Follows"
+msgstr "Följer"
+
+#: gitk:4810
+msgid "Precedes"
+msgstr "Föregår"
+
+#: gitk:5093
+msgid "Error getting merge diffs:"
+msgstr "Fel vid hämtning av sammanslagningsdiff:"
+
+#: gitk:5778
+msgid "Goto:"
+msgstr "Gå till:"
+
+#: gitk:5780
+msgid "SHA1 ID:"
+msgstr "SHA1-id:"
+
+#: gitk:5805
+#, tcl-format
+msgid "Short SHA1 id %s is ambiguous"
+msgstr "Förkortat SHA1-id %s är tvetydigt"
+
+#: gitk:5817
+#, tcl-format
+msgid "SHA1 id %s is not known"
+msgstr "SHA-id:t %s är inte känt"
+
+#: gitk:5819
+#, tcl-format
+msgid "Tag/Head %s is not known"
+msgstr "Tagg/huvud %s är okänt"
+
+#: gitk:5961
+msgid "Children"
+msgstr "Barn"
+
+#: gitk:6018
+#, tcl-format
+msgid "Reset %s branch to here"
+msgstr "Återställ grenen %s hit"
+
+#: gitk:6049
+msgid "Top"
+msgstr "Topp"
+
+#: gitk:6050
+msgid "From"
+msgstr "Från"
+
+#: gitk:6055
+msgid "To"
+msgstr "Till"
+
+#: gitk:6078
+msgid "Generate patch"
+msgstr "Generera patch"
+
+#: gitk:6080
+msgid "From:"
+msgstr "Från:"
+
+#: gitk:6089
+msgid "To:"
+msgstr "Till:"
+
+#: gitk:6098
+msgid "Reverse"
+msgstr "Vänd"
+
+#: gitk:6100 gitk:6269
+msgid "Output file:"
+msgstr "Utdatafil:"
+
+#: gitk:6106
+msgid "Generate"
+msgstr "Generera"
+
+#: gitk:6142
+msgid "Error creating patch:"
+msgstr "Fel vid generering av patch:"
+
+#: gitk:6164 gitk:6257 gitk:6311
+msgid "ID:"
+msgstr "Id:"
+
+#: gitk:6173
+msgid "Tag name:"
+msgstr "Taggnamn:"
+
+#: gitk:6177 gitk:6320
+msgid "Create"
+msgstr "Skapa"
+
+#: gitk:6192
+msgid "No tag name specified"
+msgstr "Inget taggnamn angavs"
+
+#: gitk:6196
+#, tcl-format
+msgid "Tag \"%s\" already exists"
+msgstr "Taggen \"%s\" finns redan"
+
+#: gitk:6202
+msgid "Error creating tag:"
+msgstr "Fel vid skapande av tagg:"
+
+#: gitk:6266
+msgid "Command:"
+msgstr "Kommando:"
+
+#: gitk:6274
+msgid "Write"
+msgstr "Skriv"
+
+#: gitk:6290
+msgid "Error writing commit:"
+msgstr "Fel vid skrivning av incheckning:"
+
+#: gitk:6316
+msgid "Name:"
+msgstr "Namn:"
+
+#: gitk:6335
+msgid "Please specify a name for the new branch"
+msgstr "Ange ett namn för den nya grenen"
+
+#: gitk:6364
+#, tcl-format
+msgid "Commit %s is already included in branch %s -- really re-apply it?"
+msgstr "Incheckningen %s finns redan på grenen %s -- skall den verkligen appliceras på nytt?"
+
+#: gitk:6369
+msgid "Cherry-picking"
+msgstr "Plockar"
+
+#: gitk:6381
+msgid "No changes committed"
+msgstr "Inga ändringar incheckade"
+
+#: gitk:6404
+msgid "Confirm reset"
+msgstr "Bekräfta återställning"
+
+#: gitk:6406
+#, tcl-format
+msgid "Reset branch %s to %s?"
+msgstr "Återställa grenen %s till %s?"
+
+#: gitk:6410
+msgid "Reset type:"
+msgstr "Typ av återställning:"
+
+#: gitk:6414
+msgid "Soft: Leave working tree and index untouched"
+msgstr "Mjuk: Rör inte utcheckning och index"
+
+#: gitk:6417
+msgid "Mixed: Leave working tree untouched, reset index"
+msgstr "Blandad: Rör inte utcheckning, återställ index"
+
+#: gitk:6420
+msgid ""
+"Hard: Reset working tree and index\n"
+"(discard ALL local changes)"
+msgstr ""
+"Hård: Återställ utcheckning och index\n"
+"(förkastar ALLA lokala ändringar)"
+
+#: gitk:6436
+msgid "Resetting"
+msgstr "Återställer"
+
+#: gitk:6493
+msgid "Checking out"
+msgstr "Checkar ut"
+
+#: gitk:6523
+msgid "Cannot delete the currently checked-out branch"
+msgstr "Kan inte ta bort den just nu utcheckade grenen"
+
+#: gitk:6529
+#, tcl-format
+msgid ""
+"The commits on branch %s aren't on any other branch.\n"
+"Really delete branch %s?"
+msgstr ""
+"Incheckningarna på grenen %s existerar inte på någon annan gren.\n"
+"Vill du verkligen ta bort grenen %s?"
+
+#: gitk:6560
+#, tcl-format
+msgid "Tags and heads: %s"
+msgstr "Taggar och huvuden: %s"
+
+#: gitk:6574
+msgid "Filter"
+msgstr "Filter"
+
+#: gitk:6868
+msgid ""
+"Error reading commit topology information; branch and preceding/following "
+"tag information will be incomplete."
+msgstr ""
+"Fel vid läsning av information om incheckningstopologi; information om "
+"grenar och föregående/senare taggar kommer inte vara komplett."
+
+#: gitk:7852
+msgid "Tag"
+msgstr "Tagg"
+
+#: gitk:7852
+msgid "Id"
+msgstr "Id"
+
+#: gitk:7892
+msgid "Gitk font chooser"
+msgstr "Teckensnittsväljare för Gitk"
+
+#: gitk:7909
+msgid "B"
+msgstr "F"
+
+#: gitk:7912
+msgid "I"
+msgstr "K"
+
+#: gitk:8005
+msgid "Gitk preferences"
+msgstr "Inställningar för Gitk"
+
+#: gitk:8006
+msgid "Commit list display options"
+msgstr "Alternativ för incheckningslistvy"
+
+#: gitk:8009
+msgid "Maximum graph width (lines)"
+msgstr "Maximal grafbredd (rader)"
+
+#: gitk:8013
+#, tcl-format
+msgid "Maximum graph width (% of pane)"
+msgstr "Maximal grafbredd (% av ruta)"
+
+#: gitk:8018
+msgid "Show local changes"
+msgstr "Visa lokala ändringar"
+
+#: gitk:8023
+msgid "Auto-select SHA1"
+msgstr "Välj SHA1 automatiskt"
+
+#: gitk:8028
+msgid "Diff display options"
+msgstr "Alternativ för diffvy"
+
+#: gitk:8030
+msgid "Tab spacing"
+msgstr "Blanksteg för tabulatortecken"
+
+#: gitk:8034
+msgid "Display nearby tags"
+msgstr "Visa närliggande taggar"
+
+#: gitk:8039
+msgid "Limit diffs to listed paths"
+msgstr "Begränsa diff till listade sökvägar"
+
+#: gitk:8044
+msgid "Colors: press to choose"
+msgstr "Färger: tryck för att välja"
+
+#: gitk:8047
+msgid "Background"
+msgstr "Bakgrund"
+
+#: gitk:8051
+msgid "Foreground"
+msgstr "Förgrund"
+
+#: gitk:8055
+msgid "Diff: old lines"
+msgstr "Diff: gamla rader"
+
+#: gitk:8060
+msgid "Diff: new lines"
+msgstr "Diff: nya rader"
+
+#: gitk:8065
+msgid "Diff: hunk header"
+msgstr "Diff: delhuvud"
+
+#: gitk:8071
+msgid "Select bg"
+msgstr "Markerad bakgrund"
+
+#: gitk:8075
+msgid "Fonts: press to choose"
+msgstr "Teckensnitt: tryck för att välja"
+
+#: gitk:8077
+msgid "Main font"
+msgstr "Huvudteckensnitt"
+
+#: gitk:8078
+msgid "Diff display font"
+msgstr "Teckensnitt för diffvisning"
+
+#: gitk:8079
+msgid "User interface font"
+msgstr "Teckensnitt för användargränssnitt"
+
+#: gitk:8095
+#, tcl-format
+msgid "Gitk: choose color for %s"
+msgstr "Gitk: välj färg för %s"
+
+#: gitk:8476
+msgid ""
+"Sorry, gitk cannot run with this version of Tcl/Tk.\n"
+" Gitk requires at least Tcl/Tk 8.4."
+msgstr ""
+"Gitk kan tyvärr inte köra med denna version av Tcl/Tk.\n"
+" Gitk kräver åtminstone Tcl/Tk 8.4."
+
+#: gitk:8565
+msgid "Cannot find a git repository here."
+msgstr "Hittar inget gitk-arkiv här."
+
+#: gitk:8569
+#, tcl-format
+msgid "Cannot find the git directory \"%s\"."
+msgstr "Hittar inte git-katalogen \"%s\"."
+
+#: gitk:8612
+#, tcl-format
+msgid "Ambiguous argument '%s': both revision and filename"
+msgstr "Tvetydigt argument \"%s\": både revision och filnamn"
+
+#: gitk:8624
+msgid "Bad arguments to gitk:"
+msgstr "Felaktiga argument till gitk:"
+
+#: gitk:8636
+msgid "Couldn't get list of unmerged files:"
+msgstr "Kunde inta hämta lista över ej sammanslagna filer:"
+
+#: gitk:8652
+msgid "No files selected: --merge specified but no files are unmerged."
+msgstr "Inga filer valdes: --merge angavs men det finns inga filer som inte har slagits samman."
+
+#: gitk:8655
+msgid ""
+"No files selected: --merge specified but no unmerged files are within file "
+"limit."
+msgstr ""
+"Inga filer valdes: --merge angavs men det finns inga filer inom "
+"filbegränsningen."
+
+#: gitk:8716
+msgid "Command line"
+msgstr "Kommandorad"
+
diff --git a/gitweb/INSTALL b/gitweb/INSTALL
index 9cd5b0a..f7194db 100644
--- a/gitweb/INSTALL
+++ b/gitweb/INSTALL
@@ -29,40 +29,40 @@
 See also "How to configure gitweb for your local system" in README
 file for gitweb (in gitweb/README).
 
-- There are many configuration variables which affects building of
+- There are many configuration variables which affect building of
   gitweb.cgi; see "default configuration for gitweb" section in main
   (top dir) Makefile, and instructions for building gitweb/gitweb.cgi
   target.
 
-  One of most important is where to find git wrapper binary. Gitweb
-  tries to find git wrapper at $(bindir)/git, so you have to set $bindir
+  One of the most important is where to find the git wrapper binary. Gitweb
+  tries to find the git wrapper at $(bindir)/git, so you have to set $bindir
   when building gitweb.cgi, or $prefix from which $bindir is derived. If
-  you build and install gitweb together with the rest of git suite,
+  you build and install gitweb together with the rest of the git suite,
   there should be no problems. Otherwise, if git was for example
   installed from a binary package, you have to set $prefix (or $bindir)
   accordingly.
 
 - Another important issue is where are git repositories you want to make
-  available to gitweb. By default gitweb search for repositories under
+  available to gitweb. By default gitweb searches for repositories under
   /pub/git; if you want to have projects somewhere else, like /home/git,
   use GITWEB_PROJECTROOT build configuration variable.
 
   By default all git repositories under projectroot are visible and
-  available to gitweb. List of projects is generated by default by
+  available to gitweb. The list of projects is generated by default by
   scanning the projectroot directory for git repositories. This can be
   changed (configured) as described in "Gitweb repositories" section
   below.
 
-  Note that gitweb deals directly with object database, and does not
-  need working directory; the name of the project is the name of its
+  Note that gitweb deals directly with the object database, and does not
+  need a working directory; the name of the project is the name of its
   repository object database, usually projectname.git for bare
   repositories. If you want to provide gitweb access to non-bare (live)
-  repository, you can make projectname.git symbolic link under
+  repositories, you can make projectname.git a symbolic link under
   projectroot linking to projectname/.git (but it is just
   a suggestion).
 
 - You can control where gitweb tries to find its main CSS style file,
-  its favicon and logo with GITWEB_CSS, GITWEB_FAVICON and GITWEB_LOGO
+  its favicon and logo with the GITWEB_CSS, GITWEB_FAVICON and GITWEB_LOGO
   build configuration variables. By default gitweb tries to find them
   in the same directory as gitweb.cgi script.
 
@@ -91,13 +91,17 @@
 See also "Runtime gitweb configuration" section in README file
 for gitweb (in gitweb/README).
 
-- You can configure gitweb further using gitweb configuration file;
-  by default it is file named gitweb_config.perl in the same place as
-  gitweb.cgi script. You can control default place for config file
-  using GITWEB_CONFIG build configuration variable, and you can set it
-  using GITWEB_CONFIG environmental variable.
+- You can configure gitweb further using the gitweb configuration file;
+  by default this is a file named gitweb_config.perl in the same place as
+  gitweb.cgi script. You can control the default place for the config file
+  using the GITWEB_CONFIG build configuration variable, and you can set it
+  using the GITWEB_CONFIG environment variable. If this file does not
+  exist, gitweb looks for a system-wide configuration file, normally
+  /etc/gitweb.conf. You can change the default using the
+  GITWEB_CONFIG_SYSTEM build configuration variable, and override it
+  through the GITWEB_CONFIG_SYSTEM environment variable.
 
-- Gitweb config file is [fragment] of perl code. You can set variables
+- The gitweb config file is a fragment of perl code. You can set variables
   using "our $variable = value"; text from "#" character until the end
   of a line is ignored. See perlsyn(1) for details.
 
@@ -124,36 +128,37 @@
 -------------------
 
 - By default all git repositories under projectroot are visible and
-  available to gitweb. List of projects is generated by default by
+  available to gitweb. The list of projects is generated by default by
   scanning the projectroot directory for git repositories (for object
   databases to be more exact).
 
-  You can provide pre-generated list of [visible] repositories,
+  You can provide a pre-generated list of [visible] repositories,
   together with information about their owners (the project ownership
-  is taken from owner of repository directory otherwise), by setting
-  GITWEB_LIST build configuration variable (or $projects_list variable
-  in gitweb config file) to point to a plain file.
+  defaults to the owner of the repository directory otherwise), by setting
+  the GITWEB_LIST build configuration variable (or the $projects_list
+  variable in the gitweb config file) to point to a plain file.
 
-  Each line of projects list file should consist of url-encoded path
-  to project repository database (relative to projectroot) separated
-  by space from url-encoded project owner; spaces in both project path
-  and project owner have to be encoded as either '%20' or '+'.
+  Each line of the projects list file should consist of the url-encoded path
+  to the project repository database (relative to projectroot), followed
+  by the url-encoded project owner on the same line (separated by a space).
+  Spaces in both project path and project owner have to be encoded as either
+  '%20' or '+'.
 
-  You can generate projects list index file using project_index action
-  (the 'TXT' link on projects list page) directly from gitweb.
+  You can generate the projects list index file using the project_index
+  action (the 'TXT' link on projects list page) directly from gitweb.
 
-- By default even if project is not visible on projects list page, you
-  can view it nevertheless by hand-crafting gitweb URL. You can set
-  GITWEB_STRICT_EXPORT build configuration variable (or $strict_export
-  variable in gitweb config file) to only allow viewing of
+- By default, even if a project is not visible on projects list page, you
+  can view it nevertheless by hand-crafting a gitweb URL. You can set the
+  GITWEB_STRICT_EXPORT build configuration variable (or the $strict_export
+  variable in the gitweb config file) to only allow viewing of
   repositories also shown on the overview page.
 
 - Alternatively, you can configure gitweb to only list and allow
-  viewing of the explicitly exported repositories, via
-  GITWEB_EXPORT_OK build configuration variable (or $export_ok
+  viewing of the explicitly exported repositories, via the
+  GITWEB_EXPORT_OK build configuration variable (or the $export_ok
   variable in gitweb config file). If it evaluates to true, gitweb
-  show repository only if this file exists in its object database
-  (if directory has the magic file $export_ok).
+  shows repositories only if this file exists in its object database
+  (if directory has the magic file named $export_ok).
 
 Generating projects list using gitweb
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/gitweb/README b/gitweb/README
index 2163071..356ab7b 100644
--- a/gitweb/README
+++ b/gitweb/README
@@ -2,7 +2,7 @@
 =================
 
 The one working on:
-  http://www.kernel.org/git/
+  http://git.kernel.org/
 
 From the git version 1.4.0 gitweb is bundled with git.
 
@@ -10,13 +10,13 @@
 How to configure gitweb for your local system
 ---------------------------------------------
 
-See also "Build time configuration" section in INSTALL
+See also the "Build time configuration" section in the INSTALL
 file for gitweb (in gitweb/INSTALL).
 
 You can specify the following configuration variables when building GIT:
  * GIT_BINDIR
-   Points out where to find git executable.  You should set up it to
-   the place where git binary was installed (usually /usr/bin) if you
+   Points where to find the git executable.  You should set it up to
+   the place where the git binary was installed (usually /usr/bin) if you
    don't install git from sources together with gitweb.  [Default: $(bindir)]
  * GITWEB_SITENAME
    Shown in the title of all generated pages, defaults to the server name
@@ -24,13 +24,13 @@
  * GITWEB_PROJECTROOT
    The root directory for all projects shown by gitweb. Must be set
    correctly for gitweb to find repositories to display.  See also
-   "Gitweb repositories" in INSTALL file for gitweb.  [Default: /pub/git]
+   "Gitweb repositories" in the INSTALL file for gitweb.  [Default: /pub/git]
  * GITWEB_PROJECT_MAXDEPTH
-   The filesystem traversing limit for getting projects list; the number
+   The filesystem traversing limit for getting the project list; the number
    is taken as depth relative to the projectroot.  It is used when
    GITWEB_LIST is a directory (or is not set; then project root is used).
    Is is meant to speed up project listing on large work trees by limiting
-   find depth.  [Default: 2007]
+   search depth.  [Default: 2007]
  * GITWEB_LIST
    Points to a directory to scan for projects (defaults to project root
    if not set / if empty) or to a file with explicit listing of projects
@@ -72,15 +72,15 @@
    Git base URLs used for URL to where fetch project from, i.e. full
    URL is "$git_base_url/$project".  Shown on projects summary page.
    Repository URL for project can be also configured per repository; this
-   takes precendence over URL composed from base URL and project name.
+   takes precedence over URLs composed from base URL and a project name.
    Note that you can setup multiple base URLs (for example one for
-   git:// protocol access, one for http:// access) from gitweb config
-   file.  [No default]
+   git:// protocol access, another for http:// access) from the gitweb
+   config file.  [No default]
  * GITWEB_CSS
    Points to the location where you put gitweb.css on your web server
-   (or to be more generic URI of gitweb stylesheet).  Relative to base
-   URI of gitweb.  Note that you can setup multiple stylesheets from
-   gitweb config file.  [Default: gitweb.css]
+   (or to be more generic, the URI of gitweb stylesheet).  Relative to the
+   base URI of gitweb.  Note that you can setup multiple stylesheets from
+   the gitweb config file.  [Default: gitweb.css]
  * GITWEB_LOGO
    Points to the location where you put git-logo.png on your web server
    (or to be more generic URI of logo, 72x27 size, displayed in top right
@@ -100,13 +100,20 @@
    is set when gitweb.cgi is executed, then the file specified in the
    environment variable will be loaded instead of the file specified
    when gitweb.cgi was created.  [Default: gitweb_config.perl]
+ * GITWEB_CONFIG_SYSTEM
+   This Perl file will be loaded using 'do' as a fallback if GITWEB_CONFIG
+   does not exist.  If the environment variable GITWEB_CONFIG_SYSTEM is set
+   when gitweb.cgi is executed, then the file specified in the environment
+   variable will be loaded instead of the file specified when gitweb.cgi was
+   created.  [Default: /etc/gitweb.conf]
 
 
 Runtime gitweb configuration
 ----------------------------
 
 You can adjust gitweb behaviour using the file specified in `GITWEB_CONFIG`
-(defaults to 'gitweb_config.perl' in the same directory as the CGI).
+(defaults to 'gitweb_config.perl' in the same directory as the CGI), and
+as a fallback `GITWEB_CONFIG_SYSTEM` (defaults to /etc/gitweb.conf).
 The most notable thing that is not configurable at compile time are the
 optional features, stored in the '%features' variable.
 
@@ -114,15 +121,15 @@
 in your `GITWEB_CONFIG` or per-project in `project.git/config` can be found
 as comments inside 'gitweb.cgi'.
 
-See also "Gitweb config file" (with example of gitweb config file), and
-"Gitweb repositories" sections in INSTALL file for gitweb.
+See also the "Gitweb config file" (with an example of config file), and
+the "Gitweb repositories" sections in INSTALL file for gitweb.
 
 
-Gitweb config file is [fragment] of perl code. You can set variables
+The gitweb config file is a fragment of perl code. You can set variables
 using "our $variable = value"; text from "#" character until the end
 of a line is ignored. See perlsyn(1) man page for details.
 
-Below there is list of vaiables which you might want to set in gitweb config.
+Below is the list of variables which you might want to set in gitweb config.
 See the top of 'gitweb.cgi' for the full list of variables and their
 descriptions.
 
@@ -133,7 +140,7 @@
 (with the exception of $projectroot and $projects_list this list does
 not include variables usually directly set during build):
  * $GIT
-   Cure git executable to use.  By default set to "$GIT_BINDIR/git", which
+   Core git executable to use.  By default set to "$GIT_BINDIR/git", which
    in turn is by default set to "$(bindir)/git".  If you use git from binary
    package, set this to "/usr/bin/git".  This can just be "git" if your
    webserver has a sensible PATH.  If you have multiple git versions
@@ -169,7 +176,7 @@
    to make it easier to upgrade gitweb. You can add 'site' stylesheet
    for example by using
       push @stylesheets, "gitweb-site.css";
-   in gitweb config file.
+   in the gitweb config file.
  * $logo_url, $logo_label
    URI and label (title) of GIT logo link (or your site logo, if you choose
    to use different logo image). By default they point to git homepage;
@@ -191,12 +198,12 @@
    Default mimetype for blob_plain (raw) view, if mimetype checking
    doesn't result in some other type; by default 'text/plain'.
  * $default_text_plain_charset
-   Default charset for text files. If not set, web serwer configuration
+   Default charset for text files. If not set, web server configuration
    would be used.
  * $mimetypes_file
    File to use for (filename extension based) guessing of MIME types before
-   trying /etc/mime.types. Path, if relative, is taken currently as taken
-   relative to current git repositoy.
+   trying /etc/mime.types. Path, if relative, is taken currently as
+   relative to the current git repository.
  * $fallback_encoding
    Gitweb assumes this charset if line contains non-UTF-8 characters.
    Fallback decoding is used without error checking, so it can be even
@@ -225,14 +232,14 @@
    single line description of a project (of a repository). Plain text file;
    HTML will be escaped. By default set to
      Unnamed repository; edit this file to name it for gitweb.
-   from the template during creating repository. You can use
+   from the template during repository creation. You can use the
    gitweb.description repo configuration variable, but the file takes
-   precendence.
+   precedence.
  * cloneurl (or multiple-valued gitweb.url)
    File with repository URL (used for clone and fetch), one per line.
    Displayed in the project summary page. You can use multiple-valued
    gitweb.url repository configuration variable for that, but the file
-   takes precendence.
+   takes precedence.
  * gitweb.owner
    You can use the gitweb.owner repository configuration variable to set
    repository's owner. It is displayed in the project list and summary
@@ -248,12 +255,15 @@
 If you want to have one URL for both gitweb and your http://
 repositories, you can configure apache like this:
 
-<VirtualHost www:80>
-    ServerName git.domain.org
+<VirtualHost *:80>
+    ServerName git.example.org
     DocumentRoot /pub/git
-    RewriteEngine on
-    RewriteRule ^/(.*\.git/(?!/?(info|objects|refs)).*)?$ /cgi-bin/gitweb.cgi%{REQUEST_URI}  [L,PT]
     SetEnv	GITWEB_CONFIG	/etc/gitweb.conf
+    RewriteEngine on
+    # make the front page an internal rewrite to the gitweb script
+    RewriteRule ^/$  /cgi-bin/gitweb.cgi
+    # make access for "dumb clients" work
+    RewriteRule ^/(.*\.git/(?!/?(HEAD|info|objects|refs)).*)?$ /cgi-bin/gitweb.cgi%{REQUEST_URI}  [L,PT]
 </VirtualHost>
 
 The above configuration expects your public repositories to live under
@@ -269,6 +279,13 @@
 gitweb.cgi).  Look at the comments in that file for information on
 which variables and what they mean.
 
+If you use the rewrite rules from the example you'll likely also need
+something like the following in your gitweb.conf (or gitweb_config.perl) file:
+
+  @stylesheets = ("/some/absolute/path/gitweb.css");
+  $my_uri = "/";
+  $home_link = "/";
+
 
 Originally written by:
   Kay Sievers <kay.sievers@vrfy.org>
diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css
index 446a1c3..aa0eeca 100644
--- a/gitweb/gitweb.css
+++ b/gitweb/gitweb.css
@@ -464,6 +464,14 @@
 	background-color: #ee5500;
 }
 
+a.rss_logo.generic {
+	background-color: #ff8800;
+}
+
+a.rss_logo.generic:hover {
+	background-color: #ee7700;
+}
+
 span.refs span {
 	padding: 0px 4px;
 	font-size: 70%;
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f37b687..f88ce35 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -369,10 +369,15 @@
 }
 
 our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
-do $GITWEB_CONFIG if -e $GITWEB_CONFIG;
+if (-e $GITWEB_CONFIG) {
+	do $GITWEB_CONFIG;
+} else {
+	our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++";
+	do $GITWEB_CONFIG_SYSTEM if -e $GITWEB_CONFIG_SYSTEM;
+}
 
 # version of the core git binary
-our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
+our $git_version = qx("$GIT" --version) =~ m/git version (.*)$/ ? $1 : "unknown";
 
 $projects_list ||= $projectroot;
 
@@ -587,7 +592,7 @@
 ## ======================================================================
 ## action links
 
-sub href(%) {
+sub href (%) {
 	my %params = @_;
 	# default is to use -absolute url() i.e. $my_uri
 	my $href = $params{-full} ? $my_url : $my_uri;
@@ -861,6 +866,10 @@
 	my $add_len = shift || 10;
 	my $where = shift || 'right'; # 'left' | 'center' | 'right'
 
+	# Make sure perl knows it is utf8 encoded so we don't
+	# cut in the middle of a utf8 multibyte char.
+	$str = to_utf8($str);
+
 	# allow only $len chars, but don't cut a word if it would fit in $add_len
 	# if it doesn't fit, cut it if it's still longer than the dots we would add
 	# remove chopped character entities entirely
@@ -1443,6 +1452,46 @@
 	}
 }
 
+## ......................................................................
+## functions returning values to be passed, perhaps after some
+## transformation, to other functions; e.g. returning arguments to href()
+
+# returns hash to be passed to href to generate gitweb URL
+# in -title key it returns description of link
+sub get_feed_info {
+	my $format = shift || 'Atom';
+	my %res = (action => lc($format));
+
+	# feed links are possible only for project views
+	return unless (defined $project);
+	# some views should link to OPML, or to generic project feed,
+	# or don't have specific feed yet (so they should use generic)
+	return if ($action =~ /^(?:tags|heads|forks|tag|search)$/x);
+
+	my $branch;
+	# branches refs uses 'refs/heads/' prefix (fullname) to differentiate
+	# from tag links; this also makes possible to detect branch links
+	if ((defined $hash_base && $hash_base =~ m!^refs/heads/(.*)$!) ||
+	    (defined $hash      && $hash      =~ m!^refs/heads/(.*)$!)) {
+		$branch = $1;
+	}
+	# find log type for feed description (title)
+	my $type = 'log';
+	if (defined $file_name) {
+		$type  = "history of $file_name";
+		$type .= "/" if ($action eq 'tree');
+		$type .= " on '$branch'" if (defined $branch);
+	} else {
+		$type = "log of $branch" if (defined $branch);
+	}
+
+	$res{-title} = $type;
+	$res{'hash'} = (defined $branch ? "refs/heads/$branch" : undef);
+	$res{'file_name'} = $file_name;
+
+	return %res;
+}
+
 ## ----------------------------------------------------------------------
 ## git utility subroutines, invoking git commands
 
@@ -1451,9 +1500,13 @@
 	return $GIT, '--git-dir='.$git_dir;
 }
 
-# returns path to the core git executable and the --git-dir parameter as string
-sub git_cmd_str {
-	return join(' ', git_cmd());
+# quote the given arguments for passing them to the shell
+# quote_command("command", "arg 1", "arg with ' and ! characters")
+# => "'command' 'arg 1' 'arg with '\'' and '\!' characters'"
+# Try to avoid using this function wherever possible.
+sub quote_command {
+	return join(' ',
+		    map( { my $a = $_; $a =~ s/(['!])/'\\$1'/g; "'$a'" } @_ ));
 }
 
 # get HEAD ref of given project as hash
@@ -2109,49 +2162,6 @@
 	return wantarray ? @cos : \@cos;
 }
 
-# parse ref from ref_file, given by ref_id, with given type
-sub parse_ref {
-	my $ref_file = shift;
-	my $ref_id = shift;
-	my $type = shift || git_get_type($ref_id);
-	my %ref_item;
-
-	$ref_item{'type'} = $type;
-	$ref_item{'id'} = $ref_id;
-	$ref_item{'epoch'} = 0;
-	$ref_item{'age'} = "unknown";
-	if ($type eq "tag") {
-		my %tag = parse_tag($ref_id);
-		$ref_item{'comment'} = $tag{'comment'};
-		if ($tag{'type'} eq "commit") {
-			my %co = parse_commit($tag{'object'});
-			$ref_item{'epoch'} = $co{'committer_epoch'};
-			$ref_item{'age'} = $co{'age_string'};
-		} elsif (defined($tag{'epoch'})) {
-			my $age = time - $tag{'epoch'};
-			$ref_item{'epoch'} = $tag{'epoch'};
-			$ref_item{'age'} = age_string($age);
-		}
-		$ref_item{'reftype'} = $tag{'type'};
-		$ref_item{'name'} = $tag{'name'};
-		$ref_item{'refid'} = $tag{'object'};
-	} elsif ($type eq "commit"){
-		my %co = parse_commit($ref_id);
-		$ref_item{'reftype'} = "commit";
-		$ref_item{'name'} = $ref_file;
-		$ref_item{'title'} = $co{'title'};
-		$ref_item{'refid'} = $ref_id;
-		$ref_item{'epoch'} = $co{'committer_epoch'};
-		$ref_item{'age'} = $co{'age_string'};
-	} else {
-		$ref_item{'reftype'} = $type;
-		$ref_item{'name'} = $ref_file;
-		$ref_item{'refid'} = $ref_id;
-	}
-
-	return %ref_item;
-}
-
 # parse line of git-diff-tree "raw" output
 sub parse_difftree_raw_line {
 	my $line = shift;
@@ -2432,8 +2442,7 @@
 	return $default_blob_plain_mimetype unless $fd;
 
 	if (-T $fd) {
-		return 'text/plain' .
-		       ($default_text_plain_charset ? '; charset='.$default_text_plain_charset : '');
+		return 'text/plain';
 	} elsif (! $filename) {
 		return 'application/octet-stream';
 	} elsif ($filename =~ m/\.png$/i) {
@@ -2447,6 +2456,17 @@
 	}
 }
 
+sub blob_contenttype {
+	my ($fd, $file_name, $type) = @_;
+
+	$type ||= blob_mimetype($fd, $file_name);
+	if ($type eq 'text/plain' && defined $default_text_plain_charset) {
+		$type .= "; charset=$default_text_plain_charset";
+	}
+
+	return $type;
+}
+
 ## ======================================================================
 ## functions printing HTML: header, footer, error page
 
@@ -2505,30 +2525,49 @@
 		}
 	}
 	if (defined $project) {
-		printf('<link rel="alternate" title="%s log RSS feed" '.
-		       'href="%s" type="application/rss+xml" />'."\n",
-		       esc_param($project), href(action=>"rss"));
-		printf('<link rel="alternate" title="%s log RSS feed (no merges)" '.
-		       'href="%s" type="application/rss+xml" />'."\n",
-		       esc_param($project), href(action=>"rss",
-		                                 extra_options=>"--no-merges"));
-		printf('<link rel="alternate" title="%s log Atom feed" '.
-		       'href="%s" type="application/atom+xml" />'."\n",
-		       esc_param($project), href(action=>"atom"));
-		printf('<link rel="alternate" title="%s log Atom feed (no merges)" '.
-		       'href="%s" type="application/atom+xml" />'."\n",
-		       esc_param($project), href(action=>"atom",
-		                                 extra_options=>"--no-merges"));
+		my %href_params = get_feed_info();
+		if (!exists $href_params{'-title'}) {
+			$href_params{'-title'} = 'log';
+		}
+
+		foreach my $format qw(RSS Atom) {
+			my $type = lc($format);
+			my %link_attr = (
+				'-rel' => 'alternate',
+				'-title' => "$project - $href_params{'-title'} - $format feed",
+				'-type' => "application/$type+xml"
+			);
+
+			$href_params{'action'} = $type;
+			$link_attr{'-href'} = href(%href_params);
+			print "<link ".
+			      "rel=\"$link_attr{'-rel'}\" ".
+			      "title=\"$link_attr{'-title'}\" ".
+			      "href=\"$link_attr{'-href'}\" ".
+			      "type=\"$link_attr{'-type'}\" ".
+			      "/>\n";
+
+			$href_params{'extra_options'} = '--no-merges';
+			$link_attr{'-href'} = href(%href_params);
+			$link_attr{'-title'} .= ' (no merges)';
+			print "<link ".
+			      "rel=\"$link_attr{'-rel'}\" ".
+			      "title=\"$link_attr{'-title'}\" ".
+			      "href=\"$link_attr{'-href'}\" ".
+			      "type=\"$link_attr{'-type'}\" ".
+			      "/>\n";
+		}
+
 	} else {
 		printf('<link rel="alternate" title="%s projects list" '.
-		       'href="%s" type="text/plain; charset=utf-8"/>'."\n",
+		       'href="%s" type="text/plain; charset=utf-8" />'."\n",
 		       $site_name, href(project=>undef, action=>"project_index"));
 		printf('<link rel="alternate" title="%s projects feeds" '.
-		       'href="%s" type="text/x-opml"/>'."\n",
+		       'href="%s" type="text/x-opml" />'."\n",
 		       $site_name, href(project=>undef, action=>"opml"));
 	}
 	if (defined $favicon) {
-		print qq(<link rel="shortcut icon" href="$favicon" type="image/png"/>\n);
+		print qq(<link rel="shortcut icon" href="$favicon" type="image/png" />\n);
 	}
 
 	print "</head>\n" .
@@ -2555,7 +2594,7 @@
 	print "</div>\n";
 
 	my ($have_search) = gitweb_check_feature('search');
-	if ((defined $project) && ($have_search)) {
+	if (defined $project && $have_search) {
 		if (!defined $searchtext) {
 			$searchtext = "";
 		}
@@ -2571,16 +2610,13 @@
 		my ($use_pathinfo) = gitweb_check_feature('pathinfo');
 		if ($use_pathinfo) {
 			$action .= "/".esc_url($project);
-		} else {
-			$cgi->param("p", $project);
 		}
-		$cgi->param("a", "search");
-		$cgi->param("h", $search_hash);
 		print $cgi->startform(-method => "get", -action => $action) .
 		      "<div class=\"search\">\n" .
-		      (!$use_pathinfo && $cgi->hidden(-name => "p") . "\n") .
-		      $cgi->hidden(-name => "a") . "\n" .
-		      $cgi->hidden(-name => "h") . "\n" .
+		      (!$use_pathinfo &&
+		      $cgi->input({-name=>"p", -value=>$project, -type=>"hidden"}) . "\n") .
+		      $cgi->input({-name=>"a", -value=>"search", -type=>"hidden"}) . "\n" .
+		      $cgi->input({-name=>"h", -value=>$search_hash, -type=>"hidden"}) . "\n" .
 		      $cgi->popup_menu(-name => 'st', -default => 'commit',
 		                       -values => ['commit', 'grep', 'author', 'committer', 'pickaxe']) .
 		      $cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) .
@@ -2596,23 +2632,35 @@
 }
 
 sub git_footer_html {
+	my $feed_class = 'rss_logo';
+
 	print "<div class=\"page_footer\">\n";
 	if (defined $project) {
 		my $descr = git_get_project_description($project);
 		if (defined $descr) {
 			print "<div class=\"page_footer_text\">" . esc_html($descr) . "</div>\n";
 		}
-		print $cgi->a({-href => href(action=>"rss"),
-		              -class => "rss_logo"}, "RSS") . " ";
-		print $cgi->a({-href => href(action=>"atom"),
-		              -class => "rss_logo"}, "Atom") . "\n";
+
+		my %href_params = get_feed_info();
+		if (!%href_params) {
+			$feed_class .= ' generic';
+		}
+		$href_params{'-title'} ||= 'log';
+
+		foreach my $format qw(RSS Atom) {
+			$href_params{'action'} = lc($format);
+			print $cgi->a({-href => href(%href_params),
+			              -title => "$href_params{'-title'} $format feed",
+			              -class => $feed_class}, $format)."\n";
+		}
+
 	} else {
 		print $cgi->a({-href => href(project=>undef, action=>"opml"),
-		              -class => "rss_logo"}, "OPML") . " ";
+		              -class => $feed_class}, "OPML") . " ";
 		print $cgi->a({-href => href(project=>undef, action=>"project_index"),
-		              -class => "rss_logo"}, "TXT") . "\n";
+		              -class => $feed_class}, "TXT") . "\n";
 	}
-	print "</div>\n" ;
+	print "</div>\n"; # class="page_footer"
 
 	if (-f $site_footer) {
 		open (my $fd, $site_footer);
@@ -4297,6 +4345,7 @@
 }
 
 sub git_blob_plain {
+	my $type = shift;
 	my $expires;
 
 	if (!defined $hash) {
@@ -4312,13 +4361,13 @@
 		$expires = "+1d";
 	}
 
-	my $type = shift;
 	open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
-		or die_error(undef, "Couldn't cat $file_name, $hash");
+		or die_error(undef, "Open git-cat-file blob '$hash' failed");
 
-	$type ||= blob_mimetype($fd, $file_name);
+	# content-type (can include charset)
+	$type = blob_contenttype($fd, $file_name, $type);
 
-	# save as filename, even when no $file_name is given
+	# "save as" filename, even when no $file_name is given
 	my $save_as = "$hash";
 	if (defined $file_name) {
 		$save_as = $file_name;
@@ -4327,9 +4376,9 @@
 	}
 
 	print $cgi->header(
-		-type => "$type",
-		-expires=>$expires,
-		-content_disposition => 'inline; filename="' . "$save_as" . '"');
+		-type => $type,
+		-expires => $expires,
+		-content_disposition => 'inline; filename="' . $save_as . '"');
 	undef $/;
 	binmode STDOUT, ':raw';
 	print <$fd>;
@@ -4545,7 +4594,6 @@
 		$hash = git_get_head_hash($project);
 	}
 
-	my $git_command = git_cmd_str();
 	my $name = $project;
 	$name =~ s,([^/])/*\.git$,$1,;
 	$name = basename($name);
@@ -4553,11 +4601,12 @@
 	$name =~ s/\047/\047\\\047\047/g;
 	my $cmd;
 	$filename .= "-$hash$known_snapshot_formats{$format}{'suffix'}";
-	$cmd = "$git_command archive " .
-		"--format=$known_snapshot_formats{$format}{'format'} " .
-		"--prefix=\'$name\'/ $hash";
+	$cmd = quote_command(
+		git_cmd(), 'archive',
+		"--format=$known_snapshot_formats{$format}{'format'}",
+		"--prefix=$name/", $hash);
 	if (exists $known_snapshot_formats{$format}{'compressor'}) {
-		$cmd .= ' | ' . join ' ', @{$known_snapshot_formats{$format}{'compressor'}};
+		$cmd .= ' | ' . quote_command(@{$known_snapshot_formats{$format}{'compressor'}});
 	}
 
 	print $cgi->header(
@@ -4770,8 +4819,8 @@
 	if ($hash || ($hash_base && !defined $file_name)) {
 		my $object_id = $hash || $hash_base;
 
-		my $git_command = git_cmd_str();
-		open my $fd, "-|", "$git_command cat-file -t $object_id 2>/dev/null"
+		open my $fd, "-|", quote_command(
+			git_cmd(), 'cat-file', '-t', $object_id) . ' 2> /dev/null'
 			or die_error('404 Not Found', "Object does not exist");
 		$type = <$fd>;
 		chomp $type;
diff --git "a/gitweb/test/M\303\244rchen" "b/gitweb/test/M\303\244rchen"
deleted file mode 100644
index 8f7a1d3..0000000
--- "a/gitweb/test/M\303\244rchen"
+++ /dev/null
@@ -1,2 +0,0 @@
-Märchen
-Märchen
diff --git a/gitweb/test/file with spaces b/gitweb/test/file with spaces
deleted file mode 100644
index f108543..0000000
--- a/gitweb/test/file with spaces
+++ /dev/null
@@ -1,4 +0,0 @@
-This
-filename
-contains
-spaces.
diff --git a/gitweb/test/file+plus+sign b/gitweb/test/file+plus+sign
deleted file mode 100644
index fd05278..0000000
--- a/gitweb/test/file+plus+sign
+++ /dev/null
@@ -1,6 +0,0 @@
-This
-filename
-contains
-+
-plus
-chars.
diff --git a/graph.c b/graph.c
new file mode 100644
index 0000000..e2633f8
--- /dev/null
+++ b/graph.c
@@ -0,0 +1,1132 @@
+#include "cache.h"
+#include "commit.h"
+#include "graph.h"
+#include "diff.h"
+#include "revision.h"
+
+/*
+ * TODO:
+ * - Add colors to the graph.
+ *   Pick a color for each column, and print all characters
+ *   in that column with the specified color.
+ *
+ * - Limit the number of columns, similar to the way gitk does.
+ *   If we reach more than a specified number of columns, omit
+ *   sections of some columns.
+ *
+ * - The output during the GRAPH_PRE_COMMIT and GRAPH_COLLAPSING states
+ *   could be made more compact by printing horizontal lines, instead of
+ *   long diagonal lines.  For example, during collapsing, something like
+ *   this:          instead of this:
+ *   | | | | |      | | | | |
+ *   | |_|_|/       | | | |/
+ *   |/| | |        | | |/|
+ *   | | | |        | |/| |
+ *                  |/| | |
+ *                  | | | |
+ *
+ *   If there are several parallel diagonal lines, they will need to be
+ *   replaced with horizontal lines on subsequent rows.
+ */
+
+struct column {
+	/*
+	 * The parent commit of this column.
+	 */
+	struct commit *commit;
+	/*
+	 * XXX: Once we add support for colors, struct column could also
+	 * contain the color of its branch line.
+	 */
+};
+
+enum graph_state {
+	GRAPH_PADDING,
+	GRAPH_SKIP,
+	GRAPH_PRE_COMMIT,
+	GRAPH_COMMIT,
+	GRAPH_POST_MERGE,
+	GRAPH_COLLAPSING
+};
+
+struct git_graph {
+	/*
+	 * The commit currently being processed
+	 */
+	struct commit *commit;
+	/* The rev-info used for the current traversal */
+	struct rev_info *revs;
+	/*
+	 * The number of interesting parents that this commit has.
+	 *
+	 * Note that this is not the same as the actual number of parents.
+	 * This count excludes parents that won't be printed in the graph
+	 * output, as determined by graph_is_interesting().
+	 */
+	int num_parents;
+	/*
+	 * The width of the graph output for this commit.
+	 * All rows for this commit are padded to this width, so that
+	 * messages printed after the graph output are aligned.
+	 */
+	int width;
+	/*
+	 * The next expansion row to print
+	 * when state is GRAPH_PRE_COMMIT
+	 */
+	int expansion_row;
+	/*
+	 * The current output state.
+	 * This tells us what kind of line graph_next_line() should output.
+	 */
+	enum graph_state state;
+	/*
+	 * The output state for the previous line of output.
+	 * This is primarily used to determine how the first merge line
+	 * should appear, based on the last line of the previous commit.
+	 */
+	enum graph_state prev_state;
+	/*
+	 * The index of the column that refers to this commit.
+	 *
+	 * If none of the incoming columns refer to this commit,
+	 * this will be equal to num_columns.
+	 */
+	int commit_index;
+	/*
+	 * The commit_index for the previously displayed commit.
+	 *
+	 * This is used to determine how the first line of a merge
+	 * graph output should appear, based on the last line of the
+	 * previous commit.
+	 */
+	int prev_commit_index;
+	/*
+	 * The maximum number of columns that can be stored in the columns
+	 * and new_columns arrays.  This is also half the number of entries
+	 * that can be stored in the mapping and new_mapping arrays.
+	 */
+	int column_capacity;
+	/*
+	 * The number of columns (also called "branch lines" in some places)
+	 */
+	int num_columns;
+	/*
+	 * The number of columns in the new_columns array
+	 */
+	int num_new_columns;
+	/*
+	 * The number of entries in the mapping array
+	 */
+	int mapping_size;
+	/*
+	 * The column state before we output the current commit.
+	 */
+	struct column *columns;
+	/*
+	 * The new column state after we output the current commit.
+	 * Only valid when state is GRAPH_COLLAPSING.
+	 */
+	struct column *new_columns;
+	/*
+	 * An array that tracks the current state of each
+	 * character in the output line during state GRAPH_COLLAPSING.
+	 * Each entry is -1 if this character is empty, or a non-negative
+	 * integer if the character contains a branch line.  The value of
+	 * the integer indicates the target position for this branch line.
+	 * (I.e., this array maps the current column positions to their
+	 * desired positions.)
+	 *
+	 * The maximum capacity of this array is always
+	 * sizeof(int) * 2 * column_capacity.
+	 */
+	int *mapping;
+	/*
+	 * A temporary array for computing the next mapping state
+	 * while we are outputting a mapping line.  This is stored as part
+	 * of the git_graph simply so we don't have to allocate a new
+	 * temporary array each time we have to output a collapsing line.
+	 */
+	int *new_mapping;
+};
+
+struct git_graph *graph_init(struct rev_info *opt)
+{
+	struct git_graph *graph = xmalloc(sizeof(struct git_graph));
+	graph->commit = NULL;
+	graph->revs = opt;
+	graph->num_parents = 0;
+	graph->expansion_row = 0;
+	graph->state = GRAPH_PADDING;
+	graph->prev_state = GRAPH_PADDING;
+	graph->commit_index = 0;
+	graph->prev_commit_index = 0;
+	graph->num_columns = 0;
+	graph->num_new_columns = 0;
+	graph->mapping_size = 0;
+
+	/*
+	 * Allocate a reasonably large default number of columns
+	 * We'll automatically grow columns later if we need more room.
+	 */
+	graph->column_capacity = 30;
+	graph->columns = xmalloc(sizeof(struct column) *
+				 graph->column_capacity);
+	graph->new_columns = xmalloc(sizeof(struct column) *
+				     graph->column_capacity);
+	graph->mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);
+	graph->new_mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);
+
+	return graph;
+}
+
+void graph_release(struct git_graph *graph)
+{
+	free(graph->columns);
+	free(graph->new_columns);
+	free(graph->mapping);
+	free(graph);
+}
+
+static void graph_update_state(struct git_graph *graph, enum graph_state s)
+{
+	graph->prev_state = graph->state;
+	graph->state = s;
+}
+
+static void graph_ensure_capacity(struct git_graph *graph, int num_columns)
+{
+	if (graph->column_capacity >= num_columns)
+		return;
+
+	do {
+		graph->column_capacity *= 2;
+	} while (graph->column_capacity < num_columns);
+
+	graph->columns = xrealloc(graph->columns,
+				  sizeof(struct column) *
+				  graph->column_capacity);
+	graph->new_columns = xrealloc(graph->new_columns,
+				      sizeof(struct column) *
+				      graph->column_capacity);
+	graph->mapping = xrealloc(graph->mapping,
+				  sizeof(int) * 2 * graph->column_capacity);
+	graph->new_mapping = xrealloc(graph->new_mapping,
+				      sizeof(int) * 2 * graph->column_capacity);
+}
+
+/*
+ * Returns 1 if the commit will be printed in the graph output,
+ * and 0 otherwise.
+ */
+static int graph_is_interesting(struct git_graph *graph, struct commit *commit)
+{
+	/*
+	 * If revs->boundary is set, commits whose children have
+	 * been shown are always interesting, even if they have the
+	 * UNINTERESTING or TREESAME flags set.
+	 */
+	if (graph->revs && graph->revs->boundary) {
+		if (commit->object.flags & CHILD_SHOWN)
+			return 1;
+	}
+
+	/*
+	 * Uninteresting and pruned commits won't be printed
+	 */
+	return (commit->object.flags & (UNINTERESTING | TREESAME)) ? 0 : 1;
+}
+
+static struct commit_list *next_interesting_parent(struct git_graph *graph,
+						   struct commit_list *orig)
+{
+	struct commit_list *list;
+
+	/*
+	 * If revs->first_parent_only is set, only the first
+	 * parent is interesting.  None of the others are.
+	 */
+	if (graph->revs->first_parent_only)
+		return NULL;
+
+	/*
+	 * Return the next interesting commit after orig
+	 */
+	for (list = orig->next; list; list = list->next) {
+		if (graph_is_interesting(graph, list->item))
+			return list;
+	}
+
+	return NULL;
+}
+
+static struct commit_list *first_interesting_parent(struct git_graph *graph)
+{
+	struct commit_list *parents = graph->commit->parents;
+
+	/*
+	 * If this commit has no parents, ignore it
+	 */
+	if (!parents)
+		return NULL;
+
+	/*
+	 * If the first parent is interesting, return it
+	 */
+	if (graph_is_interesting(graph, parents->item))
+		return parents;
+
+	/*
+	 * Otherwise, call next_interesting_parent() to get
+	 * the next interesting parent
+	 */
+	return next_interesting_parent(graph, parents);
+}
+
+static void graph_insert_into_new_columns(struct git_graph *graph,
+					  struct commit *commit,
+					  int *mapping_index)
+{
+	int i;
+
+	/*
+	 * If the commit is already in the new_columns list, we don't need to
+	 * add it.  Just update the mapping correctly.
+	 */
+	for (i = 0; i < graph->num_new_columns; i++) {
+		if (graph->new_columns[i].commit == commit) {
+			graph->mapping[*mapping_index] = i;
+			*mapping_index += 2;
+			return;
+		}
+	}
+
+	/*
+	 * This commit isn't already in new_columns.  Add it.
+	 */
+	graph->new_columns[graph->num_new_columns].commit = commit;
+	graph->mapping[*mapping_index] = graph->num_new_columns;
+	*mapping_index += 2;
+	graph->num_new_columns++;
+}
+
+static void graph_update_width(struct git_graph *graph,
+			       int is_commit_in_existing_columns)
+{
+	/*
+	 * Compute the width needed to display the graph for this commit.
+	 * This is the maximum width needed for any row.  All other rows
+	 * will be padded to this width.
+	 *
+	 * Compute the number of columns in the widest row:
+	 * Count each existing column (graph->num_columns), and each new
+	 * column added by this commit.
+	 */
+	int max_cols = graph->num_columns + graph->num_parents;
+
+	/*
+	 * Even if the current commit has no parents to be printed, it
+	 * still takes up a column for itself.
+	 */
+	if (graph->num_parents < 1)
+		max_cols++;
+
+	/*
+	 * We added a column for the the current commit as part of
+	 * graph->num_parents.  If the current commit was already in
+	 * graph->columns, then we have double counted it.
+	 */
+	if (is_commit_in_existing_columns)
+		max_cols--;
+
+	/*
+	 * Each column takes up 2 spaces
+	 */
+	graph->width = max_cols * 2;
+}
+
+static void graph_update_columns(struct git_graph *graph)
+{
+	struct commit_list *parent;
+	struct column *tmp_columns;
+	int max_new_columns;
+	int mapping_idx;
+	int i, seen_this, is_commit_in_columns;
+
+	/*
+	 * Swap graph->columns with graph->new_columns
+	 * graph->columns contains the state for the previous commit,
+	 * and new_columns now contains the state for our commit.
+	 *
+	 * We'll re-use the old columns array as storage to compute the new
+	 * columns list for the commit after this one.
+	 */
+	tmp_columns = graph->columns;
+	graph->columns = graph->new_columns;
+	graph->num_columns = graph->num_new_columns;
+
+	graph->new_columns = tmp_columns;
+	graph->num_new_columns = 0;
+
+	/*
+	 * Now update new_columns and mapping with the information for the
+	 * commit after this one.
+	 *
+	 * First, make sure we have enough room.  At most, there will
+	 * be graph->num_columns + graph->num_parents columns for the next
+	 * commit.
+	 */
+	max_new_columns = graph->num_columns + graph->num_parents;
+	graph_ensure_capacity(graph, max_new_columns);
+
+	/*
+	 * Clear out graph->mapping
+	 */
+	graph->mapping_size = 2 * max_new_columns;
+	for (i = 0; i < graph->mapping_size; i++)
+		graph->mapping[i] = -1;
+
+	/*
+	 * Populate graph->new_columns and graph->mapping
+	 *
+	 * Some of the parents of this commit may already be in
+	 * graph->columns.  If so, graph->new_columns should only contain a
+	 * single entry for each such commit.  graph->mapping should
+	 * contain information about where each current branch line is
+	 * supposed to end up after the collapsing is performed.
+	 */
+	seen_this = 0;
+	mapping_idx = 0;
+	is_commit_in_columns = 1;
+	for (i = 0; i <= graph->num_columns; i++) {
+		struct commit *col_commit;
+		if (i == graph->num_columns) {
+			if (seen_this)
+				break;
+			is_commit_in_columns = 0;
+			col_commit = graph->commit;
+		} else {
+			col_commit = graph->columns[i].commit;
+		}
+
+		if (col_commit == graph->commit) {
+			int old_mapping_idx = mapping_idx;
+			seen_this = 1;
+			graph->commit_index = i;
+			for (parent = first_interesting_parent(graph);
+			     parent;
+			     parent = next_interesting_parent(graph, parent)) {
+				graph_insert_into_new_columns(graph,
+							      parent->item,
+							      &mapping_idx);
+			}
+			/*
+			 * We always need to increment mapping_idx by at
+			 * least 2, even if it has no interesting parents.
+			 * The current commit always takes up at least 2
+			 * spaces.
+			 */
+			if (mapping_idx == old_mapping_idx)
+				mapping_idx += 2;
+		} else {
+			graph_insert_into_new_columns(graph, col_commit,
+						      &mapping_idx);
+		}
+	}
+
+	/*
+	 * Shrink mapping_size to be the minimum necessary
+	 */
+	while (graph->mapping_size > 1 &&
+	       graph->mapping[graph->mapping_size - 1] < 0)
+		graph->mapping_size--;
+
+	/*
+	 * Compute graph->width for this commit
+	 */
+	graph_update_width(graph, is_commit_in_columns);
+}
+
+void graph_update(struct git_graph *graph, struct commit *commit)
+{
+	struct commit_list *parent;
+
+	/*
+	 * Set the new commit
+	 */
+	graph->commit = commit;
+
+	/*
+	 * Count how many interesting parents this commit has
+	 */
+	graph->num_parents = 0;
+	for (parent = first_interesting_parent(graph);
+	     parent;
+	     parent = next_interesting_parent(graph, parent))
+	{
+		graph->num_parents++;
+	}
+
+	/*
+	 * Store the old commit_index in prev_commit_index.
+	 * graph_update_columns() will update graph->commit_index for this
+	 * commit.
+	 */
+	graph->prev_commit_index = graph->commit_index;
+
+	/*
+	 * Call graph_update_columns() to update
+	 * columns, new_columns, and mapping.
+	 */
+	graph_update_columns(graph);
+
+	graph->expansion_row = 0;
+
+	/*
+	 * Update graph->state.
+	 * Note that we don't call graph_update_state() here, since
+	 * we don't want to update graph->prev_state.  No line for
+	 * graph->state was ever printed.
+	 *
+	 * If the previous commit didn't get to the GRAPH_PADDING state,
+	 * it never finished its output.  Goto GRAPH_SKIP, to print out
+	 * a line to indicate that portion of the graph is missing.
+	 *
+	 * If there are 3 or more parents, we may need to print extra rows
+	 * before the commit, to expand the branch lines around it and make
+	 * room for it.  We need to do this only if there is a branch row
+	 * (or more) to the right of this commit.
+	 *
+	 * If there are less than 3 parents, we can immediately print the
+	 * commit line.
+	 */
+	if (graph->state != GRAPH_PADDING)
+		graph->state = GRAPH_SKIP;
+	else if (graph->num_parents >= 3 &&
+		 graph->commit_index < (graph->num_columns - 1))
+		graph->state = GRAPH_PRE_COMMIT;
+	else
+		graph->state = GRAPH_COMMIT;
+}
+
+static int graph_is_mapping_correct(struct git_graph *graph)
+{
+	int i;
+
+	/*
+	 * The mapping is up to date if each entry is at its target,
+	 * or is 1 greater than its target.
+	 * (If it is 1 greater than the target, '/' will be printed, so it
+	 * will look correct on the next row.)
+	 */
+	for (i = 0; i < graph->mapping_size; i++) {
+		int target = graph->mapping[i];
+		if (target < 0)
+			continue;
+		if (target == (i / 2))
+			continue;
+		return 0;
+	}
+
+	return 1;
+}
+
+static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb)
+{
+	/*
+	 * Add additional spaces to the end of the strbuf, so that all
+	 * lines for a particular commit have the same width.
+	 *
+	 * This way, fields printed to the right of the graph will remain
+	 * aligned for the entire commit.
+	 */
+	int extra;
+	if (sb->len >= graph->width)
+		return;
+
+	extra = graph->width - sb->len;
+	strbuf_addf(sb, "%*s", (int) extra, "");
+}
+
+static void graph_output_padding_line(struct git_graph *graph,
+				      struct strbuf *sb)
+{
+	int i;
+
+	/*
+	 * We could conceivable be called with a NULL commit
+	 * if our caller has a bug, and invokes graph_next_line()
+	 * immediately after graph_init(), without first calling
+	 * graph_update().  Return without outputting anything in this
+	 * case.
+	 */
+	if (!graph->commit)
+		return;
+
+	/*
+	 * Output a padding row, that leaves all branch lines unchanged
+	 */
+	for (i = 0; i < graph->num_new_columns; i++) {
+		strbuf_addstr(sb, "| ");
+	}
+
+	graph_pad_horizontally(graph, sb);
+}
+
+static void graph_output_skip_line(struct git_graph *graph, struct strbuf *sb)
+{
+	/*
+	 * Output an ellipsis to indicate that a portion
+	 * of the graph is missing.
+	 */
+	strbuf_addstr(sb, "...");
+	graph_pad_horizontally(graph, sb);
+
+	if (graph->num_parents >= 3 &&
+	    graph->commit_index < (graph->num_columns - 1))
+		graph_update_state(graph, GRAPH_PRE_COMMIT);
+	else
+		graph_update_state(graph, GRAPH_COMMIT);
+}
+
+static void graph_output_pre_commit_line(struct git_graph *graph,
+					 struct strbuf *sb)
+{
+	int num_expansion_rows;
+	int i, seen_this;
+
+	/*
+	 * This function formats a row that increases the space around a commit
+	 * with multiple parents, to make room for it.  It should only be
+	 * called when there are 3 or more parents.
+	 *
+	 * We need 2 extra rows for every parent over 2.
+	 */
+	assert(graph->num_parents >= 3);
+	num_expansion_rows = (graph->num_parents - 2) * 2;
+
+	/*
+	 * graph->expansion_row tracks the current expansion row we are on.
+	 * It should be in the range [0, num_expansion_rows - 1]
+	 */
+	assert(0 <= graph->expansion_row &&
+	       graph->expansion_row < num_expansion_rows);
+
+	/*
+	 * Output the row
+	 */
+	seen_this = 0;
+	for (i = 0; i < graph->num_columns; i++) {
+		struct column *col = &graph->columns[i];
+		if (col->commit == graph->commit) {
+			seen_this = 1;
+			strbuf_addf(sb, "| %*s", graph->expansion_row, "");
+		} else if (seen_this && (graph->expansion_row == 0)) {
+			/*
+			 * This is the first line of the pre-commit output.
+			 * If the previous commit was a merge commit and
+			 * ended in the GRAPH_POST_MERGE state, all branch
+			 * lines after graph->prev_commit_index were
+			 * printed as "\" on the previous line.  Continue
+			 * to print them as "\" on this line.  Otherwise,
+			 * print the branch lines as "|".
+			 */
+			if (graph->prev_state == GRAPH_POST_MERGE &&
+			    graph->prev_commit_index < i)
+				strbuf_addstr(sb, "\\ ");
+			else
+				strbuf_addstr(sb, "| ");
+		} else if (seen_this && (graph->expansion_row > 0)) {
+			strbuf_addstr(sb, "\\ ");
+		} else {
+			strbuf_addstr(sb, "| ");
+		}
+	}
+
+	graph_pad_horizontally(graph, sb);
+
+	/*
+	 * Increment graph->expansion_row,
+	 * and move to state GRAPH_COMMIT if necessary
+	 */
+	graph->expansion_row++;
+	if (graph->expansion_row >= num_expansion_rows)
+		graph_update_state(graph, GRAPH_COMMIT);
+}
+
+static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)
+{
+	/*
+	 * For boundary commits, print 'o'
+	 * (We should only see boundary commits when revs->boundary is set.)
+	 */
+	if (graph->commit->object.flags & BOUNDARY) {
+		assert(graph->revs->boundary);
+		strbuf_addch(sb, 'o');
+		return;
+	}
+
+	/*
+	 * If revs->left_right is set, print '<' for commits that
+	 * come from the left side, and '>' for commits from the right
+	 * side.
+	 */
+	if (graph->revs && graph->revs->left_right) {
+		if (graph->commit->object.flags & SYMMETRIC_LEFT)
+			strbuf_addch(sb, '<');
+		else
+			strbuf_addch(sb, '>');
+		return;
+	}
+
+	/*
+	 * Print '*' in all other cases
+	 */
+	strbuf_addch(sb, '*');
+}
+
+void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
+{
+	int seen_this = 0;
+	int i, j;
+
+	/*
+	 * Output the row containing this commit
+	 * Iterate up to and including graph->num_columns,
+	 * since the current commit may not be in any of the existing
+	 * columns.  (This happens when the current commit doesn't have any
+	 * children that we have already processed.)
+	 */
+	seen_this = 0;
+	for (i = 0; i <= graph->num_columns; i++) {
+		struct commit *col_commit;
+		if (i == graph->num_columns) {
+			if (seen_this)
+				break;
+			col_commit = graph->commit;
+		} else {
+			col_commit = graph->columns[i].commit;
+		}
+
+		if (col_commit == graph->commit) {
+			seen_this = 1;
+			graph_output_commit_char(graph, sb);
+
+			if (graph->num_parents < 3)
+				strbuf_addch(sb, ' ');
+			else {
+				int num_dashes =
+					((graph->num_parents - 2) * 2) - 1;
+				for (j = 0; j < num_dashes; j++)
+					strbuf_addch(sb, '-');
+				strbuf_addstr(sb, ". ");
+			}
+		} else if (seen_this && (graph->num_parents > 2)) {
+			strbuf_addstr(sb, "\\ ");
+		} else if (seen_this && (graph->num_parents == 2)) {
+			/*
+			 * This is a 2-way merge commit.
+			 * There is no GRAPH_PRE_COMMIT stage for 2-way
+			 * merges, so this is the first line of output
+			 * for this commit.  Check to see what the previous
+			 * line of output was.
+			 *
+			 * If it was GRAPH_POST_MERGE, the branch line
+			 * coming into this commit may have been '\',
+			 * and not '|' or '/'.  If so, output the branch
+			 * line as '\' on this line, instead of '|'.  This
+			 * makes the output look nicer.
+			 */
+			if (graph->prev_state == GRAPH_POST_MERGE &&
+			    graph->prev_commit_index < i)
+				strbuf_addstr(sb, "\\ ");
+			else
+				strbuf_addstr(sb, "| ");
+		} else {
+			strbuf_addstr(sb, "| ");
+		}
+	}
+
+	graph_pad_horizontally(graph, sb);
+
+	/*
+	 * Update graph->state
+	 */
+	if (graph->num_parents > 1)
+		graph_update_state(graph, GRAPH_POST_MERGE);
+	else if (graph_is_mapping_correct(graph))
+		graph_update_state(graph, GRAPH_PADDING);
+	else
+		graph_update_state(graph, GRAPH_COLLAPSING);
+}
+
+void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb)
+{
+	int seen_this = 0;
+	int i, j;
+
+	/*
+	 * Output the post-merge row
+	 */
+	for (i = 0; i <= graph->num_columns; i++) {
+		struct commit *col_commit;
+		if (i == graph->num_columns) {
+			if (seen_this)
+				break;
+			col_commit = graph->commit;
+		} else {
+			col_commit = graph->columns[i].commit;
+		}
+
+		if (col_commit == graph->commit) {
+			seen_this = 1;
+			strbuf_addch(sb, '|');
+			for (j = 0; j < graph->num_parents - 1; j++)
+				strbuf_addstr(sb, "\\ ");
+		} else if (seen_this) {
+			strbuf_addstr(sb, "\\ ");
+		} else {
+			strbuf_addstr(sb, "| ");
+		}
+	}
+
+	graph_pad_horizontally(graph, sb);
+
+	/*
+	 * Update graph->state
+	 */
+	if (graph_is_mapping_correct(graph))
+		graph_update_state(graph, GRAPH_PADDING);
+	else
+		graph_update_state(graph, GRAPH_COLLAPSING);
+}
+
+void graph_output_collapsing_line(struct git_graph *graph, struct strbuf *sb)
+{
+	int i;
+	int *tmp_mapping;
+
+	/*
+	 * Clear out the new_mapping array
+	 */
+	for (i = 0; i < graph->mapping_size; i++)
+		graph->new_mapping[i] = -1;
+
+	for (i = 0; i < graph->mapping_size; i++) {
+		int target = graph->mapping[i];
+		if (target < 0)
+			continue;
+
+		/*
+		 * Since update_columns() always inserts the leftmost
+		 * column first, each branch's target location should
+		 * always be either its current location or to the left of
+		 * its current location.
+		 *
+		 * We never have to move branches to the right.  This makes
+		 * the graph much more legible, since whenever branches
+		 * cross, only one is moving directions.
+		 */
+		assert(target * 2 <= i);
+
+		if (target * 2 == i) {
+			/*
+			 * This column is already in the
+			 * correct place
+			 */
+			assert(graph->new_mapping[i] == -1);
+			graph->new_mapping[i] = target;
+		} else if (graph->new_mapping[i - 1] < 0) {
+			/*
+			 * Nothing is to the left.
+			 * Move to the left by one
+			 */
+			graph->new_mapping[i - 1] = target;
+		} else if (graph->new_mapping[i - 1] == target) {
+			/*
+			 * There is a branch line to our left
+			 * already, and it is our target.  We
+			 * combine with this line, since we share
+			 * the same parent commit.
+			 *
+			 * We don't have to add anything to the
+			 * output or new_mapping, since the
+			 * existing branch line has already taken
+			 * care of it.
+			 */
+		} else {
+			/*
+			 * There is a branch line to our left,
+			 * but it isn't our target.  We need to
+			 * cross over it.
+			 *
+			 * The space just to the left of this
+			 * branch should always be empty.
+			 */
+			assert(graph->new_mapping[i - 1] > target);
+			assert(graph->new_mapping[i - 2] < 0);
+			graph->new_mapping[i - 2] = target;
+		}
+	}
+
+	/*
+	 * The new mapping may be 1 smaller than the old mapping
+	 */
+	if (graph->new_mapping[graph->mapping_size - 1] < 0)
+		graph->mapping_size--;
+
+	/*
+	 * Output out a line based on the new mapping info
+	 */
+	for (i = 0; i < graph->mapping_size; i++) {
+		int target = graph->new_mapping[i];
+		if (target < 0)
+			strbuf_addch(sb, ' ');
+		else if (target * 2 == i)
+			strbuf_addch(sb, '|');
+		else
+			strbuf_addch(sb, '/');
+	}
+
+	graph_pad_horizontally(graph, sb);
+
+	/*
+	 * Swap mapping and new_mapping
+	 */
+	tmp_mapping = graph->mapping;
+	graph->mapping = graph->new_mapping;
+	graph->new_mapping = tmp_mapping;
+
+	/*
+	 * If graph->mapping indicates that all of the branch lines
+	 * are already in the correct positions, we are done.
+	 * Otherwise, we need to collapse some branch lines together.
+	 */
+	if (graph_is_mapping_correct(graph))
+		graph_update_state(graph, GRAPH_PADDING);
+}
+
+int graph_next_line(struct git_graph *graph, struct strbuf *sb)
+{
+	switch (graph->state) {
+	case GRAPH_PADDING:
+		graph_output_padding_line(graph, sb);
+		return 0;
+	case GRAPH_SKIP:
+		graph_output_skip_line(graph, sb);
+		return 0;
+	case GRAPH_PRE_COMMIT:
+		graph_output_pre_commit_line(graph, sb);
+		return 0;
+	case GRAPH_COMMIT:
+		graph_output_commit_line(graph, sb);
+		return 1;
+	case GRAPH_POST_MERGE:
+		graph_output_post_merge_line(graph, sb);
+		return 0;
+	case GRAPH_COLLAPSING:
+		graph_output_collapsing_line(graph, sb);
+		return 0;
+	}
+
+	assert(0);
+	return 0;
+}
+
+void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
+{
+	int i, j;
+
+	if (graph->state != GRAPH_COMMIT) {
+		graph_next_line(graph, sb);
+		return;
+	}
+
+	/*
+	 * Output the row containing this commit
+	 * Iterate up to and including graph->num_columns,
+	 * since the current commit may not be in any of the existing
+	 * columns.  (This happens when the current commit doesn't have any
+	 * children that we have already processed.)
+	 */
+	for (i = 0; i < graph->num_columns; i++) {
+		struct commit *col_commit = graph->columns[i].commit;
+		if (col_commit == graph->commit) {
+			strbuf_addch(sb, '|');
+
+			if (graph->num_parents < 3)
+				strbuf_addch(sb, ' ');
+			else {
+				int num_spaces = ((graph->num_parents - 2) * 2);
+				for (j = 0; j < num_spaces; j++)
+					strbuf_addch(sb, ' ');
+			}
+		} else {
+			strbuf_addstr(sb, "| ");
+		}
+	}
+
+	graph_pad_horizontally(graph, sb);
+
+	/*
+	 * Update graph->prev_state since we have output a padding line
+	 */
+	graph->prev_state = GRAPH_PADDING;
+}
+
+int graph_is_commit_finished(struct git_graph const *graph)
+{
+	return (graph->state == GRAPH_PADDING);
+}
+
+void graph_show_commit(struct git_graph *graph)
+{
+	struct strbuf msgbuf;
+	int shown_commit_line = 0;
+
+	if (!graph)
+		return;
+
+	strbuf_init(&msgbuf, 0);
+
+	while (!shown_commit_line) {
+		shown_commit_line = graph_next_line(graph, &msgbuf);
+		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		if (!shown_commit_line)
+			putchar('\n');
+		strbuf_setlen(&msgbuf, 0);
+	}
+
+	strbuf_release(&msgbuf);
+}
+
+void graph_show_oneline(struct git_graph *graph)
+{
+	struct strbuf msgbuf;
+
+	if (!graph)
+		return;
+
+	strbuf_init(&msgbuf, 0);
+	graph_next_line(graph, &msgbuf);
+	fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+	strbuf_release(&msgbuf);
+}
+
+void graph_show_padding(struct git_graph *graph)
+{
+	struct strbuf msgbuf;
+
+	if (!graph)
+		return;
+
+	strbuf_init(&msgbuf, 0);
+	graph_padding_line(graph, &msgbuf);
+	fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+	strbuf_release(&msgbuf);
+}
+
+int graph_show_remainder(struct git_graph *graph)
+{
+	struct strbuf msgbuf;
+	int shown = 0;
+
+	if (!graph)
+		return 0;
+
+	if (graph_is_commit_finished(graph))
+		return 0;
+
+	strbuf_init(&msgbuf, 0);
+	for (;;) {
+		graph_next_line(graph, &msgbuf);
+		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+		strbuf_setlen(&msgbuf, 0);
+		shown = 1;
+
+		if (!graph_is_commit_finished(graph))
+			putchar('\n');
+		else
+			break;
+	}
+	strbuf_release(&msgbuf);
+
+	return shown;
+}
+
+
+void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb)
+{
+	char *p;
+
+	if (!graph) {
+		fwrite(sb->buf, sizeof(char), sb->len, stdout);
+		return;
+	}
+
+	/*
+	 * Print the strbuf line by line,
+	 * and display the graph info before each line but the first.
+	 */
+	p = sb->buf;
+	while (p) {
+		size_t len;
+		char *next_p = strchr(p, '\n');
+		if (next_p) {
+			next_p++;
+			len = next_p - p;
+		} else {
+			len = (sb->buf + sb->len) - p;
+		}
+		fwrite(p, sizeof(char), len, stdout);
+		if (next_p && *next_p != '\0')
+			graph_show_oneline(graph);
+		p = next_p;
+	}
+}
+
+void graph_show_commit_msg(struct git_graph *graph,
+			   struct strbuf const *sb)
+{
+	int newline_terminated;
+
+	if (!graph) {
+		/*
+		 * If there's no graph, just print the message buffer.
+		 *
+		 * The message buffer for CMIT_FMT_ONELINE and
+		 * CMIT_FMT_USERFORMAT are already missing a terminating
+		 * newline.  All of the other formats should have it.
+		 */
+		fwrite(sb->buf, sizeof(char), sb->len, stdout);
+		return;
+	}
+
+	newline_terminated = (sb->len && sb->buf[sb->len - 1] == '\n');
+
+	/*
+	 * Show the commit message
+	 */
+	graph_show_strbuf(graph, sb);
+
+	/*
+	 * If there is more output needed for this commit, show it now
+	 */
+	if (!graph_is_commit_finished(graph)) {
+		/*
+		 * If sb doesn't have a terminating newline, print one now,
+		 * so we can start the remainder of the graph output on a
+		 * new line.
+		 */
+		if (!newline_terminated)
+			putchar('\n');
+
+		graph_show_remainder(graph);
+
+		/*
+		 * If sb ends with a newline, our output should too.
+		 */
+		if (newline_terminated)
+			putchar('\n');
+	}
+}
diff --git a/graph.h b/graph.h
new file mode 100644
index 0000000..eab4e3d
--- /dev/null
+++ b/graph.h
@@ -0,0 +1,121 @@
+#ifndef GRAPH_H
+#define GRAPH_H
+
+/* A graph is a pointer to this opaque structure */
+struct git_graph;
+
+/*
+ * Create a new struct git_graph.
+ * The graph should be freed with graph_release() when no longer needed.
+ */
+struct git_graph *graph_init(struct rev_info *opt);
+
+/*
+ * Destroy a struct git_graph and free associated memory.
+ */
+void graph_release(struct git_graph *graph);
+
+/*
+ * Update a git_graph with a new commit.
+ * This will cause the graph to begin outputting lines for the new commit
+ * the next time graph_next_line() is called.
+ *
+ * If graph_update() is called before graph_is_commit_finished() returns 1,
+ * the next call to graph_next_line() will output an ellipsis ("...")
+ * to indicate that a portion of the graph is missing.
+ */
+void graph_update(struct git_graph *graph, struct commit *commit);
+
+/*
+ * Output the next line for a graph.
+ * This formats the next graph line into the specified strbuf.  It is not
+ * terminated with a newline.
+ *
+ * Returns 1 if the line includes the current commit, and 0 otherwise.
+ * graph_next_line() will return 1 exactly once for each time
+ * graph_update() is called.
+ */
+int graph_next_line(struct git_graph *graph, struct strbuf *sb);
+
+/*
+ * Output a padding line in the graph.
+ * This is similar to graph_next_line().  However, it is guaranteed to
+ * never print the current commit line.  Instead, if the commit line is
+ * next, it will simply output a line of vertical padding, extending the
+ * branch lines downwards, but leaving them otherwise unchanged.
+ */
+void graph_padding_line(struct git_graph *graph, struct strbuf *sb);
+
+/*
+ * Determine if a graph has finished outputting lines for the current
+ * commit.
+ *
+ * Returns 1 if graph_next_line() needs to be called again before
+ * graph_update() should be called.  Returns 0 if no more lines are needed
+ * for this commit.  If 0 is returned, graph_next_line() may still be
+ * called without calling graph_update(), and it will merely output
+ * appropriate "vertical padding" in the graph.
+ */
+int graph_is_commit_finished(struct git_graph const *graph);
+
+
+/*
+ * graph_show_*: helper functions for printing to stdout
+ */
+
+
+/*
+ * If the graph is non-NULL, print the history graph to stdout,
+ * up to and including the line containing this commit.
+ * Does not print a terminating newline on the last line.
+ */
+void graph_show_commit(struct git_graph *graph);
+
+/*
+ * If the graph is non-NULL, print one line of the history graph to stdout.
+ * Does not print a terminating newline on the last line.
+ */
+void graph_show_oneline(struct git_graph *graph);
+
+/*
+ * If the graph is non-NULL, print one line of vertical graph padding to
+ * stdout.  Does not print a terminating newline on the last line.
+ */
+void graph_show_padding(struct git_graph *graph);
+
+/*
+ * If the graph is non-NULL, print the rest of the history graph for this
+ * commit to stdout.  Does not print a terminating newline on the last line.
+ */
+int graph_show_remainder(struct git_graph *graph);
+
+/*
+ * Print a strbuf to stdout.  If the graph is non-NULL, all lines but the
+ * first will be prefixed with the graph output.
+ *
+ * If the strbuf ends with a newline, the output will end after this
+ * newline.  A new graph line will not be printed after the final newline.
+ * If the strbuf is empty, no output will be printed.
+ *
+ * Since the first line will not include the graph ouput, the caller is
+ * responsible for printing this line's graph (perhaps via
+ * graph_show_commit() or graph_show_oneline()) before calling
+ * graph_show_strbuf().
+ */
+void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb);
+
+/*
+ * Print a commit message strbuf and the remainder of the graph to stdout.
+ *
+ * This is similar to graph_show_strbuf(), but it always prints the
+ * remainder of the graph.
+ *
+ * If the strbuf ends with a newline, the output printed by
+ * graph_show_commit_msg() will end with a newline.  If the strbuf is
+ * missing a terminating newline (including if it is empty), the output
+ * printed by graph_show_commit_msg() will also be missing a terminating
+ * newline.
+ */
+void graph_show_commit_msg(struct git_graph *graph, struct strbuf const *sb);
+
+#endif /* GRAPH_H */
diff --git a/hash-object.c b/hash-object.c
index 61e7160..48d5223 100644
--- a/hash-object.c
+++ b/hash-object.c
@@ -6,6 +6,7 @@
  */
 #include "cache.h"
 #include "blob.h"
+#include "quote.h"
 
 static void hash_object(const char *path, enum object_type type, int write_object)
 {
@@ -20,6 +21,7 @@
 		    ? "Unable to add %s to database"
 		    : "Unable to hash %s", path);
 	printf("%s\n", sha1_to_hex(sha1));
+	maybe_flush_or_die(stdout, "hash to stdout");
 }
 
 static void hash_stdin(const char *type, int write_object)
@@ -30,8 +32,27 @@
 	printf("%s\n", sha1_to_hex(sha1));
 }
 
+static void hash_stdin_paths(const char *type, int write_objects)
+{
+	struct strbuf buf, nbuf;
+
+	strbuf_init(&buf, 0);
+	strbuf_init(&nbuf, 0);
+	while (strbuf_getline(&buf, stdin, '\n') != EOF) {
+		if (buf.buf[0] == '"') {
+			strbuf_reset(&nbuf);
+			if (unquote_c_style(&nbuf, buf.buf, NULL))
+				die("line is badly quoted");
+			strbuf_swap(&buf, &nbuf);
+		}
+		hash_object(buf.buf, type_from_string(type), write_objects);
+	}
+	strbuf_release(&buf);
+	strbuf_release(&nbuf);
+}
+
 static const char hash_object_usage[] =
-"git-hash-object [-t <type>] [-w] [--stdin] <file>...";
+"git-hash-object [ [-t <type>] [-w] [--stdin] <file>... | --stdin-paths < <list-of-paths> ]";
 
 int main(int argc, char **argv)
 {
@@ -42,8 +63,9 @@
 	int prefix_length = -1;
 	int no_more_flags = 0;
 	int hashstdin = 0;
+	int stdin_paths = 0;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	for (i = 1 ; i < argc; i++) {
 		if (!no_more_flags && argv[i][0] == '-') {
@@ -65,7 +87,19 @@
 			}
 			else if (!strcmp(argv[i], "--help"))
 				usage(hash_object_usage);
+			else if (!strcmp(argv[i], "--stdin-paths")) {
+				if (hashstdin) {
+					error("Can't use --stdin-paths with --stdin");
+					usage(hash_object_usage);
+				}
+				stdin_paths = 1;
+
+			}
 			else if (!strcmp(argv[i], "--stdin")) {
+				if (stdin_paths) {
+					error("Can't use %s with --stdin-paths", argv[i]);
+					usage(hash_object_usage);
+				}
 				if (hashstdin)
 					die("Multiple --stdin arguments are not supported");
 				hashstdin = 1;
@@ -76,6 +110,11 @@
 		else {
 			const char *arg = argv[i];
 
+			if (stdin_paths) {
+				error("Can't specify files (such as \"%s\") with --stdin-paths", arg);
+				usage(hash_object_usage);
+			}
+
 			if (hashstdin) {
 				hash_stdin(type, write_object);
 				hashstdin = 0;
@@ -87,6 +126,10 @@
 			no_more_flags = 1;
 		}
 	}
+
+	if (stdin_paths)
+		hash_stdin_paths(type, write_object);
+
 	if (hashstdin)
 		hash_stdin(type, write_object);
 	return 0;
diff --git a/help.c b/help.c
index 10298fb..8aff94c 100644
--- a/help.c
+++ b/help.c
@@ -11,10 +11,16 @@
 #include "run-command.h"
 
 static struct man_viewer_list {
-	void (*exec)(const char *);
 	struct man_viewer_list *next;
+	char name[FLEX_ARRAY];
 } *man_viewer_list;
 
+static struct man_viewer_info_list {
+	struct man_viewer_info_list *next;
+	const char *info;
+	char name[FLEX_ARRAY];
+} *man_viewer_info_list;
+
 enum help_format {
 	HELP_FORMAT_MAN,
 	HELP_FORMAT_INFO,
@@ -49,6 +55,18 @@
 	die("unrecognized help format '%s'", format);
 }
 
+static const char *get_man_viewer_info(const char *name)
+{
+	struct man_viewer_info_list *viewer;
+
+	for (viewer = man_viewer_info_list; viewer; viewer = viewer->next)
+	{
+		if (!strcasecmp(name, viewer->name))
+			return viewer->info;
+	}
+	return NULL;
+}
+
 static int check_emacsclient_version(void)
 {
 	struct strbuf buffer = STRBUF_INIT;
@@ -95,57 +113,146 @@
 	return 0;
 }
 
-static void exec_woman_emacs(const char *page)
+static void exec_woman_emacs(const char* path, const char *page)
 {
 	if (!check_emacsclient_version()) {
 		/* This works only with emacsclient version >= 22. */
 		struct strbuf man_page = STRBUF_INIT;
+
+		if (!path)
+			path = "emacsclient";
 		strbuf_addf(&man_page, "(woman \"%s\")", page);
-		execlp("emacsclient", "emacsclient", "-e", man_page.buf, NULL);
+		execlp(path, "emacsclient", "-e", man_page.buf, NULL);
+		warning("failed to exec '%s': %s", path, strerror(errno));
 	}
 }
 
-static void exec_man_konqueror(const char *page)
+static void exec_man_konqueror(const char* path, const char *page)
 {
 	const char *display = getenv("DISPLAY");
 	if (display && *display) {
 		struct strbuf man_page = STRBUF_INIT;
+		const char *filename = "kfmclient";
+
+		/* It's simpler to launch konqueror using kfmclient. */
+		if (path) {
+			const char *file = strrchr(path, '/');
+			if (file && !strcmp(file + 1, "konqueror")) {
+				char *new = xstrdup(path);
+				char *dest = strrchr(new, '/');
+
+				/* strlen("konqueror") == strlen("kfmclient") */
+				strcpy(dest + 1, "kfmclient");
+				path = new;
+			}
+			if (file)
+				filename = file;
+		} else
+			path = "kfmclient";
 		strbuf_addf(&man_page, "man:%s(1)", page);
-		execlp("kfmclient", "kfmclient", "newTab", man_page.buf, NULL);
+		execlp(path, filename, "newTab", man_page.buf, NULL);
+		warning("failed to exec '%s': %s", path, strerror(errno));
 	}
 }
 
-static void exec_man_man(const char *page)
+static void exec_man_man(const char* path, const char *page)
 {
-	execlp("man", "man", page, NULL);
+	if (!path)
+		path = "man";
+	execlp(path, "man", page, NULL);
+	warning("failed to exec '%s': %s", path, strerror(errno));
 }
 
-static void do_add_man_viewer(void (*exec)(const char *))
+static void exec_man_cmd(const char *cmd, const char *page)
+{
+	struct strbuf shell_cmd = STRBUF_INIT;
+	strbuf_addf(&shell_cmd, "%s %s", cmd, page);
+	execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL);
+	warning("failed to exec '%s': %s", cmd, strerror(errno));
+}
+
+static void add_man_viewer(const char *name)
 {
 	struct man_viewer_list **p = &man_viewer_list;
+	size_t len = strlen(name);
 
 	while (*p)
 		p = &((*p)->next);
-	*p = xmalloc(sizeof(**p));
-	(*p)->next = NULL;
-	(*p)->exec = exec;
+	*p = xcalloc(1, (sizeof(**p) + len + 1));
+	strncpy((*p)->name, name, len);
 }
 
-static int add_man_viewer(const char *value)
+static int supported_man_viewer(const char *name, size_t len)
 {
-	if (!strcasecmp(value, "man"))
-		do_add_man_viewer(exec_man_man);
-	else if (!strcasecmp(value, "woman"))
-		do_add_man_viewer(exec_woman_emacs);
-	else if (!strcasecmp(value, "konqueror"))
-		do_add_man_viewer(exec_man_konqueror);
+	return (!strncasecmp("man", name, len) ||
+		!strncasecmp("woman", name, len) ||
+		!strncasecmp("konqueror", name, len));
+}
+
+static void do_add_man_viewer_info(const char *name,
+				   size_t len,
+				   const char *value)
+{
+	struct man_viewer_info_list *new = xcalloc(1, sizeof(*new) + len + 1);
+
+	strncpy(new->name, name, len);
+	new->info = xstrdup(value);
+	new->next = man_viewer_info_list;
+	man_viewer_info_list = new;
+}
+
+static int add_man_viewer_path(const char *name,
+			       size_t len,
+			       const char *value)
+{
+	if (supported_man_viewer(name, len))
+		do_add_man_viewer_info(name, len, value);
 	else
-		warning("'%s': unsupported man viewer.", value);
+		warning("'%s': path for unsupported man viewer.\n"
+			"Please consider using 'man.<tool>.cmd' instead.",
+			name);
 
 	return 0;
 }
 
-static int git_help_config(const char *var, const char *value)
+static int add_man_viewer_cmd(const char *name,
+			      size_t len,
+			      const char *value)
+{
+	if (supported_man_viewer(name, len))
+		warning("'%s': cmd for supported man viewer.\n"
+			"Please consider using 'man.<tool>.path' instead.",
+			name);
+	else
+		do_add_man_viewer_info(name, len, value);
+
+	return 0;
+}
+
+static int add_man_viewer_info(const char *var, const char *value)
+{
+	const char *name = var + 4;
+	const char *subkey = strrchr(name, '.');
+
+	if (!subkey)
+		return error("Config with no key for man viewer: %s", name);
+
+	if (!strcmp(subkey, ".path")) {
+		if (!value)
+			return config_error_nonbool(var);
+		return add_man_viewer_path(name, subkey - name, value);
+	}
+	if (!strcmp(subkey, ".cmd")) {
+		if (!value)
+			return config_error_nonbool(var);
+		return add_man_viewer_cmd(name, subkey - name, value);
+	}
+
+	warning("'%s': unsupported man viewer sub key.", subkey);
+	return 0;
+}
+
+static int git_help_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "help.format")) {
 		if (!value)
@@ -156,9 +263,13 @@
 	if (!strcmp(var, "man.viewer")) {
 		if (!value)
 			return config_error_nonbool(var);
-		return add_man_viewer(value);
+		add_man_viewer(value);
+		return 0;
 	}
-	return git_default_config(var, value);
+	if (!prefixcmp(var, "man."))
+		return add_man_viewer_info(var, value);
+
+	return git_default_config(var, value, cb);
 }
 
 /* most GUI terminals set COLUMNS (although some don't export it) */
@@ -453,6 +564,22 @@
 	strbuf_release(&new_path);
 }
 
+static void exec_viewer(const char *name, const char *page)
+{
+	const char *info = get_man_viewer_info(name);
+
+	if (!strcasecmp(name, "man"))
+		exec_man_man(info, page);
+	else if (!strcasecmp(name, "woman"))
+		exec_woman_emacs(info, page);
+	else if (!strcasecmp(name, "konqueror"))
+		exec_man_konqueror(info, page);
+	else if (info)
+		exec_man_cmd(info, page);
+	else
+		warning("'%s': unknown man viewer.", name);
+}
+
 static void show_man_page(const char *git_cmd)
 {
 	struct man_viewer_list *viewer;
@@ -461,9 +588,9 @@
 	setup_man_path();
 	for (viewer = man_viewer_list; viewer; viewer = viewer->next)
 	{
-		viewer->exec(page); /* will return when unable */
+		exec_viewer(viewer->name, page); /* will return when unable */
 	}
-	exec_man_man(page);
+	exec_viewer("man", page);
 	die("no man viewer handled the request");
 }
 
@@ -514,7 +641,7 @@
 	const char *alias;
 
 	setup_git_directory_gently(&nongit);
-	git_config(git_help_config);
+	git_config(git_help_config, NULL);
 
 	argc = parse_options(argc, argv, builtin_help_options,
 			builtin_help_usage, 0);
@@ -522,12 +649,14 @@
 	if (show_all) {
 		printf("usage: %s\n\n", git_usage_string);
 		list_commands();
+		printf("%s\n", git_more_info_string);
 		return 0;
 	}
 
 	if (!argv[0]) {
 		printf("usage: %s\n\n", git_usage_string);
 		list_common_cmds_help();
+		printf("\n%s\n", git_more_info_string);
 		return 0;
 	}
 
diff --git a/http-push.c b/http-push.c
index 5b23038..665712a 100644
--- a/http-push.c
+++ b/http-push.c
@@ -9,6 +9,7 @@
 #include "revision.h"
 #include "exec_cmd.h"
 #include "remote.h"
+#include "list-objects.h"
 
 #include <expat.h>
 
@@ -1349,6 +1350,24 @@
 	return rc;
 }
 
+static void remove_locks(void)
+{
+	struct remote_lock *lock = remote->locks;
+
+	fprintf(stderr, "Removing remote locks...\n");
+	while (lock) {
+		unlock_remote(lock);
+		lock = lock->next;
+	}
+}
+
+static void remove_locks_on_signal(int signo)
+{
+	remove_locks();
+	signal(signo, SIG_DFL);
+	raise(signo);
+}
+
 static void remote_ls(const char *path, int flags,
 		      void (*userFunc)(struct remote_ls_ctx *ls),
 		      void *userData);
@@ -1759,15 +1778,15 @@
 static void one_remote_ref(char *refname)
 {
 	struct ref *ref;
-	unsigned char remote_sha1[20];
 	struct object *obj;
-	int len = strlen(refname) + 1;
 
-	if (http_fetch_ref(remote->url, refname + 5 /* "refs/" */,
-			   remote_sha1) != 0) {
+	ref = alloc_ref_from_str(refname);
+
+	if (http_fetch_ref(remote->url, ref) != 0) {
 		fprintf(stderr,
 			"Unable to fetch ref %s from %s\n",
 			refname, remote->url);
+		free(ref);
 		return;
 	}
 
@@ -1775,18 +1794,15 @@
 	 * Fetch a copy of the object if it doesn't exist locally - it
 	 * may be required for updating server info later.
 	 */
-	if (remote->can_update_info_refs && !has_sha1_file(remote_sha1)) {
-		obj = lookup_unknown_object(remote_sha1);
+	if (remote->can_update_info_refs && !has_sha1_file(ref->old_sha1)) {
+		obj = lookup_unknown_object(ref->old_sha1);
 		if (obj) {
 			fprintf(stderr,	"  fetch %s for %s\n",
-				sha1_to_hex(remote_sha1), refname);
+				sha1_to_hex(ref->old_sha1), refname);
 			add_fetch_request(obj);
 		}
 	}
 
-	ref = xcalloc(1, sizeof(*ref) + len);
-	hashcpy(ref->old_sha1, remote_sha1);
-	memcpy(ref->name, refname, len);
 	*remote_tail = ref;
 	remote_tail = &ref->next;
 }
@@ -1863,61 +1879,39 @@
 	return found;
 }
 
-static void mark_edge_parents_uninteresting(struct commit *commit)
-{
-	struct commit_list *parents;
-
-	for (parents = commit->parents; parents; parents = parents->next) {
-		struct commit *parent = parents->item;
-		if (!(parent->object.flags & UNINTERESTING))
-			continue;
-		mark_tree_uninteresting(parent->tree);
-	}
-}
-
-static void mark_edges_uninteresting(struct commit_list *list)
-{
-	for ( ; list; list = list->next) {
-		struct commit *commit = list->item;
-
-		if (commit->object.flags & UNINTERESTING) {
-			mark_tree_uninteresting(commit->tree);
-			continue;
-		}
-		mark_edge_parents_uninteresting(commit);
-	}
-}
-
 static void add_remote_info_ref(struct remote_ls_ctx *ls)
 {
 	struct strbuf *buf = (struct strbuf *)ls->userData;
-	unsigned char remote_sha1[20];
 	struct object *o;
 	int len;
 	char *ref_info;
+	struct ref *ref;
 
-	if (http_fetch_ref(remote->url, ls->dentry_name + 5 /* "refs/" */,
-			   remote_sha1) != 0) {
+	ref = alloc_ref_from_str(ls->dentry_name);
+
+	if (http_fetch_ref(remote->url, ref) != 0) {
 		fprintf(stderr,
 			"Unable to fetch ref %s from %s\n",
 			ls->dentry_name, remote->url);
 		aborted = 1;
+		free(ref);
 		return;
 	}
 
-	o = parse_object(remote_sha1);
+	o = parse_object(ref->old_sha1);
 	if (!o) {
 		fprintf(stderr,
 			"Unable to parse object %s for remote ref %s\n",
-			sha1_to_hex(remote_sha1), ls->dentry_name);
+			sha1_to_hex(ref->old_sha1), ls->dentry_name);
 		aborted = 1;
+		free(ref);
 		return;
 	}
 
 	len = strlen(ls->dentry_name) + 42;
 	ref_info = xcalloc(len + 1, 1);
 	sprintf(ref_info, "%s	%s\n",
-		sha1_to_hex(remote_sha1), ls->dentry_name);
+		sha1_to_hex(ref->old_sha1), ls->dentry_name);
 	fwrite_buffer(ref_info, 1, len, buf);
 	free(ref_info);
 
@@ -1932,6 +1926,7 @@
 			free(ref_info);
 		}
 	}
+	free(ref);
 }
 
 static void update_remote_info_refs(struct remote_lock *lock)
@@ -2255,6 +2250,11 @@
 		goto cleanup;
 	}
 
+	signal(SIGINT, remove_locks_on_signal);
+	signal(SIGHUP, remove_locks_on_signal);
+	signal(SIGQUIT, remove_locks_on_signal);
+	signal(SIGTERM, remove_locks_on_signal);
+
 	/* Check whether the remote has server info files */
 	remote->can_update_info_refs = 0;
 	remote->has_info_refs = remote_exists("info/refs");
@@ -2384,6 +2384,7 @@
 		}
 		init_revisions(&revs, setup_git_directory());
 		setup_revisions(commit_argc, commit_argv, &revs, NULL);
+		revs.edge_hint = 0; /* just in case */
 		free(new_sha1_hex);
 		if (old_sha1_hex) {
 			free(old_sha1_hex);
@@ -2394,7 +2395,7 @@
 		pushing = 0;
 		if (prepare_revision_walk(&revs))
 			die("revision walk setup failed");
-		mark_edges_uninteresting(revs.commits);
+		mark_edges_uninteresting(revs.commits, &revs, NULL);
 		objects_to_send = get_delta(&revs, ref_lock);
 		finish_all_active_slots();
 
diff --git a/http-walker.c b/http-walker.c
index 7bda34d..7403306 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;
@@ -888,10 +890,10 @@
 		     data->alt->base);
 }
 
-static int fetch_ref(struct walker *walker, char *ref, unsigned char *sha1)
+static int fetch_ref(struct walker *walker, struct ref *ref)
 {
 	struct walker_data *data = walker->data;
-	return http_fetch_ref(data->alt->base, ref, sha1);
+	return http_fetch_ref(data->alt->base, ref);
 }
 
 static void cleanup(struct walker *walker)
diff --git a/http.c b/http.c
index 256a5f1..1108ab4 100644
--- a/http.c
+++ b/http.c
@@ -13,14 +13,14 @@
 char curl_errorstr[CURL_ERROR_SIZE];
 
 static int curl_ssl_verify = -1;
-static char *ssl_cert = NULL;
+static const char *ssl_cert = NULL;
 #if LIBCURL_VERSION_NUM >= 0x070902
-static char *ssl_key = NULL;
+static const char *ssl_key = NULL;
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
-static char *ssl_capath = NULL;
+static const char *ssl_capath = NULL;
 #endif
-static char *ssl_cainfo = NULL;
+static const char *ssl_cainfo = NULL;
 static long curl_low_speed_limit = -1;
 static long curl_low_speed_time = -1;
 static int curl_ftp_no_epsv = 0;
@@ -30,10 +30,11 @@
 
 static struct active_request_slot *active_queue_head = NULL;
 
-size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb,
-			   struct buffer *buffer)
+size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, void *buffer_)
 {
 	size_t size = eltsize * nmemb;
+	struct buffer *buffer = buffer_;
+
 	if (size > buffer->buf.len - buffer->posn)
 		size = buffer->buf.len - buffer->posn;
 	memcpy(ptr, buffer->buf.buf + buffer->posn, size);
@@ -42,17 +43,17 @@
 	return size;
 }
 
-size_t fwrite_buffer(const void *ptr, size_t eltsize,
-			    size_t nmemb, struct strbuf *buffer)
+size_t fwrite_buffer(const void *ptr, size_t eltsize, size_t nmemb, void *buffer_)
 {
 	size_t size = eltsize * nmemb;
+	struct strbuf *buffer = buffer_;
+
 	strbuf_add(buffer, ptr, size);
 	data_received++;
 	return size;
 }
 
-size_t fwrite_null(const void *ptr, size_t eltsize,
-			  size_t nmemb, struct strbuf *buffer)
+size_t fwrite_null(const void *ptr, size_t eltsize, size_t nmemb, void *strbuf)
 {
 	data_received++;
 	return eltsize * nmemb;
@@ -90,7 +91,7 @@
 }
 #endif
 
-static int http_options(const char *var, const char *value)
+static int http_options(const char *var, const char *value, void *cb)
 {
 	if (!strcmp("http.sslverify", var)) {
 		if (curl_ssl_verify == -1) {
@@ -100,39 +101,27 @@
 	}
 
 	if (!strcmp("http.sslcert", var)) {
-		if (ssl_cert == NULL) {
-			if (!value)
-				return config_error_nonbool(var);
-			ssl_cert = xstrdup(value);
-		}
+		if (ssl_cert == NULL)
+			return git_config_string(&ssl_cert, var, value);
 		return 0;
 	}
 #if LIBCURL_VERSION_NUM >= 0x070902
 	if (!strcmp("http.sslkey", var)) {
-		if (ssl_key == NULL) {
-			if (!value)
-				return config_error_nonbool(var);
-			ssl_key = xstrdup(value);
-		}
+		if (ssl_key == NULL)
+			return git_config_string(&ssl_key, var, value);
 		return 0;
 	}
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
 	if (!strcmp("http.sslcapath", var)) {
-		if (ssl_capath == NULL) {
-			if (!value)
-				return config_error_nonbool(var);
-			ssl_capath = xstrdup(value);
-		}
+		if (ssl_capath == NULL)
+			return git_config_string(&ssl_capath, var, value);
 		return 0;
 	}
 #endif
 	if (!strcmp("http.sslcainfo", var)) {
-		if (ssl_cainfo == NULL) {
-			if (!value)
-				return config_error_nonbool(var);
-			ssl_cainfo = xstrdup(value);
-		}
+		if (ssl_cainfo == NULL)
+			return git_config_string(&ssl_cainfo, var, value);
 		return 0;
 	}
 
@@ -169,7 +158,7 @@
 	}
 
 	/* Fall back on the default ones */
-	return git_default_config(var, value);
+	return git_default_config(var, value, cb);
 }
 
 static CURL* get_curl_handle(void)
@@ -263,7 +252,7 @@
 	if (low_speed_time != NULL)
 		curl_low_speed_time = strtol(low_speed_time, NULL, 10);
 
-	git_config(http_options);
+	git_config(http_options, NULL);
 
 	if (curl_ssl_verify == -1)
 		curl_ssl_verify = 1;
@@ -583,14 +572,15 @@
 	int len, baselen, ch;
 
 	baselen = strlen(base);
-	len = baselen + 7; /* "/refs/" + NUL */
+	len = baselen + 2; /* '/' after base and terminating NUL */
 	for (cp = ref; (ch = *cp) != 0; cp++, len++)
 		if (needs_quote(ch))
 			len += 2; /* extra two hex plus replacement % */
 	qref = xmalloc(len);
 	memcpy(qref, base, baselen);
-	memcpy(qref + baselen, "/refs/", 6);
-	for (cp = ref, dp = qref + baselen + 6; (ch = *cp) != 0; cp++) {
+	dp = qref + baselen;
+	*(dp++) = '/';
+	for (cp = ref; (ch = *cp) != 0; cp++) {
 		if (needs_quote(ch)) {
 			*dp++ = '%';
 			*dp++ = hex((ch >> 4) & 0xF);
@@ -604,7 +594,7 @@
 	return qref;
 }
 
-int http_fetch_ref(const char *base, const char *ref, unsigned char *sha1)
+int http_fetch_ref(const char *base, struct ref *ref)
 {
 	char *url;
 	struct strbuf buffer = STRBUF_INIT;
@@ -612,7 +602,7 @@
 	struct slot_results results;
 	int ret;
 
-	url = quote_ref_url(base, ref);
+	url = quote_ref_url(base, ref->name);
 	slot = get_active_slot();
 	slot->results = &results;
 	curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
@@ -624,12 +614,15 @@
 		if (results.curl_result == CURLE_OK) {
 			strbuf_rtrim(&buffer);
 			if (buffer.len == 40)
-				ret = get_sha1_hex(buffer.buf, sha1);
-			else
+				ret = get_sha1_hex(buffer.buf, ref->old_sha1);
+			else if (!prefixcmp(buffer.buf, "ref: ")) {
+				ref->symref = xstrdup(buffer.buf + 5);
+				ret = 0;
+			} else
 				ret = 1;
 		} else {
 			ret = error("Couldn't get %s for %s\n%s",
-				    url, ref, curl_errorstr);
+				    url, ref->name, curl_errorstr);
 		}
 	} else {
 		ret = error("Unable to start request");
diff --git a/http.h b/http.h
index 04169d5..905b462 100644
--- a/http.h
+++ b/http.h
@@ -64,12 +64,9 @@
 };
 
 /* Curl request read/write callbacks */
-extern size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb,
-			   struct buffer *buffer);
-extern size_t fwrite_buffer(const void *ptr, size_t eltsize,
-			    size_t nmemb, struct strbuf *buffer);
-extern size_t fwrite_null(const void *ptr, size_t eltsize,
-			  size_t nmemb, struct strbuf *buffer);
+extern size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, void *strbuf);
+extern size_t fwrite_buffer(const void *ptr, size_t eltsize, size_t nmemb, void *strbuf);
+extern size_t fwrite_null(const void *ptr, size_t eltsize, size_t nmemb, void *strbuf);
 
 /* Slot lifecycle functions */
 extern struct active_request_slot *get_active_slot(void);
@@ -105,6 +102,6 @@
 
 #define missing_target(a) missing__target((a)->http_code, (a)->curl_result)
 
-extern int http_fetch_ref(const char *base, const char *ref, unsigned char *sha1);
+extern int http_fetch_ref(const char *base, struct ref *ref);
 
 #endif /* HTTP_H */
diff --git a/ident.c b/ident.c
index ed44a53..b35504a 100644
--- a/ident.c
+++ b/ident.c
@@ -250,6 +250,9 @@
 
 const char *git_committer_info(int flag)
 {
+	if (getenv("GIT_COMMITTER_NAME") &&
+	    getenv("GIT_COMMITTER_EMAIL"))
+		user_ident_explicitly_given = 1;
 	return fmt_ident(getenv("GIT_COMMITTER_NAME"),
 			 getenv("GIT_COMMITTER_EMAIL"),
 			 getenv("GIT_COMMITTER_DATE"),
diff --git a/imap-send.c b/imap-send.c
index db65597..1ec1310 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -1247,7 +1247,7 @@
 static char *imap_folder;
 
 static int
-git_imap_config(const char *key, const char *val)
+git_imap_config(const char *key, const char *val, void *cb)
 {
 	char imap_key[] = "imap.";
 
@@ -1296,7 +1296,7 @@
 	/* init the random number generator */
 	arc4_init();
 
-	git_config( git_imap_config );
+	git_config(git_imap_config, NULL);
 
 	if (!imap_folder) {
 		fprintf( stderr, "no imap store specified\n" );
diff --git a/index-pack.c b/index-pack.c
index 9c0c278..7d5344a 100644
--- a/index-pack.c
+++ b/index-pack.c
@@ -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;
@@ -210,6 +220,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;
@@ -425,33 +475,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);
 		}
 	}
 
@@ -461,11 +538,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)
@@ -480,7 +557,6 @@
 {
 	int i;
 	struct delta_entry *delta = deltas;
-	void *data;
 	struct stat st;
 
 	/*
@@ -495,7 +571,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++;
@@ -544,6 +620,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;
@@ -554,22 +631,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);
 	}
 }
@@ -600,7 +679,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++];
@@ -618,9 +698,14 @@
 	write_or_die(output_fd, header, n);
 	obj[0].idx.crc32 = crc32(0, Z_NULL, 0);
 	obj[0].idx.crc32 = crc32(obj[0].idx.crc32, header, n);
+	obj[0].size = size;
+	obj[0].hdr_size = n;
+	obj[0].type = type;
+	obj[0].real_type = type;
 	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)
@@ -655,28 +740,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);
@@ -694,6 +782,7 @@
 	if (!from_stdin) {
 		close(input_fd);
 	} else {
+		fsync_or_die(output_fd, curr_pack_name);
 		err = close(output_fd);
 		if (err)
 			die("error while closing pack file: %s", strerror(errno));
@@ -765,7 +854,7 @@
 	}
 }
 
-static int git_index_pack_config(const char *k, const char *v)
+static int git_index_pack_config(const char *k, const char *v, void *cb)
 {
 	if (!strcmp(k, "pack.indexversion")) {
 		pack_idx_default_version = git_config_int(k, v);
@@ -773,7 +862,7 @@
 			die("bad pack.indexversion=%d", pack_idx_default_version);
 		return 0;
 	}
-	return git_default_config(k, v);
+	return git_default_config(k, v, cb);
 }
 
 int main(int argc, char **argv)
@@ -786,7 +875,7 @@
 	struct pack_idx_entry **idx_objects;
 	unsigned char sha1[20];
 
-	git_config(git_index_pack_config);
+	git_config(git_index_pack_config, NULL);
 
 	for (i = 1; i < argc; i++) {
 		char *arg = argv[i];
diff --git a/ll-merge.c b/ll-merge.c
index 5ae7433..9837c84 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -225,7 +225,7 @@
 static struct ll_merge_driver *ll_user_merge, **ll_user_merge_tail;
 static const char *default_ll_merge;
 
-static int read_merge_config(const char *var, const char *value)
+static int read_merge_config(const char *var, const char *value, void *cb)
 {
 	struct ll_merge_driver *fn;
 	const char *ep, *name;
@@ -309,7 +309,7 @@
 	if (ll_user_merge_tail)
 		return;
 	ll_user_merge_tail = &ll_user_merge;
-	git_config(read_merge_config);
+	git_config(read_merge_config, NULL);
 }
 
 static const struct ll_merge_driver *find_ll_merge_driver(const char *merge_attr)
diff --git a/lockfile.c b/lockfile.c
index 663f18f..4023797 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -24,7 +24,7 @@
 static void remove_lock_file_on_signal(int signo)
 {
 	remove_lock_file();
-	signal(SIGINT, SIG_DFL);
+	signal(signo, SIG_DFL);
 	raise(signo);
 }
 
@@ -135,6 +135,9 @@
 	if (0 <= lk->fd) {
 		if (!lock_file_list) {
 			signal(SIGINT, remove_lock_file_on_signal);
+			signal(SIGHUP, remove_lock_file_on_signal);
+			signal(SIGTERM, remove_lock_file_on_signal);
+			signal(SIGQUIT, remove_lock_file_on_signal);
 			atexit(remove_lock_file);
 		}
 		lk->owner = getpid();
@@ -160,6 +163,34 @@
 	return fd;
 }
 
+int hold_lock_file_for_append(struct lock_file *lk, const char *path, int die_on_error)
+{
+	int fd, orig_fd;
+
+	fd = lock_file(lk, path);
+	if (fd < 0) {
+		if (die_on_error)
+			die("unable to create '%s.lock': %s", path, strerror(errno));
+		return fd;
+	}
+
+	orig_fd = open(path, O_RDONLY);
+	if (orig_fd < 0) {
+		if (errno != ENOENT) {
+			if (die_on_error)
+				die("cannot open '%s' for copying", path);
+			close(fd);
+			return error("cannot open '%s' for copying", path);
+		}
+	} else if (copy_fd(orig_fd, fd)) {
+		if (die_on_error)
+			exit(128);
+		close(fd);
+		return -1;
+	}
+	return fd;
+}
+
 int close_lock_file(struct lock_file *lk)
 {
 	int fd = lk->fd;
diff --git a/log-tree.c b/log-tree.c
index 5b29639..5505606 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "diff.h"
 #include "commit.h"
+#include "graph.h"
 #include "log-tree.h"
 #include "reflog-walk.h"
 
@@ -165,11 +166,16 @@
 	}
 
 	printf("From %s Mon Sep 17 00:00:00 2001\n", name);
-	if (opt->message_id)
+	graph_show_oneline(opt->graph);
+	if (opt->message_id) {
 		printf("Message-Id: <%s>\n", opt->message_id);
-	if (opt->ref_message_id)
+		graph_show_oneline(opt->graph);
+	}
+	if (opt->ref_message_id) {
 		printf("In-Reply-To: <%s>\nReferences: <%s>\n",
 		       opt->ref_message_id, opt->ref_message_id);
+		graph_show_oneline(opt->graph);
+	}
 	if (opt->mime_boundary) {
 		static char subject_buffer[1024];
 		static char buffer[1024];
@@ -208,54 +214,76 @@
 	*extra_headers_p = extra_headers;
 }
 
-void show_log(struct rev_info *opt, const char *sep)
+void show_log(struct rev_info *opt)
 {
 	struct strbuf msgbuf;
 	struct log_info *log = opt->loginfo;
 	struct commit *commit = log->commit, *parent = log->parent;
 	int abbrev = opt->diffopt.abbrev;
 	int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40;
-	const char *extra;
 	const char *subject = NULL, *extra_headers = opt->extra_headers;
 	int need_8bit_cte = 0;
 
 	opt->loginfo = NULL;
 	if (!opt->verbose_header) {
-		if (commit->object.flags & BOUNDARY)
-			putchar('-');
-		else if (commit->object.flags & UNINTERESTING)
-			putchar('^');
-		else if (opt->left_right) {
-			if (commit->object.flags & SYMMETRIC_LEFT)
-				putchar('<');
-			else
-				putchar('>');
+		graph_show_commit(opt->graph);
+
+		if (!opt->graph) {
+			if (commit->object.flags & BOUNDARY)
+				putchar('-');
+			else if (commit->object.flags & UNINTERESTING)
+				putchar('^');
+			else if (opt->left_right) {
+				if (commit->object.flags & SYMMETRIC_LEFT)
+					putchar('<');
+				else
+					putchar('>');
+			}
 		}
 		fputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
-		if (opt->parents)
+		if (opt->print_parents)
 			show_parents(commit, abbrev_commit);
 		show_decorations(commit);
+		if (opt->graph && !graph_is_commit_finished(opt->graph)) {
+			putchar('\n');
+			graph_show_remainder(opt->graph);
+		}
 		putchar(opt->diffopt.line_termination);
 		return;
 	}
 
 	/*
-	 * The "oneline" format has several special cases:
-	 *  - The pretty-printed commit lacks a newline at the end
-	 *    of the buffer, but we do want to make sure that we
-	 *    have a newline there. If the separator isn't already
-	 *    a newline, add an extra one.
-	 *  - unlike other log messages, the one-line format does
-	 *    not have an empty line between entries.
+	 * If use_terminator is set, add a newline at the end of the entry.
+	 * Otherwise, add a diffopt.line_termination character before all
+	 * entries but the first.  (IOW, as a separator between entries)
 	 */
-	extra = "";
-	if (*sep != '\n' && opt->commit_format == CMIT_FMT_ONELINE)
-		extra = "\n";
-	if (opt->shown_one && opt->commit_format != CMIT_FMT_ONELINE)
+	if (opt->shown_one && !opt->use_terminator) {
+		/*
+		 * If entries are separated by a newline, the output
+		 * should look human-readable.  If the last entry ended
+		 * with a newline, print the graph output before this
+		 * newline.  Otherwise it will end up as a completely blank
+		 * line and will look like a gap in the graph.
+		 *
+		 * If the entry separator is not a newline, the output is
+		 * primarily intended for programmatic consumption, and we
+		 * never want the extra graph output before the entry
+		 * separator.
+		 */
+		if (opt->diffopt.line_termination == '\n' &&
+		    !opt->missing_newline)
+			graph_show_padding(opt->graph);
 		putchar(opt->diffopt.line_termination);
+	}
 	opt->shown_one = 1;
 
 	/*
+	 * If the history graph was requested,
+	 * print the graph, up to this commit's line
+	 */
+	graph_show_commit(opt->graph);
+
+	/*
 	 * Print header line of header..
 	 */
 
@@ -267,19 +295,22 @@
 		fputs(diff_get_color_opt(&opt->diffopt, DIFF_COMMIT), stdout);
 		if (opt->commit_format != CMIT_FMT_ONELINE)
 			fputs("commit ", stdout);
-		if (commit->object.flags & BOUNDARY)
-			putchar('-');
-		else if (commit->object.flags & UNINTERESTING)
-			putchar('^');
-		else if (opt->left_right) {
-			if (commit->object.flags & SYMMETRIC_LEFT)
-				putchar('<');
-			else
-				putchar('>');
+
+		if (!opt->graph) {
+			if (commit->object.flags & BOUNDARY)
+				putchar('-');
+			else if (commit->object.flags & UNINTERESTING)
+				putchar('^');
+			else if (opt->left_right) {
+				if (commit->object.flags & SYMMETRIC_LEFT)
+					putchar('<');
+				else
+					putchar('>');
+			}
 		}
 		fputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit),
 		      stdout);
-		if (opt->parents)
+		if (opt->print_parents)
 			show_parents(commit, abbrev_commit);
 		if (parent)
 			printf(" (from %s)",
@@ -287,15 +318,24 @@
 						  abbrev_commit));
 		show_decorations(commit);
 		printf("%s", diff_get_color_opt(&opt->diffopt, DIFF_RESET));
-		putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n');
+		if (opt->commit_format == CMIT_FMT_ONELINE) {
+			putchar(' ');
+		} else {
+			putchar('\n');
+			graph_show_oneline(opt->graph);
+		}
 		if (opt->reflog_info) {
+			/*
+			 * setup_revisions() ensures that opt->reflog_info
+			 * and opt->graph cannot both be set,
+			 * so we don't need to worry about printing the
+			 * graph info here.
+			 */
 			show_reflog_message(opt->reflog_info,
 				    opt->commit_format == CMIT_FMT_ONELINE,
 				    opt->date_mode);
-			if (opt->commit_format == CMIT_FMT_ONELINE) {
-				printf("%s", sep);
+			if (opt->commit_format == CMIT_FMT_ONELINE)
 				return;
-			}
 		}
 	}
 
@@ -314,11 +354,30 @@
 
 	if (opt->add_signoff)
 		append_signoff(&msgbuf, opt->add_signoff);
-	if (opt->show_log_size)
+	if (opt->show_log_size) {
 		printf("log size %i\n", (int)msgbuf.len);
+		graph_show_oneline(opt->graph);
+	}
 
-	if (msgbuf.len)
-		printf("%s%s%s", msgbuf.buf, extra, sep);
+	/*
+	 * Set opt->missing_newline if msgbuf doesn't
+	 * end in a newline (including if it is empty)
+	 */
+	if (!msgbuf.len || msgbuf.buf[msgbuf.len - 1] != '\n')
+		opt->missing_newline = 1;
+	else
+		opt->missing_newline = 0;
+
+	if (opt->graph)
+		graph_show_commit_msg(opt->graph, &msgbuf);
+	else
+		fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+	if (opt->use_terminator) {
+		if (!opt->missing_newline)
+			graph_show_padding(opt->graph);
+		putchar('\n');
+	}
+
 	strbuf_release(&msgbuf);
 }
 
@@ -340,7 +399,7 @@
 		 * an extra newline between the end of log and the
 		 * output for readability.
 		 */
-		show_log(opt, opt->diffopt.msg_sep);
+		show_log(opt);
 		if ((opt->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT) &&
 		    opt->verbose_header &&
 		    opt->commit_format != CMIT_FMT_ONELINE) {
@@ -428,7 +487,7 @@
 	shown = log_tree_diff(opt, commit, &log);
 	if (!shown && opt->loginfo && opt->always_show_header) {
 		log.parent = NULL;
-		show_log(opt, "");
+		show_log(opt);
 		shown = 1;
 	}
 	opt->loginfo = NULL;
diff --git a/log-tree.h b/log-tree.h
index 8946ff3..59ba4c4 100644
--- a/log-tree.h
+++ b/log-tree.h
@@ -11,7 +11,7 @@
 int log_tree_diff_flush(struct rev_info *);
 int log_tree_commit(struct rev_info *, struct commit *);
 int log_tree_opt_parse(struct rev_info *, const char **, int);
-void show_log(struct rev_info *opt, const char *sep);
+void show_log(struct rev_info *opt);
 void show_decorations(struct commit *commit);
 void log_write_email_headers(struct rev_info *opt, const char *name,
 			     const char **subject_p,
diff --git a/name-hash.c b/name-hash.c
new file mode 100644
index 0000000..0031d78
--- /dev/null
+++ b/name-hash.c
@@ -0,0 +1,119 @@
+/*
+ * name-hash.c
+ *
+ * Hashing names in the index state
+ *
+ * Copyright (C) 2008 Linus Torvalds
+ */
+#define NO_THE_INDEX_COMPATIBILITY_MACROS
+#include "cache.h"
+
+/*
+ * This removes bit 5 if bit 6 is set.
+ *
+ * That will make US-ASCII characters hash to their upper-case
+ * equivalent. We could easily do this one whole word at a time,
+ * but that's for future worries.
+ */
+static inline unsigned char icase_hash(unsigned char c)
+{
+	return c & ~((c & 0x40) >> 1);
+}
+
+static unsigned int hash_name(const char *name, int namelen)
+{
+	unsigned int hash = 0x123;
+
+	do {
+		unsigned char c = *name++;
+		c = icase_hash(c);
+		hash = hash*101 + c;
+	} while (--namelen);
+	return hash;
+}
+
+static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)
+{
+	void **pos;
+	unsigned int hash;
+
+	if (ce->ce_flags & CE_HASHED)
+		return;
+	ce->ce_flags |= CE_HASHED;
+	ce->next = NULL;
+	hash = hash_name(ce->name, ce_namelen(ce));
+	pos = insert_hash(hash, ce, &istate->name_hash);
+	if (pos) {
+		ce->next = *pos;
+		*pos = ce;
+	}
+}
+
+static void lazy_init_name_hash(struct index_state *istate)
+{
+	int nr;
+
+	if (istate->name_hash_initialized)
+		return;
+	for (nr = 0; nr < istate->cache_nr; nr++)
+		hash_index_entry(istate, istate->cache[nr]);
+	istate->name_hash_initialized = 1;
+}
+
+void add_name_hash(struct index_state *istate, struct cache_entry *ce)
+{
+	ce->ce_flags &= ~CE_UNHASHED;
+	if (istate->name_hash_initialized)
+		hash_index_entry(istate, ce);
+}
+
+static int slow_same_name(const char *name1, int len1, const char *name2, int len2)
+{
+	if (len1 != len2)
+		return 0;
+
+	while (len1) {
+		unsigned char c1 = *name1++;
+		unsigned char c2 = *name2++;
+		len1--;
+		if (c1 != c2) {
+			c1 = toupper(c1);
+			c2 = toupper(c2);
+			if (c1 != c2)
+				return 0;
+		}
+	}
+	return 1;
+}
+
+static int same_name(const struct cache_entry *ce, const char *name, int namelen, int icase)
+{
+	int len = ce_namelen(ce);
+
+	/*
+	 * Always do exact compare, even if we want a case-ignoring comparison;
+	 * we do the quick exact one first, because it will be the common case.
+	 */
+	if (len == namelen && !cache_name_compare(name, namelen, ce->name, len))
+		return 1;
+
+	return icase && slow_same_name(name, namelen, ce->name, len);
+}
+
+struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int icase)
+{
+	unsigned int hash = hash_name(name, namelen);
+	struct cache_entry *ce;
+
+	lazy_init_name_hash(istate);
+	ce = lookup_hash(hash, &istate->name_hash);
+
+	while (ce) {
+		if (!(ce->ce_flags & CE_UNHASHED)) {
+			if (same_name(ce, name, namelen, icase))
+				return ce;
+		}
+		ce = ce->next;
+	}
+	return NULL;
+}
diff --git a/pack-check.c b/pack-check.c
index 0f8ad2c..f489873 100644
--- a/pack-check.c
+++ b/pack-check.c
@@ -25,10 +25,10 @@
 	off_t index_size = p->index_size;
 	const unsigned char *index_base = p->index_data;
 	SHA_CTX ctx;
-	unsigned char sha1[20];
-	off_t offset = 0, pack_sig = p->pack_size - 20;
+	unsigned char sha1[20], *pack_sig;
+	off_t offset = 0, pack_sig_ofs = p->pack_size - 20;
 	uint32_t nr_objects, i;
-	int err;
+	int err = 0;
 	struct idx_entry *entries;
 
 	/* Note that the pack header checks are actually performed by
@@ -38,21 +38,22 @@
 	 */
 
 	SHA1_Init(&ctx);
-	while (offset < pack_sig) {
+	while (offset < pack_sig_ofs) {
 		unsigned int remaining;
 		unsigned char *in = use_pack(p, w_curs, offset, &remaining);
 		offset += remaining;
-		if (offset > pack_sig)
-			remaining -= (unsigned int)(offset - pack_sig);
+		if (offset > pack_sig_ofs)
+			remaining -= (unsigned int)(offset - pack_sig_ofs);
 		SHA1_Update(&ctx, in, remaining);
 	}
 	SHA1_Final(sha1, &ctx);
-	if (hashcmp(sha1, use_pack(p, w_curs, pack_sig, NULL)))
-		return error("Packfile %s SHA1 mismatch with itself",
-			     p->pack_name);
-	if (hashcmp(sha1, index_base + index_size - 40))
-		return error("Packfile %s SHA1 mismatch with idx",
-			     p->pack_name);
+	pack_sig = use_pack(p, w_curs, pack_sig_ofs, NULL);
+	if (hashcmp(sha1, pack_sig))
+		err = error("%s SHA1 checksum mismatch",
+			    p->pack_name);
+	if (hashcmp(index_base + index_size - 40, pack_sig))
+		err = error("%s SHA1 does not match its inddex",
+			    p->pack_name);
 	unuse_pack(w_curs);
 
 	/* Make sure everything reachable from idx is valid.  Since we
@@ -72,22 +73,23 @@
 	}
 	qsort(entries, nr_objects, sizeof(*entries), compare_entries);
 
-	for (i = 0, err = 0; i < nr_objects; i++) {
+	for (i = 0; i < nr_objects; i++) {
 		void *data;
 		enum object_type type;
 		unsigned long size;
 
 		data = unpack_entry(p, entries[i].offset, &type, &size);
 		if (!data) {
-			err = error("cannot unpack %s from %s",
-				    sha1_to_hex(entries[i].sha1), p->pack_name);
-			continue;
+			err = error("cannot unpack %s from %s at offset %"PRIuMAX"",
+				    sha1_to_hex(entries[i].sha1), p->pack_name,
+				    (uintmax_t)entries[i].offset);
+			break;
 		}
 		if (check_sha1_signature(entries[i].sha1, data, size, typename(type))) {
 			err = error("packed %s from %s is corrupt",
 				    sha1_to_hex(entries[i].sha1), p->pack_name);
 			free(data);
-			continue;
+			break;
 		}
 		free(data);
 	}
@@ -158,31 +160,28 @@
 	const unsigned char *index_base;
 	SHA_CTX ctx;
 	unsigned char sha1[20];
-	int ret;
+	int err = 0;
+	struct pack_window *w_curs = NULL;
 
 	if (open_pack_index(p))
 		return error("packfile %s index not opened", p->pack_name);
 	index_size = p->index_size;
 	index_base = p->index_data;
 
-	ret = 0;
 	/* Verify SHA1 sum of the index file */
 	SHA1_Init(&ctx);
 	SHA1_Update(&ctx, index_base, (unsigned int)(index_size - 20));
 	SHA1_Final(sha1, &ctx);
 	if (hashcmp(sha1, index_base + index_size - 20))
-		ret = error("Packfile index for %s SHA1 mismatch",
+		err = error("Packfile index for %s SHA1 mismatch",
 			    p->pack_name);
 
-	if (!ret) {
-		/* Verify pack file */
-		struct pack_window *w_curs = NULL;
-		ret = verify_packfile(p, &w_curs);
-		unuse_pack(&w_curs);
-	}
+	/* Verify pack file */
+	err |= verify_packfile(p, &w_curs);
+	unuse_pack(&w_curs);
 
 	if (verbose) {
-		if (ret)
+		if (err)
 			printf("%s: bad\n", p->pack_name);
 		else {
 			show_pack_info(p);
@@ -190,5 +189,5 @@
 		}
 	}
 
-	return ret;
+	return err;
 }
diff --git a/pack-write.c b/pack-write.c
index 665e2b2..f52cabe 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -139,7 +139,7 @@
 	}
 
 	sha1write(f, sha1, 20);
-	sha1close(f, NULL, 1);
+	sha1close(f, NULL, CSUM_FSYNC);
 	SHA1_Final(sha1, &ctx);
 	return index_name;
 }
@@ -183,7 +183,6 @@
 
 char *index_pack_lockfile(int ip_out)
 {
-	int len, s;
 	char packname[46];
 
 	/*
@@ -193,11 +192,8 @@
 	 * case, we need it to remove the corresponding .keep file
 	 * later on.  If we don't get that then tough luck with it.
 	 */
-	for (len = 0;
-		 len < 46 && (s = xread(ip_out, packname+len, 46-len)) > 0;
-		 len += s);
-	if (len == 46 && packname[45] == '\n' &&
-		memcmp(packname, "keep\t", 5) == 0) {
+	if (read_in_full(ip_out, packname, 46) == 46 && packname[45] == '\n' &&
+	    memcmp(packname, "keep\t", 5) == 0) {
 		char path[PATH_MAX];
 		packname[45] = 0;
 		snprintf(path, sizeof(path), "%s/pack/pack-%s.keep",
diff --git a/pager.c b/pager.c
index ca002f9..dbd9414 100644
--- a/pager.c
+++ b/pager.c
@@ -33,7 +33,7 @@
 		return;
 	if (!pager) {
 		if (!pager_program)
-			git_config(git_default_config);
+			git_config(git_default_config, NULL);
 		pager = pager_program;
 	}
 	if (!pager)
diff --git a/parse-options.c b/parse-options.c
index acf3fe3..12c8822 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -344,7 +344,10 @@
 			break;
 		case OPTION_INTEGER:
 			if (opts->flags & PARSE_OPT_OPTARG)
-				pos += fprintf(stderr, "[<n>]");
+				if (opts->long_name)
+					pos += fprintf(stderr, "[=<n>]");
+				else
+					pos += fprintf(stderr, "[<n>]");
 			else
 				pos += fprintf(stderr, " <n>");
 			break;
@@ -355,12 +358,18 @@
 		case OPTION_STRING:
 			if (opts->argh) {
 				if (opts->flags & PARSE_OPT_OPTARG)
-					pos += fprintf(stderr, " [<%s>]", opts->argh);
+					if (opts->long_name)
+						pos += fprintf(stderr, "[=<%s>]", opts->argh);
+					else
+						pos += fprintf(stderr, "[<%s>]", opts->argh);
 				else
 					pos += fprintf(stderr, " <%s>", opts->argh);
 			} else {
 				if (opts->flags & PARSE_OPT_OPTARG)
-					pos += fprintf(stderr, " [...]");
+					if (opts->long_name)
+						pos += fprintf(stderr, "[=...]");
+					else
+						pos += fprintf(stderr, "[...]");
 				else
 					pos += fprintf(stderr, " ...");
 			}
@@ -416,3 +425,15 @@
 	*(unsigned long *)(opt->value) = approxidate(arg);
 	return 0;
 }
+
+/*
+ * This should really be OPTION_FILENAME type as a part of
+ * parse_options that take prefix to do this while parsing.
+ */
+extern const char *parse_options_fix_filename(const char *prefix, const char *file)
+{
+	if (!file || !prefix || is_absolute_path(file) || !strcmp("-", file))
+		return file;
+	return prefix_filename(prefix, strlen(prefix), file);
+}
+
diff --git a/parse-options.h b/parse-options.h
index 4ee443d..13ad158 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -123,4 +123,6 @@
 	  "use <n> digits to display SHA-1s", \
 	  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
 
+extern const char *parse_options_fix_filename(const char *prefix, const char *file);
+
 #endif
diff --git a/path.c b/path.c
index f4ed979..c1d5679 100644
--- a/path.c
+++ b/path.c
@@ -91,7 +91,8 @@
 	struct stat st;
 	char *buf, buffer[256];
 	unsigned char sha1[20];
-	int len, fd;
+	int fd;
+	ssize_t len;
 
 	if (lstat(path, &st) < 0)
 		return -1;
@@ -266,32 +267,86 @@
 	if (lstat(path, &st) < 0)
 		return -1;
 	mode = st.st_mode;
-	if (mode & S_IRUSR)
-		mode |= (shared_repository == PERM_GROUP
-			 ? S_IRGRP
-			 : (shared_repository == PERM_EVERYBODY
-			    ? (S_IRGRP|S_IROTH)
-			    : 0));
 
-	if (mode & S_IWUSR)
-		mode |= S_IWGRP;
+	if (shared_repository) {
+		int tweak = shared_repository;
+		if (!(mode & S_IWUSR))
+			tweak &= ~0222;
+		mode |= tweak;
+	} else {
+		/* Preserve old PERM_UMASK behaviour */
+		if (mode & S_IWUSR)
+			mode |= S_IWGRP;
+	}
 
-	if (mode & S_IXUSR)
-		mode |= (shared_repository == PERM_GROUP
-			 ? S_IXGRP
-			 : (shared_repository == PERM_EVERYBODY
-			    ? (S_IXGRP|S_IXOTH)
-			    : 0));
-	if (S_ISDIR(mode))
+	if (S_ISDIR(mode)) {
 		mode |= FORCE_DIR_SET_GID;
+
+		/* Copy read bits to execute bits */
+		mode |= (shared_repository & 0444) >> 2;
+	}
+
 	if ((mode & st.st_mode) != mode && chmod(path, mode) < 0)
 		return -2;
 	return 0;
 }
 
+static const char *get_pwd_cwd(void)
+{
+	static char cwd[PATH_MAX + 1];
+	char *pwd;
+	struct stat cwd_stat, pwd_stat;
+	if (getcwd(cwd, PATH_MAX) == NULL)
+		return NULL;
+	pwd = getenv("PWD");
+	if (pwd && strcmp(pwd, cwd)) {
+		stat(cwd, &cwd_stat);
+		if (!stat(pwd, &pwd_stat) &&
+		    pwd_stat.st_dev == cwd_stat.st_dev &&
+		    pwd_stat.st_ino == cwd_stat.st_ino) {
+			strlcpy(cwd, pwd, PATH_MAX);
+		}
+	}
+	return cwd;
+}
+
+const char *make_nonrelative_path(const char *path)
+{
+	static char buf[PATH_MAX + 1];
+
+	if (is_absolute_path(path)) {
+		if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
+			die ("Too long path: %.*s", 60, path);
+	} else {
+		const char *cwd = get_pwd_cwd();
+		if (!cwd)
+			die("Cannot determine the current working directory");
+		if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
+			die ("Too long path: %.*s", 60, path);
+	}
+	return buf;
+}
+
 /* We allow "recursive" symbolic links. Only within reason, though. */
 #define MAXDEPTH 5
 
+const char *make_relative_path(const char *abs, const char *base)
+{
+	static char buf[PATH_MAX + 1];
+	int baselen;
+	if (!base)
+		return abs;
+	baselen = strlen(base);
+	if (prefixcmp(abs, base))
+		return abs;
+	if (abs[baselen] == '/')
+		baselen++;
+	else if (base[baselen - 1] != '/')
+		return abs;
+	strcpy(buf, abs + baselen);
+	return buf;
+}
+
 const char *make_absolute_path(const char *path)
 {
 	static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
diff --git a/perl/Git.pm b/perl/Git.pm
index a2812ea..97e61ef 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -39,6 +39,10 @@
   my $lastrev = $repo->command_oneline( [ 'rev-list', '--all' ],
                                         STDERR => 0 );
 
+  my $sha1 = $repo->hash_and_insert_object('file.txt');
+  my $tempfile = tempfile();
+  my $size = $repo->cat_blob($sha1, $tempfile);
+
 =cut
 
 
@@ -51,6 +55,7 @@
 # Methods which can be called as standalone functions as well:
 @EXPORT_OK = qw(command command_oneline command_noisy
                 command_output_pipe command_input_pipe command_close_pipe
+                command_bidi_pipe command_close_bidi_pipe
                 version exec_path hash_object git_cmd_try);
 
 
@@ -92,6 +97,7 @@
 use Carp qw(carp croak); # but croak is bad - throw instead
 use Error qw(:try);
 use Cwd qw(abs_path);
+use IPC::Open2 qw(open2);
 
 }
 
@@ -216,7 +222,6 @@
 	bless $self, $class;
 }
 
-
 =back
 
 =head1 METHODS
@@ -375,6 +380,60 @@
 	_cmd_close($fh, $ctx);
 }
 
+=item command_bidi_pipe ( COMMAND [, ARGUMENTS... ] )
+
+Execute the given C<COMMAND> in the same way as command_output_pipe()
+does but return both an input pipe filehandle and an output pipe filehandle.
+
+The function will return return C<($pid, $pipe_in, $pipe_out, $ctx)>.
+See C<command_close_bidi_pipe()> for details.
+
+=cut
+
+sub command_bidi_pipe {
+	my ($pid, $in, $out);
+	$pid = open2($in, $out, 'git', @_);
+	return ($pid, $in, $out, join(' ', @_));
+}
+
+=item command_close_bidi_pipe ( PID, PIPE_IN, PIPE_OUT [, CTX] )
+
+Close the C<PIPE_IN> and C<PIPE_OUT> as returned from C<command_bidi_pipe()>,
+checking whether the command finished successfully. The optional C<CTX>
+argument is required if you want to see the command name in the error message,
+and it is the fourth value returned by C<command_bidi_pipe()>.  The call idiom
+is:
+
+	my ($pid, $in, $out, $ctx) = $r->command_bidi_pipe('cat-file --batch-check');
+	print "000000000\n" $out;
+	while (<$in>) { ... }
+	$r->command_close_bidi_pipe($pid, $in, $out, $ctx);
+
+Note that you should not rely on whatever actually is in C<CTX>;
+currently it is simply the command name but in future the context might
+have more complicated structure.
+
+=cut
+
+sub command_close_bidi_pipe {
+	my ($pid, $in, $out, $ctx) = @_;
+	foreach my $fh ($in, $out) {
+		unless (close $fh) {
+			if ($!) {
+				carp "error closing pipe: $!";
+			} elsif ($? >> 8) {
+				throw Git::Error::Command($ctx, $? >>8);
+			}
+		}
+	}
+
+	waitpid $pid, 0;
+
+	if ($? >> 8) {
+		throw Git::Error::Command($ctx, $? >>8);
+	}
+}
+
 
 =item command_noisy ( COMMAND [, ARGUMENTS... ] )
 
@@ -487,28 +546,26 @@
 (exception is thrown otherwise), in array context returns allows the
 variable to be set multiple times and returns all the values.
 
-Must be called on a repository instance.
-
 This currently wraps command('config') so it is not so fast.
 
 =cut
 
 sub config {
-	my ($self, $var) = @_;
-	$self->repo_path()
-		or throw Error::Simple("not a repository");
+	my ($self, $var) = _maybe_self(@_);
 
 	try {
+		my @cmd = ('config');
+		unshift @cmd, $self if $self;
 		if (wantarray) {
-			return $self->command('config', '--get-all', $var);
+			return command(@cmd, '--get-all', $var);
 		} else {
-			return $self->command_oneline('config', '--get', $var);
+			return command_oneline(@cmd, '--get', $var);
 		}
 	} catch Git::Error::Command with {
 		my $E = shift;
 		if ($E->value() == 1) {
 			# Key not found.
-			return undef;
+			return;
 		} else {
 			throw $E;
 		}
@@ -522,20 +579,17 @@
 is usable as a boolean in perl (and C<undef> if it's not defined,
 of course).
 
-Must be called on a repository instance.
-
 This currently wraps command('config') so it is not so fast.
 
 =cut
 
 sub config_bool {
-	my ($self, $var) = @_;
-	$self->repo_path()
-		or throw Error::Simple("not a repository");
+	my ($self, $var) = _maybe_self(@_);
 
 	try {
-		my $val = $self->command_oneline('config', '--bool', '--get',
-					      $var);
+		my @cmd = ('config', '--bool', '--get', $var);
+		unshift @cmd, $self if $self;
+		my $val = command_oneline(@cmd);
 		return undef unless defined $val;
 		return $val eq 'true';
 	} catch Git::Error::Command with {
@@ -557,19 +611,17 @@
 by 1024, 1048576 (1024^2), or 1073741824 (1024^3) prior to output.
 It would return C<undef> if configuration variable is not defined,
 
-Must be called on a repository instance.
-
 This currently wraps command('config') so it is not so fast.
 
 =cut
 
 sub config_int {
-	my ($self, $var) = @_;
-	$self->repo_path()
-		or throw Error::Simple("not a repository");
+	my ($self, $var) = _maybe_self(@_);
 
 	try {
-		return $self->command_oneline('config', '--int', '--get', $var);
+		my @cmd = ('config', '--int', '--get', $var);
+		unshift @cmd, $self if $self;
+		return command_oneline(@cmd);
 	} catch Git::Error::Command with {
 		my $E = shift;
 		if ($E->value() == 1) {
@@ -639,15 +691,15 @@
 	"$name <$email>" eq ident_person($name);
 	$time_tz =~ /^\d+ [+-]\d{4}$/;
 
-Both methods must be called on a repository instance.
-
 =cut
 
 sub ident {
-	my ($self, $type) = @_;
+	my ($self, $type) = _maybe_self(@_);
 	my $identstr;
 	if (lc $type eq lc 'committer' or lc $type eq lc 'author') {
-		$identstr = $self->command_oneline('var', 'GIT_'.uc($type).'_IDENT');
+		my @cmd = ('var', 'GIT_'.uc($type).'_IDENT');
+		unshift @cmd, $self if $self;
+		$identstr = command_oneline(@cmd);
 	} else {
 		$identstr = $type;
 	}
@@ -659,17 +711,16 @@
 }
 
 sub ident_person {
-	my ($self, @ident) = @_;
-	$#ident == 0 and @ident = $self->ident($ident[0]);
+	my ($self, @ident) = _maybe_self(@_);
+	$#ident == 0 and @ident = $self ? $self->ident($ident[0]) : ident($ident[0]);
 	return "$ident[0] <$ident[1]>";
 }
 
 
 =item hash_object ( TYPE, FILENAME )
 
-Compute the SHA1 object id of the given C<FILENAME> (or data waiting in
-C<FILEHANDLE>) considering it is of the C<TYPE> object type (C<blob>,
-C<commit>, C<tree>).
+Compute the SHA1 object id of the given C<FILENAME> considering it is
+of the C<TYPE> object type (C<blob>, C<commit>, C<tree>).
 
 The method can be called without any instance or on a specified Git repository,
 it makes zero difference.
@@ -685,6 +736,147 @@
 }
 
 
+=item hash_and_insert_object ( FILENAME )
+
+Compute the SHA1 object id of the given C<FILENAME> and add the object to the
+object database.
+
+The function returns the SHA1 hash.
+
+=cut
+
+# TODO: Support for passing FILEHANDLE instead of FILENAME
+sub hash_and_insert_object {
+	my ($self, $filename) = @_;
+
+	carp "Bad filename \"$filename\"" if $filename =~ /[\r\n]/;
+
+	$self->_open_hash_and_insert_object_if_needed();
+	my ($in, $out) = ($self->{hash_object_in}, $self->{hash_object_out});
+
+	unless (print $out $filename, "\n") {
+		$self->_close_hash_and_insert_object();
+		throw Error::Simple("out pipe went bad");
+	}
+
+	chomp(my $hash = <$in>);
+	unless (defined($hash)) {
+		$self->_close_hash_and_insert_object();
+		throw Error::Simple("in pipe went bad");
+	}
+
+	return $hash;
+}
+
+sub _open_hash_and_insert_object_if_needed {
+	my ($self) = @_;
+
+	return if defined($self->{hash_object_pid});
+
+	($self->{hash_object_pid}, $self->{hash_object_in},
+	 $self->{hash_object_out}, $self->{hash_object_ctx}) =
+		command_bidi_pipe(qw(hash-object -w --stdin-paths));
+}
+
+sub _close_hash_and_insert_object {
+	my ($self) = @_;
+
+	return unless defined($self->{hash_object_pid});
+
+	my @vars = map { 'hash_object_' . $_ } qw(pid in out ctx);
+
+	command_close_bidi_pipe($self->{@vars});
+	delete $self->{@vars};
+}
+
+=item cat_blob ( SHA1, FILEHANDLE )
+
+Prints the contents of the blob identified by C<SHA1> to C<FILEHANDLE> and
+returns the number of bytes printed.
+
+=cut
+
+sub cat_blob {
+	my ($self, $sha1, $fh) = @_;
+
+	$self->_open_cat_blob_if_needed();
+	my ($in, $out) = ($self->{cat_blob_in}, $self->{cat_blob_out});
+
+	unless (print $out $sha1, "\n") {
+		$self->_close_cat_blob();
+		throw Error::Simple("out pipe went bad");
+	}
+
+	my $description = <$in>;
+	if ($description =~ / missing$/) {
+		carp "$sha1 doesn't exist in the repository";
+		return -1;
+	}
+
+	if ($description !~ /^[0-9a-fA-F]{40} \S+ (\d+)$/) {
+		carp "Unexpected result returned from git cat-file";
+		return -1;
+	}
+
+	my $size = $1;
+
+	my $blob;
+	my $bytesRead = 0;
+
+	while (1) {
+		my $bytesLeft = $size - $bytesRead;
+		last unless $bytesLeft;
+
+		my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
+		my $read = read($in, $blob, $bytesToRead, $bytesRead);
+		unless (defined($read)) {
+			$self->_close_cat_blob();
+			throw Error::Simple("in pipe went bad");
+		}
+
+		$bytesRead += $read;
+	}
+
+	# Skip past the trailing newline.
+	my $newline;
+	my $read = read($in, $newline, 1);
+	unless (defined($read)) {
+		$self->_close_cat_blob();
+		throw Error::Simple("in pipe went bad");
+	}
+	unless ($read == 1 && $newline eq "\n") {
+		$self->_close_cat_blob();
+		throw Error::Simple("didn't find newline after blob");
+	}
+
+	unless (print $fh $blob) {
+		$self->_close_cat_blob();
+		throw Error::Simple("couldn't write to passed in filehandle");
+	}
+
+	return $size;
+}
+
+sub _open_cat_blob_if_needed {
+	my ($self) = @_;
+
+	return if defined($self->{cat_blob_pid});
+
+	($self->{cat_blob_pid}, $self->{cat_blob_in},
+	 $self->{cat_blob_out}, $self->{cat_blob_ctx}) =
+		command_bidi_pipe(qw(cat-file --batch));
+}
+
+sub _close_cat_blob {
+	my ($self) = @_;
+
+	return unless defined($self->{cat_blob_pid});
+
+	my @vars = map { 'cat_blob_' . $_ } qw(pid in out ctx);
+
+	command_close_bidi_pipe($self->{@vars});
+	delete $self->{@vars};
+}
 
 =back
 
@@ -902,7 +1094,11 @@
 }
 
 
-sub DESTROY { }
+sub DESTROY {
+	my ($self) = @_;
+	$self->_close_hash_and_insert_object();
+	$self->_close_cat_blob();
+}
 
 
 # Pipe implementation for ActiveState Perl.
diff --git a/pkt-line.c b/pkt-line.c
index 355546a..f5d0086 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -65,16 +65,11 @@
 
 static void safe_read(int fd, void *buffer, unsigned size)
 {
-	size_t n = 0;
-
-	while (n < size) {
-		ssize_t ret = xread(fd, (char *) buffer + n, size - n);
-		if (ret < 0)
-			die("read error (%s)", strerror(errno));
-		if (!ret)
-			die("The remote end hung up unexpectedly");
-		n += ret;
-	}
+	ssize_t ret = read_in_full(fd, buffer, size);
+	if (ret < 0)
+		die("read error (%s)", strerror(errno));
+	else if (ret < size)
+		die("The remote end hung up unexpectedly");
 }
 
 int packet_read_line(int fd, char *buffer, unsigned size)
diff --git a/pretty.c b/pretty.c
index 16bfb86..628a520 100644
--- a/pretty.c
+++ b/pretty.c
@@ -3,41 +3,50 @@
 #include "utf8.h"
 #include "diff.h"
 #include "revision.h"
-
-static struct cmt_fmt_map {
-	const char *n;
-	size_t cmp_len;
-	enum cmit_fmt v;
-} cmt_fmts[] = {
-	{ "raw",	1,	CMIT_FMT_RAW },
-	{ "medium",	1,	CMIT_FMT_MEDIUM },
-	{ "short",	1,	CMIT_FMT_SHORT },
-	{ "email",	1,	CMIT_FMT_EMAIL },
-	{ "full",	5,	CMIT_FMT_FULL },
-	{ "fuller",	5,	CMIT_FMT_FULLER },
-	{ "oneline",	1,	CMIT_FMT_ONELINE },
-	{ "format:",	7,	CMIT_FMT_USERFORMAT},
-};
+#include "path-list.h"
+#include "mailmap.h"
 
 static char *user_format;
 
-enum cmit_fmt get_commit_format(const char *arg)
+void get_commit_format(const char *arg, struct rev_info *rev)
 {
 	int i;
+	static struct cmt_fmt_map {
+		const char *n;
+		size_t cmp_len;
+		enum cmit_fmt v;
+	} cmt_fmts[] = {
+		{ "raw",	1,	CMIT_FMT_RAW },
+		{ "medium",	1,	CMIT_FMT_MEDIUM },
+		{ "short",	1,	CMIT_FMT_SHORT },
+		{ "email",	1,	CMIT_FMT_EMAIL },
+		{ "full",	5,	CMIT_FMT_FULL },
+		{ "fuller",	5,	CMIT_FMT_FULLER },
+		{ "oneline",	1,	CMIT_FMT_ONELINE },
+	};
 
-	if (!arg || !*arg)
-		return CMIT_FMT_DEFAULT;
-	if (*arg == '=')
-		arg++;
-	if (!prefixcmp(arg, "format:")) {
+	rev->use_terminator = 0;
+	if (!arg || !*arg) {
+		rev->commit_format = CMIT_FMT_DEFAULT;
+		return;
+	}
+	if (!prefixcmp(arg, "format:") || !prefixcmp(arg, "tformat:")) {
+		const char *cp = strchr(arg, ':') + 1;
 		free(user_format);
-		user_format = xstrdup(arg + 7);
-		return CMIT_FMT_USERFORMAT;
+		user_format = xstrdup(cp);
+		if (arg[0] == 't')
+			rev->use_terminator = 1;
+		rev->commit_format = CMIT_FMT_USERFORMAT;
+		return;
 	}
 	for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
 		if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) &&
-		    !strncmp(arg, cmt_fmts[i].n, strlen(arg)))
-			return cmt_fmts[i].v;
+		    !strncmp(arg, cmt_fmts[i].n, strlen(arg))) {
+			if (cmt_fmts[i].v == CMIT_FMT_ONELINE)
+				rev->use_terminator = 1;
+			rev->commit_format = cmt_fmts[i].v;
+			return;
+		}
 	}
 
 	die("invalid --pretty format: %s", arg);
@@ -281,6 +290,25 @@
 	return out;
 }
 
+static int mailmap_name(struct strbuf *sb, const char *email)
+{
+	static struct path_list *mail_map;
+	char buffer[1024];
+
+	if (!mail_map) {
+		mail_map = xcalloc(1, sizeof(*mail_map));
+		read_mailmap(mail_map, ".mailmap", NULL);
+	}
+
+	if (!mail_map->nr)
+		return -1;
+
+	if (!map_email(mail_map, email, buffer, sizeof(buffer)))
+		return -1;
+	strbuf_addstr(sb, buffer);
+	return 0;
+}
+
 static size_t format_person_part(struct strbuf *sb, char part,
                                const char *msg, int len)
 {
@@ -302,10 +330,12 @@
 	if (end >= len - 2)
 		goto skip;
 
-	if (part == 'n') {	/* name */
+	if (part == 'n' || part == 'N') {	/* name */
 		while (end > 0 && isspace(msg[end - 1]))
 			end--;
-		strbuf_add(sb, msg, end);
+		if (part != 'N' || !msg[end] || !msg[end + 1] ||
+		    mailmap_name(sb, msg + end + 2) < 0)
+			strbuf_add(sb, msg, end);
 		return placeholder_len;
 	}
 	start = ++end; /* save email start position */
@@ -457,6 +487,7 @@
 	const struct commit *commit = c->commit;
 	const char *msg = commit->buffer;
 	struct commit_list *p;
+	int h1, h2;
 
 	/* these are independent of the commit */
 	switch (placeholder[0]) {
@@ -478,6 +509,16 @@
 	case 'n':		/* newline */
 		strbuf_addch(sb, '\n');
 		return 1;
+	case 'x':
+		/* %x00 == NUL, %x0a == LF, etc. */
+		if (0 <= (h1 = hexval_table[0xff & placeholder[1]]) &&
+		    h1 <= 16 &&
+		    0 <= (h2 = hexval_table[0xff & placeholder[2]]) &&
+		    h2 <= 16) {
+			strbuf_addch(sb, (h1<<4)|h2);
+			return 3;
+		} else
+			return 0;
 	}
 
 	/* these depend on the commit */
diff --git a/progress.c b/progress.c
index d19f80c..55a8687 100644
--- a/progress.c
+++ b/progress.c
@@ -241,16 +241,21 @@
 	*p_progress = NULL;
 	if (progress->last_value != -1) {
 		/* Force the last update */
-		char buf[strlen(msg) + 5];
+		char buf[128], *bufp;
+		size_t len = strlen(msg) + 5;
 		struct throughput *tp = progress->throughput;
+
+		bufp = (len < sizeof(buf)) ? buf : xmalloc(len + 1);
 		if (tp) {
 			unsigned int rate = !tp->avg_misecs ? 0 :
 					tp->avg_bytes / tp->avg_misecs;
 			throughput_string(tp, tp->curr_total, rate);
 		}
 		progress_update = 1;
-		sprintf(buf, ", %s.\n", msg);
-		display(progress, progress->last_value, buf);
+		sprintf(bufp, ", %s.\n", msg);
+		display(progress, progress->last_value, bufp);
+		if (buf != bufp)
+			free(bufp);
 	}
 	clear_progress_signal();
 	free(progress->throughput);
diff --git a/read-cache.c b/read-cache.c
index a92b25b..f83de8c 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -23,80 +23,21 @@
 
 struct index_state the_index;
 
-static unsigned int hash_name(const char *name, int namelen)
-{
-	unsigned int hash = 0x123;
-
-	do {
-		unsigned char c = *name++;
-		hash = hash*101 + c;
-	} while (--namelen);
-	return hash;
-}
-
-static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)
-{
-	void **pos;
-	unsigned int hash;
-
-	if (ce->ce_flags & CE_HASHED)
-		return;
-	ce->ce_flags |= CE_HASHED;
-	ce->next = NULL;
-	hash = hash_name(ce->name, ce_namelen(ce));
-	pos = insert_hash(hash, ce, &istate->name_hash);
-	if (pos) {
-		ce->next = *pos;
-		*pos = ce;
-	}
-}
-
-static void lazy_init_name_hash(struct index_state *istate)
-{
-	int nr;
-
-	if (istate->name_hash_initialized)
-		return;
-	for (nr = 0; nr < istate->cache_nr; nr++)
-		hash_index_entry(istate, istate->cache[nr]);
-	istate->name_hash_initialized = 1;
-}
-
 static void set_index_entry(struct index_state *istate, int nr, struct cache_entry *ce)
 {
-	ce->ce_flags &= ~CE_UNHASHED;
 	istate->cache[nr] = ce;
-	if (istate->name_hash_initialized)
-		hash_index_entry(istate, ce);
+	add_name_hash(istate, ce);
 }
 
 static void replace_index_entry(struct index_state *istate, int nr, struct cache_entry *ce)
 {
 	struct cache_entry *old = istate->cache[nr];
 
-	remove_index_entry(old);
+	remove_name_hash(old);
 	set_index_entry(istate, nr, ce);
 	istate->cache_changed = 1;
 }
 
-int index_name_exists(struct index_state *istate, const char *name, int namelen)
-{
-	unsigned int hash = hash_name(name, namelen);
-	struct cache_entry *ce;
-
-	lazy_init_name_hash(istate);
-	ce = lookup_hash(hash, &istate->name_hash);
-
-	while (ce) {
-		if (!(ce->ce_flags & CE_UNHASHED)) {
-			if (!cache_name_compare(name, namelen, ce->name, ce->ce_flags))
-				return 1;
-		}
-		ce = ce->next;
-	}
-	return 0;
-}
-
 /*
  * This only updates the "non-critical" parts of the directory
  * cache, ie the parts that aren't tracked by GIT, and only used
@@ -197,6 +138,16 @@
 	return 0;
 }
 
+static int is_empty_blob_sha1(const unsigned char *sha1)
+{
+	static const unsigned char empty_blob_sha1[20] = {
+		0xe6,0x9d,0xe2,0x9b,0xb2,0xd1,0xd6,0x43,0x4b,0x8b,
+		0x29,0xae,0x77,0x5a,0xd8,0xc2,0xe4,0x8c,0x53,0x91
+	};
+
+	return !hashcmp(sha1, empty_blob_sha1);
+}
+
 static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
 {
 	unsigned int changed = 0;
@@ -252,12 +203,19 @@
 	if (ce->ce_size != (unsigned int) st->st_size)
 		changed |= DATA_CHANGED;
 
+	/* Racily smudged entry? */
+	if (!ce->ce_size) {
+		if (!is_empty_blob_sha1(ce->sha1))
+			changed |= DATA_CHANGED;
+	}
+
 	return changed;
 }
 
 static int is_racy_timestamp(const struct index_state *istate, struct cache_entry *ce)
 {
-	return (istate->timestamp &&
+	return (!S_ISGITLINK(ce->ce_mode) &&
+		istate->timestamp &&
 		((unsigned int)istate->timestamp) <= ce->ce_mtime);
 }
 
@@ -438,7 +396,7 @@
 {
 	struct cache_entry *ce = istate->cache[pos];
 
-	remove_index_entry(ce);
+	remove_name_hash(ce);
 	istate->cache_changed = 1;
 	istate->cache_nr--;
 	if (pos >= istate->cache_nr)
@@ -488,21 +446,52 @@
 	return pos;
 }
 
-int add_file_to_index(struct index_state *istate, const char *path, int verbose)
+static int different_name(struct cache_entry *ce, struct cache_entry *alias)
 {
-	int size, namelen, pos;
-	struct stat st;
-	struct cache_entry *ce;
+	int len = ce_namelen(ce);
+	return ce_namelen(alias) != len || memcmp(ce->name, alias->name, len);
+}
+
+/*
+ * If we add a filename that aliases in the cache, we will use the
+ * name that we already have - but we don't want to update the same
+ * alias twice, because that implies that there were actually two
+ * different files with aliasing names!
+ *
+ * So we use the CE_ADDED flag to verify that the alias was an old
+ * one before we accept it as
+ */
+static struct cache_entry *create_alias_ce(struct cache_entry *ce, struct cache_entry *alias)
+{
+	int len;
+	struct cache_entry *new;
+
+	if (alias->ce_flags & CE_ADDED)
+		die("Will not add file alias '%s' ('%s' already exists in index)", ce->name, alias->name);
+
+	/* Ok, create the new entry using the name of the existing alias */
+	len = ce_namelen(alias);
+	new = xcalloc(1, cache_entry_size(len));
+	memcpy(new->name, alias->name, len);
+	copy_cache_entry(new, ce);
+	free(ce);
+	return new;
+}
+
+int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags)
+{
+	int size, namelen, was_same;
+	mode_t st_mode = st->st_mode;
+	struct cache_entry *ce, *alias;
 	unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;
+	int verbose = flags & (ADD_CACHE_VERBOSE | ADD_CACHE_PRETEND);
+	int pretend = flags & ADD_CACHE_PRETEND;
 
-	if (lstat(path, &st))
-		die("%s: unable to stat (%s)", path, strerror(errno));
-
-	if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
-		die("%s: can only add regular files, symbolic links or git-directories", path);
+	if (!S_ISREG(st_mode) && !S_ISLNK(st_mode) && !S_ISDIR(st_mode))
+		return error("%s: can only add regular files, symbolic links or git-directories", path);
 
 	namelen = strlen(path);
-	if (S_ISDIR(st.st_mode)) {
+	if (S_ISDIR(st_mode)) {
 		while (namelen && path[namelen-1] == '/')
 			namelen--;
 	}
@@ -510,10 +499,10 @@
 	ce = xcalloc(1, size);
 	memcpy(ce->name, path, namelen);
 	ce->ce_flags = namelen;
-	fill_stat_cache_info(ce, &st);
+	fill_stat_cache_info(ce, st);
 
 	if (trust_executable_bit && has_symlinks)
-		ce->ce_mode = create_ce_mode(st.st_mode);
+		ce->ce_mode = create_ce_mode(st_mode);
 	else {
 		/* If there is an existing entry, pick the mode bits and type
 		 * from it, otherwise assume unexecutable regular file.
@@ -522,28 +511,46 @@
 		int pos = index_name_pos_also_unmerged(istate, path, namelen);
 
 		ent = (0 <= pos) ? istate->cache[pos] : NULL;
-		ce->ce_mode = ce_mode_from_stat(ent, st.st_mode);
+		ce->ce_mode = ce_mode_from_stat(ent, st_mode);
 	}
 
-	pos = index_name_pos(istate, ce->name, namelen);
-	if (0 <= pos &&
-	    !ce_stage(istate->cache[pos]) &&
-	    !ie_match_stat(istate, istate->cache[pos], &st, ce_option)) {
+	alias = index_name_exists(istate, ce->name, ce_namelen(ce), ignore_case);
+	if (alias && !ce_stage(alias) && !ie_match_stat(istate, alias, st, ce_option)) {
 		/* Nothing changed, really */
 		free(ce);
-		ce_mark_uptodate(istate->cache[pos]);
+		ce_mark_uptodate(alias);
+		alias->ce_flags |= CE_ADDED;
 		return 0;
 	}
+	if (index_path(ce->sha1, path, st, 1))
+		return error("unable to index file %s", path);
+	if (ignore_case && alias && different_name(ce, alias))
+		ce = create_alias_ce(ce, alias);
+	ce->ce_flags |= CE_ADDED;
 
-	if (index_path(ce->sha1, path, &st, 1))
-		die("unable to index file %s", path);
-	if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
-		die("unable to add %s to index",path);
-	if (verbose)
+	/* It was suspected to be recily clean, but it turns out to be Ok */
+	was_same = (alias &&
+		    !ce_stage(alias) &&
+		    !hashcmp(alias->sha1, ce->sha1) &&
+		    ce->ce_mode == alias->ce_mode);
+
+	if (pretend)
+		;
+	else if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
+		return error("unable to add %s to index",path);
+	if (verbose && !was_same)
 		printf("add '%s'\n", path);
 	return 0;
 }
 
+int add_file_to_index(struct index_state *istate, const char *path, int flags)
+{
+	struct stat st;
+	if (lstat(path, &st))
+		die("%s: unable to stat (%s)", path, strerror(errno));
+	return add_to_index(istate, path, &st, flags);
+}
+
 struct cache_entry *make_cache_entry(unsigned int mode,
 		const unsigned char *sha1, const char *path, int stage,
 		int refresh)
@@ -902,6 +909,15 @@
 	if (ce_uptodate(ce))
 		return ce;
 
+	/*
+	 * CE_VALID means the user promised us that the change to
+	 * the work tree does not matter and told us not to worry.
+	 */
+	if (!ignore_valid && (ce->ce_flags & CE_VALID)) {
+		ce_mark_uptodate(ce);
+		return ce;
+	}
+
 	if (lstat(ce->name, &st) < 0) {
 		if (err)
 			*err = errno;
@@ -962,6 +978,7 @@
 	int allow_unmerged = (flags & REFRESH_UNMERGED) != 0;
 	int quiet = (flags & REFRESH_QUIET) != 0;
 	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;
 
 	for (i = 0; i < istate->cache_nr; i++) {
@@ -969,6 +986,9 @@
 		int cache_errno = 0;
 
 		ce = istate->cache[i];
+		if (ignore_submodules && S_ISGITLINK(ce->ce_mode))
+			continue;
+
 		if (ce_stage(ce)) {
 			while ((i < istate->cache_nr) &&
 			       ! strcmp(istate->cache[i]->name, ce->name))
@@ -1370,7 +1390,7 @@
 		struct cache_entry *ce = cache[i];
 		if (ce->ce_flags & CE_REMOVE)
 			continue;
-		if (is_racy_timestamp(istate, ce))
+		if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce))
 			ce_smudge_racily_clean_entry(ce);
 		if (ce_write_entry(&c, newfd, ce) < 0)
 			return -1;
diff --git a/receive-pack.c b/receive-pack.c
index f83ae87..b26f2e3 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -10,6 +10,7 @@
 static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
 
 static int deny_non_fast_forwards = 0;
+static int receive_fsck_objects;
 static int receive_unpack_limit = -1;
 static int transfer_unpack_limit = -1;
 static int unpack_limit = 100;
@@ -18,7 +19,7 @@
 static char capabilities[] = " report-status delete-refs ";
 static int capabilities_sent;
 
-static int receive_pack_config(const char *var, const char *value)
+static int receive_pack_config(const char *var, const char *value, void *cb)
 {
 	if (strcmp(var, "receive.denynonfastforwards") == 0) {
 		deny_non_fast_forwards = git_config_bool(var, value);
@@ -35,7 +36,12 @@
 		return 0;
 	}
 
-	return git_default_config(var, value);
+	if (strcmp(var, "receive.fsckobjects") == 0) {
+		receive_fsck_objects = git_config_bool(var, value);
+		return 0;
+	}
+
+	return git_default_config(var, value, cb);
 }
 
 static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
@@ -368,11 +374,13 @@
 			ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
 
 	if (ntohl(hdr.hdr_entries) < unpack_limit) {
-		int code;
-		const char *unpacker[3];
-		unpacker[0] = "unpack-objects";
-		unpacker[1] = hdr_arg;
-		unpacker[2] = NULL;
+		int code, i = 0;
+		const char *unpacker[4];
+		unpacker[i++] = "unpack-objects";
+		if (receive_fsck_objects)
+			unpacker[i++] = "--strict";
+		unpacker[i++] = hdr_arg;
+		unpacker[i++] = NULL;
 		code = run_command_v_opt(unpacker, RUN_GIT_CMD);
 		switch (code) {
 		case 0:
@@ -393,8 +401,8 @@
 			return "unpacker exited with error code";
 		}
 	} else {
-		const char *keeper[6];
-		int s, status;
+		const char *keeper[7];
+		int s, status, i = 0;
 		char keep_arg[256];
 		struct child_process ip;
 
@@ -402,12 +410,14 @@
 		if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
 			strcpy(keep_arg + s, "localhost");
 
-		keeper[0] = "index-pack";
-		keeper[1] = "--stdin";
-		keeper[2] = "--fix-thin";
-		keeper[3] = hdr_arg;
-		keeper[4] = keep_arg;
-		keeper[5] = NULL;
+		keeper[i++] = "index-pack";
+		keeper[i++] = "--stdin";
+		if (receive_fsck_objects)
+			keeper[i++] = "--strict";
+		keeper[i++] = "--fix-thin";
+		keeper[i++] = hdr_arg;
+		keeper[i++] = keep_arg;
+		keeper[i++] = NULL;
 		memset(&ip, 0, sizeof(ip));
 		ip.argv = keeper;
 		ip.out = -1;
@@ -479,7 +489,7 @@
 	if (is_repository_shallow())
 		die("attempt to push into a shallow repository");
 
-	git_config(receive_pack_config);
+	git_config(receive_pack_config, NULL);
 
 	if (0 <= transfer_unpack_limit)
 		unpack_limit = transfer_unpack_limit;
diff --git a/refs.c b/refs.c
index 1b0050e..c9bcf14 100644
--- a/refs.c
+++ b/refs.c
@@ -159,6 +159,8 @@
 } cached_refs;
 static struct ref_list *current_ref;
 
+static struct ref_list *extra_refs;
+
 static void free_ref_list(struct ref_list *list)
 {
 	struct ref_list *next;
@@ -215,6 +217,17 @@
 	cached_refs->packed = sort_ref_list(list);
 }
 
+void add_extra_ref(const char *name, const unsigned char *sha1, int flag)
+{
+	extra_refs = add_ref(name, sha1, flag, extra_refs, NULL);
+}
+
+void clear_extra_refs(void)
+{
+	free_ref_list(extra_refs);
+	extra_refs = NULL;
+}
+
 static struct ref_list *get_packed_refs(void)
 {
 	if (!cached_refs.did_packed) {
@@ -352,6 +365,7 @@
 {
 	int len = strlen(path), retval;
 	char *gitdir;
+	const char *tmp;
 
 	while (len && path[len-1] == '/')
 		len--;
@@ -359,16 +373,27 @@
 		return -1;
 	gitdir = xmalloc(len + MAXREFLEN + 8);
 	memcpy(gitdir, path, len);
-	memcpy(gitdir + len, "/.git/", 7);
+	memcpy(gitdir + len, "/.git", 6);
+	len += 5;
 
-	retval = resolve_gitlink_ref_recursive(gitdir, len+6, refname, result, 0);
+	tmp = read_gitfile_gently(gitdir);
+	if (tmp) {
+		free(gitdir);
+		len = strlen(tmp);
+		gitdir = xmalloc(len + MAXREFLEN + 3);
+		memcpy(gitdir, tmp, len);
+	}
+	gitdir[len] = '/';
+	gitdir[++len] = '\0';
+	retval = resolve_gitlink_ref_recursive(gitdir, len, refname, result, 0);
 	free(gitdir);
 	return retval;
 }
 
 const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag)
 {
-	int depth = MAXDEPTH, len;
+	int depth = MAXDEPTH;
+	ssize_t len;
 	char buffer[256];
 	static char ref_buffer[256];
 
@@ -535,6 +560,11 @@
 	struct ref_list *packed = get_packed_refs();
 	struct ref_list *loose = get_loose_refs();
 
+	struct ref_list *extra;
+
+	for (extra = extra_refs; extra; extra = extra->next)
+		retval = do_one_ref(base, fn, trim, cb_data, extra);
+
 	while (packed && loose) {
 		struct ref_list *entry;
 		int cmp = strcmp(packed->name, loose->name);
@@ -895,7 +925,7 @@
 		i = strlen(lock->lk->filename) - 5; /* .lock */
 		lock->lk->filename[i] = 0;
 		err = unlink(lock->lk->filename);
-		if (err) {
+		if (err && errno != ENOENT) {
 			ret = 1;
 			error("unlink(%s) failed: %s",
 			      lock->lk->filename, strerror(errno));
diff --git a/refs.h b/refs.h
index 06abee1..06ad260 100644
--- a/refs.h
+++ b/refs.h
@@ -24,6 +24,15 @@
 extern int for_each_branch_ref(each_ref_fn, void *);
 extern int for_each_remote_ref(each_ref_fn, void *);
 
+/*
+ * Extra refs will be listed by for_each_ref() before any actual refs
+ * for the duration of this process or until clear_extra_refs() is
+ * called. Only extra refs added before for_each_ref() is called will
+ * be listed on a given call of for_each_ref().
+ */
+extern void add_extra_ref(const char *refname, const unsigned char *sha1, int flags);
+extern void clear_extra_refs(void);
+
 extern int peel_ref(const char *, unsigned char *);
 
 /** Locks a "refs/" ref returning the lock on success and NULL on failure. **/
diff --git a/remote.c b/remote.c
index 2d9af40..5f687b2 100644
--- a/remote.c
+++ b/remote.c
@@ -2,6 +2,16 @@
 #include "remote.h"
 #include "refs.h"
 
+static struct refspec s_tag_refspec = {
+	0,
+	1,
+	0,
+	"refs/tags/",
+	"refs/tags/"
+};
+
+const struct refspec *tag_refspec = &s_tag_refspec;
+
 struct counted_string {
 	size_t len;
 	const char *s;
@@ -288,7 +298,7 @@
 	remote->fetch_tags = 1; /* always auto-follow */
 }
 
-static int handle_config(const char *key, const char *value)
+static int handle_config(const char *key, const char *value, void *cb)
 {
 	const char *name;
 	const char *subkey;
@@ -337,44 +347,49 @@
 		return 0;
 	}
 	remote = make_remote(name, subkey - name);
-	if (!value) {
-		/* if we ever have a boolean variable, e.g. "remote.*.disabled"
-		 * [remote "frotz"]
-		 *      disabled
-		 * is a valid way to set it to true; we get NULL in value so
-		 * we need to handle it here.
-		 *
-		 * if (!strcmp(subkey, ".disabled")) {
-		 *      val = git_config_bool(key, value);
-		 *      return 0;
-		 * } else
-		 *
-		 */
-		return 0; /* ignore unknown booleans */
-	}
-	if (!strcmp(subkey, ".url")) {
-		add_url(remote, xstrdup(value));
+	if (!strcmp(subkey, ".mirror"))
+		remote->mirror = git_config_bool(key, value);
+	else if (!strcmp(subkey, ".skipdefaultupdate"))
+		remote->skip_default_update = git_config_bool(key, value);
+
+	else if (!strcmp(subkey, ".url")) {
+		const char *v;
+		if (git_config_string(&v, key, value))
+			return -1;
+		add_url(remote, v);
 	} else if (!strcmp(subkey, ".push")) {
-		add_push_refspec(remote, xstrdup(value));
+		const char *v;
+		if (git_config_string(&v, key, value))
+			return -1;
+		add_push_refspec(remote, v);
 	} else if (!strcmp(subkey, ".fetch")) {
-		add_fetch_refspec(remote, xstrdup(value));
+		const char *v;
+		if (git_config_string(&v, key, value))
+			return -1;
+		add_fetch_refspec(remote, v);
 	} else if (!strcmp(subkey, ".receivepack")) {
+		const char *v;
+		if (git_config_string(&v, key, value))
+			return -1;
 		if (!remote->receivepack)
-			remote->receivepack = xstrdup(value);
+			remote->receivepack = v;
 		else
 			error("more than one receivepack given, using the first");
 	} else if (!strcmp(subkey, ".uploadpack")) {
+		const char *v;
+		if (git_config_string(&v, key, value))
+			return -1;
 		if (!remote->uploadpack)
-			remote->uploadpack = xstrdup(value);
+			remote->uploadpack = v;
 		else
 			error("more than one uploadpack given, using the first");
 	} else if (!strcmp(subkey, ".tagopt")) {
 		if (!strcmp(value, "--no-tags"))
 			remote->fetch_tags = -1;
 	} else if (!strcmp(subkey, ".proxy")) {
-		remote->http_proxy = xstrdup(value);
-	} else if (!strcmp(subkey, ".skipdefaultupdate"))
-		remote->skip_default_update = 1;
+		return git_config_string((const char **)&remote->http_proxy,
+					 key, value);
+	}
 	return 0;
 }
 
@@ -405,10 +420,32 @@
 		current_branch =
 			make_branch(head_ref + strlen("refs/heads/"), 0);
 	}
-	git_config(handle_config);
+	git_config(handle_config, NULL);
 	alias_all_urls();
 }
 
+/*
+ * We need to make sure the tracking branches are well formed, but a
+ * wildcard refspec in "struct refspec" must have a trailing slash. We
+ * temporarily drop the trailing '/' while calling check_ref_format(),
+ * and put it back.  The caller knows that a CHECK_REF_FORMAT_ONELEVEL
+ * error return is Ok for a wildcard refspec.
+ */
+static int verify_refname(char *name, int is_glob)
+{
+	int result, len = -1;
+
+	if (is_glob) {
+		len = strlen(name);
+		assert(name[len - 1] == '/');
+		name[len - 1] = '\0';
+	}
+	result = check_ref_format(name);
+	if (is_glob)
+		name[len - 1] = '/';
+	return result;
+}
+
 static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
 {
 	int i;
@@ -416,11 +453,11 @@
 	struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec);
 
 	for (i = 0; i < nr_refspec; i++) {
-		size_t llen, rlen;
+		size_t llen;
 		int is_glob;
 		const char *lhs, *rhs;
 
-		llen = rlen = is_glob = 0;
+		llen = is_glob = 0;
 
 		lhs = refspec[i];
 		if (*lhs == '+') {
@@ -429,13 +466,20 @@
 		}
 
 		rhs = strrchr(lhs, ':');
+
+		/*
+		 * Before going on, special case ":" (or "+:") as a refspec
+		 * for matching refs.
+		 */
+		if (!fetch && rhs == lhs && rhs[1] == '\0') {
+			rs[i].matching = 1;
+			continue;
+		}
+
 		if (rhs) {
-			rhs++;
-			rlen = strlen(rhs);
+			size_t rlen = strlen(++rhs);
 			is_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, "/*"));
-			if (is_glob)
-				rlen -= 2;
-			rs[i].dst = xstrndup(rhs, rlen);
+			rs[i].dst = xstrndup(rhs, rlen - is_glob);
 		}
 
 		llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
@@ -443,7 +487,7 @@
 			if ((rhs && !is_glob) || (!rhs && fetch))
 				goto invalid;
 			is_glob = 1;
-			llen -= 2;
+			llen--;
 		} else if (rhs && is_glob) {
 			goto invalid;
 		}
@@ -460,7 +504,7 @@
 			if (!*rs[i].src)
 				; /* empty is ok */
 			else {
-				st = check_ref_format(rs[i].src);
+				st = verify_refname(rs[i].src, is_glob);
 				if (st && st != CHECK_REF_FORMAT_ONELEVEL)
 					goto invalid;
 			}
@@ -475,7 +519,7 @@
 			} else if (!*rs[i].dst) {
 				; /* ok */
 			} else {
-				st = check_ref_format(rs[i].dst);
+				st = verify_refname(rs[i].dst, is_glob);
 				if (st && st != CHECK_REF_FORMAT_ONELEVEL)
 					goto invalid;
 			}
@@ -490,7 +534,7 @@
 			if (!*rs[i].src)
 				; /* empty is ok */
 			else if (is_glob) {
-				st = check_ref_format(rs[i].src);
+				st = verify_refname(rs[i].src, is_glob);
 				if (st && st != CHECK_REF_FORMAT_ONELEVEL)
 					goto invalid;
 			}
@@ -504,13 +548,13 @@
 			 * - otherwise it must be a valid looking ref.
 			 */
 			if (!rs[i].dst) {
-				st = check_ref_format(rs[i].src);
+				st = verify_refname(rs[i].src, is_glob);
 				if (st && st != CHECK_REF_FORMAT_ONELEVEL)
 					goto invalid;
 			} else if (!*rs[i].dst) {
 				goto invalid;
 			} else {
-				st = check_ref_format(rs[i].dst);
+				st = verify_refname(rs[i].dst, is_glob);
 				if (st && st != CHECK_REF_FORMAT_ONELEVEL)
 					goto invalid;
 			}
@@ -659,8 +703,7 @@
 		if (!fetch->dst)
 			continue;
 		if (fetch->pattern) {
-			if (!prefixcmp(needle, key) &&
-			    needle[strlen(key)] == '/') {
+			if (!prefixcmp(needle, key)) {
 				*result = xmalloc(strlen(value) +
 						  strlen(needle) -
 						  strlen(key) + 1);
@@ -686,6 +729,13 @@
 	return ret;
 }
 
+struct ref *alloc_ref_from_str(const char* str)
+{
+	struct ref *ret = alloc_ref(strlen(str) + 1);
+	strcpy(ret->name, str);
+	return ret;
+}
+
 static struct ref *copy_ref(const struct ref *ref)
 {
 	struct ref *ret = xmalloc(sizeof(struct ref) + strlen(ref->name) + 1);
@@ -706,13 +756,22 @@
 	return ret;
 }
 
+void free_ref(struct ref *ref)
+{
+	if (!ref)
+		return;
+	free(ref->remote_status);
+	free(ref->symref);
+	free(ref);
+}
+
 void free_refs(struct ref *ref)
 {
 	struct ref *next;
 	while (ref) {
 		next = ref->next;
 		free(ref->peer_ref);
-		free(ref);
+		free_ref(ref);
 		ref = next;
 	}
 }
@@ -783,7 +842,6 @@
 {
 	unsigned char sha1[20];
 	struct ref *ref;
-	int len;
 
 	if (!*name) {
 		ref = alloc_ref(20);
@@ -793,21 +851,14 @@
 	}
 	if (get_sha1(name, sha1))
 		return NULL;
-	len = strlen(name) + 1;
-	ref = alloc_ref(len);
-	memcpy(ref->name, name, len);
+	ref = alloc_ref_from_str(name);
 	hashcpy(ref->new_sha1, sha1);
 	return ref;
 }
 
 static struct ref *make_linked_ref(const char *name, struct ref ***tail)
 {
-	struct ref *ret;
-	size_t len;
-
-	len = strlen(name) + 1;
-	ret = alloc_ref(len);
-	memcpy(ret->name, name, len);
+	struct ref *ret = alloc_ref_from_str(name);
 	tail_link_ref(ret, tail);
 	return ret;
 }
@@ -834,16 +885,15 @@
 
 static int match_explicit(struct ref *src, struct ref *dst,
 			  struct ref ***dst_tail,
-			  struct refspec *rs,
-			  int errs)
+			  struct refspec *rs)
 {
 	struct ref *matched_src, *matched_dst;
 
 	const char *dst_value = rs->dst;
 	char *dst_guess;
 
-	if (rs->pattern)
-		return errs;
+	if (rs->pattern || rs->matching)
+		return 0;
 
 	matched_src = matched_dst = NULL;
 	switch (count_refspec_match(rs->src, src, &matched_src)) {
@@ -856,23 +906,16 @@
 		 */
 		matched_src = try_explicit_object_name(rs->src);
 		if (!matched_src)
-			error("src refspec %s does not match any.", rs->src);
+			return error("src refspec %s does not match any.", rs->src);
 		break;
 	default:
-		matched_src = NULL;
-		error("src refspec %s matches more than one.", rs->src);
-		break;
+		return error("src refspec %s matches more than one.", rs->src);
 	}
 
-	if (!matched_src)
-		errs = 1;
-
 	if (!dst_value) {
 		unsigned char sha1[20];
 		int flag;
 
-		if (!matched_src)
-			return errs;
 		dst_value = resolve_ref(matched_src->name, sha1, 1, &flag);
 		if (!dst_value ||
 		    ((flag & REF_ISSYMREF) &&
@@ -903,18 +946,16 @@
 		      dst_value);
 		break;
 	}
-	if (errs || !matched_dst)
-		return 1;
-	if (matched_dst->peer_ref) {
-		errs = 1;
-		error("dst ref %s receives from more than one src.",
+	if (!matched_dst)
+		return -1;
+	if (matched_dst->peer_ref)
+		return error("dst ref %s receives from more than one src.",
 		      matched_dst->name);
-	}
 	else {
 		matched_dst->peer_ref = matched_src;
 		matched_dst->force = rs->force;
 	}
-	return errs;
+	return 0;
 }
 
 static int match_explicit_refs(struct ref *src, struct ref *dst,
@@ -923,8 +964,8 @@
 {
 	int i, errs;
 	for (i = errs = 0; i < rs_nr; i++)
-		errs |= match_explicit(src, dst, dst_tail, &rs[i], errs);
-	return -errs;
+		errs += match_explicit(src, dst, dst_tail, &rs[i]);
+	return errs;
 }
 
 static const struct refspec *check_pattern_match(const struct refspec *rs,
@@ -932,13 +973,21 @@
 						 const struct ref *src)
 {
 	int i;
+	int matching_refs = -1;
 	for (i = 0; i < rs_nr; i++) {
-		if (rs[i].pattern &&
-		    !prefixcmp(src->name, rs[i].src) &&
-		    src->name[strlen(rs[i].src)] == '/')
+		if (rs[i].matching &&
+		    (matching_refs == -1 || rs[i].force)) {
+			matching_refs = i;
+			continue;
+		}
+
+		if (rs[i].pattern && !prefixcmp(src->name, rs[i].src))
 			return rs + i;
 	}
-	return NULL;
+	if (matching_refs != -1)
+		return rs + matching_refs;
+	else
+		return NULL;
 }
 
 /*
@@ -949,11 +998,16 @@
 int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
 	       int nr_refspec, const char **refspec, int flags)
 {
-	struct refspec *rs =
-		parse_push_refspec(nr_refspec, (const char **) refspec);
+	struct refspec *rs;
 	int send_all = flags & MATCH_REFS_ALL;
 	int send_mirror = flags & MATCH_REFS_MIRROR;
+	static const char *default_refspec[] = { ":", 0 };
 
+	if (!nr_refspec) {
+		nr_refspec = 1;
+		refspec = default_refspec;
+	}
+	rs = parse_push_refspec(nr_refspec, (const char **) refspec);
 	if (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec))
 		return -1;
 
@@ -964,48 +1018,50 @@
 		char *dst_name;
 		if (src->peer_ref)
 			continue;
-		if (nr_refspec) {
-			pat = check_pattern_match(rs, nr_refspec, src);
-			if (!pat)
-				continue;
-		}
-		else if (!send_mirror && prefixcmp(src->name, "refs/heads/"))
+
+		pat = check_pattern_match(rs, nr_refspec, src);
+		if (!pat)
+			continue;
+
+		if (pat->matching) {
 			/*
 			 * "matching refs"; traditionally we pushed everything
 			 * including refs outside refs/heads/ hierarchy, but
 			 * that does not make much sense these days.
 			 */
-			continue;
+			if (!send_mirror && prefixcmp(src->name, "refs/heads/"))
+				continue;
+			dst_name = xstrdup(src->name);
 
-		if (pat) {
+		} else {
 			const char *dst_side = pat->dst ? pat->dst : pat->src;
 			dst_name = xmalloc(strlen(dst_side) +
 					   strlen(src->name) -
 					   strlen(pat->src) + 2);
 			strcpy(dst_name, dst_side);
 			strcat(dst_name, src->name + strlen(pat->src));
-		} else
-			dst_name = xstrdup(src->name);
+		}
 		dst_peer = find_ref_by_name(dst, dst_name);
-		if (dst_peer && dst_peer->peer_ref)
-			/* We're already sending something to this ref. */
-			goto free_name;
+		if (dst_peer) {
+			if (dst_peer->peer_ref)
+				/* We're already sending something to this ref. */
+				goto free_name;
 
-		if (!dst_peer && !nr_refspec && !(send_all || send_mirror))
-			/*
-			 * Remote doesn't have it, and we have no
-			 * explicit pattern, and we don't have
-			 * --all nor --mirror.
-			 */
-			goto free_name;
-		if (!dst_peer) {
+		} else {
+			if (pat->matching && !(send_all || send_mirror))
+				/*
+				 * Remote doesn't have it, and we have no
+				 * explicit pattern, and we don't have
+				 * --all nor --mirror.
+				 */
+				goto free_name;
+
 			/* Create a new one and link it */
 			dst_peer = make_linked_ref(dst_name, dst_tail);
 			hashcpy(dst_peer->new_sha1, src->new_sha1);
 		}
 		dst_peer->peer_ref = src;
-		if (pat)
-			dst_peer->force = pat->force;
+		dst_peer->force = pat->force;
 	free_name:
 		free(dst_name);
 	}
@@ -1111,9 +1167,7 @@
 		return NULL;
 
 	if (!prefixcmp(name, "refs/")) {
-		ret = alloc_ref(strlen(name) + 1);
-		strcpy(ret->name, name);
-		return ret;
+		return alloc_ref_from_str(name);
 	}
 
 	if (!prefixcmp(name, "heads/") ||
@@ -1172,3 +1226,15 @@
 
 	return 0;
 }
+
+int resolve_remote_symref(struct ref *ref, struct ref *list)
+{
+	if (!ref->symref)
+		return 0;
+	for (; list; list = list->next)
+		if (!strcmp(ref->symref, list->name)) {
+			hashcpy(ref->old_sha1, list->old_sha1);
+			return 0;
+		}
+	return 1;
+}
diff --git a/remote.h b/remote.h
index a38774b..8eed87b 100644
--- a/remote.h
+++ b/remote.h
@@ -26,6 +26,7 @@
 	 */
 	int fetch_tags;
 	int skip_default_update;
+	int mirror;
 
 	const char *receivepack;
 	const char *uploadpack;
@@ -46,13 +47,18 @@
 struct refspec {
 	unsigned force : 1;
 	unsigned pattern : 1;
+	unsigned matching : 1;
 
 	char *src;
 	char *dst;
 };
 
+extern const struct refspec *tag_refspec;
+
 struct ref *alloc_ref(unsigned namelen);
 
+struct ref *alloc_ref_from_str(const char* str);
+
 struct ref *copy_ref_list(const struct ref *ref);
 
 int check_ref_type(const struct ref *ref, int flags);
@@ -62,6 +68,8 @@
  */
 void free_refs(struct ref *ref);
 
+int resolve_remote_symref(struct ref *ref, struct ref *list);
+
 /*
  * Removes and frees any duplicate refs in the map.
  */
diff --git a/revision.c b/revision.c
index ffbed3f..a68abec 100644
--- a/revision.c
+++ b/revision.c
@@ -6,6 +6,7 @@
 #include "diff.h"
 #include "refs.h"
 #include "revision.h"
+#include "graph.h"
 #include "grep.h"
 #include "reflog-walk.h"
 #include "patch-ids.h"
@@ -258,7 +259,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;
 
@@ -284,7 +285,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);
@@ -411,11 +412,26 @@
 	commit->object.flags |= TREESAME;
 }
 
-static int add_parents_to_list(struct rev_info *revs, struct commit *commit, struct commit_list **list)
+static void insert_by_date_cached(struct commit *p, struct commit_list **head,
+		    struct commit_list *cached_base, struct commit_list **cache)
+{
+	struct commit_list *new_entry;
+
+	if (cached_base && p->date < cached_base->item->date)
+		new_entry = insert_by_date(p, &cached_base->next);
+	else
+		new_entry = insert_by_date(p, head);
+
+	if (cache && (!*cache || p->date < (*cache)->item->date))
+		*cache = new_entry;
+}
+
+static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
+		    struct commit_list **list, struct commit_list **cache_ptr)
 {
 	struct commit_list *parent = commit->parents;
 	unsigned left_flag;
-	int add, rest;
+	struct commit_list *cached_base = cache_ptr ? *cache_ptr : NULL;
 
 	if (commit->object.flags & ADDED)
 		return 0;
@@ -445,7 +461,7 @@
 			if (p->object.flags & SEEN)
 				continue;
 			p->object.flags |= SEEN;
-			insert_by_date(p, list);
+			insert_by_date_cached(p, list, cached_base, cache_ptr);
 		}
 		return 0;
 	}
@@ -462,19 +478,18 @@
 
 	left_flag = (commit->object.flags & SYMMETRIC_LEFT);
 
-	rest = !revs->first_parent_only;
-	for (parent = commit->parents, add = 1; parent; add = rest) {
+	for (parent = commit->parents; parent; parent = parent->next) {
 		struct commit *p = parent->item;
 
-		parent = parent->next;
 		if (parse_commit(p) < 0)
 			return -1;
 		p->object.flags |= left_flag;
-		if (p->object.flags & SEEN)
-			continue;
-		p->object.flags |= SEEN;
-		if (add)
-			insert_by_date(p, list);
+		if (!(p->object.flags & SEEN)) {
+			p->object.flags |= SEEN;
+			insert_by_date_cached(p, list, cached_base, cache_ptr);
+		}
+		if(revs->first_parent_only)
+			break;
 	}
 	return 0;
 }
@@ -612,7 +627,7 @@
 
 		if (revs->max_age != -1 && (commit->date < revs->max_age))
 			obj->flags |= UNINTERESTING;
-		if (add_parents_to_list(revs, commit, &list) < 0)
+		if (add_parents_to_list(revs, commit, &list, NULL) < 0)
 			return -1;
 		if (obj->flags & UNINTERESTING) {
 			mark_parents_uninteresting(commit);
@@ -1105,7 +1120,8 @@
 				}
 			}
 			if (!strcmp(arg, "--parents")) {
-				revs->parents = 1;
+				revs->rewrite_parents = 1;
+				revs->print_parents = 1;
 				continue;
 			}
 			if (!strcmp(arg, "--dense")) {
@@ -1197,9 +1213,20 @@
 				revs->verbose_header = 1;
 				continue;
 			}
-			if (!prefixcmp(arg, "--pretty")) {
+			if (!strcmp(arg, "--pretty")) {
 				revs->verbose_header = 1;
-				revs->commit_format = get_commit_format(arg+8);
+				get_commit_format(arg+8, revs);
+				continue;
+			}
+			if (!prefixcmp(arg, "--pretty=")) {
+				revs->verbose_header = 1;
+				get_commit_format(arg+9, revs);
+				continue;
+			}
+			if (!strcmp(arg, "--graph")) {
+				revs->topo_order = 1;
+				revs->rewrite_parents = 1;
+				revs->graph = graph_init(revs);
 				continue;
 			}
 			if (!strcmp(arg, "--root")) {
@@ -1396,6 +1423,15 @@
 	if (revs->reverse && revs->reflog_info)
 		die("cannot combine --reverse with --walk-reflogs");
 
+	/*
+	 * Limitations on the graph functionality
+	 */
+	if (revs->reverse && revs->graph)
+		die("cannot combine --reverse with --graph");
+
+	if (revs->reflog_info && revs->graph)
+		die("cannot combine --walk-reflogs with --graph");
+
 	return left;
 }
 
@@ -1438,10 +1474,12 @@
 
 static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp)
 {
+	struct commit_list *cache = NULL;
+
 	for (;;) {
 		struct commit *p = *pp;
 		if (!revs->limited)
-			if (add_parents_to_list(revs, p, &revs->commits) < 0)
+			if (add_parents_to_list(revs, p, &revs->commits, &cache) < 0)
 				return rewrite_one_error;
 		if (p->parents && p->parents->next)
 			return rewrite_one_ok;
@@ -1524,13 +1562,13 @@
 		/* Commit without changes? */
 		if (commit->object.flags & TREESAME) {
 			/* drop merges unless we want parenthood */
-			if (!revs->parents)
+			if (!revs->rewrite_parents)
 				return commit_ignore;
 			/* non-merge - always ignore it */
 			if (!commit->parents || !commit->parents->next)
 				return commit_ignore;
 		}
-		if (revs->parents && rewrite_parents(revs, commit) < 0)
+		if (revs->rewrite_parents && rewrite_parents(revs, commit) < 0)
 			return commit_error;
 	}
 	return commit_show;
@@ -1560,7 +1598,7 @@
 			if (revs->max_age != -1 &&
 			    (commit->date < revs->max_age))
 				continue;
-			if (add_parents_to_list(revs, commit, &revs->commits) < 0)
+			if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0)
 				return NULL;
 		}
 
@@ -1597,28 +1635,62 @@
 	}
 }
 
-struct commit *get_revision(struct rev_info *revs)
+static void create_boundary_commit_list(struct rev_info *revs)
+{
+	unsigned i;
+	struct commit *c;
+	struct object_array *array = &revs->boundary_commits;
+	struct object_array_entry *objects = array->objects;
+
+	/*
+	 * If revs->commits is non-NULL at this point, an error occurred in
+	 * get_revision_1().  Ignore the error and continue printing the
+	 * boundary commits anyway.  (This is what the code has always
+	 * done.)
+	 */
+	if (revs->commits) {
+		free_commit_list(revs->commits);
+		revs->commits = NULL;
+	}
+
+	/*
+	 * Put all of the actual boundary commits from revs->boundary_commits
+	 * into revs->commits
+	 */
+	for (i = 0; i < array->nr; i++) {
+		c = (struct commit *)(objects[i].item);
+		if (!c)
+			continue;
+		if (!(c->object.flags & CHILD_SHOWN))
+			continue;
+		if (c->object.flags & (SHOWN | BOUNDARY))
+			continue;
+		c->object.flags |= BOUNDARY;
+		commit_list_insert(c, &revs->commits);
+	}
+
+	/*
+	 * If revs->topo_order is set, sort the boundary commits
+	 * in topological order
+	 */
+	sort_in_topological_order(&revs->commits, revs->lifo);
+}
+
+static struct commit *get_revision_internal(struct rev_info *revs)
 {
 	struct commit *c = NULL;
 	struct commit_list *l;
 
 	if (revs->boundary == 2) {
-		unsigned i;
-		struct object_array *array = &revs->boundary_commits;
-		struct object_array_entry *objects = array->objects;
-		for (i = 0; i < array->nr; i++) {
-			c = (struct commit *)(objects[i].item);
-			if (!c)
-				continue;
-			if (!(c->object.flags & CHILD_SHOWN))
-				continue;
-			if (!(c->object.flags & SHOWN))
-				break;
-		}
-		if (array->nr <= i)
-			return NULL;
-
-		c->object.flags |= SHOWN | BOUNDARY;
+		/*
+		 * All of the normal commits have already been returned,
+		 * and we are now returning boundary commits.
+		 * create_boundary_commit_list() has populated
+		 * revs->commits with the remaining commits to return.
+		 */
+		c = pop_commit(&revs->commits);
+		if (c)
+			c->object.flags |= SHOWN;
 		return c;
 	}
 
@@ -1682,7 +1754,14 @@
 		 * switch to boundary commits output mode.
 		 */
 		revs->boundary = 2;
-		return get_revision(revs);
+
+		/*
+		 * Update revs->commits to contain the list of
+		 * boundary commits.
+		 */
+		create_boundary_commit_list(revs);
+
+		return get_revision_internal(revs);
 	}
 
 	/*
@@ -1704,3 +1783,11 @@
 
 	return c;
 }
+
+struct commit *get_revision(struct rev_info *revs)
+{
+	struct commit *c = get_revision_internal(revs);
+	if (c && revs->graph)
+		graph_update(revs->graph, c);
+	return c;
+}
diff --git a/revision.h b/revision.h
index c8b3b94..31f08c4 100644
--- a/revision.h
+++ b/revision.h
@@ -10,7 +10,6 @@
 #define CHILD_SHOWN	(1u<<6)
 #define ADDED		(1u<<7)	/* Parents already parsed and added? */
 #define SYMMETRIC_LEFT	(1u<<8)
-#define TOPOSORT	(1u<<9)	/* In the active toposort list.. */
 
 struct rev_info;
 struct log_info;
@@ -46,7 +45,8 @@
 			unpacked:1, /* see also ignore_packed below */
 			boundary:2,
 			left_right:1,
-			parents:1,
+			rewrite_parents:1,
+			print_parents:1,
 			reverse:1,
 			cherry_pick:1,
 			first_parent_only:1;
@@ -64,7 +64,9 @@
 
 	/* Format info */
 	unsigned int	shown_one:1,
-			abbrev_commit:1;
+			abbrev_commit:1,
+			use_terminator:1,
+			missing_newline:1;
 	enum date_mode date_mode;
 
 	const char **ignore_packed; /* pretend objects in these are unpacked */
@@ -87,6 +89,9 @@
 	/* Filter by commit log message */
 	struct grep_opt	*grep_filter;
 
+	/* Display history graph */
+	struct git_graph *graph;
+
 	/* special limits */
 	int skip_count;
 	int max_count;
diff --git a/run-command.c b/run-command.c
index 44100a7..7068ec7 100644
--- a/run-command.c
+++ b/run-command.c
@@ -65,6 +65,8 @@
 		cmd->err = fderr[0];
 	}
 
+	trace_argv_printf(cmd->argv, "trace: run_command:");
+
 	cmd->pid = fork();
 	if (cmd->pid < 0) {
 		if (need_in)
diff --git a/setup.c b/setup.c
index 3d2d958..3b111ea 100644
--- a/setup.c
+++ b/setup.c
@@ -292,15 +292,16 @@
 	work_tree = get_git_work_tree();
 	git_dir = get_git_dir();
 	if (!is_absolute_path(git_dir))
-		set_git_dir(make_absolute_path(git_dir));
+		git_dir = make_absolute_path(git_dir);
 	if (!work_tree || chdir(work_tree))
 		die("This operation must be run in a work tree");
+	set_git_dir(make_relative_path(git_dir, work_tree));
 	initialized = 1;
 }
 
 static int check_repository_format_gently(int *nongit_ok)
 {
-	git_config(check_repository_format_version);
+	git_config(check_repository_format_version, NULL);
 	if (GIT_REPO_VERSION < repository_format_version) {
 		if (!nongit_ok)
 			die ("Expected git repo version <= %d, found %d",
@@ -315,6 +316,44 @@
 }
 
 /*
+ * Try to read the location of the git directory from the .git file,
+ * return path to git directory if found.
+ */
+const char *read_gitfile_gently(const char *path)
+{
+	char *buf;
+	struct stat st;
+	int fd;
+	size_t len;
+
+	if (stat(path, &st))
+		return NULL;
+	if (!S_ISREG(st.st_mode))
+		return NULL;
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		die("Error opening %s: %s", path, strerror(errno));
+	buf = xmalloc(st.st_size + 1);
+	len = read_in_full(fd, buf, st.st_size);
+	close(fd);
+	if (len != st.st_size)
+		die("Error reading %s", path);
+	buf[len] = '\0';
+	if (prefixcmp(buf, "gitdir: "))
+		die("Invalid gitfile format: %s", path);
+	while (buf[len - 1] == '\n' || buf[len - 1] == '\r')
+		len--;
+	if (len < 9)
+		die("No path in gitfile: %s", path);
+	buf[len] = '\0';
+	if (!is_git_directory(buf + 8))
+		die("Not a git repository: %s", buf + 8);
+	path = make_absolute_path(buf + 8);
+	free(buf);
+	return path;
+}
+
+/*
  * We cannot decide in this function whether we are in the work tree or
  * not, since the config can only be read _after_ this function was called.
  */
@@ -323,6 +362,7 @@
 	const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
 	static char cwd[PATH_MAX+1];
 	const char *gitdirenv;
+	const char *gitfile_dir;
 	int len, offset;
 
 	/*
@@ -377,8 +417,10 @@
 
 	/*
 	 * Test in the following order (relative to the cwd):
+	 * - .git (file containing "gitdir: <path>")
 	 * - .git/
 	 * - ./ (bare)
+	 * - ../.git
 	 * - ../.git/
 	 * - ../ (bare)
 	 * - ../../.git/
@@ -386,6 +428,12 @@
 	 */
 	offset = len = strlen(cwd);
 	for (;;) {
+		gitfile_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
+		if (gitfile_dir) {
+			if (set_git_dir(gitfile_dir))
+				die("Repository setup failed");
+			break;
+		}
 		if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT))
 			break;
 		if (is_git_directory(".")) {
@@ -428,24 +476,56 @@
 
 int git_config_perm(const char *var, const char *value)
 {
-	if (value) {
-		int i;
-		if (!strcmp(value, "umask"))
-			return PERM_UMASK;
-		if (!strcmp(value, "group"))
-			return PERM_GROUP;
-		if (!strcmp(value, "all") ||
-		    !strcmp(value, "world") ||
-		    !strcmp(value, "everybody"))
-			return PERM_EVERYBODY;
-		i = atoi(value);
-		if (i > 1)
-			return i;
+	int i;
+	char *endptr;
+
+	if (value == NULL)
+		return PERM_GROUP;
+
+	if (!strcmp(value, "umask"))
+		return PERM_UMASK;
+	if (!strcmp(value, "group"))
+		return PERM_GROUP;
+	if (!strcmp(value, "all") ||
+	    !strcmp(value, "world") ||
+	    !strcmp(value, "everybody"))
+		return PERM_EVERYBODY;
+
+	/* Parse octal numbers */
+	i = strtol(value, &endptr, 8);
+
+	/* If not an octal number, maybe true/false? */
+	if (*endptr != 0)
+		return git_config_bool(var, value) ? PERM_GROUP : PERM_UMASK;
+
+	/*
+	 * Treat values 0, 1 and 2 as compatibility cases, otherwise it is
+	 * a chmod value.
+	 */
+	switch (i) {
+	case PERM_UMASK:               /* 0 */
+		return PERM_UMASK;
+	case OLD_PERM_GROUP:           /* 1 */
+		return PERM_GROUP;
+	case OLD_PERM_EVERYBODY:       /* 2 */
+		return PERM_EVERYBODY;
 	}
-	return git_config_bool(var, value);
+
+	/* A filemode value was given: 0xxx */
+
+	if ((i & 0600) != 0600)
+		die("Problem with core.sharedRepository filemode value "
+		    "(0%.3o).\nThe owner of files must always have "
+		    "read and write permissions.", i);
+
+	/*
+	 * Mask filemode value. Others can not get write permission.
+	 * x flags for directories are handled separately.
+	 */
+	return i & 0666;
 }
 
-int check_repository_format_version(const char *var, const char *value)
+int check_repository_format_version(const char *var, const char *value, void *cb)
 {
 	if (strcmp(var, "core.repositoryformatversion") == 0)
 		repository_format_version = git_config_int(var, value);
diff --git a/sha1-lookup.c b/sha1-lookup.c
new file mode 100644
index 0000000..da35747
--- /dev/null
+++ b/sha1-lookup.c
@@ -0,0 +1,171 @@
+#include "cache.h"
+#include "sha1-lookup.h"
+
+/*
+ * Conventional binary search loop looks like this:
+ *
+ *	unsigned lo, hi;
+ *      do {
+ *              unsigned mi = (lo + hi) / 2;
+ *              int cmp = "entry pointed at by mi" minus "target";
+ *              if (!cmp)
+ *                      return (mi is the wanted one)
+ *              if (cmp > 0)
+ *                      hi = mi; "mi is larger than target"
+ *              else
+ *                      lo = mi+1; "mi is smaller than target"
+ *      } while (lo < hi);
+ *
+ * The invariants are:
+ *
+ * - When entering the loop, lo points at a slot that is never
+ *   above the target (it could be at the target), hi points at a
+ *   slot that is guaranteed to be above the target (it can never
+ *   be at the target).
+ *
+ * - We find a point 'mi' between lo and hi (mi could be the same
+ *   as lo, but never can be as same as hi), and check if it hits
+ *   the target.  There are three cases:
+ *
+ *    - if it is a hit, we are happy.
+ *
+ *    - if it is strictly higher than the target, we set it to hi,
+ *      and repeat the search.
+ *
+ *    - if it is strictly lower than the target, we update lo to
+ *      one slot after it, because we allow lo to be at the target.
+ *
+ *   If the loop exits, there is no matching entry.
+ *
+ * When choosing 'mi', we do not have to take the "middle" but
+ * anywhere in between lo and hi, as long as lo <= mi < hi is
+ * satisfied.  When we somehow know that the distance between the
+ * target and lo is much shorter than the target and hi, we could
+ * pick mi that is much closer to lo than the midway.
+ *
+ * Now, we can take advantage of the fact that SHA-1 is a good hash
+ * function, and as long as there are enough entries in the table, we
+ * can expect uniform distribution.  An entry that begins with for
+ * example "deadbeef..." is much likely to appear much later than in
+ * the midway of the table.  It can reasonably be expected to be near
+ * 87% (222/256) from the top of the table.
+ *
+ * However, we do not want to pick "mi" too precisely.  If the entry at
+ * the 87% in the above example turns out to be higher than the target
+ * we are looking for, we would end up narrowing the search space down
+ * only by 13%, instead of 50% we would get if we did a simple binary
+ * search.  So we would want to hedge our bets by being less aggressive.
+ *
+ * The table at "table" holds at least "nr" entries of "elem_size"
+ * bytes each.  Each entry has the SHA-1 key at "key_offset".  The
+ * table is sorted by the SHA-1 key of the entries.  The caller wants
+ * to find the entry with "key", and knows that the entry at "lo" is
+ * not higher than the entry it is looking for, and that the entry at
+ * "hi" is higher than the entry it is looking for.
+ */
+int sha1_entry_pos(const void *table,
+		   size_t elem_size,
+		   size_t key_offset,
+		   unsigned lo, unsigned hi, unsigned nr,
+		   const unsigned char *key)
+{
+	const unsigned char *base = table;
+	const unsigned char *hi_key, *lo_key;
+	unsigned ofs_0;
+	static int debug_lookup = -1;
+
+	if (debug_lookup < 0)
+		debug_lookup = !!getenv("GIT_DEBUG_LOOKUP");
+
+	if (!nr || lo >= hi)
+		return -1;
+
+	if (nr == hi)
+		hi_key = NULL;
+	else
+		hi_key = base + elem_size * hi + key_offset;
+	lo_key = base + elem_size * lo + key_offset;
+
+	ofs_0 = 0;
+	do {
+		int cmp;
+		unsigned ofs, mi, range;
+		unsigned lov, hiv, kyv;
+		const unsigned char *mi_key;
+
+		range = hi - lo;
+		if (hi_key) {
+			for (ofs = ofs_0; ofs < 20; ofs++)
+				if (lo_key[ofs] != hi_key[ofs])
+					break;
+			ofs_0 = ofs;
+			/*
+			 * byte 0 thru (ofs-1) are the same between
+			 * lo and hi; ofs is the first byte that is
+			 * different.
+			 */
+			hiv = hi_key[ofs_0];
+			if (ofs_0 < 19)
+				hiv = (hiv << 8) | hi_key[ofs_0+1];
+		} else {
+			hiv = 256;
+			if (ofs_0 < 19)
+				hiv <<= 8;
+		}
+		lov = lo_key[ofs_0];
+		kyv = key[ofs_0];
+		if (ofs_0 < 19) {
+			lov = (lov << 8) | lo_key[ofs_0+1];
+			kyv = (kyv << 8) | key[ofs_0+1];
+		}
+		assert(lov < hiv);
+
+		if (kyv < lov)
+			return -1 - lo;
+		if (hiv < kyv)
+			return -1 - hi;
+
+		/*
+		 * Even if we know the target is much closer to 'hi'
+		 * than 'lo', if we pick too precisely and overshoot
+		 * (e.g. when we know 'mi' is closer to 'hi' than to
+		 * 'lo', pick 'mi' that is higher than the target), we
+		 * end up narrowing the search space by a smaller
+		 * amount (i.e. the distance between 'mi' and 'hi')
+		 * than what we would have (i.e. about half of 'lo'
+		 * and 'hi').  Hedge our bets to pick 'mi' less
+		 * aggressively, i.e. make 'mi' a bit closer to the
+		 * middle than we would otherwise pick.
+		 */
+		kyv = (kyv * 6 + lov + hiv) / 8;
+		if (lov < hiv - 1) {
+			if (kyv == lov)
+				kyv++;
+			else if (kyv == hiv)
+				kyv--;
+		}
+		mi = (range - 1) * (kyv - lov) / (hiv - lov) + lo;
+
+		if (debug_lookup) {
+			printf("lo %u hi %u rg %u mi %u ", lo, hi, range, mi);
+			printf("ofs %u lov %x, hiv %x, kyv %x\n",
+			       ofs_0, lov, hiv, kyv);
+		}
+		if (!(lo <= mi && mi < hi))
+			die("assertion failure lo %u mi %u hi %u %s",
+			    lo, mi, hi, sha1_to_hex(key));
+
+		mi_key = base + elem_size * mi + key_offset;
+		cmp = memcmp(mi_key + ofs_0, key + ofs_0, 20 - ofs_0);
+		if (!cmp)
+			return mi;
+		if (cmp > 0) {
+			hi = mi;
+			hi_key = mi_key;
+		} else {
+			lo = mi + 1;
+			lo_key = mi_key + elem_size;
+		}
+	} while (lo < hi);
+	return -lo-1;
+}
diff --git a/sha1-lookup.h b/sha1-lookup.h
new file mode 100644
index 0000000..3249a81
--- /dev/null
+++ b/sha1-lookup.h
@@ -0,0 +1,9 @@
+#ifndef SHA1_LOOKUP_H
+#define SHA1_LOOKUP_H
+
+extern int sha1_entry_pos(const void *table,
+			  size_t elem_size,
+			  size_t key_offset,
+			  unsigned lo, unsigned hi, unsigned nr,
+			  const unsigned char *key);
+#endif
diff --git a/sha1_file.c b/sha1_file.c
index 445a871..ff3bb49 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -15,6 +15,7 @@
 #include "tree.h"
 #include "refs.h"
 #include "pack-revindex.h"
+#include "sha1-lookup.h"
 
 #ifndef O_NOATIME
 #if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
@@ -34,8 +35,6 @@
 
 const unsigned char null_sha1[20];
 
-static unsigned int sha1_file_open_flag = O_NOATIME;
-
 const signed char hexval_table[256] = {
 	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 00-07 */
 	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 08-0f */
@@ -117,7 +116,16 @@
 	return 0;
 }
 
-char * sha1_to_hex(const unsigned char *sha1)
+int safe_create_leading_directories_const(const char *path)
+{
+	/* path points to cache entries, so xstrdup before messing with it */
+	char *buf = xstrdup(path);
+	int result = safe_create_leading_directories(buf);
+	free(buf);
+	return result;
+}
+
+char *sha1_to_hex(const unsigned char *sha1)
 {
 	static int bufno;
 	static char hexbuffer[4][50];
@@ -175,21 +183,23 @@
 	return base;
 }
 
-char *sha1_pack_name(const unsigned char *sha1)
+static char *sha1_get_pack_name(const unsigned char *sha1,
+				char **name, char **base, const char *which)
 {
 	static const char hex[] = "0123456789abcdef";
-	static char *name, *base, *buf;
+	char *buf;
 	int i;
 
-	if (!base) {
+	if (!*base) {
 		const char *sha1_file_directory = get_object_directory();
 		int len = strlen(sha1_file_directory);
-		base = xmalloc(len + 60);
-		sprintf(base, "%s/pack/pack-1234567890123456789012345678901234567890.pack", sha1_file_directory);
-		name = base + len + 11;
+		*base = xmalloc(len + 60);
+		sprintf(*base, "%s/pack/pack-1234567890123456789012345678901234567890.%s",
+			sha1_file_directory, which);
+		*name = *base + len + 11;
 	}
 
-	buf = name;
+	buf = *name;
 
 	for (i = 0; i < 20; i++) {
 		unsigned int val = *sha1++;
@@ -197,32 +207,21 @@
 		*buf++ = hex[val & 0xf];
 	}
 
-	return base;
+	return *base;
+}
+
+char *sha1_pack_name(const unsigned char *sha1)
+{
+	static char *name, *base;
+
+	return sha1_get_pack_name(sha1, &name, &base, "pack");
 }
 
 char *sha1_pack_index_name(const unsigned char *sha1)
 {
-	static const char hex[] = "0123456789abcdef";
-	static char *name, *base, *buf;
-	int i;
+	static char *name, *base;
 
-	if (!base) {
-		const char *sha1_file_directory = get_object_directory();
-		int len = strlen(sha1_file_directory);
-		base = xmalloc(len + 60);
-		sprintf(base, "%s/pack/pack-1234567890123456789012345678901234567890.idx", sha1_file_directory);
-		name = base + len + 11;
-	}
-
-	buf = name;
-
-	for (i = 0; i < 20; i++) {
-		unsigned int val = *sha1++;
-		*buf++ = hex[val >> 4];
-		*buf++ = hex[val & 0xf];
-	}
-
-	return base;
+	return sha1_get_pack_name(sha1, &name, &base, "idx");
 }
 
 struct alternate_object_database *alt_odb_list;
@@ -379,6 +378,18 @@
 	munmap(map, mapsz);
 }
 
+void add_to_alternates_file(const char *reference)
+{
+	struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
+	int fd = hold_lock_file_for_append(lock, git_path("objects/info/alternates"), 1);
+	char *alt = mkpath("%s/objects\n", reference);
+	write_or_die(fd, alt, strlen(alt));
+	if (commit_lock_file(lock))
+		die("could not close alternates file");
+	if (alt_odb_tail)
+		link_alt_odb_entries(alt, alt + strlen(alt), '\n', NULL, 0);
+}
+
 void prepare_alt_odb(void)
 {
 	const char *alt;
@@ -395,21 +406,21 @@
 	read_info_alternates(get_object_directory(), 0);
 }
 
-static char *find_sha1_file(const unsigned char *sha1, struct stat *st)
+static int has_loose_object(const unsigned char *sha1)
 {
 	char *name = sha1_file_name(sha1);
 	struct alternate_object_database *alt;
 
-	if (!stat(name, st))
-		return name;
+	if (!access(name, F_OK))
+		return 1;
 	prepare_alt_odb();
 	for (alt = alt_odb_list; alt; alt = alt->next) {
 		name = alt->name;
 		fill_sha1_path(name, sha1);
-		if (!stat(alt->base, st))
-			return alt->base;
+		if (!access(alt->base, F_OK))
+			return 1;
 	}
-	return NULL;
+	return 0;
 }
 
 static unsigned int pack_used_ctr;
@@ -829,13 +840,7 @@
 
 struct packed_git *parse_pack_index(unsigned char *sha1)
 {
-	char *path = sha1_pack_index_name(sha1);
-	return parse_pack_index_file(sha1, path);
-}
-
-struct packed_git *parse_pack_index_file(const unsigned char *sha1,
-					 const char *idx_path)
-{
+	const char *idx_path = sha1_pack_index_name(sha1);
 	const char *path = sha1_pack_name(sha1);
 	struct packed_git *p = xmalloc(sizeof(*p) + strlen(path) + 2);
 
@@ -993,38 +998,58 @@
 	return hashcmp(sha1, real_sha1) ? -1 : 0;
 }
 
+static int git_open_noatime(const char *name)
+{
+	static int sha1_file_open_flag = O_NOATIME;
+	int fd = open(name, O_RDONLY | sha1_file_open_flag);
+
+	/* Might the failure be due to O_NOATIME? */
+	if (fd < 0 && errno != ENOENT && sha1_file_open_flag) {
+		fd = open(name, O_RDONLY);
+		if (fd >= 0)
+			sha1_file_open_flag = 0;
+	}
+	return fd;
+}
+
+static int open_sha1_file(const unsigned char *sha1)
+{
+	int fd;
+	char *name = sha1_file_name(sha1);
+	struct alternate_object_database *alt;
+
+	fd = git_open_noatime(name);
+	if (fd >= 0)
+		return fd;
+
+	prepare_alt_odb();
+	errno = ENOENT;
+	for (alt = alt_odb_list; alt; alt = alt->next) {
+		name = alt->name;
+		fill_sha1_path(name, sha1);
+		fd = git_open_noatime(alt->base);
+		if (fd >= 0)
+			return fd;
+	}
+	return -1;
+}
+
 static void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
 {
-	struct stat st;
 	void *map;
 	int fd;
-	char *filename = find_sha1_file(sha1, &st);
 
-	if (!filename) {
-		return NULL;
-	}
+	fd = open_sha1_file(sha1);
+	map = NULL;
+	if (fd >= 0) {
+		struct stat st;
 
-	fd = open(filename, O_RDONLY | sha1_file_open_flag);
-	if (fd < 0) {
-		/* See if it works without O_NOATIME */
-		switch (sha1_file_open_flag) {
-		default:
-			fd = open(filename, O_RDONLY);
-			if (fd >= 0)
-				break;
-		/* Fallthrough */
-		case 0:
-			return NULL;
+		if (!fstat(fd, &st)) {
+			*size = xsize_t(st.st_size);
+			map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
 		}
-
-		/* If it failed once, it will probably fail again.
-		 * Stop using O_NOATIME
-		 */
-		sha1_file_open_flag = 0;
+		close(fd);
 	}
-	*size = xsize_t(st.st_size);
-	map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
-	close(fd);
 	return map;
 }
 
@@ -1584,6 +1609,7 @@
 	off_t base_offset;
 
 	base_offset = get_delta_base(p, w_curs, &curpos, *type, obj_offset);
+	unuse_pack(w_curs);
 	base = cache_or_unpack_entry(p, base_offset, &base_size, type, 0);
 	if (!base)
 		die("failed to read delta base object"
@@ -1675,7 +1701,12 @@
 {
 	const uint32_t *level1_ofs = p->index_data;
 	const unsigned char *index = p->index_data;
-	unsigned hi, lo;
+	unsigned hi, lo, stride;
+	static int use_lookup = -1;
+	static int debug_lookup = -1;
+
+	if (debug_lookup < 0)
+		debug_lookup = !!getenv("GIT_DEBUG_LOOKUP");
 
 	if (!index) {
 		if (open_pack_index(p))
@@ -1690,11 +1721,34 @@
 	index += 4 * 256;
 	hi = ntohl(level1_ofs[*sha1]);
 	lo = ((*sha1 == 0x0) ? 0 : ntohl(level1_ofs[*sha1 - 1]));
+	if (p->index_version > 1) {
+		stride = 20;
+	} else {
+		stride = 24;
+		index += 4;
+	}
+
+	if (debug_lookup)
+		printf("%02x%02x%02x... lo %u hi %u nr %u\n",
+		       sha1[0], sha1[1], sha1[2], lo, hi, p->num_objects);
+
+	if (use_lookup < 0)
+		use_lookup = !!getenv("GIT_USE_LOOKUP");
+	if (use_lookup) {
+		int pos = sha1_entry_pos(index, stride, 0,
+					 lo, hi, p->num_objects, sha1);
+		if (pos < 0)
+			return 0;
+		return nth_packed_object_offset(p, pos);
+	}
 
 	do {
 		unsigned mi = (lo + hi) / 2;
-		unsigned x = (p->index_version > 1) ? (mi * 20) : (mi * 24 + 4);
-		int cmp = hashcmp(index + x, sha1);
+		int cmp = hashcmp(index + mi * stride, sha1);
+
+		if (debug_lookup)
+			printf("lo %u hi %u rg %u mi %u\n",
+			       lo, hi, hi - lo, mi);
 		if (!cmp)
 			return nth_packed_object_offset(p, mi);
 		if (cmp > 0)
@@ -1987,48 +2041,11 @@
 }
 
 /*
- * Link the tempfile to the final place, possibly creating the
- * last directory level as you do so.
- *
- * Returns the errno on failure, 0 on success.
- */
-static int link_temp_to_file(const char *tmpfile, const char *filename)
-{
-	int ret;
-	char *dir;
-
-	if (!link(tmpfile, filename))
-		return 0;
-
-	/*
-	 * Try to mkdir the last path component if that failed.
-	 *
-	 * Re-try the "link()" regardless of whether the mkdir
-	 * succeeds, since a race might mean that somebody
-	 * else succeeded.
-	 */
-	ret = errno;
-	dir = strrchr(filename, '/');
-	if (dir) {
-		*dir = 0;
-		if (!mkdir(filename, 0777) && adjust_shared_perm(filename)) {
-			*dir = '/';
-			return -2;
-		}
-		*dir = '/';
-		if (!link(tmpfile, filename))
-			return 0;
-		ret = errno;
-	}
-	return ret;
-}
-
-/*
  * Move the just written object into its final resting place
  */
 int move_temp_to_file(const char *tmpfile, const char *filename)
 {
-	int ret = link_temp_to_file(tmpfile, filename);
+	int ret = link(tmpfile, filename);
 
 	/*
 	 * Coda hack - coda doesn't like cross-directory links,
@@ -2073,43 +2090,68 @@
 	return 0;
 }
 
-int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
+/* Finalize a file on disk, and close it. */
+static void close_sha1_file(int fd)
 {
-	int size, ret;
+	if (fsync_object_files)
+		fsync_or_die(fd, "sha1 file");
+	fchmod(fd, 0444);
+	if (close(fd) != 0)
+		die("unable to write sha1 file");
+}
+
+/* Size of directory component, including the ending '/' */
+static inline int directory_size(const char *filename)
+{
+	const char *s = strrchr(filename, '/');
+	if (!s)
+		return 0;
+	return s - filename + 1;
+}
+
+/*
+ * This creates a temporary file in the same directory as the final
+ * 'filename'
+ *
+ * We want to avoid cross-directory filename renames, because those
+ * can have problems on various filesystems (FAT, NFS, Coda).
+ */
+static int create_tmpfile(char *buffer, size_t bufsiz, const char *filename)
+{
+	int fd, dirlen = directory_size(filename);
+
+	if (dirlen + 20 > bufsiz) {
+		errno = ENAMETOOLONG;
+		return -1;
+	}
+	memcpy(buffer, filename, dirlen);
+	strcpy(buffer + dirlen, "tmp_obj_XXXXXX");
+	fd = mkstemp(buffer);
+	if (fd < 0 && dirlen) {
+		/* Make sure the directory exists */
+		memcpy(buffer, filename, dirlen);
+		buffer[dirlen-1] = 0;
+		if (mkdir(buffer, 0777) || adjust_shared_perm(buffer))
+			return -1;
+
+		/* Try again */
+		strcpy(buffer + dirlen - 1, "/tmp_obj_XXXXXX");
+		fd = mkstemp(buffer);
+	}
+	return fd;
+}
+
+static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
+			      void *buf, unsigned long len, time_t mtime)
+{
+	int fd, size, ret;
 	unsigned char *compressed;
 	z_stream stream;
-	unsigned char sha1[20];
 	char *filename;
 	static char tmpfile[PATH_MAX];
-	char hdr[32];
-	int fd, hdrlen;
 
-	/* Normally if we have it in the pack then we do not bother writing
-	 * it out into .git/objects/??/?{38} file.
-	 */
-	write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
 	filename = sha1_file_name(sha1);
-	if (returnsha1)
-		hashcpy(returnsha1, sha1);
-	if (has_sha1_file(sha1))
-		return 0;
-	fd = open(filename, O_RDONLY);
-	if (fd >= 0) {
-		/*
-		 * FIXME!!! We might do collision checking here, but we'd
-		 * need to uncompress the old file and check it. Later.
-		 */
-		close(fd);
-		return 0;
-	}
-
-	if (errno != ENOENT) {
-		return error("sha1 file %s: %s\n", filename, strerror(errno));
-	}
-
-	snprintf(tmpfile, sizeof(tmpfile), "%s/tmp_obj_XXXXXX", get_object_directory());
-
-	fd = mkstemp(tmpfile);
+	fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
 	if (fd < 0) {
 		if (errno == EPERM)
 			return error("insufficient permission for adding an object to repository database %s\n", get_object_directory());
@@ -2148,156 +2190,53 @@
 
 	if (write_buffer(fd, compressed, size) < 0)
 		die("unable to write sha1 file");
-	fchmod(fd, 0444);
-	if (close(fd))
-		die("unable to write sha1 file");
+	close_sha1_file(fd);
 	free(compressed);
 
+	if (mtime) {
+		struct utimbuf utb;
+		utb.actime = mtime;
+		utb.modtime = mtime;
+		if (utime(tmpfile, &utb) < 0)
+			warning("failed utime() on %s: %s",
+				tmpfile, strerror(errno));
+	}
+
 	return move_temp_to_file(tmpfile, filename);
 }
 
-/*
- * We need to unpack and recompress the object for writing
- * it out to a different file.
- */
-static void *repack_object(const unsigned char *sha1, unsigned long *objsize)
+int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
 {
-	size_t size;
-	z_stream stream;
-	unsigned char *unpacked;
+	unsigned char sha1[20];
+	char hdr[32];
+	int hdrlen;
+
+	/* Normally if we have it in the pack then we do not bother writing
+	 * it out into .git/objects/??/?{38} file.
+	 */
+	write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
+	if (returnsha1)
+		hashcpy(returnsha1, sha1);
+	if (has_sha1_file(sha1))
+		return 0;
+	return write_loose_object(sha1, hdr, hdrlen, buf, len, 0);
+}
+
+int force_object_loose(const unsigned char *sha1, time_t mtime)
+{
+	void *buf;
 	unsigned long len;
 	enum object_type type;
 	char hdr[32];
 	int hdrlen;
-	void *buf;
 
-	/* need to unpack and recompress it by itself */
-	unpacked = read_packed_sha1(sha1, &type, &len);
-	if (!unpacked)
-		error("cannot read sha1_file for %s", sha1_to_hex(sha1));
-
+	if (has_loose_object(sha1))
+		return 0;
+	buf = read_packed_sha1(sha1, &type, &len);
+	if (!buf)
+		return error("cannot read sha1_file for %s", sha1_to_hex(sha1));
 	hdrlen = sprintf(hdr, "%s %lu", typename(type), len) + 1;
-
-	/* Set it up */
-	memset(&stream, 0, sizeof(stream));
-	deflateInit(&stream, zlib_compression_level);
-	size = deflateBound(&stream, len + hdrlen);
-	buf = xmalloc(size);
-
-	/* Compress it */
-	stream.next_out = buf;
-	stream.avail_out = size;
-
-	/* First header.. */
-	stream.next_in = (void *)hdr;
-	stream.avail_in = hdrlen;
-	while (deflate(&stream, 0) == Z_OK)
-		/* nothing */;
-
-	/* Then the data itself.. */
-	stream.next_in = unpacked;
-	stream.avail_in = len;
-	while (deflate(&stream, Z_FINISH) == Z_OK)
-		/* nothing */;
-	deflateEnd(&stream);
-	free(unpacked);
-
-	*objsize = stream.total_out;
-	return buf;
-}
-
-int write_sha1_to_fd(int fd, const unsigned char *sha1)
-{
-	int retval;
-	unsigned long objsize;
-	void *buf = map_sha1_file(sha1, &objsize);
-
-	if (buf) {
-		retval = write_buffer(fd, buf, objsize);
-		munmap(buf, objsize);
-		return retval;
-	}
-
-	buf = repack_object(sha1, &objsize);
-	retval = write_buffer(fd, buf, objsize);
-	free(buf);
-	return retval;
-}
-
-int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
-		       size_t bufsize, size_t *bufposn)
-{
-	char tmpfile[PATH_MAX];
-	int local;
-	z_stream stream;
-	unsigned char real_sha1[20];
-	unsigned char discard[4096];
-	int ret;
-	SHA_CTX c;
-
-	snprintf(tmpfile, sizeof(tmpfile), "%s/tmp_obj_XXXXXX", get_object_directory());
-
-	local = mkstemp(tmpfile);
-	if (local < 0) {
-		if (errno == EPERM)
-			return error("insufficient permission for adding an object to repository database %s\n", get_object_directory());
-		else
-			return error("unable to create temporary sha1 filename %s: %s\n", tmpfile, strerror(errno));
-	}
-
-	memset(&stream, 0, sizeof(stream));
-
-	inflateInit(&stream);
-
-	SHA1_Init(&c);
-
-	do {
-		ssize_t size;
-		if (*bufposn) {
-			stream.avail_in = *bufposn;
-			stream.next_in = (unsigned char *) buffer;
-			do {
-				stream.next_out = discard;
-				stream.avail_out = sizeof(discard);
-				ret = inflate(&stream, Z_SYNC_FLUSH);
-				SHA1_Update(&c, discard, sizeof(discard) -
-					    stream.avail_out);
-			} while (stream.avail_in && ret == Z_OK);
-			if (write_buffer(local, buffer, *bufposn - stream.avail_in) < 0)
-				die("unable to write sha1 file");
-			memmove(buffer, buffer + *bufposn - stream.avail_in,
-				stream.avail_in);
-			*bufposn = stream.avail_in;
-			if (ret != Z_OK)
-				break;
-		}
-		size = xread(fd, buffer + *bufposn, bufsize - *bufposn);
-		if (size <= 0) {
-			close(local);
-			unlink(tmpfile);
-			if (!size)
-				return error("Connection closed?");
-			perror("Reading from connection");
-			return -1;
-		}
-		*bufposn += size;
-	} while (1);
-	inflateEnd(&stream);
-
-	fchmod(local, 0444);
-	if (close(local) != 0)
-		die("unable to write sha1 file");
-	SHA1_Final(real_sha1, &c);
-	if (ret != Z_STREAM_END) {
-		unlink(tmpfile);
-		return error("File %s corrupted", sha1_to_hex(sha1));
-	}
-	if (hashcmp(sha1, real_sha1)) {
-		unlink(tmpfile);
-		return error("File %s has bad hash", sha1_to_hex(sha1));
-	}
-
-	return move_temp_to_file(tmpfile, sha1_file_name(sha1));
+	return write_loose_object(sha1, hdr, hdrlen, buf, len, mtime);
 }
 
 int has_pack_index(const unsigned char *sha1)
@@ -2324,12 +2263,11 @@
 
 int has_sha1_file(const unsigned char *sha1)
 {
-	struct stat st;
 	struct pack_entry e;
 
 	if (find_pack_entry(sha1, &e, NULL))
 		return 1;
-	return find_sha1_file(sha1, &st) ? 1 : 0;
+	return has_loose_object(sha1);
 }
 
 int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object)
@@ -2437,16 +2375,10 @@
 
 int read_pack_header(int fd, struct pack_header *header)
 {
-	char *c = (char*)header;
-	ssize_t remaining = sizeof(struct pack_header);
-	do {
-		ssize_t r = xread(fd, c, remaining);
-		if (r <= 0)
-			/* "eof before pack header was fully read" */
-			return PH_ERROR_EOF;
-		remaining -= r;
-		c += r;
-	} while (remaining > 0);
+	if (read_in_full(fd, header, sizeof(*header)) < sizeof(*header))
+		/* "eof before pack header was fully read" */
+		return PH_ERROR_EOF;
+
 	if (header->hdr_signature != htonl(PACK_SIGNATURE))
 		/* "protocol error (pack signature mismatch detected)" */
 		return PH_ERROR_PACK_SIGNATURE;
diff --git a/symlinks.c b/symlinks.c
index be9ace6..5a5e781 100644
--- a/symlinks.c
+++ b/symlinks.c
@@ -1,48 +1,64 @@
 #include "cache.h"
 
-int has_symlink_leading_path(const char *name, char *last_symlink)
-{
+struct pathname {
+	int len;
 	char path[PATH_MAX];
-	const char *sp, *ep;
-	char *dp;
+};
 
-	sp = name;
-	dp = path;
+/* Return matching pathname prefix length, or zero if not matching */
+static inline int match_pathname(int len, const char *name, struct pathname *match)
+{
+	int match_len = match->len;
+	return (len > match_len &&
+		name[match_len] == '/' &&
+		!memcmp(name, match->path, match_len)) ? match_len : 0;
+}
 
-	if (last_symlink && *last_symlink) {
-		size_t last_len = strlen(last_symlink);
-		size_t len = strlen(name);
-		if (last_len < len &&
-		    !strncmp(name, last_symlink, last_len) &&
-		    name[last_len] == '/')
-			return 1;
-		*last_symlink = '\0';
+static inline void set_pathname(int len, const char *name, struct pathname *match)
+{
+	if (len < PATH_MAX) {
+		match->len = len;
+		memcpy(match->path, name, len);
+		match->path[len] = 0;
 	}
+}
 
-	while (1) {
-		size_t len;
-		struct stat st;
+int has_symlink_leading_path(int len, const char *name)
+{
+	static struct pathname link, nonlink;
+	char path[PATH_MAX];
+	struct stat st;
+	char *sp;
+	int known_dir;
 
-		ep = strchr(sp, '/');
-		if (!ep)
-			break;
-		len = ep - sp;
-		if (PATH_MAX <= dp + len - path + 2)
-			return 0; /* new name is longer than that??? */
-		memcpy(dp, sp, len);
-		dp[len] = 0;
+	/*
+	 * See if the last known symlink cache matches.
+	 */
+	if (match_pathname(len, name, &link))
+		return 1;
+
+	/*
+	 * Get rid of the last known directory part
+	 */
+	known_dir = match_pathname(len, name, &nonlink);
+
+	while ((sp = strchr(name + known_dir + 1, '/')) != NULL) {
+		int thislen = sp - name ;
+		memcpy(path, name, thislen);
+		path[thislen] = 0;
 
 		if (lstat(path, &st))
 			return 0;
+		if (S_ISDIR(st.st_mode)) {
+			set_pathname(thislen, path, &nonlink);
+			known_dir = thislen;
+			continue;
+		}
 		if (S_ISLNK(st.st_mode)) {
-			if (last_symlink)
-				strcpy(last_symlink, path);
+			set_pathname(thislen, path, &link);
 			return 1;
 		}
-
-		dp[len++] = '/';
-		dp = dp + len;
-		sp = ep + 1;
+		break;
 	}
 	return 0;
 }
diff --git a/t/.gitattributes b/t/.gitattributes
index 562b12e..ab6edbf 100644
--- a/t/.gitattributes
+++ b/t/.gitattributes
@@ -1 +1,2 @@
-* -whitespace
+t[0-9][0-9][0-9][0-9]-*.sh -whitespace
+t[0-9][0-9][0-9][0-9]/* -whitespace
diff --git a/t/.gitignore b/t/.gitignore
index fad67c0..11ffd91 100644
--- a/t/.gitignore
+++ b/t/.gitignore
@@ -1 +1 @@
-trash
+/trash directory
diff --git a/t/Makefile b/t/Makefile
index 72d7884..c6a60ab 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -20,7 +20,7 @@
 	@echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS)
 
 clean:
-	$(RM) -r trash
+	$(RM) -r 'trash directory'
 
 # we can test NO_OPTIMIZE_COMMITS independently of LC_ALL
 full-svn-test:
diff --git a/t/README b/t/README
index 73ed11b..70841a4 100644
--- a/t/README
+++ b/t/README
@@ -123,7 +123,7 @@
    (or -h), it shows the test_description and exits.
 
  - Creates an empty test directory with an empty .git/objects
-   database and chdir(2) into it.  This directory is 't/trash'
+   database and chdir(2) into it.  This directory is 't/trash directory'
    if you must know, but I do not think you care.
 
  - Defines standard test helper functions for your scripts to
diff --git a/t/diff-lib.sh b/t/diff-lib.sh
index 28b941c..4bddeb5 100644
--- a/t/diff-lib.sh
+++ b/t/diff-lib.sh
@@ -11,7 +11,7 @@
 
     sed -e "$sanitize_diff_raw" <"$1" >.tmp-1
     sed -e "$sanitize_diff_raw" <"$2" >.tmp-2
-    git diff .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
+    test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
 }
 
 sanitize_diff_raw_z='/^:/s/ '"$_x40"' '"$_x40"' \([A-Z]\)[0-9]*$/ X X \1#/'
@@ -23,7 +23,7 @@
 
     perl -pe 'y/\000/\012/' <"$1" | sed -e "$sanitize_diff_raw_z" >.tmp-1
     perl -pe 'y/\000/\012/' <"$2" | sed -e "$sanitize_diff_raw_z" >.tmp-2
-    git diff .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
+    test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
 }
 
 compare_diff_patch () {
@@ -37,5 +37,5 @@
 	/^[dis]*imilarity index [0-9]*%$/d
 	/^index [0-9a-f]*\.\.[0-9a-f]/d
     ' <"$2" >.tmp-2
-    git diff .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
+    test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
 }
diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh
index 9decd2e..5d3bd9d 100644
--- a/t/lib-git-svn.sh
+++ b/t/lib-git-svn.sh
@@ -20,12 +20,13 @@
 fi
 
 svnrepo=$PWD/svnrepo
+export svnrepo
 
 perl -w -e "
 use SVN::Core;
 use SVN::Repos;
 \$SVN::Core::VERSION gt '1.1.0' or exit(42);
-system(qw/svnadmin create --fs-type fsfs/, '$svnrepo') == 0 or exit(41);
+system(qw/svnadmin create --fs-type fsfs/, \$ENV{svnrepo}) == 0 or exit(41);
 " >&3 2>&4
 x=$?
 if test $x -ne 0
@@ -73,11 +74,16 @@
 done
 
 start_httpd () {
+	repo_base_path="$1"
 	if test -z "$SVN_HTTPD_PORT"
 	then
 		echo >&2 'SVN_HTTPD_PORT is not defined!'
 		return
 	fi
+	if test -z "$repo_base_path"
+	then
+		repo_base_path=svn
+	fi
 
 	mkdir "$GIT_DIR"/logs
 
@@ -90,13 +96,13 @@
 Listen 127.0.0.1:$SVN_HTTPD_PORT
 LoadModule dav_module $SVN_HTTPD_MODULE_PATH/mod_dav.so
 LoadModule dav_svn_module $SVN_HTTPD_MODULE_PATH/mod_dav_svn.so
-<Location /svn>
+<Location /$repo_base_path>
 	DAV svn
 	SVNPath $rawsvnrepo
 </Location>
 EOF
 	"$SVN_HTTPD_PATH" -f "$GIT_DIR"/httpd.conf -k start
-	svnrepo=http://127.0.0.1:$SVN_HTTPD_PORT/svn
+	svnrepo="http://127.0.0.1:$SVN_HTTPD_PORT/$repo_base_path"
 }
 
 stop_httpd () {
diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index 7f206c5..a5c4436 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -61,7 +61,8 @@
 			-new -x509 -nodes \
 			-out $HTTPD_ROOT_PATH/httpd.pem \
 			-keyout $HTTPD_ROOT_PATH/httpd.pem
-		export GIT_SSL_NO_VERIFY=t
+		GIT_SSL_NO_VERIFY=t
+		export GIT_SSL_NO_VERIFY
 		HTTPD_PARA="$HTTPD_PARA -DSSL"
 	else
 		HTTPD_URL=http://127.0.0.1:$LIB_HTTPD_PORT
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 27b54cb..690f80a 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -305,10 +305,10 @@
 	file="$dir"/index &&
 	test "$file" = "$(test-absolute-path $dir2/index)" &&
 	basename=blub &&
-	test "$dir/$basename" = $(cd .git && test-absolute-path $basename) &&
+	test "$dir/$basename" = "$(cd .git && test-absolute-path "$basename")" &&
 	ln -s ../first/file .git/syml &&
 	sym="$(cd first; pwd -P)"/file &&
-	test "$sym" = "$(test-absolute-path $dir2/syml)"
+	test "$sym" = "$(test-absolute-path "$dir2/syml")"
 '
 
 test_expect_success 'very long name in the index handled sanely' '
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index b0289e3..c0b781a 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -79,6 +79,17 @@
 	check_config git-dir-bare.git true unset
 '
 
+test_expect_success 'init --bare' '
+
+	(
+		unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+		mkdir git-init-bare.git &&
+		cd git-init-bare.git &&
+		git init --bare
+	) &&
+	check_config git-init-bare.git true unset
+'
+
 test_expect_success 'GIT_DIR non-bare' '
 
 	(
@@ -130,4 +141,30 @@
 	test_cmp again/empty again/err2
 '
 
+test_expect_success 'init with --template' '
+	mkdir template-source &&
+	echo content >template-source/file &&
+	(
+		mkdir template-custom &&
+		cd template-custom &&
+		git init --template=../template-source
+	) &&
+	test_cmp template-source/file template-custom/.git/file
+'
+
+test_expect_success 'init with --template (blank)' '
+	(
+		mkdir template-plain &&
+		cd template-plain &&
+		git init
+	) &&
+	test -f template-plain/.git/info/exclude &&
+	(
+		mkdir template-blank &&
+		cd template-blank &&
+		git init --template=
+	) &&
+	! test -f template-blank/.git/info/exclude
+'
+
 test_done
diff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh
new file mode 100755
index 0000000..c5dbc72
--- /dev/null
+++ b/t/t0002-gitfile.sh
@@ -0,0 +1,103 @@
+#!/bin/sh
+
+test_description='.git file
+
+Verify that plumbing commands work when .git is a file
+'
+. ./test-lib.sh
+
+objpath() {
+    echo "$1" | sed -e 's|\(..\)|\1/|'
+}
+
+objck() {
+	p=$(objpath "$1")
+	if test ! -f "$REAL/objects/$p"
+	then
+		echo "Object not found: $REAL/objects/$p"
+		false
+	fi
+}
+
+
+test_expect_success 'initial setup' '
+	REAL="$(pwd)/.real" &&
+	mv .git "$REAL"
+'
+
+test_expect_success 'bad setup: invalid .git file format' '
+	echo "gitdir $REAL" >.git &&
+	if git rev-parse 2>.err
+	then
+		echo "git rev-parse accepted an invalid .git file"
+		false
+	fi &&
+	if ! grep -qe "Invalid gitfile format" .err
+	then
+		echo "git rev-parse returned wrong error"
+		false
+	fi
+'
+
+test_expect_success 'bad setup: invalid .git file path' '
+	echo "gitdir: $REAL.not" >.git &&
+	if git rev-parse 2>.err
+	then
+		echo "git rev-parse accepted an invalid .git file path"
+		false
+	fi &&
+	if ! grep -qe "Not a git repository" .err
+	then
+		echo "git rev-parse returned wrong error"
+		false
+	fi
+'
+
+test_expect_success 'final setup + check rev-parse --git-dir' '
+	echo "gitdir: $REAL" >.git &&
+	test "$REAL" = "$(git rev-parse --git-dir)"
+'
+
+test_expect_success 'check hash-object' '
+	echo "foo" >bar &&
+	SHA=$(cat bar | git hash-object -w --stdin) &&
+	objck $SHA
+'
+
+test_expect_success 'check cat-file' '
+	git cat-file blob $SHA >actual &&
+	diff -u bar actual
+'
+
+test_expect_success 'check update-index' '
+	if test -f "$REAL/index"
+	then
+		echo "Hmm, $REAL/index exists?"
+		false
+	fi &&
+	rm -f "$REAL/objects/$(objpath $SHA)" &&
+	git update-index --add bar &&
+	if ! test -f "$REAL/index"
+	then
+		echo "$REAL/index not found"
+		false
+	fi &&
+	objck $SHA
+'
+
+test_expect_success 'check write-tree' '
+	SHA=$(git write-tree) &&
+	objck $SHA
+'
+
+test_expect_success 'check commit-tree' '
+	SHA=$(echo "commit bar" | git commit-tree $SHA) &&
+	objck $SHA
+'
+
+test_expect_success 'check rev-list' '
+	echo $SHA >"$REAL/HEAD" &&
+	test "$SHA" = "$(git rev-list HEAD)"
+'
+
+test_done
diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index c56d2fb..3d8e06a 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -54,4 +54,39 @@
 
 '
 
+test_expect_success 'setup bare' '
+
+	git clone --bare . bare.git &&
+	cd bare.git
+
+'
+
+test_expect_success 'bare repository: check that .gitattribute is ignored' '
+
+	(
+		echo "f	test=f"
+		echo "a/i test=a/i"
+	) >.gitattributes &&
+	attr_check f unspecified &&
+	attr_check a/f unspecified &&
+	attr_check a/c/f unspecified &&
+	attr_check a/i unspecified &&
+	attr_check subdir/a/i unspecified
+
+'
+
+test_expect_success 'bare repository: test info/attributes' '
+
+	(
+		echo "f	test=f"
+		echo "a/i test=a/i"
+	) >info/attributes &&
+	attr_check f f &&
+	attr_check a/f f &&
+	attr_check a/c/f f &&
+	attr_check a/i a/i &&
+	attr_check subdir/a/i unspecified
+
+'
+
 test_done
diff --git a/t/t0004-unwritable.sh b/t/t0004-unwritable.sh
index 9255c63..63e1217 100755
--- a/t/t0004-unwritable.sh
+++ b/t/t0004-unwritable.sh
@@ -8,6 +8,7 @@
 
 	>file &&
 	git add file &&
+	test_tick &&
 	git commit -m initial &&
 	echo >file &&
 	git add file
@@ -17,11 +18,11 @@
 test_expect_success 'write-tree should notice unwritable repository' '
 
 	(
-		chmod a-w .git/objects
+		chmod a-w .git/objects .git/objects/?? &&
 		test_must_fail git write-tree
 	)
 	status=$?
-	chmod 775 .git/objects
+	chmod 775 .git/objects .git/objects/??
 	(exit $status)
 
 '
@@ -29,11 +30,11 @@
 test_expect_success 'commit should notice unwritable repository' '
 
 	(
-		chmod a-w .git/objects
+		chmod a-w .git/objects .git/objects/?? &&
 		test_must_fail git commit -m second
 	)
 	status=$?
-	chmod 775 .git/objects
+	chmod 775 .git/objects .git/objects/??
 	(exit $status)
 
 '
@@ -41,12 +42,12 @@
 test_expect_success 'update-index should notice unwritable repository' '
 
 	(
-		echo a >file &&
-		chmod a-w .git/objects
+		echo 6O >file &&
+		chmod a-w .git/objects .git/objects/?? &&
 		test_must_fail git update-index file
 	)
 	status=$?
-	chmod 775 .git/objects
+	chmod 775 .git/objects .git/objects/??
 	(exit $status)
 
 '
@@ -55,11 +56,11 @@
 
 	(
 		echo b >file &&
-		chmod a-w .git/objects
+		chmod a-w .git/objects .git/objects/?? &&
 		test_must_fail git add file
 	)
 	status=$?
-	chmod 775 .git/objects
+	chmod 775 .git/objects .git/objects/??
 	(exit $status)
 
 '
diff --git a/t/t0030-stripspace.sh b/t/t0030-stripspace.sh
index 3ecdd66..ccb0a3c 100755
--- a/t/t0030-stripspace.sh
+++ b/t/t0030-stripspace.sh
@@ -16,96 +16,96 @@
     'long lines without spaces should be unchanged' '
     echo "$ttt" >expect &&
     git stripspace <expect >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     echo "$ttt$ttt" >expect &&
     git stripspace <expect >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     echo "$ttt$ttt$ttt" >expect &&
     git stripspace <expect >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     echo "$ttt$ttt$ttt$ttt" >expect &&
     git stripspace <expect >actual &&
-    git diff expect actual
+    test_cmp expect actual
 '
 
 test_expect_success \
     'lines with spaces at the beginning should be unchanged' '
     echo "$sss$ttt" >expect &&
     git stripspace <expect >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     echo "$sss$sss$ttt" >expect &&
     git stripspace <expect >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     echo "$sss$sss$sss$ttt" >expect &&
     git stripspace <expect >actual &&
-    git diff expect actual
+    test_cmp expect actual
 '
 
 test_expect_success \
     'lines with intermediate spaces should be unchanged' '
     echo "$ttt$sss$ttt" >expect &&
     git stripspace <expect >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     echo "$ttt$sss$sss$ttt" >expect &&
     git stripspace <expect >actual &&
-    git diff expect actual
+    test_cmp expect actual
 '
 
 test_expect_success \
     'consecutive blank lines should be unified' '
     printf "$ttt\n\n$ttt\n" > expect &&
     printf "$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt$ttt\n\n$ttt\n" > expect &&
     printf "$ttt$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt$ttt$ttt\n\n$ttt\n" > expect &&
     printf "$ttt$ttt$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n\n$ttt\n" > expect &&
     printf "$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n\n$ttt$ttt\n" > expect &&
     printf "$ttt\n\n\n\n\n$ttt$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n\n$ttt$ttt$ttt\n" > expect &&
     printf "$ttt\n\n\n\n\n$ttt$ttt$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n\n$ttt\n" > expect &&
     printf "$ttt\n\t\n \n\n  \t\t\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt$ttt\n\n$ttt\n" > expect &&
     printf "$ttt$ttt\n\t\n \n\n  \t\t\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt$ttt$ttt\n\n$ttt\n" > expect &&
     printf "$ttt$ttt$ttt\n\t\n \n\n  \t\t\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n\n$ttt\n" > expect &&
     printf "$ttt\n\t\n \n\n  \t\t\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n\n$ttt$ttt\n" > expect &&
     printf "$ttt\n\t\n \n\n  \t\t\n$ttt$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n\n$ttt$ttt$ttt\n" > expect &&
     printf "$ttt\n\t\n \n\n  \t\t\n$ttt$ttt$ttt\n" | git stripspace >actual &&
-    git diff expect actual
+    test_cmp expect actual
 '
 
 test_expect_success \
@@ -113,114 +113,114 @@
     > expect &&
 
     printf "\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "\n\n\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$sss\n$sss\n$sss\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$sss$sss\n$sss\n\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "\n$sss\n$sss$sss\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$sss$sss$sss$sss\n\n\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "\n$sss$sss$sss$sss\n\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "\n\n$sss$sss$sss$sss\n" | git stripspace >actual &&
-    git diff expect actual
+    test_cmp expect actual
 '
 
 test_expect_success \
     'consecutive blank lines at the beginning should be removed' '
     printf "$ttt\n" > expect &&
     printf "\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n" > expect &&
     printf "\n\n\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt$ttt\n" > expect &&
     printf "\n\n\n$ttt$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt$ttt$ttt\n" > expect &&
     printf "\n\n\n$ttt$ttt$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt$ttt$ttt$ttt\n" > expect &&
     printf "\n\n\n$ttt$ttt$ttt$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n" > expect &&
 
     printf "$sss\n$sss\n$sss\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "\n$sss\n$sss$sss\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$sss$sss\n$sss\n\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$sss$sss$sss\n\n\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "\n$sss$sss$sss\n\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "\n\n$sss$sss$sss\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual
+    test_cmp expect actual
 '
 
 test_expect_success \
     'consecutive blank lines at the end should be removed' '
     printf "$ttt\n" > expect &&
     printf "$ttt\n\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n" > expect &&
     printf "$ttt\n\n\n\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt$ttt\n" > expect &&
     printf "$ttt$ttt\n\n\n\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt$ttt$ttt\n" > expect &&
     printf "$ttt$ttt$ttt\n\n\n\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt$ttt$ttt$ttt\n" > expect &&
     printf "$ttt$ttt$ttt$ttt\n\n\n\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n" > expect &&
 
     printf "$ttt\n$sss\n$sss\n$sss\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n\n$sss\n$sss$sss\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n$sss$sss\n$sss\n\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n$sss$sss$sss\n\n\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n\n$sss$sss$sss\n\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n\n\n$sss$sss$sss\n" | git stripspace >actual &&
-    git diff expect actual
+    test_cmp expect actual
 '
 
 test_expect_success \
@@ -257,27 +257,27 @@
     'text plus spaces without newline should show the correct lines' '
     printf "$ttt\n" >expect &&
     printf "$ttt$sss" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n" >expect &&
     printf "$ttt$sss$sss" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n" >expect &&
     printf "$ttt$sss$sss$sss" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt$ttt\n" >expect &&
     printf "$ttt$ttt$sss" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt$ttt\n" >expect &&
     printf "$ttt$ttt$sss$sss" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt$ttt$ttt\n" >expect &&
     printf "$ttt$ttt$ttt$sss" | git stripspace >actual &&
-    git diff expect actual
+    test_cmp expect actual
 '
 
 test_expect_success \
@@ -294,27 +294,27 @@
     'text plus spaces at end should be cleaned and newline must remain' '
     echo "$ttt" >expect &&
     echo "$ttt$sss" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     echo "$ttt" >expect &&
     echo "$ttt$sss$sss" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     echo "$ttt" >expect &&
     echo "$ttt$sss$sss$sss" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     echo "$ttt$ttt" >expect &&
     echo "$ttt$ttt$sss" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     echo "$ttt$ttt" >expect &&
     echo "$ttt$ttt$sss$sss" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     echo "$ttt$ttt$ttt" >expect &&
     echo "$ttt$ttt$ttt$sss" | git stripspace >actual &&
-    git diff expect actual
+    test_cmp expect actual
 '
 
 # spaces only:
@@ -324,19 +324,19 @@
     printf "" >expect &&
 
     echo | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     echo "$sss" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     echo "$sss$sss" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     echo "$sss$sss$sss" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     echo "$sss$sss$sss$sss" | git stripspace >actual &&
-    git diff expect actual
+    test_cmp expect actual
 '
 
 test_expect_success \
@@ -353,43 +353,43 @@
     printf "" >expect &&
 
     printf "" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$sss$sss" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$sss$sss$sss" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$sss$sss$sss$sss" | git stripspace >actual &&
-    git diff expect actual
+    test_cmp expect actual
 '
 
 test_expect_success \
     'consecutive text lines should be unchanged' '
     printf "$ttt$ttt\n$ttt\n" >expect &&
     printf "$ttt$ttt\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n$ttt$ttt\n$ttt\n" >expect &&
     printf "$ttt\n$ttt$ttt\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n$ttt\n$ttt\n$ttt$ttt\n" >expect &&
     printf "$ttt\n$ttt\n$ttt\n$ttt$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n$ttt\n\n$ttt$ttt\n$ttt\n" >expect &&
     printf "$ttt\n$ttt\n\n$ttt$ttt\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt$ttt\n\n$ttt\n$ttt$ttt\n" >expect &&
     printf "$ttt$ttt\n\n$ttt\n$ttt$ttt\n" | git stripspace >actual &&
-    git diff expect actual &&
+    test_cmp expect actual &&
 
     printf "$ttt\n$ttt$ttt\n\n$ttt\n" >expect &&
     printf "$ttt\n$ttt$ttt\n\n$ttt\n" | git stripspace >actual &&
-    git diff expect actual
+    test_cmp expect actual
 '
 
 test_expect_success 'strip comments, too' '
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index c23f0ac..6309aed 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -11,55 +11,81 @@
 usage: test-parse-options <options>
 
     -b, --boolean         get a boolean
+    -4, --or4             bitwise-or boolean with ...0100
+
     -i, --integer <n>     get a integer
     -j <n>                get a integer, too
+    --set23               set integer to 23
+    -t <time>             get timestamp of <time>
+    -L, --length <str>    get length of <str>
 
-string options
+String options
     -s, --string <string>
                           get a string
     --string2 <str>       get another string
     --st <st>             get another string (pervert ordering)
     -o <str>              get another string
+    --default-string      set string to default
 
-magic arguments
+Magic arguments
     --quux                means --quux
 
+Standard options
+    --abbrev[=<n>]        use <n> digits to display SHA-1s
+    -v, --verbose         be verbose
+    -n, --dry-run         dry run
+    -q, --quiet           be quiet
+
 EOF
 
 test_expect_success 'test help' '
-	! test-parse-options -h > output 2> output.err &&
+	test_must_fail test-parse-options -h > output 2> output.err &&
 	test ! -s output &&
-	git diff expect.err output.err
+	test_cmp expect.err output.err
 '
 
 cat > expect << EOF
 boolean: 2
 integer: 1729
 string: 123
+abbrev: 7
+verbose: 2
+quiet: no
+dry run: yes
 EOF
 
 test_expect_success 'short options' '
-	test-parse-options -s123 -b -i 1729 -b > output 2> output.err &&
-	git diff expect output &&
+	test-parse-options -s123 -b -i 1729 -b -vv -n > output 2> output.err &&
+	test_cmp expect output &&
 	test ! -s output.err
 '
+
 cat > expect << EOF
 boolean: 2
 integer: 1729
 string: 321
+abbrev: 10
+verbose: 2
+quiet: no
+dry run: no
 EOF
 
 test_expect_success 'long options' '
 	test-parse-options --boolean --integer 1729 --boolean --string2=321 \
+		--verbose --verbose --no-dry-run --abbrev=10 \
 		> output 2> output.err &&
 	test ! -s output.err &&
-	git diff expect output
+	test_cmp expect output
 '
 
 cat > expect << EOF
 boolean: 1
 integer: 13
 string: 123
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
 arg 00: a1
 arg 01: b1
 arg 02: --boolean
@@ -69,25 +95,29 @@
 	test-parse-options a1 --string 123 b1 --boolean -j 13 -- --boolean \
 		> output 2> output.err &&
 	test ! -s output.err &&
-	git diff expect output
+	test_cmp expect output
 '
 
 cat > expect << EOF
 boolean: 0
 integer: 2
 string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
 EOF
 
 test_expect_success 'unambiguously abbreviated option' '
 	test-parse-options --int 2 --boolean --no-bo > output 2> output.err &&
 	test ! -s output.err &&
-	git diff expect output
+	test_cmp expect output
 '
 
 test_expect_success 'unambiguously abbreviated option with "="' '
 	test-parse-options --int=2 > output 2> output.err &&
 	test ! -s output.err &&
-	git diff expect output
+	test_cmp expect output
 '
 
 test_expect_success 'ambiguously abbreviated option' '
@@ -99,35 +129,107 @@
 boolean: 0
 integer: 0
 string: 123
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
 EOF
 
 test_expect_success 'non ambiguous option (after two options it abbreviates)' '
 	test-parse-options --st 123 > output 2> output.err &&
 	test ! -s output.err &&
-	git diff expect output
+	test_cmp expect output
 '
 
-cat > expect.err << EOF
+cat > typo.err << EOF
 error: did you mean \`--boolean\` (with two dashes ?)
 EOF
 
 test_expect_success 'detect possible typos' '
-	! test-parse-options -boolean > output 2> output.err &&
+	test_must_fail test-parse-options -boolean > output 2> output.err &&
 	test ! -s output &&
-	git diff expect.err output.err
+	test_cmp typo.err output.err
 '
 
 cat > expect <<EOF
 boolean: 0
 integer: 0
 string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
 arg 00: --quux
 EOF
 
 test_expect_success 'keep some options as arguments' '
 	test-parse-options --quux > output 2> output.err &&
         test ! -s output.err &&
-        git diff expect output
+        test_cmp expect output
 '
 
+cat > expect <<EOF
+boolean: 0
+integer: 1
+string: default
+abbrev: 7
+verbose: 0
+quiet: yes
+dry run: no
+arg 00: foo
+EOF
+
+test_expect_success 'OPT_DATE() and OPT_SET_PTR() work' '
+	test-parse-options -t "1970-01-01 00:00:01 +0000" --default-string \
+		foo -q > output 2> output.err &&
+	test ! -s output.err &&
+	test_cmp expect output
+'
+
+cat > expect <<EOF
+Callback: "four", 0
+boolean: 5
+integer: 4
+string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
+EOF
+
+test_expect_success 'OPT_CALLBACK() and OPT_BIT() work' '
+	test-parse-options --length=four -b -4 > output 2> output.err &&
+	test ! -s output.err &&
+	test_cmp expect output
+'
+
+cat > expect <<EOF
+Callback: "not set", 1
+EOF
+
+test_expect_success 'OPT_CALLBACK() and callback errors work' '
+	test_must_fail test-parse-options --no-length > output 2> output.err &&
+	test_cmp expect output &&
+	test_cmp expect.err output.err
+'
+
+cat > expect <<EOF
+boolean: 1
+integer: 23
+string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
+EOF
+
+test_expect_success 'OPT_BIT() and OPT_SET_INT() work' '
+	test-parse-options --set23 -bbbbb --no-or4 > output 2> output.err &&
+	test ! -s output.err &&
+	test_cmp expect output
+'
+
+# --or4
+# --no-or4
+
 test_done
diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh
index 3fbad77..c5360e2 100755
--- a/t/t0050-filesystem.sh
+++ b/t/t0050-filesystem.sh
@@ -7,6 +7,7 @@
 auml=`printf '\xc3\xa4'`
 aumlcdiar=`printf '\x61\xcc\x88'`
 
+case_insensitive=
 test_expect_success 'see if we expect ' '
 
 	test_case=test_expect_success
@@ -17,6 +18,7 @@
 	if test "$(cat junk/CamelCase)" != good
 	then
 		test_case=test_expect_failure
+		case_insensitive=t
 		say "will test on a case insensitive filesystem"
 	fi &&
 	rm -fr junk &&
@@ -32,8 +34,23 @@
 	rm -fr junk
 '
 
+if test "$case_insensitive"
+then
+test_expect_success "detection of case insensitive filesystem during repo init" '
+
+	test $(git config --bool core.ignorecase) = true
+'
+else
+test_expect_success "detection of case insensitive filesystem during repo init" '
+
+	! git config --bool core.ignorecase >/dev/null ||
+	test $(git config --bool core.ignorecase) = false
+'
+fi
+
 test_expect_success "setup case tests" '
 
+	git config core.ignorecase true &&
 	touch camelcase &&
 	git add camelcase &&
 	git commit -m "initial" &&
@@ -55,11 +72,23 @@
 
 $test_case 'merge (case change)' '
 
+	rm -f CamelCase &&
+	rm -f camelcase &&
 	git reset --hard initial &&
 	git merge topic
 
 '
 
+$test_case 'add (with different case)' '
+
+	git reset --hard initial &&
+	rm camelcase &&
+	echo 1 >CamelCase &&
+	git add CamelCase &&
+	test $(git-ls-files | grep -i camelcase | wc -l) = 1
+
+'
+
 test_expect_success "setup unicode normalization tests" '
 
   test_create_repo unicode &&
diff --git a/t/t1000-read-tree-m-3way.sh b/t/t1000-read-tree-m-3way.sh
index 17f519f..807fb83 100755
--- a/t/t1000-read-tree-m-3way.sh
+++ b/t/t1000-read-tree-m-3way.sh
@@ -131,7 +131,7 @@
 
 check_result () {
     git ls-files --stage | sed -e 's/ '"$_x40"' / X /' >current &&
-    git diff expected current
+    test_cmp expected current
 }
 
 # This is done on an empty work directory, which is the normal
diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh
index b01b003..4b44e13 100755
--- a/t/t1001-read-tree-m-2way.sh
+++ b/t/t1001-read-tree-m-2way.sh
@@ -33,7 +33,7 @@
 	    -e '/^--- /d; /^+++ /d; /^@@ /d;' \
 	    -e 's/^\([-+][0-7][0-7][0-7][0-7][0-7][0-7]\) '"$_x40"' /\1 X /p' \
 	    "$1"
-	git diff expected current
+	test_cmp expected current
 }
 
 check_cache_at () {
@@ -86,7 +86,7 @@
     'rm -f .git/index &&
      read_tree_twoway $treeH $treeM &&
      git ls-files --stage >1-3.out &&
-     git diff M.out 1-3.out &&
+     test_cmp M.out 1-3.out &&
      check_cache_at bozbar dirty &&
      check_cache_at frotz dirty &&
      check_cache_at nitfol dirty'
@@ -101,7 +101,7 @@
      git update-index --add yomin &&
      read_tree_twoway $treeH $treeM &&
      git ls-files --stage >4.out || return 1
-     git diff M.out 4.out >4diff.out
+     git diff --no-index M.out 4.out >4diff.out
      compare_change 4diff.out expected &&
      check_cache_at yomin clean'
 
@@ -115,7 +115,7 @@
      echo yomin yomin >yomin &&
      read_tree_twoway $treeH $treeM &&
      git ls-files --stage >5.out || return 1
-     git diff M.out 5.out >5diff.out
+     git diff --no-index M.out 5.out >5diff.out
      compare_change 5diff.out expected &&
      check_cache_at yomin dirty'
 
@@ -127,7 +127,7 @@
      git update-index --add frotz &&
      read_tree_twoway $treeH $treeM &&
      git ls-files --stage >6.out &&
-     git diff M.out 6.out &&
+     test_cmp M.out 6.out &&
      check_cache_at frotz clean'
 
 test_expect_success \
@@ -140,7 +140,7 @@
      echo frotz frotz >frotz &&
      read_tree_twoway $treeH $treeM &&
      git ls-files --stage >7.out &&
-     git diff M.out 7.out &&
+     test_cmp M.out 7.out &&
      check_cache_at frotz dirty'
 
 test_expect_success \
@@ -171,7 +171,7 @@
      git update-index --add rezrov &&
      read_tree_twoway $treeH $treeM &&
      git ls-files --stage >10.out &&
-     git diff M.out 10.out'
+     test_cmp M.out 10.out'
 
 test_expect_success \
     '11 - dirty path removed.' \
@@ -216,7 +216,7 @@
      git update-index --add nitfol &&
      read_tree_twoway $treeH $treeM &&
      git ls-files --stage >14.out || return 1
-     git diff M.out 14.out >14diff.out
+     git diff --no-index M.out 14.out >14diff.out
      compare_change 14diff.out expected &&
      check_cache_at nitfol clean'
 
@@ -230,7 +230,7 @@
      echo nitfol nitfol nitfol >nitfol &&
      read_tree_twoway $treeH $treeM &&
      git ls-files --stage >15.out || return 1
-     git diff M.out 15.out >15diff.out
+     git diff --no-index M.out 15.out >15diff.out
      compare_change 15diff.out expected &&
      check_cache_at nitfol dirty'
 
@@ -262,7 +262,7 @@
      git update-index --add bozbar &&
      read_tree_twoway $treeH $treeM &&
      git ls-files --stage >18.out &&
-     git diff M.out 18.out &&
+     test_cmp M.out 18.out &&
      check_cache_at bozbar clean'
 
 test_expect_success \
@@ -275,7 +275,7 @@
      echo gnusto gnusto >bozbar &&
      read_tree_twoway $treeH $treeM &&
      git ls-files --stage >19.out &&
-     git diff M.out 19.out &&
+     test_cmp M.out 19.out &&
      check_cache_at bozbar dirty'
 
 test_expect_success \
@@ -287,7 +287,7 @@
      git update-index --add bozbar &&
      read_tree_twoway $treeH $treeM &&
      git ls-files --stage >20.out &&
-     git diff M.out 20.out &&
+     test_cmp M.out 20.out &&
      check_cache_at bozbar dirty'
 
 test_expect_success \
@@ -337,7 +337,7 @@
      git update-index --add DF &&
      read_tree_twoway $treeDF $treeDFDF &&
      git ls-files --stage >DFDFcheck.out &&
-     git diff DFDF.out DFDFcheck.out &&
+     test_cmp DFDF.out DFDFcheck.out &&
      check_cache_at DF/DF dirty &&
      :'
 
diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh
index 42e5cf8..e04990e 100755
--- a/t/t1002-read-tree-m-u-2way.sh
+++ b/t/t1002-read-tree-m-u-2way.sh
@@ -16,7 +16,7 @@
 	sed >current \
 	    -e '/^--- /d; /^+++ /d; /^@@ /d;' \
 	    -e 's/^\(.[0-7][0-7][0-7][0-7][0-7][0-7]\) '"$_x40"' /\1 X /' "$1"
-	git diff expected current
+	test_cmp expected current
 }
 
 check_cache_at () {
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
new file mode 100755
index 0000000..d8b7f2f
--- /dev/null
+++ b/t/t1006-cat-file.sh
@@ -0,0 +1,244 @@
+#!/bin/sh
+
+test_description='git cat-file'
+
+. ./test-lib.sh
+
+echo_without_newline () {
+    printf '%s' "$*"
+}
+
+strlen () {
+    echo_without_newline "$1" | wc -c | sed -e 's/^ *//'
+}
+
+maybe_remove_timestamp () {
+    if test -z "$2"; then
+        echo_without_newline "$1"
+    else
+	echo_without_newline "$(printf '%s\n' "$1" | sed -e 's/ [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$//')"
+    fi
+}
+
+run_tests () {
+    type=$1
+    sha1=$2
+    size=$3
+    content=$4
+    pretty_content=$5
+    no_ts=$6
+
+    batch_output="$sha1 $type $size
+$content"
+
+    test_expect_success "$type exists" '
+	git cat-file -e $sha1
+    '
+
+    test_expect_success "Type of $type is correct" '
+        test $type = "$(git cat-file -t $sha1)"
+    '
+
+    test_expect_success "Size of $type is correct" '
+        test $size = "$(git cat-file -s $sha1)"
+    '
+
+    test -z "$content" ||
+    test_expect_success "Content of $type is correct" '
+	expect="$(maybe_remove_timestamp "$content" $no_ts)"
+	actual="$(maybe_remove_timestamp "$(git cat-file $type $sha1)" $no_ts)"
+
+        if test "z$expect" = "z$actual"
+	then
+		: happy
+	else
+		echo "Oops: expected $expect"
+		echo "but got $actual"
+		false
+        fi
+    '
+
+    test_expect_success "Pretty content of $type is correct" '
+	expect="$(maybe_remove_timestamp "$pretty_content" $no_ts)"
+	actual="$(maybe_remove_timestamp "$(git cat-file -p $sha1)" $no_ts)"
+        if test "z$expect" = "z$actual"
+	then
+		: happy
+	else
+		echo "Oops: expected $expect"
+		echo "but got $actual"
+		false
+        fi
+    '
+
+    test -z "$content" ||
+    test_expect_success "--batch output of $type is correct" '
+	expect="$(maybe_remove_timestamp "$batch_output" $no_ts)"
+	actual="$(maybe_remove_timestamp "$(echo $sha1 | git cat-file --batch)" $no_ts)"
+        if test "z$expect" = "z$actual"
+	then
+		: happy
+	else
+		echo "Oops: expected $expect"
+		echo "but got $actual"
+		false
+        fi
+    '
+
+    test_expect_success "--batch-check output of $type is correct" '
+	expect="$sha1 $type $size"
+	actual="$(echo_without_newline $sha1 | git cat-file --batch-check)"
+        if test "z$expect" = "z$actual"
+	then
+		: happy
+	else
+		echo "Oops: expected $expect"
+		echo "but got $actual"
+		false
+        fi
+    '
+}
+
+hello_content="Hello World"
+hello_size=$(strlen "$hello_content")
+hello_sha1=$(echo_without_newline "$hello_content" | git hash-object --stdin)
+
+test_expect_success "setup" '
+	echo_without_newline "$hello_content" > hello &&
+	git update-index --add hello
+'
+
+run_tests 'blob' $hello_sha1 $hello_size "$hello_content" "$hello_content"
+
+tree_sha1=$(git write-tree)
+tree_size=33
+tree_pretty_content="100644 blob $hello_sha1	hello"
+
+run_tests 'tree' $tree_sha1 $tree_size "" "$tree_pretty_content"
+
+commit_message="Intial commit"
+commit_sha1=$(echo_without_newline "$commit_message" | git commit-tree $tree_sha1)
+commit_size=176
+commit_content="tree $tree_sha1
+author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 0000000000 +0000
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 0000000000 +0000
+
+$commit_message"
+
+run_tests 'commit' $commit_sha1 $commit_size "$commit_content" "$commit_content" 1
+
+tag_header_without_timestamp="object $hello_sha1
+type blob
+tag hellotag
+tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
+tag_description="This is a tag"
+tag_content="$tag_header_without_timestamp 0000000000 +0000
+
+$tag_description"
+tag_pretty_content="$tag_header_without_timestamp Thu Jan 1 00:00:00 1970 +0000
+
+$tag_description"
+
+tag_sha1=$(echo_without_newline "$tag_content" | git mktag)
+tag_size=$(strlen "$tag_content")
+
+run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_pretty_content" 1
+
+test_expect_success \
+    "Reach a blob from a tag pointing to it" \
+    "test '$hello_content' = \"\$(git cat-file blob $tag_sha1)\""
+
+for batch in batch batch-check
+do
+    for opt in t s e p
+    do
+	test_expect_success "Passing -$opt with --$batch fails" '
+	    test_must_fail git cat-file --$batch -$opt $hello_sha1
+	'
+
+	test_expect_success "Passing --$batch with -$opt fails" '
+	    test_must_fail git cat-file -$opt --$batch $hello_sha1
+	'
+    done
+
+    test_expect_success "Passing <type> with --$batch fails" '
+	test_must_fail git cat-file --$batch blob $hello_sha1
+    '
+
+    test_expect_success "Passing --$batch with <type> fails" '
+	test_must_fail git cat-file blob --$batch $hello_sha1
+    '
+
+    test_expect_success "Passing sha1 with --$batch fails" '
+	test_must_fail git cat-file --$batch $hello_sha1
+    '
+done
+
+test_expect_success "--batch-check for a non-existent named object" '
+    test "foobar42 missing
+foobar84 missing" = \
+    "$( ( echo foobar42; echo_without_newline foobar84; ) | git cat-file --batch-check)"
+'
+
+test_expect_success "--batch-check for a non-existent hash" '
+    test "0000000000000000000000000000000000000042 missing
+0000000000000000000000000000000000000084 missing" = \
+    "$( ( echo 0000000000000000000000000000000000000042;
+         echo_without_newline 0000000000000000000000000000000000000084; ) \
+       | git cat-file --batch-check)"
+'
+
+test_expect_success "--batch for an existent and a non-existent hash" '
+    test "$tag_sha1 tag $tag_size
+$tag_content
+0000000000000000000000000000000000000000 missing" = \
+    "$( ( echo $tag_sha1;
+         echo_without_newline 0000000000000000000000000000000000000000; ) \
+       | git cat-file --batch)"
+'
+
+test_expect_success "--batch-check for an emtpy line" '
+    test " missing" = "$(echo | git cat-file --batch-check)"
+'
+
+batch_input="$hello_sha1
+$commit_sha1
+$tag_sha1
+deadbeef
+
+"
+
+batch_output="$hello_sha1 blob $hello_size
+$hello_content
+$commit_sha1 commit $commit_size
+$commit_content
+$tag_sha1 tag $tag_size
+$tag_content
+deadbeef missing
+ missing"
+
+test_expect_success '--batch with multiple sha1s gives correct format' '
+	test "$(maybe_remove_timestamp "$batch_output" 1)" = "$(maybe_remove_timestamp "$(echo_without_newline "$batch_input" | git cat-file --batch)" 1)"
+'
+
+batch_check_input="$hello_sha1
+$tree_sha1
+$commit_sha1
+$tag_sha1
+deadbeef
+
+"
+
+batch_check_output="$hello_sha1 blob $hello_size
+$tree_sha1 tree $tree_size
+$commit_sha1 commit $commit_size
+$tag_sha1 tag $tag_size
+deadbeef missing
+ missing"
+
+test_expect_success "--batch-check with multiple sha1s gives correct format" '
+    test "$batch_check_output" = \
+    "$(echo_without_newline "$batch_check_input" | git cat-file --batch-check)"
+'
+
+test_done
diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh
new file mode 100755
index 0000000..0526295
--- /dev/null
+++ b/t/t1007-hash-object.sh
@@ -0,0 +1,133 @@
+#!/bin/sh
+
+test_description=git-hash-object
+
+. ./test-lib.sh
+
+echo_without_newline() {
+	printf '%s' "$*"
+}
+
+test_blob_does_not_exist() {
+	test_expect_success 'blob does not exist in database' "
+		test_must_fail git cat-file blob $1
+	"
+}
+
+test_blob_exists() {
+	test_expect_success 'blob exists in database' "
+		git cat-file blob $1
+	"
+}
+
+hello_content="Hello World"
+hello_sha1=5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689
+
+example_content="This is an example"
+example_sha1=ddd3f836d3e3fbb7ae289aa9ae83536f76956399
+
+setup_repo() {
+	echo_without_newline "$hello_content" > hello
+	echo_without_newline "$example_content" > example
+}
+
+test_repo=test
+push_repo() {
+	test_create_repo $test_repo
+	cd $test_repo
+
+	setup_repo
+}
+
+pop_repo() {
+	cd ..
+	rm -rf $test_repo
+}
+
+setup_repo
+
+# Argument checking
+
+test_expect_success "multiple '--stdin's are rejected" '
+	test_must_fail git hash-object --stdin --stdin < example
+'
+
+test_expect_success "Can't use --stdin and --stdin-paths together" '
+	test_must_fail git hash-object --stdin --stdin-paths &&
+	test_must_fail git hash-object --stdin-paths --stdin
+'
+
+test_expect_success "Can't pass filenames as arguments with --stdin-paths" '
+	test_must_fail git hash-object --stdin-paths hello < example
+'
+
+# Behavior
+
+push_repo
+
+test_expect_success 'hash a file' '
+	test $hello_sha1 = $(git hash-object hello)
+'
+
+test_blob_does_not_exist $hello_sha1
+
+test_expect_success 'hash from stdin' '
+	test $example_sha1 = $(git hash-object --stdin < example)
+'
+
+test_blob_does_not_exist $example_sha1
+
+test_expect_success 'hash a file and write to database' '
+	test $hello_sha1 = $(git hash-object -w hello)
+'
+
+test_blob_exists $hello_sha1
+
+test_expect_success 'git hash-object --stdin file1 <file0 first operates on file0, then file1' '
+	echo foo > file1 &&
+	obname0=$(echo bar | git hash-object --stdin) &&
+	obname1=$(git hash-object file1) &&
+	obname0new=$(echo bar | git hash-object --stdin file1 | sed -n -e 1p) &&
+	obname1new=$(echo bar | git hash-object --stdin file1 | sed -n -e 2p) &&
+	test "$obname0" = "$obname0new" &&
+	test "$obname1" = "$obname1new"
+'
+
+pop_repo
+
+for args in "-w --stdin" "--stdin -w"; do
+	push_repo
+
+	test_expect_success "hash from stdin and write to database ($args)" '
+		test $example_sha1 = $(git hash-object $args < example)
+	'
+
+	test_blob_exists $example_sha1
+
+	pop_repo
+done
+
+filenames="hello
+example"
+
+sha1s="$hello_sha1
+$example_sha1"
+
+test_expect_success "hash two files with names on stdin" '
+	test "$sha1s" = "$(echo_without_newline "$filenames" | git hash-object --stdin-paths)"
+'
+
+for args in "-w --stdin-paths" "--stdin-paths -w"; do
+	push_repo
+
+	test_expect_success "hash two files with names on stdin and write to database ($args)" '
+		test "$sha1s" = "$(echo_without_newline "$filenames" | git hash-object $args)"
+	'
+
+	test_blob_exists $hello_sha1
+	test_blob_exists $example_sha1
+
+	pop_repo
+done
+
+test_done
diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index b9cef34..fc386ba 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -21,7 +21,7 @@
 '
 
 test_expect_success 'update-index and ls-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git update-index --add one &&
 	case "`git ls-files`" in
 	one) echo ok one ;;
@@ -41,7 +41,7 @@
 '
 
 test_expect_success 'cat-file' '
-	cd $HERE &&
+	cd "$HERE" &&
 	two=`git ls-files -s dir/two` &&
 	two=`expr "$two" : "[0-7]* \\([0-9a-f]*\\)"` &&
 	echo "$two" &&
@@ -54,7 +54,7 @@
 rm -f actual dir/actual
 
 test_expect_success 'diff-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	echo a >>one &&
 	echo d >>dir/two &&
 	case "`git diff-files --name-only`" in
@@ -74,7 +74,7 @@
 '
 
 test_expect_success 'write-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	top=`git write-tree` &&
 	echo $top &&
 	cd dir &&
@@ -84,7 +84,7 @@
 '
 
 test_expect_success 'checkout-index' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git checkout-index -f -u one &&
 	cmp one original.one &&
 	cd dir &&
@@ -93,7 +93,7 @@
 '
 
 test_expect_success 'read-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -f one dir/two &&
 	tree=`git write-tree` &&
 	git read-tree --reset -u "$tree" &&
@@ -107,27 +107,27 @@
 '
 
 test_expect_success 'no file/rev ambiguity check inside .git' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git commit -a -m 1 &&
-	cd $HERE/.git &&
+	cd "$HERE"/.git &&
 	git show -s HEAD
 '
 
 test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && GIT_DIR=. git show -s HEAD
 '
 
 # This still does not work as it should...
 : test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && git show -s HEAD
 '
 
 test_expect_success 'detection should not be fooled by a symlink' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -fr foo.git &&
 	git clone -s .git another &&
 	ln -s another yetanother &&
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index b36a901..afe7e66 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -427,13 +427,13 @@
 weird
 EOF
 
-test_expect_success "rename succeeded" "git diff expect .git/config"
+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_expect_success "rename succeeded" "git diff expect .git/config"
+test_expect_success "rename succeeded" "test_cmp expect .git/config"
 
 test_expect_success "rename another section" \
 	'git config --rename-section branch."1 234 blabl/a" branch.drei'
@@ -449,7 +449,7 @@
 weird
 EOF
 
-test_expect_success "rename succeeded" "git diff expect .git/config"
+test_expect_success "rename succeeded" "test_cmp expect .git/config"
 
 cat >> .git/config << EOF
   [branch "zwei"] a = 1 [branch "vier"]
@@ -465,7 +465,7 @@
 EOF
 
 test_expect_success "section was removed properly" \
-	"git diff -u expect .git/config"
+	"test_cmp expect .git/config"
 
 rm .git/config
 
@@ -595,6 +595,64 @@
 
 rm .git/config
 
+cat >expect <<\EOF
+[bool]
+	true1 = true
+	true2 = true
+	false1 = false
+	false2 = false
+[int]
+	int1 = 0
+	int2 = 1
+	int3 = -1
+EOF
+
+test_expect_success 'get --bool-or-int' '
+	(
+		echo "[bool]"
+		echo true1
+		echo true2 = true
+		echo false = false
+		echo "[int]"
+		echo int1 = 0
+		echo int2 = 1
+		echo int3 = -1
+	) >>.git/config &&
+	test $(git config --bool-or-int bool.true1) = true &&
+	test $(git config --bool-or-int bool.true2) = true &&
+	test $(git config --bool-or-int bool.false) = false &&
+	test $(git config --bool-or-int int.int1) = 0 &&
+	test $(git config --bool-or-int int.int2) = 1 &&
+	test $(git config --bool-or-int int.int3) = -1
+
+'
+
+rm .git/config
+cat >expect <<\EOF
+[bool]
+	true1 = true
+	false1 = false
+	true2 = true
+	false2 = false
+[int]
+	int1 = 0
+	int2 = 1
+	int3 = -1
+EOF
+
+test_expect_success 'set --bool-or-int' '
+	git config --bool-or-int bool.true1 true &&
+	git config --bool-or-int bool.false1 false &&
+	git config --bool-or-int bool.true2 yes &&
+	git config --bool-or-int bool.false2 no &&
+	git config --bool-or-int int.int1 0 &&
+	git config --bool-or-int int.int2 1 &&
+	git config --bool-or-int int.int3 -1 &&
+	test_cmp expect .git/config
+'
+
+rm .git/config
+
 git config quote.leading " test"
 git config quote.ending "test "
 git config quote.semicolon "test;test"
diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh
index 6bfe19a..dc85e8b 100755
--- a/t/t1301-shared-repo.sh
+++ b/t/t1301-shared-repo.sh
@@ -7,6 +7,39 @@
 
 . ./test-lib.sh
 
+# User must have read permissions to the repo -> failure on --shared=0400
+test_expect_success 'shared = 0400 (faulty permission u-w)' '
+	mkdir sub && (
+		cd sub && git init --shared=0400
+	)
+	ret="$?"
+	rm -rf sub
+	test $ret != "0"
+'
+
+for u in 002 022
+do
+	test_expect_success "shared=1 does not clear bits preset by umask $u" '
+		mkdir sub && (
+			cd sub &&
+			umask $u &&
+			git init --shared=1 &&
+			test 1 = "$(git config core.sharedrepository)"
+		) &&
+		actual=$(ls -l sub/.git/HEAD)
+		case "$actual" in
+		-rw-rw-r--*)
+			: happy
+			;;
+		*)
+			echo Oops, .git/HEAD is not 0664 but $actual
+			false
+			;;
+		esac
+	'
+	rm -rf sub
+done
+
 test_expect_success 'shared=all' '
 	mkdir sub &&
 	cd sub &&
@@ -33,4 +66,59 @@
 	esac
 '
 
+for u in	0660:rw-rw---- \
+		0640:rw-r----- \
+		0600:rw------- \
+		0666:rw-rw-rw- \
+		0664:rw-rw-r--
+do
+	x=$(expr "$u" : ".*:\([rw-]*\)") &&
+	y=$(echo "$x" | sed -e "s/w/-/g") &&
+	u=$(expr "$u" : "\([0-7]*\)") &&
+	git config core.sharedrepository "$u" &&
+	umask 0277 &&
+
+	test_expect_success "shared = $u ($y) ro" '
+
+		rm -f .git/info/refs &&
+		git update-server-info &&
+		actual="$(ls -l .git/info/refs)" &&
+		actual=${actual%% *} &&
+		test "x$actual" = "x-$y" || {
+			ls -lt .git/info
+			false
+		}
+	'
+
+	umask 077 &&
+	test_expect_success "shared = $u ($x) rw" '
+
+		rm -f .git/info/refs &&
+		git update-server-info &&
+		actual="$(ls -l .git/info/refs)" &&
+		actual=${actual%% *} &&
+		test "x$actual" = "x-$x" || {
+			ls -lt .git/info
+			false
+		}
+
+	'
+
+done
+
+test_expect_success 'git reflog expire honors core.sharedRepository' '
+	git config core.sharedRepository group &&
+	git reflog expire --all &&
+	actual="$(ls -l .git/logs/refs/heads/master)" &&
+	case "$actual" in
+	-rw-rw-*)
+		: happy
+		;;
+	*)
+		echo Ooops, .git/logs/refs/heads/master is not 0662 [$actual]
+		false
+		;;
+	esac
+'
+
 test_done
diff --git a/t/t1303-wacky-config.sh b/t/t1303-wacky-config.sh
index 99985dc..f98f4c5 100755
--- a/t/t1303-wacky-config.sh
+++ b/t/t1303-wacky-config.sh
@@ -11,7 +11,7 @@
 check() {
 	echo "$2" >expected
 	git config --get "$1" >actual
-	git diff actual expected
+	test_cmp actual expected
 }
 
 test_expect_success 'modify same key' '
@@ -34,4 +34,10 @@
 	check section2.key bar
 '
 
+SECTION="test.q\"s\\sq'sp e.key"
+test_expect_success 'make sure git-config escapes section names properly' '
+	git config "$SECTION" bar &&
+	check "$SECTION" bar
+'
+
 test_done
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 78cd412..b8b7ab4 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -32,6 +32,14 @@
 	"create $m" \
 	"git update-ref $m $B $A &&
 	 test $B"' = $(cat .git/'"$m"')'
+test_expect_success "fail to delete $m with stale ref" '
+	test_must_fail git update-ref -d $m $A &&
+	test $B = "$(cat .git/$m)"
+'
+test_expect_success "delete $m" '
+	git update-ref -d $m $B &&
+	! test -f .git/$m
+'
 rm -f .git/$m
 
 test_expect_success \
@@ -49,6 +57,14 @@
 	"create $m (by HEAD)" \
 	"git update-ref HEAD $B $A &&
 	 test $B"' = $(cat .git/'"$m"')'
+test_expect_success "fail to delete $m (by HEAD) with stale ref" '
+	test_must_fail git update-ref -d HEAD $A &&
+	test $B = $(cat .git/$m)
+'
+test_expect_success "delete $m (by HEAD)" '
+	git update-ref -d HEAD $B &&
+	! test -f .git/$m
+'
 rm -f .git/$m
 
 test_expect_success '(not) create HEAD with old sha1' "
diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh
index 73f830d..5b24f05 100755
--- a/t/t1410-reflog.sh
+++ b/t/t1410-reflog.sh
@@ -188,16 +188,30 @@
 	test_tick &&
 	git commit -m tiger C &&
 
-	test 5 = $(git reflog | wc -l) &&
+	HEAD_entry_count=$(git reflog | wc -l)
+	master_entry_count=$(git reflog show master | wc -l)
+
+	test $HEAD_entry_count = 5 &&
+	test $master_entry_count = 5 &&
+
 
 	git reflog delete master@{1} &&
 	git reflog show master > output &&
-	test 4 = $(wc -l < output) &&
+	test $(($master_entry_count - 1)) = $(wc -l < output) &&
+	test $HEAD_entry_count = $(git reflog | wc -l) &&
 	! grep ox < output &&
 
+	master_entry_count=$(wc -l < output)
+
+	git reflog delete HEAD@{1} &&
+	test $(($HEAD_entry_count -1)) = $(git reflog | wc -l) &&
+	test $master_entry_count = $(git reflog show master | wc -l) &&
+
+	HEAD_entry_count=$(git reflog | wc -l)
+
 	git reflog delete master@{07.04.2005.15:15:00.-0700} &&
 	git reflog show master > output &&
-	test 3 = $(wc -l < output) &&
+	test $(($master_entry_count - 1)) = $(wc -l < output) &&
 	! grep dragon < output
 
 '
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
index 38a2bf0..85da4ca 100755
--- a/t/t1500-rev-parse.sh
+++ b/t/t1500-rev-parse.sh
@@ -51,8 +51,9 @@
 
 mkdir work || exit 1
 cd work || exit 1
-export GIT_DIR=../.git
-export GIT_CONFIG="$(pwd)"/../.git/config
+GIT_DIR=../.git
+GIT_CONFIG="$(pwd)"/../.git/config
+export GIT_DIR GIT_CONFIG
 
 git config core.bare false
 test_rev_parse 'GIT_DIR=../.git, core.bare = false' false false true ''
@@ -64,8 +65,8 @@
 test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false true ''
 
 mv ../.git ../repo.git || exit 1
-export GIT_DIR=../repo.git
-export GIT_CONFIG="$(pwd)"/../repo.git/config
+GIT_DIR=../repo.git
+GIT_CONFIG="$(pwd)"/../repo.git/config
 
 git config core.bare false
 test_rev_parse 'GIT_DIR=../repo.git, core.bare = false' false false true ''
diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index 7ee3820..2ee88d8 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -32,24 +32,25 @@
 mv .git repo.git || exit 1
 
 say "core.worktree = relative path"
-export GIT_DIR=repo.git
-export GIT_CONFIG="$(pwd)"/$GIT_DIR/config
+GIT_DIR=repo.git
+GIT_CONFIG="$(pwd)"/$GIT_DIR/config
+export GIT_DIR GIT_CONFIG
 unset GIT_WORK_TREE
 git config core.worktree ../work
 test_rev_parse 'outside'      false false false
 cd work || exit 1
-export GIT_DIR=../repo.git
-export GIT_CONFIG="$(pwd)"/$GIT_DIR/config
+GIT_DIR=../repo.git
+GIT_CONFIG="$(pwd)"/$GIT_DIR/config
 test_rev_parse 'inside'       false false true ''
 cd sub/dir || exit 1
-export GIT_DIR=../../../repo.git
-export GIT_CONFIG="$(pwd)"/$GIT_DIR/config
+GIT_DIR=../../../repo.git
+GIT_CONFIG="$(pwd)"/$GIT_DIR/config
 test_rev_parse 'subdirectory' false false true sub/dir/
 cd ../../.. || exit 1
 
 say "core.worktree = absolute path"
-export GIT_DIR=$(pwd)/repo.git
-export GIT_CONFIG=$GIT_DIR/config
+GIT_DIR=$(pwd)/repo.git
+GIT_CONFIG=$GIT_DIR/config
 git config core.worktree "$(pwd)/work"
 test_rev_parse 'outside'      false false false
 cd work || exit 1
@@ -59,25 +60,26 @@
 cd ../../.. || exit 1
 
 say "GIT_WORK_TREE=relative path (override core.worktree)"
-export GIT_DIR=$(pwd)/repo.git
-export GIT_CONFIG=$GIT_DIR/config
+GIT_DIR=$(pwd)/repo.git
+GIT_CONFIG=$GIT_DIR/config
 git config core.worktree non-existent
-export GIT_WORK_TREE=work
+GIT_WORK_TREE=work
+export GIT_WORK_TREE
 test_rev_parse 'outside'      false false false
 cd work || exit 1
-export GIT_WORK_TREE=.
+GIT_WORK_TREE=.
 test_rev_parse 'inside'       false false true ''
 cd sub/dir || exit 1
-export GIT_WORK_TREE=../..
+GIT_WORK_TREE=../..
 test_rev_parse 'subdirectory' false false true sub/dir/
 cd ../../.. || exit 1
 
 mv work repo.git/work
 
 say "GIT_WORK_TREE=absolute path, work tree below git dir"
-export GIT_DIR=$(pwd)/repo.git
-export GIT_CONFIG=$GIT_DIR/config
-export GIT_WORK_TREE=$(pwd)/repo.git/work
+GIT_DIR=$(pwd)/repo.git
+GIT_CONFIG=$GIT_DIR/config
+GIT_WORK_TREE=$(pwd)/repo.git/work
 test_rev_parse 'outside'              false false false
 cd repo.git || exit 1
 test_rev_parse 'in repo.git'              false true  false
diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh
index 762af5f..3508d0a 100755
--- a/t/t1502-rev-parse-parseopt.sh
+++ b/t/t1502-rev-parse-parseopt.sh
@@ -13,7 +13,7 @@
     --bar ...             some cool option --bar with an argument
 
 An option group Header
-    -C [...]              option C with an optional argument
+    -C[...]               option C with an optional argument
 
 Extras
     --extra1              line above used to cause a segfault but no longer does
@@ -37,7 +37,7 @@
 Extras
 extra1    line above used to cause a segfault but no longer does
 EOF
-	git diff expect.err output.err
+	test_cmp expect.err output.err
 '
 
 test_done
diff --git a/t/t1503-rev-parse-verify.sh b/t/t1503-rev-parse-verify.sh
new file mode 100755
index 0000000..95244c9
--- /dev/null
+++ b/t/t1503-rev-parse-verify.sh
@@ -0,0 +1,107 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Christian Couder
+#
+test_description='test git rev-parse --verify'
+
+exec </dev/null
+
+. ./test-lib.sh
+
+add_line_into_file()
+{
+    _line=$1
+    _file=$2
+
+    if [ -f "$_file" ]; then
+        echo "$_line" >> $_file || return $?
+        MSG="Add <$_line> into <$_file>."
+    else
+        echo "$_line" > $_file || return $?
+        git add $_file || return $?
+        MSG="Create file <$_file> with <$_line> inside."
+    fi
+
+    test_tick
+    git-commit --quiet -m "$MSG" $_file
+}
+
+HASH1=
+HASH2=
+HASH3=
+HASH4=
+
+test_expect_success 'set up basic repo with 1 file (hello) and 4 commits' '
+	add_line_into_file "1: Hello World" hello &&
+	HASH1=$(git rev-parse --verify HEAD) &&
+	add_line_into_file "2: A new day for git" hello &&
+	HASH2=$(git rev-parse --verify HEAD) &&
+	add_line_into_file "3: Another new day for git" hello &&
+	HASH3=$(git rev-parse --verify HEAD) &&
+	add_line_into_file "4: Ciao for now" hello &&
+	HASH4=$(git rev-parse --verify HEAD)
+'
+
+test_expect_success 'works with one good rev' '
+	rev_hash1=$(git rev-parse --verify $HASH1) &&
+	test "$rev_hash1" = "$HASH1" &&
+	rev_hash2=$(git rev-parse --verify $HASH2) &&
+	test "$rev_hash2" = "$HASH2" &&
+	rev_hash3=$(git rev-parse --verify $HASH3) &&
+	test "$rev_hash3" = "$HASH3" &&
+	rev_hash4=$(git rev-parse --verify $HASH4) &&
+	test "$rev_hash4" = "$HASH4" &&
+	rev_master=$(git rev-parse --verify master) &&
+	test "$rev_master" = "$HASH4" &&
+	rev_head=$(git rev-parse --verify HEAD) &&
+	test "$rev_head" = "$HASH4"
+'
+
+test_expect_success 'fails with any bad rev or many good revs' '
+	test_must_fail git rev-parse --verify 2>error &&
+	grep "single revision" error &&
+	test_must_fail git rev-parse --verify foo 2>error &&
+	grep "single revision" error &&
+	test_must_fail git rev-parse --verify HEAD bar 2>error &&
+	grep "single revision" error &&
+	test_must_fail git rev-parse --verify baz HEAD 2>error &&
+	grep "single revision" error &&
+	test_must_fail git rev-parse --verify $HASH2 HEAD 2>error &&
+	grep "single revision" error
+'
+
+test_expect_success 'fails silently when using -q' '
+	test_must_fail git rev-parse --verify --quiet 2>error &&
+	test -z "$(cat error)" &&
+	test_must_fail git rev-parse -q --verify foo 2>error &&
+	test -z "$(cat error)" &&
+	test_must_fail git rev-parse --verify -q HEAD bar 2>error &&
+	test -z "$(cat error)" &&
+	test_must_fail git rev-parse --quiet --verify baz HEAD 2>error &&
+	test -z "$(cat error)" &&
+	test_must_fail git rev-parse -q --verify $HASH2 HEAD 2>error &&
+	test -z "$(cat error)"
+'
+
+test_expect_success 'no stdout output on error' '
+	test -z "$(git rev-parse --verify)" &&
+	test -z "$(git rev-parse --verify foo)" &&
+	test -z "$(git rev-parse --verify baz HEAD)" &&
+	test -z "$(git rev-parse --verify HEAD bar)" &&
+	test -z "$(git rev-parse --verify $HASH2 HEAD)"
+'
+
+test_expect_success 'use --default' '
+	git rev-parse --verify --default master &&
+	git rev-parse --verify --default master HEAD &&
+	git rev-parse --default master --verify &&
+	git rev-parse --default master --verify HEAD &&
+	git rev-parse --verify HEAD --default master &&
+	test_must_fail git rev-parse --verify foo --default master &&
+	test_must_fail git rev-parse --default HEAD --verify bar &&
+	test_must_fail git rev-parse --verify --default HEAD baz &&
+	test_must_fail git rev-parse --default foo --verify &&
+	test_must_fail git rev-parse --verify --default bar
+'
+
+test_done
diff --git a/t/t2002-checkout-cache-u.sh b/t/t2002-checkout-cache-u.sh
index 0f441bc..70361c8 100755
--- a/t/t2002-checkout-cache-u.sh
+++ b/t/t2002-checkout-cache-u.sh
@@ -21,13 +21,13 @@
 rm -f path0 &&
 git read-tree $t &&
 git checkout-index -f -a &&
-! git diff-files | diff - /dev/null'
+test_must_fail git diff-files --exit-code'
 
 test_expect_success \
 'with -u, git checkout-index picks up stat information from new files.' '
 rm -f path0 &&
 git read-tree $t &&
 git checkout-index -u -f -a &&
-git diff-files | diff - /dev/null'
+git diff-files --exit-code'
 
 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/t2200-add-update.sh b/t/t2200-add-update.sh
index b664341..f57a6e0 100755
--- a/t/t2200-add-update.sh
+++ b/t/t2200-add-update.sh
@@ -111,4 +111,21 @@
 
 '
 
+test_expect_success 'add -n -u should not add but just report' '
+
+	(
+		echo "add '\''check'\''" &&
+		echo "remove '\''top'\''"
+	) >expect &&
+	before=$(git ls-files -s check top) &&
+	echo changed >>check &&
+	rm -f top &&
+	git add -n -u >actual &&
+	after=$(git ls-files -s check top) &&
+
+	test "$before" = "$after" &&
+	test_cmp expect actual
+
+'
+
 test_done
diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh
index 55f057c..1caeaca 100755
--- a/t/t3001-ls-files-others-exclude.sh
+++ b/t/t3001-ls-files-others-exclude.sh
@@ -65,7 +65,7 @@
        --exclude-per-directory=.gitignore \
        --exclude-from=.git/ignore \
        >output &&
-     git diff expect output'
+     test_cmp expect output'
 
 # Test \r\n (MSDOS-like systems)
 printf '*.1\r\n/*.3\r\n!*.6\r\n' >.gitignore
@@ -77,7 +77,7 @@
        --exclude-per-directory=.gitignore \
        --exclude-from=.git/ignore \
        >output &&
-     git diff expect output'
+     test_cmp expect output'
 
 cat > excludes-file << EOF
 *.[1-8]
diff --git a/t/t3002-ls-files-dashpath.sh b/t/t3002-ls-files-dashpath.sh
index 8687a01..8704b04 100755
--- a/t/t3002-ls-files-dashpath.sh
+++ b/t/t3002-ls-files-dashpath.sh
@@ -23,7 +23,7 @@
 test_expect_success \
     'git ls-files without path restriction.' \
     'git ls-files --others >output &&
-     git diff output - <<EOF
+     test_cmp output - <<EOF
 --
 -foo
 output
@@ -34,7 +34,7 @@
 test_expect_success \
     'git ls-files with path restriction.' \
     'git ls-files --others path0 >output &&
-	git diff output - <<EOF
+	test_cmp output - <<EOF
 path0
 EOF
 '
@@ -42,7 +42,7 @@
 test_expect_success \
     'git ls-files with path restriction with --.' \
     'git ls-files --others -- path0 >output &&
-	git diff output - <<EOF
+	test_cmp output - <<EOF
 path0
 EOF
 '
@@ -50,7 +50,7 @@
 test_expect_success \
     'git ls-files with path restriction with -- --.' \
     'git ls-files --others -- -- >output &&
-	git diff output - <<EOF
+	test_cmp output - <<EOF
 --
 EOF
 '
@@ -58,7 +58,7 @@
 test_expect_success \
     'git ls-files with no path restriction.' \
     'git ls-files --others -- >output &&
-	git diff output - <<EOF
+	test_cmp output - <<EOF
 --
 -foo
 output
diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh
index 607f57f..aff3603 100755
--- a/t/t3030-merge-recursive.sh
+++ b/t/t3030-merge-recursive.sh
@@ -43,7 +43,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o1 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 '
 
 test_expect_success 'setup 2' '
@@ -61,7 +61,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual &&
+	test_cmp expected actual &&
 
 	echo goodbye >>a &&
 	o2=$(git hash-object a) &&
@@ -82,7 +82,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 '
 
 test_expect_success 'setup 3' '
@@ -100,7 +100,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual &&
+	test_cmp expected actual &&
 
 	rm -f b && mkdir b && echo df-1 >b/c && git add b/c &&
 	o3=$(git hash-object b/c) &&
@@ -119,7 +119,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 '
 
 test_expect_success 'setup 4' '
@@ -137,7 +137,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual &&
+	test_cmp expected actual &&
 
 	rm -f a && mkdir a && echo df-2 >a/c && git add a/c &&
 	o4=$(git hash-object a/c) &&
@@ -156,7 +156,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 '
 
 test_expect_success 'setup 5' '
@@ -174,7 +174,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual &&
+	test_cmp expected actual &&
 
 	rm -f b &&
 	echo remove-conflict >a &&
@@ -195,7 +195,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 
 '
 
@@ -214,7 +214,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual &&
+	test_cmp expected actual &&
 
 	rm -fr d && echo df-3 >d && git add d &&
 	o6=$(git hash-object d) &&
@@ -233,7 +233,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o6 0	d"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 '
 
 test_expect_success 'merge-recursive simple' '
@@ -265,7 +265,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o1 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 
 '
 
@@ -297,7 +297,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o1 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 
 '
 
@@ -318,7 +318,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o1 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 
 '
 
@@ -352,7 +352,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o1 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 
 '
 
@@ -386,7 +386,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o1 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 
 '
 
@@ -420,7 +420,7 @@
 		echo "100644 $o0 1	d/e"
 		echo "100644 $o1 2	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 
 '
 
@@ -454,7 +454,7 @@
 		echo "100644 $o0 1	d/e"
 		echo "100644 $o1 3	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 
 '
 
@@ -480,7 +480,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o1 0	d/e"
 	) >expected &&
-	git diff -u expected actual &&
+	test_cmp expected actual &&
 
 	git read-tree --prefix=a1/ master &&
 	git ls-files -s >actual &&
@@ -498,7 +498,7 @@
 		echo "100644 $o0 0	c"
 		echo "100644 $o1 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 
 	git read-tree --prefix=z/ master &&
 	git ls-files -s >actual &&
@@ -520,7 +520,7 @@
 		echo "100644 $o0 0	z/c"
 		echo "100644 $o1 0	z/d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 
 '
 
diff --git a/t/t3040-subprojects-basic.sh b/t/t3040-subprojects-basic.sh
index 79b9f23..f6973e9 100755
--- a/t/t3040-subprojects-basic.sh
+++ b/t/t3040-subprojects-basic.sh
@@ -24,7 +24,7 @@
     git add sub2 &&
     git commit -q -m "subprojects added" &&
     git diff-tree --abbrev=5 HEAD^ HEAD |cut -d" " -f-3,5- >current &&
-    git diff expected current'
+    test_cmp expected current'
 
 git branch save HEAD
 
@@ -62,7 +62,7 @@
     'git ls-files -s >expected &&
     git clone -l -s . cloned &&
     ( cd cloned && git ls-files -s ) >current &&
-    git diff expected current'
+    test_cmp expected current'
 
 test_expect_success 'removing and adding subproject' \
     'git update-index --force-remove -- sub2 &&
diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh
index 2b21b10..4261e96 100755
--- a/t/t3050-subprojects-fetch.sh
+++ b/t/t3050-subprojects-fetch.sh
@@ -20,7 +20,7 @@
 '
 
 test_expect_success clone '
-	git clone file://`pwd`/.git cloned &&
+	git clone "file://$(pwd)/.git" cloned &&
 	(git rev-parse HEAD; git ls-files -s) >expected &&
 	(
 		cd cloned &&
diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh
index 46427e3..6e6a254 100755
--- a/t/t3100-ls-tree-restrict.sh
+++ b/t/t3100-ls-tree-restrict.sh
@@ -35,7 +35,7 @@
 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
 test_output () {
     sed -e "s/ $_x40	/ X	/" <current >check
-    git diff expected check
+    test_cmp expected check
 }
 
 test_expect_success \
diff --git a/t/t3101-ls-tree-dirname.sh b/t/t3101-ls-tree-dirname.sh
index 70f9ce9..4dd7d12 100755
--- a/t/t3101-ls-tree-dirname.sh
+++ b/t/t3101-ls-tree-dirname.sh
@@ -43,7 +43,7 @@
 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
 test_output () {
     sed -e "s/ $_x40	/ X	/" <current >check
-    git diff expected check
+    test_cmp expected check
 }
 
 test_expect_success \
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index cb5f7a4..8d87686 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -224,4 +224,238 @@
 	test -z "$(git config branch.all1.merge)"
 '
 
+test_expect_success 'autosetuprebase local on a tracked local branch' '
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	git config branch.autosetuprebase local &&
+	(git show-ref -q refs/remotes/local/o || git-fetch local) &&
+	git branch mybase &&
+	git branch --track myr1 mybase &&
+	test "$(git config branch.myr1.remote)" = . &&
+	test "$(git config branch.myr1.merge)" = refs/heads/mybase &&
+	test "$(git config branch.myr1.rebase)" = true
+'
+
+test_expect_success 'autosetuprebase always on a tracked local branch' '
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	git config branch.autosetuprebase always &&
+	(git show-ref -q refs/remotes/local/o || git-fetch local) &&
+	git branch mybase2 &&
+	git branch --track myr2 mybase &&
+	test "$(git config branch.myr2.remote)" = . &&
+	test "$(git config branch.myr2.merge)" = refs/heads/mybase &&
+	test "$(git config branch.myr2.rebase)" = true
+'
+
+test_expect_success 'autosetuprebase remote on a tracked local branch' '
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	git config branch.autosetuprebase remote &&
+	(git show-ref -q refs/remotes/local/o || git-fetch local) &&
+	git branch mybase3 &&
+	git branch --track myr3 mybase2 &&
+	test "$(git config branch.myr3.remote)" = . &&
+	test "$(git config branch.myr3.merge)" = refs/heads/mybase2 &&
+	! test "$(git config branch.myr3.rebase)" = true
+'
+
+test_expect_success 'autosetuprebase never on a tracked local branch' '
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	git config branch.autosetuprebase never &&
+	(git show-ref -q refs/remotes/local/o || git-fetch local) &&
+	git branch mybase4 &&
+	git branch --track myr4 mybase2 &&
+	test "$(git config branch.myr4.remote)" = . &&
+	test "$(git config branch.myr4.merge)" = refs/heads/mybase2 &&
+	! test "$(git config branch.myr4.rebase)" = true
+'
+
+test_expect_success 'autosetuprebase local on a tracked remote branch' '
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	git config branch.autosetuprebase local &&
+	(git show-ref -q refs/remotes/local/master || git-fetch local) &&
+	git branch --track myr5 local/master &&
+	test "$(git config branch.myr5.remote)" = local &&
+	test "$(git config branch.myr5.merge)" = refs/heads/master &&
+	! test "$(git config branch.myr5.rebase)" = true
+'
+
+test_expect_success 'autosetuprebase never on a tracked remote branch' '
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	git config branch.autosetuprebase never &&
+	(git show-ref -q refs/remotes/local/master || git-fetch local) &&
+	git branch --track myr6 local/master &&
+	test "$(git config branch.myr6.remote)" = local &&
+	test "$(git config branch.myr6.merge)" = refs/heads/master &&
+	! test "$(git config branch.myr6.rebase)" = true
+'
+
+test_expect_success 'autosetuprebase remote on a tracked remote branch' '
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	git config branch.autosetuprebase remote &&
+	(git show-ref -q refs/remotes/local/master || git-fetch local) &&
+	git branch --track myr7 local/master &&
+	test "$(git config branch.myr7.remote)" = local &&
+	test "$(git config branch.myr7.merge)" = refs/heads/master &&
+	test "$(git config branch.myr7.rebase)" = true
+'
+
+test_expect_success 'autosetuprebase always on a tracked remote branch' '
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	git config branch.autosetuprebase remote &&
+	(git show-ref -q refs/remotes/local/master || git-fetch local) &&
+	git branch --track myr8 local/master &&
+	test "$(git config branch.myr8.remote)" = local &&
+	test "$(git config branch.myr8.merge)" = refs/heads/master &&
+	test "$(git config branch.myr8.rebase)" = true
+'
+
+test_expect_success 'autosetuprebase unconfigured on a tracked remote branch' '
+	git config --unset branch.autosetuprebase &&
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/master || git-fetch local) &&
+	git branch --track myr9 local/master &&
+	test "$(git config branch.myr9.remote)" = local &&
+	test "$(git config branch.myr9.merge)" = refs/heads/master &&
+	test "z$(git config branch.myr9.rebase)" = z
+'
+
+test_expect_success 'autosetuprebase unconfigured on a tracked local branch' '
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/o || git-fetch local) &&
+	git branch mybase10 &&
+	git branch --track myr10 mybase2 &&
+	test "$(git config branch.myr10.remote)" = . &&
+	test "$(git config branch.myr10.merge)" = refs/heads/mybase2 &&
+	test "z$(git config branch.myr10.rebase)" = z
+'
+
+test_expect_success 'autosetuprebase unconfigured on untracked local branch' '
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/master || git-fetch local) &&
+	git branch --no-track myr11 mybase2 &&
+	test "z$(git config branch.myr11.remote)" = z &&
+	test "z$(git config branch.myr11.merge)" = z &&
+	test "z$(git config branch.myr11.rebase)" = z
+'
+
+test_expect_success 'autosetuprebase unconfigured on untracked remote branch' '
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/master || git-fetch local) &&
+	git branch --no-track myr12 local/master &&
+	test "z$(git config branch.myr12.remote)" = z &&
+	test "z$(git config branch.myr12.merge)" = z &&
+	test "z$(git config branch.myr12.rebase)" = z
+'
+
+test_expect_success 'autosetuprebase never on an untracked local branch' '
+	git config branch.autosetuprebase never &&
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/master || git-fetch local) &&
+	git branch --no-track myr13 mybase2 &&
+	test "z$(git config branch.myr13.remote)" = z &&
+	test "z$(git config branch.myr13.merge)" = z &&
+	test "z$(git config branch.myr13.rebase)" = z
+'
+
+test_expect_success 'autosetuprebase local on an untracked local branch' '
+	git config branch.autosetuprebase local &&
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/master || git-fetch local) &&
+	git branch --no-track myr14 mybase2 &&
+	test "z$(git config branch.myr14.remote)" = z &&
+	test "z$(git config branch.myr14.merge)" = z &&
+	test "z$(git config branch.myr14.rebase)" = z
+'
+
+test_expect_success 'autosetuprebase remote on an untracked local branch' '
+	git config branch.autosetuprebase remote &&
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/master || git-fetch local) &&
+	git branch --no-track myr15 mybase2 &&
+	test "z$(git config branch.myr15.remote)" = z &&
+	test "z$(git config branch.myr15.merge)" = z &&
+	test "z$(git config branch.myr15.rebase)" = z
+'
+
+test_expect_success 'autosetuprebase always on an untracked local branch' '
+	git config branch.autosetuprebase always &&
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/master || git-fetch local) &&
+	git branch --no-track myr16 mybase2 &&
+	test "z$(git config branch.myr16.remote)" = z &&
+	test "z$(git config branch.myr16.merge)" = z &&
+	test "z$(git config branch.myr16.rebase)" = z
+'
+
+test_expect_success 'autosetuprebase never on an untracked remote branch' '
+	git config branch.autosetuprebase never &&
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/master || git-fetch local) &&
+	git branch --no-track myr17 local/master &&
+	test "z$(git config branch.myr17.remote)" = z &&
+	test "z$(git config branch.myr17.merge)" = z &&
+	test "z$(git config branch.myr17.rebase)" = z
+'
+
+test_expect_success 'autosetuprebase local on an untracked remote branch' '
+	git config branch.autosetuprebase local &&
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/master || git-fetch local) &&
+	git branch --no-track myr18 local/master &&
+	test "z$(git config branch.myr18.remote)" = z &&
+	test "z$(git config branch.myr18.merge)" = z &&
+	test "z$(git config branch.myr18.rebase)" = z
+'
+
+test_expect_success 'autosetuprebase remote on an untracked remote branch' '
+	git config branch.autosetuprebase remote &&
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/master || git-fetch local) &&
+	git branch --no-track myr19 local/master &&
+	test "z$(git config branch.myr19.remote)" = z &&
+	test "z$(git config branch.myr19.merge)" = z &&
+	test "z$(git config branch.myr19.rebase)" = z
+'
+
+test_expect_success 'autosetuprebase always on an untracked remote branch' '
+	git config branch.autosetuprebase always &&
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/master || git-fetch local) &&
+	git branch --no-track myr20 local/master &&
+	test "z$(git config branch.myr20.remote)" = z &&
+	test "z$(git config branch.myr20.merge)" = z &&
+	test "z$(git config branch.myr20.rebase)" = z
+'
+
+test_expect_success 'detect misconfigured autosetuprebase (bad value)' '
+	git config branch.autosetuprebase garbage &&
+	test_must_fail git branch
+'
+
+test_expect_success 'detect misconfigured autosetuprebase (no value)' '
+	git config --unset branch.autosetuprebase &&
+	echo "[branch] autosetuprebase" >> .git/config &&
+	test_must_fail git branch &&
+	git config --unset branch.autosetuprebase
+'
+
 test_done
diff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh
index b4cf628..f86f4bc 100755
--- a/t/t3201-branch-contains.sh
+++ b/t/t3201-branch-contains.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='branch --contains <commit>'
+test_description='branch --contains <commit>, --merged, and --no-merged'
 
 . ./test-lib.sh
 
@@ -55,4 +55,44 @@
 
 '
 
+test_expect_success 'side: branch --merged' '
+
+	git branch --merged >actual &&
+	{
+		echo "  master" &&
+		echo "* side"
+	} >expect &&
+	test_cmp expect actual
+
+'
+
+test_expect_success 'side: branch --no-merged' '
+
+	git branch --no-merged >actual &&
+	>expect &&
+	test_cmp expect actual
+
+'
+
+test_expect_success 'master: branch --merged' '
+
+	git checkout master &&
+	git branch --merged >actual &&
+	{
+		echo "* master"
+	} >expect &&
+	test_cmp expect actual
+
+'
+
+test_expect_success 'master: branch --no-merged' '
+
+	git branch --no-merged >actual &&
+	{
+		echo "  side"
+	} >expect &&
+	test_cmp expect actual
+
+'
+
 test_done
diff --git a/t/t3202-show-branch-octopus.sh b/t/t3202-show-branch-octopus.sh
new file mode 100755
index 0000000..7fe4a6e
--- /dev/null
+++ b/t/t3202-show-branch-octopus.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+test_description='test show-branch with more than 8 heads'
+
+. ./test-lib.sh
+
+numbers="1 2 3 4 5 6 7 8 9 10"
+
+test_expect_success 'setup' '
+
+	> file &&
+	git add file &&
+	test_tick &&
+	git commit -m initial &&
+
+	for i in $numbers
+	do
+		git checkout -b branch$i master &&
+		> file$i &&
+		git add file$i &&
+		test_tick &&
+		git commit -m branch$i || break
+	done
+
+'
+
+cat > expect << EOF
+! [branch1] branch1
+ ! [branch2] branch2
+  ! [branch3] branch3
+   ! [branch4] branch4
+    ! [branch5] branch5
+     ! [branch6] branch6
+      ! [branch7] branch7
+       ! [branch8] branch8
+        ! [branch9] branch9
+         * [branch10] branch10
+----------
+         * [branch10] branch10
+        +  [branch9] branch9
+       +   [branch8] branch8
+      +    [branch7] branch7
+     +     [branch6] branch6
+    +      [branch5] branch5
+   +       [branch4] branch4
+  +        [branch3] branch3
+ +         [branch2] branch2
++          [branch1] branch1
++++++++++* [branch10^] initial
+EOF
+
+test_expect_success 'show-branch with more than 8 branches' '
+
+	git show-branch $(for i in $numbers; do echo branch$i; done) > out &&
+	test_cmp expect out
+
+'
+
+test_done
diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh
index 24a00a9..0574ef1 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -35,7 +35,7 @@
 test_expect_success 'git ls-files no-funny' \
 	'git update-index --add "$p0" "$p2" &&
 	git ls-files >current &&
-	git diff expected current'
+	test_cmp expected current'
 
 t0=`git write-tree`
 echo "$t0" >t0
@@ -48,14 +48,14 @@
 test_expect_success 'git ls-files with-funny' \
 	'git update-index --add "$p1" &&
 	git ls-files >current &&
-	git diff expected current'
+	test_cmp expected current'
 
 echo 'just space
 no-funny
 tabs	," (dq) and spaces' >expected
 test_expect_success 'git ls-files -z with-funny' \
 	'git ls-files -z | perl -pe y/\\000/\\012/ >current &&
-	git diff expected current'
+	test_cmp expected current'
 
 t1=`git write-tree`
 echo "$t1" >t1
@@ -67,28 +67,28 @@
 EOF
 test_expect_success 'git ls-tree with funny' \
 	'git ls-tree -r $t1 | sed -e "s/^[^	]*	//" >current &&
-	 git diff expected current'
+	 test_cmp expected current'
 
 cat > expected <<\EOF
 A	"tabs\t,\" (dq) and spaces"
 EOF
 test_expect_success 'git diff-index with-funny' \
 	'git diff-index --name-status $t0 >current &&
-	git diff expected current'
+	test_cmp expected current'
 
 test_expect_success 'git diff-tree with-funny' \
 	'git diff-tree --name-status $t0 $t1 >current &&
-	git diff expected current'
+	test_cmp expected current'
 
 echo 'A
 tabs	," (dq) and spaces' >expected
 test_expect_success 'git diff-index -z with-funny' \
 	'git diff-index -z --name-status $t0 | perl -pe y/\\000/\\012/ >current &&
-	git diff expected current'
+	test_cmp expected current'
 
 test_expect_success 'git diff-tree -z with-funny' \
 	'git diff-tree -z --name-status $t0 $t1 | perl -pe y/\\000/\\012/ >current &&
-	git diff expected current'
+	test_cmp expected current'
 
 cat > expected <<\EOF
 CNUM	no-funny	"tabs\t,\" (dq) and spaces"
@@ -96,7 +96,7 @@
 test_expect_success 'git diff-tree -C with-funny' \
 	'git diff-tree -C --find-copies-harder --name-status \
 		$t0 $t1 | sed -e 's/^C[0-9]*/CNUM/' >current &&
-	git diff expected current'
+	test_cmp expected current'
 
 cat > expected <<\EOF
 RNUM	no-funny	"tabs\t,\" (dq) and spaces"
@@ -105,7 +105,7 @@
 	'git update-index --force-remove "$p0" &&
 	git diff-index -M --name-status \
 		$t0 | sed -e 's/^R[0-9]*/RNUM/' >current &&
-	git diff expected current'
+	test_cmp expected current'
 
 cat > expected <<\EOF
 diff --git a/no-funny "b/tabs\t,\" (dq) and spaces"
@@ -116,7 +116,7 @@
 test_expect_success 'git diff-tree delete with-funny' \
 	'git diff-index -M -p $t0 |
 	 sed -e "s/index [0-9]*%/index NUM%/" >current &&
-	 git diff expected current'
+	 test_cmp expected current'
 
 chmod +x "$p1"
 cat > expected <<\EOF
@@ -130,7 +130,7 @@
 test_expect_success 'git diff-tree delete with-funny' \
 	'git diff-index -M -p $t0 |
 	 sed -e "s/index [0-9]*%/index NUM%/" >current &&
-	 git diff expected current'
+	 test_cmp expected current'
 
 cat >expected <<\EOF
  "tabs\t,\" (dq) and spaces"
@@ -139,7 +139,7 @@
 test_expect_success 'git diff-tree rename with-funny applied' \
 	'git diff-index -M -p $t0 |
 	 git apply --stat | sed -e "s/|.*//" -e "s/ *\$//" >current &&
-	 git diff expected current'
+	 test_cmp expected current'
 
 cat > expected <<\EOF
  no-funny
@@ -149,12 +149,12 @@
 test_expect_success 'git diff-tree delete with-funny applied' \
 	'git diff-index -p $t0 |
 	 git apply --stat | sed -e "s/|.*//" -e "s/ *\$//" >current &&
-	 git diff expected current'
+	 test_cmp expected current'
 
 test_expect_success 'git apply non-git diff' \
 	'git diff-index -p $t0 |
 	 sed -ne "/^[-+@]/p" |
 	 git apply --stat | sed -e "s/|.*//" -e "s/ *\$//" >current &&
-	 git diff expected current'
+	 test_cmp expected current'
 
 test_done
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 496f4ec..91bb5e1 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -9,7 +9,8 @@
 '
 . ./test-lib.sh
 
-export GIT_AUTHOR_EMAIL=bogus_email_address
+GIT_AUTHOR_EMAIL=bogus_email_address
+export GIT_AUTHOR_EMAIL
 
 test_expect_success \
     'prepare repository with topic branches' \
@@ -44,13 +45,13 @@
 
 test_expect_success \
     'the rebase operation should not have destroyed author information' \
-    '! git log | grep "Author:" | grep "<>"'
+    '! (git log | grep "Author:" | grep "<>")'
 
 test_expect_success 'rebase after merge master' '
      git reset --hard topic &&
      git merge master &&
      git rebase master &&
-     ! git show | grep "^Merge:"
+     ! (git show | grep "^Merge:")
 '
 
 test_expect_success 'rebase of history with merges is linearized' '
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 9cf873f..b9e3dbd 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -91,9 +91,8 @@
 done
 EOF
 
+test_set_editor "$(pwd)/fake-editor.sh"
 chmod a+x fake-editor.sh
-VISUAL="$(pwd)/fake-editor.sh"
-export VISUAL
 
 test_expect_success 'no changes are a nop' '
 	git rebase -i F &&
diff --git a/t/t3407-rebase-abort.sh b/t/t3407-rebase-abort.sh
index 37944c3..1777ffe 100755
--- a/t/t3407-rebase-abort.sh
+++ b/t/t3407-rebase-abort.sh
@@ -4,7 +4,13 @@
 
 . ./test-lib.sh
 
+### Test that we handle space characters properly
+work_dir="$(pwd)/test dir"
+
 test_expect_success setup '
+	mkdir -p "$work_dir" &&
+	cd "$work_dir" &&
+	git init &&
 	echo a > a &&
 	git add a &&
 	git commit -m a &&
@@ -28,32 +34,35 @@
 	dotest=$2
 
 	test_expect_success "rebase$type --abort" '
+		cd "$work_dir" &&
 		# Clean up the state from the previous one
-		git reset --hard pre-rebase
-		test_must_fail git rebase'"$type"' master &&
-		test -d '$dotest' &&
+		git reset --hard pre-rebase &&
+		test_must_fail git rebase$type master &&
+		test -d "$dotest" &&
 		git rebase --abort &&
 		test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) &&
-		test ! -d '$dotest'
+		test ! -d "$dotest"
 	'
 
 	test_expect_success "rebase$type --abort after --skip" '
+		cd "$work_dir" &&
 		# Clean up the state from the previous one
-		git reset --hard pre-rebase
-		test_must_fail git rebase'"$type"' master &&
-		test -d '$dotest' &&
+		git reset --hard pre-rebase &&
+		test_must_fail git rebase$type master &&
+		test -d "$dotest" &&
 		test_must_fail git rebase --skip &&
 		test $(git rev-parse HEAD) = $(git rev-parse master) &&
 		git-rebase --abort &&
 		test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) &&
-		test ! -d '$dotest'
+		test ! -d "$dotest"
 	'
 
 	test_expect_success "rebase$type --abort after --continue" '
+		cd "$work_dir" &&
 		# Clean up the state from the previous one
-		git reset --hard pre-rebase
-		test_must_fail git rebase'"$type"' master &&
-		test -d '$dotest' &&
+		git reset --hard pre-rebase &&
+		test_must_fail git rebase$type master &&
+		test -d "$dotest" &&
 		echo c > a &&
 		echo d >> a &&
 		git add a &&
@@ -61,7 +70,7 @@
 		test $(git rev-parse HEAD) != $(git rev-parse master) &&
 		git rebase --abort &&
 		test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) &&
-		test ! -d '$dotest'
+		test ! -d "$dotest"
 	'
 }
 
diff --git a/t/t3500-cherry.sh b/t/t3500-cherry.sh
index d0a440f..4911c48 100755
--- a/t/t3500-cherry.sh
+++ b/t/t3500-cherry.sh
@@ -10,7 +10,8 @@
 '
 . ./test-lib.sh
 
-export GIT_AUTHOR_EMAIL=bogus_email_address
+GIT_AUTHOR_EMAIL=bogus_email_address
+export GIT_AUTHOR_EMAIL
 
 test_expect_success \
     'prepare repository with topic branch, and check cherry finds the 2 patches from there' \
diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
index f542f0a..7893d8c 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -217,4 +217,16 @@
 	! 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 287e058..fcbc203 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -81,17 +81,17 @@
 
 test_expect_success '.gitignore is honored' '
 	git add . &&
-	! git ls-files | grep "\\.ig"
+	! (git ls-files | grep "\\.ig")
 '
 
 test_expect_success 'error out when attempting to add ignored ones without -f' '
 	! git add a.?? &&
-	! git ls-files | grep "\\.ig"
+	! (git ls-files | grep "\\.ig")
 '
 
 test_expect_success 'error out when attempting to add ignored ones without -f' '
 	! git add d.?? &&
-	! git ls-files | grep "\\.ig"
+	! (git ls-files | grep "\\.ig")
 '
 
 test_expect_success 'add ignored ones with -f' '
@@ -179,4 +179,55 @@
 	test -z "`git diff-index HEAD -- foo`"
 '
 
+test_expect_success 'git add should fail atomically upon an unreadable file' '
+	git reset --hard &&
+	date >foo1 &&
+	date >foo2 &&
+	chmod 0 foo2 &&
+	test_must_fail git add --verbose . &&
+	! ( git ls-files foo1 | grep foo1 )
+'
+
+rm -f foo2
+
+test_expect_success 'git add --ignore-errors' '
+	git reset --hard &&
+	date >foo1 &&
+	date >foo2 &&
+	chmod 0 foo2 &&
+	test_must_fail git add --verbose --ignore-errors . &&
+	git ls-files foo1 | grep foo1
+'
+
+rm -f foo2
+
+test_expect_success 'git add (add.ignore-errors)' '
+	git config add.ignore-errors 1 &&
+	git reset --hard &&
+	date >foo1 &&
+	date >foo2 &&
+	chmod 0 foo2 &&
+	test_must_fail git add --verbose . &&
+	git ls-files foo1 | grep foo1
+'
+rm -f foo2
+
+test_expect_success 'git add (add.ignore-errors = false)' '
+	git config add.ignore-errors 0 &&
+	git reset --hard &&
+	date >foo1 &&
+	date >foo2 &&
+	chmod 0 foo2 &&
+	test_must_fail git add --verbose . &&
+	! ( git ls-files foo1 | grep foo1 )
+'
+
+test_expect_success 'git add '\''fo\?bar'\'' ignores foobar' '
+	git reset --hard &&
+	touch fo\?bar foobar &&
+	git add '\''fo\?bar'\'' &&
+	git ls-files fo\?bar | grep -F fo\?bar &&
+	! ( git ls-files foobar | grep foobar )
+'
+
 test_done
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index 77c90f6..fae64ea 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -66,4 +66,30 @@
 	grep "unchanged *+3/-0 file" output
 '
 
+if test "$(git config --bool core.filemode)" = false
+then
+    say 'skipping filemode tests (filesystem does not properly support modes)'
+else
+
+test_expect_success 'patch does not affect mode' '
+	git reset --hard &&
+	echo content >>file &&
+	chmod +x file &&
+	printf "n\\ny\\n" | git add -p &&
+	git show :file | grep content &&
+	git diff file | grep "new mode"
+'
+
+test_expect_success 'stage mode but not hunk' '
+	git reset --hard &&
+	echo content >>file &&
+	chmod +x file &&
+	printf "y\\nn\\n" | git add -p &&
+	git diff --cached file | grep "new mode" &&
+	git diff          file | grep "+content"
+'
+
+fi
+# end of tests disabled when filemode is not usable
+
 test_done
diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh
index 94b1c24..883281d 100755
--- a/t/t3900-i18n-commit.sh
+++ b/t/t3900-i18n-commit.sh
@@ -9,7 +9,7 @@
 
 compare_with () {
 	git show -s $1 | sed -e '1,/^$/d' -e 's/^    //' >current &&
-	git diff current "$2"
+	test_cmp current "$2"
 }
 
 test_expect_success setup '
diff --git a/t/t4006-diff-mode.sh b/t/t4006-diff-mode.sh
index ab5406d..4e92fce 100755
--- a/t/t4006-diff-mode.sh
+++ b/t/t4006-diff-mode.sh
@@ -38,6 +38,6 @@
 
 test_expect_success \
     'verify' \
-    'git diff expected check'
+    'test_cmp expected check'
 
 test_done
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 6b4d1c5..9337b81 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -112,7 +112,7 @@
 		} >"$actual" &&
 		if test -f "$expect"
 		then
-			git diff "$expect" "$actual" &&
+			test_cmp "$expect" "$actual" &&
 			rm -f "$actual"
 		else
 			# this is to help developing new tests.
@@ -257,6 +257,7 @@
 diff --patch-with-stat -r initial..side
 diff --patch-with-raw -r initial..side
 diff --name-status dir2 dir
+diff --no-index --name-status dir2 dir
 EOF
 
 test_done
diff --git a/t/t4013/diff.diff_--name-status_dir2_dir b/t/t4013/diff.diff_--name-status_dir2_dir
index ef7fdb7..d0d96aa 100644
--- a/t/t4013/diff.diff_--name-status_dir2_dir
+++ b/t/t4013/diff.diff_--name-status_dir2_dir
@@ -1,3 +1,2 @@
 $ git diff --name-status dir2 dir
-A	dir/sub
 $
diff --git a/t/t4013/diff.diff_--no-index_--name-status_dir2_dir b/t/t4013/diff.diff_--no-index_--name-status_dir2_dir
new file mode 100644
index 0000000..6a47584
--- /dev/null
+++ b/t/t4013/diff.diff_--no-index_--name-status_dir2_dir
@@ -0,0 +1,3 @@
+$ git diff --no-index --name-status dir2 dir
+A	dir/sub
+$
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index b2b7a8d..3583e68 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -226,7 +226,7 @@
 
 	git format-patch --cover-letter -2 &&
 	sed -e "1,/A U Thor/d" -e "/^$/q" < 0000-cover-letter.patch > output &&
-	git diff expect output
+	test_cmp expect output
 
 '
 
diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
index 83c54b7..ca0302f 100755
--- a/t/t4015-diff-whitespace.sh
+++ b/t/t4015-diff-whitespace.sh
@@ -43,13 +43,13 @@
 EOF
 
 git diff > out
-test_expect_success "Ray's example without options" 'git diff expect out'
+test_expect_success "Ray's example without options" 'test_cmp expect out'
 
 git diff -w > out
-test_expect_success "Ray's example with -w" 'git diff expect out'
+test_expect_success "Ray's example with -w" 'test_cmp expect out'
 
 git diff -b > out
-test_expect_success "Ray's example with -b" 'git diff expect out'
+test_expect_success "Ray's example with -b" 'test_cmp expect out'
 
 tr 'Q' '\015' << EOF > x
 whitespace at beginning
@@ -90,14 +90,14 @@
 +CR at end
 EOF
 git diff > out
-test_expect_success 'another test, without options' 'git diff expect out'
+test_expect_success 'another test, without options' 'test_cmp expect out'
 
 cat << EOF > expect
 diff --git a/x b/x
 index d99af23..8b32fb5 100644
 EOF
 git diff -w > out
-test_expect_success 'another test, with -w' 'git diff expect out'
+test_expect_success 'another test, with -w' 'test_cmp expect out'
 
 tr 'Q' '\015' << EOF > expect
 diff --git a/x b/x
@@ -115,7 +115,7 @@
  CR at endQ
 EOF
 git diff -b > out
-test_expect_success 'another test, with -b' 'git diff expect out'
+test_expect_success 'another test, with -b' 'test_cmp expect out'
 
 test_expect_success 'check mixed spaces and tabs in indent' '
 
diff --git a/t/t4016-diff-quote.sh b/t/t4016-diff-quote.sh
index 5dbdc0c..0950250 100755
--- a/t/t4016-diff-quote.sh
+++ b/t/t4016-diff-quote.sh
@@ -49,7 +49,7 @@
 EOF
 test_expect_success 'git diff --summary -M HEAD' '
 	git diff --summary -M HEAD >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 cat >expect <<\EOF
@@ -64,7 +64,7 @@
 EOF
 test_expect_success 'git diff --stat -M HEAD' '
 	git diff --stat -M HEAD >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 test_done
diff --git a/t/t4017-diff-retval.sh b/t/t4017-diff-retval.sh
index dc0b712..0d0fb87 100755
--- a/t/t4017-diff-retval.sh
+++ b/t/t4017-diff-retval.sh
@@ -105,4 +105,12 @@
 
 '
 
+
+test_expect_success 'check should test not just the last line' '
+	echo "" >>a &&
+	git --no-pager diff --check
+	test $? = 2
+
+'
+
 test_done
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index f9db81d..6d3ef6c 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -33,13 +33,13 @@
 sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java
 
 test_expect_success 'default behaviour' '
-	git diff Beer.java Beer-correct.java |
+	git diff --no-index Beer.java Beer-correct.java |
 	grep "^@@.*@@ public class Beer"
 '
 
 test_expect_success 'preset java pattern' '
 	echo "*.java diff=java" >.gitattributes &&
-	git diff Beer.java Beer-correct.java |
+	git diff --no-index Beer.java Beer-correct.java |
 	grep "^@@.*@@ public static void main("
 '
 
@@ -48,13 +48,13 @@
 [^ 	].*s.*'
 
 test_expect_success 'custom pattern' '
-	git diff Beer.java Beer-correct.java |
+	git diff --no-index Beer.java Beer-correct.java |
 	grep "^@@.*@@ int special;$"
 '
 
 test_expect_success 'last regexp must not be negated' '
 	git config diff.java.funcname "!static" &&
-	! git diff Beer.java Beer-correct.java
+	! git diff --no-index Beer.java Beer-correct.java
 '
 
 test_done
diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh
index 1fd3fb7..ba6679c 100755
--- a/t/t4027-diff-submodule.sh
+++ b/t/t4027-diff-submodule.sh
@@ -50,4 +50,11 @@
 	test_cmp expect actual.files
 '
 
+test_expect_success 'git diff (empty submodule dir)' '
+	: >empty &&
+	rm -rf sub/* sub/.git &&
+	git diff > actual.empty &&
+	test_cmp empty actual.empty
+'
+
 test_done
diff --git a/t/t4100-apply-stat.sh b/t/t4100-apply-stat.sh
index 435f65b..8073a5a 100755
--- a/t/t4100-apply-stat.sh
+++ b/t/t4100-apply-stat.sh
@@ -11,36 +11,36 @@
 test_expect_success \
     'rename' \
     'git apply --stat --summary <../t4100/t-apply-1.patch >current &&
-    git diff ../t4100/t-apply-1.expect current'
+    test_cmp ../t4100/t-apply-1.expect current'
 
 test_expect_success \
     'copy' \
     'git apply --stat --summary <../t4100/t-apply-2.patch >current &&
-    git diff ../t4100/t-apply-2.expect current'
+    test_cmp ../t4100/t-apply-2.expect current'
 
 test_expect_success \
     'rewrite' \
     'git apply --stat --summary <../t4100/t-apply-3.patch >current &&
-    git diff ../t4100/t-apply-3.expect current'
+    test_cmp ../t4100/t-apply-3.expect current'
 
 test_expect_success \
     'mode' \
     'git apply --stat --summary <../t4100/t-apply-4.patch >current &&
-    git diff ../t4100/t-apply-4.expect current'
+    test_cmp ../t4100/t-apply-4.expect current'
 
 test_expect_success \
     'non git' \
     'git apply --stat --summary <../t4100/t-apply-5.patch >current &&
-    git diff ../t4100/t-apply-5.expect current'
+    test_cmp ../t4100/t-apply-5.expect current'
 
 test_expect_success \
     'non git' \
     'git apply --stat --summary <../t4100/t-apply-6.patch >current &&
-    git diff ../t4100/t-apply-6.expect current'
+    test_cmp ../t4100/t-apply-6.expect current'
 
 test_expect_success \
     'non git' \
     'git apply --stat --summary <../t4100/t-apply-7.patch >current &&
-    git diff ../t4100/t-apply-7.expect current'
+    test_cmp ../t4100/t-apply-7.expect current'
 
 test_done
diff --git a/t/t4104-apply-boundary.sh b/t/t4104-apply-boundary.sh
index 43943ab..e7e2913 100755
--- a/t/t4104-apply-boundary.sh
+++ b/t/t4104-apply-boundary.sh
@@ -90,7 +90,7 @@
 				cat '"$kind-patch.$with"'
 				(exit 1)
 			} &&
-			git diff '"$kind"'-expect victim
+			test_cmp '"$kind"'-expect victim
 		'
 	done
 done
@@ -108,7 +108,7 @@
 			cat '"$kind-ng.without"'
 			(exit 1)
 		} &&
-		git diff '"$kind"'-expect victim
+		test_cmp '"$kind"'-expect victim
 	'
 done
 
diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh
index a07ff42..9ace578 100755
--- a/t/t4115-apply-symlink.sh
+++ b/t/t4115-apply-symlink.sh
@@ -33,7 +33,7 @@
 	git checkout side &&
 	git apply patch &&
 	git diff-files -p >patched &&
-	git diff patch patched
+	test_cmp patch patched
 
 '
 
@@ -42,7 +42,7 @@
 	git checkout -f side &&
 	git apply --index patch &&
 	git diff-index --cached -p HEAD >patched &&
-	git diff patch patched
+	test_cmp patch patched
 
 '
 
diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh
index c3f4579..1459a90 100755
--- a/t/t4116-apply-reverse.sh
+++ b/t/t4116-apply-reverse.sh
@@ -42,7 +42,7 @@
 	git reset --hard second &&
 	git apply --reverse --binary --index patch &&
 	git diff >diff &&
-	git diff /dev/null diff
+	test_cmp /dev/null diff
 
 '
 
diff --git a/t/t4117-apply-reject.sh b/t/t4117-apply-reject.sh
index 659e17c..e9ccd16 100755
--- a/t/t4117-apply-reject.sh
+++ b/t/t4117-apply-reject.sh
@@ -54,7 +54,7 @@
 		exit 1
 	fi
 
-	git diff file1 saved.file1
+	test_cmp file1 saved.file1
 '
 
 test_expect_success 'apply without --reject should fail' '
@@ -65,7 +65,7 @@
 		exit 1
 	fi
 
-	git diff file1 saved.file1
+	test_cmp file1 saved.file1
 '
 
 test_expect_success 'apply with --reject should fail but update the file' '
@@ -79,7 +79,7 @@
 		exit 1
 	fi
 
-	git diff file1 expected &&
+	test_cmp file1 expected &&
 
 	cat file1.rej &&
 
@@ -105,7 +105,7 @@
 		echo "file1 still exists?"
 		exit 1
 	}
-	git diff file2 expected &&
+	test_cmp file2 expected &&
 
 	cat file2.rej &&
 
@@ -132,7 +132,7 @@
 		echo "file1 still exists?"
 		exit 1
 	}
-	git diff file2 expected &&
+	test_cmp file2 expected &&
 
 	cat file2.rej &&
 
@@ -151,7 +151,7 @@
 
 	git apply --verbose patch.1 &&
 
-	git diff file1 clean
+	test_cmp file1 clean
 '
 
 test_done
diff --git a/t/t4118-apply-empty-context.sh b/t/t4118-apply-empty-context.sh
index 1d531ca..f92e259 100755
--- a/t/t4118-apply-empty-context.sh
+++ b/t/t4118-apply-empty-context.sh
@@ -38,7 +38,7 @@
 		echo "0	1	file1" &&
 		echo "0	1	file2"
 	} >expect &&
-	git diff expect actual
+	test_cmp expect actual
 
 '
 
@@ -48,8 +48,8 @@
 	cat file2.orig >file2 &&
 	git update-index file1 file2 &&
 	git apply --index diff.output &&
-	git diff file1.mods file1 &&
-	git diff file2.mods file2
+	test_cmp file1.mods file1 &&
+	test_cmp file2.mods file2
 '
 
 test_done
diff --git a/t/t4126-apply-empty.sh b/t/t4126-apply-empty.sh
new file mode 100755
index 0000000..ceb6a79
--- /dev/null
+++ b/t/t4126-apply-empty.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+test_description='apply empty'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+	>empty &&
+	git add empty &&
+	test_tick &&
+	git commit -m initial &&
+	for i in a b c d e
+	do
+		echo $i
+	done >empty &&
+	cat empty >expect &&
+	git diff |
+	sed -e "/^diff --git/d" \
+	    -e "/^index /d" \
+	    -e "s|a/empty|empty.orig|" \
+	    -e "s|b/empty|empty|" >patch0 &&
+	sed -e "s|empty|missing|" patch0 >patch1 &&
+	>empty &&
+	git update-index --refresh
+'
+
+test_expect_success 'apply empty' '
+	git reset --hard &&
+	rm -f missing &&
+	git apply patch0 &&
+	test_cmp expect empty
+'
+
+test_expect_success 'apply --index empty' '
+	git reset --hard &&
+	rm -f missing &&
+	git apply --index patch0 &&
+	test_cmp expect empty &&
+	git diff --exit-code
+'
+
+test_expect_success 'apply create' '
+	git reset --hard &&
+	rm -f missing &&
+	git apply patch1 &&
+	test_cmp expect missing
+'
+
+test_expect_success 'apply --index create' '
+	git reset --hard &&
+	rm -f missing &&
+	git apply --index patch1 &&
+	test_cmp expect missing &&
+	git diff --exit-code
+'
+
+test_done
diff --git a/t/t4150-am-subdir.sh b/t/t4150-am-subdir.sh
deleted file mode 100755
index 52069b4..0000000
--- a/t/t4150-am-subdir.sh
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/bin/sh
-
-test_description='git am running from a subdirectory'
-
-. ./test-lib.sh
-
-test_expect_success setup '
-	echo hello >world &&
-	git add world &&
-	test_tick &&
-	git commit -m initial &&
-	git tag initial &&
-	echo goodbye >world &&
-	git add world &&
-	test_tick &&
-	git commit -m second &&
-	git format-patch --stdout HEAD^ >patchfile &&
-	: >expect
-'
-
-test_expect_success 'am regularly from stdin' '
-	git checkout initial &&
-	git am <patchfile &&
-	git diff master >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'am regularly from file' '
-	git checkout initial &&
-	git am patchfile &&
-	git diff master >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'am regularly from stdin in subdirectory' '
-	rm -fr subdir &&
-	git checkout initial &&
-	(
-		mkdir -p subdir &&
-		cd subdir &&
-		git am <../patchfile
-	) &&
-	git diff master>actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'am regularly from file in subdirectory' '
-	rm -fr subdir &&
-	git checkout initial &&
-	(
-		mkdir -p subdir &&
-		cd subdir &&
-		git am ../patchfile
-	) &&
-	git diff master >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'am regularly from file in subdirectory with full path' '
-	rm -fr subdir &&
-	git checkout initial &&
-	P=$(pwd) &&
-	(
-		mkdir -p subdir &&
-		cd subdir &&
-		git am "$P/patchfile"
-	) &&
-	git diff master >actual &&
-	test_cmp expect actual
-'
-
-test_done
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
new file mode 100755
index 0000000..722ae96
--- /dev/null
+++ b/t/t4150-am.sh
@@ -0,0 +1,260 @@
+#!/bin/sh
+
+test_description='git am running'
+
+. ./test-lib.sh
+
+cat >msg <<EOF
+second
+
+Lorem ipsum dolor sit amet, consectetuer sadipscing elitr, sed diam nonumy
+eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
+voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita
+kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem
+ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
+tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
+vero eos et accusam et justo duo dolores et ea rebum.
+
+	Duis autem vel eum iriure dolor in hendrerit in vulputate velit
+	esse molestie consequat, vel illum dolore eu feugiat nulla facilisis
+	at vero eros et accumsan et iusto odio dignissim qui blandit
+	praesent luptatum zzril delenit augue duis dolore te feugait nulla
+	facilisi.
+
+
+Lorem ipsum dolor sit amet,
+consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut
+laoreet dolore magna aliquam erat volutpat.
+
+  git
+  ---
+  +++
+
+Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit
+lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure
+dolor in hendrerit in vulputate velit esse molestie consequat, vel illum
+dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio
+dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te
+feugait nulla facilisi.
+EOF
+
+cat >failmail <<EOF
+From foo@example.com Fri May 23 10:43:49 2008
+From:	foo@example.com
+To:	bar@example.com
+Subject: Re: [RFC/PATCH] git-foo.sh
+Date:	Fri, 23 May 2008 05:23:42 +0200
+
+Sometimes we have to find out that there's nothing left.
+
+EOF
+
+cat >pine <<EOF
+From MAILER-DAEMON Fri May 23 10:43:49 2008
+Date: 23 May 2008 05:23:42 +0200
+From: Mail System Internal Data <MAILER-DAEMON@example.com>
+Subject: DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA
+Message-ID: <foo-0001@example.com>
+
+This text is part of the internal format of your mail folder, and is not
+a real message.  It is created automatically by the mail system software.
+If deleted, important folder data will be lost, and it will be re-created
+with the data reset to initial values.
+
+EOF
+
+echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >expected
+
+test_expect_success setup '
+	echo hello >file &&
+	git add file &&
+	test_tick &&
+	git commit -m first &&
+	git tag first &&
+	echo world >>file &&
+	git add file &&
+	test_tick &&
+	git commit -s -F msg &&
+	git tag second &&
+	git format-patch --stdout first >patch1 &&
+	sed -n -e "3,\$p" msg >file &&
+	git add file &&
+	test_tick &&
+	git commit -m third &&
+	git format-patch --stdout first >patch2	&&
+	git checkout -b lorem &&
+	sed -n -e "11,\$p" msg >file &&
+	head -n 9 msg >>file &&
+	test_tick &&
+	git commit -a -m "moved stuff" &&
+	echo goodbye >another &&
+	git add another &&
+	test_tick &&
+	git commit -m "added another file" &&
+	git format-patch --stdout master >lorem-move.patch
+'
+
+# reset time
+unset test_tick
+test_tick
+
+test_expect_success 'am applies patch correctly' '
+	git checkout first &&
+	test_tick &&
+	git am <patch1 &&
+	! test -d .dotest &&
+	test -z "$(git diff second)" &&
+	test "$(git rev-parse second)" = "$(git rev-parse HEAD)" &&
+	test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)"
+'
+
+GIT_AUTHOR_NAME="Another Thor"
+GIT_AUTHOR_EMAIL="a.thor@example.com"
+GIT_COMMITTER_NAME="Co M Miter" 
+GIT_COMMITTER_EMAIL="c.miter@example.com"
+export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL
+
+compare () {
+	test "$(git cat-file commit "$2" | grep "^$1 ")" = \
+	     "$(git cat-file commit "$3" | grep "^$1 ")"
+}
+
+test_expect_success 'am changes committer and keeps author' '
+	test_tick &&
+	git checkout first &&
+	git am patch2 &&
+	! test -d .dotest &&
+	test "$(git rev-parse master^^)" = "$(git rev-parse HEAD^^)" &&
+	test -z "$(git diff master..HEAD)" &&
+	test -z "$(git diff master^..HEAD^)" &&
+	compare author master HEAD &&
+	compare author master^ HEAD^ &&
+	test "$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" = \
+	     "$(git log -1 --pretty=format:"%cn <%ce>" HEAD)"
+'
+
+test_expect_success 'am --signoff adds Signed-off-by: line' '
+	git checkout -b master2 first &&
+	git am --signoff <patch2 &&
+	echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >>expected &&
+	git cat-file commit HEAD^ | grep "Signed-off-by:" >actual &&
+	test_cmp actual expected &&
+	echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >expected &&
+	git cat-file commit HEAD | grep "Signed-off-by:" >actual &&
+	test_cmp actual expected
+'
+
+test_expect_success 'am stays in branch' '
+	test "refs/heads/master2" = "$(git symbolic-ref HEAD)"
+'
+
+test_expect_success 'am --signoff does not add Signed-off-by: line if already there' '
+	git format-patch --stdout HEAD^ >patch3 &&
+	sed -e "/^Subject/ s,\[PATCH,Re: Re: Re: & 1/5 v2," patch3 >patch4
+	git checkout HEAD^ &&
+	git am --signoff patch4 &&
+	test "$(git cat-file commit HEAD | grep -c "^Signed-off-by:")" -eq 1
+'
+
+test_expect_success 'am without --keep removes Re: and [PATCH] stuff' '
+	test "$(git rev-parse HEAD)" = "$(git rev-parse master2)"
+'
+
+test_expect_success 'am --keep really keeps the subject' '
+	git checkout HEAD^ &&
+	git am --keep patch4 &&
+	! test -d .dotest &&
+	git-cat-file commit HEAD |
+		grep -q -F "Re: Re: Re: [PATCH 1/5 v2] third"
+'
+
+test_expect_success 'am -3 falls back to 3-way merge' '
+	git checkout -b lorem2 master2 &&
+	sed -n -e "3,\$p" msg >file &&
+	head -n 9 msg >>file &&
+	git add file &&
+	test_tick &&
+	git commit -m "copied stuff" &&
+	git am -3 lorem-move.patch &&
+	! test -d .dotest &&
+	test -z "$(git diff lorem)"
+'
+
+test_expect_success 'am pauses on conflict' '
+	git checkout lorem2^^ &&
+	! git am lorem-move.patch &&
+	test -d .dotest
+'
+
+test_expect_success 'am --skip works' '
+	git am --skip &&
+	! test -d .dotest &&
+	test -z "$(git diff lorem2^^ -- file)" &&
+	test goodbye = "$(cat another)"
+'
+
+test_expect_success 'am --resolved works' '
+	git checkout lorem2^^ &&
+	! git am lorem-move.patch &&
+	test -d .dotest &&
+	echo resolved >>file &&
+	git add file &&
+	git am --resolved &&
+	! test -d .dotest &&
+	test goodbye = "$(cat another)"
+'
+
+test_expect_success 'am takes patches from a Pine mailbox' '
+	git checkout first &&
+	cat pine patch1 | git am &&
+	! test -d .dotest &&
+	test -z "$(git diff master^..HEAD)"
+'
+
+test_expect_success 'am fails on mail without patch' '
+	! git am <failmail &&
+	rm -r .dotest/
+'
+
+test_expect_success 'am fails on empty patch' '
+	echo "---" >>failmail &&
+	! git am <failmail &&
+	git am --skip &&
+	! test -d .dotest
+'
+
+test_expect_success 'am works from stdin in subdirectory' '
+	rm -fr subdir &&
+	git checkout first &&
+	(
+		mkdir -p subdir &&
+		cd subdir &&
+		git am <../patch1
+	) &&
+	test -z "$(git diff second)"
+'
+
+test_expect_success 'am works from file (relative path given) in subdirectory' '
+	rm -fr subdir &&
+	git checkout first &&
+	(
+		mkdir -p subdir &&
+		cd subdir &&
+		git am ../patch1
+	) &&
+	test -z "$(git diff second)"
+'
+
+test_expect_success 'am works from file (absolute path given) in subdirectory' '
+	rm -fr subdir &&
+	git checkout first &&
+	P=$(pwd) &&
+	(
+		mkdir -p subdir &&
+		cd subdir &&
+		git am "$P/patch1"
+	) &&
+	test -z "$(git diff second)"
+'
+
+test_done
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index 3cbfee7..85d7e3e 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -101,7 +101,7 @@
 EOF
 git rerere diff > out
 
-test_expect_success 'rerere diff' 'git diff expect out'
+test_expect_success 'rerere diff' 'test_cmp expect out'
 
 cat > expect << EOF
 a1
@@ -109,7 +109,7 @@
 
 git rerere status > out
 
-test_expect_success 'rerere status' 'git diff expect out'
+test_expect_success 'rerere status' 'test_cmp expect out'
 
 test_expect_success 'commit succeeds' \
 	"git commit -q -a -m 'prefer first over second'"
@@ -126,7 +126,7 @@
 git show first:a1 | sed 's/To die: t/To die! T/' > expect
 test_expect_success 'rerere kicked in' "! grep ======= a1"
 
-test_expect_success 'rerere prefers first change' 'git diff a1 expect'
+test_expect_success 'rerere prefers first change' 'test_cmp a1 expect'
 
 rm $rr/postimage
 echo "$sha1	a1" | perl -pe 'y/\012/\000/' > .git/rr-cache/MERGE_RR
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index b536454..4c8af45 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -71,4 +71,5 @@
 
 
 
-test_done
\ No newline at end of file
+test_done
+
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index fa62b6a..87902f8 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -25,7 +25,6 @@
 '
 
 . ./test-lib.sh
-TAR=${TAR:-tar}
 UNZIP=${UNZIP:-unzip}
 
 SUBSTFORMAT=%H%n
@@ -67,10 +66,10 @@
 
 test_expect_success \
     'validate file modification time' \
-    'TZ=GMT $TAR tvf b.tar a/a |
-     awk \{print\ \$4,\ \(length\(\$5\)\<7\)\ ?\ \$5\":00\"\ :\ \$5\} \
-     >b.mtime &&
-     echo "2005-05-27 22:00:00" >expected.mtime &&
+    'mkdir extract &&
+     "$TAR" xf b.tar -C extract a/a &&
+     perl -e '\''print((stat("extract/a/a"))[9], "\n")'\'' >b.mtime &&
+     echo "1117231200" >expected.mtime &&
      diff expected.mtime b.mtime'
 
 test_expect_success \
@@ -80,7 +79,7 @@
 
 test_expect_success \
     'extract tar archive' \
-    '(cd b && $TAR xf -) <b.tar'
+    '(cd b && "$TAR" xf -) <b.tar'
 
 test_expect_success \
     'validate filenames' \
@@ -97,7 +96,7 @@
 
 test_expect_success \
     'extract tar archive with prefix' \
-    '(cd c && $TAR xf -) <c.tar'
+    '(cd c && "$TAR" xf -) <c.tar'
 
 test_expect_success \
     'validate filenames with prefix' \
@@ -117,7 +116,7 @@
 
 test_expect_success \
     'extract substfiles' \
-    '(mkdir f && cd f && $TAR xf -) <f.tar'
+    '(mkdir f && cd f && "$TAR" xf -) <f.tar'
 
 test_expect_success \
      'validate substfile contents' \
@@ -129,7 +128,7 @@
 
 test_expect_success \
     'extract substfiles from archive with prefix' \
-    '(mkdir g && cd g && $TAR xf -) <g.tar'
+    '(mkdir g && cd g && "$TAR" xf -) <g.tar'
 
 test_expect_success \
      'validate substfile contents from archive with prefix' \
diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh
index d6c55c1..e9f3e72 100755
--- a/t/t5100-mailinfo.sh
+++ b/t/t5100-mailinfo.sh
@@ -11,7 +11,7 @@
 	'git mailsplit -o. ../t5100/sample.mbox >last &&
 	last=`cat last` &&
 	echo total is $last &&
-	test `cat last` = 9'
+	test `cat last` = 10'
 
 for mail in `echo 00*`
 do
@@ -25,4 +25,22 @@
 		diff ../t5100/info$mail info$mail"
 done
 
+test_expect_success 'respect NULs' '
+
+	git mailsplit -d3 -o. ../t5100/nul-plain &&
+	cmp ../t5100/nul-plain 001 &&
+	(cat 001 | git mailinfo msg patch) &&
+	test 4 = $(wc -l < patch)
+
+'
+
+test_expect_success 'Preserve NULs out of MIME encoded message' '
+
+	git mailsplit -d5 -o. ../t5100/nul-b64.in &&
+	cmp ../t5100/nul-b64.in 00001 &&
+	git mailinfo msg patch <00001 &&
+	cmp ../t5100/nul-b64.expect patch
+
+'
+
 test_done
diff --git a/t/t5100/0010 b/t/t5100/0010
new file mode 100644
index 0000000..f5892c9
--- /dev/null
+++ b/t/t5100/0010
@@ -0,0 +1,35 @@
+From b9704a518e21158433baa2cc2d591fea687967f6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Lukas=20Sandstr=C3=B6m?= <lukass@etek.chalmers.se>
+Date: Thu, 10 Jul 2008 23:41:33 +0200
+Subject: Re: discussion that lead to this patch
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+[PATCH] git-mailinfo: Fix getting the subject from the body
+
+"Subject: " isn't in the static array "header", and thus
+memcmp("Subject: ", header[i], 7) will never match.
+
+Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>
+Signed-off-by: Junio C Hamano <gitster@pobox.com>
+---
+ builtin-mailinfo.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
+index 962aa34..2d1520f 100644
+--- a/builtin-mailinfo.c
++++ b/builtin-mailinfo.c
+@@ -334,7 +334,7 @@ static int check_header(char *line, unsigned linesize, char **hdr_data, int over
+ 		return 1;
+ 	if (!memcmp("[PATCH]", line, 7) && isspace(line[7])) {
+ 		for (i = 0; header[i]; i++) {
+-			if (!memcmp("Subject: ", header[i], 9)) {
++			if (!memcmp("Subject", header[i], 7)) {
+ 				if (! handle_header(line, hdr_data[i], 0)) {
+ 					return 1;
+ 				}
+-- 
+1.5.6.2.455.g1efb2
+
diff --git a/t/t5100/info0010 b/t/t5100/info0010
new file mode 100644
index 0000000..1791241
--- /dev/null
+++ b/t/t5100/info0010
@@ -0,0 +1,5 @@
+Author: Lukas Sandström
+Email: lukass@etek.chalmers.se
+Subject: git-mailinfo: Fix getting the subject from the body
+Date: Thu, 10 Jul 2008 23:41:33 +0200
+
diff --git a/t/t5100/msg0010 b/t/t5100/msg0010
new file mode 100644
index 0000000..a96c230
--- /dev/null
+++ b/t/t5100/msg0010
@@ -0,0 +1,5 @@
+"Subject: " isn't in the static array "header", and thus
+memcmp("Subject: ", header[i], 7) will never match.
+
+Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>
+Signed-off-by: Junio C Hamano <gitster@pobox.com>
diff --git a/t/t5100/nul-b64.expect b/t/t5100/nul-b64.expect
new file mode 100644
index 0000000..d7d680f
--- /dev/null
+++ b/t/t5100/nul-b64.expect
Binary files differ
diff --git a/t/t5100/nul-b64.in b/t/t5100/nul-b64.in
new file mode 100644
index 0000000..16540d9
--- /dev/null
+++ b/t/t5100/nul-b64.in
@@ -0,0 +1,37 @@
+From 667d8940e719cddee1cfe237cbbe215e20270b09 Mon Sep 17 00:00:00 2001
+From: Junio C Hamano <gitster@pobox.com>
+Date: Sun, 25 May 2008 00:38:18 -0700
+Subject: [PATCH] second
+Content-Transfer-Encoding: base64
+
+LS0tCiBmaWxlIHwgIEJpbiAxMzU3IC0+IDEzNTcgYnl0ZXMKIDEgZmlsZXMgY2hhbmdlZCwg
+MCBpbnNlcnRpb25zKCspLCAwIGRlbGV0aW9ucygtKQoKZGlmZiAtLWdpdCBhL2ZpbGUgYi9m
+aWxlCmluZGV4IDc3MzYxZDguLjllMDJiZTYgMTAwNjQ0Ci0tLSBhL2ZpbGUKKysrIGIvZmls
+ZQpAQCAtMSwxMiArMSwxMiBAQAogTG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNl
+Y3RldHVlciBhZGlwaXNjaW5nIGVsaXQuIFN1c3BlbmRpc3NlCiBzaXQgYW1ldCB0dXJwaXMg
+ZWdldCBlc3QgY3Vyc3VzIGxhb3JlZXQuIEFsaXF1YW0gbWF1cmlzLiBQcmFlc2VudAotdm9s
+dXRwYXQuIFByb2luIGluIHB1cnVzLiBOdWxsYSB1cm5hIHNhcGllbiwgZGFwaWJ1cyBzaXQg
+YW1ldCwKK3ZvbHV0cGF0LiBQcm9pbiBpbiBwdXJ1cy4gTnVsbGEgdXJuYSBzYXBpZW4sIGRh
+cGkAdXMgc2l0IGFtZXQsCiBoZW5kcmVyaXQgbmVjLCB0ZW1wdXMgZXUsIG1pLiBVdCBwb3J0
+YSwgbGVvIGlkIHRpbmNpZHVudCB1bGxhbWNvcnBlciwKLXZlbGl0IGZlbGlzIHRyaXN0aXF1
+ZSBhbnRlLCBhdCBsb2JvcnRpcyBkaWFtIHBlZGUgdXQgZHVpLiBQcm9pbiBhYwordmVsaXQg
+ZmVsaXMgdHJpc3RpcXVlIGFudGUsIGF0IGxvAG9ydGlzIGRpYW0gcGVkZSB1dCBkdWkuIFBy
+b2luIGFjCiBsZWN0dXMuIERvbmVjIGF0IG1hc3NhIGFjIGlwc3VtIGhlbmRyZXJpdCBzb2xs
+aWNpdHVkaW4uIE5hbSBkaWN0dW0KIG5pc2kgc2VkIG1pLiBEdWlzIHNlZCBhbnRlLiBVdCB2
+aXRhZSBlc3QgdXQgZHVpIHVsdHJpY2llcyBkaWduaXNzaW0uCiAKLUluIHZlbCBvZGlvIGVn
+ZXQgbmlzbCBjb252YWxsaXMgdm9sdXRwYXQuIE1vcmJpIHZpdGFlIG5pYmguIE51bGxhbQor
+SW4gdmVsIG9kaW8gZWdldCBuaXNsIGNvbnZhbGxpcyB2b2x1dHBhdC4gTW9yAGkgdml0YWUg
+bmkAaC4gTnVsbGFtCiBhY2N1bXNhbiwgZG9sb3IgcXVpcyBhbGlxdWFtIHNjZWxlcmlzcXVl
+LCBlbGl0IGVuaW0gY29uZGltZW50dW0KIG1hdXJpcywgbm9uIHRyaXN0aXF1ZSBtYXVyaXMg
+dHVycGlzIGV0IG1hdXJpcy4gVXQgbm9uIG5pc2wuIE5hbSBkaWFtCiBtaSwgc2VtcGVyIHBv
+c3VlcmUsIGVsZWlmZW5kIHV0LCBhdWN0b3IgdmVsLCBlcmF0LiBTZWQgcG9zdWVyZQpAQCAt
+MTYsNyArMTYsNyBAQCBzZWQgZXN0LiBFdGlhbSBkaWFtIGZlbGlzLCBmZXJtZW50dW0gZWdl
+dCwgYWRpcGlzY2luZyBhdCwgcG9zdWVyZSBpbiwKIGR1aS4gRXRpYW0gbHVjdHVzLgogCiBO
+dWxsYSBpZCBhdWd1ZS4gTmFtIGlhY3VsaXMgYWNjdW1zYW4gbmlzaS4gU3VzcGVuZGlzc2Ug
+cG90ZW50aS4gTnVuYwotdmFyaXVzIGF1Z3VlIG5lYyBvcmNpLiBVdCBjb25kaW1lbnR1bSBk
+b2xvciBzYWdpdHRpcyBuaWJoLiBTdXNwZW5kaXNzZQordmFyaXVzIGF1Z3VlIG5lYyBvcmNp
+LiBVdCBjb25kaW1lbnR1bSBkb2xvciBzYWdpdHRpcyBuaQBoLiBTdXNwZW5kaXNzZQogdGVt
+cG9yIGxlY3R1cyBzZWQgbWFnbmEuIFN1c3BlbmRpc3NlIHBvdGVudGkuIE51bGxhbSB0ZW1w
+b3IgaXBzdW0uIFNlZAogbW9sZXN0aWUgdGVsbHVzLiBQaGFzZWxsdXMgbGlndWxhLiBJbiB2
+ZWhpY3VsYSB1bHRyaWNlcwogbmlzaS4gU3VzcGVuZGlzc2UgZmVsaXMgYXVndWUsIHBlbGxl
+bnRlc3F1ZSBhdCwgZGljdHVtIHZpdmVycmEsCi0tIAoxLjUuNS4xLjU0MC5nNTc3ODAKCg==
diff --git a/t/t5100/nul-plain b/t/t5100/nul-plain
new file mode 100644
index 0000000..3d40691
--- /dev/null
+++ b/t/t5100/nul-plain
Binary files differ
diff --git a/t/t5100/patch0010 b/t/t5100/patch0010
new file mode 100644
index 0000000..f055481
--- /dev/null
+++ b/t/t5100/patch0010
@@ -0,0 +1,20 @@
+---
+ builtin-mailinfo.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
+index 962aa34..2d1520f 100644
+--- a/builtin-mailinfo.c
++++ b/builtin-mailinfo.c
+@@ -334,7 +334,7 @@ static int check_header(char *line, unsigned linesize, char **hdr_data, int over
+ 		return 1;
+ 	if (!memcmp("[PATCH]", line, 7) && isspace(line[7])) {
+ 		for (i = 0; header[i]; i++) {
+-			if (!memcmp("Subject: ", header[i], 9)) {
++			if (!memcmp("Subject", header[i], 7)) {
+ 				if (! handle_header(line, hdr_data[i], 0)) {
+ 					return 1;
+ 				}
+-- 
+1.5.6.2.455.g1efb2
+
diff --git a/t/t5100/sample.mbox b/t/t5100/sample.mbox
index 0476b96..aba57f9 100644
--- a/t/t5100/sample.mbox
+++ b/t/t5100/sample.mbox
@@ -430,3 +430,38 @@
 =20
 =20
  2. When the environment variable 'GIT_EXTERNAL_DIFF' is set, the
+From b9704a518e21158433baa2cc2d591fea687967f6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Lukas=20Sandstr=C3=B6m?= <lukass@etek.chalmers.se>
+Date: Thu, 10 Jul 2008 23:41:33 +0200
+Subject: Re: discussion that lead to this patch
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+[PATCH] git-mailinfo: Fix getting the subject from the body
+
+"Subject: " isn't in the static array "header", and thus
+memcmp("Subject: ", header[i], 7) will never match.
+
+Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>
+Signed-off-by: Junio C Hamano <gitster@pobox.com>
+---
+ builtin-mailinfo.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
+index 962aa34..2d1520f 100644
+--- a/builtin-mailinfo.c
++++ b/builtin-mailinfo.c
+@@ -334,7 +334,7 @@ static int check_header(char *line, unsigned linesize, char **hdr_data, int over
+ 		return 1;
+ 	if (!memcmp("[PATCH]", line, 7) && isspace(line[7])) {
+ 		for (i = 0; header[i]; i++) {
+-			if (!memcmp("Subject: ", header[i], 9)) {
++			if (!memcmp("Subject", header[i], 7)) {
+ 				if (! handle_header(line, hdr_data[i], 0)) {
+ 					return 1;
+ 				}
+-- 
+1.5.6.2.455.g1efb2
+
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index c955fe4..983a393 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -274,4 +274,99 @@
      packname_4=$(git pack-objects test-4 <obj-list) &&
      test 3 = $(ls test-4-*.pack | wc -l)'
 
+test_expect_success 'unpacking with --strict' '
+
+	git config --unset pack.packsizelimit &&
+	for j in a b c d e f g
+	do
+		for i in 0 1 2 3 4 5 6 7 8 9
+		do
+			o=$(echo $j$i | git hash-object -w --stdin) &&
+			echo "100644 $o	0 $j$i"
+		done
+	done >LIST &&
+	rm -f .git/index &&
+	git update-index --index-info <LIST &&
+	LIST=$(git write-tree) &&
+	rm -f .git/index &&
+	head -n 10 LIST | git update-index --index-info &&
+	LI=$(git write-tree) &&
+	rm -f .git/index &&
+	tail -n 10 LIST | git update-index --index-info &&
+	ST=$(git write-tree) &&
+	PACK5=$( git rev-list --objects "$LIST" "$LI" "$ST" | \
+		git pack-objects test-5 ) &&
+	PACK6=$( (
+			echo "$LIST"
+			echo "$LI"
+			echo "$ST"
+		 ) | git pack-objects test-6 ) &&
+	test_create_repo test-5 &&
+	(
+		cd test-5 &&
+		git unpack-objects --strict <../test-5-$PACK5.pack &&
+		git ls-tree -r $LIST &&
+		git ls-tree -r $LI &&
+		git ls-tree -r $ST
+	) &&
+	test_create_repo test-6 &&
+	(
+		# tree-only into empty repo -- many unreachables
+		cd test-6 &&
+		test_must_fail git unpack-objects --strict <../test-6-$PACK6.pack
+	) &&
+	(
+		# already populated -- no unreachables
+		cd test-5 &&
+		git unpack-objects --strict <../test-6-$PACK6.pack
+	)
+'
+
+test_expect_success 'index-pack with --strict' '
+
+	for j in a b c d e f g
+	do
+		for i in 0 1 2 3 4 5 6 7 8 9
+		do
+			o=$(echo $j$i | git hash-object -w --stdin) &&
+			echo "100644 $o	0 $j$i"
+		done
+	done >LIST &&
+	rm -f .git/index &&
+	git update-index --index-info <LIST &&
+	LIST=$(git write-tree) &&
+	rm -f .git/index &&
+	head -n 10 LIST | git update-index --index-info &&
+	LI=$(git write-tree) &&
+	rm -f .git/index &&
+	tail -n 10 LIST | git update-index --index-info &&
+	ST=$(git write-tree) &&
+	PACK5=$( git rev-list --objects "$LIST" "$LI" "$ST" | \
+		git pack-objects test-5 ) &&
+	PACK6=$( (
+			echo "$LIST"
+			echo "$LI"
+			echo "$ST"
+		 ) | git pack-objects test-6 ) &&
+	test_create_repo test-7 &&
+	(
+		cd test-7 &&
+		git index-pack --strict --stdin <../test-5-$PACK5.pack &&
+		git ls-tree -r $LIST &&
+		git ls-tree -r $LI &&
+		git ls-tree -r $ST
+	) &&
+	test_create_repo test-8 &&
+	(
+		# tree-only into empty repo -- many unreachables
+		cd test-8 &&
+		test_must_fail git index-pack --strict --stdin <../test-6-$PACK6.pack
+	) &&
+	(
+		# already populated -- no unreachables
+		cd test-7 &&
+		git index-pack --strict --stdin <../test-6-$PACK6.pack
+	)
+'
+
 test_done
diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh
index b88b5bb..09fd917 100755
--- a/t/t5302-pack-index.sh
+++ b/t/t5302-pack-index.sh
@@ -65,7 +65,7 @@
 
 have_64bits=
 if msg=$(git verify-pack -v "test-3-${pack3}.pack" 2>&1) ||
-	! echo "$msg" | grep "pack too large .* off_t"
+	! (echo "$msg" | grep "pack too large .* off_t")
 then
 	have_64bits=t
 else
diff --git a/t/t5303-hash-object.sh b/t/t5303-hash-object.sh
deleted file mode 100755
index 543c078..0000000
--- a/t/t5303-hash-object.sh
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/sh
-
-test_description=git-hash-object
-
-. ./test-lib.sh
-
-test_expect_success \
-    'git hash-object -w --stdin saves the object' \
-    'obname=$(echo foo | git hash-object -w --stdin) &&
-    obpath=$(echo $obname | sed -e "s/\(..\)/\1\//") &&
-    test -r .git/objects/"$obpath" &&
-    rm -f .git/objects/"$obpath"'
-    
-test_expect_success \
-    'git hash-object --stdin -w saves the object' \
-    'obname=$(echo foo | git hash-object --stdin -w) &&
-    obpath=$(echo $obname | sed -e "s/\(..\)/\1\//") &&
-    test -r .git/objects/"$obpath" &&
-    rm -f .git/objects/"$obpath"'    
-
-test_expect_success \
-    'git hash-object --stdin file1 <file0 first operates on file0, then file1' \
-    'echo foo > file1 &&
-    obname0=$(echo bar | git hash-object --stdin) &&
-    obname1=$(git hash-object file1) &&
-    obname0new=$(echo bar | git hash-object --stdin file1 | sed -n -e 1p) &&
-    obname1new=$(echo bar | git hash-object --stdin file1 | sed -n -e 2p) &&
-    test "$obname0" = "$obname0new" &&
-    test "$obname1" = "$obname1new"'
-
-test_expect_success \
-    'git hash-object refuses multiple --stdin arguments' \
-    '! git hash-object --stdin --stdin < file1'
-
-test_done
diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh
old mode 100644
new mode 100755
index 9fd9d07..771c0a0
--- a/t/t5304-prune.sh
+++ b/t/t5304-prune.sh
@@ -21,7 +21,7 @@
 	orig_pack=$(echo .git/objects/pack/*.pack) &&
 	: > .git/objects/tmp_1.pack &&
 	: > .git/objects/tmp_2.pack &&
-	test-chmtime -86501 .git/objects/tmp_1.pack &&
+	test-chmtime =-86501 .git/objects/tmp_1.pack &&
 	git prune --expire 1.day &&
 	test -f $orig_pack &&
 	test -f .git/objects/tmp_2.pack &&
@@ -39,7 +39,7 @@
 	git prune --expire=1.hour.ago &&
 	test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
 	test -f $BLOB_FILE &&
-	test-chmtime -86500 $BLOB_FILE &&
+	test-chmtime =-86500 $BLOB_FILE &&
 	git prune --expire 1.day &&
 	test $before = $(git count-objects | sed "s/ .*//") &&
 	! test -f $BLOB_FILE
@@ -53,11 +53,11 @@
 	BLOB_FILE=.git/objects/$(echo $BLOB | sed "s/^../&\//") &&
 	test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
 	test -f $BLOB_FILE &&
-	test-chmtime -$((86400*14-30)) $BLOB_FILE &&
+	test-chmtime =-$((86400*14-30)) $BLOB_FILE &&
 	git gc &&
 	test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
 	test -f $BLOB_FILE &&
-	test-chmtime -$((86400*14+1)) $BLOB_FILE &&
+	test-chmtime =-$((86400*14+1)) $BLOB_FILE &&
 	git gc &&
 	test $before = $(git count-objects | sed "s/ .*//") &&
 	! test -f $BLOB_FILE
diff --git a/t/t5305-include-tag.sh b/t/t5305-include-tag.sh
index 0db2754..fb471a0 100755
--- a/t/t5305-include-tag.sh
+++ b/t/t5305-include-tag.sh
@@ -50,7 +50,7 @@
 		test_must_fail git cat-file -e $tag &&
 		git rev-list --objects $commit
 	) >list.actual &&
-	git diff list.expect list.actual
+	test_cmp list.expect list.actual
 '
 
 rm -rf clone.git
@@ -78,7 +78,7 @@
 		export GIT_DIR &&
 		git rev-list --objects $tag
 	) >list.actual &&
-	git diff list.expect list.actual
+	test_cmp list.expect list.actual
 '
 
 test_done
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index 2b6b6e3..68c2ae6 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -110,7 +110,7 @@
 	cd .. &&
 	git update-ref refs/heads/master master^ || return 1
 	git-send-pack --force ./victim/.git/ master && return 1
-	! git diff .git/refs/heads/master victim/.git/refs/heads/master
+	! test_cmp .git/refs/heads/master victim/.git/refs/heads/master
 '
 
 test_expect_success \
diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh
index 9a12024..2fff300 100755
--- a/t/t5401-update-hooks.sh
+++ b/t/t5401-update-hooks.sh
@@ -83,23 +83,23 @@
 test_expect_success 'pre-receive hook input' '
 	(echo $commit0 $commit1 refs/heads/master;
 	 echo $commit1 $commit0 refs/heads/tofail
-	) | git diff - victim/.git/pre-receive.stdin
+	) | test_cmp - victim/.git/pre-receive.stdin
 '
 
 test_expect_success 'update hook arguments' '
 	(echo refs/heads/master $commit0 $commit1;
 	 echo refs/heads/tofail $commit1 $commit0
-	) | git diff - victim/.git/update.args
+	) | test_cmp - victim/.git/update.args
 '
 
 test_expect_success 'post-receive hook input' '
 	echo $commit0 $commit1 refs/heads/master |
-	git diff - victim/.git/post-receive.stdin
+	test_cmp - victim/.git/post-receive.stdin
 '
 
 test_expect_success 'post-update hook arguments' '
 	echo refs/heads/master |
-	git diff - victim/.git/post-update.args
+	test_cmp - victim/.git/post-update.args
 '
 
 test_expect_success 'all hook stdin is /dev/null' '
@@ -130,7 +130,7 @@
 EOF
 test_expect_success 'send-pack stderr contains hook messages' '
 	grep ^STD send.err >actual &&
-	git diff - actual <expect
+	test_cmp - actual <expect
 '
 
 test_done
diff --git a/t/t5404-tracking-branches.sh b/t/t5404-tracking-branches.sh
index 1493a92..64fe261 100755
--- a/t/t5404-tracking-branches.sh
+++ b/t/t5404-tracking-branches.sh
@@ -10,6 +10,7 @@
 	git commit -m 1 &&
 	git branch b1 &&
 	git branch b2 &&
+	git branch b3 &&
 	git clone . aa &&
 	git checkout b1 &&
 	echo b1 >>file &&
@@ -50,4 +51,10 @@
 	test "$(git rev-parse origin/b1)" = "origin/b1"
 '
 
+test_expect_success 'already deleted tracking branches ignored' '
+	git branch -d -r origin/b3 &&
+	git push origin :b3 >output 2>&1 &&
+	! grep error output
+'
+
 test_done
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 788b4a5..140e874 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -31,7 +31,7 @@
 	sec=$(($sec+1))
 	commit=$(echo "$text" | GIT_AUTHOR_DATE=$sec \
 		git commit-tree $tree $parents 2>>log2.txt)
-	export $name=$commit
+	eval "$name=$commit; export $name"
 	echo $commit > .git/refs/heads/$branch
 	eval ${branch}TIP=$commit
 }
@@ -129,7 +129,7 @@
 
 pull_to_client 3rd "A" $((1*3)) # old fails
 
-test_expect_success "clone shallow" "git-clone --depth 2 file://`pwd`/. shallow"
+test_expect_success "clone shallow" 'git-clone --depth 2 "file://$(pwd)/." shallow'
 
 (cd shallow; git count-objects -v) > count.shallow
 
diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh
index 86e5b9b..4074e23 100755
--- a/t/t5503-tagfollow.sh
+++ b/t/t5503-tagfollow.sh
@@ -50,7 +50,7 @@
 	) &&
 	test -s $U &&
 	cut -d" " -f1,2 $U >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 test_expect_success "create tag T on A, create C on branch cat" '
@@ -82,7 +82,7 @@
 	) &&
 	test -s $U &&
 	cut -d" " -f1,2 $U >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 test_expect_success "create commits O, B, tag S on B" '
@@ -118,7 +118,7 @@
 	) &&
 	test -s $U &&
 	cut -d" " -f1,2 $U >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 cat - <<EOF >expect
@@ -144,7 +144,7 @@
 	) &&
 	test -s $U &&
 	cut -d" " -f1,2 $U >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 test_done
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 48ff2d4..1e192a2 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -135,7 +135,26 @@
 	 git config --add remote.origin.push \
 		+refs/tags/lastbackup &&
 	 git remote show origin > output &&
-	 git diff expect output)
+	 test_cmp expect output)
+'
+
+cat > test/expect << EOF
+* remote origin
+  URL: $(pwd)/one/.git
+  Remote branch merged with 'git pull' while on branch master
+    master
+  Tracked remote branches
+    master side
+  Local branches pushed with 'git push'
+    master:upstream +refs/tags/lastbackup
+EOF
+
+test_expect_success 'show -n' '
+	(mv one one.unreachable &&
+	 cd test &&
+	 git remote show -n origin > output &&
+	 mv ../one.unreachable ../one &&
+	 test_cmp expect output)
 '
 
 test_expect_success 'prune' '
@@ -148,6 +167,24 @@
 	 ! git rev-parse refs/remotes/origin/side)
 '
 
+cat > test/expect << EOF
+Pruning origin
+URL: $(pwd)/one/.git
+ * [would prune] origin/side2
+EOF
+
+test_expect_success 'prune --dry-run' '
+	(cd one &&
+	 git branch -m side2 side) &&
+	(cd test &&
+	 git remote prune --dry-run origin > output &&
+	 git rev-parse refs/remotes/origin/side2 &&
+	 ! git rev-parse refs/remotes/origin/side &&
+	(cd ../one &&
+	 git branch -m side side2) &&
+	 test_cmp expect output)
+'
+
 test_expect_success 'add --mirror && prune' '
 	(mkdir mirror &&
 	 cd mirror &&
@@ -164,6 +201,24 @@
 	 git rev-parse --verify refs/heads/side)
 '
 
+test_expect_success 'add alt && prune' '
+	(mkdir alttst &&
+	 cd alttst &&
+	 git init &&
+	 git remote add -f origin ../one &&
+	 git config remote.alt.url ../one &&
+	 git config remote.alt.fetch "+refs/heads/*:refs/remotes/origin/*") &&
+	(cd one &&
+	 git branch -m side side2) &&
+	(cd alttst &&
+	 git rev-parse --verify refs/remotes/origin/side &&
+	 ! git rev-parse --verify refs/remotes/origin/side2 &&
+	 git fetch alt &&
+	 git remote prune alt &&
+	 ! git rev-parse --verify refs/remotes/origin/side &&
+	 git rev-parse --verify refs/remotes/origin/side2)
+'
+
 cat > one/expect << EOF
   apis/master
   apis/side
@@ -179,7 +234,7 @@
 	 git remote add apis ../mirror &&
 	 git remote update &&
 	 git branch -r > output &&
-	 git diff expect output)
+	 test_cmp expect output)
 
 '
 
@@ -206,7 +261,7 @@
 	 git config remotes.titanus manduca &&
 	 git remote update phobaeticus titanus &&
 	 git branch -r > output &&
-	 git diff expect output)
+	 test_cmp expect output)
 
 '
 
@@ -229,7 +284,7 @@
 	 git config remote.drosophila.skipDefaultUpdate true &&
 	 git remote update default &&
 	 git branch -r > output &&
-	 git diff expect output)
+	 test_cmp expect output)
 
 '
 
@@ -249,7 +304,7 @@
 	 git config remotes.default "$(printf "\t drosophila  \n")" &&
 	 git remote update default &&
 	 git branch -r > output &&
-	 git diff expect output)
+	 test_cmp expect output)
 
 '
 
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 6946557..df7750f 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -37,7 +37,8 @@
 		echo "Pull: refs/heads/one:refs/heads/one"
 	} >.git/remotes/two &&
 	cd .. &&
-	git clone . bundle
+	git clone . bundle &&
+	git clone . seven
 '
 
 test_expect_success "fetch test" '
@@ -295,4 +296,11 @@
 	)
 '
 
+test_expect_success 'pushing nonexistent branch by mistake should not segv' '
+
+	cd "$D" &&
+	test_must_fail git push seven no:no
+
+'
+
 test_done
diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh
index 670a8f1..22ba380 100755
--- a/t/t5511-refspec.sh
+++ b/t/t5511-refspec.sh
@@ -23,10 +23,13 @@
 }
 
 test_refspec push ''						invalid
-test_refspec push ':'						invalid
+test_refspec push ':'
+test_refspec push '::'						invalid
+test_refspec push '+:'
 
 test_refspec fetch ''
 test_refspec fetch ':'
+test_refspec fetch '::'						invalid
 
 test_refspec push 'refs/heads/*:refs/remotes/frotz/*'
 test_refspec push 'refs/heads/*:refs/remotes/frotz'		invalid
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index c0dc949..1dd8eed 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -17,7 +17,7 @@
 		git show-ref -d	| sed -e "s/ /	/"
 	) >expected.all &&
 
-	git remote add self $(pwd)/.git
+	git remote add self "$(pwd)/.git"
 
 '
 
diff --git a/t/t5513-fetch-track.sh b/t/t5513-fetch-track.sh
new file mode 100755
index 0000000..9e74862
--- /dev/null
+++ b/t/t5513-fetch-track.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+test_description='fetch follows remote tracking branches correctly'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+	>file &&
+	git add . &&
+	test_tick &&
+	git commit -m Initial &&
+	git branch b-0 &&
+	git branch b1 &&
+	git branch b/one &&
+	test_create_repo other &&
+	(
+		cd other &&
+		git config remote.origin.url .. &&
+		git config remote.origin.fetch "+refs/heads/b/*:refs/remotes/b/*"
+	)
+'
+
+test_expect_success fetch '
+	(
+		cd other && git fetch origin &&
+		test "$(git for-each-ref --format="%(refname)")" = refs/remotes/b/one
+	)
+'
+
+test_done
diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh
index 65c3774..3def75e 100755
--- a/t/t5515-fetch-merge-logic.sh
+++ b/t/t5515-fetch-merge-logic.sh
@@ -151,7 +151,7 @@
 		git show-ref >"$actual_r" &&
 		if test -f "$expect_f"
 		then
-			git diff -u "$expect_f" "$actual_f" &&
+			test_cmp "$expect_f" "$actual_f" &&
 			rm -f "$actual_f"
 		else
 			# this is to help developing new tests.
@@ -160,7 +160,7 @@
 		fi &&
 		if test -f "$expect_r"
 		then
-			git diff -u "$expect_r" "$actual_r" &&
+			test_cmp "$expect_r" "$actual_r" &&
 			rm -f "$actual_r"
 		else
 			# this is to help developing new tests.
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 0a757d5..6805032 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -105,7 +105,7 @@
 	(
 		TRASH=$(pwd)/ &&
 		cd testrepo &&
-		git config url.$TRASH.insteadOf trash/
+		git config "url.$TRASH.insteadOf" trash/ &&
 		git config remote.up.url trash/. &&
 		git config remote.up.fetch "refs/heads/*:refs/remotes/origin/*" &&
 		git fetch up &&
@@ -145,8 +145,8 @@
 
 test_expect_success 'push with insteadOf' '
 	mk_empty &&
-	TRASH=$(pwd)/ &&
-	git config url.$TRASH.insteadOf trash/ &&
+	TRASH="$(pwd)/" &&
+	git config "url.$TRASH.insteadOf" trash/ &&
 	git push trash/testrepo refs/heads/master:refs/remotes/origin/master &&
 	(
 		cd testrepo &&
@@ -165,6 +165,47 @@
 
 '
 
+test_expect_success 'push with matching heads on the command line' '
+
+	mk_test heads/master &&
+	git push testrepo : &&
+	check_push_result $the_commit heads/master
+
+'
+
+test_expect_success 'failed (non-fast-forward) push with matching heads' '
+
+	mk_test heads/master &&
+	git push testrepo : &&
+	git commit --amend -massaged &&
+	! git push testrepo &&
+	check_push_result $the_commit heads/master &&
+	git reset --hard $the_commit
+
+'
+
+test_expect_success 'push --force with matching heads' '
+
+	mk_test heads/master &&
+	git push testrepo : &&
+	git commit --amend -massaged &&
+	git push --force testrepo &&
+	! check_push_result $the_commit heads/master &&
+	git reset --hard $the_commit
+
+'
+
+test_expect_success 'push with matching heads and forced update' '
+
+	mk_test heads/master &&
+	git push testrepo : &&
+	git commit --amend -massaged &&
+	git push testrepo +: &&
+	! check_push_result $the_commit heads/master &&
+	git reset --hard $the_commit
+
+'
+
 test_expect_success 'push with no ambiguity (1)' '
 
 	mk_test heads/master &&
diff --git a/t/t5517-push-mirror.sh b/t/t5517-push-mirror.sh
index ed3fec1..ea49ded 100755
--- a/t/t5517-push-mirror.sh
+++ b/t/t5517-push-mirror.sh
@@ -25,7 +25,7 @@
 	(
 		cd master &&
 		git init &&
-		git config remote.up.url ../mirror
+		git remote add $1 up ../mirror
 	)
 }
 
@@ -225,4 +225,43 @@
 
 '
 
+test_expect_success 'remote.foo.mirror adds and removes branches' '
+
+	mk_repo_pair --mirror &&
+	(
+		cd master &&
+		echo one >foo && git add foo && git commit -m one &&
+		git branch keep master &&
+		git branch remove master &&
+		git push up &&
+		git branch -D remove
+		git push up
+	) &&
+	(
+		cd mirror &&
+		git show-ref -s --verify refs/heads/keep &&
+		invert git show-ref -s --verify refs/heads/remove
+	)
+
+'
+
+test_expect_success 'remote.foo.mirror=no has no effect' '
+
+	mk_repo_pair &&
+	(
+		cd master &&
+		echo one >foo && git add foo && git commit -m one &&
+		git config --add remote.up.mirror no &&
+		git branch keep master &&
+		git push --mirror up &&
+		git branch -D keep &&
+		git push up
+	) &&
+	(
+		cd mirror &&
+		git show-ref -s --verify refs/heads/keep
+	)
+
+'
+
 test_done
diff --git a/t/t5518-fetch-exit-status.sh b/t/t5518-fetch-exit-status.sh
new file mode 100755
index 0000000..c6bc65f
--- /dev/null
+++ b/t/t5518-fetch-exit-status.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Dmitry V. Levin
+#
+
+test_description='fetch exit status test'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+	>file &&
+	git add file &&
+	git commit -m initial &&
+
+	git checkout -b side &&
+	echo side >file &&
+	git commit -a -m side &&
+
+	git checkout master &&
+	echo next >file &&
+	git commit -a -m next
+'
+
+test_expect_success 'non fast forward fetch' '
+
+	test_must_fail git fetch . master:side
+
+'
+
+test_expect_success 'forced update' '
+
+	git fetch . +master:side
+
+'
+
+test_done
diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh
index 9484129..997b2db 100755
--- a/t/t5520-pull.sh
+++ b/t/t5520-pull.sh
@@ -92,4 +92,22 @@
 
 '
 
+test_expect_success 'pull --rebase dies early with dirty working directory' '
+
+	git update-ref refs/remotes/me/copy copy^ &&
+	COPY=$(git rev-parse --verify me/copy) &&
+	git rebase --onto $COPY copy &&
+	git config branch.to-rebase.remote me &&
+	git config branch.to-rebase.merge refs/heads/copy &&
+	git config branch.to-rebase.rebase true &&
+	echo dirty >> file &&
+	git add file &&
+	test_must_fail git pull &&
+	test $COPY = $(git rev-parse --verify me/copy) &&
+	git checkout HEAD -- file &&
+	git pull &&
+	test $COPY != $(git rev-parse --verify me/copy)
+
+'
+
 test_done
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index dc9d63d..d785b3d 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -17,10 +17,57 @@
 
 '
 
-test_expect_success 'clone with excess parameters' '
+test_expect_success 'clone with excess parameters (1)' '
 
+	rm -fr dst &&
+	test_must_fail git clone -n src dst junk
+
+'
+
+test_expect_success 'clone with excess parameters (2)' '
+
+	rm -fr dst &&
 	test_must_fail git clone -n "file://$(pwd)/src" dst junk
 
 '
 
+test_expect_success 'clone does not keep pack' '
+
+	rm -fr dst &&
+	git clone -n "file://$(pwd)/src" dst &&
+	! test -f dst/file &&
+	! (echo dst/.git/objects/pack/pack-* | grep "\.keep")
+
+'
+
+test_expect_success 'clone checks out files' '
+
+	rm -fr dst &&
+	git clone src dst &&
+	test -f dst/file
+
+'
+
+test_expect_success 'clone respects GIT_WORK_TREE' '
+
+	GIT_WORK_TREE=worktree git clone src bare &&
+	test -f bare/config &&
+	test -f worktree/file
+
+'
+
+test_expect_success 'clone creates intermediate directories' '
+
+	git clone src long/path/to/dst &&
+	test -f long/path/to/dst/file
+
+'
+
+test_expect_success 'clone creates intermediate directories for bare repo' '
+
+	git clone --bare src long/path/to/bare/dst &&
+	test -f long/path/to/bare/dst/config
+
+'
+
 test_done
diff --git a/t/t5602-clone-remote-exec.sh b/t/t5602-clone-remote-exec.sh
new file mode 100755
index 0000000..8367a68
--- /dev/null
+++ b/t/t5602-clone-remote-exec.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+test_description=clone
+
+. ./test-lib.sh
+
+test_expect_success setup '
+	echo "#!/bin/sh" > not_ssh
+	echo "echo \"\$*\" > not_ssh_output" >> not_ssh
+	echo "exit 1" >> not_ssh
+	chmod +x not_ssh
+'
+
+test_expect_success 'clone calls git-upload-pack unqualified with no -u option' '
+	GIT_SSH=./not_ssh git clone localhost:/path/to/repo junk
+	echo "localhost git-upload-pack '\''/path/to/repo'\''" >expected
+	test_cmp expected not_ssh_output
+'
+
+test_expect_success 'clone calls specified git-upload-pack with -u option' '
+	GIT_SSH=./not_ssh git clone -u /something/bin/git-upload-pack localhost:/path/to/repo junk
+	echo "localhost /something/bin/git-upload-pack '\''/path/to/repo'\''" >expected
+	test_cmp expected not_ssh_output
+'
+
+test_done
diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh
index b6a5486..1c10916 100755
--- a/t/t5700-clone-reference.sh
+++ b/t/t5700-clone-reference.sh
@@ -8,6 +8,8 @@
 
 base_dir=`pwd`
 
+U=$base_dir/UPLOAD_LOG
+
 test_expect_success 'preparing first repository' \
 'test_create_repo A && cd A &&
 echo first > file1 &&
@@ -50,8 +52,13 @@
 
 cd "$base_dir"
 
+rm -f "$U"
+
 test_expect_success 'cloning with reference (no -l -s)' \
-'git clone --reference B file://`pwd`/A D'
+'GIT_DEBUG_SEND_PACK=3 git clone --reference B "file://$(pwd)/A" D 3>"$U"'
+
+test_expect_success 'fetched no objects' \
+'! grep "^want" "$U"'
 
 cd "$base_dir"
 
@@ -113,4 +120,30 @@
 
 cd "$base_dir"
 
+test_expect_success 'preparing alternate repository #1' \
+'test_create_repo F && cd F &&
+echo first > file1 &&
+git add file1 &&
+git commit -m initial'
+
+cd "$base_dir"
+
+test_expect_success 'cloning alternate repo #2 and adding changes to repo #1' \
+'git clone F G && cd F &&
+echo second > file2 &&
+git add file2 &&
+git commit -m addition'
+
+cd "$base_dir"
+
+test_expect_success 'cloning alternate repo #1, using #2 as reference' \
+'git clone --reference G F H'
+
+cd "$base_dir"
+
+test_expect_success 'cloning with reference being subset of source (-l -s)' \
+'git clone -l -s --reference A B E'
+
+cd "$base_dir"
+
 test_done
diff --git a/t/t5710-info-alternate.sh b/t/t5710-info-alternate.sh
index 910ccb4..ef7127c 100755
--- a/t/t5710-info-alternate.sh
+++ b/t/t5710-info-alternate.sh
@@ -81,9 +81,9 @@
 cd "$base_dir"
 
 test_expect_success 'breaking of loops' \
-"echo '$base_dir/B/.git/objects' >> '$base_dir'/A/.git/objects/info/alternates&&
+'echo "$base_dir"/B/.git/objects >> "$base_dir"/A/.git/objects/info/alternates&&
 cd C &&
-test_valid_repo"
+test_valid_repo'
 
 cd "$base_dir"
 
diff --git a/t/t6000lib.sh b/t/t6000lib.sh
index c0baaa5..f55627b 100755
--- a/t/t6000lib.sh
+++ b/t/t6000lib.sh
@@ -49,13 +49,15 @@
 	shift 1
         _save=$GIT_AUTHOR_EMAIL
 
-	export GIT_AUTHOR_EMAIL="$_author"
+	GIT_AUTHOR_EMAIL="$_author"
+	export GIT_AUTHOR_EMAIL
 	"$@"
 	if test -z "$_save"
 	then
 		unset GIT_AUTHOR_EMAIL
 	else
-		export GIT_AUTHOR_EMAIL="$_save"
+		GIT_AUTHOR_EMAIL="$_save"
+		export GIT_AUTHOR_EMAIL
 	fi
 }
 
@@ -69,7 +71,8 @@
 {
     _date=$1
     shift 1
-    export GIT_COMMITTER_DATE="$_date"
+    GIT_COMMITTER_DATE="$_date"
+    export GIT_COMMITTER_DATE
     "$@"
     unset GIT_COMMITTER_DATE
 }
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index 0dc915e..9176484 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -15,7 +15,7 @@
 	cat >expect.$1
 	test_expect_success "format $1" "
 git rev-list --pretty=format:$2 master >output.$1 &&
-git diff expect.$1 output.$1
+test_cmp expect.$1 output.$1
 "
 }
 
diff --git a/t/t6010-merge-base.sh b/t/t6010-merge-base.sh
index 96f3d35..b6e57b2 100755
--- a/t/t6010-merge-base.sh
+++ b/t/t6010-merge-base.sh
@@ -13,10 +13,11 @@
 M=1130000000
 Z=+0000
 
-export GIT_COMMITTER_EMAIL=git@comm.iter.xz
-export GIT_COMMITTER_NAME='C O Mmiter'
-export GIT_AUTHOR_NAME='A U Thor'
-export GIT_AUTHOR_EMAIL=git@au.thor.xz
+GIT_COMMITTER_EMAIL=git@comm.iter.xz
+GIT_COMMITTER_NAME='C O Mmiter'
+GIT_AUTHOR_NAME='A U Thor'
+GIT_AUTHOR_EMAIL=git@au.thor.xz
+export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
 
 doit() {
 	OFFSET=$1; shift
diff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh
index 79dc58b..74e9e66 100755
--- a/t/t6023-merge-file.sh
+++ b/t/t6023-merge-file.sh
@@ -63,7 +63,7 @@
 	"git merge-file test2.txt orig.txt new2.txt"
 
 test_expect_success "merge result added missing LF" \
-	"git diff test.txt test2.txt"
+	"test_cmp test.txt test2.txt"
 
 cp test.txt backup.txt
 test_expect_success "merge with conflicts" \
@@ -86,7 +86,7 @@
 virga tua et baculus tuus ipsa me consolata sunt.
 EOF
 
-test_expect_success "expected conflict markers" "git diff test.txt expect.txt"
+test_expect_success "expected conflict markers" "test_cmp test.txt expect.txt"
 
 cp backup.txt test.txt
 test_expect_success "merge with conflicts, using -L" \
@@ -110,7 +110,7 @@
 EOF
 
 test_expect_success "expected conflict markers, with -L" \
-	"git diff test.txt expect.txt"
+	"test_cmp test.txt expect.txt"
 
 sed "s/ tu / TU /" < new1.txt > new5.txt
 test_expect_success "conflict in removed tail" \
@@ -132,7 +132,7 @@
 >>>>>>> new5.txt
 EOF
 
-test_expect_success "expected conflict markers" "git diff expect out"
+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 &&
diff --git a/t/t6024-recursive-merge.sh b/t/t6024-recursive-merge.sh
index 23d24d3..6a6a130 100755
--- a/t/t6024-recursive-merge.sh
+++ b/t/t6024-recursive-merge.sh
@@ -70,7 +70,7 @@
 >>>>>>> G:a1
 EOF
 
-test_expect_success "result contains a conflict" "git diff expect a1"
+test_expect_success "result contains a conflict" "test_cmp expect a1"
 
 git ls-files --stage > out
 cat > expect << EOF
@@ -79,7 +79,7 @@
 100644 fd7923529855d0b274795ae3349c5e0438333979 3	a1
 EOF
 
-test_expect_success "virtual trees were processed" "git diff expect out"
+test_expect_success "virtual trees were processed" "test_cmp expect out"
 
 test_expect_success 'refuse to merge binary files' '
 	git reset --hard &&
diff --git a/t/t6029-merge-subtree.sh b/t/t6029-merge-subtree.sh
index 43f5459..5bbfa44 100755
--- a/t/t6029-merge-subtree.sh
+++ b/t/t6029-merge-subtree.sh
@@ -57,7 +57,7 @@
 		echo "100644 $o1 0	git-gui/git-gui.sh"
 		echo "100644 $o2 0	git.c"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 '
 
 test_expect_success 'merge update' '
@@ -73,7 +73,7 @@
 		echo "100644 $o3 0	git-gui/git-gui.sh"
 		echo "100644 $o2 0	git.c"
 	) >expected &&
-	git diff -u expected actual
+	test_cmp expected actual
 '
 
 test_done
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 933f567..0626544 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -126,6 +126,47 @@
 	test -z "$(git for-each-ref "refs/heads/bisect")"
 '
 
+test_expect_success 'bisect start: back in good branch' '
+	git branch > branch.output &&
+	grep "* other" branch.output > /dev/null &&
+	git bisect start $HASH4 $HASH1 -- &&
+	git bisect good &&
+	git bisect start $HASH4 $HASH1 -- &&
+	git bisect bad &&
+	git bisect reset &&
+	git branch > branch.output &&
+	grep "* other" branch.output > /dev/null
+'
+
+test_expect_success 'bisect start: no ".git/BISECT_START" if junk rev' '
+	git bisect start $HASH4 $HASH1 -- &&
+	git bisect good &&
+	test_must_fail git bisect start $HASH4 foo -- &&
+	git branch > branch.output &&
+	grep "* other" branch.output > /dev/null &&
+	test_must_fail test -e .git/BISECT_START
+'
+
+test_expect_success 'bisect start: no ".git/BISECT_START" if mistaken rev' '
+	git bisect start $HASH4 $HASH1 -- &&
+	git bisect good &&
+	test_must_fail git bisect start $HASH1 $HASH4 -- &&
+	git branch > branch.output &&
+	grep "* other" branch.output > /dev/null &&
+	test_must_fail test -e .git/BISECT_START
+'
+
+test_expect_success 'bisect start: no ".git/BISECT_START" if checkout error' '
+	echo "temp stuff" > hello &&
+	test_must_fail git bisect start $HASH4 $HASH1 -- &&
+	git branch &&
+	git branch > branch.output &&
+	grep "* other" branch.output > /dev/null &&
+	test_must_fail test -e .git/BISECT_START &&
+	test -z "$(git for-each-ref "refs/bisect/*")" &&
+	git checkout HEAD hello
+'
+
 # $HASH1 is good, $HASH4 is bad, we skip $HASH3
 # but $HASH2 is bad,
 # so we should find $HASH2 as the first bad commit
@@ -281,25 +322,6 @@
 	test $HEAD = $(cat .git/BISECT_START) &&
 	git bisect reset &&
 	test $HEAD = $(git rev-parse --verify HEAD)
-
-'
-
-test_expect_success 'bisect refuses to start if branch bisect exists' '
-	git bisect reset &&
-	git branch bisect &&
-	test_must_fail git bisect start &&
-	git branch -d bisect &&
-	git checkout -b bisect &&
-	test_must_fail git bisect start &&
-	git checkout master &&
-	git branch -d bisect
-'
-
-test_expect_success 'bisect refuses to start if branch new-bisect exists' '
-	git bisect reset &&
-	git branch new-bisect &&
-	test_must_fail git bisect start &&
-	git branch -d new-bisect
 '
 
 test_expect_success 'bisect errors out if bad and good are mistaken' '
@@ -309,6 +331,25 @@
 	git bisect reset
 '
 
+test_expect_success 'bisect does not create a "bisect" branch' '
+	git bisect reset &&
+	git bisect start $HASH7 $HASH1 &&
+	git branch bisect &&
+	rev_hash4=$(git rev-parse --verify HEAD) &&
+	test "$rev_hash4" = "$HASH4" &&
+	git branch -D bisect &&
+	git bisect good &&
+	git branch bisect &&
+	rev_hash6=$(git rev-parse --verify HEAD) &&
+	test "$rev_hash6" = "$HASH6" &&
+	git bisect good > my_bisect_log.txt &&
+	grep "$HASH7 is first bad commit" my_bisect_log.txt &&
+	git bisect reset &&
+	rev_hash6=$(git rev-parse --verify bisect) &&
+	test "$rev_hash6" = "$HASH6" &&
+	git branch -D bisect
+'
+
 #
 #
 test_done
diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh
index c8310ae..8073e0c 100755
--- a/t/t6031-merge-recursive.sh
+++ b/t/t6031-merge-recursive.sh
@@ -3,6 +3,9 @@
 test_description='merge-recursive: handle file mode'
 . ./test-lib.sh
 
+# Note that we follow "chmod +x F" with "update-index --chmod=+x F" to
+# help filesystems that do not have the executable bit.
+
 test_expect_success 'mode change in one branch: keep changed version' '
 	: >file1 &&
 	git add file1 &&
@@ -13,7 +16,7 @@
 	git commit -m a &&
 	git checkout -b b1 master &&
 	chmod +x file1 &&
-	git add file1 &&
+	git update-index --chmod=+x file1 &&
 	git commit -m b1 &&
 	git checkout a1 &&
 	git merge-recursive master -- a1 b1 &&
@@ -26,7 +29,7 @@
 	: >file2 &&
 	H=$(git hash-object file2) &&
 	chmod +x file2 &&
-	git add file2 &&
+	git update-index --add --chmod=+x file2 &&
 	git commit -m a2 &&
 	git checkout -b b2 master &&
 	: >file2 &&
diff --git a/t/t6032-merge-large-rename.sh b/t/t6032-merge-large-rename.sh
new file mode 100755
index 0000000..eac5eba
--- /dev/null
+++ b/t/t6032-merge-large-rename.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+test_description='merging with large rename matrix'
+. ./test-lib.sh
+
+count() {
+	i=1
+	while test $i -le $1; do
+		echo $i
+		i=$(($i + 1))
+	done
+}
+
+test_expect_success 'setup (initial)' '
+	touch file &&
+	git add . &&
+	git commit -m initial &&
+	git tag initial
+'
+
+make_text() {
+	echo $1: $2
+	for i in `count 20`; do
+		echo $1: $i
+	done
+	echo $1: $3
+}
+
+test_rename() {
+	test_expect_success "rename ($1, $2)" '
+	n='$1'
+	expect='$2'
+	git checkout -f master &&
+	git branch -D test$n || true &&
+	git reset --hard initial &&
+	for i in $(count $n); do
+		make_text $i initial initial >$i
+	done &&
+	git add . &&
+	git commit -m add=$n &&
+	for i in $(count $n); do
+		make_text $i changed initial >$i
+	done &&
+	git commit -a -m change=$n &&
+	git checkout -b test$n HEAD^ &&
+	for i in $(count $n); do
+		git rm $i
+		make_text $i initial changed >$i.moved
+	done &&
+	git add . &&
+	git commit -m change+rename=$n &&
+	case "$expect" in
+		ok) git merge master ;;
+		 *) test_must_fail git merge master ;;
+	esac
+	'
+}
+
+test_rename 5 ok
+
+test_expect_success 'set diff.renamelimit to 4' '
+	git config diff.renamelimit 4
+'
+test_rename 4 ok
+test_rename 5 fail
+
+test_expect_success 'set merge.renamelimit to 5' '
+	git config merge.renamelimit 5
+'
+test_rename 5 ok
+test_rename 6 fail
+
+test_done
diff --git a/t/t6033-merge-crlf.sh b/t/t6033-merge-crlf.sh
new file mode 100755
index 0000000..75d9602
--- /dev/null
+++ b/t/t6033-merge-crlf.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+append_cr () {
+	sed -e 's/$/Q/' | tr Q '\015'
+}
+
+remove_cr () {
+	tr '\015' Q | sed -e 's/Q$//'
+}
+
+test_description='merge conflict in crlf repo
+
+		b---M
+	       /   /
+	initial---a
+
+'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+	git config core.autocrlf true &&
+	echo foo | append_cr >file &&
+	git add file &&
+	git commit -m "Initial" &&
+	git tag initial &&
+	git branch side &&
+	echo line from a | append_cr >file &&
+	git commit -m "add line from a" file &&
+	git tag a &&
+	git checkout side &&
+	echo line from b | append_cr >file &&
+	git commit -m "add line from b" file &&
+	git tag b &&
+	git checkout master
+'
+
+test_expect_success 'Check "ours" is CRLF' '
+	git reset --hard initial &&
+	git merge side -s ours &&
+	cat file | remove_cr | append_cr >file.temp &&
+	test_cmp file file.temp
+'
+
+test_expect_success 'Check that conflict file is CRLF' '
+	git reset --hard a &&
+	test_must_fail git merge side &&
+	cat file | remove_cr | append_cr >file.temp &&
+	test_cmp file file.temp
+'
+
+test_done
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index c6bfef5..2fb672c 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -108,7 +108,7 @@
 EOF
 check_describe A-* HEAD
 test_expect_success 'warning was displayed for Q' '
-	git diff err.expect err.actual
+	test_cmp err.expect err.actual
 '
 test_expect_success 'rename tag Q back to A' '
 	mv .git/refs/tags/Q .git/refs/tags/A
@@ -139,4 +139,6 @@
 
 check_describe "test2-lightweight-*" --tags --match="test2-*"
 
+check_describe "test2-lightweight-*" --long --tags --match="test2-*" HEAD^
+
 test_done
diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh
index 526d7d1..bc74349 100755
--- a/t/t6200-fmt-merge-msg.sh
+++ b/t/t6200-fmt-merge-msg.sh
@@ -79,20 +79,20 @@
 	git fetch . left &&
 
 	git fmt-merge-msg <.git/FETCH_HEAD >actual &&
-	git diff actual expected
+	test_cmp expected actual
 '
 
-cat >expected <<\EOF
-Merge branch 'left' of ../trash
+cat >expected <<EOF
+Merge branch 'left' of ../$test
 EOF
 
 test_expect_success 'merge-msg test #2' '
 
 	git checkout master &&
-	git fetch ../trash left &&
+	git fetch ../"$test" left &&
 
 	git fmt-merge-msg <.git/FETCH_HEAD >actual &&
-	git diff actual expected
+	test_cmp expected actual
 '
 
 cat >expected <<\EOF
@@ -106,8 +106,24 @@
   Common #1
 EOF
 
-test_expect_success 'merge-msg test #3' '
+test_expect_success 'merge-msg test #3-1' '
 
+	git config --unset-all merge.log
+	git config --unset-all merge.summary
+	git config merge.log true &&
+
+	git checkout master &&
+	setdate &&
+	git fetch . left &&
+
+	git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'merge-msg test #3-2' '
+
+	git config --unset-all merge.log
+	git config --unset-all merge.summary
 	git config merge.summary true &&
 
 	git checkout master &&
@@ -115,7 +131,7 @@
 	git fetch . left &&
 
 	git fmt-merge-msg <.git/FETCH_HEAD >actual &&
-	git diff actual expected
+	test_cmp expected actual
 '
 
 cat >expected <<\EOF
@@ -136,8 +152,24 @@
   Common #1
 EOF
 
-test_expect_success 'merge-msg test #4' '
+test_expect_success 'merge-msg test #4-1' '
 
+	git config --unset-all merge.log
+	git config --unset-all merge.summary
+	git config merge.log true &&
+
+	git checkout master &&
+	setdate &&
+	git fetch . left right &&
+
+	git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'merge-msg test #4-2' '
+
+	git config --unset-all merge.log
+	git config --unset-all merge.summary
 	git config merge.summary true &&
 
 	git checkout master &&
@@ -145,11 +177,27 @@
 	git fetch . left right &&
 
 	git fmt-merge-msg <.git/FETCH_HEAD >actual &&
-	git diff actual expected
+	test_cmp expected actual
 '
 
-test_expect_success 'merge-msg test #5' '
+test_expect_success 'merge-msg test #5-1' '
 
+	git config --unset-all merge.log
+	git config --unset-all merge.summary
+	git config merge.log yes &&
+
+	git checkout master &&
+	setdate &&
+	git fetch . left right &&
+
+	git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'merge-msg test #5-2' '
+
+	git config --unset-all merge.log
+	git config --unset-all merge.summary
 	git config merge.summary yes &&
 
 	git checkout master &&
@@ -157,7 +205,7 @@
 	git fetch . left right &&
 
 	git fmt-merge-msg <.git/FETCH_HEAD >actual &&
-	git diff actual expected
+	test_cmp expected actual
 '
 
 test_done
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index f46ec93..91ea85d 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -75,14 +75,14 @@
 test_expect_success 'Check unformatted date fields output' '
 	(git for-each-ref --shell --format="%(refname) %(committerdate) %(authordate)" refs/heads &&
 	git for-each-ref --shell --format="%(refname) %(taggerdate)" refs/tags) >actual &&
-	git diff expected actual
+	test_cmp expected actual
 '
 
 test_expect_success 'Check format "default" formatted date fields output' '
 	f=default &&
 	(git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
 	git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual &&
-	git diff expected actual
+	test_cmp expected actual
 '
 
 # Don't know how to do relative check because I can't know when this script
@@ -109,7 +109,7 @@
 	f=short &&
 	(git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
 	git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual &&
-	git diff expected actual
+	test_cmp expected actual
 '
 
 cat >expected <<\EOF
@@ -121,7 +121,7 @@
 	f=local &&
 	(git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
 	git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual &&
-	git diff expected actual
+	test_cmp expected actual
 '
 
 cat >expected <<\EOF
@@ -133,7 +133,7 @@
 	f=iso8601 &&
 	(git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
 	git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual &&
-	git diff expected actual
+	test_cmp expected actual
 '
 
 cat >expected <<\EOF
@@ -145,7 +145,7 @@
 	f=rfc2822 &&
 	(git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
 	git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual &&
-	git diff expected actual
+	test_cmp expected actual
 '
 
 cat >expected <<\EOF
@@ -155,7 +155,7 @@
 
 test_expect_success 'Verify ascending sort' '
 	git-for-each-ref --format="%(refname)" --sort=refname >actual &&
-	git diff expected actual
+	test_cmp expected actual
 '
 
 
@@ -166,7 +166,7 @@
 
 test_expect_success 'Verify descending sort' '
 	git-for-each-ref --format="%(refname)" --sort=-refname >actual &&
-	git diff expected actual
+	test_cmp expected actual
 '
 
 cat >expected <<\EOF
@@ -176,17 +176,17 @@
 
 test_expect_success 'Quoting style: shell' '
 	git for-each-ref --shell --format="%(refname)" >actual &&
-	git diff expected actual
+	test_cmp expected actual
 '
 
 test_expect_success 'Quoting style: perl' '
 	git for-each-ref --perl --format="%(refname)" >actual &&
-	git diff expected actual
+	test_cmp expected actual
 '
 
 test_expect_success 'Quoting style: python' '
 	git for-each-ref --python --format="%(refname)" >actual &&
-	git diff expected actual
+	test_cmp expected actual
 '
 
 cat >expected <<\EOF
@@ -196,7 +196,7 @@
 
 test_expect_success 'Quoting style: tcl' '
 	git for-each-ref --tcl --format="%(refname)" >actual &&
-	git diff expected actual
+	test_cmp expected actual
 '
 
 for i in "--perl --shell" "-s --python" "--python --tcl" "--tcl --perl"; do
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index f126204..e26f726 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -116,7 +116,7 @@
 		 "git ls-files -s | sed \"s-\\t-&newsubdir/-\" |
 	          GIT_INDEX_FILE=\$GIT_INDEX_FILE.new \
 			git update-index --index-info &&
-		  mv \$GIT_INDEX_FILE.new \$GIT_INDEX_FILE" directorymoved &&
+		  mv \"\$GIT_INDEX_FILE.new\" \"\$GIT_INDEX_FILE\"" directorymoved &&
 	test -z "$(git diff HEAD directorymoved:newsubdir)"'
 
 test_expect_success 'stops when msg filter fails' '
@@ -210,4 +210,36 @@
 	test $(git rev-list master | wc -l) = 3
 '
 
+test_expect_success 'Tag name filtering retains tag message' '
+	git tag -m atag T &&
+	git cat-file tag T > expect &&
+	git filter-branch -f --tag-name-filter cat &&
+	git cat-file tag T > actual &&
+	test_cmp expect actual
+'
+
+faux_gpg_tag='object XXXXXX
+type commit
+tag S
+tagger T A Gger <tagger@example.com> 1206026339 -0500
+
+This is a faux gpg signed tag.
+-----BEGIN PGP SIGNATURE-----
+Version: FauxGPG v0.0.0 (FAUX/Linux)
+
+gdsfoewhxu/6l06f1kxyxhKdZkrcbaiOMtkJUA9ITAc1mlamh0ooasxkH1XwMbYQ
+acmwXaWET20H0GeAGP+7vow=
+=agpO
+-----END PGP SIGNATURE-----
+'
+test_expect_success 'Tag name filtering strips gpg signature' '
+	sha1=$(git rev-parse HEAD) &&
+	sha1t=$(echo "$faux_gpg_tag" | sed -e s/XXXXXX/$sha1/ | git mktag) &&
+	git update-ref "refs/tags/S" "$sha1t" &&
+	echo "$faux_gpg_tag" | sed -e s/XXXXXX/$sha1/ | head -n 6 > expect &&
+	git filter-branch -f --tag-name-filter cat &&
+	git cat-file tag S > actual &&
+	test_cmp expect actual
+'
+
 test_done
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 1a7141e..acddbf5 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -116,9 +116,9 @@
 EOF
 test_expect_success \
 	'trying to delete tags without params should succeed and do nothing' '
-	git tag -l > actual && git diff expect actual &&
+	git tag -l > actual && test_cmp expect actual &&
 	git-tag -d &&
-	git tag -l > actual && git diff expect actual
+	git tag -l > actual && test_cmp expect actual
 '
 
 test_expect_success \
@@ -173,9 +173,9 @@
 	git tag v1.0 &&
 	git tag t210 &&
 	git tag -l > actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git tag > actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 cat >expect <<EOF
@@ -186,7 +186,7 @@
 test_expect_success \
 	'listing tags with substring as pattern must print those matching' '
 	git-tag -l "*a*" > actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 cat >expect <<EOF
@@ -196,7 +196,7 @@
 test_expect_success \
 	'listing tags with a suffix as pattern must print those matching' '
 	git-tag -l "*.1" > actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 cat >expect <<EOF
@@ -206,7 +206,7 @@
 test_expect_success \
 	'listing tags with a prefix as pattern must print those matching' '
 	git-tag -l "t21*" > actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 cat >expect <<EOF
@@ -215,7 +215,7 @@
 test_expect_success \
 	'listing tags using a name as pattern must print that one matching' '
 	git-tag -l a1 > actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 cat >expect <<EOF
@@ -224,7 +224,7 @@
 test_expect_success \
 	'listing tags using a name as pattern must print that one matching' '
 	git-tag -l v1.0 > actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 cat >expect <<EOF
@@ -234,14 +234,14 @@
 test_expect_success \
 	'listing tags with ? in the pattern should print those matching' '
 	git-tag -l "v1.?.?" > actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 >expect
 test_expect_success \
 	'listing tags using v.* should print nothing because none have v.' '
 	git-tag -l "v.*" > actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 cat >expect <<EOF
@@ -253,7 +253,7 @@
 test_expect_success \
 	'listing tags using v* should print only those having v' '
 	git-tag -l "v*" > actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 # creating and verifying lightweight tags:
@@ -302,7 +302,7 @@
 	'creating an annotated tag with -m message should succeed' '
 	git-tag -m "A message" annotated-tag &&
 	get_tag_msg annotated-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 cat >msgfile <<EOF
@@ -315,7 +315,7 @@
 	'creating an annotated tag with -F messagefile should succeed' '
 	git-tag -F msgfile file-annotated-tag &&
 	get_tag_msg file-annotated-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 cat >inputmsg <<EOF
@@ -327,7 +327,7 @@
 test_expect_success 'creating an annotated tag with -F - should succeed' '
 	git-tag -F - stdin-annotated-tag <inputmsg &&
 	get_tag_msg stdin-annotated-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 test_expect_success \
@@ -358,7 +358,7 @@
 	'creating a tag with an empty -m message should succeed' '
 	git-tag -m "" empty-annotated-tag &&
 	get_tag_msg empty-annotated-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 >emptyfile
@@ -367,7 +367,7 @@
 	'creating a tag with an empty -F messagefile should succeed' '
 	git-tag -F emptyfile emptyfile-annotated-tag &&
 	get_tag_msg emptyfile-annotated-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 printf '\n\n  \n\t\nLeading blank lines\n' >blanksfile
@@ -388,7 +388,7 @@
 	'extra blanks in the message for an annotated tag should be removed' '
 	git-tag -F blanksfile blanks-annotated-tag &&
 	get_tag_msg blanks-annotated-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 get_tag_header blank-annotated-tag $commit commit $time >expect
@@ -396,7 +396,7 @@
 	'creating a tag with blank -m message with spaces should succeed' '
 	git-tag -m "     " blank-annotated-tag &&
 	get_tag_msg blank-annotated-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 echo '     ' >blankfile
@@ -407,7 +407,7 @@
 	'creating a tag with blank -F messagefile with spaces should succeed' '
 	git-tag -F blankfile blankfile-annotated-tag &&
 	get_tag_msg blankfile-annotated-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 printf '      ' >blanknonlfile
@@ -416,7 +416,7 @@
 	'creating a tag with -F file of spaces and no newline should succeed' '
 	git-tag -F blanknonlfile blanknonlfile-annotated-tag &&
 	get_tag_msg blanknonlfile-annotated-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 # messages with commented lines:
@@ -451,7 +451,7 @@
 	'creating a tag using a -F messagefile with #comments should succeed' '
 	git-tag -F commentsfile comments-annotated-tag &&
 	get_tag_msg comments-annotated-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 get_tag_header comment-annotated-tag $commit commit $time >expect
@@ -459,7 +459,7 @@
 	'creating a tag with a #comment in the -m message should succeed' '
 	git-tag -m "#comment" comment-annotated-tag &&
 	get_tag_msg comment-annotated-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 echo '#comment' >commentfile
@@ -470,7 +470,7 @@
 	'creating a tag with #comments in the -F messagefile should succeed' '
 	git-tag -F commentfile commentfile-annotated-tag &&
 	get_tag_msg commentfile-annotated-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 printf '#comment' >commentnonlfile
@@ -479,7 +479,7 @@
 	'creating a tag with a file of #comment and no newline should succeed' '
 	git-tag -F commentnonlfile commentnonlfile-annotated-tag &&
 	get_tag_msg commentnonlfile-annotated-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 # listing messages for annotated non-signed tags:
@@ -490,23 +490,23 @@
 
 	echo "tag-one-line" >expect &&
 	git-tag -l | grep "^tag-one-line" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n0 -l | grep "^tag-one-line" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n0 -l tag-one-line >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 
 	echo "tag-one-line    A msg" >expect &&
 	git-tag -n1 -l | grep "^tag-one-line" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n -l | grep "^tag-one-line" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n1 -l tag-one-line >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n2 -l tag-one-line >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n999 -l tag-one-line >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 test_expect_success \
@@ -515,23 +515,23 @@
 
 	echo "tag-zero-lines" >expect &&
 	git-tag -l | grep "^tag-zero-lines" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n0 -l | grep "^tag-zero-lines" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n0 -l tag-zero-lines >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 
 	echo "tag-zero-lines  " >expect &&
 	git-tag -n1 -l | grep "^tag-zero-lines" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n -l | grep "^tag-zero-lines" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n1 -l tag-zero-lines >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n2 -l tag-zero-lines >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n999 -l tag-zero-lines >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 echo 'tag line one' >annotagmsg
@@ -543,39 +543,39 @@
 
 	echo "tag-lines" >expect &&
 	git-tag -l | grep "^tag-lines" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n0 -l | grep "^tag-lines" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n0 -l tag-lines >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 
 	echo "tag-lines       tag line one" >expect &&
 	git-tag -n1 -l | grep "^tag-lines" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n -l | grep "^tag-lines" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n1 -l tag-lines >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 
 	echo "    tag line two" >>expect &&
 	git-tag -n2 -l | grep "^ *tag.line" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n2 -l tag-lines >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 
 	echo "    tag line three" >>expect &&
 	git-tag -n3 -l | grep "^ *tag.line" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n3 -l tag-lines >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n4 -l | grep "^ *tag.line" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n4 -l tag-lines >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n99 -l | grep "^ *tag.line" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n99 -l tag-lines >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 # subsequent tests require gpg; check if it is available
@@ -626,7 +626,8 @@
 
 cp -R ../t7004 ./gpghome
 chmod 0700 gpghome
-export GNUPGHOME="$(pwd)/gpghome"
+GNUPGHOME="$(pwd)/gpghome"
+export GNUPGHOME
 
 get_tag_header signed-tag $commit commit $time >expect
 echo 'A signed tag message' >>expect
@@ -634,7 +635,7 @@
 test_expect_success 'creating a signed tag with -m message should succeed' '
 	git-tag -s -m "A signed tag message" signed-tag &&
 	get_tag_msg signed-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 get_tag_header u-signed-tag $commit commit $time >expect
@@ -644,7 +645,7 @@
 
 	git tag -u committer@example.com -m "Another message" u-signed-tag &&
 	get_tag_msg u-signed-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 
 '
 
@@ -674,7 +675,7 @@
 test_expect_success '-u implies signed tag' '
 	GIT_EDITOR=./fakeeditor git-tag -u CDDE430D implied-sign &&
 	get_tag_msg implied-sign >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 cat >sigmsgfile <<EOF
@@ -688,7 +689,7 @@
 	'creating a signed tag with -F messagefile should succeed' '
 	git-tag -s -F sigmsgfile file-signed-tag &&
 	get_tag_msg file-signed-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 cat >siginputmsg <<EOF
@@ -701,7 +702,7 @@
 test_expect_success 'creating a signed tag with -F - should succeed' '
 	git-tag -s -F - stdin-signed-tag <siginputmsg &&
 	get_tag_msg stdin-signed-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 get_tag_header implied-annotate $commit commit $time >expect
@@ -710,7 +711,7 @@
 test_expect_success '-s implies annotated tag' '
 	GIT_EDITOR=./fakeeditor git-tag -s implied-annotate &&
 	get_tag_msg implied-annotate >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 test_expect_success \
@@ -751,7 +752,7 @@
 	'creating a signed tag with an empty -m message should succeed' '
 	git-tag -s -m "" empty-signed-tag &&
 	get_tag_msg empty-signed-tag >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -v empty-signed-tag
 '
 
@@ -762,7 +763,7 @@
 	'creating a signed tag with an empty -F messagefile should succeed' '
 	git-tag -s -F sigemptyfile emptyfile-signed-tag &&
 	get_tag_msg emptyfile-signed-tag >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -v emptyfile-signed-tag
 '
 
@@ -785,7 +786,7 @@
 	'extra blanks in the message for a signed tag should be removed' '
 	git-tag -s -F sigblanksfile blanks-signed-tag &&
 	get_tag_msg blanks-signed-tag >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -v blanks-signed-tag
 '
 
@@ -795,7 +796,7 @@
 	'creating a signed tag with a blank -m message should succeed' '
 	git-tag -s -m "     " blank-signed-tag &&
 	get_tag_msg blank-signed-tag >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -v blank-signed-tag
 '
 
@@ -808,7 +809,7 @@
 	'creating a signed tag with blank -F file with spaces should succeed' '
 	git-tag -s -F sigblankfile blankfile-signed-tag &&
 	get_tag_msg blankfile-signed-tag >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -v blankfile-signed-tag
 '
 
@@ -819,7 +820,7 @@
 	'creating a signed tag with spaces and no newline should succeed' '
 	git-tag -s -F sigblanknonlfile blanknonlfile-signed-tag &&
 	get_tag_msg blanknonlfile-signed-tag >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -v signed-tag
 '
 
@@ -856,7 +857,7 @@
 	'creating a signed tag with a -F file with #comments should succeed' '
 	git-tag -s -F sigcommentsfile comments-signed-tag &&
 	get_tag_msg comments-signed-tag >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -v comments-signed-tag
 '
 
@@ -866,7 +867,7 @@
 	'creating a signed tag with #commented -m message should succeed' '
 	git-tag -s -m "#comment" comment-signed-tag &&
 	get_tag_msg comment-signed-tag >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -v comment-signed-tag
 '
 
@@ -879,7 +880,7 @@
 	'creating a signed tag with #commented -F messagefile should succeed' '
 	git-tag -s -F sigcommentfile commentfile-signed-tag &&
 	get_tag_msg commentfile-signed-tag >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -v commentfile-signed-tag
 '
 
@@ -890,7 +891,7 @@
 	'creating a signed tag with a #comment and no newline should succeed' '
 	git-tag -s -F sigcommentnonlfile commentnonlfile-signed-tag &&
 	get_tag_msg commentnonlfile-signed-tag >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -v commentnonlfile-signed-tag
 '
 
@@ -902,23 +903,23 @@
 
 	echo "stag-one-line" >expect &&
 	git-tag -l | grep "^stag-one-line" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n0 -l | grep "^stag-one-line" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n0 -l stag-one-line >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 
 	echo "stag-one-line   A message line signed" >expect &&
 	git-tag -n1 -l | grep "^stag-one-line" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n -l | grep "^stag-one-line" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n1 -l stag-one-line >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n2 -l stag-one-line >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n999 -l stag-one-line >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 test_expect_success \
@@ -927,23 +928,23 @@
 
 	echo "stag-zero-lines" >expect &&
 	git-tag -l | grep "^stag-zero-lines" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n0 -l | grep "^stag-zero-lines" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n0 -l stag-zero-lines >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 
 	echo "stag-zero-lines " >expect &&
 	git-tag -n1 -l | grep "^stag-zero-lines" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n -l | grep "^stag-zero-lines" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n1 -l stag-zero-lines >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n2 -l stag-zero-lines >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n999 -l stag-zero-lines >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 echo 'stag line one' >sigtagmsg
@@ -955,39 +956,39 @@
 
 	echo "stag-lines" >expect &&
 	git-tag -l | grep "^stag-lines" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n0 -l | grep "^stag-lines" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n0 -l stag-lines >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 
 	echo "stag-lines      stag line one" >expect &&
 	git-tag -n1 -l | grep "^stag-lines" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n -l | grep "^stag-lines" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n1 -l stag-lines >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 
 	echo "    stag line two" >>expect &&
 	git-tag -n2 -l | grep "^ *stag.line" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n2 -l stag-lines >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 
 	echo "    stag line three" >>expect &&
 	git-tag -n3 -l | grep "^ *stag.line" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n3 -l stag-lines >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n4 -l | grep "^ *stag.line" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n4 -l stag-lines >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n99 -l | grep "^ *stag.line" >actual &&
-	git diff expect actual &&
+	test_cmp expect actual &&
 	git-tag -n99 -l stag-lines >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 # tags pointing to objects different from commits:
@@ -1003,7 +1004,7 @@
 	'creating a signed tag pointing to a tree should succeed' '
 	git-tag -s -m "A message for a tree" tree-signed-tag HEAD^{tree} &&
 	get_tag_msg tree-signed-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 get_tag_header blob-signed-tag $blob blob $time >expect
@@ -1013,7 +1014,7 @@
 	'creating a signed tag pointing to a blob should succeed' '
 	git-tag -s -m "A message for a blob" blob-signed-tag HEAD:foo &&
 	get_tag_msg blob-signed-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 get_tag_header tag-signed-tag $tag tag $time >expect
@@ -1023,7 +1024,7 @@
 	'creating a signed tag pointing to another tag should succeed' '
 	git-tag -s -m "A message for another tag" tag-signed-tag signed-tag &&
 	get_tag_msg tag-signed-tag >actual &&
-	git diff expect actual
+	test_cmp expect actual
 '
 
 # try to sign with bad user.signingkey
@@ -1063,7 +1064,27 @@
 	git tag -a -m "An annotation to be reused" reuse &&
 	GIT_EDITOR=true git tag -f -a reuse &&
 	get_tag_msg reuse >actual &&
-	git diff expect actual
+	test_cmp expect actual
+'
+
+test_expect_success 'filename for the message is relative to cwd' '
+	mkdir subdir &&
+	echo "Tag message in top directory" >msgfile-5 &&
+	echo "Tag message in sub directory" >subdir/msgfile-5 &&
+	(
+		cd subdir &&
+		git tag -a -F msgfile-5 tag-from-subdir
+	) &&
+	git cat-file tag tag-from-subdir | grep "in sub directory"
+'
+
+test_expect_success 'filename for the message is relative to cwd' '
+	echo "Tag message in sub directory" >subdir/msgfile-6 &&
+	(
+		cd subdir &&
+		git tag -a -F msgfile-6 tag-from-subdir-2
+	) &&
+	git cat-file tag tag-from-subdir-2 | grep "in sub directory"
 '
 
 test_done
diff --git a/t/t7010-setup.sh b/t/t7010-setup.sh
index 02cf7c5..d8a7c79 100755
--- a/t/t7010-setup.sh
+++ b/t/t7010-setup.sh
@@ -122,7 +122,7 @@
 
 test_expect_success 'log using absolute path names' '
 	echo bb >>a/b/c/d &&
-	git commit -m "bb" $(pwd)/a/b/c/d &&
+	git commit -m "bb" "$(pwd)/a/b/c/d" &&
 
 	git log a/b/c/d >f1.txt &&
 	git log "$(pwd)/a/b/c/d" >f2.txt &&
diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh
index e5c9f30..96d1508 100755
--- a/t/t7102-reset.sh
+++ b/t/t7102-reset.sh
@@ -34,13 +34,13 @@
 
 check_changes () {
 	test "$(git rev-parse HEAD)" = "$1" &&
-	git diff | git diff .diff_expect - &&
-	git diff --cached | git diff .cached_expect - &&
+	git diff | test_cmp .diff_expect - &&
+	git diff --cached | test_cmp .cached_expect - &&
 	for FILE in *
 	do
 		echo $FILE':'
 		cat $FILE || return
-	done | git diff .cat_expect -
+	done | test_cmp .cat_expect -
 }
 
 >.diff_expect
@@ -390,9 +390,9 @@
 	git add file1 file3 file4 &&
 	! git reset HEAD -- file1 file2 file3 &&
 	git diff > output &&
-	git diff output expect &&
+	test_cmp output expect &&
 	git diff --cached > output &&
-	git diff output cached_expect
+	test_cmp output cached_expect
 '
 
 test_expect_success 'test resetting the index at give paths' '
@@ -425,7 +425,54 @@
 test_expect_success '--mixed refreshes the index' '
 	echo 123 >> file2 &&
 	git reset --mixed HEAD > output &&
-	git diff --exit-code expect output
+	test_cmp expect output
+'
+
+test_expect_success 'disambiguation (1)' '
+
+	git reset --hard &&
+	>secondfile &&
+	git add secondfile &&
+	test_must_fail git reset secondfile &&
+	test -z "$(git diff --cached --name-only)" &&
+	test -f secondfile &&
+	test ! -s secondfile
+
+'
+
+test_expect_success 'disambiguation (2)' '
+
+	git reset --hard &&
+	>secondfile &&
+	git add secondfile &&
+	rm -f secondfile &&
+	test_must_fail git reset secondfile &&
+	test -n "$(git diff --cached --name-only -- secondfile)" &&
+	test ! -f secondfile
+
+'
+
+test_expect_success 'disambiguation (3)' '
+
+	git reset --hard &&
+	>secondfile &&
+	git add secondfile &&
+	rm -f secondfile &&
+	test_must_fail git reset HEAD secondfile &&
+	test -z "$(git diff --cached --name-only)" &&
+	test ! -f secondfile
+
+'
+
+test_expect_success 'disambiguation (4)' '
+
+	git reset --hard &&
+	>secondfile &&
+	git add secondfile &&
+	rm -f secondfile &&
+	test_must_fail git reset -- secondfile &&
+	test -z "$(git diff --cached --name-only)" &&
+	test ! -f secondfile
 '
 
 test_done
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index a50492f..bd77239 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -112,7 +112,7 @@
 	touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
 	would_clean=$(
 		cd docs &&
-		git clean -n $(pwd)/../src |
+		git clean -n "$(pwd)/../src" |
 		sed -n -e "s|^Would remove ||p"
 	) &&
 	test "$would_clean" = ../src/part3.c || {
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 2ef85a8..6c7b902 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -196,4 +196,17 @@
 	test -z "$D"
 '
 
+test_expect_success 'update --init' '
+
+	mv init init2 &&
+	git config -f .gitmodules submodule.example.url "$(pwd)/init2" &&
+	git config --remove-section submodule.example
+	git submodule update init > update.out &&
+	grep "not initialized" update.out &&
+	test ! -d init/.git &&
+	git submodule update --init init &&
+	test -d init/.git
+
+'
+
 test_done
diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh
index b9a2219..bf12dbd 100755
--- a/t/t7401-submodule-summary.sh
+++ b/t/t7401-submodule-summary.sh
@@ -192,4 +192,17 @@
 EOF
 "
 
+test_expect_success '--for-status' "
+    git submodule summary --for-status HEAD^ >actual &&
+    test_cmp actual - <<EOF
+# Modified submodules:
+#
+# * sm1 $head6...0000000:
+#
+# * sm2 0000000...$head7 (2):
+#   > Add foo9
+#
+EOF
+"
+
 test_done
diff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh
new file mode 100755
index 0000000..5becb3e
--- /dev/null
+++ b/t/t7402-submodule-rebase.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Johannes Schindelin
+#
+
+test_description='Test rebasing and stashing with dirty submodules'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+	echo file > file &&
+	git add file &&
+	test_tick &&
+	git commit -m initial &&
+	git clone . submodule &&
+	git add submodule &&
+	test_tick &&
+	git commit -m submodule &&
+	echo second line >> file &&
+	(cd submodule && git pull) &&
+	test_tick &&
+	git commit -m file-and-submodule -a
+
+'
+
+test_expect_success 'rebase with a dirty submodule' '
+
+	(cd submodule &&
+	 echo 3rd line >> file &&
+	 test_tick &&
+	 git commit -m fork -a) &&
+	echo unrelated >> file2 &&
+	git add file2 &&
+	test_tick &&
+	git commit -m unrelated file2 &&
+	echo other line >> file &&
+	test_tick &&
+	git commit -m update file &&
+	CURRENT=$(cd submodule && git rev-parse HEAD) &&
+	EXPECTED=$(git rev-parse HEAD~2:submodule) &&
+	GIT_TRACE=1 git rebase --onto HEAD~2 HEAD^ &&
+	STORED=$(git rev-parse HEAD:submodule) &&
+	test $EXPECTED = $STORED &&
+	test $CURRENT = $(cd submodule && git rev-parse HEAD)
+
+'
+
+cat > fake-editor.sh << \EOF
+#!/bin/sh
+echo $EDITOR_TEXT
+EOF
+chmod a+x fake-editor.sh
+
+test_expect_success 'interactive rebase with a dirty submodule' '
+
+	test submodule = $(git diff --name-only) &&
+	HEAD=$(git rev-parse HEAD) &&
+	GIT_EDITOR="\"$(pwd)/fake-editor.sh\"" EDITOR_TEXT="pick $HEAD" \
+		git rebase -i HEAD^ &&
+	test submodule = $(git diff --name-only)
+
+'
+
+test_expect_success 'rebase with dirty file and submodule fails' '
+
+	echo yet another line >> file &&
+	test_tick &&
+	git commit -m next file &&
+	echo rewrite > file &&
+	test_tick &&
+	git commit -m rewrite file &&
+	echo dirty > file &&
+	! git rebase --onto HEAD~2 HEAD^
+
+'
+
+test_expect_success 'stash with a dirty submodule' '
+
+	echo new > file &&
+	CURRENT=$(cd submodule && git rev-parse HEAD) &&
+	git stash &&
+	test new != $(cat file) &&
+	test submodule = $(git diff --name-only) &&
+	test $CURRENT = $(cd submodule && git rev-parse HEAD) &&
+	git stash apply &&
+	test new = $(cat file) &&
+	test $CURRENT = $(cd submodule && git rev-parse HEAD)
+
+'
+
+test_done
diff --git a/t/t7500-commit.sh b/t/t7500-commit.sh
index baed6ce..823256a 100755
--- a/t/t7500-commit.sh
+++ b/t/t7500-commit.sh
@@ -138,4 +138,33 @@
 	diff expect output
 '
 
+test_expect_success 'commit message from file (1)' '
+	mkdir subdir &&
+	echo "Log in top directory" >log &&
+	echo "Log in sub directory" >subdir/log &&
+	(
+		cd subdir &&
+		git commit --allow-empty -F log
+	) &&
+	commit_msg_is "Log in sub directory"
+'
+
+test_expect_success 'commit message from file (2)' '
+	rm -f log &&
+	echo "Log in sub directory" >subdir/log &&
+	(
+		cd subdir &&
+		git commit --allow-empty -F log
+	) &&
+	commit_msg_is "Log in sub directory"
+'
+
+test_expect_success 'commit message from stdin' '
+	(
+		cd subdir &&
+		echo "Log with foo word" | git commit --allow-empty -F -
+	) &&
+	commit_msg_is "Log with foo word"
+'
+
 test_done
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index c0288f3..d3370ff 100755
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -41,7 +41,7 @@
 test_expect_success \
 	"using paths with --interactive" \
 	"echo bong-o-bong >file &&
-	! echo 7 | git-commit -m foo --interactive file"
+	! (echo 7 | git-commit -m foo --interactive file)"
 
 test_expect_success \
 	"using invalid commit with -C" \
@@ -79,8 +79,8 @@
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -e "s/a file/an amend commit/g" < $1 > $1-
-mv $1- $1
+sed -e "s/a file/an amend commit/g" < "$1" > "$1-"
+mv "$1-" "$1"
 EOF
 chmod 755 editor
 
@@ -99,8 +99,8 @@
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -e "s/amend/older/g"  < $1 > $1-
-mv $1- $1
+sed -e "s/amend/older/g"  < "$1" > "$1-"
+mv "$1-" "$1"
 EOF
 chmod 755 editor
 
diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh
index 284c941..c25eff9 100755
--- a/t/t7502-commit.sh
+++ b/t/t7502-commit.sh
@@ -154,6 +154,38 @@
 
 '
 
+echo "#
+# Author:    $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>
+#" >> expect
+
+test_expect_success 'author different from committer' '
+
+	echo >>negative &&
+	git commit -e -m "sample"
+	head -n 7 .git/COMMIT_EDITMSG >actual &&
+	test_cmp expect actual
+'
+
+mv expect expect.tmp
+sed '$d' < expect.tmp > expect
+rm -f expect.tmp
+echo "# Committer:
+#" >> expect
+
+test_expect_success 'committer is automatic' '
+
+	echo >>negative &&
+	(
+		unset GIT_COMMITTER_EMAIL
+		unset GIT_COMMITTER_NAME
+		# must fail because there is no change
+		test_must_fail git commit -e -m "sample"
+	) &&
+	head -n 8 .git/COMMIT_EDITMSG |	\
+	sed "s/^# Committer: .*/# Committer:/" >actual &&
+	test_cmp expect actual
+'
+
 pwd=`pwd`
 cat >> .git/FAKE_EDITOR << EOF
 #! /bin/sh
@@ -164,23 +196,56 @@
 
 test_expect_success 'do not fire editor in the presence of conflicts' '
 
-	git clean
-	echo f>g
-	git add g
-	git commit -myes
-	git branch second
-	echo master>g
-	echo g>h
-	git add g h
-	git commit -mmaster
-	git checkout second
-	echo second>g
-	git add g
-	git commit -msecond
-	git cherry-pick -n master
-	echo "editor not started" > .git/result
-	GIT_EDITOR=`pwd`/.git/FAKE_EDITOR git commit && exit 1  # should fail
-	test "`cat .git/result`" = "editor not started"
+	git clean -f &&
+	echo f >g &&
+	git add g &&
+	git commit -m "add g" &&
+	git branch second &&
+	echo master >g &&
+	echo g >h &&
+	git add g h &&
+	git commit -m "modify g and add h" &&
+	git checkout second &&
+	echo second >g &&
+	git add g &&
+	git commit -m second &&
+	# Must fail due to conflict
+	test_must_fail git cherry-pick -n master &&
+	echo "editor not started" >.git/result &&
+	(
+		GIT_EDITOR="$(pwd)/.git/FAKE_EDITOR" &&
+		export GIT_EDITOR &&
+		test_must_fail git commit
+	) &&
+	test "$(cat .git/result)" = "editor not started"
+'
+
+pwd=`pwd`
+cat >.git/FAKE_EDITOR <<EOF
+#! $SHELL_PATH
+# kill -TERM command added below.
+EOF
+
+test_expect_success 'a SIGTERM should break locks' '
+	echo >>negative &&
+	"$SHELL_PATH" -c '\''
+	  echo kill -TERM $$ >> .git/FAKE_EDITOR
+	  GIT_EDITOR=.git/FAKE_EDITOR exec git commit -a'\'' && exit 1  # should fail
+	! test -f .git/index.lock
+'
+
+rm -f .git/MERGE_MSG .git/COMMIT_EDITMSG
+git reset -q --hard
+
+test_expect_success 'Hand committing of a redundant merge removes dups' '
+
+	git rev-parse second master >expect &&
+	test_must_fail git merge second master &&
+	git checkout master g &&
+	EDITOR=: git commit -a &&
+	git cat-file commit HEAD | sed -n -e "s/^parent //p" -e "/^$/q" >actual &&
+	test_cmp expect actual
+
 '
 
 test_done
diff --git a/t/t7502-status.sh b/t/t7502-status.sh
index cd08516..80a438d 100755
--- a/t/t7502-status.sh
+++ b/t/t7502-status.sh
@@ -63,7 +63,7 @@
 test_expect_success 'status (2)' '
 
 	git status > output &&
-	git diff expect output
+	test_cmp expect output
 
 '
 
@@ -93,7 +93,7 @@
 test_expect_success 'status with relative paths' '
 
 	(cd dir1 && git status) > output &&
-	git diff expect output
+	test_cmp expect output
 
 '
 
@@ -124,7 +124,7 @@
 
 	git config status.relativePaths false
 	(cd dir1 && git status) > output &&
-	git diff expect output
+	test_cmp expect output
 
 '
 
@@ -149,4 +149,138 @@
 	test_cmp expect output
 '
 
+test_expect_success 'setup status submodule summary' '
+	test_create_repo sm && (
+		cd sm &&
+		>foo &&
+		git add foo &&
+		git commit -m "Add foo"
+	) &&
+	git add sm
+'
+
+cat >expect <<EOF
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD <file>..." to unstage)
+#
+#	new file:   dir2/added
+#	new file:   sm
+#
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#
+#	modified:   dir1/modified
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#	dir1/untracked
+#	dir2/modified
+#	dir2/untracked
+#	expect
+#	output
+#	untracked
+EOF
+test_expect_success 'status submodule summary is disabled by default' '
+	git status >output &&
+	test_cmp expect output
+'
+
+head=$(cd sm && git rev-parse --short=7 --verify HEAD)
+
+cat >expect <<EOF
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD <file>..." to unstage)
+#
+#	new file:   dir2/added
+#	new file:   sm
+#
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#
+#	modified:   dir1/modified
+#
+# Modified submodules:
+#
+# * sm 0000000...$head (1):
+#   > Add foo
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#	dir1/untracked
+#	dir2/modified
+#	dir2/untracked
+#	expect
+#	output
+#	untracked
+EOF
+test_expect_success 'status submodule summary' '
+	git config status.submodulesummary 10 &&
+	git status >output &&
+	test_cmp expect output
+'
+
+
+cat >expect <<EOF
+# On branch master
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#
+#	modified:   dir1/modified
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#	dir1/untracked
+#	dir2/modified
+#	dir2/untracked
+#	expect
+#	output
+#	untracked
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
+test_expect_success 'status submodule summary (clean submodule)' '
+	git commit -m "commit submodule" &&
+	git config status.submodulesummary 10 &&
+	test_must_fail git status >output &&
+	test_cmp expect output
+'
+
+cat >expect <<EOF
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD^1 <file>..." to unstage)
+#
+#	new file:   dir2/added
+#	new file:   sm
+#
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#
+#	modified:   dir1/modified
+#
+# Modified submodules:
+#
+# * sm 0000000...$head (1):
+#   > Add foo
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#	dir1/untracked
+#	dir2/modified
+#	dir2/untracked
+#	expect
+#	output
+#	untracked
+EOF
+test_expect_success 'status submodule summary (--amend)' '
+	git config status.submodulesummary 10 &&
+	git status --amend >output &&
+	test_cmp expect output
+'
+
 test_done
diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh
index eff36aa..88577af 100755
--- a/t/t7504-commit-msg-hook.sh
+++ b/t/t7504-commit-msg-hook.sh
@@ -19,6 +19,9 @@
 exit 0
 EOF
 chmod +x fake-editor
+
+## Not using test_set_editor here so we can easily ensure the editor variable
+## is only set for the editor tests
 FAKE_EDITOR="$(pwd)/fake-editor"
 export FAKE_EDITOR
 
@@ -27,7 +30,7 @@
 	echo "more foo" >> file &&
 	git add file &&
 	echo "more foo" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit
 
 '
 
@@ -44,7 +47,7 @@
 	echo "more bar" > file &&
 	git add file &&
 	echo "more bar" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify
 
 '
 
@@ -71,7 +74,7 @@
 	echo "more more" >> file &&
 	git add file &&
 	echo "more more" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit
 
 '
 
@@ -88,7 +91,7 @@
 	echo "even more more" >> file &&
 	git add file &&
 	echo "even more more" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify
 
 '
 
@@ -111,7 +114,7 @@
 	echo "more another" >> file &&
 	git add file &&
 	echo "more another" > FAKE_MSG &&
-	! (GIT_EDITOR="$FAKE_EDITOR" git commit)
+	! (GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit)
 
 '
 
@@ -128,7 +131,7 @@
 	echo "more stuff" >> file &&
 	git add file &&
 	echo "more stuff" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify
 
 '
 
@@ -146,7 +149,7 @@
 	echo "content again" >> file &&
 	git add file &&
 	echo "content again" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit -m "content again"
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -m "content again"
 
 '
 
@@ -163,7 +166,7 @@
 	echo "even more content" >> file &&
 	git add file &&
 	echo "even more content" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify
 
 '
 
@@ -193,7 +196,7 @@
 	echo "additional content" >> file &&
 	git add file &&
 	echo "additional content" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit &&
 	commit_msg_is "new message"
 
 '
@@ -212,7 +215,7 @@
 	echo "more plus" >> file &&
 	git add file &&
 	echo "more plus" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify &&
 	commit_msg_is "more plus"
 
 '
diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh
index 802aa62..cd6c7c8 100755
--- a/t/t7505-prepare-commit-msg-hook.sh
+++ b/t/t7505-prepare-commit-msg-hook.sh
@@ -18,6 +18,9 @@
 exit 0
 EOF
 chmod +x fake-editor
+
+## Not using test_set_editor here so we can easily ensure the editor variable
+## is only set for the editor tests
 FAKE_EDITOR="$(pwd)/fake-editor"
 export FAKE_EDITOR
 
@@ -58,7 +61,7 @@
 
 	echo "more" >> file &&
 	git add file &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit -e -m "more more" &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -e -m "more more" &&
 	test "`git log -1 --pretty=format:%s`" = message
 
 '
@@ -85,7 +88,7 @@
 
 	echo "more" >> file &&
 	git add file &&
-	(echo more more | GIT_EDITOR="$FAKE_EDITOR" git commit -e -F -) &&
+	(echo more more | GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -e -F -) &&
 	test "`git log -1 --pretty=format:%s`" = message
 
 '
@@ -104,7 +107,7 @@
 
 	echo "more more" >> file &&
 	git add file &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit &&
 	test "`git log -1 --pretty=format:%s`" = default
 
 '
@@ -114,7 +117,7 @@
 	head=`git rev-parse HEAD` &&
 	echo "more" >> file &&
 	git add file &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --amend &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --amend &&
 	test "`git log -1 --pretty=format:%s`" = "$head"
 
 '
@@ -124,7 +127,7 @@
 	head=`git rev-parse HEAD` &&
 	echo "more" >> file &&
 	git add file &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit -c $head &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -c $head &&
 	test "`git log -1 --pretty=format:%s`" = "$head"
 
 '
@@ -139,7 +142,7 @@
 	head=`git rev-parse HEAD` &&
 	echo "more" >> file &&
 	git add file &&
-	! GIT_EDITOR="$FAKE_EDITOR" git commit -c $head
+	! GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -c $head
 
 '
 
@@ -148,7 +151,7 @@
 	head=`git rev-parse HEAD` &&
 	echo "more" >> file &&
 	git add file &&
-	! GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify -c $head
+	! GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify -c $head
 
 '
 
diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh
new file mode 100755
index 0000000..a75130c
--- /dev/null
+++ b/t/t7506-status-submodule.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+test_description='git-status for submodule'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	test_create_repo sub
+	cd sub &&
+	: >bar &&
+	git add bar &&
+	git commit -m " Add bar" &&
+	cd .. &&
+	git add sub &&
+	git commit -m "Add submodule sub"
+'
+
+test_expect_success 'status clean' '
+	git status |
+	grep "nothing to commit"
+'
+test_expect_success 'status -a clean' '
+	git status -a |
+	grep "nothing to commit"
+'
+test_expect_success 'rm submodule contents' '
+	rm -rf sub/* sub/.git
+'
+test_expect_success 'status clean (empty submodule dir)' '
+	git status |
+	grep "nothing to commit"
+'
+test_expect_success 'status -a clean (empty submodule dir)' '
+	git status -a |
+	grep "nothing to commit"
+'
+
+test_done
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 56869ac..daf45b7 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -104,7 +104,11 @@
 	git log --no-merges ^HEAD c2 >>squash.1-5 &&
 	echo "Squashed commit of the following:" >squash.1-5-9 &&
 	echo >>squash.1-5-9 &&
-	git log --no-merges ^HEAD c2 c3 >>squash.1-5-9
+	git log --no-merges ^HEAD c2 c3 >>squash.1-5-9 &&
+	echo > msg.nolog &&
+	echo "* commit 'c3':" >msg.log &&
+	echo "  commit 3" >>msg.log &&
+	echo >>msg.log
 }
 
 verify_diff() {
@@ -218,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' '
@@ -364,7 +344,7 @@
 
 test_debug 'gitk --all'
 
-test_expect_success 'override config option -n' '
+test_expect_success 'override config option -n with --summary' '
 	git reset --hard c1 &&
 	git config branch.master.mergeoptions "-n" &&
 	test_tick &&
@@ -373,15 +353,30 @@
 	verify_parents $c1 $c2 &&
 	if ! grep "^ file |  *2 +-$" diffstat.txt
 	then
-		echo "[OOPS] diffstat was not generated"
+		echo "[OOPS] diffstat was not generated with --summary"
+		false
+	fi
+'
+
+test_expect_success 'override config option -n with --stat' '
+	git reset --hard c1 &&
+	git config branch.master.mergeoptions "-n" &&
+	test_tick &&
+	git merge --stat c2 >diffstat.txt &&
+	verify_merge file result.1-5 msg.1-5 &&
+	verify_parents $c1 $c2 &&
+	if ! grep "^ file |  *2 +-$" diffstat.txt
+	then
+		echo "[OOPS] diffstat was not generated with --stat"
+		false
 	fi
 '
 
 test_debug 'gitk --all'
 
-test_expect_success 'override config option --summary' '
+test_expect_success 'override config option --stat' '
 	git reset --hard c1 &&
-	git config branch.master.mergeoptions "--summary" &&
+	git config branch.master.mergeoptions "--stat" &&
 	test_tick &&
 	git merge -n c2 >diffstat.txt &&
 	verify_merge file result.1-5 msg.1-5 &&
@@ -441,6 +436,16 @@
 	verify_head $c1
 '
 
+test_expect_success 'merge log message' '
+	git reset --hard c0 &&
+	git merge --no-log c2 &&
+	git show -s --pretty=format:%b HEAD >msg.act &&
+	verify_diff msg.nolog msg.act "[OOPS] bad merge log message" &&
+	git merge --log c3 &&
+	git show -s --pretty=format:%b HEAD >msg.act &&
+	verify_diff msg.log msg.act "[OOPS] bad merge log message"
+'
+
 test_debug 'gitk --all'
 
 test_done
diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh
old mode 100644
new mode 100755
diff --git a/t/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh
new file mode 100755
index 0000000..6a5211f
--- /dev/null
+++ b/t/t7701-repack-unpack-unreachable.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+test_description='git-repack works correctly'
+
+. ./test-lib.sh
+
+test_expect_success '-A option leaves unreachable objects unpacked' '
+	echo content > file1 &&
+	git add . &&
+	git commit -m initial_commit &&
+	# create a transient branch with unique content
+	git checkout -b transient_branch &&
+	echo more content >> file1 &&
+	# record the objects created in the database for file, commit, tree
+	fsha1=$(git hash-object file1) &&
+	git commit -a -m more_content &&
+	csha1=$(git rev-parse HEAD^{commit}) &&
+	tsha1=$(git rev-parse HEAD^{tree}) &&
+	git checkout master &&
+	echo even more content >> file1 &&
+	git commit -a -m even_more_content &&
+	# delete the transient branch
+	git branch -D transient_branch &&
+	# pack the repo
+	git repack -A -d -l &&
+	# verify objects are packed in repository
+	test 3 = $(git verify-pack -v -- .git/objects/pack/*.idx |
+		   grep -e "^$fsha1 " -e "^$csha1 " -e "^$tsha1 " |
+		   sort | uniq | wc -l) &&
+	git show $fsha1 &&
+	git show $csha1 &&
+	git show $tsha1 &&
+	# now expire the reflog
+	sleep 1 &&
+	git reflog expire --expire-unreachable=now --all &&
+	# and repack
+	git repack -A -d -l &&
+	# verify objects are retained unpacked
+	test 0 = $(git verify-pack -v -- .git/objects/pack/*.idx |
+		   grep -e "^$fsha1 " -e "^$csha1 " -e "^$tsha1 " |
+		   sort | uniq | wc -l) &&
+	git show $fsha1 &&
+	git show $csha1 &&
+	git show $tsha1
+'
+
+test_done
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index a4bcd28..3e4eb63 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -139,15 +139,16 @@
 
 test_expect_success 'setup fake editor' '
 	(echo "#!/bin/sh" &&
-	 echo "echo fake edit >>\$1"
+	 echo "echo fake edit >>\"\$1\""
 	) >fake-editor &&
 	chmod +x fake-editor
 '
 
+test_set_editor "$(pwd)/fake-editor"
+
 test_expect_success '--compose works' '
 	clean_fake_sendmail &&
 	echo y | \
-		GIT_EDITOR=$(pwd)/fake-editor \
 		GIT_SEND_EMAIL_NOTTY=1 \
 		git send-email \
 		--compose --subject foo \
@@ -166,14 +167,80 @@
 	grep "Subject:.*Second" msgtxt2
 '
 
+cat >expected-show-all-headers <<\EOF
+0001-Second.patch
+(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
+Dry-OK. Log says:
+Server: relay.example.com
+MAIL FROM:<from@example.com>
+RCPT TO:<to@example.com>,<cc@example.com>,<author@example.com>
+From: Example <from@example.com>
+To: to@example.com
+Cc: cc@example.com, A <author@example.com>
+Subject: [PATCH 1/1] Second.
+Date: DATE-STRING
+Message-Id: MESSAGE-ID-STRING
+X-Mailer: X-MAILER-STRING
+
+Result: OK
+EOF
+
+test_expect_success 'sendemail.cc set' '
+	git config sendemail.cc cc@example.com &&
+	git send-email \
+		--dry-run \
+		--from="Example <from@example.com>" \
+		--to=to@example.com \
+		--smtp-server relay.example.com \
+		$patches |
+	sed	-e "s/^\(Date:\).*/\1 DATE-STRING/" \
+		-e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
+		-e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
+		>actual-show-all-headers &&
+	test_cmp expected-show-all-headers actual-show-all-headers
+'
+
+cat >expected-show-all-headers <<\EOF
+0001-Second.patch
+(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
+Dry-OK. Log says:
+Server: relay.example.com
+MAIL FROM:<from@example.com>
+RCPT TO:<to@example.com>,<author@example.com>
+From: Example <from@example.com>
+To: to@example.com
+Cc: A <author@example.com>
+Subject: [PATCH 1/1] Second.
+Date: DATE-STRING
+Message-Id: MESSAGE-ID-STRING
+X-Mailer: X-MAILER-STRING
+
+Result: OK
+EOF
+
+test_expect_success 'sendemail.cc unset' '
+	git config --unset sendemail.cc &&
+	git send-email \
+		--dry-run \
+		--from="Example <from@example.com>" \
+		--to=to@example.com \
+		--smtp-server relay.example.com \
+		$patches |
+	sed	-e "s/^\(Date:\).*/\1 DATE-STRING/" \
+		-e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
+		-e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
+		>actual-show-all-headers &&
+	test_cmp expected-show-all-headers actual-show-all-headers
+'
+
 test_expect_success '--compose adds MIME for utf8 body' '
 	clean_fake_sendmail &&
 	(echo "#!/bin/sh" &&
-	 echo "echo utf8 body: àéìöú >>\$1"
+	 echo "echo utf8 body: àéìöú >>\"\$1\""
 	) >fake-editor-utf8 &&
 	chmod +x fake-editor-utf8 &&
 	echo y | \
-	  GIT_EDITOR=$(pwd)/fake-editor-utf8 \
+	  GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
 	  GIT_SEND_EMAIL_NOTTY=1 \
 	  git send-email \
 	  --compose --subject foo \
@@ -193,11 +260,11 @@
 	 echo " echo Content-Transfer-Encoding: 8bit"
 	 echo " echo Subject: foo"
 	 echo " echo "
-	 echo " echo utf8 body: àéìöú) >\$1"
+	 echo " echo utf8 body: àéìöú) >\"\$1\""
 	) >fake-editor-utf8-mime &&
 	chmod +x fake-editor-utf8-mime &&
 	echo y | \
-	  GIT_EDITOR=$(pwd)/fake-editor-utf8-mime \
+	  GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \
 	  GIT_SEND_EMAIL_NOTTY=1 \
 	  git send-email \
 	  --compose --subject foo \
@@ -213,7 +280,7 @@
 test_expect_success '--compose adds MIME for utf8 subject' '
 	clean_fake_sendmail &&
 	echo y | \
-	  GIT_EDITOR=$(pwd)/fake-editor \
+	  GIT_EDITOR="\"$(pwd)/fake-editor\"" \
 	  GIT_SEND_EMAIL_NOTTY=1 \
 	  git send-email \
 	  --compose --subject utf8-sübjëct \
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index 4e24ab3..242cdf0 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -20,39 +20,39 @@
 echo 'define NO_SVN_TESTS to skip git-svn tests'
 
 test_expect_success \
-    'initialize git-svn' "
+    'initialize git-svn' '
 	mkdir import &&
 	cd import &&
 	echo foo > foo &&
 	ln -s foo foo.link
 	mkdir -p dir/a/b/c/d/e &&
-	echo 'deep dir' > dir/a/b/c/d/e/file &&
+	echo "deep dir" > dir/a/b/c/d/e/file &&
 	mkdir bar &&
-	echo 'zzz' > bar/zzz &&
-	echo '#!/bin/sh' > exec.sh &&
+	echo "zzz" > bar/zzz &&
+	echo "#!/bin/sh" > exec.sh &&
 	chmod +x exec.sh &&
-	svn import -m 'import for git-svn' . $svnrepo >/dev/null &&
+	svn import -m "import for git-svn" . "$svnrepo" >/dev/null &&
 	cd .. &&
 	rm -rf import &&
-	git-svn init $svnrepo"
+	git-svn init "$svnrepo"'
 
 test_expect_success \
     'import an SVN revision into git' \
     'git-svn fetch'
 
-test_expect_success "checkout from svn" "svn co $svnrepo '$SVN_TREE'"
+test_expect_success "checkout from svn" 'svn co "$svnrepo" "$SVN_TREE"'
 
 name='try a deep --rmdir with a commit'
-test_expect_success "$name" "
+test_expect_success "$name" '
 	git checkout -f -b mybranch remotes/git-svn &&
 	mv dir/a/b/c/d/e/file dir/file &&
 	cp dir/file file &&
 	git update-index --add --remove dir/a/b/c/d/e/file dir/file file &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch &&
-	svn up '$SVN_TREE' &&
-	test -d '$SVN_TREE'/dir && test ! -d '$SVN_TREE'/dir/a"
+	svn up "$SVN_TREE" &&
+	test -d "$SVN_TREE"/dir && test ! -d "$SVN_TREE"/dir/a'
 
 
 name='detect node change from file to directory #1'
@@ -68,108 +68,108 @@
 
 
 name='detect node change from directory to file #1'
-test_expect_success "$name" "
-	rm -rf dir '$GIT_DIR'/index &&
+test_expect_success "$name" '
+	rm -rf dir "$GIT_DIR"/index &&
 	git checkout -f -b mybranch2 remotes/git-svn &&
 	mv bar/zzz zzz &&
 	rm -rf bar &&
 	mv zzz bar &&
 	git update-index --remove -- bar/zzz &&
 	git update-index --add -- bar &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	! git-svn set-tree --find-copies-harder --rmdir \
-		remotes/git-svn..mybranch2" || true
+		remotes/git-svn..mybranch2' || true
 
 
 name='detect node change from file to directory #2'
-test_expect_success "$name" "
-	rm -f '$GIT_DIR'/index &&
+test_expect_success "$name" '
+	rm -f "$GIT_DIR"/index &&
 	git checkout -f -b mybranch3 remotes/git-svn &&
 	rm bar/zzz &&
 	git update-index --remove bar/zzz &&
 	mkdir bar/zzz &&
 	echo yyy > bar/zzz/yyy &&
 	git update-index --add bar/zzz/yyy &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	! git-svn set-tree --find-copies-harder --rmdir \
-		remotes/git-svn..mybranch3" || true
+		remotes/git-svn..mybranch3' || true
 
 
 name='detect node change from directory to file #2'
-test_expect_success "$name" "
-	rm -f '$GIT_DIR'/index &&
+test_expect_success "$name" '
+	rm -f "$GIT_DIR"/index &&
 	git checkout -f -b mybranch4 remotes/git-svn &&
 	rm -rf dir &&
 	git update-index --remove -- dir/file &&
 	touch dir &&
 	echo asdf > dir &&
 	git update-index --add -- dir &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	! git-svn set-tree --find-copies-harder --rmdir \
-		remotes/git-svn..mybranch4" || true
+		remotes/git-svn..mybranch4' || true
 
 
 name='remove executable bit from a file'
-test_expect_success "$name" "
-	rm -f '$GIT_DIR'/index &&
+test_expect_success "$name" '
+	rm -f "$GIT_DIR"/index &&
 	git checkout -f -b mybranch5 remotes/git-svn &&
 	chmod -x exec.sh &&
 	git update-index exec.sh &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test ! -x '$SVN_TREE'/exec.sh"
+	svn up "$SVN_TREE" &&
+	test ! -x "$SVN_TREE"/exec.sh'
 
 
 name='add executable bit back file'
-test_expect_success "$name" "
+test_expect_success "$name" '
 	chmod +x exec.sh &&
 	git update-index exec.sh &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -x '$SVN_TREE'/exec.sh"
+	svn up "$SVN_TREE" &&
+	test -x "$SVN_TREE"/exec.sh'
 
 
 name='executable file becomes a symlink to bar/zzz (file)'
-test_expect_success "$name" "
+test_expect_success "$name" '
 	rm exec.sh &&
 	ln -s bar/zzz exec.sh &&
 	git update-index exec.sh &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -L '$SVN_TREE'/exec.sh"
+	svn up "$SVN_TREE" &&
+	test -L "$SVN_TREE"/exec.sh'
 
 name='new symlink is added to a file that was also just made executable'
 
-test_expect_success "$name" "
+test_expect_success "$name" '
 	chmod +x bar/zzz &&
 	ln -s bar/zzz exec-2.sh &&
 	git update-index --add bar/zzz exec-2.sh &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -x '$SVN_TREE'/bar/zzz &&
-	test -L '$SVN_TREE'/exec-2.sh"
+	svn up "$SVN_TREE" &&
+	test -x "$SVN_TREE"/bar/zzz &&
+	test -L "$SVN_TREE"/exec-2.sh'
 
 name='modify a symlink to become a file'
-test_expect_success "$name" "
+test_expect_success "$name" '
 	echo git help > help || true &&
 	rm exec-2.sh &&
 	cp help exec-2.sh &&
 	git update-index exec-2.sh &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -f '$SVN_TREE'/exec-2.sh &&
-	test ! -L '$SVN_TREE'/exec-2.sh &&
-	git diff help $SVN_TREE/exec-2.sh"
+	svn up "$SVN_TREE" &&
+	test -f "$SVN_TREE"/exec-2.sh &&
+	test ! -L "$SVN_TREE"/exec-2.sh &&
+	test_cmp help "$SVN_TREE"/exec-2.sh'
 
 if test "$have_utf8" = t
 then
@@ -190,10 +190,10 @@
 GIT_SVN_ID=alt
 export GIT_SVN_ID
 test_expect_success "$name" \
-    "git-svn init $svnrepo && git-svn fetch &&
+    'git-svn init "$svnrepo" && git-svn fetch &&
      git rev-list --pretty=raw remotes/git-svn | grep ^tree | uniq > a &&
      git rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b &&
-     git diff a b"
+     test_cmp a b'
 
 name='check imported tree checksums expected tree checksums'
 rm -f expected
@@ -211,7 +211,7 @@
 tree 8f51f74cf0163afc9ad68a4b1537288c4558b5a4
 EOF
 
-test_expect_success "$name" "git diff a expected"
+test_expect_success "$name" "test_cmp a expected"
 
 test_expect_success 'exit if remote refs are ambigious' "
         git config --add svn-remote.svn.fetch \
@@ -219,22 +219,22 @@
 	! git-svn migrate
 "
 
-test_expect_success 'exit if init-ing a would clobber a URL' "
-        svnadmin create ${PWD}/svnrepo2 &&
-        svn mkdir -m 'mkdir bar' ${svnrepo}2/bar &&
+test_expect_success 'exit if init-ing a would clobber a URL' '
+        svnadmin create "${PWD}/svnrepo2" &&
+        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
-        "
+                                "^bar:refs/remotes/git-svn$" &&
+	! git-svn init "${svnrepo}2/bar"
+        '
 
 test_expect_success \
-  'init allows us to connect to another directory in the same repo' "
-        git-svn init --minimize-url -i bar $svnrepo/bar &&
+  'init allows us to connect to another directory in the same repo' '
+        git-svn init --minimize-url -i bar "$svnrepo/bar" &&
         git config --get svn-remote.svn.fetch \
-                              '^bar:refs/remotes/bar$' &&
+                              "^bar:refs/remotes/bar$" &&
         git config --get svn-remote.svn.fetch \
-                              '^:refs/remotes/git-svn$'
-        "
+                              "^:refs/remotes/git-svn$"
+        '
 
 test_expect_success 'able to dcommit to a subdirectory' "
 	git-svn fetch -i bar &&
diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh
index d7a7047..f420796 100755
--- a/t/t9101-git-svn-props.sh
+++ b/t/t9101-git-svn-props.sh
@@ -52,7 +52,7 @@
 cd ..
 
 rm -rf import
-test_expect_success 'checkout working copy from svn' "svn co $svnrepo test_wc"
+test_expect_success 'checkout working copy from svn' 'svn co "$svnrepo" test_wc'
 test_expect_success 'setup some commits to svn' \
 	'cd test_wc &&
 		echo Greetings >> kw.c &&
@@ -66,7 +66,7 @@
 		svn commit -m "Propset Id" &&
 	cd ..'
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' 'git-svn init "$svnrepo"'
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 
 name='test svn:keywords ignoring'
@@ -90,9 +90,9 @@
 	 cd ..'
 
 test_expect_success 'fetch and pull latest from svn and checkout a new wc' \
-	"git-svn fetch &&
+	'git-svn fetch &&
 	 git pull . remotes/git-svn &&
-	 svn co $svnrepo new_wc"
+	 svn co "$svnrepo" new_wc'
 
 for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf
 do
diff --git a/t/t9102-git-svn-deep-rmdir.sh b/t/t9102-git-svn-deep-rmdir.sh
index 4e08083..0e7ce34 100755
--- a/t/t9102-git-svn-deep-rmdir.sh
+++ b/t/t9102-git-svn-deep-rmdir.sh
@@ -2,29 +2,29 @@
 test_description='git-svn rmdir'
 . ./lib-git-svn.sh
 
-test_expect_success 'initialize repo' "
+test_expect_success 'initialize repo' '
 	mkdir import &&
 	cd import &&
 	mkdir -p deeply/nested/directory/number/1 &&
 	mkdir -p deeply/nested/directory/number/2 &&
 	echo foo > deeply/nested/directory/number/1/file &&
 	echo foo > deeply/nested/directory/number/2/another &&
-	svn import -m 'import for git-svn' . $svnrepo &&
+	svn import -m "import for git-svn" . "$svnrepo" &&
 	cd ..
-	"
+	'
 
-test_expect_success 'mirror via git-svn' "
-	git-svn init $svnrepo &&
+test_expect_success 'mirror via git-svn' '
+	git-svn init "$svnrepo" &&
 	git-svn fetch &&
 	git checkout -f -b test-rmdir remotes/git-svn
-	"
+	'
 
-test_expect_success 'Try a commit on rmdir' "
+test_expect_success 'Try a commit on rmdir' '
 	git rm -f deeply/nested/directory/number/2/another &&
-	git commit -a -m 'remove another' &&
+	git commit -a -m "remove another" &&
 	git-svn set-tree --rmdir HEAD &&
-	svn ls -R $svnrepo | grep ^deeply/nested/directory/number/1
-	"
+	svn ls -R "$svnrepo" | grep ^deeply/nested/directory/number/1
+	'
 
 
 test_done
diff --git a/t/t9103-git-svn-tracked-directory-removed.sh b/t/t9103-git-svn-tracked-directory-removed.sh
index 0f0b0fd..9ffd845 100755
--- a/t/t9103-git-svn-tracked-directory-removed.sh
+++ b/t/t9103-git-svn-tracked-directory-removed.sh
@@ -10,30 +10,30 @@
 	mkdir import &&
 	mkdir import/trunk &&
 	echo hello >> import/trunk/README &&
-	svn import -m initial import $svnrepo &&
+	svn import -m initial import "$svnrepo" &&
 	rm -rf import &&
-	svn co $svnrepo/trunk trunk &&
+	svn co "$svnrepo"/trunk trunk &&
 	echo bye bye >> trunk/README &&
-	svn rm -m "gone" $svnrepo/trunk &&
+	svn rm -m "gone" "$svnrepo"/trunk &&
 	rm -rf trunk &&
 	mkdir trunk &&
 	echo "new" > trunk/FOLLOWME &&
-	svn import -m "new trunk" trunk $svnrepo/trunk
+	svn import -m "new trunk" trunk "$svnrepo"/trunk
 '
 
 test_expect_success 'clone repo with git' '
-	git svn clone -s $svnrepo x &&
+	git svn clone -s "$svnrepo" x &&
 	test -f x/FOLLOWME &&
 	test ! -f x/README
 '
 
-test_expect_success 'make sure r2 still has old file' '
+test_expect_success 'make sure r2 still has old file' "
 	cd x &&
-		test -n "$(git svn find-rev r1)" &&
-		git reset --hard $(git svn find-rev r1) &&
+		test -n \"\$(git svn find-rev r1)\" &&
+		git reset --hard \$(git svn find-rev r1) &&
 		test -f README &&
 		test ! -f FOLLOWME &&
-		test x$(git svn find-rev r2) = x
-'
+		test x\$(git svn find-rev r2) = x
+"
 
 test_done
diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh
index 7ba7630..4d964e2 100755
--- a/t/t9104-git-svn-follow-parent.sh
+++ b/t/t9104-git-svn-follow-parent.sh
@@ -6,165 +6,165 @@
 test_description='git-svn fetching'
 . ./lib-git-svn.sh
 
-test_expect_success 'initialize repo' "
+test_expect_success 'initialize repo' '
 	mkdir import &&
 	cd import &&
 	mkdir -p trunk &&
 	echo hello > trunk/readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m "initial" . "$svnrepo" &&
 	cd .. &&
-	svn co $svnrepo wc &&
+	svn co "$svnrepo" wc &&
 	cd wc &&
 	echo world >> trunk/readme &&
 	poke trunk/readme &&
-	svn commit -m 'another commit' &&
+	svn commit -m "another commit" &&
 	svn up &&
 	svn mv trunk thunk &&
 	echo goodbye >> thunk/readme &&
 	poke thunk/readme &&
-	svn commit -m 'bye now' &&
+	svn commit -m "bye now" &&
 	cd ..
-	"
+	'
 
-test_expect_success 'init and fetch a moved directory' "
-	git-svn init --minimize-url -i thunk $svnrepo/thunk &&
+test_expect_success 'init and fetch a moved directory' '
+	git-svn init --minimize-url -i thunk "$svnrepo"/thunk &&
 	git-svn fetch -i thunk &&
-	test \"\`git rev-parse --verify refs/remotes/thunk@2\`\" \
-           = \"\`git rev-parse --verify refs/remotes/thunk~1\`\" &&
-        test \"\`git cat-file blob refs/remotes/thunk:readme |\
-                 sed -n -e '3p'\`\" = goodbye &&
-	test -z \"\`git config --get svn-remote.svn.fetch \
-	         '^trunk:refs/remotes/thunk@2$'\`\"
-	"
+	test "`git rev-parse --verify refs/remotes/thunk@2`" \
+           = "`git rev-parse --verify refs/remotes/thunk~1`" &&
+        test "`git cat-file blob refs/remotes/thunk:readme |\
+                 sed -n -e "3p"`" = goodbye &&
+	test -z "`git config --get svn-remote.svn.fetch \
+	         "^trunk:refs/remotes/thunk@2$"`"
+	'
 
-test_expect_success 'init and fetch from one svn-remote' "
-        git config svn-remote.svn.url $svnrepo &&
+test_expect_success 'init and fetch from one svn-remote' '
+        git config svn-remote.svn.url "$svnrepo" &&
         git config --add svn-remote.svn.fetch \
           trunk:refs/remotes/svn/trunk &&
         git config --add svn-remote.svn.fetch \
           thunk:refs/remotes/svn/thunk &&
         git-svn fetch -i svn/thunk &&
-	test \"\`git rev-parse --verify refs/remotes/svn/trunk\`\" \
-           = \"\`git rev-parse --verify refs/remotes/svn/thunk~1\`\" &&
-        test \"\`git cat-file blob refs/remotes/svn/thunk:readme |\
-                 sed -n -e '3p'\`\" = goodbye
-        "
+	test "`git rev-parse --verify refs/remotes/svn/trunk`" \
+           = "`git rev-parse --verify refs/remotes/svn/thunk~1`" &&
+        test "`git cat-file blob refs/remotes/svn/thunk:readme |\
+                 sed -n -e "3p"`" = goodbye
+        '
 
-test_expect_success 'follow deleted parent' "
-        (svn cp -m 'resurrecting trunk as junk' \
-               $svnrepo/trunk@2 $svnrepo/junk ||
-         svn cp -m 'resurrecting trunk as junk' \
-               -r2 $svnrepo/trunk $svnrepo/junk) &&
+test_expect_success 'follow deleted parent' '
+        (svn cp -m "resurrecting trunk as junk" \
+               "$svnrepo"/trunk@2 "$svnrepo"/junk ||
+         svn cp -m "resurrecting trunk as junk" \
+               -r2 "$svnrepo"/trunk "$svnrepo"/junk) &&
         git config --add svn-remote.svn.fetch \
           junk:refs/remotes/svn/junk &&
         git-svn fetch -i svn/thunk &&
         git-svn fetch -i svn/junk &&
-        test -z \"\`git diff svn/junk svn/trunk\`\" &&
-        test \"\`git merge-base svn/junk svn/trunk\`\" \
-           = \"\`git rev-parse svn/trunk\`\"
-        "
+        test -z "`git diff svn/junk svn/trunk`" &&
+        test "`git merge-base svn/junk svn/trunk`" \
+           = "`git rev-parse svn/trunk`"
+        '
 
-test_expect_success 'follow larger parent' "
+test_expect_success 'follow larger parent' '
         mkdir -p import/trunk/thunk/bump/thud &&
         echo hi > import/trunk/thunk/bump/thud/file &&
-        svn import -m 'import a larger parent' import $svnrepo/larger-parent &&
-        svn cp -m 'hi' $svnrepo/larger-parent $svnrepo/another-larger &&
+        svn import -m "import a larger parent" import "$svnrepo"/larger-parent &&
+        svn cp -m "hi" "$svnrepo"/larger-parent "$svnrepo"/another-larger &&
         git-svn init --minimize-url -i larger \
-          $svnrepo/another-larger/trunk/thunk/bump/thud &&
+          "$svnrepo"/another-larger/trunk/thunk/bump/thud &&
         git-svn fetch -i larger &&
         git rev-parse --verify refs/remotes/larger &&
         git rev-parse --verify \
            refs/remotes/larger-parent/trunk/thunk/bump/thud &&
-        test \"\`git merge-base \
+        test "`git merge-base \
                  refs/remotes/larger-parent/trunk/thunk/bump/thud \
-                 refs/remotes/larger\`\" = \
-             \"\`git rev-parse refs/remotes/larger\`\"
+                 refs/remotes/larger`" = \
+             "`git rev-parse refs/remotes/larger`"
         true
-        "
+        '
 
-test_expect_success 'follow higher-level parent' "
-        svn mkdir -m 'follow higher-level parent' $svnrepo/blob &&
-        svn co $svnrepo/blob blob &&
+test_expect_success 'follow higher-level parent' '
+        svn mkdir -m "follow higher-level parent" "$svnrepo"/blob &&
+        svn co "$svnrepo"/blob blob &&
         cd blob &&
                 echo hi > hi &&
                 svn add hi &&
-                svn commit -m 'hihi' &&
+                svn commit -m "hihi" &&
                 cd ..
-        svn mkdir -m 'new glob at top level' $svnrepo/glob &&
-        svn mv -m 'move blob down a level' $svnrepo/blob $svnrepo/glob/blob &&
-        git-svn init --minimize-url -i blob $svnrepo/glob/blob &&
+        svn mkdir -m "new glob at top level" "$svnrepo"/glob &&
+        svn mv -m "move blob down a level" "$svnrepo"/blob "$svnrepo"/glob/blob &&
+        git-svn init --minimize-url -i blob "$svnrepo"/glob/blob &&
         git-svn fetch -i blob
-        "
+        '
 
-test_expect_success 'follow deleted directory' "
-	svn mv -m 'bye!' $svnrepo/glob/blob/hi $svnrepo/glob/blob/bye &&
-	svn rm -m 'remove glob' $svnrepo/glob &&
-	git-svn init --minimize-url -i glob $svnrepo/glob &&
+test_expect_success 'follow deleted directory' '
+	svn mv -m "bye!" "$svnrepo"/glob/blob/hi "$svnrepo"/glob/blob/bye &&
+	svn rm -m "remove glob" "$svnrepo"/glob &&
+	git-svn init --minimize-url -i glob "$svnrepo"/glob &&
 	git-svn fetch -i glob &&
-	test \"\`git cat-file blob refs/remotes/glob:blob/bye\`\" = hi &&
-	test \"\`git ls-tree refs/remotes/glob | wc -l \`\" -eq 1
-	"
+	test "`git cat-file blob refs/remotes/glob:blob/bye`" = hi &&
+	test "`git ls-tree refs/remotes/glob | wc -l `" -eq 1
+	'
 
 # ref: r9270 of the Subversion repository: (http://svn.collab.net/repos/svn)
 # in trunk/subversion/bindings/swig/perl
-test_expect_success 'follow-parent avoids deleting relevant info' "
+test_expect_success 'follow-parent avoids deleting relevant info' '
 	mkdir -p import/trunk/subversion/bindings/swig/perl/t &&
 	for i in a b c ; do \
-	  echo \$i > import/trunk/subversion/bindings/swig/perl/\$i.pm &&
-	  echo _\$i > import/trunk/subversion/bindings/swig/perl/t/\$i.t; \
+	  echo $i > import/trunk/subversion/bindings/swig/perl/$i.pm &&
+	  echo _$i > import/trunk/subversion/bindings/swig/perl/t/$i.t; \
 	done &&
-	  echo 'bad delete test' > \
+	  echo "bad delete test" > \
 	   import/trunk/subversion/bindings/swig/perl/t/larger-parent &&
-	  echo 'bad delete test 2' > \
+	  echo "bad delete test 2" > \
 	   import/trunk/subversion/bindings/swig/perl/another-larger &&
 	cd import &&
-	  svn import -m 'r9270 test' . $svnrepo/r9270 &&
+	  svn import -m "r9270 test" . "$svnrepo"/r9270 &&
 	cd .. &&
-	svn co $svnrepo/r9270/trunk/subversion/bindings/swig/perl r9270 &&
+	svn co "$svnrepo"/r9270/trunk/subversion/bindings/swig/perl r9270 &&
 	cd r9270 &&
 	  svn mkdir native &&
 	  svn mv t native/t &&
-	  for i in a b c; do svn mv \$i.pm native/\$i.pm; done &&
+	  for i in a b c; do svn mv $i.pm native/$i.pm; done &&
 	  echo z >> native/t/c.t &&
 	  poke native/t/c.t &&
-	  svn commit -m 'reorg test' &&
+	  svn commit -m "reorg test" &&
 	cd .. &&
 	git-svn init --minimize-url -i r9270-t \
-	  $svnrepo/r9270/trunk/subversion/bindings/swig/perl/native/t &&
+	  "$svnrepo"/r9270/trunk/subversion/bindings/swig/perl/native/t &&
 	git-svn fetch -i r9270-t &&
-	test \`git rev-list r9270-t | wc -l\` -eq 2 &&
-	test \"\`git ls-tree --name-only r9270-t~1\`\" = \
-	     \"\`git ls-tree --name-only r9270-t\`\"
-	"
+	test `git rev-list r9270-t | wc -l` -eq 2 &&
+	test "`git ls-tree --name-only r9270-t~1`" = \
+	     "`git ls-tree --name-only r9270-t`"
+	'
 
-test_expect_success "track initial change if it was only made to parent" "
-	svn cp -m 'wheee!' $svnrepo/r9270/trunk $svnrepo/r9270/drunk &&
+test_expect_success "track initial change if it was only made to parent" '
+	svn cp -m "wheee!" "$svnrepo"/r9270/trunk "$svnrepo"/r9270/drunk &&
 	git-svn init --minimize-url -i r9270-d \
-	  $svnrepo/r9270/drunk/subversion/bindings/swig/perl/native/t &&
+	  "$svnrepo"/r9270/drunk/subversion/bindings/swig/perl/native/t &&
 	git-svn fetch -i r9270-d &&
-	test \`git rev-list r9270-d | wc -l\` -eq 3 &&
-	test \"\`git ls-tree --name-only r9270-t\`\" = \
-	     \"\`git ls-tree --name-only r9270-d\`\" &&
-	test \"\`git rev-parse r9270-t\`\" = \
-	     \"\`git rev-parse r9270-d~1\`\"
-	"
+	test `git rev-list r9270-d | wc -l` -eq 3 &&
+	test "`git ls-tree --name-only r9270-t`" = \
+	     "`git ls-tree --name-only r9270-d`" &&
+	test "`git rev-parse r9270-t`" = \
+	     "`git rev-parse r9270-d~1`"
+	'
 
-test_expect_success "track multi-parent paths" "
-	svn cp -m 'resurrect /glob' $svnrepo/r9270 $svnrepo/glob &&
+test_expect_success "track multi-parent paths" '
+	svn cp -m "resurrect /glob" "$svnrepo"/r9270 "$svnrepo"/glob &&
 	git-svn multi-fetch &&
-	test \`git cat-file commit refs/remotes/glob | \
-	       grep '^parent ' | wc -l\` -eq 2
-	"
+	test `git cat-file commit refs/remotes/glob | \
+	       grep "^parent " | wc -l` -eq 2
+	'
 
 test_expect_success "multi-fetch continues to work" "
 	git-svn multi-fetch
 	"
 
-test_expect_success "multi-fetch works off a 'clean' repository" "
-	rm -r $GIT_DIR/svn $GIT_DIR/refs/remotes $GIT_DIR/logs &&
-	mkdir $GIT_DIR/svn &&
+test_expect_success "multi-fetch works off a 'clean' repository" '
+	rm -r "$GIT_DIR/svn" "$GIT_DIR/refs/remotes" "$GIT_DIR/logs" &&
+	mkdir "$GIT_DIR/svn" &&
 	git-svn multi-fetch
-	"
+	'
 
 test_debug 'gitk --all &'
 
diff --git a/t/t9105-git-svn-commit-diff.sh b/t/t9105-git-svn-commit-diff.sh
index 318e172..6323036 100755
--- a/t/t9105-git-svn-commit-diff.sh
+++ b/t/t9105-git-svn-commit-diff.sh
@@ -4,18 +4,18 @@
 test_description='git-svn commit-diff'
 . ./lib-git-svn.sh
 
-test_expect_success 'initialize repo' "
+test_expect_success 'initialize repo' '
 	mkdir import &&
 	cd import &&
 	echo hello > readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m "initial" . "$svnrepo" &&
 	cd .. &&
 	echo hello > readme &&
 	git update-index --add readme &&
-	git commit -a -m 'initial' &&
+	git commit -a -m "initial" &&
 	echo world >> readme &&
-	git commit -a -m 'another'
-	"
+	git commit -a -m "another"
+	'
 
 head=`git rev-parse --verify HEAD^0`
 prev=`git rev-parse --verify HEAD^1`
@@ -24,20 +24,20 @@
 # commit, so only a basic test of functionality is needed since we've
 # already tested commit extensively elsewhere
 
-test_expect_success 'test the commit-diff command' "
-	test -n '$prev' && test -n '$head' &&
-	git-svn commit-diff -r1 '$prev' '$head' '$svnrepo' &&
-	svn co $svnrepo wc &&
+test_expect_success 'test the commit-diff command' '
+	test -n "$prev" && test -n "$head" &&
+	git-svn commit-diff -r1 "$prev" "$head" "$svnrepo" &&
+	svn co "$svnrepo" wc &&
 	cmp readme wc/readme
-	"
+	'
 
-test_expect_success 'commit-diff to a sub-directory (with git-svn config)' "
-	svn import -m 'sub-directory' import $svnrepo/subdir &&
-	git-svn init --minimize-url $svnrepo/subdir &&
+test_expect_success 'commit-diff to a sub-directory (with git-svn config)' '
+	svn import -m "sub-directory" import "$svnrepo"/subdir &&
+	git-svn init --minimize-url "$svnrepo"/subdir &&
 	git-svn fetch &&
-	git-svn commit-diff -r3 '$prev' '$head' &&
-	svn cat $svnrepo/subdir/readme > readme.2 &&
+	git-svn commit-diff -r3 "$prev" "$head" &&
+	svn cat "$svnrepo"/subdir/readme > readme.2 &&
 	cmp readme readme.2
-	"
+	'
 
 test_done
diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh
index f74ab12..58a3a7b 100755
--- a/t/t9106-git-svn-commit-diff-clobber.sh
+++ b/t/t9106-git-svn-commit-diff-clobber.sh
@@ -4,56 +4,56 @@
 test_description='git-svn commit-diff clobber'
 . ./lib-git-svn.sh
 
-test_expect_success 'initialize repo' "
+test_expect_success 'initialize repo' '
 	mkdir import &&
 	cd import &&
 	echo initial > file &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m "initial" . "$svnrepo" &&
 	cd .. &&
 	echo initial > file &&
 	git update-index --add file &&
-	git commit -a -m 'initial'
-	"
-test_expect_success 'commit change from svn side' "
-	svn co $svnrepo t.svn &&
+	git commit -a -m "initial"
+	'
+test_expect_success 'commit change from svn side' '
+	svn co "$svnrepo" t.svn &&
 	cd t.svn &&
 	echo second line from svn >> file &&
 	poke file &&
-	svn commit -m 'second line from svn' &&
+	svn commit -m "second line from svn" &&
 	cd .. &&
 	rm -rf t.svn
-	"
+	'
 
-test_expect_success 'commit conflicting change from git' "
+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
-"
+	git commit -a -m "second line from git" &&
+	! git-svn commit-diff -r1 HEAD~1 HEAD "$svnrepo"
+'
 
-test_expect_success 'commit complementing change from git' "
+test_expect_success 'commit complementing change from git' '
 	git reset --hard HEAD~1 &&
 	echo second line from svn >> file &&
-	git commit -a -m 'second line from svn' &&
+	git commit -a -m "second line from svn" &&
 	echo third line from git >> file &&
-	git commit -a -m 'third line from git' &&
-	git-svn commit-diff -r2 HEAD~1 HEAD $svnrepo
-	"
+	git commit -a -m "third line from git" &&
+	git-svn commit-diff -r2 HEAD~1 HEAD "$svnrepo"
+	'
 
-test_expect_success 'dcommit fails to commit because of conflict' "
-	git-svn init $svnrepo &&
+test_expect_success 'dcommit fails to commit because of conflict' '
+	git-svn init "$svnrepo" &&
 	git-svn fetch &&
 	git reset --hard refs/remotes/git-svn &&
-	svn co $svnrepo t.svn &&
+	svn co "$svnrepo" t.svn &&
 	cd t.svn &&
 	echo fourth line from svn >> file &&
 	poke file &&
-	svn commit -m 'fourth line from svn' &&
+	svn commit -m "fourth line from svn" &&
 	cd .. &&
 	rm -rf t.svn &&
-	echo 'fourth line from git' >> file &&
-	git commit -a -m 'fourth line from git' &&
+	echo "fourth line from git" >> file &&
+	git commit -a -m "fourth line from git" &&
 	! git-svn dcommit
-	"
+	'
 
 test_expect_success 'dcommit does the svn equivalent of an index merge' "
 	git reset --hard refs/remotes/git-svn &&
@@ -66,15 +66,15 @@
 	git-svn dcommit
 	"
 
-test_expect_success 'commit another change from svn side' "
-	svn co $svnrepo t.svn &&
+test_expect_success 'commit another change from svn side' '
+	svn co "$svnrepo" t.svn &&
 	cd t.svn &&
 		echo third line from svn >> file &&
 		poke file &&
-		svn commit -m 'third line from svn' &&
+		svn commit -m "third line from svn" &&
 	cd .. &&
 	rm -rf t.svn
-	"
+	'
 
 test_expect_success 'multiple dcommit from git-svn will not clobber svn' "
 	git reset --hard refs/remotes/git-svn &&
diff --git a/t/t9106-git-svn-dcommit-clobber-series.sh b/t/t9106-git-svn-dcommit-clobber-series.sh
index ca8a00e..a400dc7 100755
--- a/t/t9106-git-svn-dcommit-clobber-series.sh
+++ b/t/t9106-git-svn-dcommit-clobber-series.sh
@@ -4,30 +4,30 @@
 test_description='git-svn dcommit clobber series'
 . ./lib-git-svn.sh
 
-test_expect_success 'initialize repo' "
+test_expect_success 'initialize repo' '
 	mkdir import &&
 	cd import &&
-	awk 'BEGIN { for (i = 1; i < 64; i++) { print i } }' > file
-	svn import -m 'initial' . $svnrepo &&
+	awk "BEGIN { for (i = 1; i < 64; i++) { print i } }" > file
+	svn import -m "initial" . "$svnrepo" &&
 	cd .. &&
-	git svn init $svnrepo &&
+	git svn init "$svnrepo" &&
 	git svn fetch &&
 	test -e file
-	"
+	'
 
-test_expect_success '(supposedly) non-conflicting change from SVN' "
-	test x\"\`sed -n -e 58p < file\`\" = x58 &&
-	test x\"\`sed -n -e 61p < file\`\" = x61 &&
-	svn co $svnrepo tmp &&
+test_expect_success '(supposedly) non-conflicting change from SVN' '
+	test x"`sed -n -e 58p < file`" = x58 &&
+	test x"`sed -n -e 61p < file`" = x61 &&
+	svn co "$svnrepo" tmp &&
 	cd tmp &&
-		perl -i -p -e 's/^58\$/5588/' file &&
-		perl -i -p -e 's/^61\$/6611/' file &&
+		perl -i -p -e "s/^58$/5588/" file &&
+		perl -i -p -e "s/^61$/6611/" file &&
 		poke file &&
-		test x\"\`sed -n -e 58p < file\`\" = x5588 &&
-		test x\"\`sed -n -e 61p < file\`\" = x6611 &&
-		svn commit -m '58 => 5588, 61 => 6611' &&
+		test x"`sed -n -e 58p < file`" = x5588 &&
+		test x"`sed -n -e 61p < file`" = x6611 &&
+		svn commit -m "58 => 5588, 61 => 6611" &&
 		cd ..
-	"
+	'
 
 test_expect_success 'some unrelated changes to git' "
 	echo hi > life &&
diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh
index 0a41d52..d9b553a 100755
--- a/t/t9107-git-svn-migrate.sh
+++ b/t/t9107-git-svn-migrate.sh
@@ -3,61 +3,61 @@
 test_description='git-svn metadata migrations from previous versions'
 . ./lib-git-svn.sh
 
-test_expect_success 'setup old-looking metadata' "
-	cp $GIT_DIR/config $GIT_DIR/config-old-git-svn &&
+test_expect_success 'setup old-looking metadata' '
+	cp "$GIT_DIR"/config "$GIT_DIR"/config-old-git-svn &&
 	mkdir import &&
 	cd import &&
 		for i in trunk branches/a branches/b \
 		         tags/0.1 tags/0.2 tags/0.3; do
-			mkdir -p \$i && \
-			echo hello >> \$i/README || exit 1
+			mkdir -p $i && \
+			echo hello >> $i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . "$svnrepo"
 		cd .. &&
-	git-svn init $svnrepo &&
+	git-svn init "$svnrepo" &&
 	git-svn fetch &&
-	mv $GIT_DIR/svn/* $GIT_DIR/ &&
-	mv $GIT_DIR/svn/.metadata $GIT_DIR/ &&
-	rmdir $GIT_DIR/svn &&
+	mv "$GIT_DIR"/svn/* "$GIT_DIR"/ &&
+	mv "$GIT_DIR"/svn/.metadata "$GIT_DIR"/ &&
+	rmdir "$GIT_DIR"/svn &&
 	git update-ref refs/heads/git-svn-HEAD refs/remotes/git-svn &&
 	git update-ref refs/heads/svn-HEAD refs/remotes/git-svn &&
 	git update-ref -d refs/remotes/git-svn refs/remotes/git-svn
-	"
+	'
 
 head=`git rev-parse --verify refs/heads/git-svn-HEAD^0`
 test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'"
 
-test_expect_success 'initialize old-style (v0) git-svn layout' "
-	mkdir -p $GIT_DIR/git-svn/info $GIT_DIR/svn/info &&
-	echo $svnrepo > $GIT_DIR/git-svn/info/url &&
-	echo $svnrepo > $GIT_DIR/svn/info/url &&
+test_expect_success 'initialize old-style (v0) git-svn layout' '
+	mkdir -p "$GIT_DIR"/git-svn/info "$GIT_DIR"/svn/info &&
+	echo "$svnrepo" > "$GIT_DIR"/git-svn/info/url &&
+	echo "$svnrepo" > "$GIT_DIR"/svn/info/url &&
 	git-svn migrate &&
-	! test -d $GIT_DIR/git-svn &&
+	! test -d "$GIT_DIR"/git-svn &&
 	git rev-parse --verify refs/remotes/git-svn^0 &&
 	git rev-parse --verify refs/remotes/svn^0 &&
-	test \`git config --get svn-remote.svn.url\` = '$svnrepo' &&
-	test \`git config --get svn-remote.svn.fetch\` = \
-             ':refs/remotes/git-svn'
-	"
+	test "$(git config --get svn-remote.svn.url)" = "$svnrepo" &&
+	test `git config --get svn-remote.svn.fetch` = \
+             ":refs/remotes/git-svn"
+	'
 
-test_expect_success 'initialize a multi-repository repo' "
-	git-svn init $svnrepo -T trunk -t tags -b branches &&
+test_expect_success 'initialize a multi-repository repo' '
+	git-svn init "$svnrepo" -T trunk -t tags -b branches &&
 	git config --get-all svn-remote.svn.fetch > fetch.out &&
-	grep '^trunk:refs/remotes/trunk$' fetch.out &&
-	test -n \"\`git config --get svn-remote.svn.branches \
-	            '^branches/\*:refs/remotes/\*$'\`\" &&
-	test -n \"\`git config --get svn-remote.svn.tags \
-	            '^tags/\*:refs/remotes/tags/\*$'\`\" &&
+	grep "^trunk:refs/remotes/trunk$" fetch.out &&
+	test -n "`git config --get svn-remote.svn.branches \
+	            "^branches/\*:refs/remotes/\*$"`" &&
+	test -n "`git config --get svn-remote.svn.tags \
+	            "^tags/\*:refs/remotes/tags/\*$"`" &&
 	git config --unset svn-remote.svn.branches \
-	                        '^branches/\*:refs/remotes/\*$' &&
+	                        "^branches/\*:refs/remotes/\*$" &&
 	git config --unset svn-remote.svn.tags \
-	                        '^tags/\*:refs/remotes/tags/\*$' &&
-	git config --add svn-remote.svn.fetch 'branches/a:refs/remotes/a' &&
-	git config --add svn-remote.svn.fetch 'branches/b:refs/remotes/b' &&
+	                        "^tags/\*:refs/remotes/tags/\*$" &&
+	git config --add svn-remote.svn.fetch "branches/a:refs/remotes/a" &&
+	git config --add svn-remote.svn.fetch "branches/b:refs/remotes/b" &&
 	for i in tags/0.1 tags/0.2 tags/0.3; do
 		git config --add svn-remote.svn.fetch \
-		                 \$i:refs/remotes/\$i || exit 1; done
-	"
+		                 $i:refs/remotes/$i || exit 1; done
+	'
 
 # refs should all be different, but the trees should all be the same:
 test_expect_success 'multi-fetch works on partial urls + paths' "
@@ -73,43 +73,43 @@
 	                         refs/remotes/\$j\`\" ||exit 1; done; done
 	"
 
-test_expect_success 'migrate --minimize on old inited layout' "
+test_expect_success 'migrate --minimize on old inited layout' '
 	git config --unset-all svn-remote.svn.fetch &&
 	git config --unset-all svn-remote.svn.url &&
-	rm -rf $GIT_DIR/svn &&
-	for i in \`cat fetch.out\`; do
-		path=\`expr \$i : '\\([^:]*\\):.*$'\`
-		ref=\`expr \$i : '[^:]*:refs/remotes/\\(.*\\)$'\`
-		if test -z \"\$ref\"; then continue; fi
-		if test -n \"\$path\"; then path=\"/\$path\"; fi
-		( mkdir -p $GIT_DIR/svn/\$ref/info/ &&
-		echo $svnrepo\$path > $GIT_DIR/svn/\$ref/info/url ) || exit 1;
+	rm -rf "$GIT_DIR"/svn &&
+	for i in `cat fetch.out`; do
+		path=`expr $i : "\([^:]*\):.*$"`
+		ref=`expr $i : "[^:]*:refs/remotes/\(.*\)$"`
+		if test -z "$ref"; then continue; fi
+		if test -n "$path"; then path="/$path"; fi
+		( mkdir -p "$GIT_DIR"/svn/$ref/info/ &&
+		echo "$svnrepo"$path > "$GIT_DIR"/svn/$ref/info/url ) || exit 1;
 	done &&
 	git-svn migrate --minimize &&
-	test -z \"\`git config -l |grep -v '^svn-remote\.git-svn\.'\`\" &&
+	test -z "`git config -l |grep -v "^svn-remote\.git-svn\."`" &&
 	git config --get-all svn-remote.svn.fetch > fetch.out &&
-	grep '^trunk:refs/remotes/trunk$' fetch.out &&
-	grep '^branches/a:refs/remotes/a$' fetch.out &&
-	grep '^branches/b:refs/remotes/b$' fetch.out &&
-	grep '^tags/0\.1:refs/remotes/tags/0\.1$' fetch.out &&
-	grep '^tags/0\.2:refs/remotes/tags/0\.2$' fetch.out &&
-	grep '^tags/0\.3:refs/remotes/tags/0\.3$' fetch.out
-	grep '^:refs/remotes/git-svn' fetch.out
-	"
+	grep "^trunk:refs/remotes/trunk$" fetch.out &&
+	grep "^branches/a:refs/remotes/a$" fetch.out &&
+	grep "^branches/b:refs/remotes/b$" fetch.out &&
+	grep "^tags/0\.1:refs/remotes/tags/0\.1$" fetch.out &&
+	grep "^tags/0\.2:refs/remotes/tags/0\.2$" fetch.out &&
+	grep "^tags/0\.3:refs/remotes/tags/0\.3$" fetch.out
+	grep "^:refs/remotes/git-svn" fetch.out
+	'
 
-test_expect_success  ".rev_db auto-converted to .rev_map.UUID" "
+test_expect_success  ".rev_db auto-converted to .rev_map.UUID" '
 	git-svn fetch -i trunk &&
-	test -z \"\$(ls $GIT_DIR/svn/trunk/.rev_db.* 2>/dev/null)\" &&
-	expect=\"\$(ls $GIT_DIR/svn/trunk/.rev_map.*)\" &&
-	test -n \"\$expect\" &&
-	rev_db=\$(echo \$expect | sed -e 's,_map,_db,') &&
-	convert_to_rev_db \$expect \$rev_db &&
-	rm -f \$expect &&
-	test -f \$rev_db &&
+	test -z "$(ls "$GIT_DIR"/svn/trunk/.rev_db.* 2>/dev/null)" &&
+	expect="$(ls "$GIT_DIR"/svn/trunk/.rev_map.*)" &&
+	test -n "$expect" &&
+	rev_db="$(echo $expect | sed -e "s,_map,_db,")" &&
+	convert_to_rev_db "$expect" "$rev_db" &&
+	rm -f "$expect" &&
+	test -f "$rev_db" &&
 	git-svn fetch -i trunk &&
-	test -z \"\$(ls $GIT_DIR/svn/trunk/.rev_db.* 2>/dev/null)\" &&
-	test ! -e $GIT_DIR/svn/trunk/.rev_db &&
-	test -f \$expect
-	"
+	test -z "$(ls "$GIT_DIR"/svn/trunk/.rev_db.* 2>/dev/null)" &&
+	test ! -e "$GIT_DIR"/svn/trunk/.rev_db &&
+	test -f "$expect"
+	'
 
 test_done
diff --git a/t/t9108-git-svn-glob.sh b/t/t9108-git-svn-glob.sh
index db4344c..f6f71d0 100755
--- a/t/t9108-git-svn-glob.sh
+++ b/t/t9108-git-svn-glob.sh
@@ -10,77 +10,77 @@
 initial
 EOF
 
-test_expect_success 'test refspec globbing' "
+test_expect_success 'test refspec globbing' '
 	mkdir -p trunk/src/a trunk/src/b trunk/doc &&
-	echo 'hello world' > trunk/src/a/readme &&
-	echo 'goodbye world' > trunk/src/b/readme &&
-	svn import -m 'initial' trunk $svnrepo/trunk &&
-	svn co $svnrepo tmp &&
+	echo "hello world" > trunk/src/a/readme &&
+	echo "goodbye world" > trunk/src/b/readme &&
+	svn import -m "initial" trunk "$svnrepo"/trunk &&
+	svn co "$svnrepo" tmp &&
 	cd tmp &&
 		mkdir branches tags &&
 		svn add branches tags &&
 		svn cp trunk branches/start &&
-		svn commit -m 'start a new branch' &&
+		svn commit -m "start a new branch" &&
 		svn up &&
-		echo 'hi' >> branches/start/src/b/readme &&
+		echo "hi" >> branches/start/src/b/readme &&
 		poke branches/start/src/b/readme &&
-		echo 'hey' >> branches/start/src/a/readme &&
+		echo "hey" >> branches/start/src/a/readme &&
 		poke branches/start/src/a/readme &&
-		svn commit -m 'hi' &&
+		svn commit -m "hi" &&
 		svn up &&
 		svn cp branches/start tags/end &&
-		echo 'bye' >> tags/end/src/b/readme &&
+		echo "bye" >> tags/end/src/b/readme &&
 		poke tags/end/src/b/readme &&
-		echo 'aye' >> tags/end/src/a/readme &&
+		echo "aye" >> tags/end/src/a/readme &&
 		poke tags/end/src/a/readme &&
-		svn commit -m 'the end' &&
-		echo 'byebye' >> tags/end/src/b/readme &&
+		svn commit -m "the end" &&
+		echo "byebye" >> tags/end/src/b/readme &&
 		poke tags/end/src/b/readme &&
-		svn commit -m 'nothing to see here'
+		svn commit -m "nothing to see here"
 		cd .. &&
-	git config --add svn-remote.svn.url $svnrepo &&
+	git config --add svn-remote.svn.url "$svnrepo" &&
 	git config --add svn-remote.svn.fetch \
-	                 'trunk/src/a:refs/remotes/trunk' &&
+	                 "trunk/src/a:refs/remotes/trunk" &&
 	git config --add svn-remote.svn.branches \
-	                 'branches/*/src/a:refs/remotes/branches/*' &&
+	                 "branches/*/src/a:refs/remotes/branches/*" &&
 	git config --add svn-remote.svn.tags\
-	                 'tags/*/src/a:refs/remotes/tags/*' &&
+	                 "tags/*/src/a:refs/remotes/tags/*" &&
 	git-svn multi-fetch &&
 	git log --pretty=oneline refs/remotes/tags/end | \
-	    sed -e 's/^.\{41\}//' > output.end &&
+	    sed -e "s/^.\{41\}//" > output.end &&
 	cmp expect.end output.end &&
-	test \"\`git rev-parse refs/remotes/tags/end~1\`\" = \
-		\"\`git rev-parse refs/remotes/branches/start\`\" &&
-	test \"\`git rev-parse refs/remotes/branches/start~2\`\" = \
-		\"\`git rev-parse refs/remotes/trunk\`\"
-	"
+	test "`git rev-parse refs/remotes/tags/end~1`" = \
+		"`git rev-parse refs/remotes/branches/start`" &&
+	test "`git rev-parse refs/remotes/branches/start~2`" = \
+		"`git rev-parse refs/remotes/trunk`"
+	'
 
 echo try to try > expect.two
 echo nothing to see here >> expect.two
 cat expect.end >> expect.two
 
-test_expect_success 'test left-hand-side only globbing' "
-	git config --add svn-remote.two.url $svnrepo &&
+test_expect_success 'test left-hand-side only globbing' '
+	git config --add svn-remote.two.url "$svnrepo" &&
 	git config --add svn-remote.two.fetch trunk:refs/remotes/two/trunk &&
 	git config --add svn-remote.two.branches \
-	                 'branches/*:refs/remotes/two/branches/*' &&
+	                 "branches/*:refs/remotes/two/branches/*" &&
 	git config --add svn-remote.two.tags \
-	                 'tags/*:refs/remotes/two/tags/*' &&
+	                 "tags/*:refs/remotes/two/tags/*" &&
 	cd tmp &&
-		echo 'try try' >> tags/end/src/b/readme &&
+		echo "try try" >> tags/end/src/b/readme &&
 		poke tags/end/src/b/readme &&
-		svn commit -m 'try to try'
+		svn commit -m "try to try"
 		cd .. &&
 	git-svn fetch two &&
-	test \`git rev-list refs/remotes/two/tags/end | wc -l\` -eq 6 &&
-	test \`git rev-list refs/remotes/two/branches/start | wc -l\` -eq 3 &&
-	test \`git rev-parse refs/remotes/two/branches/start~2\` = \
-	     \`git rev-parse refs/remotes/two/trunk\` &&
-	test \`git rev-parse refs/remotes/two/tags/end~3\` = \
-	     \`git rev-parse refs/remotes/two/branches/start\` &&
+	test `git rev-list refs/remotes/two/tags/end | wc -l` -eq 6 &&
+	test `git rev-list refs/remotes/two/branches/start | wc -l` -eq 3 &&
+	test `git rev-parse refs/remotes/two/branches/start~2` = \
+	     `git rev-parse refs/remotes/two/trunk` &&
+	test `git rev-parse refs/remotes/two/tags/end~3` = \
+	     `git rev-parse refs/remotes/two/branches/start` &&
 	git log --pretty=oneline refs/remotes/two/tags/end | \
-	    sed -e 's/^.\{41\}//' > output.two &&
+	    sed -e "s/^.\{41\}//" > output.two &&
 	cmp expect.two output.two
-	"
+	'
 
 test_done
diff --git a/t/t9110-git-svn-use-svm-props.sh b/t/t9110-git-svn-use-svm-props.sh
index 6235af4..047659f 100755
--- a/t/t9110-git-svn-use-svm-props.sh
+++ b/t/t9110-git-svn-use-svm-props.sh
@@ -7,15 +7,15 @@
 
 . ./lib-git-svn.sh
 
-test_expect_success 'load svm repo' "
-	svnadmin load -q $rawsvnrepo < ../t9110/svm.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/mirror/arr &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/mirror/argh &&
+test_expect_success 'load svm repo' '
+	svnadmin load -q "$rawsvnrepo" < ../t9110/svm.dump &&
+	git-svn init --minimize-url -R arr -i bar "$svnrepo"/mirror/arr &&
+	git-svn init --minimize-url -R argh -i dir "$svnrepo"/mirror/argh &&
 	git-svn init --minimize-url -R argh -i e \
-	  $svnrepo/mirror/argh/a/b/c/d/e &&
+	  "$svnrepo"/mirror/argh/a/b/c/d/e &&
 	git config svn.useSvmProps true &&
 	git-svn fetch --all
-	"
+	'
 
 uuid=161ce429-a9dd-4828-af4a-52023f968c89
 
diff --git a/t/t9111-git-svn-use-svnsync-props.sh b/t/t9111-git-svn-use-svnsync-props.sh
index ec7dedd..a8d74dc 100755
--- a/t/t9111-git-svn-use-svnsync-props.sh
+++ b/t/t9111-git-svn-use-svnsync-props.sh
@@ -7,14 +7,14 @@
 
 . ./lib-git-svn.sh
 
-test_expect_success 'load svnsync repo' "
-	svnadmin load -q $rawsvnrepo < ../t9111/svnsync.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/bar &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/dir &&
-	git-svn init --minimize-url -R argh -i e $svnrepo/dir/a/b/c/d/e &&
+test_expect_success 'load svnsync repo' '
+	svnadmin load -q "$rawsvnrepo" < ../t9111/svnsync.dump &&
+	git-svn init --minimize-url -R arr -i bar "$svnrepo"/bar &&
+	git-svn init --minimize-url -R argh -i dir "$svnrepo"/dir &&
+	git-svn init --minimize-url -R argh -i e "$svnrepo"/dir/a/b/c/d/e &&
 	git config svn.useSvnsyncProps true &&
 	git-svn fetch --all
-	"
+	'
 
 uuid=161ce429-a9dd-4828-af4a-52023f968c89
 
diff --git a/t/t9112-git-svn-md5less-file.sh b/t/t9112-git-svn-md5less-file.sh
index 646a5f0..d470a92 100755
--- a/t/t9112-git-svn-md5less-file.sh
+++ b/t/t9112-git-svn-md5less-file.sh
@@ -40,8 +40,8 @@
 
 EOF
 
-test_expect_success 'load svn dumpfile' "svnadmin load $rawsvnrepo < dumpfile.svn"
+test_expect_success 'load svn dumpfile' 'svnadmin load "$rawsvnrepo" < dumpfile.svn'
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' 'git-svn init "$svnrepo"'
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 test_done
diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh
index 9ef0db9..31c929b 100755
--- a/t/t9113-git-svn-dcommit-new-file.sh
+++ b/t/t9113-git-svn-dcommit-new-file.sh
@@ -15,18 +15,18 @@
 
 start_svnserve () {
 	svnserve --listen-port $SVNSERVE_PORT \
-	         --root $rawsvnrepo \
+	         --root "$rawsvnrepo" \
 	         --listen-once \
 	         --listen-host 127.0.0.1 &
 }
 
-test_expect_success 'start tracking an empty repo' "
-	svn mkdir -m 'empty dir' $svnrepo/empty-dir &&
-	echo anon-access = write >> $rawsvnrepo/conf/svnserve.conf &&
+test_expect_success 'start tracking an empty repo' '
+	svn mkdir -m "empty dir" "$svnrepo"/empty-dir &&
+	echo anon-access = write >> "$rawsvnrepo"/conf/svnserve.conf &&
 	start_svnserve &&
 	git svn init svn://127.0.0.1:$SVNSERVE_PORT &&
 	git svn fetch
-	"
+	'
 
 test_expect_success 'create files in new directory with dcommit' "
 	mkdir git-new-dir &&
diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh
index 225060b..61d7781 100755
--- a/t/t9114-git-svn-dcommit-merge.sh
+++ b/t/t9114-git-svn-dcommit-merge.sh
@@ -34,35 +34,35 @@
 EOF
 }
 
-test_expect_success 'setup svn repository' "
-	svn co $svnrepo mysvnwork &&
+test_expect_success 'setup svn repository' '
+	svn co "$svnrepo" mysvnwork &&
 	mkdir -p mysvnwork/trunk &&
 	cd mysvnwork &&
 		big_text_block >> trunk/README &&
 		svn add trunk &&
-		svn ci -m 'first commit' trunk &&
+		svn ci -m "first commit" trunk &&
 		cd ..
-	"
+	'
 
-test_expect_success 'setup git mirror and merge' "
-	git svn init $svnrepo -t tags -T trunk -b branches &&
+test_expect_success 'setup git mirror and merge' '
+	git svn init "$svnrepo" -t tags -T trunk -b branches &&
 	git svn fetch &&
 	git checkout --track -b svn remotes/trunk &&
 	git checkout -b merge &&
 	echo new file > new_file &&
 	git add new_file &&
-	git commit -a -m 'New file' &&
+	git commit -a -m "New file" &&
 	echo hello >> README &&
-	git commit -a -m 'hello' &&
+	git commit -a -m "hello" &&
 	echo add some stuff >> new_file &&
-	git commit -a -m 'add some stuff' &&
+	git commit -a -m "add some stuff" &&
 	git checkout svn &&
 	mv -f README tmp &&
 	echo friend > README &&
 	cat tmp >> README &&
-	git commit -a -m 'friend' &&
+	git commit -a -m "friend" &&
 	git pull . merge
-	"
+	'
 
 test_debug 'gitk --all & sleep 1'
 
diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh
index 182299c..f0fbd3a 100755
--- a/t/t9115-git-svn-dcommit-funky-renames.sh
+++ b/t/t9115-git-svn-dcommit-funky-renames.sh
@@ -7,16 +7,16 @@
 
 . ./lib-git-svn.sh
 
-test_expect_success 'load repository with strange names' "
-	svnadmin load -q $rawsvnrepo < ../t9115/funky-names.dump &&
-	start_httpd
-	"
+test_expect_success 'load repository with strange names' '
+	svnadmin load -q "$rawsvnrepo" < ../t9115/funky-names.dump &&
+	start_httpd gtk+
+	'
 
-test_expect_success 'init and fetch repository' "
-	git svn init $svnrepo &&
+test_expect_success 'init and fetch repository' '
+	git svn init "$svnrepo" &&
 	git svn fetch &&
 	git reset --hard git-svn
-	"
+	'
 
 test_expect_success 'create file in existing ugly and empty dir' '
 	mkdir "#{bad_directory_name}" &&
@@ -49,6 +49,39 @@
 	git svn dcommit
 	'
 
+test_expect_success 'add a file with plus signs' '
+	echo .. > +_+ &&
+	git update-index --add +_+ &&
+	git commit -m plus &&
+	mkdir gtk+ &&
+	git mv +_+ gtk+/_+_ &&
+	git commit -m plus_dir &&
+	git svn dcommit
+	'
+
+test_expect_success 'clone the repository to test rebase' '
+	git svn clone "$svnrepo" test-rebase &&
+	cd test-rebase &&
+		echo test-rebase > test-rebase &&
+		git add test-rebase &&
+		git commit -m test-rebase &&
+		cd ..
+	'
+
+test_expect_success 'make a commit to test rebase' '
+		echo test-rebase-main > test-rebase-main &&
+		git add test-rebase-main &&
+		git commit -m test-rebase-main &&
+		git svn dcommit
+	'
+
+test_expect_success 'git-svn rebase works inside a fresh-cloned repository' '
+	cd test-rebase &&
+		git svn rebase &&
+		test -e test-rebase-main &&
+		test -e test-rebase
+	'
+
 stop_httpd
 
 test_done
diff --git a/t/t9116-git-svn-log.sh b/t/t9116-git-svn-log.sh
index e1e8bdf..4b2cc87 100755
--- a/t/t9116-git-svn-log.sh
+++ b/t/t9116-git-svn-log.sh
@@ -6,17 +6,17 @@
 test_description='git-svn log tests'
 . ./lib-git-svn.sh
 
-test_expect_success 'setup repository and import' "
+test_expect_success 'setup repository and import' '
 	mkdir import &&
 	cd import &&
 		for i in trunk branches/a branches/b \
 		         tags/0.1 tags/0.2 tags/0.3; do
-			mkdir -p \$i && \
-			echo hello >> \$i/README || exit 1
+			mkdir -p $i && \
+			echo hello >> $i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . "$svnrepo"
 		cd .. &&
-	git-svn init $svnrepo -T trunk -b branches -t tags &&
+	git-svn init "$svnrepo" -T trunk -b branches -t tags &&
 	git-svn fetch &&
 	git reset --hard trunk &&
 	echo bye >> README &&
@@ -37,7 +37,7 @@
 	echo try >> README &&
 	git commit -a -m try &&
 	git svn dcommit
-	"
+	'
 
 test_expect_success 'run log' "
 	git reset --hard a &&
diff --git a/t/t9117-git-svn-init-clone.sh b/t/t9117-git-svn-init-clone.sh
index d482b40..7a689bb 100755
--- a/t/t9117-git-svn-init-clone.sh
+++ b/t/t9117-git-svn-init-clone.sh
@@ -13,43 +13,43 @@
 mkdir tmp
 cd tmp
 
-test_expect_success 'setup svnrepo' "
+test_expect_success 'setup svnrepo' '
 	mkdir project project/trunk project/branches project/tags &&
 	echo foo > project/trunk/foo &&
-	svn import -m '$test_description' project $svnrepo/project &&
+	svn import -m "$test_description" project "$svnrepo"/project &&
 	rm -rf project
-	"
+	'
 
-test_expect_success 'basic clone' "
+test_expect_success 'basic clone' '
 	test ! -d trunk &&
-	git svn clone $svnrepo/project/trunk &&
+	git svn clone "$svnrepo"/project/trunk &&
 	test -d trunk/.git/svn &&
 	test -e trunk/foo &&
 	rm -rf trunk
-	"
+	'
 
-test_expect_success 'clone to target directory' "
+test_expect_success 'clone to target directory' '
 	test ! -d target &&
-	git svn clone $svnrepo/project/trunk target &&
+	git svn clone "$svnrepo"/project/trunk target &&
 	test -d target/.git/svn &&
 	test -e target/foo &&
 	rm -rf target
-	"
+	'
 
-test_expect_success 'clone with --stdlayout' "
+test_expect_success 'clone with --stdlayout' '
 	test ! -d project &&
-	git svn clone -s $svnrepo/project &&
+	git svn clone -s "$svnrepo"/project &&
 	test -d project/.git/svn &&
 	test -e project/foo &&
 	rm -rf project
-	"
+	'
 
-test_expect_success 'clone to target directory with --stdlayout' "
+test_expect_success 'clone to target directory with --stdlayout' '
 	test ! -d target &&
-	git svn clone -s $svnrepo/project target &&
+	git svn clone -s "$svnrepo"/project target &&
 	test -d target/.git/svn &&
 	test -e target/foo &&
 	rm -rf target
-	"
+	'
 
 test_done
diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh
index 640bb06..3281cbd 100755
--- a/t/t9118-git-svn-funky-branch-names.sh
+++ b/t/t9118-git-svn-funky-branch-names.sh
@@ -6,25 +6,25 @@
 test_description='git-svn funky branch names'
 . ./lib-git-svn.sh
 
-test_expect_success 'setup svnrepo' "
+test_expect_success 'setup svnrepo' '
 	mkdir project project/trunk project/branches project/tags &&
 	echo foo > project/trunk/foo &&
-	svn import -m '$test_description' project \"$svnrepo/pr ject\" &&
+	svn import -m "$test_description" project "$svnrepo/pr ject" &&
 	rm -rf project &&
-	svn cp -m 'fun' \"$svnrepo/pr ject/trunk\" \
-	                \"$svnrepo/pr ject/branches/fun plugin\" &&
-	svn cp -m 'more fun!' \"$svnrepo/pr ject/branches/fun plugin\" \
-	                      \"$svnrepo/pr ject/branches/more fun plugin!\" &&
+	svn cp -m "fun" "$svnrepo/pr ject/trunk" \
+	                "$svnrepo/pr ject/branches/fun plugin" &&
+	svn cp -m "more fun!" "$svnrepo/pr ject/branches/fun plugin" \
+	                      "$svnrepo/pr ject/branches/more fun plugin!" &&
 	start_httpd
-	"
+	'
 
-test_expect_success 'test clone with funky branch names' "
-	git svn clone -s \"$svnrepo/pr ject\" project &&
+test_expect_success 'test clone with funky branch names' '
+	git svn clone -s "$svnrepo/pr ject" project &&
 	cd project &&
-		git rev-parse 'refs/remotes/fun%20plugin' &&
-		git rev-parse 'refs/remotes/more%20fun%20plugin!' &&
+		git rev-parse "refs/remotes/fun%20plugin" &&
+		git rev-parse "refs/remotes/more%20fun%20plugin!" &&
 	cd ..
-	"
+	'
 
 test_expect_success 'test dcommit to funky branch' "
 	cd project &&
diff --git a/t/t9120-git-svn-clone-with-percent-escapes.sh b/t/t9120-git-svn-clone-with-percent-escapes.sh
index 9a4eabe..5979e13 100755
--- a/t/t9120-git-svn-clone-with-percent-escapes.sh
+++ b/t/t9120-git-svn-clone-with-percent-escapes.sh
@@ -6,13 +6,13 @@
 test_description='git-svn clone with percent escapes'
 . ./lib-git-svn.sh
 
-test_expect_success 'setup svnrepo' "
+test_expect_success 'setup svnrepo' '
 	mkdir project project/trunk project/branches project/tags &&
 	echo foo > project/trunk/foo &&
-	svn import -m '$test_description' project '$svnrepo/pr ject' &&
+	svn import -m "$test_description" project "$svnrepo/pr ject" &&
 	rm -rf project &&
 	start_httpd
-"
+'
 
 if test "$SVN_HTTPD_PORT" = ""
 then
diff --git a/t/t9121-git-svn-fetch-renamed-dir.sh b/t/t9121-git-svn-fetch-renamed-dir.sh
index 5143ed6..99230b0 100755
--- a/t/t9121-git-svn-fetch-renamed-dir.sh
+++ b/t/t9121-git-svn-fetch-renamed-dir.sh
@@ -7,14 +7,14 @@
 
 . ./lib-git-svn.sh
 
-test_expect_success 'load repository with renamed directory' "
-	svnadmin load -q $rawsvnrepo < ../t9121/renamed-dir.dump
-	"
+test_expect_success 'load repository with renamed directory' '
+	svnadmin load -q "$rawsvnrepo" < ../t9121/renamed-dir.dump
+	'
 
-test_expect_success 'init and fetch repository' "
-	git svn init $svnrepo/newname &&
+test_expect_success 'init and fetch repository' '
+	git svn init "$svnrepo/newname" &&
 	git svn fetch
-	"
+	'
 
 test_done
 
diff --git a/t/t9122-git-svn-author.sh b/t/t9122-git-svn-author.sh
new file mode 100755
index 0000000..1190576
--- /dev/null
+++ b/t/t9122-git-svn-author.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+
+test_description='git svn authorship'
+. ./lib-git-svn.sh
+
+test_expect_success 'setup svn repository' '
+	svn checkout "$svnrepo" work.svn &&
+	(
+		cd work.svn &&
+		echo >file
+		svn add file
+		svn commit -m "first commit" file
+	)
+'
+
+test_expect_success 'interact with it via git-svn' '
+	mkdir work.git &&
+	(
+		cd work.git &&
+		git svn init "$svnrepo"
+		git svn fetch &&
+
+		echo modification >file &&
+		test_tick &&
+		git commit -a -m second &&
+
+		test_tick &&
+		git svn dcommit &&
+
+		echo "further modification" >file &&
+		test_tick &&
+		git commit -a -m third &&
+
+		test_tick &&
+		git svn --add-author-from dcommit &&
+
+		echo "yet further modification" >file &&
+		test_tick &&
+		git commit -a -m fourth &&
+
+		test_tick &&
+		git svn --add-author-from --use-log-author dcommit &&
+
+		git log &&
+
+		git show -s HEAD^^ >../actual.2 &&
+		git show -s HEAD^  >../actual.3 &&
+		git show -s HEAD   >../actual.4
+
+	) &&
+
+	# Make sure that --add-author-from without --use-log-author
+	# did not affect the authorship information
+	myself=$(grep "^Author: " actual.2) &&
+	unaffected=$(grep "^Author: " actual.3) &&
+	test "z$myself" = "z$unaffected" &&
+
+	# Make sure lack of --add-author-from did not add cruft
+	! grep "^    From: A U Thor " actual.2 &&
+
+	# Make sure --add-author-from added cruft
+	grep "^    From: A U Thor " actual.3 &&
+	grep "^    From: A U Thor " actual.4 &&
+
+	# Make sure --add-author-from with --use-log-author affected
+	# the authorship information
+	grep "^Author: A U Thor " actual.4 &&
+
+	# Make sure there are no commit messages with excess blank lines
+	test $(grep "^ " actual.2 | wc -l) = 3 &&
+	test $(grep "^ " actual.3 | wc -l) = 5 &&
+	test $(grep "^ " actual.4 | wc -l) = 5 &&
+
+	# Make sure there are no svn commit messages with excess blank lines
+	(
+		cd work.svn &&
+		svn up &&
+		
+		test $(svn log -r2:2 | wc -l) = 5 &&
+		test $(svn log -r4:4 | wc -l) = 7
+	)
+'
+
+test_done
diff --git a/t/t9123-git-svn-rebuild-with-rewriteroot.sh b/t/t9123-git-svn-rebuild-with-rewriteroot.sh
new file mode 100755
index 0000000..c18878f
--- /dev/null
+++ b/t/t9123-git-svn-rebuild-with-rewriteroot.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Jan Krüger
+#
+
+test_description='git-svn respects rewriteRoot during rebuild'
+
+. ./lib-git-svn.sh
+
+mkdir import
+cd import
+	touch foo
+	svn import -m 'import for git-svn' . "$svnrepo" >/dev/null
+cd ..
+rm -rf import
+
+test_expect_success 'init, fetch and checkout repository' '
+	git svn init --rewrite-root=http://invalid.invalid/ "$svnrepo" &&
+	git svn fetch
+	git checkout -b mybranch remotes/git-svn
+	'
+
+test_expect_success 'remove rev_map' '
+	rm "$GIT_SVN_DIR"/.rev_map.*
+	'
+
+test_expect_success 'rebuild rev_map' '
+	git svn rebase >/dev/null
+	'
+
+test_done
+
diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh
index 42b144b..b1dc32d 100755
--- a/t/t9200-git-cvsexportcommit.sh
+++ b/t/t9200-git-cvsexportcommit.sh
@@ -297,4 +297,21 @@
 
 '
 
+test_expect_success 'use the same checkout for Git and CVS' '
+
+	(mkdir shared &&
+	 cd shared &&
+	 unset GIT_DIR &&
+	 cvs co . &&
+	 git init &&
+	 git add " space" &&
+	 git commit -m "fake initial commit" &&
+	 echo Hello >> " space" &&
+	 git commit -m "Another change" " space" &&
+	 git cvsexportcommit -W -p -u -c HEAD &&
+	 grep Hello " space" &&
+	 git diff-files)
+
+'
+
 test_done
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index c4f4465..5edf56f 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -74,7 +74,7 @@
 test_expect_success \
 	'A: verify commit' \
 	'git cat-file commit master | sed 1d >actual &&
-	git diff expect actual'
+	test_cmp expect actual'
 
 cat >expect <<EOF
 100644 blob file2
@@ -84,22 +84,22 @@
 test_expect_success \
 	'A: verify tree' \
 	'git cat-file -p master^{tree} | sed "s/ [0-9a-f]*	/ /" >actual &&
-	 git diff expect actual'
+	 test_cmp expect actual'
 
 echo "$file2_data" >expect
 test_expect_success \
 	'A: verify file2' \
-	'git cat-file blob master:file2 >actual && git diff expect actual'
+	'git cat-file blob master:file2 >actual && test_cmp expect actual'
 
 echo "$file3_data" >expect
 test_expect_success \
 	'A: verify file3' \
-	'git cat-file blob master:file3 >actual && git diff expect actual'
+	'git cat-file blob master:file3 >actual && test_cmp expect actual'
 
 printf "$file4_data" >expect
 test_expect_success \
 	'A: verify file4' \
-	'git cat-file blob master:file4 >actual && git diff expect actual'
+	'git cat-file blob master:file4 >actual && test_cmp expect actual'
 
 cat >expect <<EOF
 :2 `git rev-parse --verify master:file2`
@@ -109,7 +109,7 @@
 EOF
 test_expect_success \
 	'A: verify marks output' \
-	'git diff expect marks.out'
+	'test_cmp expect marks.out'
 
 test_expect_success \
 	'A: verify marks import' \
@@ -117,7 +117,7 @@
 		--import-marks=marks.out \
 		--export-marks=marks.new \
 		</dev/null &&
-	git diff -u expect marks.new'
+	test_cmp expect marks.new'
 
 test_tick
 cat >input <<INPUT_END
@@ -259,7 +259,7 @@
 test_expect_success \
 	'C: verify commit' \
 	'git cat-file commit branch | sed 1d >actual &&
-	 git diff expect actual'
+	 test_cmp expect actual'
 
 cat >expect <<EOF
 :000000 100755 0000000000000000000000000000000000000000 f1fb5da718392694d0076d677d6d0e364c79b0bc A	file2/newf
@@ -316,13 +316,13 @@
 test_expect_success \
 	'D: verify file5' \
 	'git cat-file blob branch:newdir/interesting >actual &&
-	 git diff expect actual'
+	 test_cmp expect actual'
 
 echo "$file6_data" >expect
 test_expect_success \
 	'D: verify file6' \
 	'git cat-file blob branch:newdir/exec.sh >actual &&
-	 git diff expect actual'
+	 test_cmp expect actual'
 
 ###
 ### series E
@@ -358,7 +358,7 @@
 test_expect_success \
 	'E: verify commit' \
 	'git cat-file commit branch | sed 1,2d >actual &&
-	git diff expect actual'
+	test_cmp expect actual'
 
 ###
 ### series F
@@ -411,7 +411,7 @@
 test_expect_success \
 	'F: verify other commit' \
 	'git cat-file commit other >actual &&
-	git diff expect actual'
+	test_cmp expect actual'
 
 ###
 ### series G
@@ -489,7 +489,7 @@
 test_expect_success \
 	'H: verify file' \
 	'git cat-file blob H:h/e/l/lo >actual &&
-	 git diff expect actual'
+	 test_cmp expect actual'
 
 ###
 ### series I
@@ -515,7 +515,7 @@
 test_expect_success \
 	'I: verify edge list' \
 	'sed -e s/pack-.*pack/pack-.pack/ edges.list >actual &&
-	 git diff expect actual'
+	 test_cmp expect actual'
 
 ###
 ### series J
@@ -625,7 +625,7 @@
     'L: verify internal tree sorting' \
 	'git-fast-import <input &&
 	 git diff-tree --abbrev --raw L^ L >output &&
-	 git diff expect output'
+	 test_cmp expect output'
 
 ###
 ### series M
@@ -885,7 +885,7 @@
 	 test 8 = `find .git/objects/pack -type f | wc -l` &&
 	 test `git rev-parse refs/tags/O3-2nd` = `git rev-parse O3^` &&
 	 git log --reverse --pretty=oneline O3 | sed s/^.*z// >actual &&
-	 git diff expect actual'
+	 test_cmp expect actual'
 
 cat >input <<INPUT_END
 commit refs/heads/O4
@@ -916,6 +916,6 @@
 	'O: progress outputs as requested by input' \
 	'git-fast-import <input >actual &&
 	 grep "progress " <input >expect &&
-	 git diff expect actual'
+	 test_cmp expect actual'
 
 test_done
diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
index 166b43f..e97aaa6 100755
--- a/t/t9400-git-cvsserver-server.sh
+++ b/t/t9400-git-cvsserver-server.sh
@@ -153,21 +153,21 @@
    tail log | grep "^error 1 Conflicting roots specified$"'
 
 test_expect_success 'req_Root (strict paths)' \
-  'cat request-anonymous | git-cvsserver --strict-paths pserver $SERVERDIR >log 2>&1 &&
+  'cat request-anonymous | git-cvsserver --strict-paths pserver "$SERVERDIR" >log 2>&1 &&
    sed -ne \$p log | grep "^I LOVE YOU$"'
 
 test_expect_success 'req_Root failure (strict-paths)' '
     ! cat request-anonymous |
-    git-cvsserver --strict-paths pserver $WORKDIR >log 2>&1
+    git-cvsserver --strict-paths pserver "$WORKDIR" >log 2>&1
 '
 
 test_expect_success 'req_Root (w/o strict-paths)' \
-  'cat request-anonymous | git-cvsserver pserver $WORKDIR/ >log 2>&1 &&
+  'cat request-anonymous | git-cvsserver pserver "$WORKDIR/" >log 2>&1 &&
    sed -ne \$p log | grep "^I LOVE YOU$"'
 
 test_expect_success 'req_Root failure (w/o strict-paths)' '
     ! cat request-anonymous |
-    git-cvsserver pserver $WORKDIR/gitcvs >log 2>&1
+    git-cvsserver pserver "$WORKDIR/gitcvs" >log 2>&1
 '
 
 cat >request-base  <<EOF
@@ -180,25 +180,25 @@
 EOF
 
 test_expect_success 'req_Root (base-path)' \
-  'cat request-base | git-cvsserver --strict-paths --base-path $WORKDIR/ pserver $SERVERDIR >log 2>&1 &&
+  'cat request-base | git-cvsserver --strict-paths --base-path "$WORKDIR/" pserver "$SERVERDIR" >log 2>&1 &&
    sed -ne \$p log | grep "^I LOVE YOU$"'
 
 test_expect_success 'req_Root failure (base-path)' '
     ! cat request-anonymous |
-    git-cvsserver --strict-paths --base-path $WORKDIR pserver $SERVERDIR >log 2>&1
+    git-cvsserver --strict-paths --base-path "$WORKDIR" pserver "$SERVERDIR" >log 2>&1
 '
 
 GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled false || exit 1
 
 test_expect_success 'req_Root (export-all)' \
-  'cat request-anonymous | git-cvsserver --export-all pserver $WORKDIR >log 2>&1 &&
+  'cat request-anonymous | git-cvsserver --export-all pserver "$WORKDIR" >log 2>&1 &&
    sed -ne \$p log | grep "^I LOVE YOU$"'
 
 test_expect_success 'req_Root failure (export-all w/o whitelist)' \
   '! (cat request-anonymous | git-cvsserver --export-all pserver >log 2>&1 || false)'
 
 test_expect_success 'req_Root (everything together)' \
-  'cat request-base | git-cvsserver --export-all --strict-paths --base-path $WORKDIR/ pserver $SERVERDIR >log 2>&1 &&
+  'cat request-base | git-cvsserver --export-all --strict-paths --base-path "$WORKDIR/" pserver "$SERVERDIR" >log 2>&1 &&
    sed -ne \$p log | grep "^I LOVE YOU$"'
 
 GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true || exit 1
diff --git a/t/t9401-git-cvsserver-crlf.sh b/t/t9401-git-cvsserver-crlf.sh
new file mode 100755
index 0000000..e27a1c5
--- /dev/null
+++ b/t/t9401-git-cvsserver-crlf.sh
@@ -0,0 +1,337 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Matthew Ogilvie
+# Parts adapted from other tests.
+#
+
+test_description='git-cvsserver -kb modes
+
+tests -kb mode for binary files when accessing a git
+repository using cvs CLI client via git-cvsserver server'
+
+. ./test-lib.sh
+
+q_to_nul () {
+    perl -pe 'y/Q/\000/'
+}
+
+q_to_cr () {
+    tr Q '\015'
+}
+
+marked_as () {
+    foundEntry="$(grep "^/$2/" "$1/CVS/Entries")"
+    if [ x"$foundEntry" = x"" ] ; then
+       echo "NOT FOUND: $1 $2 1 $3" >> "${WORKDIR}/marked.log"
+       return 1
+    fi
+    test x"$(grep "^/$2/" "$1/CVS/Entries" | cut -d/ -f5)" = x"$3"
+    stat=$?
+    echo "$1 $2 $stat '$3'" >> "${WORKDIR}/marked.log"
+    return $stat
+}
+
+not_present() {
+    foundEntry="$(grep "^/$2/" "$1/CVS/Entries")"
+    if [ -r "$1/$2" ] ; then
+        echo "Error: File still exists: $1 $2" >> "${WORKDIR}/marked.log"
+        return 1;
+    fi
+    if [ x"$foundEntry" != x"" ] ; then
+        echo "Error: should not have found: $1 $2" >> "${WORKDIR}/marked.log"
+        return 1;
+    else
+        echo "Correctly not found: $1 $2" >> "${WORKDIR}/marked.log"
+        return 0;
+    fi
+}
+
+cvs >/dev/null 2>&1
+if test $? -ne 1
+then
+    test_expect_success 'skipping git-cvsserver tests, cvs not found' :
+    test_done
+    exit
+fi
+perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || {
+    test_expect_success 'skipping git-cvsserver tests, Perl SQLite interface unavailable' :
+    test_done
+    exit
+}
+
+unset GIT_DIR GIT_CONFIG
+WORKDIR=$(pwd)
+SERVERDIR=$(pwd)/gitcvs.git
+git_config="$SERVERDIR/config"
+CVSROOT=":fork:$SERVERDIR"
+CVSWORK="$(pwd)/cvswork"
+CVS_SERVER=git-cvsserver
+export CVSROOT CVS_SERVER
+
+rm -rf "$CVSWORK" "$SERVERDIR"
+test_expect_success 'setup' '
+    echo "Simple text file" >textfile.c &&
+    echo "File with embedded NUL: Q <- there" | q_to_nul > binfile.bin &&
+    mkdir subdir &&
+    echo "Another text file" > subdir/file.h &&
+    echo "Another binary: Q (this time CR)" | q_to_cr > subdir/withCr.bin &&
+    echo "Mixed up NUL, but marked text: Q <- there" | q_to_nul > mixedUp.c
+    echo "Unspecified" > subdir/unspecified.other &&
+    echo "/*.bin -crlf" > .gitattributes &&
+    echo "/*.c crlf" >> .gitattributes &&
+    echo "subdir/*.bin -crlf" >> .gitattributes &&
+    echo "subdir/*.c crlf" >> .gitattributes &&
+    echo "subdir/file.h crlf" >> .gitattributes &&
+    git add .gitattributes textfile.c binfile.bin mixedUp.c subdir/* &&
+    git commit -q -m "First Commit" &&
+    git clone -q --local --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 &&
+    GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true &&
+    GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log"
+'
+
+test_expect_success 'cvs co (default crlf)' '
+    GIT_CONFIG="$git_config" cvs -Q co -d cvswork master >cvs.log 2>&1 &&
+    test x"$(grep '/-k' cvswork/CVS/Entries cvswork/subdir/CVS/Entries)" = x""
+'
+
+rm -rf cvswork
+test_expect_success 'cvs co (allbinary)' '
+    GIT_DIR="$SERVERDIR" git config --bool gitcvs.allbinary true &&
+    GIT_CONFIG="$git_config" cvs -Q co -d cvswork master >cvs.log 2>&1 &&
+    marked_as cvswork textfile.c -kb &&
+    marked_as cvswork binfile.bin -kb &&
+    marked_as cvswork .gitattributes -kb &&
+    marked_as cvswork mixedUp.c -kb &&
+    marked_as cvswork/subdir withCr.bin -kb &&
+    marked_as cvswork/subdir file.h -kb &&
+    marked_as cvswork/subdir unspecified.other -kb
+'
+
+rm -rf cvswork cvs.log
+test_expect_success 'cvs co (use attributes/allbinary)' '
+    GIT_DIR="$SERVERDIR" git config --bool gitcvs.usecrlfattr true &&
+    GIT_CONFIG="$git_config" cvs -Q co -d cvswork master >cvs.log 2>&1 &&
+    marked_as cvswork textfile.c "" &&
+    marked_as cvswork binfile.bin -kb &&
+    marked_as cvswork .gitattributes -kb &&
+    marked_as cvswork mixedUp.c "" &&
+    marked_as cvswork/subdir withCr.bin -kb &&
+    marked_as cvswork/subdir file.h "" &&
+    marked_as cvswork/subdir unspecified.other -kb
+'
+
+rm -rf cvswork
+test_expect_success 'cvs co (use attributes)' '
+    GIT_DIR="$SERVERDIR" git config --bool gitcvs.allbinary false &&
+    GIT_CONFIG="$git_config" cvs -Q co -d cvswork master >cvs.log 2>&1 &&
+    marked_as cvswork textfile.c "" &&
+    marked_as cvswork binfile.bin -kb &&
+    marked_as cvswork .gitattributes "" &&
+    marked_as cvswork mixedUp.c "" &&
+    marked_as cvswork/subdir withCr.bin -kb &&
+    marked_as cvswork/subdir file.h "" &&
+    marked_as cvswork/subdir unspecified.other ""
+'
+
+test_expect_success 'adding files' '
+    cd cvswork/subdir &&
+    echo "more text" > src.c &&
+    GIT_CONFIG="$git_config" cvs -Q add src.c >cvs.log 2>&1 &&
+    marked_as . src.c "" &&
+    echo "psuedo-binary" > temp.bin &&
+    cd .. &&
+    GIT_CONFIG="$git_config" cvs -Q add subdir/temp.bin >cvs.log 2>&1 &&
+    marked_as subdir temp.bin "-kb" &&
+    cd subdir &&
+    GIT_CONFIG="$git_config" cvs -Q ci -m "adding files" >cvs.log 2>&1 &&
+    marked_as . temp.bin "-kb" &&
+    marked_as . src.c ""
+'
+
+cd "$WORKDIR"
+test_expect_success 'updating' '
+    git pull gitcvs.git &&
+    echo 'hi' > subdir/newfile.bin &&
+    echo 'junk' > subdir/file.h &&
+    echo 'hi' > subdir/newfile.c &&
+    echo 'hello' >> binfile.bin &&
+    git add subdir/newfile.bin subdir/file.h subdir/newfile.c binfile.bin &&
+    git commit -q -m "Add and change some files" &&
+    git push gitcvs.git >/dev/null &&
+    cd cvswork &&
+    GIT_CONFIG="$git_config" cvs -Q update &&
+    cd .. &&
+    marked_as cvswork textfile.c "" &&
+    marked_as cvswork binfile.bin -kb &&
+    marked_as cvswork .gitattributes "" &&
+    marked_as cvswork mixedUp.c "" &&
+    marked_as cvswork/subdir withCr.bin -kb &&
+    marked_as cvswork/subdir file.h "" &&
+    marked_as cvswork/subdir unspecified.other "" &&
+    marked_as cvswork/subdir newfile.bin -kb &&
+    marked_as cvswork/subdir newfile.c "" &&
+    echo "File with embedded NUL: Q <- there" | q_to_nul > tmpExpect1 &&
+    echo "hello" >> tmpExpect1 &&
+    cmp cvswork/binfile.bin tmpExpect1
+'
+
+rm -rf cvswork
+test_expect_success 'cvs co (use attributes/guess)' '
+    GIT_DIR="$SERVERDIR" git config gitcvs.allbinary guess &&
+    GIT_CONFIG="$git_config" cvs -Q co -d cvswork master >cvs.log 2>&1 &&
+    marked_as cvswork textfile.c "" &&
+    marked_as cvswork binfile.bin -kb &&
+    marked_as cvswork .gitattributes "" &&
+    marked_as cvswork mixedUp.c "" &&
+    marked_as cvswork/subdir withCr.bin -kb &&
+    marked_as cvswork/subdir file.h "" &&
+    marked_as cvswork/subdir unspecified.other "" &&
+    marked_as cvswork/subdir newfile.bin -kb &&
+    marked_as cvswork/subdir newfile.c ""
+'
+
+test_expect_success 'setup multi-line files' '
+    ( echo "line 1" &&
+      echo "line 2" &&
+      echo "line 3" &&
+      echo "line 4 with NUL: Q <-" ) | q_to_nul > multiline.c &&
+    git add multiline.c &&
+    ( echo "line 1" &&
+      echo "line 2" &&
+      echo "line 3" &&
+      echo "line 4" ) | q_to_nul > multilineTxt.c &&
+    git add multilineTxt.c &&
+    git commit -q -m "multiline files" &&
+    git push gitcvs.git >/dev/null
+'
+
+rm -rf cvswork
+test_expect_success 'cvs co (guess)' '
+    GIT_DIR="$SERVERDIR" git config --bool gitcvs.usecrlfattr false &&
+    GIT_CONFIG="$git_config" cvs -Q co -d cvswork master >cvs.log 2>&1 &&
+    marked_as cvswork textfile.c "" &&
+    marked_as cvswork binfile.bin -kb &&
+    marked_as cvswork .gitattributes "" &&
+    marked_as cvswork mixedUp.c -kb &&
+    marked_as cvswork multiline.c -kb &&
+    marked_as cvswork multilineTxt.c "" &&
+    marked_as cvswork/subdir withCr.bin -kb &&
+    marked_as cvswork/subdir file.h "" &&
+    marked_as cvswork/subdir unspecified.other "" &&
+    marked_as cvswork/subdir newfile.bin "" &&
+    marked_as cvswork/subdir newfile.c ""
+'
+
+test_expect_success 'cvs co another copy (guess)' '
+    GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 master >cvs.log 2>&1 &&
+    marked_as cvswork2 textfile.c "" &&
+    marked_as cvswork2 binfile.bin -kb &&
+    marked_as cvswork2 .gitattributes "" &&
+    marked_as cvswork2 mixedUp.c -kb &&
+    marked_as cvswork2 multiline.c -kb &&
+    marked_as cvswork2 multilineTxt.c "" &&
+    marked_as cvswork2/subdir withCr.bin -kb &&
+    marked_as cvswork2/subdir file.h "" &&
+    marked_as cvswork2/subdir unspecified.other "" &&
+    marked_as cvswork2/subdir newfile.bin "" &&
+    marked_as cvswork2/subdir newfile.c ""
+'
+
+test_expect_success 'add text (guess)' '
+    cd cvswork &&
+    echo "simpleText" > simpleText.c &&
+    GIT_CONFIG="$git_config" cvs -Q add simpleText.c &&
+    cd .. &&
+    marked_as cvswork simpleText.c ""
+'
+
+test_expect_success 'add bin (guess)' '
+    cd cvswork &&
+    echo "simpleBin: NUL: Q <- there" | q_to_nul > simpleBin.bin &&
+    GIT_CONFIG="$git_config" cvs -Q add simpleBin.bin &&
+    cd .. &&
+    marked_as cvswork simpleBin.bin -kb
+'
+
+test_expect_success 'remove files (guess)' '
+    cd cvswork &&
+    GIT_CONFIG="$git_config" cvs -Q rm -f subdir/file.h &&
+    cd subdir &&
+    GIT_CONFIG="$git_config" cvs -Q rm -f withCr.bin &&
+    cd ../.. &&
+    marked_as cvswork/subdir withCr.bin -kb &&
+    marked_as cvswork/subdir file.h ""
+'
+
+test_expect_success 'cvs ci (guess)' '
+    cd cvswork &&
+    GIT_CONFIG="$git_config" cvs -Q ci -m "add/rm files" >cvs.log 2>&1 &&
+    cd .. &&
+    marked_as cvswork textfile.c "" &&
+    marked_as cvswork binfile.bin -kb &&
+    marked_as cvswork .gitattributes "" &&
+    marked_as cvswork mixedUp.c -kb &&
+    marked_as cvswork multiline.c -kb &&
+    marked_as cvswork multilineTxt.c "" &&
+    not_present cvswork/subdir withCr.bin &&
+    not_present cvswork/subdir file.h &&
+    marked_as cvswork/subdir unspecified.other "" &&
+    marked_as cvswork/subdir newfile.bin "" &&
+    marked_as cvswork/subdir newfile.c "" &&
+    marked_as cvswork simpleBin.bin -kb &&
+    marked_as cvswork simpleText.c ""
+'
+
+test_expect_success 'update subdir of other copy (guess)' '
+    cd cvswork2/subdir &&
+    GIT_CONFIG="$git_config" cvs -Q update &&
+    cd ../.. &&
+    marked_as cvswork2 textfile.c "" &&
+    marked_as cvswork2 binfile.bin -kb &&
+    marked_as cvswork2 .gitattributes "" &&
+    marked_as cvswork2 mixedUp.c -kb &&
+    marked_as cvswork2 multiline.c -kb &&
+    marked_as cvswork2 multilineTxt.c "" &&
+    not_present cvswork2/subdir withCr.bin &&
+    not_present cvswork2/subdir file.h &&
+    marked_as cvswork2/subdir unspecified.other "" &&
+    marked_as cvswork2/subdir newfile.bin "" &&
+    marked_as cvswork2/subdir newfile.c "" &&
+    not_present cvswork2 simpleBin.bin &&
+    not_present cvswork2 simpleText.c
+'
+
+echo "starting update/merge" >> "${WORKDIR}/marked.log"
+test_expect_success 'update/merge full other copy (guess)' '
+    git pull gitcvs.git master &&
+    sed "s/3/replaced_3/" < multilineTxt.c > ml.temp &&
+    mv ml.temp multilineTxt.c &&
+    git add multilineTxt.c &&
+    git commit -q -m "modify multiline file" >> "${WORKDIR}/marked.log" &&
+    git push gitcvs.git >/dev/null &&
+    cd cvswork2 &&
+    sed "s/1/replaced_1/" < multilineTxt.c > ml.temp &&
+    mv ml.temp multilineTxt.c &&
+    GIT_CONFIG="$git_config" cvs update > cvs.log 2>&1 &&
+    cd .. &&
+    marked_as cvswork2 textfile.c "" &&
+    marked_as cvswork2 binfile.bin -kb &&
+    marked_as cvswork2 .gitattributes "" &&
+    marked_as cvswork2 mixedUp.c -kb &&
+    marked_as cvswork2 multiline.c -kb &&
+    marked_as cvswork2 multilineTxt.c "" &&
+    not_present cvswork2/subdir withCr.bin &&
+    not_present cvswork2/subdir file.h &&
+    marked_as cvswork2/subdir unspecified.other "" &&
+    marked_as cvswork2/subdir newfile.bin "" &&
+    marked_as cvswork2/subdir newfile.c "" &&
+    marked_as cvswork2 simpleBin.bin -kb &&
+    marked_as cvswork2 simpleText.c "" &&
+    echo "line replaced_1" > tmpExpect2 &&
+    echo "line 2" >> tmpExpect2 &&
+    echo "line replaced_3" >> tmpExpect2 &&
+    echo "line 4" | q_to_nul >> tmpExpect2 &&
+    cmp cvswork2/multilineTxt.c tmpExpect2
+'
+
+test_done
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index 061a259..ae7082b 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -10,6 +10,7 @@
 or warnings to log.'
 
 gitweb_init () {
+	safe_pwd="$(perl -MPOSIX=getcwd -e 'print quotemeta(getcwd)')"
 	cat >gitweb_config.perl <<EOF
 #!/usr/bin/perl
 
@@ -17,16 +18,16 @@
 
 our \$version = "current";
 our \$GIT = "git";
-our \$projectroot = "$(pwd)";
+our \$projectroot = "$safe_pwd";
 our \$project_maxdepth = 8;
 our \$home_link_str = "projects";
 our \$site_name = "[localhost]";
 our \$site_header = "";
 our \$site_footer = "";
 our \$home_text = "indextext.html";
-our @stylesheets = ("file:///$(pwd)/../../gitweb/gitweb.css");
-our \$logo = "file:///$(pwd)/../../gitweb/git-logo.png";
-our \$favicon = "file:///$(pwd)/../../gitweb/git-favicon.png";
+our @stylesheets = ("file:///$safe_pwd/../../gitweb/gitweb.css");
+our \$logo = "file:///$safe_pwd/../../gitweb/git-logo.png";
+our \$favicon = "file:///$safe_pwd/../../gitweb/git-favicon.png";
 our \$projects_list = "";
 our \$export_ok = "";
 our \$strict_export = "";
@@ -39,19 +40,21 @@
 }
 
 gitweb_run () {
-	export GATEWAY_INTERFACE="CGI/1.1"
-	export HTTP_ACCEPT="*/*"
-	export REQUEST_METHOD="GET"
-	export QUERY_STRING=""$1""
-	export PATH_INFO=""$2""
+	GATEWAY_INTERFACE="CGI/1.1"
+	HTTP_ACCEPT="*/*"
+	REQUEST_METHOD="GET"
+	QUERY_STRING=""$1""
+	PATH_INFO=""$2""
+	export GATEWAY_INTERFACE HTTP_ACCEPT REQUEST_METHOD QUERY_STRING PATH_INFO
 
-	export GITWEB_CONFIG=$(pwd)/gitweb_config.perl
+	GITWEB_CONFIG=$(pwd)/gitweb_config.perl
+	export GITWEB_CONFIG
 
 	# some of git commands write to STDERR on error, but this is not
 	# written to web server logs, so we are not interested in that:
 	# we are interested only in properly formatted errors/warnings
 	rm -f gitweb.log &&
-	perl -- $(pwd)/../../gitweb/gitweb.perl \
+	perl -- "$(pwd)/../../gitweb/gitweb.perl" \
 		>/dev/null 2>gitweb.log &&
 	if grep -q -s "^[[]" gitweb.log >/dev/null; then false; else true; fi
 
diff --git a/t/t9600-cvsimport.sh b/t/t9600-cvsimport.sh
index 00a74ee..655f882 100755
--- a/t/t9600-cvsimport.sh
+++ b/t/t9600-cvsimport.sh
@@ -36,7 +36,7 @@
 
 test_expect_success 'setup a cvs module' '
 
-	mkdir $CVSROOT/module &&
+	mkdir "$CVSROOT/module" &&
 	cvs co -d module-cvs module &&
 	cd module-cvs &&
 	cat <<EOF >o_fortuna &&
@@ -69,7 +69,7 @@
 test_expect_success 'import a trivial module' '
 
 	git cvsimport -a -z 0 -C module-git module &&
-	git diff module-cvs/o_fortuna module-git/o_fortuna
+	test_cmp module-cvs/o_fortuna module-git/o_fortuna
 
 '
 
@@ -110,7 +110,7 @@
 	git cvsimport -a -z 0 module &&
 	git merge origin &&
 	cd .. &&
-	git diff module-cvs/o_fortuna module-git/o_fortuna
+	test_cmp module-cvs/o_fortuna module-git/o_fortuna
 
 '
 
@@ -131,7 +131,7 @@
 		git cvsimport -a -z0 &&
 		git merge origin &&
 	cd .. &&
-	git diff module-cvs/tick module-git/tick
+	test_cmp module-cvs/tick module-git/tick
 
 '
 
@@ -142,7 +142,7 @@
 		git cvsimport -a -z0 &&
 		echo 1 >expect &&
 		git log -1 --pretty=format:%s%n >actual &&
-		git diff actual expect &&
+		test_cmp actual expect &&
 	cd ..
 
 '
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 7c2a8ba..c861141 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -160,6 +160,22 @@
 
 trap 'die' exit
 
+# The semantics of the editor variables are that of invoking
+# sh -c "$EDITOR \"$@\"" files ...
+#
+# If our trash directory contains shell metacharacters, they will be
+# interpreted if we just set $EDITOR directly, so do a little dance with
+# environment variables to work around this.
+#
+# In particular, quoting isn't enough, as the path may contain the same quote
+# that we're using.
+test_set_editor () {
+	FAKE_EDITOR="$1"
+	export FAKE_EDITOR
+	VISUAL='"$FAKE_EDITOR"'
+	export VISUAL
+}
+
 test_tick () {
 	if test -z "${test_tick+set}"
 	then
@@ -329,7 +345,7 @@
 	repo="$1"
 	mkdir "$repo"
 	cd "$repo" || error "Cannot setup test environment"
-	"$GIT_EXEC_PATH/git" init --template=$GIT_EXEC_PATH/templates/blt/ >/dev/null 2>&1 ||
+	"$GIT_EXEC_PATH/git" init "--template=$GIT_EXEC_PATH/templates/blt/" >/dev/null 2>&1 ||
 	error "cannot run git init -- have you built things yet?"
 	mv .git/hooks .git/hooks-disabled
 	cd "$owd"
@@ -352,7 +368,7 @@
 	case "$test_failure" in
 	0)
 		# We could:
-		# cd .. && rm -fr trash
+		# cd .. && rm -fr 'trash directory'
 		# but that means we forbid any tests that use their own
 		# subdirectory from calling test_done without coming back
 		# to where they started from.
@@ -370,7 +386,7 @@
 }
 
 # Test the binaries we have just built.  The tests are kept in
-# t/ subdirectory and are run in trash subdirectory.
+# t/ subdirectory and are run in 'trash directory' subdirectory.
 PATH=$(pwd)/..:$PATH
 GIT_EXEC_PATH=$(pwd)/..
 GIT_TEMPLATE_DIR=$(pwd)/../templates/blt
@@ -395,15 +411,17 @@
 . ../GIT-BUILD-OPTIONS
 
 # Test repository
-test=trash
+test="trash directory"
 rm -fr "$test" || {
 	trap - exit
 	echo >&5 "FATAL: Cannot prepare test area"
 	exit 1
 }
 
-test_create_repo $test
-cd "$test"
+test_create_repo "$test"
+# Use -P to resolve symlinks in our working directory so that the cwd
+# in subprocesses like git equals our $PWD (for pathname comparisons).
+cd -P "$test" || exit 1
 
 this_test=$(expr "./$0" : '.*/\(t[0-9]*\)-[^/]*$')
 for skp in $GIT_SKIP_TESTS
diff --git a/templates/hooks--prepare-commit-msg b/templates/hooks--prepare-commit-msg
index ff0f42a..d3c1da3 100644
--- a/templates/hooks--prepare-commit-msg
+++ b/templates/hooks--prepare-commit-msg
@@ -20,11 +20,11 @@
 # The third example adds a Signed-off-by line to the message, that can
 # still be edited.  This is rarely a good idea.
 
-case "$2 $3" in
-  merge)
-    sed -i '/^Conflicts:/,/#/!b;s/^/# &/;s/^# #/#/' "$1" ;;
+case "$2,$3" in
+  merge,)
+    perl -i -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
 
-# ""|template)
+# ,|template,)
 #   perl -i -pe '
 #      print "\n" . `git diff --cached --name-status -r`
 #	 if /^#/ && $first++ == 0' "$1" ;;
diff --git a/test-parse-options.c b/test-parse-options.c
index 73360d7..2a79e72 100644
--- a/test-parse-options.c
+++ b/test-parse-options.c
@@ -2,9 +2,22 @@
 #include "parse-options.h"
 
 static int boolean = 0;
-static int integer = 0;
+static unsigned long integer = 0;
+static int abbrev = 7;
+static int verbose = 0, dry_run = 0, quiet = 0;
 static char *string = NULL;
 
+int length_callback(const struct option *opt, const char *arg, int unset)
+{
+	printf("Callback: \"%s\", %d\n",
+		(arg ? arg : "not set"), unset);
+	if (unset)
+		return 1; /* do not support unset */
+
+	*(unsigned long *)opt->value = strlen(arg);
+	return 0;
+}
+
 int main(int argc, const char **argv)
 {
 	const char *usage[] = {
@@ -13,15 +26,29 @@
 	};
 	struct option options[] = {
 		OPT_BOOLEAN('b', "boolean", &boolean, "get a boolean"),
+		OPT_BIT('4', "or4", &boolean,
+			"bitwise-or boolean with ...0100", 4),
+		OPT_GROUP(""),
 		OPT_INTEGER('i', "integer", &integer, "get a integer"),
 		OPT_INTEGER('j', NULL, &integer, "get a integer, too"),
-		OPT_GROUP("string options"),
+		OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23),
+		OPT_DATE('t', NULL, &integer, "get timestamp of <time>"),
+		OPT_CALLBACK('L', "length", &integer, "str",
+			"get length of <str>", length_callback),
+		OPT_GROUP("String options"),
 		OPT_STRING('s', "string", &string, "string", "get a string"),
 		OPT_STRING(0, "string2", &string, "str", "get another string"),
 		OPT_STRING(0, "st", &string, "st", "get another string (pervert ordering)"),
 		OPT_STRING('o', NULL, &string, "str", "get another string"),
-		OPT_GROUP("magic arguments"),
+		OPT_SET_PTR(0, "default-string", &string,
+			"set string to default", (unsigned long)"default"),
+		OPT_GROUP("Magic arguments"),
 		OPT_ARGUMENT("quux", "means --quux"),
+		OPT_GROUP("Standard options"),
+		OPT__ABBREV(&abbrev),
+		OPT__VERBOSE(&verbose),
+		OPT__DRY_RUN(&dry_run),
+		OPT__QUIET(&quiet),
 		OPT_END(),
 	};
 	int i;
@@ -29,8 +56,12 @@
 	argc = parse_options(argc, argv, options, usage, 0);
 
 	printf("boolean: %d\n", boolean);
-	printf("integer: %d\n", integer);
+	printf("integer: %lu\n", integer);
 	printf("string: %s\n", string ? string : "(not set)");
+	printf("abbrev: %d\n", abbrev);
+	printf("verbose: %d\n", verbose);
+	printf("quiet: %s\n", quiet ? "yes" : "no");
+	printf("dry run: %s\n", dry_run ? "yes" : "no");
 
 	for (i = 0; i < argc; i++)
 		printf("arg %02d: %s\n", i, argv[i]);
diff --git a/transport.c b/transport.c
index 393e0e8..b3e3e61 100644
--- a/transport.c
+++ b/transport.c
@@ -203,7 +203,7 @@
 }
 
 static int fetch_objs_via_rsync(struct transport *transport,
-				 int nr_objs, struct ref **to_fetch)
+				int nr_objs, const struct ref **to_fetch)
 {
 	struct strbuf buf = STRBUF_INIT;
 	struct child_process rsync;
@@ -350,7 +350,7 @@
 
 #ifndef NO_CURL /* http fetch is the only user */
 static int fetch_objs_via_walker(struct transport *transport,
-				 int nr_objs, struct ref **to_fetch)
+				 int nr_objs, const struct ref **to_fetch)
 {
 	char *dest = xstrdup(transport->url);
 	struct walker *walker = transport->data;
@@ -441,10 +441,14 @@
 	struct ref *ref = NULL;
 	struct ref *last_ref = NULL;
 
+	struct walker *walker;
+
 	if (!transport->data)
 		transport->data = get_http_walker(transport->url,
 						transport->remote);
 
+	walker = transport->data;
+
 	refs_url = xmalloc(strlen(transport->url) + 11);
 	sprintf(refs_url, "%s/info/refs", transport->url);
 
@@ -459,17 +463,14 @@
 		run_active_slot(slot);
 		if (results.curl_result != CURLE_OK) {
 			strbuf_release(&buffer);
-			if (missing_target(&results)) {
-				return NULL;
-			} else {
-				error("%s", curl_errorstr);
-				return NULL;
-			}
+			if (missing_target(&results))
+				die("%s not found: did you run git update-server-info on the server?", refs_url);
+			else
+				die("%s download error - %s", refs_url, curl_errorstr);
 		}
 	} else {
 		strbuf_release(&buffer);
-		error("Unable to start request");
-		return NULL;
+		die("Unable to start HTTP request");
 	}
 
 	data = buffer.buf;
@@ -500,11 +501,20 @@
 
 	strbuf_release(&buffer);
 
+	ref = alloc_ref_from_str("HEAD");
+	if (!walker->fetch_ref(walker, ref) &&
+	    !resolve_remote_symref(ref, refs)) {
+		ref->next = refs;
+		refs = ref;
+	} else {
+		free(ref);
+	}
+
 	return refs;
 }
 
 static int fetch_objs_via_curl(struct transport *transport,
-				 int nr_objs, struct ref **to_fetch)
+				 int nr_objs, const struct ref **to_fetch)
 {
 	if (!transport->data)
 		transport->data = get_http_walker(transport->url,
@@ -532,9 +542,8 @@
 		die ("Could not read bundle '%s'.", transport->url);
 	for (i = 0; i < data->header.references.nr; i++) {
 		struct ref_list_entry *e = data->header.references.list + i;
-		struct ref *ref = alloc_ref(strlen(e->name) + 1);
+		struct ref *ref = alloc_ref_from_str(e->name);
 		hashcpy(ref->old_sha1, e->sha1);
-		strcpy(ref->name, e->name);
 		ref->next = result;
 		result = ref;
 	}
@@ -542,7 +551,7 @@
 }
 
 static int fetch_refs_from_bundle(struct transport *transport,
-			       int nr_heads, struct ref **to_fetch)
+			       int nr_heads, const struct ref **to_fetch)
 {
 	struct bundle_transport_data *data = transport->data;
 	return unbundle(&data->header, data->fd);
@@ -616,7 +625,7 @@
 }
 
 static int fetch_refs_via_pack(struct transport *transport,
-			       int nr_heads, struct ref **to_fetch)
+			       int nr_heads, const struct ref **to_fetch)
 {
 	struct git_transport_data *data = transport->data;
 	char **heads = xmalloc(nr_heads * sizeof(*heads));
@@ -633,7 +642,9 @@
 	args.lock_pack = 1;
 	args.use_thin_pack = data->thin;
 	args.include_tag = data->followtags;
-	args.verbose = transport->verbose > 0;
+	args.verbose = (transport->verbose > 0);
+	args.quiet = args.no_progress = (transport->verbose < 0);
+	args.no_progress = !isatty(1);
 	args.depth = data->depth;
 
 	for (i = 0; i < nr_heads; i++)
@@ -784,12 +795,12 @@
 	return transport->remote_refs;
 }
 
-int transport_fetch_refs(struct transport *transport, struct ref *refs)
+int transport_fetch_refs(struct transport *transport, const struct ref *refs)
 {
 	int rc;
 	int nr_heads = 0, nr_alloc = 0;
-	struct ref **heads = NULL;
-	struct ref *rm;
+	const struct ref **heads = NULL;
+	const struct ref *rm;
 
 	for (rm = refs; rm; rm = rm->next) {
 		if (rm->peer_ref &&
diff --git a/transport.h b/transport.h
index 8abfc0a..d0b5205 100644
--- a/transport.h
+++ b/transport.h
@@ -19,7 +19,7 @@
 			  const char *value);
 
 	struct ref *(*get_refs_list)(struct transport *transport);
-	int (*fetch)(struct transport *transport, int refs_nr, struct ref **refs);
+	int (*fetch)(struct transport *transport, int refs_nr, const struct ref **refs);
 	int (*push)(struct transport *connection, int refspec_nr, const char **refspec, int flags);
 
 	int (*disconnect)(struct transport *connection);
@@ -68,7 +68,7 @@
 
 const struct ref *transport_get_remote_refs(struct transport *transport);
 
-int transport_fetch_refs(struct transport *transport, struct ref *refs);
+int transport_fetch_refs(struct transport *transport, const struct ref *refs);
 void transport_unlock_pack(struct transport *transport);
 int transport_disconnect(struct transport *transport);
 
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/unpack-file.c b/unpack-file.c
index 65c66eb..bcdc8bb 100644
--- a/unpack-file.c
+++ b/unpack-file.c
@@ -31,7 +31,7 @@
 		die("Not a valid object name %s", argv[1]);
 
 	setup_git_directory();
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	puts(create_temp_file(sha1));
 	return 0;
diff --git a/unpack-trees.c b/unpack-trees.c
index a59f475..cba0aca 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -8,6 +8,36 @@
 #include "progress.h"
 #include "refs.h"
 
+/*
+ * Error messages expected by scripts out of plumbing commands such as
+ * read-tree.  Non-scripted Porcelain is not required to use these messages
+ * and in fact are encouraged to reword them to better suit their particular
+ * situation better.  See how "git checkout" replaces not_uptodate_file to
+ * explain why it does not allow switching between branches when you have
+ * local changes, for example.
+ */
+static struct unpack_trees_error_msgs unpack_plumbing_errors = {
+	/* would_overwrite */
+	"Entry '%s' would be overwritten by merge. Cannot merge.",
+
+	/* not_uptodate_file */
+	"Entry '%s' not uptodate. Cannot merge.",
+
+	/* not_uptodate_dir */
+	"Updating '%s' would lose untracked files in it",
+
+	/* would_lose_untracked */
+	"Untracked working tree file '%s' would be %s by merge.",
+
+	/* bind_overlap */
+	"Entry '%s' overlaps with '%s'.  Cannot bind.",
+};
+
+#define ERRORMSG(o,fld) \
+	( ((o) && (o)->msgs.fld) \
+	? ((o)->msgs.fld) \
+	: (unpack_plumbing_errors.fld) )
+
 static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
 	unsigned int set, unsigned int clear)
 {
@@ -26,11 +56,12 @@
  * directories, in case this unlink is the removal of the
  * last entry in the directory -- empty directories are removed.
  */
-static void unlink_entry(char *name, char *last_symlink)
+static void unlink_entry(struct cache_entry *ce)
 {
 	char *cp, *prev;
+	char *name = ce->name;
 
-	if (has_symlink_leading_path(name, last_symlink))
+	if (has_symlink_leading_path(ce_namelen(ce), ce->name))
 		return;
 	if (unlink(name))
 		return;
@@ -58,7 +89,6 @@
 {
 	unsigned cnt = 0, total = 0;
 	struct progress *progress = NULL;
-	char last_symlink[PATH_MAX];
 	struct index_state *index = &o->result;
 	int i;
 	int errs = 0;
@@ -75,24 +105,27 @@
 		cnt = 0;
 	}
 
-	*last_symlink = '\0';
 	for (i = 0; i < index->cache_nr; i++) {
 		struct cache_entry *ce = index->cache[i];
 
-		if (ce->ce_flags & (CE_UPDATE | CE_REMOVE))
-			display_progress(progress, ++cnt);
 		if (ce->ce_flags & CE_REMOVE) {
+			display_progress(progress, ++cnt);
 			if (o->update)
-				unlink_entry(ce->name, last_symlink);
+				unlink_entry(ce);
 			remove_index_entry_at(&o->result, i);
 			i--;
 			continue;
 		}
+	}
+
+	for (i = 0; i < index->cache_nr; i++) {
+		struct cache_entry *ce = index->cache[i];
+
 		if (ce->ce_flags & CE_UPDATE) {
+			display_progress(progress, ++cnt);
 			ce->ce_flags &= ~CE_UPDATE;
 			if (o->update) {
 				errs |= checkout_entry(ce, &state, NULL);
-				*last_symlink = '\0';
 			}
 		}
 	}
@@ -325,8 +358,13 @@
 	return -1;
 }
 
+/*
+ * N-way merge "len" trees.  Returns 0 on success, -1 on failure to manipulate the
+ * resulting index, -2 on failure to reflect the changes to the work tree.
+ */
 int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options *o)
 {
+	int ret;
 	static struct cache_entry *dfc;
 
 	if (len > MAX_UNPACK_TREES)
@@ -371,19 +409,17 @@
 		return unpack_failed(o, "Merge requires file-level merging");
 
 	o->src_index = NULL;
-	if (check_updates(o))
-		return -1;
+	ret = check_updates(o) ? (-2) : 0;
 	if (o->dst_index)
 		*o->dst_index = o->result;
-	return 0;
+	return ret;
 }
 
 /* Here come the merge functions */
 
-static int reject_merge(struct cache_entry *ce)
+static int reject_merge(struct cache_entry *ce, struct unpack_trees_options *o)
 {
-	return error("Entry '%s' would be overwritten by merge. Cannot merge.",
-		     ce->name);
+	return error(ERRORMSG(o, would_overwrite), ce->name);
 }
 
 static int same(struct cache_entry *a, struct cache_entry *b)
@@ -427,7 +463,7 @@
 	if (errno == ENOENT)
 		return 0;
 	return o->gently ? -1 :
-		error("Entry '%s' not uptodate. Cannot merge.", ce->name);
+		error(ERRORMSG(o, not_uptodate_file), ce->name);
 }
 
 static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_options *o)
@@ -514,13 +550,28 @@
 	i = read_directory(&d, ce->name, pathbuf, namelen+1, NULL);
 	if (i)
 		return o->gently ? -1 :
-			error("Updating '%s' would lose untracked files in it",
-			      ce->name);
+			error(ERRORMSG(o, not_uptodate_dir), ce->name);
 	free(pathbuf);
 	return cnt;
 }
 
 /*
+ * This gets called when there was no index entry for the tree entry 'dst',
+ * but we found a file in the working tree that 'lstat()' said was fine,
+ * and we're on a case-insensitive filesystem.
+ *
+ * See if we can find a case-insensitive match in the index that also
+ * matches the stat information, and assume it's that other file!
+ */
+static int icase_exists(struct unpack_trees_options *o, struct cache_entry *dst, struct stat *st)
+{
+	struct cache_entry *src;
+
+	src = index_name_exists(o->src_index, dst->name, ce_namelen(dst), 1);
+	return src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID);
+}
+
+/*
  * We do not want to remove or overwrite a working tree file that
  * is not tracked, unless it is ignored.
  */
@@ -532,12 +583,23 @@
 	if (o->index_only || o->reset || !o->update)
 		return 0;
 
-	if (has_symlink_leading_path(ce->name, NULL))
+	if (has_symlink_leading_path(ce_namelen(ce), ce->name))
 		return 0;
 
 	if (!lstat(ce->name, &st)) {
 		int cnt;
 		int dtype = ce_to_dtype(ce);
+		struct cache_entry *result;
+
+		/*
+		 * It may be that the 'lstat()' succeeded even though
+		 * target 'ce' was absent, because there is an old
+		 * entry that is different only in case..
+		 *
+		 * Ignore that lstat() if it matches.
+		 */
+		if (ignore_case && icase_exists(o, ce, &st))
+			return 0;
 
 		if (o->dir && excluded(o->dir, ce->name, &dtype))
 			/*
@@ -581,16 +643,14 @@
 		 * delete this path, which is in a subdirectory that
 		 * is being replaced with a blob.
 		 */
-		cnt = index_name_pos(&o->result, ce->name, strlen(ce->name));
-		if (0 <= cnt) {
-			struct cache_entry *ce = o->result.cache[cnt];
-			if (ce->ce_flags & CE_REMOVE)
+		result = index_name_exists(&o->result, ce->name, ce_namelen(ce), 0);
+		if (result) {
+			if (result->ce_flags & CE_REMOVE)
 				return 0;
 		}
 
 		return o->gently ? -1 :
-			error("Untracked working tree file '%s' "
-			      "would be %s by merge.", ce->name, action);
+			error(ERRORMSG(o, would_lose_untracked), ce->name, action);
 	}
 	return 0;
 }
@@ -722,7 +782,7 @@
 	/* #14, #14ALT, #2ALT */
 	if (remote && !df_conflict_head && head_match && !remote_match) {
 		if (index && !same(index, remote) && !same(index, head))
-			return o->gently ? -1 : reject_merge(index);
+			return o->gently ? -1 : reject_merge(index, o);
 		return merged_entry(remote, index, o);
 	}
 	/*
@@ -730,7 +790,7 @@
 	 * make sure that it matches head.
 	 */
 	if (index && !same(index, head))
-		return o->gently ? -1 : reject_merge(index);
+		return o->gently ? -1 : reject_merge(index, o);
 
 	if (head) {
 		/* #5ALT, #15 */
@@ -872,11 +932,11 @@
 		else {
 			/* all other failures */
 			if (oldtree)
-				return o->gently ? -1 : reject_merge(oldtree);
+				return o->gently ? -1 : reject_merge(oldtree, o);
 			if (current)
-				return o->gently ? -1 : reject_merge(current);
+				return o->gently ? -1 : reject_merge(current, o);
 			if (newtree)
-				return o->gently ? -1 : reject_merge(newtree);
+				return o->gently ? -1 : reject_merge(newtree, o);
 			return -1;
 		}
 	}
@@ -902,7 +962,7 @@
 			     o->merge_size);
 	if (a && old)
 		return o->gently ? -1 :
-			error("Entry '%s' overlaps with '%s'.  Cannot bind.", a->name, old->name);
+			error(ERRORMSG(o, bind_overlap), a->name, old->name);
 	if (!a)
 		return keep_entry(old, o);
 	else
diff --git a/unpack-trees.h b/unpack-trees.h
index 50453ed..94e5672 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -8,21 +8,30 @@
 typedef int (*merge_fn_t)(struct cache_entry **src,
 		struct unpack_trees_options *options);
 
+struct unpack_trees_error_msgs {
+	const char *would_overwrite;
+	const char *not_uptodate_file;
+	const char *not_uptodate_dir;
+	const char *would_lose_untracked;
+	const char *bind_overlap;
+};
+
 struct unpack_trees_options {
-	int reset;
-	int merge;
-	int update;
-	int index_only;
-	int nontrivial_merge;
-	int trivial_merges_only;
-	int verbose_update;
-	int aggressive;
-	int skip_unmerged;
-	int gently;
+	unsigned int reset:1,
+		     merge:1,
+		     update:1,
+		     index_only:1,
+		     nontrivial_merge:1,
+		     trivial_merges_only:1,
+		     verbose_update:1,
+		     aggressive:1,
+		     skip_unmerged:1,
+		     gently:1;
 	const char *prefix;
 	int pos;
 	struct dir_struct *dir;
 	merge_fn_t fn;
+	struct unpack_trees_error_msgs msgs;
 
 	int head_idx;
 	int merge_size;
@@ -31,7 +40,7 @@
 	void *unpack_data;
 
 	struct index_state *dst_index;
-	const struct index_state *src_index;
+	struct index_state *src_index;
 	struct index_state result;
 };
 
diff --git a/var.c b/var.c
index 0de0efa..724ba87 100644
--- a/var.c
+++ b/var.c
@@ -39,31 +39,32 @@
 	return val;
 }
 
-static int show_config(const char *var, const char *value)
+static int show_config(const char *var, const char *value, void *cb)
 {
 	if (value)
 		printf("%s=%s\n", var, value);
 	else
 		printf("%s\n", var);
-	return git_default_config(var, value);
+	return git_default_config(var, value, cb);
 }
 
 int main(int argc, char **argv)
 {
 	const char *val;
+	int nongit;
 	if (argc != 2) {
 		usage(var_usage);
 	}
 
-	setup_git_directory();
+	setup_git_directory_gently(&nongit);
 	val = NULL;
 
 	if (strcmp(argv[1], "-l") == 0) {
-		git_config(show_config);
+		git_config(show_config, NULL);
 		list_vars();
 		return 0;
 	}
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	val = read_var(argv[1]);
 	if (!val)
 		usage(var_usage);
diff --git a/walker.c b/walker.c
index c10eca8..0e68ee6 100644
--- a/walker.c
+++ b/walker.c
@@ -59,6 +59,7 @@
 	free(tree->buffer);
 	tree->buffer = NULL;
 	tree->size = 0;
+	tree->object.parsed = 0;
 	return 0;
 }
 
@@ -190,9 +191,13 @@
 	if (!get_sha1_hex(target, sha1))
 		return 0;
 	if (!check_ref_format(target)) {
-		if (!walker->fetch_ref(walker, target, sha1)) {
+		struct ref *ref = alloc_ref_from_str(target);
+		if (!walker->fetch_ref(walker, ref)) {
+			hashcpy(sha1, ref->old_sha1);
+			free(ref);
 			return 0;
 		}
+		free(ref);
 	}
 	return -1;
 }
diff --git a/walker.h b/walker.h
index e1d40de..8a149e1 100644
--- a/walker.h
+++ b/walker.h
@@ -5,7 +5,7 @@
 
 struct walker {
 	void *data;
-	int (*fetch_ref)(struct walker *, char *ref, unsigned char *sha1);
+	int (*fetch_ref)(struct walker *, struct ref *ref);
 	void (*prefetch)(struct walker *, unsigned char *sha1);
 	int (*fetch)(struct walker *, unsigned char *sha1);
 	void (*cleanup)(struct walker *);
diff --git a/write_or_die.c b/write_or_die.c
index e125e11..630be4c 100644
--- a/write_or_die.c
+++ b/write_or_die.c
@@ -40,7 +40,7 @@
 	}
 }
 
-int read_in_full(int fd, void *buf, size_t count)
+ssize_t read_in_full(int fd, void *buf, size_t count)
 {
 	char *p = buf;
 	ssize_t total = 0;
@@ -57,7 +57,7 @@
 	return total;
 }
 
-int write_in_full(int fd, const void *buf, size_t count)
+ssize_t write_in_full(int fd, const void *buf, size_t count)
 {
 	const char *p = buf;
 	ssize_t total = 0;
@@ -78,6 +78,13 @@
 	return total;
 }
 
+void fsync_or_die(int fd, const char *msg)
+{
+	if (fsync(fd) < 0) {
+		die("%s: fsync error (%s)", msg, strerror(errno));
+	}
+}
+
 void write_or_die(int fd, const void *buf, size_t count)
 {
 	if (write_in_full(fd, buf, count) < 0) {
diff --git a/wt-status.c b/wt-status.c
index b3fd57b..5b4d74c 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -8,14 +8,17 @@
 #include "revision.h"
 #include "diffcore.h"
 #include "quote.h"
+#include "run-command.h"
 
 int wt_status_relative_paths = 1;
 int wt_status_use_color = -1;
+int wt_status_submodule_summary;
 static char wt_status_colors[][COLOR_MAXLEN] = {
 	"",         /* WT_STATUS_HEADER: normal */
 	"\033[32m", /* WT_STATUS_UPDATED: green */
 	"\033[31m", /* WT_STATUS_CHANGED: red */
 	"\033[31m", /* WT_STATUS_UNTRACKED: red */
+	"\033[31m", /* WT_STATUS_NOBRANCH: red */
 };
 
 static const char use_add_msg[] =
@@ -36,6 +39,8 @@
 		return WT_STATUS_CHANGED;
 	if (!strcasecmp(var+offset, "untracked"))
 		return WT_STATUS_UNTRACKED;
+	if (!strcasecmp(var+offset, "nobranch"))
+		return WT_STATUS_NOBRANCH;
 	die("bad config variable '%s'", var);
 }
 
@@ -204,7 +209,7 @@
 	rev.diffopt.format_callback = wt_status_print_updated_cb;
 	rev.diffopt.format_callback_data = s;
 	rev.diffopt.detect_rename = 1;
-	rev.diffopt.rename_limit = 100;
+	rev.diffopt.rename_limit = 200;
 	rev.diffopt.break_opt = 0;
 	run_diff_index(&rev, 1);
 }
@@ -220,6 +225,36 @@
 	run_diff_files(&rev, 0);
 }
 
+static void wt_status_print_submodule_summary(struct wt_status *s)
+{
+	struct child_process sm_summary;
+	char summary_limit[64];
+	char index[PATH_MAX];
+	const char *env[] = { index, NULL };
+	const char *argv[] = {
+		"submodule",
+		"summary",
+		"--cached",
+		"--for-status",
+		"--summary-limit",
+		summary_limit,
+		s->amend ? "HEAD^" : "HEAD",
+		NULL
+	};
+
+	sprintf(summary_limit, "%d", wt_status_submodule_summary);
+	snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", s->index_file);
+
+	memset(&sm_summary, 0, sizeof(sm_summary));
+	sm_summary.argv = argv;
+	sm_summary.env = env;
+	sm_summary.git_cmd = 1;
+	sm_summary.no_stdin = 1;
+	fflush(s->fp);
+	sm_summary.out = dup(fileno(s->fp));    /* run_command closes it */
+	run_command(&sm_summary);
+}
+
 static void wt_status_print_untracked(struct wt_status *s)
 {
 	struct dir_struct dir;
@@ -282,8 +317,9 @@
 void wt_status_print(struct wt_status *s)
 {
 	unsigned char sha1[20];
-	s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0;
+	const char *branch_color = color(WT_STATUS_HEADER);
 
+	s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0;
 	if (s->branch) {
 		const char *on_what = "On branch ";
 		const char *branch_name = s->branch;
@@ -291,10 +327,11 @@
 			branch_name += 11;
 		else if (!strcmp(branch_name, "HEAD")) {
 			branch_name = "";
+			branch_color = color(WT_STATUS_NOBRANCH);
 			on_what = "Not currently on any branch.";
 		}
-		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER),
-			"# %s%s", on_what, branch_name);
+		color_fprintf(s->fp, color(WT_STATUS_HEADER), "# ");
+		color_fprintf_ln(s->fp, branch_color, "%s%s", on_what, branch_name);
 	}
 
 	if (s->is_initial) {
@@ -308,6 +345,8 @@
 	}
 
 	wt_status_print_changed(s);
+	if (wt_status_submodule_summary)
+		wt_status_print_submodule_summary(s);
 	wt_status_print_untracked(s);
 
 	if (s->verbose && !s->is_initial)
@@ -328,8 +367,15 @@
 	}
 }
 
-int git_status_config(const char *k, const char *v)
+int git_status_config(const char *k, const char *v, void *cb)
 {
+	if (!strcmp(k, "status.submodulesummary")) {
+		int is_bool;
+		wt_status_submodule_summary = git_config_bool_or_int(k, v, &is_bool);
+		if (is_bool && wt_status_submodule_summary)
+			wt_status_submodule_summary = -1;
+		return 0;
+	}
 	if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
 		wt_status_use_color = git_config_colorbool(k, v, -1);
 		return 0;
@@ -345,5 +391,5 @@
 		wt_status_relative_paths = git_config_bool(k, v);
 		return 0;
 	}
-	return git_color_default_config(k, v);
+	return git_color_default_config(k, v, cb);
 }
diff --git a/wt-status.h b/wt-status.h
index 7d61410..597c7ea 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -8,6 +8,7 @@
 	WT_STATUS_UPDATED,
 	WT_STATUS_CHANGED,
 	WT_STATUS_UNTRACKED,
+	WT_STATUS_NOBRANCH,
 };
 
 struct wt_status {
@@ -27,7 +28,7 @@
 	const char *prefix;
 };
 
-int git_status_config(const char *var, const char *value);
+int git_status_config(const char *var, const char *value, void *cb);
 extern int wt_status_use_color;
 extern int wt_status_relative_paths;
 void wt_status_prepare(struct wt_status *s);