Merge branch 'nd/fix-perf-parameters-in-tests' into maint

* nd/fix-perf-parameters-in-tests:
  test-lib.sh: unfilter GIT_PERF_*
diff --git a/Documentation/RelNotes/1.8.1.2.txt b/Documentation/RelNotes/1.8.1.2.txt
new file mode 100644
index 0000000..5ab7b18
--- /dev/null
+++ b/Documentation/RelNotes/1.8.1.2.txt
@@ -0,0 +1,25 @@
+Git 1.8.1.2 Release Notes
+=========================
+
+Fixes since v1.8.1.1
+--------------------
+
+ * An element on GIT_CEILING_DIRECTORIES list that does not name the
+   real path to a directory (i.e. a symbolic link) could have caused
+   the GIT_DIR discovery logic to escape the ceiling.
+
+ * Command line completion for "tcsh" emitted an unwanted space
+   after completing a single directory name.
+
+ * Command line completion leaked an unnecessary error message while
+   looking for possible matches with paths in <tree-ish>.
+
+ * "git archive" did not record uncompressed size in the header when
+   streaming a zip archive, which confused some implementations of unzip.
+
+ * When users spelled "cc:" in lowercase in the fake "header" in the
+   trailer part, "git send-email" failed to pick up the addresses from
+   there. As e-mail headers field names are case insensitive, this
+   script should follow suit and treat "cc:" and "Cc:" the same way.
+
+Also contains various documentation fixes.
diff --git a/Documentation/RelNotes/1.8.1.3.txt b/Documentation/RelNotes/1.8.1.3.txt
new file mode 100644
index 0000000..03bd330
--- /dev/null
+++ b/Documentation/RelNotes/1.8.1.3.txt
@@ -0,0 +1,28 @@
+Git 1.8.1.3 Release Notes
+=========================
+
+Fixes since v1.8.1.2
+--------------------
+
+ * The attribute mechanism didn't allow limiting attributes to be
+   applied to only a single directory itself with "path/" like the
+   exclude mechanism does.  The fix for this in 1.8.1.2 had
+   performance degradations.
+
+ * Command line completion code was inadvertently made incompatible with
+   older versions of bash by using a newer array notation.
+
+ * We used to stuff "user@" and then append what we read from
+   /etc/mailname to come up with a default e-mail ident, but a bug
+   lost the "user@" part.
+
+ * "git am" did not parse datestamp correctly from Hg generated patch,
+   when it is run in a locale outside C (or en).
+
+ * Attempt to "branch --edit-description" an existing branch, while
+   being on a detached HEAD, errored out.
+
+ * "git rebase --preserve-merges" lost empty merges in recent versions
+   of Git.
+
+Also contains various documentation fixes.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index bf8f911..e452ff8 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1351,6 +1351,12 @@
 	value is 0 - the command will be just shown but not executed.
 	This is the default.
 
+help.htmlpath::
+	Specify the path where the HTML documentation resides. File system paths
+	and URLs are supported. HTML pages will be prefixed with this path when
+	help is displayed in the 'web' format. This defaults to the documentation
+	path of your Git installation.
+
 http.proxy::
 	Override the HTTP proxy, normally configured using the 'http_proxy',
 	'https_proxy', and 'all_proxy' environment variables (see
diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt
index 6d5a04c..a221169 100644
--- a/Documentation/git-commit-tree.txt
+++ b/Documentation/git-commit-tree.txt
@@ -72,13 +72,13 @@
 	GIT_COMMITTER_NAME
 	GIT_COMMITTER_EMAIL
 	GIT_COMMITTER_DATE
-	EMAIL
 
 (nb "<", ">" and "\n"s are stripped)
 
 In case (some of) these environment variables are not set, the information
 is taken from the configuration items user.name and user.email, or, if not
-present, system user name and the hostname used for outgoing mail (taken
+present, the environment variable EMAIL, or, if that is not set,
+system user name and the hostname used for outgoing mail (taken
 from `/etc/mailname` and falling back to the fully qualified hostname when
 that file does not exist).
 
diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt
index 98d9881..f059ea9 100644
--- a/Documentation/git-cvsimport.txt
+++ b/Documentation/git-cvsimport.txt
@@ -18,6 +18,12 @@
 
 DESCRIPTION
 -----------
+*WARNING:* `git cvsimport` uses cvsps version 2, which is considered
+deprecated; it does not work with cvsps version 3 and later.  If you are
+performing a one-shot import of a CVS repository consider using
+link:http://cvs2svn.tigris.org/cvs2git.html[cvs2git] or
+link:https://github.com/BartMassey/parsecvs[parsecvs].
+
 Imports a CVS repository into git. It will either create a new
 repository, or incrementally import into an existing one.
 
@@ -213,11 +219,9 @@
 * Multiple tags on the same revision are not imported.
 
 If you suspect that any of these issues may apply to the repository you
-want to import consider using these alternative tools which proved to be
-more stable in practice:
+want to imort, consider using cvs2git:
 
-* cvs2git (part of cvs2svn), `http://cvs2svn.tigris.org`
-* parsecvs, `http://cgit.freedesktop.org/~keithp/parsecvs`
+* cvs2git (part of cvs2svn), `http://subversion.apache.org/`
 
 GIT
 ---
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index db55a4e..f2e08d1 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -117,7 +117,7 @@
 
 As a special case for the date-type fields, you may specify a format for
 the date by adding one of `:default`, `:relative`, `:short`, `:local`,
-`:iso8601` or `:rfc2822` to the end of the fieldname; e.g.
+`:iso8601`, `:rfc2822` or `:raw` to the end of the fieldname; e.g.
 `%(taggerdate:relative)`.
 
 
diff --git a/Documentation/howto/maintain-git.txt b/Documentation/howto/maintain-git.txt
index ea6e4a5..816c791 100644
--- a/Documentation/howto/maintain-git.txt
+++ b/Documentation/howto/maintain-git.txt
@@ -10,35 +10,42 @@
 How to maintain Git
 ===================
 
+Activities
+----------
+
 The maintainer's git time is spent on three activities.
 
- - Communication (60%)
+ - Communication (45%)
 
    Mailing list discussions on general design, fielding user
    questions, diagnosing bug reports; reviewing, commenting on,
    suggesting alternatives to, and rejecting patches.
 
- - Integration (30%)
+ - Integration (50%)
 
    Applying new patches from the contributors while spotting and
    correcting minor mistakes, shuffling the integration and
    testing branches, pushing the results out, cutting the
    releases, and making announcements.
 
- - Own development (10%)
+ - Own development (5%)
 
    Scratching my own itch and sending proposed patch series out.
 
+The Policy
+----------
+
 The policy on Integration is informally mentioned in "A Note
 from the maintainer" message, which is periodically posted to
 this mailing list after each feature release is made.
 
-The policy.
-
  - Feature releases are numbered as vX.Y.Z and are meant to
    contain bugfixes and enhancements in any area, including
    functionality, performance and usability, without regression.
 
+ - One release cycle for a feature release is expected to last for
+   eight to ten weeks.
+
  - Maintenance releases are numbered as vX.Y.Z.W and are meant
    to contain only bugfixes for the corresponding vX.Y.Z feature
    release and earlier maintenance releases vX.Y.Z.V (V < W).
@@ -62,12 +69,15 @@
  - 'pu' branch is used to publish other proposed changes that do
    not yet pass the criteria set for 'next'.
 
- - The tips of 'master', 'maint' and 'next' branches will always
-   fast-forward, to allow people to build their own
-   customization on top of them.
+ - The tips of 'master' and 'maint' branches will not be rewound to
+   allow people to build their own customization on top of them.
+   Early in a new development cycle, 'next' is rewound to the tip of
+   'master' once, but otherwise it will not be rewound until the end
+   of the cycle.
 
- - Usually 'master' contains all of 'maint', 'next' contains all
-   of 'master' and 'pu' contains all of 'next'.
+ - Usually 'master' contains all of 'maint' and 'next' contains all
+   of 'master'.  'pu' contains all the topics merged to 'next', but
+   is rebuilt directly on 'master'.
 
  - The tip of 'master' is meant to be more stable than any
    tagged releases, and the users are encouraged to follow it.
@@ -77,14 +87,22 @@
    are found before new topics are merged to 'master'.
 
 
+A Typical Git Day
+-----------------
+
 A typical git day for the maintainer implements the above policy
 by doing the following:
 
- - Scan mailing list and #git channel log.  Respond with review
-   comments, suggestions etc.  Kibitz.  Collect potentially
-   usable patches from the mailing list.  Patches about a single
-   topic go to one mailbox (I read my mail in Gnus, and type
-   \C-o to save/append messages in files in mbox format).
+ - Scan mailing list.  Respond with review comments, suggestions
+   etc.  Kibitz.  Collect potentially usable patches from the
+   mailing list.  Patches about a single topic go to one mailbox (I
+   read my mail in Gnus, and type \C-o to save/append messages in
+   files in mbox format).
+
+ - Write his own patches to address issues raised on the list but
+   nobody has stepped up solving.  Send it out just like other
+   contributors do, and pick them up just like patches from other
+   contributors (see above).
 
  - Review the patches in the saved mailboxes.  Edit proposed log
    message for typofixes and clarifications, and add Acks
@@ -100,40 +118,32 @@
    - Obviously correct fixes that pertain to the tip of 'master'
      are directly applied to 'master'.
 
+   - Other topics are not handled in this step.
+
    This step is done with "git am".
 
      $ git checkout master    ;# or "git checkout maint"
-     $ git am -3 -s mailbox
+     $ git am -sc3 mailbox
      $ make test
 
- - Merge downwards (maint->master):
-
-     $ git checkout master
-     $ git merge maint
-     $ make test
+   In practice, almost no patch directly goes to 'master' or
+   'maint'.
 
  - Review the last issue of "What's cooking" message, review the
-   topics scheduled for merging upwards (topic->master and
-   topic->maint), and merge.
+   topics ready for merging (topic->master and topic->maint).  Use
+   "Meta/cook -w" script (where Meta/ contains a checkout of the
+   'todo' branch) to aid this step.
+
+   And perform the merge.  Use "Meta/Reintegrate -e" script (see
+   later) to aid this step.
+
+     $ Meta/cook -w last-issue-of-whats-cooking.mbox
 
      $ git checkout master    ;# or "git checkout maint"
-     $ git merge ai/topic     ;# or "git merge ai/maint-topic"
+     $ echo ai/topic | Meta/Reintegrate -e ;# "git merge ai/topic"
      $ git log -p ORIG_HEAD.. ;# final review
      $ git diff ORIG_HEAD..   ;# final review
      $ make test              ;# final review
-     $ git branch -d ai/topic ;# or "git branch -d ai/maint-topic"
-
- - Merge downwards (maint->master) if needed:
-
-     $ git checkout master
-     $ git merge maint
-     $ make test
-
- - Merge downwards (master->next) if needed:
-
-     $ git checkout next
-     $ git merge master
-     $ make test
 
  - Handle the remaining patches:
 
@@ -142,9 +152,9 @@
      and not in 'master') is applied to a new topic branch that
      is forked from the tip of 'master'.  This includes both
      enhancements and unobvious fixes to 'master'.  A topic
-     branch is named as ai/topic where "ai" is typically
-     author's initial and "topic" is a descriptive name of the
-     topic (in other words, "what's the series is about").
+     branch is named as ai/topic where "ai" is two-letter string
+     named after author's initial and "topic" is a descriptive name
+     of the topic (in other words, "what's the series is about").
 
    - An unobvious fix meant for 'maint' is applied to a new
      topic branch that is forked from the tip of 'maint'.  The
@@ -162,7 +172,8 @@
 
    The above except the "replacement" are all done with:
 
-     $ git am -3 -s mailbox
+     $ git checkout ai/topic ;# or "git checkout -b ai/topic master"
+     $ git am -sc3 mailbox
 
    while patch replacement is often done by:
 
@@ -170,93 +181,170 @@
 
    then replace some parts with the new patch, and reapplying:
 
+     $ git checkout ai/topic
      $ git reset --hard ai/topic~$n
-     $ git am -3 -s 000*.txt
+     $ git am -sc3 -s 000*.txt
 
    The full test suite is always run for 'maint' and 'master'
    after patch application; for topic branches the tests are run
    as time permits.
 
+ - Merge maint to master as needed:
+
+     $ git checkout master
+     $ git merge maint
+     $ make test
+
+ - Merge master to next as needed:
+
+     $ git checkout next
+     $ git merge master
+     $ make test
+
+ - Review the last issue of "What's cooking" again and see if topics
+   that are ready to be merged to 'next' are still in good shape
+   (e.g. has there any new issue identified on the list with the
+   series?)
+
+ - Prepare 'jch' branch, which is used to represent somewhere
+   between 'master' and 'pu' and often is slightly ahead of 'next'.
+
+     $ Meta/Reintegrate master..pu >Meta/redo-jch.sh
+
+   The result is a script that lists topics to be merged in order to
+   rebuild 'pu' as the input to Meta/Reintegrate script.  Remove
+   later topics that should not be in 'jch' yet.  Add a line that
+   consists of '### match next' before the name of the first topic
+   in the output that should be in 'jch' but not in 'next' yet.
+
+ - Now we are ready to start merging topics to 'next'.  For each
+   branch whose tip is not merged to 'next', one of three things can
+   happen:
+
+   - The commits are all next-worthy; merge the topic to next;
+   - The new parts are of mixed quality, but earlier ones are
+     next-worthy; merge the early parts to next;
+   - Nothing is next-worthy; do not do anything.
+
+   This step is aided with Meta/redo-jch.sh script created earlier.
+   If a topic that was already in 'next' gained a patch, the script
+   would list it as "ai/topic~1".  To include the new patch to the
+   updated 'next', drop the "~1" part; to keep it excluded, do not
+   touch the line.  If a topic that was not in 'next' should be
+   merged to 'next', add it at the end of the list.  Then:
+
+     $ git checkout -B jch master
+     $ Meta/redo-jch.sh -c1
+
+   to rebuild the 'jch' branch from scratch.  "-c1" tells the script
+   to stop merging at the first line that begins with '###'
+   (i.e. the "### match next" line you added earlier).
+
+   At this point, build-test the result.  It may reveal semantic
+   conflicts (e.g. a topic renamed a variable, another added a new
+   reference to the variable under its old name), in which case
+   prepare an appropriate merge-fix first (see appendix), and
+   rebuild the 'jch' branch from scratch, starting at the tip of
+   'master'.
+
+   Then do the same to 'next'
+
+     $ git checkout next
+     $ sh Meta/redo-jch.sh -c1 -e
+
+   The "-e" option allows the merge message that comes from the
+   history of the topic and the comments in the "What's cooking" to
+   be edited.  The resulting tree should match 'jch' as the same set
+   of topics are merged on 'master'; otherwise there is a mismerge.
+   Investigate why and do not proceed until the mismerge is found
+   and rectified.
+
+     $ git diff jch next
+
+   When all is well, clean up the redo-jch.sh script with
+
+     $ sh Meta/redo-jch.sh -u
+
+   This removes topics listed in the script that have already been
+   merged to 'master'.  This may lose '### match next' marker;
+   add it again to the appropriate place when it happens.
+
+ - Rebuild 'pu'.
+
+     $ Meta/Reintegrate master..pu >Meta/redo-pu.sh
+
+   Edit the result by adding new topics that are not still in 'pu'
+   in the script.  Then
+
+     $ git checkout -B pu jch
+     $ sh Meta/redo-pu.sh
+
+   When all is well, clean up the redo-pu.sh script with
+
+     $ sh Meta/redo-pu.sh -u
+
+   Double check by running
+
+     $ git branch --no-merged pu
+
+   to see there is no unexpected leftover topics.
+
+   At this point, build-test the result for semantic conflicts, and
+   if there are, prepare an appropriate merge-fix first (see
+   appendix), and rebuild the 'pu' branch from scratch, starting at
+   the tip of 'jch'.
+
  - Update "What's cooking" message to review the updates to
    existing topics, newly added topics and graduated topics.
 
-   This step is helped with Meta/cook script (where Meta/ contains
-   a checkout of the 'todo' branch).
+   This step is helped with Meta/cook script.
 
- - Merge topics to 'next'.  For each branch whose tip is not
-   merged to 'next', one of three things can happen:
+     $ Meta/cook
 
-   - The commits are all next-worthy; merge the topic to next:
+   This script inspects the history between master..pu, finds tips
+   of topic branches, compares what it found with the current
+   contents in Meta/whats-cooking.txt, and updates that file.
+   Topics not listed in the file but are found in master..pu are
+   added to the "New topics" section, topics listed in the file that
+   are no longer found in master..pu are moved to the "Graduated to
+   master" section, and topics whose commits changed their states
+   (e.g. used to be only in 'pu', now merged to 'next') are updated
+   with change markers "<<" and ">>".
 
-     $ git checkout next
-     $ git merge ai/topic     ;# or "git merge ai/maint-topic"
-     $ make test
+   Look for lines enclosed in "<<" and ">>"; they hold contents from
+   old file that are replaced by this integration round.  After
+   verifying them, remove the old part.  Review the description for
+   each topic and update its doneness and plan as needed.  To review
+   the updated plan, run
 
-   - The new parts are of mixed quality, but earlier ones are
-     next-worthy; merge the early parts to next:
+     $ Meta/cook -w
 
-     $ git checkout next
-     $ git merge ai/topic~2   ;# the tip two are dubious
-     $ make test
+   which will pick up comments given to the topics, such as "Will
+   merge to 'next'", etc. (see Meta/cook script to learn what kind
+   of phrases are supported).
 
-   - Nothing is next-worthy; do not do anything.
+ - Compile, test and install all four (five) integration branches;
+   Meta/Dothem script may aid this step.
 
- - [** OBSOLETE **] Optionally rebase topics that do not have any commit
-   in next yet, when they can take advantage of low-level framework
-   change that is merged to 'master' already.
+ - Format documentation if the 'master' branch was updated;
+   Meta/dodoc.sh script may aid this step.
 
-     $ git rebase master ai/topic
+ - Push the integration branches out to public places; Meta/pushall
+   script may aid this step.
 
-   This step is helped with Meta/git-topic.perl script to
-   identify which topic is rebaseable.  There also is a
-   pre-rebase hook to make sure that topics that are already in
-   'next' are not rebased beyond the merged commit.
-
- - [** OBSOLETE **] Rebuild "pu" to merge the tips of topics not in 'next'.
-
-     $ git checkout pu
-     $ git reset --hard next
-     $ git merge ai/topic     ;# repeat for all remaining topics
-     $ make test
-
-   This step is helped with Meta/PU script
-
- - Push four integration branches to a private repository at
-   k.org and run "make test" on all of them.
-
- - Push four integration branches to /pub/scm/git/git.git at
-   k.org.  This triggers its post-update hook which:
-
-    (1) runs "git pull" in $HOME/git-doc/ repository to pull
-        'master' just pushed out;
-
-    (2) runs "make doc" in $HOME/git-doc/, install the generated
-        documentation in staging areas, which are separate
-        repositories that have html and man branches checked
-        out.
-
-    (3) runs "git commit" in the staging areas, and run "git
-        push" back to /pub/scm/git/git.git/ to update the html
-        and man branches.
-
-    (4) installs generated documentation to /pub/software/scm/git/docs/
-        to be viewed from http://www.kernel.org/
-
- - Fetch html and man branches back from k.org, and push four
-   integration branches and the two documentation branches to
-   repo.or.cz and other mirrors.
-
+Observations
+------------
 
 Some observations to be made.
 
- * Each topic is tested individually, and also together with
-   other topics cooking in 'next'.  Until it matures, none part
-   of it is merged to 'master'.
+ * Each topic is tested individually, and also together with other
+   topics cooking first in 'pu', then in 'jch' and then in 'next'.
+   Until it matures, no part of it is merged to 'master'.
 
  * A topic already in 'next' can get fixes while still in
    'next'.  Such a topic will have many merges to 'next' (in
    other words, "git log --first-parent next" will show many
-   "Merge ai/topic to next" for the same topic.
+   "Merge branch 'ai/topic' to next" for the same topic.
 
  * An unobvious fix for 'maint' is cooked in 'next' and then
    merged to 'master' to make extra sure it is Ok and then
@@ -278,3 +366,80 @@
  * Being in the 'next' branch is not a guarantee for a topic to
    be included in the next feature release.  Being in the
    'master' branch typically is.
+
+
+Appendix
+--------
+
+Preparing a "merge-fix"
+~~~~~~~~~~~~~~~~~~~~~~~
+
+A merge of two topics may not textually conflict but still have
+conflict at the semantic level. A classic example is for one topic
+to rename an variable and all its uses, while another topic adds a
+new use of the variable under its old name. When these two topics
+are merged together, the reference to the variable newly added by
+the latter topic will still use the old name in the result.
+
+The Meta/Reintegrate script that is used by redo-jch and redo-pu
+scripts implements a crude but usable way to work this issue around.
+When the script merges branch $X, it checks if "refs/merge-fix/$X"
+exists, and if so, the effect of it is squashed into the result of
+the mechanical merge.  In other words,
+
+     $ echo $X | Meta/Reintegrate
+
+is roughly equivalent to this sequence:
+
+     $ git merge --rerere-autoupdate $X
+     $ git commit
+     $ git cherry-pick -n refs/merge-fix/$X
+     $ git commit --amend
+
+The goal of this "prepare a merge-fix" step is to come up with a
+commit that can be squashed into a result of mechanical merge to
+correct semantic conflicts.
+
+After finding that the result of merging branch "ai/topic" to an
+integration branch had such a semantic conflict, say pu~4, check the
+problematic merge out on a detached HEAD, edit the working tree to
+fix the semantic conflict, and make a separate commit to record the
+fix-up:
+
+     $ git checkout pu~4
+     $ git show -s --pretty=%s ;# double check
+     Merge branch 'ai/topic' to pu
+     $ edit
+     $ git commit -m 'merge-fix/ai/topic' -a
+
+Then make a reference "refs/merge-fix/ai/topic" to point at this
+result:
+
+     $ git update-ref refs/merge-fix/ai/topic HEAD
+
+Then double check the result by asking Meta/Reintegrate to redo the
+merge:
+
+     $ git checkout pu~5 ;# the parent of the problem merge
+     $ echo ai/topic | Meta/Reintegrate
+     $ git diff pu~4
+
+This time, because you prepared refs/merge-fix/ai/topic, the
+resulting merge should have been tweaked to include the fix for the
+semantic conflict.
+
+Note that this assumes that the order in which conflicting branches
+are merged does not change.  If the reason why merging ai/topic
+branch needs this merge-fix is because another branch merged earlier
+to the integration branch changed the underlying assumption ai/topic
+branch made (e.g. ai/topic branch added a site to refer to a
+variable, while the other branch renamed that variable and adjusted
+existing use sites), and if you changed redo-jch (or redo-pu) script
+to merge ai/topic branch before the other branch, then the above
+merge-fix should not be applied while merging ai/topic, but should
+instead be applied while merging the other branch.  You would need
+to move the fix to apply to the other branch, perhaps like this:
+
+      $ mf=refs/merge-fix
+      $ git update-ref $mf/$the_other_branch $mf/ai/topic
+      $ git update-ref -d $mf/ai/topic
diff --git a/Documentation/technical/api-string-list.txt b/Documentation/technical/api-string-list.txt
index 7386bca..20be348 100644
--- a/Documentation/technical/api-string-list.txt
+++ b/Documentation/technical/api-string-list.txt
@@ -82,14 +82,6 @@
 	call free() on the util members of any items that have to be
 	deleted.  Preserve the order of the items that are retained.
 
-`string_list_longest_prefix`::
-
-	Return the longest string within a string_list that is a
-	prefix (in the sense of prefixcmp()) of the specified string,
-	or NULL if no such prefix exists.  This function does not
-	require the string_list to be sorted (it does a linear
-	search).
-
 `print_string_list`::
 
 	Dump a string_list to stdout, useful mainly for debugging purposes. It
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index c572e8d..2edb996 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.8.1.1
+DEF_VER=v1.8.1.2
 
 LF='
 '
diff --git a/INSTALL b/INSTALL
index 28f34bd..2dc3b61 100644
--- a/INSTALL
+++ b/INSTALL
@@ -131,8 +131,9 @@
 	  use English. Under autoconf the configure script will do this
 	  automatically if it can't find libintl on the system.
 
-	- Python version 2.6 or later is needed to use the git-p4
-	  interface to Perforce.
+	- Python version 2.4 or later (but not 3.x, which is not
+	  supported by Perforce) is needed to use the git-p4 interface
+	  to Perforce.
 
  - Some platform specific issues are dealt with Makefile rules,
    but depending on your specific installation, you may not
diff --git a/Makefile b/Makefile
index 05d241b..4bb3cf1 100644
--- a/Makefile
+++ b/Makefile
@@ -653,7 +653,7 @@
 LIB_H += ll-merge.h
 LIB_H += log-tree.h
 LIB_H += mailmap.h
-LIB_H += merge-file.h
+LIB_H += merge-blobs.h
 LIB_H += merge-recursive.h
 LIB_H += mergesort.h
 LIB_H += notes-cache.h
@@ -769,7 +769,7 @@
 LIB_OBJS += mailmap.o
 LIB_OBJS += match-trees.o
 LIB_OBJS += merge.o
-LIB_OBJS += merge-file.o
+LIB_OBJS += merge-blobs.o
 LIB_OBJS += merge-recursive.o
 LIB_OBJS += mergesort.o
 LIB_OBJS += name-hash.o
@@ -1475,7 +1475,8 @@
 
 ifeq ($(COMPUTE_HEADER_DEPENDENCIES),auto)
 dep_check = $(shell $(CC) $(ALL_CFLAGS) \
-	-c -MF /dev/null -MMD -MP -x c /dev/null -o /dev/null 2>&1; \
+	-c -MF /dev/null -MQ /dev/null -MMD -MP \
+	-x c /dev/null -o /dev/null 2>&1; \
 	echo $$?)
 ifeq ($(dep_check),0)
 override COMPUTE_HEADER_DEPENDENCIES = yes
@@ -2329,7 +2330,7 @@
 
 missing_dep_dirs := $(filter-out $(wildcard $(dep_dirs)),$(dep_dirs))
 dep_file = $(dir $@).depend/$(notdir $@).d
-dep_args = -MF $(dep_file) -MMD -MP
+dep_args = -MF $(dep_file) -MQ $@ -MMD -MP
 ifdef CHECK_HEADER_DEPENDENCIES
 $(error cannot compute header dependencies outside a normal build. \
 Please unset CHECK_HEADER_DEPENDENCIES and try again)
diff --git a/README b/README
index 49713ea..a960ca8 100644
--- a/README
+++ b/README
@@ -47,11 +47,10 @@
 Documentation/SubmittingPatches for instructions on patch submission).
 To subscribe to the list, send an email with just "subscribe git" in
 the body to majordomo@vger.kernel.org. The mailing list archives are
-available at http://marc.theaimsgroup.com/?l=git and other archival
-sites.
+available at http://news.gmane.org/gmane.comp.version-control.git/,
+http://marc.info/?l=git and other archival sites.
 
-The messages titled "A note from the maintainer", "What's in
-git.git (stable)" and "What's cooking in git.git (topics)" and
-the discussion following them on the mailing list give a good
-reference for project status, development direction and
-remaining tasks.
+The maintainer frequently sends the "What's cooking" reports that
+list the current status of various development topics to the mailing
+list.  The discussion following them give a good reference for
+project status, development direction and remaining tasks.
diff --git a/RelNotes b/RelNotes
index 5964e1c..ce97a3b 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.8.1.1.txt
\ No newline at end of file
+Documentation/RelNotes/1.8.1.3.txt
\ No newline at end of file
diff --git a/abspath.c b/abspath.c
index 05f2d79..40cdc46 100644
--- a/abspath.c
+++ b/abspath.c
@@ -15,16 +15,34 @@
 #define MAXDEPTH 5
 
 /*
- * Use this to get the real path, i.e. resolve links. If you want an
- * absolute path but don't mind links, use absolute_path.
+ * Return the real path (i.e., absolute path, with symlinks resolved
+ * and extra slashes removed) equivalent to the specified path.  (If
+ * you want an absolute path but don't mind links, use
+ * absolute_path().)  The return value is a pointer to a static
+ * buffer.
+ *
+ * The input and all intermediate paths must be shorter than MAX_PATH.
+ * The directory part of path (i.e., everything up to the last
+ * dir_sep) must denote a valid, existing directory, but the last
+ * component need not exist.  If die_on_error is set, then die with an
+ * informative error message if there is a problem.  Otherwise, return
+ * NULL on errors (without generating any output).
  *
  * If path is our buffer, then return path, as it's already what the
  * user wants.
  */
-const char *real_path(const char *path)
+static const char *real_path_internal(const char *path, int die_on_error)
 {
 	static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
+	char *retval = NULL;
+
+	/*
+	 * If we have to temporarily chdir(), store the original CWD
+	 * here so that we can chdir() back to it at the end of the
+	 * function:
+	 */
 	char cwd[1024] = "";
+
 	int buf_index = 1;
 
 	int depth = MAXDEPTH;
@@ -35,11 +53,19 @@
 	if (path == buf || path == next_buf)
 		return path;
 
-	if (!*path)
-		die("The empty string is not a valid path");
+	if (!*path) {
+		if (die_on_error)
+			die("The empty string is not a valid path");
+		else
+			goto error_out;
+	}
 
-	if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
-		die ("Too long path: %.*s", 60, path);
+	if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) {
+		if (die_on_error)
+			die("Too long path: %.*s", 60, path);
+		else
+			goto error_out;
+	}
 
 	while (depth--) {
 		if (!is_directory(buf)) {
@@ -54,20 +80,36 @@
 		}
 
 		if (*buf) {
-			if (!*cwd && !getcwd(cwd, sizeof(cwd)))
-				die_errno ("Could not get current working directory");
+			if (!*cwd && !getcwd(cwd, sizeof(cwd))) {
+				if (die_on_error)
+					die_errno("Could not get current working directory");
+				else
+					goto error_out;
+			}
 
-			if (chdir(buf))
-				die_errno ("Could not switch to '%s'", buf);
+			if (chdir(buf)) {
+				if (die_on_error)
+					die_errno("Could not switch to '%s'", buf);
+				else
+					goto error_out;
+			}
 		}
-		if (!getcwd(buf, PATH_MAX))
-			die_errno ("Could not get current working directory");
+		if (!getcwd(buf, PATH_MAX)) {
+			if (die_on_error)
+				die_errno("Could not get current working directory");
+			else
+				goto error_out;
+		}
 
 		if (last_elem) {
 			size_t len = strlen(buf);
-			if (len + strlen(last_elem) + 2 > PATH_MAX)
-				die ("Too long path name: '%s/%s'",
-						buf, last_elem);
+			if (len + strlen(last_elem) + 2 > PATH_MAX) {
+				if (die_on_error)
+					die("Too long path name: '%s/%s'",
+					    buf, last_elem);
+				else
+					goto error_out;
+			}
 			if (len && !is_dir_sep(buf[len-1]))
 				buf[len++] = '/';
 			strcpy(buf + len, last_elem);
@@ -77,10 +119,18 @@
 
 		if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
 			ssize_t len = readlink(buf, next_buf, PATH_MAX);
-			if (len < 0)
-				die_errno ("Invalid symlink '%s'", buf);
-			if (PATH_MAX <= len)
-				die("symbolic link too long: %s", buf);
+			if (len < 0) {
+				if (die_on_error)
+					die_errno("Invalid symlink '%s'", buf);
+				else
+					goto error_out;
+			}
+			if (PATH_MAX <= len) {
+				if (die_on_error)
+					die("symbolic link too long: %s", buf);
+				else
+					goto error_out;
+			}
 			next_buf[len] = '\0';
 			buf = next_buf;
 			buf_index = 1 - buf_index;
@@ -89,10 +139,23 @@
 			break;
 	}
 
+	retval = buf;
+error_out:
+	free(last_elem);
 	if (*cwd && chdir(cwd))
 		die_errno ("Could not change back to '%s'", cwd);
 
-	return buf;
+	return retval;
+}
+
+const char *real_path(const char *path)
+{
+	return real_path_internal(path, 1);
+}
+
+const char *real_path_if_valid(const char *path)
+{
+	return real_path_internal(path, 0);
 }
 
 static const char *get_pwd_cwd(void)
diff --git a/archive-zip.c b/archive-zip.c
index 55f66b4..d3aef53 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -240,7 +240,7 @@
 			(mode & 0111) ? ((mode) << 16) : 0;
 		if (S_ISREG(mode) && args->compression_level != 0 && size > 0)
 			method = 8;
-		compressed_size = size;
+		compressed_size = (method == 0) ? size : 0;
 
 		if (S_ISREG(mode) && type == OBJ_BLOB && !args->convert &&
 		    size > big_file_threshold) {
@@ -313,10 +313,7 @@
 	copy_le16(header.compression_method, method);
 	copy_le16(header.mtime, zip_time);
 	copy_le16(header.mdate, zip_date);
-	if (flags & ZIP_STREAM)
-		set_zip_header_data_desc(&header, 0, 0, 0);
-	else
-		set_zip_header_data_desc(&header, size, compressed_size, crc);
+	set_zip_header_data_desc(&header, size, compressed_size, crc);
 	copy_le16(header.filename_length, pathlen);
 	copy_le16(header.extra_length, ZIP_EXTRA_MTIME_SIZE);
 	write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE);
diff --git a/attr.c b/attr.c
index 466c93f..8985c5c 100644
--- a/attr.c
+++ b/attr.c
@@ -564,25 +564,12 @@
 	attr_stack = elem;
 }
 
-static const char *find_basename(const char *path)
-{
-	const char *cp, *last_slash = NULL;
-
-	for (cp = path; *cp; cp++) {
-		if (*cp == '/' && cp[1])
-			last_slash = cp;
-	}
-	return last_slash ? last_slash + 1 : path;
-}
-
-static void prepare_attr_stack(const char *path)
+static void prepare_attr_stack(const char *path, int dirlen)
 {
 	struct attr_stack *elem, *info;
-	int dirlen, len;
+	int len;
 	const char *cp;
 
-	dirlen = find_basename(path) - path;
-
 	/*
 	 * At the bottom of the attribute stack is the built-in
 	 * set of attribute definitions, followed by the contents
@@ -704,7 +691,7 @@
 
 		if (*n == ATTR__UNKNOWN) {
 			debug_set(what,
-				  a->is_macro ? a->u.attr->name : a->u.pattern,
+				  a->is_macro ? a->u.attr->name : a->u.pat.pattern,
 				  attr, v);
 			*n = v;
 			rem--;
@@ -762,15 +749,26 @@
 static void collect_all_attrs(const char *path)
 {
 	struct attr_stack *stk;
-	int i, pathlen, rem;
-	const char *basename;
+	int i, pathlen, rem, dirlen;
+	const char *basename, *cp, *last_slash = NULL;
 
-	prepare_attr_stack(path);
+	for (cp = path; *cp; cp++) {
+		if (*cp == '/' && cp[1])
+			last_slash = cp;
+	}
+	pathlen = cp - path;
+	if (last_slash) {
+		basename = last_slash + 1;
+		dirlen = last_slash - path;
+	} else {
+		basename = path;
+		dirlen = 0;
+	}
+
+	prepare_attr_stack(path, dirlen);
 	for (i = 0; i < attr_nr; i++)
 		check_all_attr[i].value = ATTR__UNKNOWN;
 
-	basename = find_basename(path);
-	pathlen = strlen(path);
 	rem = attr_nr;
 	for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
 		rem = fill(path, pathlen, basename, stk, rem);
diff --git a/builtin/apply.c b/builtin/apply.c
index 6c11e8b..9706ca7 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -3609,7 +3609,6 @@
 	 * worth showing the new sha1 prefix, but until then...
 	 */
 	for (patch = list; patch; patch = patch->next) {
-		const unsigned char *sha1_ptr;
 		unsigned char sha1[20];
 		struct cache_entry *ce;
 		const char *name;
@@ -3617,20 +3616,23 @@
 		name = patch->old_name ? patch->old_name : patch->new_name;
 		if (0 < patch->is_new)
 			continue;
-		else if (get_sha1_blob(patch->old_sha1_prefix, sha1))
-			/* git diff has no index line for mode/type changes */
-			if (!patch->lines_added && !patch->lines_deleted) {
-				if (get_current_sha1(patch->old_name, sha1))
-					die("mode change for %s, which is not "
-						"in current HEAD", name);
-				sha1_ptr = sha1;
-			} else
-				die("sha1 information is lacking or useless "
-					"(%s).", name);
-		else
-			sha1_ptr = sha1;
 
-		ce = make_cache_entry(patch->old_mode, sha1_ptr, name, 0, 0);
+		if (S_ISGITLINK(patch->old_mode)) {
+			if (get_sha1_hex(patch->old_sha1_prefix, sha1))
+				die("submoule change for %s without full index name",
+				    name);
+		} else if (!get_sha1_blob(patch->old_sha1_prefix, sha1)) {
+			; /* ok */
+		} else if (!patch->lines_added && !patch->lines_deleted) {
+			/* mode-only change: update the current */
+			if (get_current_sha1(patch->old_name, sha1))
+				die("mode change for %s, which is not "
+				    "in current HEAD", name);
+		} else
+			die("sha1 information is lacking or useless "
+			    "(%s).", name);
+
+		ce = make_cache_entry(patch->old_mode, sha1, name, 0, 0);
 		if (!ce)
 			die(_("make_cache_entry failed for path '%s'"), name);
 		if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD))
diff --git a/builtin/branch.c b/builtin/branch.c
index 1ec9c02..947c84b 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -850,11 +850,11 @@
 		const char *branch_name;
 		struct strbuf branch_ref = STRBUF_INIT;
 
-		if (detached)
-			die("Cannot give description to detached HEAD");
-		if (!argc)
+		if (!argc) {
+			if (detached)
+				die("Cannot give description to detached HEAD");
 			branch_name = head;
-		else if (argc == 1)
+		} else if (argc == 1)
 			branch_name = argv[0];
 		else
 			usage_with_options(builtin_branch_usage, options);
diff --git a/builtin/help.c b/builtin/help.c
index bd86253..6067a61 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -6,7 +6,6 @@
 #include "cache.h"
 #include "builtin.h"
 #include "exec_cmd.h"
-#include "common-cmds.h"
 #include "parse-options.h"
 #include "run-command.h"
 #include "column.h"
@@ -287,23 +286,6 @@
 
 static struct cmdnames main_cmds, other_cmds;
 
-void list_common_cmds_help(void)
-{
-	int i, longest = 0;
-
-	for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
-		if (longest < strlen(common_cmds[i].name))
-			longest = strlen(common_cmds[i].name);
-	}
-
-	puts(_("The most commonly used git commands are:"));
-	for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
-		printf("   %s   ", common_cmds[i].name);
-		mput_char(' ', longest - strlen(common_cmds[i].name));
-		puts(_(common_cmds[i].help));
-	}
-}
-
 static int is_git_command(const char *s)
 {
 	return is_in_cmdlist(&main_cmds, s) ||
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
index 2338832..be5e514 100644
--- a/builtin/merge-index.c
+++ b/builtin/merge-index.c
@@ -42,7 +42,7 @@
 	return found;
 }
 
-static void merge_file(const char *path)
+static void merge_one_path(const char *path)
 {
 	int pos = cache_name_pos(path, strlen(path));
 
@@ -102,7 +102,7 @@
 			}
 			die("git merge-index: unknown option %s", arg);
 		}
-		merge_file(arg);
+		merge_one_path(arg);
 	}
 	if (err && !quiet)
 		die("merge program failed");
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 897a563..e0d0b7d 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -3,17 +3,15 @@
 #include "xdiff-interface.h"
 #include "blob.h"
 #include "exec_cmd.h"
-#include "merge-file.h"
+#include "merge-blobs.h"
 
 static const char merge_tree_usage[] = "git merge-tree <base-tree> <branch1> <branch2>";
-static int resolve_directories = 1;
 
 struct merge_list {
 	struct merge_list *next;
 	struct merge_list *link;	/* other stages for this object */
 
-	unsigned int stage : 2,
-		     flags : 30;
+	unsigned int stage : 2;
 	unsigned int mode;
 	const char *path;
 	struct blob *blob;
@@ -27,7 +25,7 @@
 	merge_result_end = &entry->next;
 }
 
-static void merge_trees(struct tree_desc t[3], const char *base);
+static void merge_trees_recursive(struct tree_desc t[3], const char *base, int df_conflict);
 
 static const char *explanation(struct merge_list *entry)
 {
@@ -76,7 +74,7 @@
 	their = NULL;
 	if (entry)
 		their = entry->blob;
-	return merge_file(path, base, our, their, size);
+	return merge_blobs(path, base, our, their, size);
 }
 
 static void *origin(struct merge_list *entry, unsigned long *size)
@@ -174,17 +172,17 @@
 	return make_traverse_path(path, info, n);
 }
 
-static void resolve(const struct traverse_info *info, struct name_entry *branch1, struct name_entry *result)
+static void resolve(const struct traverse_info *info, struct name_entry *ours, struct name_entry *result)
 {
 	struct merge_list *orig, *final;
 	const char *path;
 
-	/* If it's already branch1, don't bother showing it */
-	if (!branch1)
+	/* If it's already ours, don't bother showing it */
+	if (!ours)
 		return;
 
 	path = traverse_path(info, result);
-	orig = create_entry(2, branch1->mode, branch1->sha1, path);
+	orig = create_entry(2, ours->mode, ours->sha1, path);
 	final = create_entry(0, result->mode, result->sha1, path);
 
 	final->link = orig;
@@ -192,34 +190,35 @@
 	add_merge_entry(final);
 }
 
-static int unresolved_directory(const struct traverse_info *info, struct name_entry n[3])
+static void unresolved_directory(const struct traverse_info *info, struct name_entry n[3],
+				 int df_conflict)
 {
 	char *newbase;
 	struct name_entry *p;
 	struct tree_desc t[3];
 	void *buf0, *buf1, *buf2;
 
-	if (!resolve_directories)
-		return 0;
-	p = n;
-	if (!p->mode) {
-		p++;
-		if (!p->mode)
-			p++;
+	for (p = n; p < n + 3; p++) {
+		if (p->mode && S_ISDIR(p->mode))
+			break;
 	}
-	if (!S_ISDIR(p->mode))
-		return 0;
+	if (n + 3 <= p)
+		return; /* there is no tree here */
+
 	newbase = traverse_path(info, p);
-	buf0 = fill_tree_descriptor(t+0, n[0].sha1);
-	buf1 = fill_tree_descriptor(t+1, n[1].sha1);
-	buf2 = fill_tree_descriptor(t+2, n[2].sha1);
-	merge_trees(t, newbase);
+
+#define ENTRY_SHA1(e) (((e)->mode && S_ISDIR((e)->mode)) ? (e)->sha1 : NULL)
+	buf0 = fill_tree_descriptor(t+0, ENTRY_SHA1(n + 0));
+	buf1 = fill_tree_descriptor(t+1, ENTRY_SHA1(n + 1));
+	buf2 = fill_tree_descriptor(t+2, ENTRY_SHA1(n + 2));
+#undef ENTRY_SHA1
+
+	merge_trees_recursive(t, newbase, df_conflict);
 
 	free(buf0);
 	free(buf1);
 	free(buf2);
 	free(newbase);
-	return 1;
 }
 
 
@@ -242,18 +241,26 @@
 static void unresolved(const struct traverse_info *info, struct name_entry n[3])
 {
 	struct merge_list *entry = NULL;
+	int i;
+	unsigned dirmask = 0, mask = 0;
 
-	if (unresolved_directory(info, n))
+	for (i = 0; i < 3; i++) {
+		mask |= (1 << 1);
+		if (n[i].mode && S_ISDIR(n[i].mode))
+			dirmask |= (1 << i);
+	}
+
+	unresolved_directory(info, n, dirmask && (dirmask != mask));
+
+	if (dirmask == mask)
 		return;
 
-	/*
-	 * Do them in reverse order so that the resulting link
-	 * list has the stages in order - link_entry adds new
-	 * links at the front.
-	 */
-	entry = link_entry(3, info, n + 2, entry);
-	entry = link_entry(2, info, n + 1, entry);
-	entry = link_entry(1, info, n + 0, entry);
+	if (n[2].mode && !S_ISDIR(n[2].mode))
+		entry = link_entry(3, info, n + 2, entry);
+	if (n[1].mode && !S_ISDIR(n[1].mode))
+		entry = link_entry(2, info, n + 1, entry);
+	if (n[0].mode && !S_ISDIR(n[0].mode))
+		entry = link_entry(1, info, n + 0, entry);
 
 	add_merge_entry(entry);
 }
@@ -292,20 +299,29 @@
 	/* Same in both? */
 	if (same_entry(entry+1, entry+2)) {
 		if (entry[0].sha1) {
+			/* Modified identically */
 			resolve(info, NULL, entry+1);
 			return mask;
 		}
+		/* "Both added the same" is left unresolved */
 	}
 
 	if (same_entry(entry+0, entry+1)) {
 		if (entry[2].sha1 && !S_ISDIR(entry[2].mode)) {
+			/* We did not touch, they modified -- take theirs */
 			resolve(info, entry+1, entry+2);
 			return mask;
 		}
+		/*
+		 * If we did not touch a directory but they made it
+		 * into a file, we fall through and unresolved()
+		 * recurses down.  Likewise for the opposite case.
+		 */
 	}
 
 	if (same_entry(entry+0, entry+2)) {
 		if (entry[1].sha1 && !S_ISDIR(entry[1].mode)) {
+			/* We modified, they did not touch -- take ours */
 			resolve(info, NULL, entry+1);
 			return mask;
 		}
@@ -315,15 +331,21 @@
 	return mask;
 }
 
-static void merge_trees(struct tree_desc t[3], const char *base)
+static void merge_trees_recursive(struct tree_desc t[3], const char *base, int df_conflict)
 {
 	struct traverse_info info;
 
 	setup_traverse_info(&info, base);
+	info.data = &df_conflict;
 	info.fn = threeway_callback;
 	traverse_trees(3, t, &info);
 }
 
+static void merge_trees(struct tree_desc t[3], const char *base)
+{
+	merge_trees_recursive(t, base, 0);
+}
+
 static void *get_tree_descriptor(struct tree_desc *desc, const char *rev)
 {
 	unsigned char sha1[20];
diff --git a/cache.h b/cache.h
index 18fdd18..2b192d2 100644
--- a/cache.h
+++ b/cache.h
@@ -714,10 +714,11 @@
 }
 int is_directory(const char *);
 const char *real_path(const char *path);
+const char *real_path_if_valid(const char *path);
 const char *absolute_path(const char *path);
 const char *relative_path(const char *abs, const char *base);
 int normalize_path_copy(char *dst, const char *src);
-int longest_ancestor_length(const char *path, const char *prefix_list);
+int longest_ancestor_length(const char *path, struct string_list *prefixes);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
 int offset_1st_component(const char *path);
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index a4c48e1..2186b4b 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -397,7 +397,7 @@
 		*)   pfx="$ref:$pfx" ;;
 		esac
 
-		__gitcomp_nl "$(git --git-dir="$(__gitdir)" ls-tree "$ls" \
+		__gitcomp_nl "$(git --git-dir="$(__gitdir)" ls-tree "$ls" 2>/dev/null \
 				| sed '/^100... blob /{
 				           s,^.*	,,
 				           s,$, ,
@@ -531,10 +531,19 @@
 	return 1
 }
 
+__git_commands () {
+	if test -n "${GIT_TESTING_COMMAND_COMPLETION:-}"
+	then
+		printf "%s" "${GIT_TESTING_COMMAND_COMPLETION}"
+	else
+		git help -a|egrep '^  [a-zA-Z0-9]'
+	fi
+}
+
 __git_list_all_commands ()
 {
 	local i IFS=" "$'\n'
-	for i in $(git help -a|egrep '^  [a-zA-Z0-9]')
+	for i in $(__git_commands)
 	do
 		case $i in
 		*--*)             : helper pattern;;
@@ -2431,7 +2440,7 @@
 				--*=*|*.) ;;
 				*) c="$c " ;;
 				esac
-				array+=("$c")
+				array[$#array+1]="$c"
 			done
 			compset -P '*[=:]'
 			compadd -Q -S '' -p "${2-}" -a -- array && _ret=0
diff --git a/contrib/completion/git-completion.tcsh b/contrib/completion/git-completion.tcsh
index 8aafb63..3e3889f 100644
--- a/contrib/completion/git-completion.tcsh
+++ b/contrib/completion/git-completion.tcsh
@@ -13,6 +13,7 @@
 #
 # To use this completion script:
 #
+#    0) You need tcsh 6.16.00 or newer.
 #    1) Copy both this file and the bash completion script to ${HOME}.
 #       You _must_ use the name ${HOME}/.git-completion.bash for the
 #       bash script.
@@ -24,6 +25,15 @@
 #        set autolist=ambiguous
 #       It will tell tcsh to list the possible completion choices.
 
+set __git_tcsh_completion_version = `\echo ${tcsh} | \sed 's/\./ /g'`
+if ( ${__git_tcsh_completion_version[1]} < 6 || \
+     ( ${__git_tcsh_completion_version[1]} == 6 && \
+       ${__git_tcsh_completion_version[2]} < 16 ) ) then
+	echo "git-completion.tcsh: Your version of tcsh is too old, you need version 6.16.00 or newer.  Git completion will not work."
+	exit
+endif
+unset __git_tcsh_completion_version
+
 set __git_tcsh_completion_original_script = ${HOME}/.git-completion.bash
 set __git_tcsh_completion_script = ${HOME}/.git-completion.tcsh.bash
 
@@ -64,9 +74,7 @@
 _\${1}
 
 IFS=\$'\n'
-if [ \${#COMPREPLY[*]} -gt 0 ]; then
-	echo "\${COMPREPLY[*]}" | sort | uniq
-else
+if [ \${#COMPREPLY[*]} -eq 0 ]; then
 	# No completions suggested.  In this case, we want tcsh to perform
 	# standard file completion.  However, there does not seem to be way
 	# to tell tcsh to do that.  To help the user, we try to simulate
@@ -85,19 +93,20 @@
 		# We don't support ~ expansion: too tricky.
 		if [ "\${TO_COMPLETE:0:1}" != "~" ]; then
 			# Use ls so as to add the '/' at the end of directories.
-			RESULT=(\`ls -dp \${TO_COMPLETE}* 2> /dev/null\`)
-			echo \${RESULT[*]}
-
-			# If there is a single completion and it is a directory,
-			# we output it a second time to trick tcsh into not adding a space
-			# after it.
-			if [ \${#RESULT[*]} -eq 1 ] && [ "\${RESULT[0]: -1}" == "/" ]; then
-				echo \${RESULT[*]}
-			fi
+			COMPREPLY=(\`ls -dp \${TO_COMPLETE}* 2> /dev/null\`)
 		fi
 	fi
 fi
 
+# tcsh does not automatically remove duplicates, so we do it ourselves
+echo "\${COMPREPLY[*]}" | sort | uniq
+
+# If there is a single completion and it is a directory, we output it
+# a second time to trick tcsh into not adding a space after it.
+if [ \${#COMPREPLY[*]} -eq 1 ] && [ "\${COMPREPLY[0]: -1}" == "/" ]; then
+	echo "\${COMPREPLY[*]}"
+fi
+
 EOF
 
 # Don't need this variable anymore, so don't pollute the users environment
diff --git a/contrib/vim/README b/contrib/vim/README
index fca1e17..8f16d06 100644
--- a/contrib/vim/README
+++ b/contrib/vim/README
@@ -17,16 +17,6 @@
 
   1. Copy these files to vim's syntax directory $HOME/.vim/syntax
   2. To auto-detect the editing of various git-related filetypes:
-	$ cat >>$HOME/.vim/filetype.vim <<'EOF'
-	autocmd BufNewFile,BufRead *.git/COMMIT_EDITMSG    setf gitcommit
-	autocmd BufNewFile,BufRead *.git/config,.gitconfig setf gitconfig
-	autocmd BufNewFile,BufRead git-rebase-todo         setf gitrebase
-	autocmd BufNewFile,BufRead .msg.[0-9]*
-		\ if getline(1) =~ '^From.*# This line is ignored.$' |
-		\   setf gitsendemail |
-		\ endif
-	autocmd BufNewFile,BufRead *.git/**
-		\ if getline(1) =~ '^\x\{40\}\>\|^ref: ' |
-		\   setf git |
-		\ endif
-	EOF
+
+	$ curl http://ftp.vim.org/pub/vim/runtime/filetype.vim |
+		sed -ne '/^" Git$/, /^$/ p' >>$HOME/.vim/filetype.vim
diff --git a/dir.c b/dir.c
index 5a83aa7..a473ca2 100644
--- a/dir.c
+++ b/dir.c
@@ -732,7 +732,8 @@
 
 static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
 {
-	if (cache_name_exists(pathname, len, ignore_case))
+	if (!(dir->flags & DIR_SHOW_IGNORED) &&
+	    cache_name_exists(pathname, len, ignore_case))
 		return NULL;
 
 	ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
@@ -834,8 +835,9 @@
  * traversal routine.
  *
  * Case 1: If we *already* have entries in the index under that
- * directory name, we always recurse into the directory to see
- * all the files.
+ * directory name, we recurse into the directory to see all the files,
+ * unless the directory is excluded and we want to show ignored
+ * directories
  *
  * Case 2: If we *already* have that directory name as a gitlink,
  * we always continue to see it as a gitlink, regardless of whether
@@ -849,6 +851,9 @@
  *      just a directory, unless "hide_empty_directories" is
  *      also true and the directory is empty, in which case
  *      we just ignore it entirely.
+ *      if we are looking for ignored directories, look if it
+ *      contains only ignored files to decide if it must be shown as
+ *      ignored or not.
  *  (b) if it looks like a git directory, and we don't have
  *      'no_gitlinks' set we treat it as a gitlink, and show it
  *      as a directory.
@@ -861,12 +866,15 @@
 };
 
 static enum directory_treatment treat_directory(struct dir_struct *dir,
-	const char *dirname, int len,
+	const char *dirname, int len, int exclude,
 	const struct path_simplify *simplify)
 {
 	/* The "len-1" is to strip the final '/' */
 	switch (directory_exists_in_index(dirname, len-1)) {
 	case index_directory:
+		if ((dir->flags & DIR_SHOW_OTHER_DIRECTORIES) && exclude)
+			break;
+
 		return recurse_into_directory;
 
 	case index_gitdir:
@@ -886,7 +894,23 @@
 	}
 
 	/* This is the "show_other_directories" case */
-	if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
+
+	/*
+	 * We are looking for ignored files and our directory is not ignored,
+	 * check if it contains only ignored files
+	 */
+	if ((dir->flags & DIR_SHOW_IGNORED) && !exclude) {
+		int ignored;
+		dir->flags &= ~DIR_SHOW_IGNORED;
+		dir->flags |= DIR_HIDE_EMPTY_DIRECTORIES;
+		ignored = read_directory_recursive(dir, dirname, len, 1, simplify);
+		dir->flags &= ~DIR_HIDE_EMPTY_DIRECTORIES;
+		dir->flags |= DIR_SHOW_IGNORED;
+
+		return ignored ? ignore_directory : show_directory;
+	}
+	if (!(dir->flags & DIR_SHOW_IGNORED) &&
+	    !(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
 		return show_directory;
 	if (!read_directory_recursive(dir, dirname, len, 1, simplify))
 		return ignore_directory;
@@ -894,6 +918,45 @@
 }
 
 /*
+ * Decide what to do when we find a file while traversing the
+ * filesystem. Mostly two cases:
+ *
+ *  1. We are looking for ignored files
+ *   (a) File is ignored, include it
+ *   (b) File is in ignored path, include it
+ *   (c) File is not ignored, exclude it
+ *
+ *  2. Other scenarios, include the file if not excluded
+ *
+ * Return 1 for exclude, 0 for include.
+ */
+static int treat_file(struct dir_struct *dir, struct strbuf *path, int exclude, int *dtype)
+{
+	struct path_exclude_check check;
+	int exclude_file = 0;
+
+	if (exclude)
+		exclude_file = !(dir->flags & DIR_SHOW_IGNORED);
+	else if (dir->flags & DIR_SHOW_IGNORED) {
+		/* Always exclude indexed files */
+		struct cache_entry *ce = index_name_exists(&the_index,
+		    path->buf, path->len, ignore_case);
+
+		if (ce)
+			return 1;
+
+		path_exclude_check_init(&check, dir);
+
+		if (!path_excluded(&check, path->buf, path->len, dtype))
+			exclude_file = 1;
+
+		path_exclude_check_clear(&check);
+	}
+
+	return exclude_file;
+}
+
+/*
  * This is an inexact early pruning of any recursive directory
  * reading - if the path cannot possibly be in the pathspec,
  * return true, and we'll skip it early.
@@ -1031,27 +1094,14 @@
 	if (dtype == DT_UNKNOWN)
 		dtype = get_dtype(de, path->buf, path->len);
 
-	/*
-	 * Do we want to see just the ignored files?
-	 * We still need to recurse into directories,
-	 * even if we don't ignore them, since the
-	 * directory may contain files that we do..
-	 */
-	if (!exclude && (dir->flags & DIR_SHOW_IGNORED)) {
-		if (dtype != DT_DIR)
-			return path_ignored;
-	}
-
 	switch (dtype) {
 	default:
 		return path_ignored;
 	case DT_DIR:
 		strbuf_addch(path, '/');
-		switch (treat_directory(dir, path->buf, path->len, simplify)) {
+
+		switch (treat_directory(dir, path->buf, path->len, exclude, simplify)) {
 		case show_directory:
-			if (exclude != !!(dir->flags
-					  & DIR_SHOW_IGNORED))
-				return path_ignored;
 			break;
 		case recurse_into_directory:
 			return path_recurse;
@@ -1061,7 +1111,12 @@
 		break;
 	case DT_REG:
 	case DT_LNK:
-		break;
+		switch (treat_file(dir, path, exclude, &dtype)) {
+		case 1:
+			return path_ignored;
+		default:
+			break;
+		}
 	}
 	return path_handled;
 }
diff --git a/git-am.sh b/git-am.sh
index c682d34..202130f 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -334,7 +334,7 @@
 			# Since we cannot guarantee that the commit message is in
 			# git-friendly format, we put no Subject: line and just consume
 			# all of the message as the body
-			perl -M'POSIX qw(strftime)' -ne 'BEGIN { $subject = 0 }
+			LANG=C LC_ALL=C perl -M'POSIX qw(strftime)' -ne 'BEGIN { $subject = 0 }
 				if ($subject) { print ; }
 				elsif (/^\# User /) { s/\# User/From:/ ; print ; }
 				elsif (/^\# Date /) {
@@ -664,7 +664,7 @@
 			sed -e '1,/^$/d' >"$dotest/msg-clean"
 			echo "$commit" >"$dotest/original-commit"
 			get_author_ident_from_commit "$commit" >"$dotest/author-script"
-			git diff-tree --root --binary "$commit" >"$dotest/patch"
+			git diff-tree --root --binary --full-index "$commit" >"$dotest/patch"
 		else
 			git mailinfo $keep $no_inbody_headers $scissors $utf8 "$dotest/msg" "$dotest/patch" \
 				<"$dotest/$msgnum" >"$dotest/info" ||
diff --git a/git-p4.py b/git-p4.py
index 551aec9..0682e61 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -12,6 +12,21 @@
 import tempfile, getopt, os.path, time, platform
 import re, shutil
 
+try:
+    from subprocess import CalledProcessError
+except ImportError:
+    # from python2.7:subprocess.py
+    # Exception classes used by this module.
+    class CalledProcessError(Exception):
+        """This exception is raised when a process run by check_call() returns
+        a non-zero exit status.  The exit status will be stored in the
+        returncode attribute."""
+        def __init__(self, returncode, cmd):
+            self.returncode = returncode
+            self.cmd = cmd
+        def __str__(self):
+            return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
+
 verbose = False
 
 # Only labels/tags matching this will be imported/exported
@@ -152,13 +167,17 @@
     expand = isinstance(cmd,basestring)
     if verbose:
         sys.stderr.write("executing %s\n" % str(cmd))
-    subprocess.check_call(cmd, shell=expand)
+    retcode = subprocess.call(cmd, shell=expand)
+    if retcode:
+        raise CalledProcessError(retcode, cmd)
 
 def p4_system(cmd):
     """Specifically invoke p4 as the system command. """
     real_cmd = p4_build_cmd(cmd)
     expand = isinstance(real_cmd, basestring)
-    subprocess.check_call(real_cmd, shell=expand)
+    retcode = subprocess.call(real_cmd, shell=expand)
+    if retcode:
+        raise CalledProcessError(retcode, real_cmd)
 
 def p4_integrate(src, dest):
     p4_system(["integrate", "-Dt", wildcard_encode(src), wildcard_encode(dest)])
@@ -742,7 +761,8 @@
     return path
 
 def wildcard_present(path):
-    return path.translate(None, "*#@%") != path
+    m = re.search("[*#@%]", path)
+    return m is not None
 
 class Command:
     def __init__(self):
@@ -3103,7 +3123,9 @@
         init_cmd = [ "git", "init" ]
         if self.cloneBare:
             init_cmd.append("--bare")
-        subprocess.check_call(init_cmd)
+        retcode = subprocess.call(init_cmd)
+        if retcode:
+            raise CalledProcessError(retcode, init_cmd)
 
         if not P4Sync.run(self, depotPaths):
             return False
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 44901d5..8ed7fcc 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -190,6 +190,11 @@
 	test "$tree" = "$ptree"
 }
 
+is_merge_commit()
+{
+	git rev-parse --verify --quiet "$1"^2 >/dev/null 2>&1
+}
+
 # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
 # GIT_AUTHOR_DATE exported from the current environment.
 do_with_author () {
@@ -874,7 +879,7 @@
 while read -r shortsha1 rest
 do
 
-	if test -z "$keep_empty" && is_empty_commit $shortsha1
+	if test -z "$keep_empty" && is_empty_commit $shortsha1 && ! is_merge_commit $shortsha1
 	then
 		comment_out="# "
 	else
diff --git a/git-send-email.perl b/git-send-email.perl
index 94c7f76..be809e5 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1285,10 +1285,10 @@
 		}
 
 		if (defined $input_format && $input_format eq 'mbox') {
-			if (/^Subject:\s+(.*)$/) {
+			if (/^Subject:\s+(.*)$/i) {
 				$subject = $1;
 			}
-			elsif (/^From:\s+(.*)$/) {
+			elsif (/^From:\s+(.*)$/i) {
 				($author, $author_encoding) = unquote_rfc2047($1);
 				next if $suppress_cc{'author'};
 				next if $suppress_cc{'self'} and $author eq $sender;
@@ -1296,14 +1296,14 @@
 					$1, $_) unless $quiet;
 				push @cc, $1;
 			}
-			elsif (/^To:\s+(.*)$/) {
+			elsif (/^To:\s+(.*)$/i) {
 				foreach my $addr (parse_address_line($1)) {
 					printf("(mbox) Adding to: %s from line '%s'\n",
 						$addr, $_) unless $quiet;
 					push @to, $addr;
 				}
 			}
-			elsif (/^Cc:\s+(.*)$/) {
+			elsif (/^Cc:\s+(.*)$/i) {
 				foreach my $addr (parse_address_line($1)) {
 					if (unquote_rfc2047($addr) eq $sender) {
 						next if ($suppress_cc{'self'});
@@ -1325,7 +1325,7 @@
 			elsif (/^Message-Id: (.*)/i) {
 				$message_id = $1;
 			}
-			elsif (!/^Date:\s/ && /^[-A-Za-z]+:\s+\S/) {
+			elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) {
 				push @xh, $_;
 			}
 
diff --git a/gpg-interface.c b/gpg-interface.c
index 0863c61..5f142f6 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -130,8 +130,10 @@
 	write_in_full(gpg.in, payload, payload_size);
 	close(gpg.in);
 
-	if (gpg_output)
+	if (gpg_output) {
 		strbuf_read(gpg_output, gpg.err, 0);
+		close(gpg.err);
+	}
 	ret = finish_command(&gpg);
 
 	unlink_or_warn(path);
diff --git a/help.c b/help.c
index 2a42ec6..1dfa0b0 100644
--- a/help.c
+++ b/help.c
@@ -223,6 +223,23 @@
 	}
 }
 
+void list_common_cmds_help(void)
+{
+	int i, longest = 0;
+
+	for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
+		if (longest < strlen(common_cmds[i].name))
+			longest = strlen(common_cmds[i].name);
+	}
+
+	puts(_("The most commonly used git commands are:"));
+	for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
+		printf("   %s   ", common_cmds[i].name);
+		mput_char(' ', longest - strlen(common_cmds[i].name));
+		puts(_(common_cmds[i].help));
+	}
+}
+
 int is_in_cmdlist(struct cmdnames *c, const char *s)
 {
 	int i;
diff --git a/ident.c b/ident.c
index ac9672f..1c123e6 100644
--- a/ident.c
+++ b/ident.c
@@ -46,6 +46,7 @@
 static int add_mailname_host(struct strbuf *buf)
 {
 	FILE *mailname;
+	struct strbuf mailnamebuf = STRBUF_INIT;
 
 	mailname = fopen("/etc/mailname", "r");
 	if (!mailname) {
@@ -54,14 +55,17 @@
 				strerror(errno));
 		return -1;
 	}
-	if (strbuf_getline(buf, mailname, '\n') == EOF) {
+	if (strbuf_getline(&mailnamebuf, mailname, '\n') == EOF) {
 		if (ferror(mailname))
 			warning("cannot read /etc/mailname: %s",
 				strerror(errno));
+		strbuf_release(&mailnamebuf);
 		fclose(mailname);
 		return -1;
 	}
 	/* success! */
+	strbuf_addbuf(buf, &mailnamebuf);
+	strbuf_release(&mailnamebuf);
 	fclose(mailname);
 	return 0;
 }
diff --git a/merge-file.c b/merge-blobs.c
similarity index 94%
rename from merge-file.c
rename to merge-blobs.c
index 7845528..57211bc 100644
--- a/merge-file.c
+++ b/merge-blobs.c
@@ -3,7 +3,7 @@
 #include "xdiff-interface.h"
 #include "ll-merge.h"
 #include "blob.h"
-#include "merge-file.h"
+#include "merge-blobs.h"
 
 static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
 {
@@ -80,7 +80,7 @@
 	return xdi_diff(f1, f2, &xpp, &xecfg, &ecb);
 }
 
-void *merge_file(const char *path, struct blob *base, struct blob *our, struct blob *their, unsigned long *size)
+void *merge_blobs(const char *path, struct blob *base, struct blob *our, struct blob *their, unsigned long *size)
 {
 	void *res = NULL;
 	mmfile_t f1, f2, common;
diff --git a/merge-blobs.h b/merge-blobs.h
new file mode 100644
index 0000000..62b569e
--- /dev/null
+++ b/merge-blobs.h
@@ -0,0 +1,8 @@
+#ifndef MERGE_BLOBS_H
+#define MERGE_BLOBS_H
+
+#include "blob.h"
+
+extern void *merge_blobs(const char *, struct blob *, struct blob *, struct blob *, unsigned long *);
+
+#endif /* MERGE_BLOBS_H */
diff --git a/merge-file.h b/merge-file.h
deleted file mode 100644
index 9b3b83a..0000000
--- a/merge-file.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef MERGE_FILE_H
-#define MERGE_FILE_H
-
-extern void *merge_file(const char *path, struct blob *base, struct blob *our,
-			struct blob *their, unsigned long *size);
-
-#endif
diff --git a/merge-recursive.c b/merge-recursive.c
index d882060..33ba5dc 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -976,7 +976,7 @@
 	return mfi;
 }
 
-static struct merge_file_info merge_file(struct merge_options *o,
+static struct merge_file_info merge_file_one(struct merge_options *o,
 					 const char *path,
 					 const unsigned char *o_sha, int o_mode,
 					 const unsigned char *a_sha, int a_mode,
@@ -1166,7 +1166,7 @@
 		struct merge_file_info mfi;
 		struct diff_filespec other;
 		struct diff_filespec *add;
-		mfi = merge_file(o, one->path,
+		mfi = merge_file_one(o, one->path,
 				 one->sha1, one->mode,
 				 a->sha1, a->mode,
 				 b->sha1, b->mode,
@@ -1450,7 +1450,7 @@
 				       ren1_dst, branch2);
 				if (o->call_depth) {
 					struct merge_file_info mfi;
-					mfi = merge_file(o, ren1_dst, null_sha1, 0,
+					mfi = merge_file_one(o, ren1_dst, null_sha1, 0,
 							 ren1->pair->two->sha1, ren1->pair->two->mode,
 							 dst_other.sha1, dst_other.mode,
 							 branch1, branch2);
diff --git a/path.c b/path.c
index cbbdf7d..d3d3f8b 100644
--- a/path.c
+++ b/path.c
@@ -12,6 +12,7 @@
  */
 #include "cache.h"
 #include "strbuf.h"
+#include "string-list.h"
 
 static char bad_path[] = "/bad-path/";
 
@@ -569,43 +570,38 @@
 
 /*
  * path = Canonical absolute path
- * prefix_list = Colon-separated list of absolute paths
+ * prefixes = string_list containing normalized, absolute paths without
+ * trailing slashes (except for the root directory, which is denoted by "/").
  *
- * Determines, for each path in prefix_list, whether the "prefix" really
+ * Determines, for each path in prefixes, whether the "prefix"
  * is an ancestor directory of path.  Returns the length of the longest
  * ancestor directory, excluding any trailing slashes, or -1 if no prefix
- * is an ancestor.  (Note that this means 0 is returned if prefix_list is
- * "/".) "/foo" is not considered an ancestor of "/foobar".  Directories
+ * is an ancestor.  (Note that this means 0 is returned if prefixes is
+ * ["/"].) "/foo" is not considered an ancestor of "/foobar".  Directories
  * are not considered to be their own ancestors.  path must be in a
  * canonical form: empty components, or "." or ".." components are not
- * allowed.  prefix_list may be null, which is like "".
+ * allowed.
  */
-int longest_ancestor_length(const char *path, const char *prefix_list)
+int longest_ancestor_length(const char *path, struct string_list *prefixes)
 {
-	char buf[PATH_MAX+1];
-	const char *ceil, *colon;
-	int len, max_len = -1;
+	int i, max_len = -1;
 
-	if (prefix_list == NULL || !strcmp(path, "/"))
+	if (!strcmp(path, "/"))
 		return -1;
 
-	for (colon = ceil = prefix_list; *colon; ceil = colon+1) {
-		for (colon = ceil; *colon && *colon != PATH_SEP; colon++);
-		len = colon - ceil;
-		if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
-			continue;
-		strlcpy(buf, ceil, len+1);
-		if (normalize_path_copy(buf, buf) < 0)
-			continue;
-		len = strlen(buf);
-		if (len > 0 && buf[len-1] == '/')
-			buf[--len] = '\0';
+	for (i = 0; i < prefixes->nr; i++) {
+		const char *ceil = prefixes->items[i].string;
+		int len = strlen(ceil);
 
-		if (!strncmp(path, buf, len) &&
-		    path[len] == '/' &&
-		    len > max_len) {
+		if (len == 1 && ceil[0] == '/')
+			len = 0; /* root matches anything, with length 0 */
+		else if (!strncmp(path, ceil, len) && path[len] == '/')
+			; /* match of length len */
+		else
+			continue; /* no match */
+
+		if (len > max_len)
 			max_len = len;
-		}
 	}
 
 	return max_len;
diff --git a/setup.c b/setup.c
index 3a1b2fd..f108c4b 100644
--- a/setup.c
+++ b/setup.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "dir.h"
+#include "string-list.h"
 
 static int inside_git_dir = -1;
 static int inside_work_tree = -1;
@@ -621,16 +622,38 @@
 }
 
 /*
+ * A "string_list_each_func_t" function that canonicalizes an entry
+ * from GIT_CEILING_DIRECTORIES using real_path_if_valid(), or
+ * discards it if unusable.
+ */
+static int canonicalize_ceiling_entry(struct string_list_item *item,
+				      void *unused)
+{
+	char *ceil = item->string;
+	const char *real_path;
+
+	if (!*ceil || !is_absolute_path(ceil))
+		return 0;
+	real_path = real_path_if_valid(ceil);
+	if (!real_path)
+		return 0;
+	free(item->string);
+	item->string = xstrdup(real_path);
+	return 1;
+}
+
+/*
  * 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.
  */
 static const char *setup_git_directory_gently_1(int *nongit_ok)
 {
 	const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
+	struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
 	static char cwd[PATH_MAX+1];
 	const char *gitdirenv, *ret;
 	char *gitfile;
-	int len, offset, offset_parent, ceil_offset;
+	int len, offset, offset_parent, ceil_offset = -1;
 	dev_t current_device = 0;
 	int one_filesystem = 1;
 
@@ -655,7 +678,14 @@
 	if (gitdirenv)
 		return setup_explicit_git_dir(gitdirenv, cwd, len, nongit_ok);
 
-	ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs);
+	if (env_ceiling_dirs) {
+		string_list_split(&ceiling_dirs, env_ceiling_dirs, PATH_SEP, -1);
+		filter_string_list(&ceiling_dirs, 0,
+				   canonicalize_ceiling_entry, NULL);
+		ceil_offset = longest_ancestor_length(cwd, &ceiling_dirs);
+		string_list_clear(&ceiling_dirs, 0);
+	}
+
 	if (ceil_offset < 0 && has_dos_drive_prefix(cwd))
 		ceil_offset = 1;
 
diff --git a/string-list.c b/string-list.c
index 397e6cf..480173f 100644
--- a/string-list.c
+++ b/string-list.c
@@ -145,26 +145,6 @@
 	filter_string_list(list, free_util, item_is_not_empty, NULL);
 }
 
-char *string_list_longest_prefix(const struct string_list *prefixes,
-				 const char *string)
-{
-	int i, max_len = -1;
-	char *retval = NULL;
-
-	for (i = 0; i < prefixes->nr; i++) {
-		char *prefix = prefixes->items[i].string;
-		if (!prefixcmp(string, prefix)) {
-			int len = strlen(prefix);
-			if (len > max_len) {
-				retval = prefix;
-				max_len = len;
-			}
-		}
-	}
-
-	return retval;
-}
-
 void string_list_clear(struct string_list *list, int free_util)
 {
 	if (list->items) {
diff --git a/string-list.h b/string-list.h
index c50b0d0..db12848 100644
--- a/string-list.h
+++ b/string-list.h
@@ -45,15 +45,6 @@
  */
 void string_list_remove_empty_items(struct string_list *list, int free_util);
 
-/*
- * Return the longest string in prefixes that is a prefix (in the
- * sense of prefixcmp()) of string, or NULL if no such prefix exists.
- * This function does not require the string_list to be sorted (it
- * does a linear search).
- */
-char *string_list_longest_prefix(const struct string_list *prefixes, const char *string);
-
-
 /* Use these functions only on sorted lists: */
 int string_list_has_string(const struct string_list *list, const char *string);
 int string_list_find_insert_index(const struct string_list *list, const char *string,
diff --git a/t/t0024-crlf-archive.sh b/t/t0024-crlf-archive.sh
index ec6c1b3..5378787 100755
--- a/t/t0024-crlf-archive.sh
+++ b/t/t0024-crlf-archive.sh
@@ -3,7 +3,12 @@
 test_description='respect crlf in git archive'
 
 . ./test-lib.sh
-UNZIP=${UNZIP:-unzip}
+GIT_UNZIP=${GIT_UNZIP:-unzip}
+
+test_lazy_prereq UNZIP '
+	"$GIT_UNZIP" -v
+	test $? -ne 127
+'
 
 test_expect_success setup '
 
@@ -26,18 +31,11 @@
 
 '
 
-"$UNZIP" -v >/dev/null 2>&1
-if [ $? -eq 127 ]; then
-	say "Skipping ZIP test, because unzip was not found"
-else
-	test_set_prereq UNZIP
-fi
-
 test_expect_success UNZIP 'zip archive' '
 
 	git archive --format=zip HEAD >test.zip &&
 
-	( mkdir unzipped && cd unzipped && unzip ../test.zip ) &&
+	( mkdir unzipped && cd unzipped && "$GIT_UNZIP" ../test.zip ) &&
 
 	test_cmp sample unzipped/sample
 
diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh
index 78816d9..05d78d2 100755
--- a/t/t0050-filesystem.sh
+++ b/t/t0050-filesystem.sh
@@ -29,12 +29,10 @@
 if test_have_prereq CASE_INSENSITIVE_FS
 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" '
-
 	test_must_fail git config --bool core.ignorecase >/dev/null ||
 	test $(git config --bool core.ignorecase) = false
 '
@@ -43,20 +41,17 @@
 if test_have_prereq SYMLINKS
 then
 test_expect_success "detection of filesystem w/o symlink support during repo init" '
-
 	test_must_fail git config --bool core.symlinks ||
 	test "$(git config --bool core.symlinks)" = true
 '
 else
 test_expect_success "detection of filesystem w/o symlink support during repo init" '
-
 	v=$(git config --bool core.symlinks) &&
 	test "$v" = false
 '
 fi
 
 test_expect_success "setup case tests" '
-
 	git config core.ignorecase true &&
 	touch camelcase &&
 	git add camelcase &&
@@ -67,29 +62,23 @@
 	git mv tmp CamelCase &&
 	git commit -m "rename" &&
 	git checkout -f master
-
 '
 
 $test_case 'rename (case change)' '
-
 	git mv camelcase CamelCase &&
 	git commit -m "rename"
-
 '
 
-$test_case 'merge (case change)' '
-
+test_expect_success 'merge (case change)' '
 	rm -f CamelCase &&
 	rm -f camelcase &&
 	git reset --hard initial &&
 	git merge topic
-
 '
 
 
 
-test_expect_failure 'add (with different case)' '
-
+test_expect_failure CASE_INSENSITIVE_FS 'add (with different case)' '
 	git reset --hard initial &&
 	rm camelcase &&
 	echo 1 >CamelCase &&
@@ -97,37 +86,30 @@
 	camel=$(git ls-files | grep -i camelcase) &&
 	test $(echo "$camel" | wc -l) = 1 &&
 	test "z$(git cat-file blob :$camel)" = z1
-
 '
 
 test_expect_success "setup unicode normalization tests" '
-
-  test_create_repo unicode &&
-  cd unicode &&
-  touch "$aumlcdiar" &&
-  git add "$aumlcdiar" &&
-  git commit -m initial &&
-  git tag initial &&
-  git checkout -b topic &&
-  git mv $aumlcdiar tmp &&
-  git mv tmp "$auml" &&
-  git commit -m rename &&
-  git checkout -f master
-
+	test_create_repo unicode &&
+	cd unicode &&
+	touch "$aumlcdiar" &&
+	git add "$aumlcdiar" &&
+	git commit -m initial &&
+	git tag initial &&
+	git checkout -b topic &&
+	git mv $aumlcdiar tmp &&
+	git mv tmp "$auml" &&
+	git commit -m rename &&
+	git checkout -f master
 '
 
 $test_unicode 'rename (silent unicode normalization)' '
-
- git mv "$aumlcdiar" "$auml" &&
- git commit -m rename
-
+	git mv "$aumlcdiar" "$auml" &&
+	git commit -m rename
 '
 
 $test_unicode 'merge (silent unicode normalization)' '
-
- git reset --hard initial &&
- git merge topic
-
+	git reset --hard initial &&
+	git merge topic
 '
 
 test_done
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 4ef2345..09a42a4 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -93,47 +93,32 @@
 norm_path /d1/.../d2 /d1/.../d2 POSIX
 norm_path /d1/..././../d2 /d1/d2 POSIX
 
-ancestor / "" -1
 ancestor / / -1
-ancestor /foo "" -1
-ancestor /foo : -1
-ancestor /foo ::. -1
-ancestor /foo ::..:: -1
 ancestor /foo / 0
 ancestor /foo /fo -1
 ancestor /foo /foo -1
-ancestor /foo /foo/ -1
 ancestor /foo /bar -1
-ancestor /foo /bar/ -1
 ancestor /foo /foo/bar -1
-ancestor /foo /foo:/bar/ -1
-ancestor /foo /foo/:/bar/ -1
-ancestor /foo /foo::/bar/ -1
-ancestor /foo /:/foo:/bar/ 0
-ancestor /foo /foo:/:/bar/ 0
-ancestor /foo /:/bar/:/foo 0
-ancestor /foo/bar "" -1
+ancestor /foo /foo:/bar -1
+ancestor /foo /:/foo:/bar 0
+ancestor /foo /foo:/:/bar 0
+ancestor /foo /:/bar:/foo 0
 ancestor /foo/bar / 0
 ancestor /foo/bar /fo -1
-ancestor /foo/bar foo -1
 ancestor /foo/bar /foo 4
-ancestor /foo/bar /foo/ 4
 ancestor /foo/bar /foo/ba -1
 ancestor /foo/bar /:/fo 0
 ancestor /foo/bar /foo:/foo/ba 4
 ancestor /foo/bar /bar -1
-ancestor /foo/bar /bar/ -1
-ancestor /foo/bar /fo: -1
-ancestor /foo/bar :/fo -1
-ancestor /foo/bar /foo:/bar/ 4
-ancestor /foo/bar /:/foo:/bar/ 4
-ancestor /foo/bar /foo:/:/bar/ 4
-ancestor /foo/bar /:/bar/:/fo 0
-ancestor /foo/bar /:/bar/ 0
-ancestor /foo/bar .:/foo/. 4
-ancestor /foo/bar .:/foo/.:.: 4
-ancestor /foo/bar /foo/./:.:/bar 4
-ancestor /foo/bar .:/bar -1
+ancestor /foo/bar /fo -1
+ancestor /foo/bar /foo:/bar 4
+ancestor /foo/bar /:/foo:/bar 4
+ancestor /foo/bar /foo:/:/bar 4
+ancestor /foo/bar /:/bar:/fo 0
+ancestor /foo/bar /:/bar 0
+ancestor /foo/bar /foo 4
+ancestor /foo/bar /foo:/bar 4
+ancestor /foo/bar /bar -1
 
 test_expect_success 'strip_path_suffix' '
 	test c:/msysgit = $(test-path-utils strip_path_suffix \
diff --git a/t/t0063-string-list.sh b/t/t0063-string-list.sh
index 41c8826..dbfc05e 100755
--- a/t/t0063-string-list.sh
+++ b/t/t0063-string-list.sh
@@ -17,14 +17,6 @@
 	"
 }
 
-test_longest_prefix () {
-	test "$(test-string-list longest_prefix "$1" "$2")" = "$3"
-}
-
-test_no_longest_prefix () {
-	test_must_fail test-string-list longest_prefix "$1" "$2"
-}
-
 test_split "foo:bar:baz" ":" "-1" <<EOF
 3
 [0]: "foo"
@@ -96,26 +88,4 @@
 	test a:b:c = "$(test-string-list remove_duplicates a:a:a:b:b:b:c:c:c)"
 '
 
-test_expect_success "test longest_prefix" '
-	test_no_longest_prefix - '' &&
-	test_no_longest_prefix - x &&
-	test_longest_prefix "" x "" &&
-	test_longest_prefix x x x &&
-	test_longest_prefix "" foo "" &&
-	test_longest_prefix : foo "" &&
-	test_longest_prefix f foo f &&
-	test_longest_prefix foo foobar foo &&
-	test_longest_prefix foo foo foo &&
-	test_no_longest_prefix bar foo &&
-	test_no_longest_prefix bar:bar foo &&
-	test_no_longest_prefix foobar foo &&
-	test_longest_prefix foo:bar foo foo &&
-	test_longest_prefix foo:bar bar bar &&
-	test_longest_prefix foo::bar foo foo &&
-	test_longest_prefix foo:foobar foo foo &&
-	test_longest_prefix foobar:foo foo foo &&
-	test_longest_prefix foo: bar "" &&
-	test_longest_prefix :foo bar ""
-'
-
 test_done
diff --git a/t/t4300-merge-tree.sh b/t/t4300-merge-tree.sh
index 46c3fe7..d0b2a45 100755
--- a/t/t4300-merge-tree.sh
+++ b/t/t4300-merge-tree.sh
@@ -254,4 +254,48 @@
 	test_cmp expected actual
 '
 
+test_expect_success 'turn file to tree' '
+	git reset --hard initial &&
+	rm initial-file &&
+	mkdir initial-file &&
+	test_commit "turn-file-to-tree" "initial-file/ONE" "CCC" &&
+	git merge-tree initial initial turn-file-to-tree >actual &&
+	cat >expect <<-\EOF &&
+	added in remote
+	  their  100644 43aa4fdec31eb92e1fdc2f0ce6ea9ddb7c32bcf7 initial-file/ONE
+	@@ -0,0 +1 @@
+	+CCC
+	removed in remote
+	  base   100644 e79c5e8f964493290a409888d5413a737e8e5dd5 initial-file
+	  our    100644 e79c5e8f964493290a409888d5413a737e8e5dd5 initial-file
+	@@ -1 +0,0 @@
+	-initial
+	EOF
+	test_cmp expect actual
+'
+
+test_expect_success 'turn tree to file' '
+	git reset --hard initial &&
+	mkdir dir &&
+	test_commit "add-tree" "dir/path" "AAA" &&
+	test_commit "add-another-tree" "dir/another" "BBB" &&
+	rm -fr dir &&
+	test_commit "make-file" "dir" "CCC" &&
+	git merge-tree add-tree add-another-tree make-file >actual &&
+	cat >expect <<-\EOF &&
+	added in local
+	  our    100644 ba629238ca89489f2b350e196ca445e09d8bb834 dir/another
+	removed in remote
+	  base   100644 43d5a8ed6ef6c00ff775008633f95787d088285d dir/path
+	  our    100644 43d5a8ed6ef6c00ff775008633f95787d088285d dir/path
+	@@ -1 +0,0 @@
+	-AAA
+	added in remote
+	  their  100644 43aa4fdec31eb92e1fdc2f0ce6ea9ddb7c32bcf7 dir
+	@@ -0,0 +1 @@
+	+CCC
+	EOF
+	test_cmp expect actual
+'
+
 test_done
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index ecf00ed..e7c240f 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -25,32 +25,11 @@
 '
 
 . ./test-lib.sh
-UNZIP=${UNZIP:-unzip}
 GZIP=${GZIP:-gzip}
 GUNZIP=${GUNZIP:-gzip -d}
 
 SUBSTFORMAT=%H%n
 
-check_zip() {
-	zipfile=$1.zip
-	listfile=$1.lst
-	dir=$1
-	dir_with_prefix=$dir/$2
-
-	test_expect_success UNZIP " extract ZIP archive" "
-		(mkdir $dir && cd $dir && $UNZIP ../$zipfile)
-	"
-
-	test_expect_success UNZIP " validate filenames" "
-		(cd ${dir_with_prefix}a && find .) | sort >$listfile &&
-		test_cmp a.lst $listfile
-	"
-
-	test_expect_success UNZIP " validate file contents" "
-		diff -r a ${dir_with_prefix}a
-	"
-}
-
 test_expect_success \
     'populate workdir' \
     'mkdir a b c &&
@@ -201,62 +180,12 @@
       test_cmp a/substfile2 g/prefix/a/substfile2
 '
 
-$UNZIP -v >/dev/null 2>&1
-if [ $? -eq 127 ]; then
-	say "Skipping ZIP tests, because unzip was not found"
-else
-	test_set_prereq UNZIP
-fi
-
-test_expect_success \
-    'git archive --format=zip' \
-    'git archive --format=zip HEAD >d.zip'
-
-check_zip d
-
-test_expect_success \
-    'git archive --format=zip in a bare repo' \
-    '(cd bare.git && git archive --format=zip HEAD) >d1.zip'
-
-test_expect_success \
-    'git archive --format=zip vs. the same in a bare repo' \
-    'test_cmp d.zip d1.zip'
-
-test_expect_success 'git archive --format=zip with --output' \
-    'git archive --format=zip --output=d2.zip HEAD &&
-    test_cmp d.zip d2.zip'
-
-test_expect_success 'git archive with --output, inferring format' '
-	git archive --output=d3.zip HEAD &&
-	test_cmp d.zip d3.zip
-'
-
 test_expect_success 'git archive with --output, override inferred format' '
 	git archive --format=tar --output=d4.zip HEAD &&
 	test_cmp b.tar d4.zip
 '
 
 test_expect_success \
-    'git archive --format=zip with prefix' \
-    'git archive --format=zip --prefix=prefix/ HEAD >e.zip'
-
-check_zip e prefix/
-
-test_expect_success 'git archive -0 --format=zip on large files' '
-	test_config core.bigfilethreshold 1 &&
-	git archive -0 --format=zip HEAD >large.zip
-'
-
-check_zip large
-
-test_expect_success 'git archive --format=zip on large files' '
-	test_config core.bigfilethreshold 1 &&
-	git archive --format=zip HEAD >large-compressed.zip
-'
-
-check_zip large-compressed
-
-test_expect_success \
     'git archive --list outside of a git repo' \
     'GIT_DIR=some/non-existing/directory git archive --list'
 
diff --git a/t/t5003-archive-zip.sh b/t/t5003-archive-zip.sh
new file mode 100755
index 0000000..7cfe9ca
--- /dev/null
+++ b/t/t5003-archive-zip.sh
@@ -0,0 +1,131 @@
+#!/bin/sh
+
+test_description='git archive --format=zip test'
+
+. ./test-lib.sh
+GIT_UNZIP=${GIT_UNZIP:-unzip}
+
+SUBSTFORMAT=%H%n
+
+test_lazy_prereq UNZIP '
+	"$GIT_UNZIP" -v
+	test $? -ne 127
+'
+
+test_lazy_prereq UNZIP_SYMLINKS '
+	(
+		mkdir unzip-symlinks &&
+		cd unzip-symlinks &&
+		"$GIT_UNZIP" "$TEST_DIRECTORY"/t5003/infozip-symlinks.zip &&
+		test -h symlink
+	)
+'
+
+check_zip() {
+	zipfile=$1.zip
+	listfile=$1.lst
+	dir=$1
+	dir_with_prefix=$dir/$2
+
+	test_expect_success UNZIP " extract ZIP archive" '
+		(mkdir $dir && cd $dir && "$GIT_UNZIP" ../$zipfile)
+	'
+
+	test_expect_success UNZIP " validate filenames" "
+		(cd ${dir_with_prefix}a && find .) | sort >$listfile &&
+		test_cmp a.lst $listfile
+	"
+
+	test_expect_success UNZIP " validate file contents" "
+		diff -r a ${dir_with_prefix}a
+	"
+}
+
+test_expect_success \
+    'populate workdir' \
+    'mkdir a b c &&
+     echo simple textfile >a/a &&
+     mkdir a/bin &&
+     cp /bin/sh a/bin &&
+     printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 &&
+     printf "A not substituted O" >a/substfile2 &&
+     (p=long_path_to_a_file && cd a &&
+      for depth in 1 2 3 4 5; do mkdir $p && cd $p; done &&
+      echo text >file_with_long_path)
+'
+
+test_expect_success SYMLINKS,UNZIP_SYMLINKS 'add symlink' '
+	ln -s a a/symlink_to_a
+'
+
+test_expect_success 'prepare file list' '
+	(cd a && find .) | sort >a.lst
+'
+
+test_expect_success \
+    'add ignored file' \
+    'echo ignore me >a/ignored &&
+     echo ignored export-ignore >.git/info/attributes'
+
+test_expect_success \
+    'add files to repository' \
+    'find a -type f | xargs git update-index --add &&
+     find a -type l | xargs git update-index --add &&
+     treeid=`git write-tree` &&
+     echo $treeid >treeid &&
+     git update-ref HEAD $(TZ=GMT GIT_COMMITTER_DATE="2005-05-27 22:00:00" \
+     git commit-tree $treeid </dev/null)'
+
+test_expect_success \
+    'create bare clone' \
+    'git clone --bare . bare.git &&
+     cp .git/info/attributes bare.git/info/attributes'
+
+test_expect_success \
+    'remove ignored file' \
+    'rm a/ignored'
+
+test_expect_success \
+    'git archive --format=zip' \
+    'git archive --format=zip HEAD >d.zip'
+
+check_zip d
+
+test_expect_success \
+    'git archive --format=zip in a bare repo' \
+    '(cd bare.git && git archive --format=zip HEAD) >d1.zip'
+
+test_expect_success \
+    'git archive --format=zip vs. the same in a bare repo' \
+    'test_cmp d.zip d1.zip'
+
+test_expect_success 'git archive --format=zip with --output' \
+    'git archive --format=zip --output=d2.zip HEAD &&
+    test_cmp d.zip d2.zip'
+
+test_expect_success 'git archive with --output, inferring format' '
+	git archive --output=d3.zip HEAD &&
+	test_cmp d.zip d3.zip
+'
+
+test_expect_success \
+    'git archive --format=zip with prefix' \
+    'git archive --format=zip --prefix=prefix/ HEAD >e.zip'
+
+check_zip e prefix/
+
+test_expect_success 'git archive -0 --format=zip on large files' '
+	test_config core.bigfilethreshold 1 &&
+	git archive -0 --format=zip HEAD >large.zip
+'
+
+check_zip large
+
+test_expect_success 'git archive --format=zip on large files' '
+	test_config core.bigfilethreshold 1 &&
+	git archive --format=zip HEAD >large-compressed.zip
+'
+
+check_zip large-compressed
+
+test_done
diff --git a/t/t5003/infozip-symlinks.zip b/t/t5003/infozip-symlinks.zip
new file mode 100644
index 0000000..065728c
--- /dev/null
+++ b/t/t5003/infozip-symlinks.zip
Binary files differ
diff --git a/t/t7061-wtstatus-ignore.sh b/t/t7061-wtstatus-ignore.sh
new file mode 100755
index 0000000..0da1214
--- /dev/null
+++ b/t/t7061-wtstatus-ignore.sh
@@ -0,0 +1,146 @@
+#!/bin/sh
+
+test_description='git-status ignored files'
+
+. ./test-lib.sh
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+?? untracked/
+EOF
+
+test_expect_success 'status untracked directory with --ignored' '
+	echo "ignored" >.gitignore &&
+	mkdir untracked &&
+	: >untracked/ignored &&
+	: >untracked/uncommitted &&
+	git status --porcelain --ignored >actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+?? untracked/uncommitted
+!! untracked/ignored
+EOF
+
+test_expect_success 'status untracked directory with --ignored -u' '
+	git status --porcelain --ignored -u >actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! ignored/
+EOF
+
+test_expect_success 'status ignored directory with --ignore' '
+	rm -rf untracked &&
+	mkdir ignored &&
+	: >ignored/uncommitted &&
+	git status --porcelain --ignored >actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! ignored/uncommitted
+EOF
+
+test_expect_success 'status ignored directory with --ignore -u' '
+	git status --porcelain --ignored -u >actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! untracked-ignored/
+EOF
+
+test_expect_success 'status untracked directory with ignored files with --ignore' '
+	rm -rf ignored &&
+	mkdir untracked-ignored &&
+	mkdir untracked-ignored/test &&
+	: >untracked-ignored/ignored &&
+	: >untracked-ignored/test/ignored &&
+	git status --porcelain --ignored >actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! untracked-ignored/ignored
+!! untracked-ignored/test/ignored
+EOF
+
+test_expect_success 'status untracked directory with ignored files with --ignore -u' '
+	git status --porcelain --ignored -u >actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+EOF
+
+test_expect_success 'status ignored tracked directory with --ignore' '
+	rm -rf untracked-ignored &&
+	mkdir tracked &&
+	: >tracked/committed &&
+	git add tracked/committed &&
+	git commit -m. &&
+	echo "tracked" >.gitignore &&
+	git status --porcelain --ignored >actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+EOF
+
+test_expect_success 'status ignored tracked directory with --ignore -u' '
+	git status --porcelain --ignored -u >actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! tracked/
+EOF
+
+test_expect_success 'status ignored tracked directory and uncommitted file with --ignore' '
+	: >tracked/uncommitted &&
+	git status --porcelain --ignored >actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! tracked/uncommitted
+EOF
+
+test_expect_success 'status ignored tracked directory and uncommitted file with --ignore -u' '
+	git status --porcelain --ignored -u >actual &&
+	test_cmp expected actual
+'
+
+test_done
diff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh
index f919c8d..8e32f19 100755
--- a/t/t7402-submodule-rebase.sh
+++ b/t/t7402-submodule-rebase.sh
@@ -3,7 +3,7 @@
 # Copyright (c) 2008 Johannes Schindelin
 #
 
-test_description='Test rebasing and stashing with dirty submodules'
+test_description='Test rebasing, stashing, etc. with submodules'
 
 . ./test-lib.sh
 
@@ -20,7 +20,8 @@
 	echo second line >> file &&
 	(cd submodule && git pull) &&
 	test_tick &&
-	git commit -m file-and-submodule -a
+	git commit -m file-and-submodule -a &&
+	git branch added-submodule
 
 '
 
@@ -89,4 +90,29 @@
 
 '
 
+test_expect_success 'rebasing submodule that should conflict' '
+	git reset --hard &&
+	git checkout added-submodule &&
+	git add submodule &&
+	test_tick &&
+	git commit -m third &&
+	(
+		cd submodule &&
+		git commit --allow-empty -m extra
+	) &&
+	git add submodule &&
+	test_tick &&
+	git commit -m fourth &&
+
+	test_must_fail git rebase --onto HEAD^^ HEAD^ HEAD^0 &&
+	git ls-files -s submodule >actual &&
+	(
+		cd submodule &&
+		echo "160000 $(git rev-parse HEAD^) 1	submodule" &&
+		echo "160000 $(git rev-parse HEAD^^) 2	submodule" &&
+		echo "160000 $(git rev-parse HEAD) 3	submodule"
+	) >expect &&
+	test_cmp expect actual
+'
+
 test_done
diff --git a/t/t9802-git-p4-filetype.sh b/t/t9802-git-p4-filetype.sh
index 21924df..aae1a3f 100755
--- a/t/t9802-git-p4-filetype.sh
+++ b/t/t9802-git-p4-filetype.sh
@@ -105,12 +105,13 @@
 	cat >gendouble.py <<-\EOF
 	import sys
 	import struct
-	import array
 
-	s = array.array("c", '\0' * 26)
-	struct.pack_into(">L", s,  0, 0x00051607)  # AppleDouble
-	struct.pack_into(">L", s,  4, 0x00020000)  # version 2
-	s.tofile(sys.stdout)
+	s = struct.pack(">LL18s",
+			0x00051607,  # AppleDouble
+			0x00020000,  # version 2
+			""           # pad to 26 bytes
+	)
+	sys.stdout.write(s)
 	EOF
 }
 
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 3cd53f8..adc1372 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -13,6 +13,25 @@
 	return 0
 }
 
+# Be careful when updating this list:
+#
+# (1) The build tree may have build artifact from different branch, or
+#     the user's $PATH may have a random executable that may begin
+#     with "git-check" that are not part of the subcommands this build
+#     will ship, e.g.  "check-ignore".  The tests for completion for
+#     subcommand names tests how "check" is expanded; we limit the
+#     possible candidates to "checkout" and "check-attr" to make sure
+#     "check-attr", which is known by the filter function as a
+#     subcommand to be thrown out, while excluding other random files
+#     that happen to begin with "check" to avoid letting them get in
+#     the way.
+#
+# (2) A test makes sure that common subcommands are included in the
+#     completion for "git <TAB>", and a plumbing is excluded.  "add",
+#     "filter-branch" and "ls-files" are listed for this.
+
+GIT_TESTING_COMMAND_COMPLETION='add checkout check-attr filter-branch ls-files'
+
 . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash"
 
 # We don't need this function to actually join words or do anything special.
@@ -196,7 +215,6 @@
 	test_completion "git --paginate check" "checkout " &&
 	test_completion "git --git-dir=foo check" "checkout " &&
 	test_completion "git --bare check" "checkout " &&
-	test_completion "git --help des" "describe " &&
 	test_completion "git --exec-path=foo check" "checkout " &&
 	test_completion "git --html-path check" "checkout " &&
 	test_completion "git --no-pager check" "checkout " &&
@@ -207,6 +225,11 @@
 	test_completion "git --no-replace-objects check" "checkout "
 '
 
+test_expect_success 'git --help completion' '
+	test_completion "git --help ad" "add " &&
+	test_completion "git --help core" "core-tutorial "
+'
+
 test_expect_success 'setup for ref completion' '
 	echo content >file1 &&
 	echo more >file2 &&
diff --git a/t/test-lib.sh b/t/test-lib.sh
index bf4cf71..ea1e4a0 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -85,6 +85,7 @@
 		.*_TEST
 		PROVE
 		VALGRIND
+		UNZIP
 		PERF_
 	));
 	my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
@@ -128,6 +129,7 @@
 unset CDPATH
 
 unset GREP_OPTIONS
+unset UNZIP
 
 case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in
 1|2|true)
diff --git a/test-path-utils.c b/test-path-utils.c
index 3bc20e9..0092cbf 100644
--- a/test-path-utils.c
+++ b/test-path-utils.c
@@ -1,4 +1,32 @@
 #include "cache.h"
+#include "string-list.h"
+
+/*
+ * A "string_list_each_func_t" function that normalizes an entry from
+ * GIT_CEILING_DIRECTORIES.  If the path is unusable for some reason,
+ * die with an explanation.
+ */
+static int normalize_ceiling_entry(struct string_list_item *item, void *unused)
+{
+	const char *ceil = item->string;
+	int len = strlen(ceil);
+	char buf[PATH_MAX+1];
+
+	if (len == 0)
+		die("Empty path is not supported");
+	if (len > PATH_MAX)
+		die("Path \"%s\" is too long", ceil);
+	if (!is_absolute_path(ceil))
+		die("Path \"%s\" is not absolute", ceil);
+	if (normalize_path_copy(buf, ceil) < 0)
+		die("Path \"%s\" could not be normalized", ceil);
+	len = strlen(buf);
+	if (len > 1 && buf[len-1] == '/')
+		die("Normalized path \"%s\" ended with slash", buf);
+	free(item->string);
+	item->string = xstrdup(buf);
+	return 1;
+}
 
 int main(int argc, char **argv)
 {
@@ -30,7 +58,28 @@
 	}
 
 	if (argc == 4 && !strcmp(argv[1], "longest_ancestor_length")) {
-		int len = longest_ancestor_length(argv[2], argv[3]);
+		int len;
+		struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
+		char *path = xstrdup(argv[2]);
+
+		/*
+		 * We have to normalize the arguments because under
+		 * Windows, bash mangles arguments that look like
+		 * absolute POSIX paths or colon-separate lists of
+		 * absolute POSIX paths into DOS paths (e.g.,
+		 * "/foo:/foo/bar" might be converted to
+		 * "D:\Src\msysgit\foo;D:\Src\msysgit\foo\bar"),
+		 * whereas longest_ancestor_length() requires paths
+		 * that use forward slashes.
+		 */
+		if (normalize_path_copy(path, path))
+			die("Path \"%s\" could not be normalized", argv[2]);
+		string_list_split(&ceiling_dirs, argv[3], PATH_SEP, -1);
+		filter_string_list(&ceiling_dirs, 0,
+				   normalize_ceiling_entry, NULL);
+		len = longest_ancestor_length(path, &ceiling_dirs);
+		string_list_clear(&ceiling_dirs, 0);
+		free(path);
 		printf("%d\n", len);
 		return 0;
 	}
diff --git a/test-string-list.c b/test-string-list.c
index 4693295..00ce6c9 100644
--- a/test-string-list.c
+++ b/test-string-list.c
@@ -97,26 +97,6 @@
 		return 0;
 	}
 
-	if (argc == 4 && !strcmp(argv[1], "longest_prefix")) {
-		/* arguments: <colon-separated-prefixes>|- <string> */
-		struct string_list prefixes = STRING_LIST_INIT_DUP;
-		int retval;
-		const char *prefix_string = argv[2];
-		const char *string = argv[3];
-		const char *match;
-
-		parse_string_list(&prefixes, prefix_string);
-		match = string_list_longest_prefix(&prefixes, string);
-		if (match) {
-			printf("%s\n", match);
-			retval = 0;
-		}
-		else
-			retval = 1;
-		string_list_clear(&prefixes, 0);
-		return retval;
-	}
-
 	fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
 		argv[1] ? argv[1] : "(there was none)");
 	return 1;
diff --git a/transport.c b/transport.c
index 9932f40..b9306ef 100644
--- a/transport.c
+++ b/transport.c
@@ -741,7 +741,7 @@
 			n += print_one_push_status(ref, dest, n, porcelain);
 		if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD &&
 		    *nonfastforward != NON_FF_HEAD) {
-			if (!strcmp(head, ref->name))
+			if (head != NULL && !strcmp(head, ref->name))
 				*nonfastforward = NON_FF_HEAD;
 			else
 				*nonfastforward = NON_FF_OTHER;
diff --git a/wt-status.c b/wt-status.c
index 2a9658b..d7cfe8f 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -516,7 +516,9 @@
 
 	if (s->show_ignored_files) {
 		dir.nr = 0;
-		dir.flags = DIR_SHOW_IGNORED | DIR_SHOW_OTHER_DIRECTORIES;
+		dir.flags = DIR_SHOW_IGNORED;
+		if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES)
+			dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
 		fill_directory(&dir, s->pathspec);
 		for (i = 0; i < dir.nr; i++) {
 			struct dir_entry *ent = dir.entries[i];