Merge branch 'ds/sparse-list-in-cone-mode'

"git sparse-checkout list" subcommand learned to give its output in
a more concise form when the "cone" mode is in effect.

* ds/sparse-list-in-cone-mode:
  sparse-checkout: document interactions with submodules
  sparse-checkout: list directories in cone mode
diff --git a/.cirrus.yml b/.cirrus.yml
new file mode 100644
index 0000000..c2f5fe3
--- /dev/null
+++ b/.cirrus.yml
@@ -0,0 +1,15 @@
+env:
+  CIRRUS_CLONE_DEPTH: 1
+
+freebsd_12_task:
+  freebsd_instance:
+    image: freebsd-12-1-release-amd64
+  install_script:
+    pkg install -y gettext gmake perl5
+  create_user_script:
+    - pw useradd git
+    - chown -R git:git .
+  build_script:
+    - su git -c gmake
+  test_script:
+    - su git -c 'gmake test'
diff --git a/.mailmap b/.mailmap
index 14fa041..7c94418 100644
--- a/.mailmap
+++ b/.mailmap
@@ -60,6 +60,7 @@
 David Turner <novalis@novalis.org> <dturner@twosigma.com>
 Derrick Stolee <dstolee@microsoft.com> <stolee@gmail.com>
 Deskin Miller <deskinm@umich.edu>
+Đoàn Trần Công Danh <congdanhqx@gmail.com> Doan Tran Cong Danh
 Dirk Süsserott <newsletter@dirk.my1.cc>
 Eric Blake <eblake@redhat.com> <ebb9@byu.net>
 Eric Hanchrow <eric.hanchrow@gmail.com> <offby1@blarg.net>
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index f45db5b..ed4e443 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -75,7 +75,7 @@
 
  - If you want to find out if a command is available on the user's
    $PATH, you should use 'type <command>', instead of 'which <command>'.
-   The output of 'which' is not machine parseable and its exit code
+   The output of 'which' is not machine parsable and its exit code
    is not reliable across platforms.
 
  - We use POSIX compliant parameter substitutions and avoid bashisms;
@@ -203,7 +203,7 @@
    . since early 2012 with e1327023ea, we have been using an enum
      definition whose last element is followed by a comma.  This, like
      an array initializer that ends with a trailing comma, can be used
-     to reduce the patch noise when adding a new identifer at the end.
+     to reduce the patch noise when adding a new identifier at the end.
 
    . since mid 2017 with cbc0f81d, we have been using designated
      initializers for struct (e.g. "struct t v = { .val = 'a' };").
diff --git a/Documentation/MyFirstContribution.txt b/Documentation/MyFirstContribution.txt
index 5e9b808..35b9130 100644
--- a/Documentation/MyFirstContribution.txt
+++ b/Documentation/MyFirstContribution.txt
@@ -38,6 +38,26 @@
 $ cd git
 ----
 
+[[dependencies]]
+=== Installing Dependencies
+
+To build Git from source, you need to have a handful of dependencies installed
+on your system. For a hint of what's needed, you can take a look at
+`INSTALL`, paying close attention to the section about Git's dependencies on
+external programs and libraries. That document mentions a way to "test-drive"
+our freshly built Git without installing; that's the method we'll be using in
+this tutorial.
+
+Make sure that your environment has everything you need by building your brand
+new clone of Git from the above step:
+
+----
+$ make
+----
+
+NOTE: The Git build is parallelizable. `-j#` is not included above but you can
+use it as you prefer, here and elsewhere.
+
 [[identify-problem]]
 === Identify Problem to Solve
 
@@ -138,9 +158,6 @@
 `DEVELOPER` flag; if there's some reason it doesn't work for you, you can turn
 it off, but it's a good idea to mention the problem to the mailing list.
 
-NOTE: The Git build is parallelizable. `-j#` is not included above but you can
-use it as you prefer, here and elsewhere.
-
 Great, now your new command builds happily on its own. But nobody invokes it.
 Let's change that.
 
@@ -534,6 +551,28 @@
 a flag.) `parse_options()` will terminate parsing when it reaches `--` and give
 you the rest of the options afterwards, untouched.
 
+Now that you have a usage hint, you can teach Git how to show it in the general
+command list shown by `git help git` or `git help -a`, which is generated from
+`command-list.txt`. Find the line for 'git-pull' so you can add your 'git-psuh'
+line above it in alphabetical order. Now, we can add some attributes about the
+command which impacts where it shows up in the aforementioned help commands. The
+top of `command-list.txt` shares some information about what each attribute
+means; in those help pages, the commands are sorted according to these
+attributes. `git psuh` is user-facing, or porcelain - so we will mark it as
+"mainporcelain". For "mainporcelain" commands, the comments at the top of
+`command-list.txt` indicate we can also optionally add an attribute from another
+list; since `git psuh` shows some information about the user's workspace but
+doesn't modify anything, let's mark it as "info". Make sure to keep your
+attributes in the same style as the rest of `command-list.txt` using spaces to
+align and delineate them:
+
+----
+git-prune-packed                        plumbingmanipulators
+git-psuh                                mainporcelain		info
+git-pull                                mainporcelain           remote
+git-push                                mainporcelain           remote
+----
+
 Build again. Now, when you run with `-h`, you should see your usage printed and
 your command terminated before anything else interesting happens. Great!
 
@@ -746,6 +785,14 @@
 but you will not be able to `/submit` your changes until someone allows you to
 use the tool.
 
+NOTE: You can typically find someone who can `/allow` you on GitGitGadget by
+either examining recent pull requests where someone has been granted `/allow`
+(https://github.com/gitgitgadget/git/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+%22%2Fallow%22[Search:
+is:pr is:open "/allow"]), in which case both the author and the person who
+granted the `/allow` can now `/allow` you, or by inquiring on the
+https://webchat.freenode.net/#git-devel[#git-devel] IRC channel on Freenode
+linking your pull request and asking for someone to `/allow` you.
+
 If the CI fails, you can update your changes with `git rebase -i` and push your
 branch again:
 
@@ -970,7 +1017,7 @@
 You will also need to go and find the Message-Id of your previous cover letter.
 You can either note it when you send the first series, from the output of `git
 send-email`, or you can look it up on the
-https://public-inbox.org/git[mailing list]. Find your cover letter in the
+https://lore.kernel.org/git[mailing list]. Find your cover letter in the
 archives, click on it, then click "permalink" or "raw" to reveal the Message-Id
 header. It should match:
 
diff --git a/Documentation/MyFirstObjectWalk.txt b/Documentation/MyFirstObjectWalk.txt
index 4d24dae..aa828df 100644
--- a/Documentation/MyFirstObjectWalk.txt
+++ b/Documentation/MyFirstObjectWalk.txt
@@ -17,7 +17,7 @@
 
 - `Documentation/user-manual.txt` under "Hacking Git" contains some coverage of
   the revision walker in its various incarnations.
-- `Documentation/technical/api-revision-walking.txt`
+- `revision.h`
 - https://eagain.net/articles/git-for-computer-scientists/[Git for Computer Scientists]
   gives a good overview of the types of objects in Git and what your object
   walk is really describing.
@@ -119,9 +119,8 @@
 
 `nr` represents the number of `rev_cmdline_entry` present in the array.
 
-`alloc` is used by the `ALLOC_GROW` macro. Check
-`Documentation/technical/api-allocation-growing.txt` - this variable is used to
-track the allocated size of the list.
+`alloc` is used by the `ALLOC_GROW` macro. Check `cache.h` - this variable is
+used to track the allocated size of the list.
 
 Per entry, we find:
 
diff --git a/Documentation/RelNotes/1.5.0.txt b/Documentation/RelNotes/1.5.0.txt
index daf4bdb..d6d42f3 100644
--- a/Documentation/RelNotes/1.5.0.txt
+++ b/Documentation/RelNotes/1.5.0.txt
@@ -251,7 +251,7 @@
    the repository when that happens.
 
 
-* Crufts removal
+* Cruft removal
 
  - We used to say "old commits are retrievable using reflog and
    'master@{yesterday}' syntax as long as you haven't run
@@ -379,7 +379,7 @@
  - The value of i18n.commitencoding in the originating
    repository is recorded in the commit object on the "encoding"
    header, if it is not UTF-8.  git-log and friends notice this,
-   and reencodes the message to the log output encoding when
+   and re-encodes the message to the log output encoding when
    displaying, if they are different.  The log output encoding
    is determined by "git log --encoding=<encoding>",
    i18n.logoutputencoding configuration, or i18n.commitencoding
diff --git a/Documentation/RelNotes/1.6.2.txt b/Documentation/RelNotes/1.6.2.txt
index ad060f4..980adfb 100644
--- a/Documentation/RelNotes/1.6.2.txt
+++ b/Documentation/RelNotes/1.6.2.txt
@@ -11,7 +11,7 @@
 configuration variable is missing.  Please refer to:
 
   http://git.or.cz/gitwiki/GitFaq#non-bare
-  http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007
+  https://lore.kernel.org/git/7vbptlsuyv.fsf@gitster.siamese.dyndns.org/
 
 for more details on the reason why this change is needed and the
 transition plan.
diff --git a/Documentation/RelNotes/1.6.3.txt b/Documentation/RelNotes/1.6.3.txt
index 418c685..4bcff94 100644
--- a/Documentation/RelNotes/1.6.3.txt
+++ b/Documentation/RelNotes/1.6.3.txt
@@ -11,7 +11,7 @@
 configuration variable is missing.  Please refer to:
 
   http://git.or.cz/gitwiki/GitFaq#non-bare
-  http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007
+  https://lore.kernel.org/git/7vbptlsuyv.fsf@gitster.siamese.dyndns.org/
 
 for more details on the reason why this change is needed and the
 transition plan.
diff --git a/Documentation/RelNotes/1.6.4.txt b/Documentation/RelNotes/1.6.4.txt
index 7a90441..a2a34b4 100644
--- a/Documentation/RelNotes/1.6.4.txt
+++ b/Documentation/RelNotes/1.6.4.txt
@@ -11,7 +11,7 @@
 configuration variable is missing.  Please refer to:
 
   http://git.or.cz/gitwiki/GitFaq#non-bare
-  http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007
+  https://lore.kernel.org/git/7vbptlsuyv.fsf@gitster.siamese.dyndns.org/
 
 for more details on the reason why this change is needed and the
 transition plan.
diff --git a/Documentation/RelNotes/1.6.5.4.txt b/Documentation/RelNotes/1.6.5.4.txt
index d3a2a3e..344333d 100644
--- a/Documentation/RelNotes/1.6.5.4.txt
+++ b/Documentation/RelNotes/1.6.5.4.txt
@@ -10,7 +10,7 @@
 
  * "git prune-packed" gave progress output even when its standard error is
    not connected to a terminal; this caused cron jobs that run it to
-   produce crufts.
+   produce cruft.
 
  * "git pack-objects --all-progress" is an option to ask progress output
    from write-object phase _if_ progress output were to be produced, and
diff --git a/Documentation/RelNotes/1.6.5.txt b/Documentation/RelNotes/1.6.5.txt
index ee141c1..6c7f7da 100644
--- a/Documentation/RelNotes/1.6.5.txt
+++ b/Documentation/RelNotes/1.6.5.txt
@@ -22,7 +22,7 @@
 configuration variable is missing.  Please refer to:
 
   http://git.or.cz/gitwiki/GitFaq#non-bare
-  http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007
+  https://lore.kernel.org/git/7vbptlsuyv.fsf@gitster.siamese.dyndns.org/
 
 for more details on the reason why this change is needed and the
 transition plan.
diff --git a/Documentation/RelNotes/1.6.6.txt b/Documentation/RelNotes/1.6.6.txt
index c50b59c..3ed1e01 100644
--- a/Documentation/RelNotes/1.6.6.txt
+++ b/Documentation/RelNotes/1.6.6.txt
@@ -64,7 +64,7 @@
    Please refer to:
 
    http://git.or.cz/gitwiki/GitFaq#non-bare
-   http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007
+   https://lore.kernel.org/git/7vbptlsuyv.fsf@gitster.siamese.dyndns.org/
 
    for more details on the reason why this change is needed and the
    transition process that already took place so far.
diff --git a/Documentation/RelNotes/1.7.0.2.txt b/Documentation/RelNotes/1.7.0.2.txt
index fcb46ca..73ed2b5 100644
--- a/Documentation/RelNotes/1.7.0.2.txt
+++ b/Documentation/RelNotes/1.7.0.2.txt
@@ -34,7 +34,7 @@
  * "git status" in 1.7.0 lacked the optimization we used to have in 1.6.X series
    to speed up scanning of large working tree.
 
- * "gitweb" did not diagnose parsing errors properly while reading tis configuration
+ * "gitweb" did not diagnose parsing errors properly while reading its configuration
    file.
 
 And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.10.4.txt b/Documentation/RelNotes/1.7.10.4.txt
index 326670d..57597f2 100644
--- a/Documentation/RelNotes/1.7.10.4.txt
+++ b/Documentation/RelNotes/1.7.10.4.txt
@@ -7,7 +7,7 @@
  * The message file for Swedish translation has been updated a bit.
 
  * A name taken from mailmap was copied into an internal buffer
-   incorrectly and could overun the buffer if it is too long.
+   incorrectly and could overrun the buffer if it is too long.
 
  * A malformed commit object that has a header line chomped in the
    middle could kill git with a NULL pointer dereference.
diff --git a/Documentation/RelNotes/1.7.12.3.txt b/Documentation/RelNotes/1.7.12.3.txt
index ecda427..4b82297 100644
--- a/Documentation/RelNotes/1.7.12.3.txt
+++ b/Documentation/RelNotes/1.7.12.3.txt
@@ -25,7 +25,7 @@
    its Accept-Encoding header.
 
  * "git receive-pack" (the counterpart to "git push") did not give
-   progress output while processing objects it received to the puser
+   progress output while processing objects it received to the user
    when run over the smart-http protocol.
 
  * "git status" honored the ignore=dirty settings in .gitmodules but
diff --git a/Documentation/RelNotes/1.7.5.3.txt b/Documentation/RelNotes/1.7.5.3.txt
index 9c03353..1d24edc 100644
--- a/Documentation/RelNotes/1.7.5.3.txt
+++ b/Documentation/RelNotes/1.7.5.3.txt
@@ -22,7 +22,7 @@
  * "git log --stdin path" with an input that has additional pathspec
    used to corrupt memory.
 
- * "git send-pack" (hence "git push") over smalt-HTTP protocol could
+ * "git send-pack" (hence "git push") over smart-HTTP protocol could
    deadlock when the client side pack-object died early.
 
  * Compressed tarball gitweb generates used to be made with the timestamp
diff --git a/Documentation/RelNotes/1.8.0.txt b/Documentation/RelNotes/1.8.0.txt
index 43883c1..63d6e4a 100644
--- a/Documentation/RelNotes/1.8.0.txt
+++ b/Documentation/RelNotes/1.8.0.txt
@@ -233,7 +233,7 @@
    together, misdetected branches.
 
  * "git receive-pack" (the counterpart to "git push") did not give
-   progress output while processing objects it received to the puser
+   progress output while processing objects it received to the user
    when run over the smart-http protocol.
 
  * When you misspell the command name you give to the "exec" action in
diff --git a/Documentation/RelNotes/1.8.4.1.txt b/Documentation/RelNotes/1.8.4.1.txt
index 96090ef..c257beb 100644
--- a/Documentation/RelNotes/1.8.4.1.txt
+++ b/Documentation/RelNotes/1.8.4.1.txt
@@ -15,7 +15,7 @@
    in 1.8.4-rc1).
 
  * "git rebase -i" and other scripted commands were feeding a
-   random, data dependant error message to 'echo' and expecting it
+   random, data dependent error message to 'echo' and expecting it
    to come out literally.
 
  * Setting the "submodule.<name>.path" variable to the empty
diff --git a/Documentation/RelNotes/1.8.4.txt b/Documentation/RelNotes/1.8.4.txt
index 02f681b..255e185 100644
--- a/Documentation/RelNotes/1.8.4.txt
+++ b/Documentation/RelNotes/1.8.4.txt
@@ -58,7 +58,7 @@
    credential helper interface from Git.pm.
 
  * Update build for Cygwin 1.[57].  Torsten Bögershausen reports that
-   this is fine with Cygwin 1.7 ($gmane/225824) so let's try moving it
+   this is fine with Cygwin 1.7 (cf. <51A606A0.5060101@web.de>) so let's try moving it
    ahead.
 
  * The credential helper to talk to keychain on OS X (in contrib/) has
diff --git a/Documentation/RelNotes/2.1.3.txt b/Documentation/RelNotes/2.1.3.txt
index acc9ebb..0dfb17c 100644
--- a/Documentation/RelNotes/2.1.3.txt
+++ b/Documentation/RelNotes/2.1.3.txt
@@ -13,7 +13,7 @@
    they are new enough to support the `--output` option.
 
  * "git pack-objects" forgot to disable the codepath to generate
-   object recheability bitmap when it needs to split the resulting
+   object reachability bitmap when it needs to split the resulting
    pack.
 
  * "gitweb" used deprecated CGI::startfrom, which was removed from
diff --git a/Documentation/RelNotes/2.10.0.txt b/Documentation/RelNotes/2.10.0.txt
index f4da28a..3792b7d 100644
--- a/Documentation/RelNotes/2.10.0.txt
+++ b/Documentation/RelNotes/2.10.0.txt
@@ -478,7 +478,7 @@
  * One part of "git am" had an oddball helper function that called
    stuff from outside "his" as opposed to calling what we have "ours",
    which was not gender-neutral and also inconsistent with the rest of
-   the system where outside stuff is usuall called "theirs" in
+   the system where outside stuff is usually called "theirs" in
    contrast to "ours".
 
  * "git blame file" allowed the lineage of lines in the uncommitted,
diff --git a/Documentation/RelNotes/2.10.2.txt b/Documentation/RelNotes/2.10.2.txt
index c4d4397..abbd331 100644
--- a/Documentation/RelNotes/2.10.2.txt
+++ b/Documentation/RelNotes/2.10.2.txt
@@ -86,7 +86,7 @@
    by refusing to check out a branch that is already checked out in
    another worktree.  However, this also prevented checking out a
    branch, which is designated as the primary branch of a bare
-   reopsitory, in a worktree that is connected to the bare
+   repository, in a worktree that is connected to the bare
    repository.  The check has been corrected to allow it.
 
  * "git rebase" immediately after "git clone" failed to find the fork
diff --git a/Documentation/RelNotes/2.11.1.txt b/Documentation/RelNotes/2.11.1.txt
index 9cd14c8..7d35cf1 100644
--- a/Documentation/RelNotes/2.11.1.txt
+++ b/Documentation/RelNotes/2.11.1.txt
@@ -104,7 +104,7 @@
    "git difftool --dir-diff" from a subdirectory never worked. This
    has been fixed.
 
- * "git p4" that tracks multile p4 paths imported a single changelist
+ * "git p4" that tracks multiple p4 paths imported a single changelist
    that touches files in these multiple paths as one commit, followed
    by many empty commits.  This has been fixed.
 
diff --git a/Documentation/RelNotes/2.12.0.txt b/Documentation/RelNotes/2.12.0.txt
index ef8b97d..d2f6a83 100644
--- a/Documentation/RelNotes/2.12.0.txt
+++ b/Documentation/RelNotes/2.12.0.txt
@@ -315,7 +315,7 @@
    "git difftool --dir-diff" from a subdirectory never worked. This
    has been fixed.
 
- * "git p4" that tracks multile p4 paths imported a single changelist
+ * "git p4" that tracks multiple p4 paths imported a single changelist
    that touches files in these multiple paths as one commit, followed
    by many empty commits.  This has been fixed.
 
diff --git a/Documentation/RelNotes/2.13.0.txt b/Documentation/RelNotes/2.13.0.txt
index aa99d4b..2a47b4c 100644
--- a/Documentation/RelNotes/2.13.0.txt
+++ b/Documentation/RelNotes/2.13.0.txt
@@ -177,7 +177,7 @@
    been changed to enable "--decorate".
 
  * The output from "git status --short" has been extended to show
-   various kinds of dirtyness in submodules differently; instead of to
+   various kinds of dirtiness in submodules differently; instead of to
    "M" for modified, 'm' and '?' can be shown to signal changes only
    to the working tree of the submodule but not the commit that is
    checked out.
diff --git a/Documentation/RelNotes/2.13.3.txt b/Documentation/RelNotes/2.13.3.txt
index 5d76ad5..384e4de 100644
--- a/Documentation/RelNotes/2.13.3.txt
+++ b/Documentation/RelNotes/2.13.3.txt
@@ -25,7 +25,7 @@
  * The code to pick up and execute command alias definition from the
    configuration used to switch to the top of the working tree and
    then come back when the expanded alias was executed, which was
-   unnecessarilyl complex.  Attempt to simplify the logic by using the
+   unnecessarily complex.  Attempt to simplify the logic by using the
    early-config mechanism that does not chdir around.
 
  * "git add -p" were updated in 2.12 timeframe to cope with custom
@@ -35,7 +35,7 @@
  * Fix a recent regression to "git rebase -i" and add tests that would
    have caught it and others.
 
- * An unaligned 32-bit access in pack-bitmap code ahs been corrected.
+ * An unaligned 32-bit access in pack-bitmap code has been corrected.
 
  * Tighten error checks for invalid "git apply" input.
 
diff --git a/Documentation/RelNotes/2.14.0.txt b/Documentation/RelNotes/2.14.0.txt
index 4246c68..2711a25 100644
--- a/Documentation/RelNotes/2.14.0.txt
+++ b/Documentation/RelNotes/2.14.0.txt
@@ -141,7 +141,7 @@
  * Some platforms have ulong that is smaller than time_t, and our
    historical use of ulong for timestamp would mean they cannot
    represent some timestamp that the platform allows.  Invent a
-   separate and dedicated timestamp_t (so that we can distingiuish
+   separate and dedicated timestamp_t (so that we can distinguish
    timestamps and a vanilla ulongs, which along is already a good
    move), and then declare uintmax_t is the type to be used as the
    timestamp_t.
@@ -442,7 +442,7 @@
  * The code to pick up and execute command alias definition from the
    configuration used to switch to the top of the working tree and
    then come back when the expanded alias was executed, which was
-   unnecessarilyl complex.  Attempt to simplify the logic by using the
+   unnecessarily complex.  Attempt to simplify the logic by using the
    early-config mechanism that does not chdir around.
 
  * Fix configuration codepath to pay proper attention to commondir
diff --git a/Documentation/RelNotes/2.14.6.txt b/Documentation/RelNotes/2.14.6.txt
new file mode 100644
index 0000000..72b7af6
--- /dev/null
+++ b/Documentation/RelNotes/2.14.6.txt
@@ -0,0 +1,54 @@
+Git v2.14.6 Release Notes
+=========================
+
+This release addresses the security issues CVE-2019-1348,
+CVE-2019-1349, CVE-2019-1350, CVE-2019-1351, CVE-2019-1352,
+CVE-2019-1353, CVE-2019-1354, and CVE-2019-1387.
+
+Fixes since v2.14.5
+-------------------
+
+ * CVE-2019-1348:
+   The --export-marks option of git fast-import is exposed also via
+   the in-stream command feature export-marks=... and it allows
+   overwriting arbitrary paths.
+
+ * CVE-2019-1349:
+   When submodules are cloned recursively, under certain circumstances
+   Git could be fooled into using the same Git directory twice. We now
+   require the directory to be empty.
+
+ * CVE-2019-1350:
+   Incorrect quoting of command-line arguments allowed remote code
+   execution during a recursive clone in conjunction with SSH URLs.
+
+ * CVE-2019-1351:
+   While the only permitted drive letters for physical drives on
+   Windows are letters of the US-English alphabet, this restriction
+   does not apply to virtual drives assigned via subst <letter>:
+   <path>. Git mistook such paths for relative paths, allowing writing
+   outside of the worktree while cloning.
+
+ * CVE-2019-1352:
+   Git was unaware of NTFS Alternate Data Streams, allowing files
+   inside the .git/ directory to be overwritten during a clone.
+
+ * CVE-2019-1353:
+   When running Git in the Windows Subsystem for Linux (also known as
+   "WSL") while accessing a working directory on a regular Windows
+   drive, none of the NTFS protections were active.
+
+ * CVE-2019-1354:
+   Filenames on Linux/Unix can contain backslashes. On Windows,
+   backslashes are directory separators. Git did not use to refuse to
+   write out tracked files with such filenames.
+
+ * CVE-2019-1387:
+   Recursive clones are currently affected by a vulnerability that is
+   caused by too-lax validation of submodule names, allowing very
+   targeted attacks via remote code execution in recursive clones.
+
+Credit for finding these vulnerabilities goes to Microsoft Security
+Response Center, in particular to Nicolas Joly. The `fast-import`
+fixes were provided by Jeff King, the other fixes by Johannes
+Schindelin with help from Garima Singh.
diff --git a/Documentation/RelNotes/2.15.4.txt b/Documentation/RelNotes/2.15.4.txt
new file mode 100644
index 0000000..dc241cb
--- /dev/null
+++ b/Documentation/RelNotes/2.15.4.txt
@@ -0,0 +1,11 @@
+Git v2.15.4 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6 to address
+the security issues CVE-2019-1348, CVE-2019-1349, CVE-2019-1350,
+CVE-2019-1351, CVE-2019-1352, CVE-2019-1353, CVE-2019-1354, and
+CVE-2019-1387; see the release notes for that version for details.
+
+In conjunction with a vulnerability that was fixed in v2.20.2,
+`.gitmodules` is no longer allowed to contain entries of the form
+`submodule.<name>.update=!command`.
diff --git a/Documentation/RelNotes/2.16.0.txt b/Documentation/RelNotes/2.16.0.txt
index 0c81c59..b474781 100644
--- a/Documentation/RelNotes/2.16.0.txt
+++ b/Documentation/RelNotes/2.16.0.txt
@@ -407,7 +407,7 @@
    (merge eef3df5a93 bw/pathspec-match-submodule-boundary later to maint).
 
  * Amending commits in git-gui broke the author name that is non-ascii
-   due to incorrect enconding conversion.
+   due to incorrect encoding conversion.
 
  * Recent update to the submodule configuration code broke "diff-tree"
    by accidentally stopping to read from the index upfront.
diff --git a/Documentation/RelNotes/2.16.3.txt b/Documentation/RelNotes/2.16.3.txt
index 64a0bcb..f0121a8 100644
--- a/Documentation/RelNotes/2.16.3.txt
+++ b/Documentation/RelNotes/2.16.3.txt
@@ -24,7 +24,7 @@
 
  * The http tracing code, often used to debug connection issues,
    learned to redact potentially sensitive information from its output
-   so that it can be more safely sharable.
+   so that it can be more safely shareable.
 
  * Crash fix for a corner case where an error codepath tried to unlock
    what it did not acquire lock on.
diff --git a/Documentation/RelNotes/2.16.6.txt b/Documentation/RelNotes/2.16.6.txt
new file mode 100644
index 0000000..438306e
--- /dev/null
+++ b/Documentation/RelNotes/2.16.6.txt
@@ -0,0 +1,8 @@
+Git v2.16.6 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6 and in
+v2.15.4 addressing the security issues CVE-2019-1348, CVE-2019-1349,
+CVE-2019-1350, CVE-2019-1351, CVE-2019-1352, CVE-2019-1353,
+CVE-2019-1354, and CVE-2019-1387; see the release notes for those
+versions for details.
diff --git a/Documentation/RelNotes/2.17.0.txt b/Documentation/RelNotes/2.17.0.txt
index c2cf891..8b17c26 100644
--- a/Documentation/RelNotes/2.17.0.txt
+++ b/Documentation/RelNotes/2.17.0.txt
@@ -216,7 +216,7 @@
 
  * The http tracing code, often used to debug connection issues,
    learned to redact potentially sensitive information from its output
-   so that it can be more safely sharable.
+   so that it can be more safely shareable.
    (merge 8ba18e6fa4 jt/http-redact-cookies later to maint).
 
  * Crash fix for a corner case where an error codepath tried to unlock
diff --git a/Documentation/RelNotes/2.17.3.txt b/Documentation/RelNotes/2.17.3.txt
new file mode 100644
index 0000000..5a46c94
--- /dev/null
+++ b/Documentation/RelNotes/2.17.3.txt
@@ -0,0 +1,12 @@
+Git v2.17.3 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6 and in
+v2.15.4 addressing the security issues CVE-2019-1348, CVE-2019-1349,
+CVE-2019-1350, CVE-2019-1351, CVE-2019-1352, CVE-2019-1353,
+CVE-2019-1354, and CVE-2019-1387; see the release notes for those
+versions for details.
+
+In addition, `git fsck` was taught to identify `.gitmodules` entries
+of the form `submodule.<name>.update=!command`, which have been
+disallowed in v2.15.4.
diff --git a/Documentation/RelNotes/2.18.0.txt b/Documentation/RelNotes/2.18.0.txt
index 3ea280c..6c8a0e9 100644
--- a/Documentation/RelNotes/2.18.0.txt
+++ b/Documentation/RelNotes/2.18.0.txt
@@ -179,7 +179,7 @@
    (merge 00a3da2a13 nd/remove-ignore-env-field later to maint).
 
  * Code to find the length to uniquely abbreviate object names based
-   on packfile content, which is a relatively recent addtion, has been
+   on packfile content, which is a relatively recent addition, has been
    optimized to use the same fan-out table.
 
  * The mechanism to use parse-options API to automate the command line
diff --git a/Documentation/RelNotes/2.18.2.txt b/Documentation/RelNotes/2.18.2.txt
new file mode 100644
index 0000000..98b168a
--- /dev/null
+++ b/Documentation/RelNotes/2.18.2.txt
@@ -0,0 +1,8 @@
+Git v2.18.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6, v2.15.4
+and in v2.17.3, addressing the security issues CVE-2019-1348,
+CVE-2019-1349, CVE-2019-1350, CVE-2019-1351, CVE-2019-1352,
+CVE-2019-1353, CVE-2019-1354, and CVE-2019-1387; see the release notes
+for those versions for details.
diff --git a/Documentation/RelNotes/2.19.0.txt b/Documentation/RelNotes/2.19.0.txt
index a06ccf6..891c79b 100644
--- a/Documentation/RelNotes/2.19.0.txt
+++ b/Documentation/RelNotes/2.19.0.txt
@@ -106,7 +106,7 @@
  * The conversion to pass "the_repository" and then "a_repository"
    throughout the object access API continues.
 
- * Continuing with the idea to programatically enumerate various
+ * Continuing with the idea to programmatically enumerate various
    pieces of data required for command line completion, teach the
    codebase to report the list of configuration variables
    subcommands care about to help complete them.
diff --git a/Documentation/RelNotes/2.19.3.txt b/Documentation/RelNotes/2.19.3.txt
new file mode 100644
index 0000000..92d7f89
--- /dev/null
+++ b/Documentation/RelNotes/2.19.3.txt
@@ -0,0 +1,8 @@
+Git v2.19.3 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6, v2.15.4
+and in v2.17.3, addressing the security issues CVE-2019-1348,
+CVE-2019-1349, CVE-2019-1350, CVE-2019-1351, CVE-2019-1352,
+CVE-2019-1353, CVE-2019-1354, and CVE-2019-1387; see the release notes
+for those versions for details.
diff --git a/Documentation/RelNotes/2.20.0.txt b/Documentation/RelNotes/2.20.0.txt
index e71fe3d..3dd7e6e 100644
--- a/Documentation/RelNotes/2.20.0.txt
+++ b/Documentation/RelNotes/2.20.0.txt
@@ -119,7 +119,7 @@
    alias expansion.
 
  * The documentation of "git gc" has been updated to mention that it
-   is no longer limited to "pruning away crufts" but also updates
+   is no longer limited to "pruning away cruft" but also updates
    ancillary files like commit-graph as a part of repository
    optimization.
 
diff --git a/Documentation/RelNotes/2.20.2.txt b/Documentation/RelNotes/2.20.2.txt
new file mode 100644
index 0000000..8e680cb
--- /dev/null
+++ b/Documentation/RelNotes/2.20.2.txt
@@ -0,0 +1,18 @@
+Git v2.20.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6, v2.15.4
+and in v2.17.3, addressing the security issues CVE-2019-1348,
+CVE-2019-1349, CVE-2019-1350, CVE-2019-1351, CVE-2019-1352,
+CVE-2019-1353, CVE-2019-1354, and CVE-2019-1387; see the release notes
+for those versions for details.
+
+The change to disallow `submodule.<name>.update=!command` entries in
+`.gitmodules` which was introduced v2.15.4 (and for which v2.17.3
+added explicit fsck checks) fixes the vulnerability in v2.20.x where a
+recursive clone followed by a submodule update could execute code
+contained within the repository without the user explicitly having
+asked for that (CVE-2019-19604).
+
+Credit for finding this vulnerability goes to Joern Schneeweisz,
+credit for the fixes goes to Jonathan Nieder.
diff --git a/Documentation/RelNotes/2.21.1.txt b/Documentation/RelNotes/2.21.1.txt
new file mode 100644
index 0000000..b759415
--- /dev/null
+++ b/Documentation/RelNotes/2.21.1.txt
@@ -0,0 +1,12 @@
+Git v2.21.1 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6, v2.15.4,
+v2.17.3 and in v2.20.2, addressing the security issues CVE-2019-1348,
+CVE-2019-1349, CVE-2019-1350, CVE-2019-1351, CVE-2019-1352,
+CVE-2019-1353, CVE-2019-1354, CVE-2019-1387, and CVE-2019-19604;
+see the release notes for those versions for details.
+
+Additionally, this version also includes a couple of fixes for the
+Windows-specific quoting of command-line arguments when Git executes
+a Unix shell on Windows.
diff --git a/Documentation/RelNotes/2.22.2.txt b/Documentation/RelNotes/2.22.2.txt
new file mode 100644
index 0000000..940a23f
--- /dev/null
+++ b/Documentation/RelNotes/2.22.2.txt
@@ -0,0 +1,8 @@
+Git v2.22.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6, v2.15.4,
+v2.17.3, v2.20.2 and in v2.21.1, addressing the security issues
+CVE-2019-1348, CVE-2019-1349, CVE-2019-1350, CVE-2019-1351,
+CVE-2019-1352, CVE-2019-1353, CVE-2019-1354, CVE-2019-1387, and
+CVE-2019-19604; see the release notes for those versions for details.
diff --git a/Documentation/RelNotes/2.23.1.txt b/Documentation/RelNotes/2.23.1.txt
new file mode 100644
index 0000000..2083b49
--- /dev/null
+++ b/Documentation/RelNotes/2.23.1.txt
@@ -0,0 +1,8 @@
+Git v2.23.1 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6, v2.15.4,
+v2.17.3, v2.20.2 and in v2.21.1, addressing the security issues
+CVE-2019-1348, CVE-2019-1349, CVE-2019-1350, CVE-2019-1351,
+CVE-2019-1352, CVE-2019-1353, CVE-2019-1354, CVE-2019-1387, and
+CVE-2019-19604; see the release notes for those versions for details.
diff --git a/Documentation/RelNotes/2.24.1.txt b/Documentation/RelNotes/2.24.1.txt
new file mode 100644
index 0000000..1810485
--- /dev/null
+++ b/Documentation/RelNotes/2.24.1.txt
@@ -0,0 +1,8 @@
+Git v2.24.1 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6, v2.15.4,
+v2.17.3, v2.20.2 and in v2.21.1, addressing the security issues
+CVE-2019-1348, CVE-2019-1349, CVE-2019-1350, CVE-2019-1351,
+CVE-2019-1352, CVE-2019-1353, CVE-2019-1354, CVE-2019-1387, and
+CVE-2019-19604; see the release notes for those versions for details.
diff --git a/Documentation/RelNotes/2.25.0.txt b/Documentation/RelNotes/2.25.0.txt
index b61b69f..feccaca 100644
--- a/Documentation/RelNotes/2.25.0.txt
+++ b/Documentation/RelNotes/2.25.0.txt
@@ -29,6 +29,49 @@
    placeholder that is similar to e/E that fills in the e-mail
    address, but only the local part on the left side of '@'.
 
+ * Documentation pages for "git shortlog" now list commit limiting
+   options explicitly.
+
+ * The patterns to detect function boundary for Elixir language has
+   been added.
+
+ * The completion script (in contrib/) learned that the "--onto"
+   option of "git rebase" can take its argument as the value of the
+   option.
+
+ * The userdiff machinery has been taught that "async def" is another
+   way to begin a "function" in Python.
+
+ * "git range-diff" learned to take the "--notes=<ref>" and the
+   "--no-notes" options to control the commit notes included in the
+   log message that gets compared.
+
+ * "git rev-parse --show-toplevel" run outside of any working tree did
+   not error out, which has been corrected.
+
+ * A few commands learned to take the pathspec from the standard input
+   or a named file, instead of taking it as the command line
+   arguments, with the "--pathspec-from-file" option.
+
+ * "git rebase -i" learned a few options that are known by "git
+   rebase" proper.
+
+ * "git submodule" learned a subcommand "set-url".
+
+ * "git log" family learned "--pretty=reference" that gives the name
+   of a commit in the format that is often used to refer to it in log
+   messages.
+
+ * The interaction between "git clone --recurse-submodules" and
+   alternate object store was ill-designed.  The documentation and
+   code have been taught to make more clear recommendations when the
+   users see failures.
+
+ * Management of sparsely checked-out working tree has gained a
+   dedicated "sparse-checkout" command.
+
+ * Miscellaneous small UX improvements on "git-p4".
+
 
 Performance, Internal Implementation, Development Support etc.
 
@@ -39,6 +82,77 @@
 
  * Test updates to prepare for SHA-2 transition continues.
 
+ * Crufty code and logic accumulated over time around the object
+   parsing and low-level object access used in "git fsck" have been
+   cleaned up.
+
+ * The implementation of "git log --graph" got refactored and then its
+   output got simplified.
+
+ * Follow recent push to move API docs from Documentation/ to header
+   files and update config.h
+
+ * "git bundle" has been taught to use the parse options API.  "git
+   bundle verify" learned "--quiet" and "git bundle create" learned
+   options to control the progress output.
+
+ * Handling of commit objects that use non UTF-8 encoding during
+   "rebase -i" has been improved.
+
+ * The beginning of rewriting "git add -i" in C.
+
+ * A label used in the todo list that are generated by "git rebase
+   --rebase-merges" is used as a part of a refname; the logic to come
+   up with the label has been tightened to avoid names that cannot be
+   used as such.
+
+ * The logic to avoid duplicate label names generated by "git rebase
+   --rebase-merges" forgot that the machinery itself uses "onto" as a
+   label name, which must be avoided by auto-generated labels, which
+   has been corrected.
+
+ * We have had compatibility fallback macro definitions for "PRIuMAX",
+   "PRIu32", etc. but did not for "PRIdMAX", while the code used the
+   last one apparently without any hiccup reported recently.  The
+   fallback macro definitions for these <inttypes.h> macros that must
+   appear in C99 systems have been removed.
+
+ * Recently we have declared that GIT_TEST_* variables take the
+   usual boolean values (it used to be that some used "non-empty
+   means true" and taking GIT_TEST_VAR=YesPlease as true); make
+   sure we notice and fail when non-bool strings are given to
+   these variables.
+
+ * Users of oneway_merge() (like "reset --hard") learned to take
+   advantage of fsmonitor to avoid unnecessary lstat(2) calls.
+
+ * Performance tweak on "git push" into a repository with many refs
+   that point at objects we have never heard of.
+
+ * PerfTest fix to avoid stale result mixed up with the latest round
+   of test results.
+
+ * Hide lower-level verify_signed-buffer() API as a pure helper to
+   implement the public check_signature() function, in order to
+   encourage new callers to use the correct and more strict
+   validation.
+
+ * Unnecessary reading of state variables back from the disk during
+   sequencer operation has been reduced.
+
+ * The code has been made to avoid gmtime() and localtime() and prefer
+   their reentrant counterparts.
+
+ * The effort to reimplement "git add -i" in C continues.
+
+ * In a repository with many packfiles, the cost of the procedure that
+   avoids registering the same packfile twice was unnecessarily high
+   by using an inefficient search algorithm, which has been corrected.
+
+ * Redo "git name-rev" to avoid recursive calls.
+
+ * FreeBSD CI support via Cirrus-CI has been added.
+
 
 Fixes since v2.24
 -----------------
@@ -63,6 +177,177 @@
    mistakenly removed paths that are outside the area of interest.
    (merge 4a58c3d7f7 js/update-index-ignore-removal-for-skip-worktree later to maint).
 
+ * "git rev-parse --git-path HEAD.lock" did not give the right path
+   when run in a secondary worktree.
+   (merge 76a53d640f js/git-path-head-dot-lock-fix later to maint).
+
+ * "git merge --no-commit" needs "--no-ff" if you do not want to move
+   HEAD, which has been corrected in the manual page for "git bisect".
+   (merge 8dd327b246 ma/bisect-doc-sample-update later to maint).
+
+ * "git worktree add" internally calls "reset --hard" that should not
+   descend into submodules, even when submodule.recurse configuration
+   is set, but it was affected.  This has been corrected.
+   (merge 4782cf2ab6 pb/no-recursive-reset-hard-in-worktree-add later to maint).
+
+ * Messages from die() etc. can be mixed up from multiple processes
+   without even line buffering on Windows, which has been worked
+   around.
+   (merge 116d1fa6c6 js/vreportf-wo-buffering later to maint).
+
+ * HTTP transport had possible allocator/deallocator mismatch, which
+   has been corrected.
+
+ * The watchman integration for fsmonitor was racy, which has been
+   corrected to be more conservative.
+   (merge dd0b61f577 kw/fsmonitor-watchman-fix later to maint).
+
+ * Fetching from multiple remotes into the same repository in parallel
+   had a bad interaction with the recent change to (optionally) update
+   the commit-graph after a fetch job finishes, as these parallel
+   fetches compete with each other.  Which has been corrected.
+
+ * Recent update to "git stash pop" made the command empty the index
+   when run with the "--quiet" option, which has been corrected.
+
+ * "git fetch" codepath had a big "do not lazily fetch missing objects
+   when I ask if something exists" switch.  This has been corrected by
+   marking the "does this thing exist?" calls with "if not please do not
+   lazily fetch it" flag.
+
+ * Test update to avoid wasted cycles.
+   (merge e0316695ec sg/skip-skipped-prereq later to maint).
+
+ * Error handling after "git push" finishes sending the packdata and
+   waits for the response to the remote side has been improved.
+   (merge ad7a403268 jk/send-pack-remote-failure later to maint).
+
+ * Some codepaths in "gitweb" that forgot to escape URLs generated
+   based on end-user input have been corrected.
+   (merge a376e37b2c jk/gitweb-anti-xss later to maint).
+
+ * CI jobs for macOS has been made less chatty when updating perforce
+   package used during testing.
+   (merge 0dbc4a0edf jc/azure-ci-osx-fix-fix later to maint).
+
+ * "git unpack-objects" used to show progress based only on the number
+   of received and unpacked objects, which stalled when it has to
+   handle an unusually large object.  It now shows the throughput as
+   well.
+   (merge bae60ba7e9 sg/unpack-progress-throughput later to maint).
+
+ * The sequencer machinery compared the HEAD and the state it is
+   attempting to commit to decide if the result would be a no-op
+   commit, even when amending a commit, which was incorrect, and
+   has been corrected.
+
+ * The code to parse GPG output used to assume incorrectly that the
+   finterprint for the primary key would always be present for a valid
+   signature, which has been corrected.
+   (merge 67a6ea6300 hi/gpg-optional-pkfp-fix later to maint).
+
+ * "git submodule status" and "git submodule status --cached" show
+   different things, but the documentation did not cover them
+   correctly, which has been corrected.
+   (merge 8d483c8408 mg/doc-submodule-status-cached later to maint).
+
+ * "git reset --patch $object" without any pathspec should allow a
+   tree object to be given, but incorrectly required a committish,
+   which has been corrected.
+
+ * "git submodule status" that is run from a subdirectory of the
+   superproject did not work well, which has been corrected.
+   (merge 1f3aea22c7 mg/submodule-status-from-a-subdirectory later to maint).
+
+ * The revision walking machinery uses resources like per-object flag
+   bits that need to be reset before a new iteration of walking
+   begins, but the resources related to topological walk were not
+   cleared correctly, which has been corrected.
+   (merge 0aa0c2b2ec mh/clear-topo-walk-upon-reset later to maint).
+
+ * TravisCI update.
+   (merge 176441bfb5 sg/osx-force-gcc-9 later to maint).
+
+ * While running "revert" or "cherry-pick --edit" for multiple
+   commits, a recent regression incorrectly detected "nothing to
+   commit, working tree clean", instead of replaying the commits,
+   which has been corrected.
+   (merge befd4f6a81 sg/assume-no-todo-update-in-cherry-pick later to maint).
+
+ * Work around a issue where a FD that is left open when spawning a
+   child process and is kept open in the child can interfere with the
+   operation in the parent process on Windows.
+
+ * One kind of progress messages were always given during commit-graph
+   generation, instead of following the "if it takes more than two
+   seconds, show progress" pattern, which has been corrected.
+
+ * "git rebase" did not work well when format.useAutoBase
+   configuration variable is set, which has been corrected.
+
+ * The "diff" machinery learned not to lose added/removed blank lines
+   in the context when --ignore-blank-lines and --function-context are
+   used at the same time.
+   (merge 0bb313a552 rs/xdiff-ignore-ws-w-func-context later to maint).
+
+ * The test on "fast-import" used to get stuck when "fast-import" died
+   in the middle.
+   (merge 0d9b0d7885 sg/t9300-robustify later to maint).
+
+ * "git format-patch" can take a set of configured format.notes values
+   to specify which notes refs to use in the log message part of the
+   output.  The behaviour of this was not consistent with multiple
+   --notes command line options, which has been corrected.
+   (merge e0f9095aaa dl/format-patch-notes-config-fixup later to maint).
+
+ * "git p4" used to ignore lfs.storage configuration variable, which
+   has been corrected.
+   (merge ea94b16fb8 rb/p4-lfs later to maint).
+
+ * Assorted fixes to the directory traversal API.
+   (merge 6836d2fe06 en/fill-directory-fixes later to maint).
+
+ * Forbid pathnames that the platform's filesystem cannot represent on
+   MinGW.
+   (merge 4dc42c6c18 js/mingw-reserved-filenames later to maint).
+
+ * "git rebase --signoff" stopped working when the command was written
+   in C, which has been corrected.
+   (merge 4fe7e43c53 en/rebase-signoff-fix later to maint).
+
  * Other code cleanup, docfix, build fix, etc.
    (merge 80736d7c5e jc/am-show-current-patch-docfix later to maint).
    (merge 8b656572ca sg/commit-graph-usage-fix later to maint).
+   (merge 6c02042139 mr/clone-dir-exists-to-path-exists later to maint).
+   (merge 44ae131e38 sg/blame-indent-heuristics-is-now-the-default later to maint).
+   (merge 0115e5d929 dl/doc-diff-no-index-implies-exit-code later to maint).
+   (merge 270de6acbe en/t6024-style later to maint).
+   (merge 14c4776d75 ns/test-desc-typofix later to maint).
+   (merge 68d40f30c4 dj/typofix-merge-strat later to maint).
+   (merge f66e0401ab jk/optim-in-pack-idx-conversion later to maint).
+   (merge 169bed7421 rs/parse-options-dup-null-fix later to maint).
+   (merge 51bd6be32d rs/use-copy-array-in-mingw-shell-command-preparation later to maint).
+   (merge b018719927 ma/t7004 later to maint).
+   (merge 932757b0cc ar/install-doc-update-cmds-needing-the-shell later to maint).
+   (merge 46efd28be1 ep/guard-kset-tar-headers later to maint).
+   (merge 9e5afdf997 ec/fetch-mark-common-refs-trace2 later to maint).
+   (merge f0e58b3fe8 pb/submodule-update-fetches later to maint).
+   (merge 2a02262078 dl/t5520-cleanup later to maint).
+   (merge a4fb016ba1 js/pkt-line-h-typofix later to maint).
+   (merge 54a7a64613 rs/simplify-prepare-cmd later to maint).
+   (merge 3eae30e464 jk/lore-is-the-archive later to maint).
+   (merge 14b7664df8 dl/lore-is-the-archive later to maint).
+   (merge 0e40a73a4c po/bundle-doc-clonable later to maint).
+   (merge e714b898c6 as/t7812-missing-redirects-fix later to maint).
+   (merge 528d9e6d01 jk/perf-wo-git-dot-pm later to maint).
+   (merge fc42f20e24 sg/test-squelch-noise-in-commit-bulk later to maint).
+   (merge c64368e3a2 bc/t9001-zsh-in-posix-emulation-mode later to maint).
+   (merge 11de8dd7ef dr/branch-usage-casefix later to maint).
+   (merge e05e8cf074 rs/archive-zip-code-cleanup later to maint).
+   (merge 147ee35558 rs/commit-export-env-simplify later to maint).
+   (merge 4507ecc771 rs/patch-id-use-oid-to-hex later to maint).
+   (merge 51a0a4ed95 mr/bisect-use-after-free later to maint).
+   (merge cc2bd5c45d pb/submodule-doc-xref later to maint).
+   (merge df5be01669 ja/doc-markup-cleanup later to maint).
+   (merge 7c5cea7242 mr/bisect-save-pointer-to-const-string later to maint).
+   (merge 20a67e8ce9 js/use-test-tool-on-path later to maint).
diff --git a/Documentation/RelNotes/2.3.3.txt b/Documentation/RelNotes/2.3.3.txt
index 5ef1264..850dc68 100644
--- a/Documentation/RelNotes/2.3.3.txt
+++ b/Documentation/RelNotes/2.3.3.txt
@@ -12,7 +12,7 @@
  * Description given by "grep -h" for its --exclude-standard option
    was phrased poorly.
 
- * Documentaton for "git remote add" mentioned "--tags" and
+ * Documentation for "git remote add" mentioned "--tags" and
    "--no-tags" and it was not clear that fetch from the remote in
    the future will use the default behaviour when neither is given
    to override it.
diff --git a/Documentation/RelNotes/2.3.7.txt b/Documentation/RelNotes/2.3.7.txt
index fc95812..5769184 100644
--- a/Documentation/RelNotes/2.3.7.txt
+++ b/Documentation/RelNotes/2.3.7.txt
@@ -4,7 +4,7 @@
 Fixes since v2.3.6
 ------------------
 
- * An earlier update to the parser that disects a URL broke an
+ * An earlier update to the parser that dissects a URL broke an
    address, followed by a colon, followed by an empty string (instead
    of the port number), e.g. ssh://example.com:/path/to/repo.
 
diff --git a/Documentation/RelNotes/2.4.3.txt b/Documentation/RelNotes/2.4.3.txt
index 914d2c1..422e930 100644
--- a/Documentation/RelNotes/2.4.3.txt
+++ b/Documentation/RelNotes/2.4.3.txt
@@ -66,7 +66,7 @@
  * Some time ago, "git blame" (incorrectly) lost the convert_to_git()
    call when synthesizing a fake "tip" commit that represents the
    state in the working tree, which broke folks who record the history
-   with LF line ending to make their project portabile across
+   with LF line ending to make their project portable across
    platforms while terminating lines in their working tree files with
    CRLF for their platform.
 
diff --git a/Documentation/RelNotes/2.5.0.txt b/Documentation/RelNotes/2.5.0.txt
index 8704450..84723f9 100644
--- a/Documentation/RelNotes/2.5.0.txt
+++ b/Documentation/RelNotes/2.5.0.txt
@@ -172,7 +172,8 @@
    incorrect patch text to "git apply".  Add tests to demonstrate
    this.
 
-   I have a slight suspicion that this may be $gmane/87202 coming back
+   I have a slight suspicion that this may be
+   cf. <7vtzf77wjp.fsf@gitster.siamese.dyndns.org> coming back
    and biting us (I seem to have said "let's run with this and see
    what happens" back then).
 
diff --git a/Documentation/RelNotes/2.7.0.txt b/Documentation/RelNotes/2.7.0.txt
index 563dadc..e3cbf3a 100644
--- a/Documentation/RelNotes/2.7.0.txt
+++ b/Documentation/RelNotes/2.7.0.txt
@@ -40,7 +40,7 @@
 
  * "git interpret-trailers" can now run outside of a Git repository.
 
- * "git p4" learned to reencode the pathname it uses to communicate
+ * "git p4" learned to re-encode the pathname it uses to communicate
    with the p4 depot with a new option.
 
  * Give progress meter to "git filter-branch".
diff --git a/Documentation/RelNotes/2.7.3.txt b/Documentation/RelNotes/2.7.3.txt
index 6adf038..f618d71 100644
--- a/Documentation/RelNotes/2.7.3.txt
+++ b/Documentation/RelNotes/2.7.3.txt
@@ -20,7 +20,7 @@
    tests.
 
  * "git show 'HEAD:Foo[BAR]Baz'" did not interpret the argument as a
-   rev, i.e. the object named by the the pathname with wildcard
+   rev, i.e. the object named by the pathname with wildcard
    characters in a tree object.
 
  * "git rev-parse --git-common-dir" used in the worktree feature
diff --git a/Documentation/RelNotes/2.8.0.txt b/Documentation/RelNotes/2.8.0.txt
index 5fbe1b8..27320b6 100644
--- a/Documentation/RelNotes/2.8.0.txt
+++ b/Documentation/RelNotes/2.8.0.txt
@@ -189,7 +189,7 @@
  * Some calls to strcpy(3) triggers a false warning from static
    analyzers that are less intelligent than humans, and reducing the
    number of these false hits helps us notice real issues.  A few
-   calls to strcpy(3) in a couple of protrams that are already safe
+   calls to strcpy(3) in a couple of programs that are already safe
    has been rewritten to avoid false warnings.
 
  * The "name_path" API was an attempt to reduce the need to construct
diff --git a/Documentation/RelNotes/2.8.3.txt b/Documentation/RelNotes/2.8.3.txt
index fedd996..a63825e 100644
--- a/Documentation/RelNotes/2.8.3.txt
+++ b/Documentation/RelNotes/2.8.3.txt
@@ -55,8 +55,8 @@
    This is necessary to use Git on Windows shared directories, and is
    already enabled for the MinGW and plain Windows builds.  It also
    has been used in Cygwin packaged versions of Git for quite a while.
-   See http://thread.gmane.org/gmane.comp.version-control.git/291853
-   and http://thread.gmane.org/gmane.comp.version-control.git/275680.
+   See https://lore.kernel.org/git/20160419091055.GF2345@dinwoodie.org/
+   and https://lore.kernel.org/git/20150811100527.GW14466@dinwoodie.org/.
 
  * "git replace -e" did not honour "core.editor" configuration.
 
diff --git a/Documentation/RelNotes/2.9.0.txt b/Documentation/RelNotes/2.9.0.txt
index b61d367..9916401 100644
--- a/Documentation/RelNotes/2.9.0.txt
+++ b/Documentation/RelNotes/2.9.0.txt
@@ -368,7 +368,7 @@
    This is necessary to use Git on Windows shared directories, and is
    already enabled for the MinGW and plain Windows builds.  It also
    has been used in Cygwin packaged versions of Git for quite a while.
-   See http://thread.gmane.org/gmane.comp.version-control.git/291853
+   See https://lore.kernel.org/git/20160419091055.GF2345@dinwoodie.org/
 
  * "merge-octopus" strategy did not ensure that the index is clean
    when merge begins.
diff --git a/Documentation/RelNotes/2.9.3.txt b/Documentation/RelNotes/2.9.3.txt
index 695b86f..305e080 100644
--- a/Documentation/RelNotes/2.9.3.txt
+++ b/Documentation/RelNotes/2.9.3.txt
@@ -36,7 +36,7 @@
  * One part of "git am" had an oddball helper function that called
    stuff from outside "his" as opposed to calling what we have "ours",
    which was not gender-neutral and also inconsistent with the rest of
-   the system where outside stuff is usuall called "theirs" in
+   the system where outside stuff is usually called "theirs" in
    contrast to "ours".
 
  * The test framework learned a new helper test_match_signal to
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 1a60cc1..4515cab 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -142,19 +142,25 @@
 
 [[commit-reference]]
 If you want to reference a previous commit in the history of a stable
-branch, use the format "abbreviated sha1 (subject, date)",
-with the subject enclosed in a pair of double-quotes, like this:
+branch, use the format "abbreviated hash (subject, date)", like this:
 
 ....
-	Commit f86a374 ("pack-bitmap.c: fix a memleak", 2015-03-30)
+	Commit f86a374 (pack-bitmap.c: fix a memleak, 2015-03-30)
 	noticed that ...
 ....
 
 The "Copy commit summary" command of gitk can be used to obtain this
-format, or this invocation of `git show`:
+format (with the subject enclosed in a pair of double-quotes), or this
+invocation of `git show`:
 
 ....
-	git show -s --date=short --pretty='format:%h ("%s", %ad)' <commit>
+	git show -s --pretty=reference <commit>
+....
+
+or, on an older version of Git without support for --pretty=reference:
+
+....
+	git show -s --date=short --pretty='format:%h (%s, %ad)' <commit>
 ....
 
 [[git-tools]]
diff --git a/Documentation/config.txt b/Documentation/config.txt
index f50f1b4..83e7bba 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -142,7 +142,7 @@
 
 `gitdir/i`::
 	This is the same as `gitdir` except that matching is done
-	case-insensitively (e.g. on case-insensitive file sytems)
+	case-insensitively (e.g. on case-insensitive file systems)
 
 `onbranch`::
 	The data that follows the keyword `onbranch:` is taken to be a
diff --git a/Documentation/config/add.txt b/Documentation/config/add.txt
index 4d753f0..c9f748f 100644
--- a/Documentation/config/add.txt
+++ b/Documentation/config/add.txt
@@ -5,3 +5,8 @@
 	option of linkgit:git-add[1].  `add.ignore-errors` is deprecated,
 	as it does not follow the usual naming convention for configuration
 	variables.
+
+add.interactive.useBuiltin::
+	[EXPERIMENTAL] Set to `true` to use the experimental built-in
+	implementation of the interactive version of linkgit:git-add[1]
+	instead of the Perl script version. Is `false` by default.
diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt
index 6aaa360..d4e698c 100644
--- a/Documentation/config/advice.txt
+++ b/Documentation/config/advice.txt
@@ -107,4 +107,7 @@
 		editor input from the user.
 	nestedTag::
 		Advice shown if a user attempts to recursively tag a tag object.
+	submoduleAlternateErrorStrategyDie:
+		Advice shown when a submodule.alternateErrorStrategy option
+		configured to "die" causes a fatal error.
 --
diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt
index bdbbee5..9e440b1 100644
--- a/Documentation/config/core.txt
+++ b/Documentation/config/core.txt
@@ -559,6 +559,12 @@
 	Defaults to `PERL5LIB` to account for the fact that Git for
 	Windows insists on using its own Perl interpreter.
 
+core.restrictinheritedhandles::
+	Windows-only: override whether spawned processes inherit only standard
+	file handles (`stdin`, `stdout` and `stderr`) or all handles. Can be
+	`auto`, `true` or `false`. Defaults to `auto`, which means `true` on
+	Windows 7 and later, and `false` on older Windows versions.
+
 core.createObject::
 	You can set this to 'link', in which case a hardlink followed by
 	a delete of the source are used to make sure that object creation
diff --git a/Documentation/config/format.txt b/Documentation/config/format.txt
index 513fcd8..45c7bd5 100644
--- a/Documentation/config/format.txt
+++ b/Documentation/config/format.txt
@@ -106,4 +106,20 @@
 instead.
 +
 This configuration can be specified multiple times in order to allow
-multiple notes refs to be included.
+multiple notes refs to be included. In that case, it will behave
+similarly to multiple `--[no-]notes[=]` options passed in. That is, a
+value of `true` will show the default notes, a value of `<ref>` will
+also show notes from that notes ref and a value of `false` will negate
+previous configurations and not show notes.
++
+For example,
++
+------------
+[format]
+	notes = true
+	notes = foo
+	notes = false
+	notes = bar
+------------
++
+will only show notes from `refs/notes/bar`.
diff --git a/Documentation/config/submodule.txt b/Documentation/config/submodule.txt
index 0a1293b..b331771 100644
--- a/Documentation/config/submodule.txt
+++ b/Documentation/config/submodule.txt
@@ -79,4 +79,6 @@
 submodule.alternateErrorStrategy::
 	Specifies how to treat errors with the alternates for a submodule
 	as computed via `submodule.alternateLocation`. Possible values are
-	`ignore`, `info`, `die`. Default is `die`.
+	`ignore`, `info`, `die`. Default is `die`. Note that if set to `ignore`
+	or `info`, and if there is an error with the computed alternate, the
+	clone proceeds as if no alternate was specified.
diff --git a/Documentation/config/tag.txt b/Documentation/config/tag.txt
index ef5adb3..6d9110d 100644
--- a/Documentation/config/tag.txt
+++ b/Documentation/config/tag.txt
@@ -13,7 +13,7 @@
 	Use of this option when running in an automated script can
 	result in a large number of tags being signed. It is therefore
 	convenient to use an agent to avoid typing your gpg passphrase
-	several times. Note that this option doesn't affects tag signing
+	several times. Note that this option doesn't affect tag signing
 	behavior enabled by "-u <keyid>" or "--local-user=<keyid>" options.
 
 tar.umask::
diff --git a/Documentation/diff-format.txt b/Documentation/diff-format.txt
index 4d846d7..fbbd410 100644
--- a/Documentation/diff-format.txt
+++ b/Documentation/diff-format.txt
@@ -61,7 +61,7 @@
 - R: renaming of a file
 - T: change in the type of the file
 - U: file is unmerged (you must complete the merge before it can
-be committed)
+  be committed)
 - X: "unknown" change type (most probably a bug, please report it)
 
 Status letters C and R are always followed by a score (denoting the
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 43b9ff3..a2f7862 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -92,6 +92,10 @@
 	Run `git gc --auto` at the end to perform garbage collection
 	if needed. This is enabled by default.
 
+--[no-]write-commit-graph::
+	Write a commit-graph after fetching. This overrides the config
+	setting `fetch.writeCommitGraph`.
+
 -p::
 --prune::
 	Before fetching, remove any remote-tracking references that no
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index 8b0e4c7..be5e3ac 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -11,7 +11,8 @@
 'git add' [--verbose | -v] [--dry-run | -n] [--force | -f] [--interactive | -i] [--patch | -p]
 	  [--edit | -e] [--[no-]all | --[no-]ignore-removal | [--update | -u]]
 	  [--intent-to-add | -N] [--refresh] [--ignore-errors] [--ignore-missing] [--renormalize]
-	  [--chmod=(+|-)x] [--] [<pathspec>...]
+	  [--chmod=(+|-)x] [--pathspec-from-file=<file> [--pathspec-file-nul]]
+	  [--] [<pathspec>...]
 
 DESCRIPTION
 -----------
@@ -187,6 +188,19 @@
 	bit is only changed in the index, the files on disk are left
 	unchanged.
 
+--pathspec-from-file=<file>::
+	Pathspec is passed in `<file>` instead of commandline args. If
+	`<file>` is exactly `-` then standard input is used. Pathspec
+	elements are separated by LF or CR/LF. Pathspec elements can be
+	quoted as explained for the configuration variable `core.quotePath`
+	(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
+	global `--literal-pathspecs`.
+
+--pathspec-file-nul::
+	Only meaningful with `--pathspec-from-file`. Pathspec elements are
+	separated with NUL character and all other characters are taken
+	literally (including newlines and quotes).
+
 \--::
 	This option can be used to separate command-line options from
 	the list of files, (useful when filenames might be mistaken
diff --git a/Documentation/git-bisect-lk2009.txt b/Documentation/git-bisect-lk2009.txt
index e999251..3ba49e8 100644
--- a/Documentation/git-bisect-lk2009.txt
+++ b/Documentation/git-bisect-lk2009.txt
@@ -158,7 +158,7 @@
 supposed to be used so that all the tests are checked after each
 commit. This means that they are not very efficient, because many
 tests are run for no interesting result, and they suffer from
-combinational explosion.
+combinatorial explosion.
 
 In fact the problem is that big software often has many different
 configuration options and that each test case should pass for each
@@ -1350,9 +1350,9 @@
 - [[[1]]] https://www.nist.gov/sites/default/files/documents/director/planning/report02-3.pdf['The Economic Impacts of Inadequate Infratructure for Software Testing'.  Nist Planning Report 02-3], see Executive Summary and Chapter 8.
 - [[[2]]] http://www.oracle.com/technetwork/java/codeconvtoc-136057.html['Code Conventions for the Java Programming Language'. Sun Microsystems.]
 - [[[3]]] https://en.wikipedia.org/wiki/Software_maintenance['Software maintenance'. Wikipedia.]
-- [[[4]]] https://public-inbox.org/git/7vps5xsbwp.fsf_-_@assigned-by-dhcp.cox.net/[Junio C Hamano. 'Automated bisect success story'.]
+- [[[4]]] https://lore.kernel.org/git/7vps5xsbwp.fsf_-_@assigned-by-dhcp.cox.net/[Junio C Hamano. 'Automated bisect success story'.]
 - [[[5]]] https://lwn.net/Articles/317154/[Christian Couder. 'Fully automated bisecting with "git bisect run"'. LWN.net.]
 - [[[6]]] https://lwn.net/Articles/277872/[Jonathan Corbet. 'Bisection divides users and developers'. LWN.net.]
-- [[[7]]] http://marc.info/?l=linux-kernel&m=119702753411680&w=2[Ingo Molnar. 'Re: BUG 2.6.23-rc3 can't see sd partitions on Alpha'. Linux-kernel mailing list.]
+- [[[7]]] https://lore.kernel.org/lkml/20071207113734.GA14598@elte.hu/[Ingo Molnar. 'Re: BUG 2.6.23-rc3 can't see sd partitions on Alpha'. Linux-kernel mailing list.]
 - [[[8]]] https://www.kernel.org/pub/software/scm/git/docs/git-bisect.html[Junio C Hamano and the git-list. 'git-bisect(1) Manual Page'. Linux Kernel Archives.]
 - [[[9]]] https://github.com/Ealdwulf/bbchop[Ealdwulf. 'bbchop'. GitHub.]
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt
index 4b45d83..7586c5a 100644
--- a/Documentation/git-bisect.txt
+++ b/Documentation/git-bisect.txt
@@ -413,7 +413,7 @@
 
 # tweak the working tree by merging the hot-fix branch
 # and then attempt a build
-if	git merge --no-commit hot-fix &&
+if	git merge --no-commit --no-ff hot-fix &&
 	make
 then
 	# run project specific test and report its status
diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt
index 7d6c9dc..d34b096 100644
--- a/Documentation/git-bundle.txt
+++ b/Documentation/git-bundle.txt
@@ -9,8 +9,8 @@
 SYNOPSIS
 --------
 [verse]
-'git bundle' create <file> <git-rev-list-args>
-'git bundle' verify <file>
+'git bundle' create [-q | --quiet | --progress | --all-progress] [--all-progress-implied] <file> <git-rev-list-args>
+'git bundle' verify [-q | --quiet] <file>
 'git bundle' list-heads <file> [<refname>...]
 'git bundle' unbundle <file> [<refname>...]
 
@@ -20,11 +20,14 @@
 Some workflows require that one or more branches of development on one
 machine be replicated on another machine, but the two machines cannot
 be directly connected, and therefore the interactive Git protocols (git,
-ssh, http) cannot be used.  This command provides support for
-'git fetch' and 'git pull' to operate by packaging objects and references
-in an archive at the originating machine, then importing those into
-another repository using 'git fetch' and 'git pull'
-after moving the archive by some means (e.g., by sneakernet).  As no
+ssh, http) cannot be used.
+
+The 'git bundle' command packages objects and references in an archive
+at the originating machine, which can then be imported into another
+repository using 'git fetch', 'git pull', or 'git clone',
+after moving the archive by some means (e.g., by sneakernet).
+
+As no
 direct connection between the repositories exists, the user must specify a
 basis for the bundle that is held by the destination repository: the
 bundle assumes that all objects in the basis are already in the
@@ -33,9 +36,11 @@
 OPTIONS
 -------
 
-create <file>::
+create [options] <file> <git-rev-list-args>::
 	Used to create a bundle named 'file'.  This requires the
-	'git-rev-list-args' arguments to define the bundle contents.
+	'<git-rev-list-args>' arguments to define the bundle contents.
+	'options' contains the options specific to the 'git bundle create'
+	subcommand.
 
 verify <file>::
 	Used to check that a bundle file is valid and will apply
@@ -75,6 +80,33 @@
 	necessarily everything in the pack (in this case, 'git bundle' acts
 	like 'git fetch-pack').
 
+--progress::
+	Progress status is reported on the standard error stream
+	by default when it is attached to a terminal, unless -q
+	is specified. This flag forces progress status even if
+	the standard error stream is not directed to a terminal.
+
+--all-progress::
+	When --stdout is specified then progress report is
+	displayed during the object count and compression phases
+	but inhibited during the write-out phase. The reason is
+	that in some cases the output stream is directly linked
+	to another command which may wish to display progress
+	status of its own as it processes incoming pack data.
+	This flag is like --progress except that it forces progress
+	report for the write-out phase as well even if --stdout is
+	used.
+
+--all-progress-implied::
+	This is used to imply --all-progress whenever progress display
+	is activated.  Unlike --all-progress this flag doesn't actually
+	force any progress display by itself.
+
+-q::
+--quiet::
+	This flag makes the command not to report its progress
+	on the standard error stream.
+
 SPECIFYING REFERENCES
 ---------------------
 
@@ -92,6 +124,14 @@
 to contain objects already in the destination, as these are ignored
 when unpacking at the destination.
 
+`git clone` can use any bundle created without negative refspecs
+(e.g., `new`, but not `old..new`).
+If you want to match `git clone --mirror`, which would include your
+refs such as `refs/remotes/*`, use `--all`.
+If you want to provide the same set of refs that a clone directly
+from the source repository would get, use `--branches --tags` for
+the `<git-rev-list-args>`.
+
 EXAMPLES
 --------
 
diff --git a/Documentation/git-check-attr.txt b/Documentation/git-check-attr.txt
index 3c05782..84f41a8 100644
--- a/Documentation/git-check-attr.txt
+++ b/Documentation/git-check-attr.txt
@@ -32,7 +32,7 @@
 	instead of from the command-line.
 
 -z::
-	The output format is modified to be machine-parseable.
+	The output format is modified to be machine-parsable.
 	If `--stdin` is also given, input paths are separated
 	with a NUL character instead of a linefeed character.
 
diff --git a/Documentation/git-check-ignore.txt b/Documentation/git-check-ignore.txt
index 8b42cb3..8b2d49c 100644
--- a/Documentation/git-check-ignore.txt
+++ b/Documentation/git-check-ignore.txt
@@ -39,7 +39,7 @@
 	instead of from the command-line.
 
 -z::
-	The output format is modified to be machine-parseable (see
+	The output format is modified to be machine-parsable (see
 	below).  If `--stdin` is also given, input paths are separated
 	with a NUL character instead of a linefeed character.
 
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index cf3cac0..c8fb995 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -12,14 +12,14 @@
 'git checkout' [-q] [-f] [-m] --detach [<branch>]
 'git checkout' [-q] [-f] [-m] [--detach] <commit>
 'git checkout' [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>]
-'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
-'git checkout' [<tree-ish>] [--] <pathspec>...
-'git checkout' (-p|--patch) [<tree-ish>] [--] [<paths>...]
+'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <pathspec>...
+'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] --pathspec-from-file=<file> [--pathspec-file-nul]
+'git checkout' (-p|--patch) [<tree-ish>] [--] [<pathspec>...]
 
 DESCRIPTION
 -----------
 Updates files in the working tree to match the version in the index
-or the specified tree.  If no paths are given, 'git checkout' will
+or the specified tree.  If no pathspec was given, 'git checkout' will
 also update `HEAD` to set the specified branch as the current
 branch.
 
@@ -79,13 +79,14 @@
 +
 Omitting `<branch>` detaches `HEAD` at the tip of the current branch.
 
-'git checkout' [<tree-ish>] [--] <pathspec>...::
+'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <pathspec>...::
+'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] --pathspec-from-file=<file> [--pathspec-file-nul]::
 
-	Overwrite paths in the working tree by replacing with the
-	contents in the index or in the `<tree-ish>` (most often a
-	commit).  When a `<tree-ish>` is given, the paths that
-	match the `<pathspec>` are updated both in the index and in
-	the working tree.
+	Overwrite the contents of the files that match the pathspec.
+	When the `<tree-ish>` (most often a commit) is not given,
+	overwrite working tree with the contents in the index.
+	When the `<tree-ish>` is given, overwrite both the index and
+	the working tree with the contents at the `<tree-ish>`.
 +
 The index may contain unmerged entries because of a previous failed merge.
 By default, if you try to check out such an entry from the index, the
@@ -96,12 +97,10 @@
 file can be discarded to re-create the original conflicted merge result.
 
 'git checkout' (-p|--patch) [<tree-ish>] [--] [<pathspec>...]::
-	This is similar to the "check out paths to the working tree
-	from either the index or from a tree-ish" mode described
-	above, but lets you use the interactive interface to show
-	the "diff" output and choose which hunks to use in the
-	result.  See below for the description of `--patch` option.
-
+	This is similar to the previous mode, but lets you use the
+	interactive interface to show the "diff" output and choose which
+	hunks to use in the result.  See below for the description of
+	`--patch` option.
 
 OPTIONS
 -------
@@ -309,6 +308,19 @@
 	working tree, but not in `<tree-ish>` are removed, to make them
 	match `<tree-ish>` exactly.
 
+--pathspec-from-file=<file>::
+	Pathspec is passed in `<file>` instead of commandline args. If
+	`<file>` is exactly `-` then standard input is used. Pathspec
+	elements are separated by LF or CR/LF. Pathspec elements can be
+	quoted as explained for the configuration variable `core.quotePath`
+	(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
+	global `--literal-pathspecs`.
+
+--pathspec-file-nul::
+	Only meaningful with `--pathspec-from-file`. Pathspec elements are
+	separated with NUL character and all other characters are taken
+	literally (including newlines and quotes).
+
 <branch>::
 	Branch to checkout; if it refers to a branch (i.e., a name that,
 	when prepended with "refs/heads/", is a valid ref), then that
@@ -339,7 +351,13 @@
 	Tree to checkout from (when paths are given). If not specified,
 	the index will be used.
 
+\--::
+	Do not interpret any more arguments as options.
 
+<pathspec>...::
+	Limits the paths affected by the operation.
++
+For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
 
 DETACHED HEAD
 -------------
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 0fe91d2..bf24f18 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -268,9 +268,9 @@
 	All submodules which are cloned will be shallow with a depth of 1.
 
 --[no-]remote-submodules::
-	All submodules which are cloned will use the status of the submodule’s
+	All submodules which are cloned will use the status of the submodule's
 	remote-tracking branch to update the submodule, rather than the
-	superproject’s recorded SHA-1. Equivalent to passing `--remote` to
+	superproject's recorded SHA-1. Equivalent to passing `--remote` to
 	`git submodule update`.
 
 --separate-git-dir=<git dir>::
diff --git a/Documentation/git-commit-graph.txt b/Documentation/git-commit-graph.txt
index 8c708a7..bcd85c1 100644
--- a/Documentation/git-commit-graph.txt
+++ b/Documentation/git-commit-graph.txt
@@ -9,7 +9,6 @@
 SYNOPSIS
 --------
 [verse]
-'git commit-graph read' [--object-dir <dir>]
 'git commit-graph verify' [--object-dir <dir>] [--shallow] [--[no-]progress]
 'git commit-graph write' <options> [--object-dir <dir>] [--[no-]progress]
 
@@ -74,11 +73,6 @@
 be the current time. After writing the split commit-graph, delete all
 unused commit-graph whose modified times are older than `datetime`.
 
-'read'::
-
-Read the commit-graph file and output basic details about it.
-Used for debugging purposes.
-
 'verify'::
 
 Read the commit-graph file and verify its contents against the object
@@ -118,12 +112,6 @@
 $ git rev-parse HEAD | git commit-graph write --stdin-commits --append
 ------------------------------------------------
 
-* Read basic information from the commit-graph file.
-+
-------------------------------------------------
-$ git commit-graph read
-------------------------------------------------
-
 
 GIT
 ---
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index afa7b75..ced5a9b 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -13,7 +13,8 @@
 	   [-F <file> | -m <msg>] [--reset-author] [--allow-empty]
 	   [--allow-empty-message] [--no-verify] [-e] [--author=<author>]
 	   [--date=<date>] [--cleanup=<mode>] [--[no-]status]
-	   [-i | -o] [-S[<keyid>]] [--] [<file>...]
+	   [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]
+	   [-S[<keyid>]] [--] [<pathspec>...]
 
 DESCRIPTION
 -----------
@@ -278,6 +279,19 @@
 	already been staged. If used together with `--allow-empty`
 	paths are also not required, and an empty commit will be created.
 
+--pathspec-from-file=<file>::
+	Pathspec is passed in `<file>` instead of commandline args. If
+	`<file>` is exactly `-` then standard input is used. Pathspec
+	elements are separated by LF or CR/LF. Pathspec elements can be
+	quoted as explained for the configuration variable `core.quotePath`
+	(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
+	global `--literal-pathspecs`.
+
+--pathspec-file-nul::
+	Only meaningful with `--pathspec-from-file`. Pathspec elements are
+	separated with NUL character and all other characters are taken
+	literally (including newlines and quotes).
+
 -u[<mode>]::
 --untracked-files[=<mode>]::
 	Show untracked files.
@@ -345,12 +359,13 @@
 \--::
 	Do not interpret any more arguments as options.
 
-<file>...::
-	When files are given on the command line, the command
-	commits the contents of the named files, without
-	recording the changes already staged.  The contents of
-	these files are also staged for the next commit on top
-	of what have been staged before.
+<pathspec>...::
+	When pathspec is given on the command line, commit the contents of
+	the files that match the pathspec without recording the changes
+	already added to the index. The contents of these files are also
+	staged for the next commit on top of what have been staged before.
++
+For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
 
 :git-commit: 1
 include::date-formats.txt[]
diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt
index b211440..6f0c7ca 100644
--- a/Documentation/git-credential.txt
+++ b/Documentation/git-credential.txt
@@ -19,8 +19,7 @@
 usernames and passwords. The git-credential command exposes this
 interface to scripts which may want to retrieve, store, or prompt for
 credentials in the same manner as Git. The design of this scriptable
-interface models the internal C API; see
-link:technical/api-credentials.html[the Git credential API] for more
+interface models the internal C API; see credential.h for more
 background on the concepts.
 
 git-credential takes an "action" option on the command-line (one of
diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt
index 79e22b1..1b1c71a 100644
--- a/Documentation/git-cvsserver.txt
+++ b/Documentation/git-cvsserver.txt
@@ -294,7 +294,7 @@
 	Git directory name
 %g::
 	Git directory name, where all characters except for
-	alpha-numeric ones, `.`, and `-` are replaced with
+	alphanumeric ones, `.`, and `-` are replaced with
 	`_` (this should make it easier to use the directory
 	name in a filename if wanted)
 %m::
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index 72179d9..37781cf 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -36,7 +36,7 @@
 	running the command in a working tree controlled by Git and
 	at least one of the paths points outside the working tree,
 	or when running the command outside a working tree
-	controlled by Git.
+	controlled by Git. This form implies `--exit-code`.
 
 'git diff' [<options>] --cached [<commit>] [--] [<path>...]::
 
diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.txt
index 37634bf..e8950de 100644
--- a/Documentation/git-fast-export.txt
+++ b/Documentation/git-fast-export.txt
@@ -142,7 +142,7 @@
 	Specify how to handle `encoding` header in commit objects.  When
 	asking to 'abort' (which is the default), this program will die
 	when encountering such a commit object.  With 'yes', the commit
-	message will be reencoded into UTF-8.  With 'no', the original
+	message will be re-encoded into UTF-8.  With 'no', the original
 	encoding will be preserved.
 
 --refspec::
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index a3f1e0c..7889f95 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -51,6 +51,21 @@
 	memory used by fast-import during this run.  Showing this output
 	is currently the default, but can be disabled with --quiet.
 
+--allow-unsafe-features::
+	Many command-line options can be provided as part of the
+	fast-import stream itself by using the `feature` or `option`
+	commands. However, some of these options are unsafe (e.g.,
+	allowing fast-import to access the filesystem outside of the
+	repository). These options are disabled by default, but can be
+	allowed by providing this option on the command line.  This
+	currently impacts only the `export-marks`, `import-marks`, and
+	`import-marks-if-exists` feature commands.
++
+	Only enable this option if you trust the program generating the
+	fast-import stream! This option is enabled automatically for
+	remote-helpers that use the `import` capability, as they are
+	already trusted to run their own code.
+
 Options for Frontends
 ~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 5876598..a530fef 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -466,13 +466,13 @@
 impossible for a backward-compatible implementation to ever be fast:
 
 * In editing files, git-filter-branch by design checks out each and
-every commit as it existed in the original repo.  If your repo has 10\^5
-files and 10\^5 commits, but each commit only modifies 5 files, then
-git-filter-branch will make you do 10\^10 modifications, despite only
-having (at most) 5*10^5 unique blobs.
+  every commit as it existed in the original repo.  If your repo has
+  10\^5 files and 10\^5 commits, but each commit only modifies 5
+  files, then git-filter-branch will make you do 10\^10 modifications,
+  despite only having (at most) 5*10^5 unique blobs.
 
 * If you try and cheat and try to make git-filter-branch only work on
-files modified in a commit, then two things happen
+  files modified in a commit, then two things happen
 
   ** you run into problems with deletions whenever the user is simply
      trying to rename files (because attempting to delete files that
@@ -481,39 +481,41 @@
      user-provided shell)
 
   ** even if you succeed at the map-deletes-for-renames chicanery, you
-     still technically violate backward compatibility because users are
-     allowed to filter files in ways that depend upon topology of
-     commits instead of filtering solely based on file contents or names
-     (though this has not been observed in the wild).
+     still technically violate backward compatibility because users
+     are allowed to filter files in ways that depend upon topology of
+     commits instead of filtering solely based on file contents or
+     names (though this has not been observed in the wild).
 
 * Even if you don't need to edit files but only want to e.g. rename or
-remove some and thus can avoid checking out each file (i.e. you can use
---index-filter), you still are passing shell snippets for your filters.
-This means that for every commit, you have to have a prepared git repo
-where those filters can be run.  That's a significant setup.
+  remove some and thus can avoid checking out each file (i.e. you can
+  use --index-filter), you still are passing shell snippets for your
+  filters.  This means that for every commit, you have to have a
+  prepared git repo where those filters can be run.  That's a
+  significant setup.
 
-* Further, several additional files are created or updated per commit by
-git-filter-branch.  Some of these are for supporting the convenience
-functions provided by git-filter-branch (such as map()), while others
-are for keeping track of internal state (but could have also been
-accessed by user filters; one of git-filter-branch's regression tests
-does so).  This essentially amounts to using the filesystem as an IPC
-mechanism between git-filter-branch and the user-provided filters.
-Disks tend to be a slow IPC mechanism, and writing these files also
-effectively represents a forced synchronization point between separate
-processes that we hit with every commit.
+* Further, several additional files are created or updated per commit
+  by git-filter-branch.  Some of these are for supporting the
+  convenience functions provided by git-filter-branch (such as map()),
+  while others are for keeping track of internal state (but could have
+  also been accessed by user filters; one of git-filter-branch's
+  regression tests does so).  This essentially amounts to using the
+  filesystem as an IPC mechanism between git-filter-branch and the
+  user-provided filters.  Disks tend to be a slow IPC mechanism, and
+  writing these files also effectively represents a forced
+  synchronization point between separate processes that we hit with
+  every commit.
 
 * The user-provided shell commands will likely involve a pipeline of
-commands, resulting in the creation of many processes per commit.
-Creating and running another process takes a widely varying amount of
-time between operating systems, but on any platform it is very slow
-relative to invoking a function.
+  commands, resulting in the creation of many processes per commit.
+  Creating and running another process takes a widely varying amount
+  of time between operating systems, but on any platform it is very
+  slow relative to invoking a function.
 
 * git-filter-branch itself is written in shell, which is kind of slow.
-This is the one performance issue that could be backward-compatibly
-fixed, but compared to the above problems that are intrinsic to the
-design of git-filter-branch, the language of the tool itself is a
-relatively minor issue.
+  This is the one performance issue that could be backward-compatibly
+  fixed, but compared to the above problems that are intrinsic to the
+  design of git-filter-branch, the language of the tool itself is a
+  relatively minor issue.
 
   ** Side note: Unfortunately, people tend to fixate on the
      written-in-shell aspect and periodically ask if git-filter-branch
@@ -534,7 +536,7 @@
 https://github.com/newren/git-filter-repo/blob/master/contrib/filter-repo-demos/filter-lamely[filter-lamely],
 a drop-in git-filter-branch replacement (with a few caveats).  While
 filter-lamely suffers from all the same safety issues as
-git-filter-branch, it at least ameloriates the performance issues a
+git-filter-branch, it at least ameliorates the performance issues a
 little.
 
 [[SAFETY]]
@@ -546,51 +548,55 @@
 with:
 
 * Someone can have a set of "working and tested filters" which they
-document or provide to a coworker, who then runs them on a different OS
-where the same commands are not working/tested (some examples in the
-git-filter-branch manpage are also affected by this).  BSD vs. GNU
-userland differences can really bite.  If lucky, error messages are
-spewed.  But just as likely, the commands either don't do the filtering
-requested, or silently corrupt by making some unwanted change.  The
-unwanted change may only affect a few commits, so it's not necessarily
-obvious either.  (The fact that problems won't necessarily be obvious
-means they are likely to go unnoticed until the rewritten history is in
-use for quite a while, at which point it's really hard to justify
-another flag-day for another rewrite.)
+  document or provide to a coworker, who then runs them on a different
+  OS where the same commands are not working/tested (some examples in
+  the git-filter-branch manpage are also affected by this).
+  BSD vs. GNU userland differences can really bite.  If lucky, error
+  messages are spewed.  But just as likely, the commands either don't
+  do the filtering requested, or silently corrupt by making some
+  unwanted change.  The unwanted change may only affect a few commits,
+  so it's not necessarily obvious either.  (The fact that problems
+  won't necessarily be obvious means they are likely to go unnoticed
+  until the rewritten history is in use for quite a while, at which
+  point it's really hard to justify another flag-day for another
+  rewrite.)
 
 * Filenames with spaces are often mishandled by shell snippets since
-they cause problems for shell pipelines.  Not everyone is familiar with
-find -print0, xargs -0, git-ls-files -z, etc.  Even people who are
-familiar with these may assume such flags are not relevant because
-someone else renamed any such files in their repo back before the person
-doing the filtering joined the project.  And often, even those familiar
-with handling arguments with spaces may not do so just because they
-aren't in the mindset of thinking about everything that could possibly
-go wrong.
+  they cause problems for shell pipelines.  Not everyone is familiar
+  with find -print0, xargs -0, git-ls-files -z, etc.  Even people who
+  are familiar with these may assume such flags are not relevant
+  because someone else renamed any such files in their repo back
+  before the person doing the filtering joined the project.  And
+  often, even those familiar with handling arguments with spaces may
+  not do so just because they aren't in the mindset of thinking about
+  everything that could possibly go wrong.
 
-* Non-ascii filenames can be silently removed despite being in a desired
-directory.  Keeping only wanted paths is often done using pipelines like
-`git ls-files | grep -v ^WANTED_DIR/ | xargs git rm`.  ls-files will
-only quote filenames if needed, so folks may not notice that one of the
-files didn't match the regex (at least not until it's much too late).
-Yes, someone who knows about core.quotePath can avoid this (unless they
-have other special characters like \t, \n, or "), and people who use
-ls-files -z with something other than grep can avoid this, but that
-doesn't mean they will.
+* Non-ascii filenames can be silently removed despite being in a
+  desired directory.  Keeping only wanted paths is often done using
+  pipelines like `git ls-files | grep -v ^WANTED_DIR/ | xargs git rm`.
+  ls-files will only quote filenames if needed, so folks may not
+  notice that one of the files didn't match the regex (at least not
+  until it's much too late).  Yes, someone who knows about
+  core.quotePath can avoid this (unless they have other special
+  characters like \t, \n, or "), and people who use ls-files -z with
+  something other than grep can avoid this, but that doesn't mean they
+  will.
 
-* Similarly, when moving files around, one can find that filenames with
-non-ascii or special characters end up in a different directory, one
-that includes a double quote character.  (This is technically the same
-issue as above with quoting, but perhaps an interesting different way
-that it can and has manifested as a problem.)
+* Similarly, when moving files around, one can find that filenames
+  with non-ascii or special characters end up in a different
+  directory, one that includes a double quote character.  (This is
+  technically the same issue as above with quoting, but perhaps an
+  interesting different way that it can and has manifested as a
+  problem.)
 
 * It's far too easy to accidentally mix up old and new history.  It's
-still possible with any tool, but git-filter-branch almost invites it.
-If lucky, the only downside is users getting frustrated that they don't
-know how to shrink their repo and remove the old stuff.  If unlucky,
-they merge old and new history and end up with multiple "copies" of each
-commit, some of which have unwanted or sensitive files and others which
-don't.  This comes about in multiple different ways:
+  still possible with any tool, but git-filter-branch almost
+  invites it.  If lucky, the only downside is users getting frustrated
+  that they don't know how to shrink their repo and remove the old
+  stuff.  If unlucky, they merge old and new history and end up with
+  multiple "copies" of each commit, some of which have unwanted or
+  sensitive files and others which don't.  This comes about in
+  multiple different ways:
 
   ** the default to only doing a partial history rewrite ('--all' is not
      the default and few examples show it)
@@ -609,8 +615,8 @@
      "DISCUSSION" section of the git filter-repo manual page for more
      details.
 
-* Annotated tags can be accidentally converted to lightweight tags, due
-to either of two issues:
+* Annotated tags can be accidentally converted to lightweight tags,
+  due to either of two issues:
 
   ** Someone can do a history rewrite, realize they messed up, restore
      from the backups in refs/original/, and then redo their
@@ -623,71 +629,74 @@
      restored from refs/original/ in a previously botched rewrite).
 
 * Any commit messages that specify an encoding will become corrupted
-by the rewrite; git-filter-branch ignores the encoding, takes the original
-bytes, and feeds it to commit-tree without telling it the proper
-encoding.  (This happens whether or not --msg-filter is used.)
+  by the rewrite; git-filter-branch ignores the encoding, takes the
+  original bytes, and feeds it to commit-tree without telling it the
+  proper encoding.  (This happens whether or not --msg-filter is
+  used.)
 
 * Commit messages (even if they are all UTF-8) by default become
-corrupted due to not being updated -- any references to other commit
-hashes in commit messages will now refer to no-longer-extant commits.
+  corrupted due to not being updated -- any references to other commit
+  hashes in commit messages will now refer to no-longer-extant
+  commits.
 
-* There are no facilities for helping users find what unwanted crud they
-should delete, which means they are much more likely to have incomplete
-or partial cleanups that sometimes result in confusion and people
-wasting time trying to understand.  (For example, folks tend to just
-look for big files to delete instead of big directories or extensions,
-and once they do so, then sometime later folks using the new repository
-who are going through history will notice a build artifact directory
-that has some files but not others, or a cache of dependencies
-(node_modules or similar) which couldn't have ever been functional since
-it's missing some files.)
+* There are no facilities for helping users find what unwanted crud
+  they should delete, which means they are much more likely to have
+  incomplete or partial cleanups that sometimes result in confusion
+  and people wasting time trying to understand.  (For example, folks
+  tend to just look for big files to delete instead of big directories
+  or extensions, and once they do so, then sometime later folks using
+  the new repository who are going through history will notice a build
+  artifact directory that has some files but not others, or a cache of
+  dependencies (node_modules or similar) which couldn't have ever been
+  functional since it's missing some files.)
 
 * If --prune-empty isn't specified, then the filtering process can
-create hoards of confusing empty commits
+  create hoards of confusing empty commits
 
 * If --prune-empty is specified, then intentionally placed empty
-commits from before the filtering operation are also pruned instead of
-just pruning commits that became empty due to filtering rules.
+  commits from before the filtering operation are also pruned instead
+  of just pruning commits that became empty due to filtering rules.
 
-* If --prune empty is specified, sometimes empty commits are missed
-and left around anyway (a somewhat rare bug, but it happens...)
+* If --prune-empty is specified, sometimes empty commits are missed
+  and left around anyway (a somewhat rare bug, but it happens...)
 
 * A minor issue, but users who have a goal to update all names and
-emails in a repository may be led to --env-filter which will only update
-authors and committers, missing taggers.
+  emails in a repository may be led to --env-filter which will only
+  update authors and committers, missing taggers.
 
 * If the user provides a --tag-name-filter that maps multiple tags to
-the same name, no warning or error is provided; git-filter-branch simply
-overwrites each tag in some undocumented pre-defined order resulting in
-only one tag at the end.  (A git-filter-branch regression test requires
-this surprising behavior.)
+  the same name, no warning or error is provided; git-filter-branch
+  simply overwrites each tag in some undocumented pre-defined order
+  resulting in only one tag at the end.  (A git-filter-branch
+  regression test requires this surprising behavior.)
 
 Also, the poor performance of git-filter-branch often leads to safety
 issues:
 
-* Coming up with the correct shell snippet to do the filtering you want
-is sometimes difficult unless you're just doing a trivial modification
-such as deleting a couple files.  Unfortunately, people often learn if
-the snippet is right or wrong by trying it out, but the rightness or
-wrongness can vary depending on special circumstances (spaces in
-filenames, non-ascii filenames, funny author names or emails, invalid
-timezones, presence of grafts or replace objects, etc.), meaning they
-may have to wait a long time, hit an error, then restart.  The
-performance of git-filter-branch is so bad that this cycle is painful,
-reducing the time available to carefully re-check (to say nothing about
-what it does to the patience of the person doing the rewrite even if
-they do technically have more time available).  This problem is extra
-compounded because errors from broken filters may not be shown for a
-long time and/or get lost in a sea of output.  Even worse, broken
-filters often just result in silent incorrect rewrites.
+* Coming up with the correct shell snippet to do the filtering you
+  want is sometimes difficult unless you're just doing a trivial
+  modification such as deleting a couple files.  Unfortunately, people
+  often learn if the snippet is right or wrong by trying it out, but
+  the rightness or wrongness can vary depending on special
+  circumstances (spaces in filenames, non-ascii filenames, funny
+  author names or emails, invalid timezones, presence of grafts or
+  replace objects, etc.), meaning they may have to wait a long time,
+  hit an error, then restart.  The performance of git-filter-branch is
+  so bad that this cycle is painful, reducing the time available to
+  carefully re-check (to say nothing about what it does to the
+  patience of the person doing the rewrite even if they do technically
+  have more time available).  This problem is extra compounded because
+  errors from broken filters may not be shown for a long time and/or
+  get lost in a sea of output.  Even worse, broken filters often just
+  result in silent incorrect rewrites.
 
-* To top it all off, even when users finally find working commands, they
-naturally want to share them.  But they may be unaware that their repo
-didn't have some special cases that someone else's does.  So, when
-someone else with a different repository runs the same commands, they
-get hit by the problems above.  Or, the user just runs commands that
-really were vetted for special cases, but they run it on a different OS
-where it doesn't work, as noted above.
+* To top it all off, even when users finally find working commands,
+  they naturally want to share them.  But they may be unaware that
+  their repo didn't have some special cases that someone else's does.
+  So, when someone else with a different repository runs the same
+  commands, they get hit by the problems above.  Or, the user just
+  runs commands that really were vetted for special cases, but they
+  run it on a different OS where it doesn't work, as noted above.
 
 GIT
 ---
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 00bdf9b..0d4f895 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -333,11 +333,12 @@
   Output an all-zero hash in each patch's From header instead
   of the hash of the commit.
 
---base=<commit>::
+--[no-]base[=<commit>]::
 	Record the base tree information to identify the state the
 	patch series applies to.  See the BASE TREE INFORMATION section
 	below for details. If <commit> is "auto", a base commit is
-	automatically chosen.
+	automatically chosen. The `--no-base` option overrides a
+	`format.useAutoBase` configuration.
 
 --root::
 	Treat the revision argument as a <revision range>, even if it
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index b406bc4..bed09bb 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -76,8 +76,12 @@
 	(or the function name regex <funcname>) within the <file>.  You may
 	not give any pathspec limiters.  This is currently limited to
 	a walk starting from a single revision, i.e., you may only
-	give zero or one positive revision arguments.
-	You can specify this option more than once.
+	give zero or one positive revision arguments, and
+	<start> and <end> (or <funcname>) must exist in the starting revision.
+	You can specify this option more than once. Implies `--patch`.
+	Patch output can be suppressed using `--no-patch`, but other diff formats
+	(namely `--raw`, `--numstat`, `--shortstat`, `--dirstat`, `--summary`,
+	`--name-only`, `--name-status`, `--check`) are not currently implemented.
 +
 include::line-range-format.txt[]
 
diff --git a/Documentation/git-range-diff.txt b/Documentation/git-range-diff.txt
index 8a6ea2c..9701c1e 100644
--- a/Documentation/git-range-diff.txt
+++ b/Documentation/git-range-diff.txt
@@ -57,6 +57,10 @@
 	See the ``Algorithm`` section below for an explanation why this is
 	needed.
 
+--[no-]notes[=<ref>]::
+	This flag is passed to the `git log` program
+	(see linkgit:git-log[1]) that generates the patches.
+
 <range1> <range2>::
 	Compare the commits specified by the two ranges, where
 	`<range1>` is considered an older version of `<range2>`.
@@ -75,7 +79,7 @@
 linkgit:git-diff[1]), most notably the `--color=[<when>]` and
 `--no-color` options. These options are used when generating the "diff
 between patches", i.e. to compare the author, commit message and diff of
-corresponding old/new commits. There is currently no means to tweak the
+corresponding old/new commits. There is currently no means to tweak most of the
 diff options passed to `git log` when generating those patches.
 
 OUTPUT STABILITY
@@ -242,7 +246,7 @@
 
 The overall time needed to compute this algorithm is the time needed to
 compute n+m commit diffs and then n*m diffs of patches, plus the time
-needed to compute the least-cost assigment between n and m diffs. Git
+needed to compute the least-cost assignment between n and m diffs. Git
 uses an implementation of the Jonker-Volgenant algorithm to solve the
 assignment problem, which has cubic runtime complexity. The matching
 found in this case will look like this:
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 639a417..1d0e2d2 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -393,16 +393,31 @@
 with `--keep-base` in order to drop those commits from your branch.
 
 --ignore-whitespace::
+	Behaves differently depending on which backend is selected.
++
+'am' backend: When applying a patch, ignore changes in whitespace in
+context lines if necessary.
++
+'interactive' backend: Treat lines with only whitespace changes as
+unchanged for the sake of a three-way merge.
+
 --whitespace=<option>::
-	These flag are passed to the 'git apply' program
+	This flag is passed to the 'git apply' program
 	(see linkgit:git-apply[1]) that applies the patch.
 +
 See also INCOMPATIBLE OPTIONS below.
 
 --committer-date-is-author-date::
+	Instead of recording the time the rebased commits are
+	created as the committer date, reuse the author date
+	as the committer date. This implies --force-rebase.
+
 --ignore-date::
-	These flags are passed to 'git am' to easily change the dates
-	of the rebased commits (see linkgit:git-am[1]).
+--reset-author-date::
+	By default, the author date of the original commit is used
+	as the author date for the resulting commit.  This option
+	tells Git to use the current timestamp instead and implies
+	`--force-rebase`.
 +
 See also INCOMPATIBLE OPTIONS below.
 
@@ -443,8 +458,8 @@
 onto `<upstream>` (or `<onto>`, if specified).
 +
 The `--rebase-merges` mode is similar in spirit to the deprecated
-`--preserve-merges`, but in contrast to that option works well in interactive
-rebases: commits can be reordered, inserted and dropped at will.
+`--preserve-merges` but works with interactive rebases,
+where commits can be reordered, inserted and dropped at will.
 +
 It is currently only possible to recreate the merge commits using the
 `recursive` merge strategy; Different merge strategies can be used only via
@@ -539,10 +554,7 @@
 
 The following options:
 
- * --committer-date-is-author-date
- * --ignore-date
  * --whitespace
- * --ignore-whitespace
  * -C
 
 are incompatible with the following options:
@@ -565,6 +577,9 @@
  * --preserve-merges and --interactive
  * --preserve-merges and --signoff
  * --preserve-merges and --rebase-merges
+ * --preserve-merges and --ignore-whitespace
+ * --preserve-merges and --committer-date-is-author-date
+ * --preserve-merges and --ignore-date
  * --keep-base and --onto
  * --keep-base and --root
 
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index 97e0544..932080c 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -8,34 +8,36 @@
 SYNOPSIS
 --------
 [verse]
-'git reset' [-q] [<tree-ish>] [--] <paths>...
-'git reset' (--patch | -p) [<tree-ish>] [--] [<paths>...]
+'git reset' [-q] [<tree-ish>] [--] <pathspec>...
+'git reset' [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]
+'git reset' (--patch | -p) [<tree-ish>] [--] [<pathspec>...]
 'git reset' [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
 
 DESCRIPTION
 -----------
-In the first and second form, copy entries from `<tree-ish>` to the index.
-In the third form, set the current branch head (`HEAD`) to `<commit>`,
+In the first three forms, copy entries from `<tree-ish>` to the index.
+In the last form, set the current branch head (`HEAD`) to `<commit>`,
 optionally modifying index and working tree to match.
 The `<tree-ish>`/`<commit>` defaults to `HEAD` in all forms.
 
-'git reset' [-q] [<tree-ish>] [--] <paths>...::
-	This form resets the index entries for all `<paths>` to their
-	state at `<tree-ish>`.  (It does not affect the working tree or
-	the current branch.)
+'git reset' [-q] [<tree-ish>] [--] <pathspec>...::
+'git reset' [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]::
+	These forms reset the index entries for all paths that match the
+	`<pathspec>` to their state at `<tree-ish>`.  (It does not affect
+	the working tree or the current branch.)
 +
-This means that `git reset <paths>` is the opposite of `git add
-<paths>`. This command is equivalent to
-`git restore [--source=<tree-ish>] --staged <paths>...`.
+This means that `git reset <pathspec>` is the opposite of `git add
+<pathspec>`. This command is equivalent to
+`git restore [--source=<tree-ish>] --staged <pathspec>...`.
 +
-After running `git reset <paths>` to update the index entry, you can
+After running `git reset <pathspec>` to update the index entry, you can
 use linkgit:git-restore[1] to check the contents out of the index to
 the working tree. Alternatively, using linkgit:git-restore[1]
 and specifying a commit with `--source`, you
 can copy the contents of a path out of a commit to the index and to the
 working tree in one go.
 
-'git reset' (--patch | -p) [<tree-ish>] [--] [<paths>...]::
+'git reset' (--patch | -p) [<tree-ish>] [--] [<pathspec>...]::
 	Interactively select hunks in the difference between the index
 	and `<tree-ish>` (defaults to `HEAD`).  The chosen hunks are applied
 	in reverse to the index.
@@ -101,6 +103,26 @@
 	`reset.quiet` config option. `--quiet` and `--no-quiet` will
 	override the default behavior.
 
+--pathspec-from-file=<file>::
+	Pathspec is passed in `<file>` instead of commandline args. If
+	`<file>` is exactly `-` then standard input is used. Pathspec
+	elements are separated by LF or CR/LF. Pathspec elements can be
+	quoted as explained for the configuration variable `core.quotePath`
+	(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
+	global `--literal-pathspecs`.
+
+--pathspec-file-nul::
+	Only meaningful with `--pathspec-from-file`. Pathspec elements are
+	separated with NUL character and all other characters are taken
+	literally (including newlines and quotes).
+
+\--::
+	Do not interpret any more arguments as options.
+
+<pathspec>...::
+	Limits the paths affected by the operation.
++
+For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
 
 EXAMPLES
 --------
diff --git a/Documentation/git-restore.txt b/Documentation/git-restore.txt
index 1ab2e40..5bf60d4 100644
--- a/Documentation/git-restore.txt
+++ b/Documentation/git-restore.txt
@@ -8,8 +8,9 @@
 SYNOPSIS
 --------
 [verse]
-'git restore' [<options>] [--source=<tree>] [--staged] [--worktree] <pathspec>...
-'git restore' (-p|--patch) [<options>] [--source=<tree>] [--staged] [--worktree] [<pathspec>...]
+'git restore' [<options>] [--source=<tree>] [--staged] [--worktree] [--] <pathspec>...
+'git restore' [<options>] [--source=<tree>] [--staged] [--worktree] --pathspec-from-file=<file> [--pathspec-file-nul]
+'git restore' (-p|--patch) [<options>] [--source=<tree>] [--staged] [--worktree] [--] [<pathspec>...]
 
 DESCRIPTION
 -----------
@@ -113,6 +114,27 @@
 	appear in the `--source` tree are removed, to make them match
 	`<tree>` exactly. The default is no-overlay mode.
 
+--pathspec-from-file=<file>::
+	Pathspec is passed in `<file>` instead of commandline args. If
+	`<file>` is exactly `-` then standard input is used. Pathspec
+	elements are separated by LF or CR/LF. Pathspec elements can be
+	quoted as explained for the configuration variable `core.quotePath`
+	(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
+	global `--literal-pathspecs`.
+
+--pathspec-file-nul::
+	Only meaningful with `--pathspec-from-file`. Pathspec elements are
+	separated with NUL character and all other characters are taken
+	literally (including newlines and quotes).
+
+\--::
+	Do not interpret any more arguments as options.
+
+<pathspec>...::
+	Limits the paths affected by the operation.
++
+For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
+
 EXAMPLES
 --------
 
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 9985477..19b12b6 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -262,7 +262,8 @@
 	directory.
 
 --show-toplevel::
-	Show the absolute path of the top-level directory.
+	Show the absolute path of the top-level directory of the working
+	tree. If there is no working tree, report an error.
 
 --show-superproject-working-tree::
 	Show the absolute path of the root of the superproject's
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt
index bc80905..a72ea7f 100644
--- a/Documentation/git-shortlog.txt
+++ b/Documentation/git-shortlog.txt
@@ -76,6 +76,9 @@
 Paths may need to be prefixed with `--` to separate them from
 options or the revision range, when confusion arises.
 
+:git-shortlog: 1
+include::rev-list-options.txt[]
+
 MAPPING AUTHORS
 ---------------
 
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index 1f46380..22425cb 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -16,6 +16,7 @@
 'git submodule' [--quiet] deinit [-f|--force] (--all|[--] <path>...)
 'git submodule' [--quiet] update [<options>] [--] [<path>...]
 'git submodule' [--quiet] set-branch [<options>] [--] <path>
+'git submodule' [--quiet] set-url [--] <path> <newurl>
 'git submodule' [--quiet] summary [<options>] [--] [<path>...]
 'git submodule' [--quiet] foreach [--recursive] <command>
 'git submodule' [--quiet] sync [--recursive] [--] [<path>...]
@@ -80,6 +81,9 @@
 	does not match the SHA-1 found in the index of the containing
 	repository and `U` if the submodule has merge conflicts.
 +
+If `--cached` is specified, this command will instead print the SHA-1
+recorded in the superproject for each submodule.
++
 If `--recursive` is specified, this command will recurse into nested
 submodules, and show their status as well.
 +
@@ -133,7 +137,8 @@
 +
 --
 Update the registered submodules to match what the superproject
-expects by cloning missing submodules and updating the working tree of
+expects by cloning missing submodules, fetching missing commits
+in submodules and updating the working tree of
 the submodules. The "updating" can be done in several ways depending
 on command line options and the value of `submodule.<name>.update`
 configuration variable. The command line option takes precedence over
@@ -180,6 +185,11 @@
 	`--default` option removes the submodule.<name>.branch configuration
 	key, which causes the tracking branch to default to 'master'.
 
+set-url [--] <path> <newurl>::
+	Sets the URL of the specified submodule to <newurl>. Then, it will
+	automatically synchronize the submodule's new remote URL
+	configuration.
+
 summary [--cached|--files] [(-n|--summary-limit) <n>] [commit] [--] [<path>...]::
 	Show commit summary between the given commit (defaults to HEAD) and
 	working tree/index. For a submodule in question, a series of commits
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 53774f5..6624a14 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -677,7 +677,8 @@
 -s<strategy>::
 --strategy=<strategy>::
 -p::
---preserve-merges::
+--rebase-merges::
+--preserve-merges (DEPRECATED)::
 	These are only used with the 'dcommit' and 'rebase' commands.
 +
 Passed directly to 'git rebase' when using 'dcommit' if a
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 2e5599a..f6d9791 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -65,7 +65,7 @@
 --sign::
 	Make a GPG-signed tag, using the default e-mail address's key.
 	The default behavior of tag GPG-signing is controlled by `tag.gpgSign`
-	configuration variable if it exists, or disabled oder otherwise.
+	configuration variable if it exists, or disabled otherwise.
 	See linkgit:git-config[1].
 
 --no-sign::
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index 0839344..c7a6271 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -432,7 +432,7 @@
 linkgit:git-config[1]).
 
 To avoid deleting a shared index file that is still used, its
-modification time is updated to the current time everytime a new split
+modification time is updated to the current time every time a new split
 index based on the shared index file is either created or read from.
 
 UNTRACKED CACHE
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 9b82564..b1597ac 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -271,8 +271,8 @@
 the working tree.
 
 
-Synching repositories
-~~~~~~~~~~~~~~~~~~~~~
+Syncing repositories
+~~~~~~~~~~~~~~~~~~~~
 
 include::cmds-synchingrepositories.txt[]
 
@@ -544,6 +544,10 @@
 	a pager.  See also the `core.pager` option in
 	linkgit:git-config[1].
 
+`GIT_PROGRESS_DELAY`::
+	A number controlling how many seconds to delay before showing
+	optional progress indicators. Defaults to 2.
+
 `GIT_EDITOR`::
 	This environment variable overrides `$EDITOR` and `$VISUAL`.
 	It is used by several Git commands when, on interactive mode,
@@ -928,7 +932,7 @@
 Report bugs to the Git mailing list <git@vger.kernel.org> where the
 development and maintenance is primarily done.  You do not have to be
 subscribed to the list to send a message there.  See the list archive
-at https://public-inbox.org/git for previous bug reports and other
+at https://lore.kernel.org/git for previous bug reports and other
 discussions.
 
 Issues which are security relevant should be disclosed privately to
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index c5a528c..508fe71 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -293,10 +293,10 @@
 
 In these cases you can tell Git the encoding of a file in the working
 directory with the `working-tree-encoding` attribute. If a file with this
-attribute is added to Git, then Git reencodes the content from the
+attribute is added to Git, then Git re-encodes the content from the
 specified encoding to UTF-8. Finally, Git stores the UTF-8 encoded
 content in its internal data structure (called "the index"). On checkout
-the content is reencoded back to the specified encoding.
+the content is re-encoded back to the specified encoding.
 
 Please note that using the `working-tree-encoding` attribute may have a
 number of pitfalls:
@@ -498,7 +498,7 @@
 When Git encounters the first file that needs to be cleaned or smudged,
 it starts the filter and performs the handshake. In the handshake, the
 welcome message sent by Git is "git-filter-client", only version 2 is
-suppported, and the supported capabilities are "clean", "smudge", and
+supported, and the supported capabilities are "clean", "smudge", and
 "delay".
 
 Afterwards Git sends a list of "key=value" pairs terminated with
@@ -812,6 +812,8 @@
 
 - `dts` suitable for devicetree (DTS) files.
 
+- `elixir` suitable for source code in the Elixir language.
+
 - `fortran` suitable for source code in the Fortran language.
 
 - `fountain` suitable for Fountain documents.
diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt
index 4b32876..373cfa2 100644
--- a/Documentation/gitcli.txt
+++ b/Documentation/gitcli.txt
@@ -211,8 +211,8 @@
 entries, and with `--cached`, it modifies only the index
 entries.
 
-See also http://marc.info/?l=git&m=116563135620359 and
-http://marc.info/?l=git&m=119150393620273 for further
+See also https://lore.kernel.org/git/7v64clg5u9.fsf@assigned-by-dhcp.cox.net/ and
+https://lore.kernel.org/git/7vy7ej9g38.fsf@gitster.siamese.dyndns.org/ for further
 information.
 
 Some other commands that also work on files in the working tree and/or
diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt
index adc7596..ea759fd 100644
--- a/Documentation/gitcredentials.txt
+++ b/Documentation/gitcredentials.txt
@@ -186,8 +186,7 @@
 --------------
 
 You can write your own custom helpers to interface with any system in
-which you keep credentials. See the documentation for Git's
-link:technical/api-credentials.html[credentials API] for details.
+which you keep credentials. See credential.h for details.
 
 GIT
 ---
diff --git a/Documentation/gitk.txt b/Documentation/gitk.txt
index 1eabb0a..c653ebb 100644
--- a/Documentation/gitk.txt
+++ b/Documentation/gitk.txt
@@ -105,8 +105,12 @@
 	(or the function name regex <funcname>) within the <file>.  You may
 	not give any pathspec limiters.  This is currently limited to
 	a walk starting from a single revision, i.e., you may only
-	give zero or one positive revision arguments.
-	You can specify this option more than once.
+	give zero or one positive revision arguments, and
+	<start> and <end> (or <funcname>) must exist in the starting revision.
+	You can specify this option more than once. Implies `--patch`.
+	Patch output can be suppressed using `--no-patch`, but other diff formats
+	(namely `--raw`, `--numstat`, `--shortstat`, `--dirstat`, `--summary`,
+	`--name-only`, `--name-status`, `--check`) are not currently implemented.
 +
 *Note:* gitk (unlike linkgit:git-log[1]) currently only understands
 this option if you specify it "glued together" with its argument.  Do
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt
index f2a65ba..67275fd 100644
--- a/Documentation/gitmodules.txt
+++ b/Documentation/gitmodules.txt
@@ -44,9 +44,8 @@
 	submodule init` to initialize the configuration variable of
 	the same name. Allowed values here are 'checkout', 'rebase',
 	'merge' or 'none'. See description of 'update' command in
-	linkgit:git-submodule[1] for their meaning. Note that the
-	'!command' form is intentionally ignored here for security
-	reasons.
+	linkgit:git-submodule[1] for their meaning. For security
+	reasons, the '!command' form is not accepted here.
 
 submodule.<name>.branch::
 	A remote branch name for tracking updates in the upstream submodule.
@@ -81,7 +80,7 @@
 	    Committed differences and modifications to tracked files will show
 	    up.
 
-	none;; No modifiations to submodules are ignored, all of committed
+	none;; No modifications to submodules are ignored, all of committed
 	    differences, and modifications to tracked and untracked files are
 	    shown. This is the default option.
 
@@ -121,7 +120,7 @@
 
 SEE ALSO
 --------
-linkgit:git-submodule[1] linkgit:git-config[1]
+linkgit:git-submodule[1], linkgit:gitsubmodules[7], linkgit:git-config[1]
 
 GIT
 ---
diff --git a/Documentation/gitsubmodules.txt b/Documentation/gitsubmodules.txt
index 0a89020..c476f89 100644
--- a/Documentation/gitsubmodules.txt
+++ b/Documentation/gitsubmodules.txt
@@ -3,7 +3,7 @@
 
 NAME
 ----
-gitsubmodules - mounting one repository inside another
+gitsubmodules - Mounting one repository inside another
 
 SYNOPSIS
 --------
diff --git a/Documentation/howto/separating-topic-branches.txt b/Documentation/howto/separating-topic-branches.txt
index bd10274..81be0d6 100644
--- a/Documentation/howto/separating-topic-branches.txt
+++ b/Documentation/howto/separating-topic-branches.txt
@@ -81,7 +81,7 @@
               o---o---o---o---o---o
 
 The last diff better not to show anything other than cleanups
-for crufts.  Then I can finally clean things up:
+for cruft.  Then I can finally clean things up:
 
         $ git branch -D topic
         $ git reset --hard HEAD^ ;# nuke pretend merge
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 59b8ff1..40dc4f5 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -34,7 +34,7 @@
 
 --cleanup=<mode>::
 	This option determines how the merge message will be cleaned up before
-	commiting. See linkgit:git-commit[1] for more details. In addition, if
+	committing. See linkgit:git-commit[1] for more details. In addition, if
 	the '<mode>' is given a value of `scissors`, scissors will be appended
 	to `MERGE_MSG` before being passed on to the commit machinery in the
 	case of a merge conflict.
diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt
index aa66cbe..2912de7 100644
--- a/Documentation/merge-strategies.txt
+++ b/Documentation/merge-strategies.txt
@@ -32,7 +32,7 @@
 ours;;
 	This option forces conflicting hunks to be auto-resolved cleanly by
 	favoring 'our' version.  Changes from the other tree that do not
-	conflict with our side are reflected to the merge result.
+	conflict with our side are reflected in the merge result.
 	For a binary file, the entire contents are taken from our side.
 +
 This should not be confused with the 'ours' merge strategy, which does not
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 31c6e8d..1a7212c 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -4,7 +4,7 @@
 If the commit is a merge, and if the pretty-format
 is not 'oneline', 'email' or 'raw', an additional line is
 inserted before the 'Author:' line.  This line begins with
-"Merge: " and the sha1s of ancestral commits are printed,
+"Merge: " and the hashes of ancestral commits are printed,
 separated by spaces.  Note that the listed commits may not
 necessarily be the list of the *direct* parent commits if you
 have limited your view of history: for example, if you are
@@ -20,20 +20,20 @@
 
 * 'oneline'
 
-	  <sha1> <title line>
+	  <hash> <title line>
 +
 This is designed to be as compact as possible.
 
 * 'short'
 
-	  commit <sha1>
+	  commit <hash>
 	  Author: <author>
 
 	      <title line>
 
 * 'medium'
 
-	  commit <sha1>
+	  commit <hash>
 	  Author: <author>
 	  Date:   <author date>
 
@@ -43,7 +43,7 @@
 
 * 'full'
 
-	  commit <sha1>
+	  commit <hash>
 	  Author: <author>
 	  Commit: <committer>
 
@@ -53,7 +53,7 @@
 
 * 'fuller'
 
-	  commit <sha1>
+	  commit <hash>
 	  Author:     <author>
 	  AuthorDate: <author date>
 	  Commit:     <committer>
@@ -63,9 +63,20 @@
 
 	       <full commit message>
 
+* 'reference'
+
+	  <abbrev hash> (<title line>, <short author date>)
++
+This format is used to refer to another commit in a commit message and
+is the same as `--pretty='format:%C(auto)%h (%s, %ad)'`.  By default,
+the date is formatted with `--date=short` unless another `--date` option
+is explicitly specified.  As with any `format:` with format
+placeholders, its output is not affected by other options like
+`--decorate` and `--walk-reflogs`.
+
 * 'email'
 
-	  From <sha1> <date>
+	  From <hash> <date>
 	  From: <author>
 	  Date: <author date>
 	  Subject: [PATCH] <title line>
@@ -75,7 +86,7 @@
 * 'raw'
 +
 The 'raw' format shows the entire commit exactly as
-stored in the commit object.  Notably, the SHA-1s are
+stored in the commit object.  Notably, the hashes are
 displayed in full, regardless of whether --abbrev or
 --no-abbrev are used, and 'parents' information show the
 true parent commits, without taking grafts or history
@@ -172,6 +183,7 @@
 '%at':: author date, UNIX timestamp
 '%ai':: author date, ISO 8601-like format
 '%aI':: author date, strict ISO 8601 format
+'%as':: author date, short format (`YYYY-MM-DD`)
 '%cn':: committer name
 '%cN':: committer name (respecting .mailmap, see
 	linkgit:git-shortlog[1] or linkgit:git-blame[1])
@@ -187,6 +199,7 @@
 '%ct':: committer date, UNIX timestamp
 '%ci':: committer date, ISO 8601-like format
 '%cI':: committer date, strict ISO 8601 format
+'%cs':: committer date, short format (`YYYY-MM-DD`)
 '%d':: ref names, like the --decorate option of linkgit:git-log[1]
 '%D':: ref names without the " (", ")" wrapping.
 '%S':: ref name given on the command line by which the commit was reached
diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt
index e44fc8f..7a6da6d 100644
--- a/Documentation/pretty-options.txt
+++ b/Documentation/pretty-options.txt
@@ -3,7 +3,7 @@
 
 	Pretty-print the contents of the commit logs in a given format,
 	where '<format>' can be one of 'oneline', 'short', 'medium',
-	'full', 'fuller', 'email', 'raw', 'format:<string>'
+	'full', 'fuller', 'reference', 'email', 'raw', 'format:<string>'
 	and 'tformat:<string>'.  When '<format>' is none of the above,
 	and has '%placeholder' in it, it acts as if
 	'--pretty=tformat:<format>' were given.
@@ -57,7 +57,7 @@
 and 'fuller').
 
 ifndef::git-rev-list[]
---notes[=<treeish>]::
+--notes[=<ref>]::
 	Show the notes (see linkgit:git-notes[1]) that annotate the
 	commit, when showing the commit log message.  This is the default
 	for `git log`, `git show` and `git whatchanged` commands when
@@ -68,8 +68,8 @@
 `core.notesRef` and `notes.displayRef` variables (or corresponding
 environment overrides). See linkgit:git-config[1] for more details.
 +
-With an optional '<treeish>' argument, use the treeish to find the notes
-to display.  The treeish can specify the full refname when it begins
+With an optional '<ref>' argument, use the ref to find the notes
+to display.  The ref can specify the full refname when it begins
 with `refs/notes/`; when it begins with `notes/`, `refs/` and otherwise
 `refs/notes/` is prefixed to form a full name of the ref.
 +
@@ -85,7 +85,7 @@
 	"--notes --notes=foo --no-notes --notes=bar" will only show notes
 	from "refs/notes/bar".
 
---show-notes[=<treeish>]::
+--show-notes[=<ref>]::
 --[no-]standard-notes::
 	These options are deprecated. Use the above --notes/--no-notes
 	options instead.
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 90ff9e2..bfd02ad 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -58,7 +58,7 @@
 	`--all-match`).
 ifndef::git-rev-list[]
 +
-When `--show-notes` is in effect, the message from the notes is
+When `--notes` is in effect, the message from the notes is
 matched as if it were part of the log message.
 endif::git-rev-list[]
 
@@ -269,7 +269,7 @@
 	exclude (that is, '{caret}commit', 'commit1..commit2',
 	and 'commit1\...commit2' notations cannot be used).
 +
-With `--pretty` format other than `oneline` (for obvious reasons),
+With `--pretty` format other than `oneline` and `reference` (for obvious reasons),
 this causes the output to have two extra lines of information
 taken from the reflog.  The reflog designator in the output may be shown
 as `ref@{Nth}` (where `Nth` is the reverse-chronological index in the
@@ -293,6 +293,8 @@
 prefixed with this information on the same line.
 This option cannot be combined with `--reverse`.
 See also linkgit:git-reflog[1].
++
+Under `--pretty=reference`, this information will not be shown at all.
 
 --merge::
 	After a failed merge, show refs that touch files having a
@@ -579,6 +581,7 @@
 contents of the paths given on the command line.  All other
 commits are marked as TREESAME (subject to be simplified away).
 
+ifndef::git-shortlog[]
 ifdef::git-rev-list[]
 Bisection Helpers
 ~~~~~~~~~~~~~~~~~
@@ -634,8 +637,9 @@
 after all the sorted commit objects, there will be the same text as if
 `--bisect-vars` had been used alone.
 endif::git-rev-list[]
+endif::git-shortlog[]
 
-
+ifndef::git-shortlog[]
 Commit Ordering
 ~~~~~~~~~~~~~~~
 
@@ -677,7 +681,9 @@
 	Output the commits chosen to be shown (see Commit Limiting
 	section above) in reverse order. Cannot be combined with
 	`--walk-reflogs`.
+endif::git-shortlog[]
 
+ifndef::git-shortlog[]
 Object Traversal
 ~~~~~~~~~~~~~~~~
 
@@ -817,7 +823,9 @@
 
 --do-walk::
 	Overrides a previous `--no-walk`.
+endif::git-shortlog[]
 
+ifndef::git-shortlog[]
 Commit Formatting
 ~~~~~~~~~~~~~~~~~
 
@@ -973,7 +981,9 @@
 	counts and print the count for equivalent commits separated
 	by a tab.
 endif::git-rev-list[]
+endif::git-shortlog[]
 
+ifndef::git-shortlog[]
 ifndef::git-rev-list[]
 Diff Formatting
 ~~~~~~~~~~~~~~~
@@ -1016,3 +1026,4 @@
 -t::
 	Show the tree objects in the diff output. This implies `-r`.
 endif::git-rev-list[]
+endif::git-shortlog[]
diff --git a/Documentation/technical/api-allocation-growing.txt b/Documentation/technical/api-allocation-growing.txt
deleted file mode 100644
index 5a59b54..0000000
--- a/Documentation/technical/api-allocation-growing.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-allocation growing API
-======================
-
-Dynamically growing an array using realloc() is error prone and boring.
-
-Define your array with:
-
-* a pointer (`item`) that points at the array, initialized to `NULL`
-  (although please name the variable based on its contents, not on its
-  type);
-
-* an integer variable (`alloc`) that keeps track of how big the current
-  allocation is, initialized to `0`;
-
-* another integer variable (`nr`) to keep track of how many elements the
-  array currently has, initialized to `0`.
-
-Then before adding `n`th element to the item, call `ALLOC_GROW(item, n,
-alloc)`.  This ensures that the array can hold at least `n` elements by
-calling `realloc(3)` and adjusting `alloc` variable.
-
-------------
-sometype *item;
-size_t nr;
-size_t alloc
-
-for (i = 0; i < nr; i++)
-	if (we like item[i] already)
-		return;
-
-/* we did not like any existing one, so add one */
-ALLOC_GROW(item, nr + 1, alloc);
-item[nr++] = value you like;
-------------
-
-You are responsible for updating the `nr` variable.
-
-If you need to specify the number of elements to allocate explicitly
-then use the macro `REALLOC_ARRAY(item, alloc)` instead of `ALLOC_GROW`.
diff --git a/Documentation/technical/api-argv-array.txt b/Documentation/technical/api-argv-array.txt
deleted file mode 100644
index 870c8ed..0000000
--- a/Documentation/technical/api-argv-array.txt
+++ /dev/null
@@ -1,65 +0,0 @@
-argv-array API
-==============
-
-The argv-array API allows one to dynamically build and store
-NULL-terminated lists.  An argv-array maintains the invariant that the
-`argv` member always points to a non-NULL array, and that the array is
-always NULL-terminated at the element pointed to by `argv[argc]`. This
-makes the result suitable for passing to functions expecting to receive
-argv from main(), or the link:api-run-command.html[run-command API].
-
-The string-list API (documented in string-list.h) is similar, but cannot be
-used for these purposes; instead of storing a straight string pointer,
-it contains an item structure with a `util` field that is not compatible
-with the traditional argv interface.
-
-Each `argv_array` manages its own memory. Any strings pushed into the
-array are duplicated, and all memory is freed by argv_array_clear().
-
-Data Structures
----------------
-
-`struct argv_array`::
-
-	A single array. This should be initialized by assignment from
-	`ARGV_ARRAY_INIT`, or by calling `argv_array_init`. The `argv`
-	member contains the actual array; the `argc` member contains the
-	number of elements in the array, not including the terminating
-	NULL.
-
-Functions
----------
-
-`argv_array_init`::
-	Initialize an array. This is no different than assigning from
-	`ARGV_ARRAY_INIT`.
-
-`argv_array_push`::
-	Push a copy of a string onto the end of the array.
-
-`argv_array_pushl`::
-	Push a list of strings onto the end of the array. The arguments
-	should be a list of `const char *` strings, terminated by a NULL
-	argument.
-
-`argv_array_pushf`::
-	Format a string and push it onto the end of the array. This is a
-	convenience wrapper combining `strbuf_addf` and `argv_array_push`.
-
-`argv_array_pushv`::
-	Push a null-terminated array of strings onto the end of the array.
-
-`argv_array_pop`::
-	Remove the final element from the array. If there are no
-	elements in the array, do nothing.
-
-`argv_array_clear`::
-	Free all memory associated with the array and return it to the
-	initial, empty state.
-
-`argv_array_detach`::
-	Disconnect the `argv` member from the `argv_array` struct and
-	return it. The caller is responsible for freeing the memory used
-	by the array, and by the strings it references. After detaching,
-	the `argv_array` is in a reinitialized state and can be pushed
-	into again.
diff --git a/Documentation/technical/api-config.txt b/Documentation/technical/api-config.txt
deleted file mode 100644
index 7d20716..0000000
--- a/Documentation/technical/api-config.txt
+++ /dev/null
@@ -1,319 +0,0 @@
-config API
-==========
-
-The config API gives callers a way to access Git configuration files
-(and files which have the same syntax). See linkgit:git-config[1] for a
-discussion of the config file syntax.
-
-General Usage
--------------
-
-Config files are parsed linearly, and each variable found is passed to a
-caller-provided callback function. The callback function is responsible
-for any actions to be taken on the config option, and is free to ignore
-some options. It is not uncommon for the configuration to be parsed
-several times during the run of a Git program, with different callbacks
-picking out different variables useful to themselves.
-
-A config callback function takes three parameters:
-
-- the name of the parsed variable. This is in canonical "flat" form: the
-  section, subsection, and variable segments will be separated by dots,
-  and the section and variable segments will be all lowercase. E.g.,
-  `core.ignorecase`, `diff.SomeType.textconv`.
-
-- the value of the found variable, as a string. If the variable had no
-  value specified, the value will be NULL (typically this means it
-  should be interpreted as boolean true).
-
-- a void pointer passed in by the caller of the config API; this can
-  contain callback-specific data
-
-A config callback should return 0 for success, or -1 if the variable
-could not be parsed properly.
-
-Basic Config Querying
----------------------
-
-Most programs will simply want to look up variables in all config files
-that Git knows about, using the normal precedence rules. To do this,
-call `git_config` with a callback function and void data pointer.
-
-`git_config` will read all config sources in order of increasing
-priority. Thus a callback should typically overwrite previously-seen
-entries with new ones (e.g., if both the user-wide `~/.gitconfig` and
-repo-specific `.git/config` contain `color.ui`, the config machinery
-will first feed the user-wide one to the callback, and then the
-repo-specific one; by overwriting, the higher-priority repo-specific
-value is left at the end).
-
-The `config_with_options` function lets the caller examine config
-while adjusting some of the default behavior of `git_config`. It should
-almost never be used by "regular" Git code that is looking up
-configuration variables. It is intended for advanced callers like
-`git-config`, which are intentionally tweaking the normal config-lookup
-process. It takes two extra parameters:
-
-`config_source`::
-If this parameter is non-NULL, it specifies the source to parse for
-configuration, rather than looking in the usual files. See `struct
-git_config_source` in `config.h` for details. Regular `git_config` defaults
-to `NULL`.
-
-`opts`::
-Specify options to adjust the behavior of parsing config files. See `struct
-config_options` in `config.h` for details. As an example: regular `git_config`
-sets `opts.respect_includes` to `1` by default.
-
-Reading Specific Files
-----------------------
-
-To read a specific file in git-config format, use
-`git_config_from_file`. This takes the same callback and data parameters
-as `git_config`.
-
-Querying For Specific Variables
--------------------------------
-
-For programs wanting to query for specific variables in a non-callback
-manner, the config API provides two functions `git_config_get_value`
-and `git_config_get_value_multi`. They both read values from an internal
-cache generated previously from reading the config files.
-
-`int git_config_get_value(const char *key, const char **value)`::
-
-	Finds the highest-priority value for the configuration variable `key`,
-	stores the pointer to it in `value` and returns 0. When the
-	configuration variable `key` is not found, returns 1 without touching
-	`value`. The caller should not free or modify `value`, as it is owned
-	by the cache.
-
-`const struct string_list *git_config_get_value_multi(const char *key)`::
-
-	Finds and returns the value list, sorted in order of increasing priority
-	for the configuration variable `key`. When the configuration variable
-	`key` is not found, returns NULL. The caller should not free or modify
-	the returned pointer, as it is owned by the cache.
-
-`void git_config_clear(void)`::
-
-	Resets and invalidates the config cache.
-
-The config API also provides type specific API functions which do conversion
-as well as retrieval for the queried variable, including:
-
-`int git_config_get_int(const char *key, int *dest)`::
-
-	Finds and parses the value to an integer for the configuration variable
-	`key`. Dies on error; otherwise, stores the value of the parsed integer in
-	`dest` and returns 0. When the configuration variable `key` is not found,
-	returns 1 without touching `dest`.
-
-`int git_config_get_ulong(const char *key, unsigned long *dest)`::
-
-	Similar to `git_config_get_int` but for unsigned longs.
-
-`int git_config_get_bool(const char *key, int *dest)`::
-
-	Finds and parses the value into a boolean value, for the configuration
-	variable `key` respecting keywords like "true" and "false". Integer
-	values are converted into true/false values (when they are non-zero or
-	zero, respectively). Other values cause a die(). If parsing is successful,
-	stores the value of the parsed result in `dest` and returns 0. When the
-	configuration variable `key` is not found, returns 1 without touching
-	`dest`.
-
-`int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)`::
-
-	Similar to `git_config_get_bool`, except that integers are copied as-is,
-	and `is_bool` flag is unset.
-
-`int git_config_get_maybe_bool(const char *key, int *dest)`::
-
-	Similar to `git_config_get_bool`, except that it returns -1 on error
-	rather than dying.
-
-`int git_config_get_string_const(const char *key, const char **dest)`::
-
-	Allocates and copies the retrieved string into the `dest` parameter for
-	the configuration variable `key`; if NULL string is given, prints an
-	error message and returns -1. When the configuration variable `key` is
-	not found, returns 1 without touching `dest`.
-
-`int git_config_get_string(const char *key, char **dest)`::
-
-	Similar to `git_config_get_string_const`, except that retrieved value
-	copied into the `dest` parameter is a mutable string.
-
-`int git_config_get_pathname(const char *key, const char **dest)`::
-
-	Similar to `git_config_get_string`, but expands `~` or `~user` into
-	the user's home directory when found at the beginning of the path.
-
-`git_die_config(const char *key, const char *err, ...)`::
-
-	First prints the error message specified by the caller in `err` and then
-	dies printing the line number and the file name of the highest priority
-	value for the configuration variable `key`.
-
-`void git_die_config_linenr(const char *key, const char *filename, int linenr)`::
-
-	Helper function which formats the die error message according to the
-	parameters entered. Used by `git_die_config()`. It can be used by callers
-	handling `git_config_get_value_multi()` to print the correct error message
-	for the desired value.
-
-See test-config.c for usage examples.
-
-Value Parsing Helpers
----------------------
-
-To aid in parsing string values, the config API provides callbacks with
-a number of helper functions, including:
-
-`git_config_int`::
-Parse the string to an integer, including unit factors. Dies on error;
-otherwise, returns the parsed result.
-
-`git_config_ulong`::
-Identical to `git_config_int`, but for unsigned longs.
-
-`git_config_bool`::
-Parse a string into a boolean value, respecting keywords like "true" and
-"false". Integer values are converted into true/false values (when they
-are non-zero or zero, respectively). Other values cause a die(). If
-parsing is successful, the return value is the result.
-
-`git_config_bool_or_int`::
-Same as `git_config_bool`, except that integers are returned as-is, and
-an `is_bool` flag is unset.
-
-`git_parse_maybe_bool`::
-Same as `git_config_bool`, except that it returns -1 on error rather
-than dying.
-
-`git_config_string`::
-Allocates and copies the value string into the `dest` parameter; if no
-string is given, prints an error message and returns -1.
-
-`git_config_pathname`::
-Similar to `git_config_string`, but expands `~` or `~user` into the
-user's home directory when found at the beginning of the path.
-
-Include Directives
-------------------
-
-By default, the config parser does not respect include directives.
-However, a caller can use the special `git_config_include` wrapper
-callback to support them. To do so, you simply wrap your "real" callback
-function and data pointer in a `struct config_include_data`, and pass
-the wrapper to the regular config-reading functions. For example:
-
--------------------------------------------
-int read_file_with_include(const char *file, config_fn_t fn, void *data)
-{
-	struct config_include_data inc = CONFIG_INCLUDE_INIT;
-	inc.fn = fn;
-	inc.data = data;
-	return git_config_from_file(git_config_include, file, &inc);
-}
--------------------------------------------
-
-`git_config` respects includes automatically. The lower-level
-`git_config_from_file` does not.
-
-Custom Configsets
------------------
-
-A `config_set` can be used to construct an in-memory cache for
-config-like files that the caller specifies (i.e., files like `.gitmodules`,
-`~/.gitconfig` etc.). For example,
-
-----------------------------------------
-struct config_set gm_config;
-git_configset_init(&gm_config);
-int b;
-/* we add config files to the config_set */
-git_configset_add_file(&gm_config, ".gitmodules");
-git_configset_add_file(&gm_config, ".gitmodules_alt");
-
-if (!git_configset_get_bool(gm_config, "submodule.frotz.ignore", &b)) {
-	/* hack hack hack */
-}
-
-/* when we are done with the configset */
-git_configset_clear(&gm_config);
-----------------------------------------
-
-Configset API provides functions for the above mentioned work flow, including:
-
-`void git_configset_init(struct config_set *cs)`::
-
-	Initializes the config_set `cs`.
-
-`int git_configset_add_file(struct config_set *cs, const char *filename)`::
-
-	Parses the file and adds the variable-value pairs to the `config_set`,
-	dies if there is an error in parsing the file. Returns 0 on success, or
-	-1 if the file does not exist or is inaccessible. The user has to decide
-	if he wants to free the incomplete configset or continue using it when
-	the function returns -1.
-
-`int git_configset_get_value(struct config_set *cs, const char *key, const char **value)`::
-
-	Finds the highest-priority value for the configuration variable `key`
-	and config set `cs`, stores the pointer to it in `value` and returns 0.
-	When the configuration variable `key` is not found, returns 1 without
-	touching `value`. The caller should not free or modify `value`, as it
-	is owned by the cache.
-
-`const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key)`::
-
-	Finds and returns the value list, sorted in order of increasing priority
-	for the configuration variable `key` and config set `cs`. When the
-	configuration variable `key` is not found, returns NULL. The caller
-	should not free or modify the returned pointer, as it is owned by the cache.
-
-`void git_configset_clear(struct config_set *cs)`::
-
-	Clears `config_set` structure, removes all saved variable-value pairs.
-
-In addition to above functions, the `config_set` API provides type specific
-functions in the vein of `git_config_get_int` and family but with an extra
-parameter, pointer to struct `config_set`.
-They all behave similarly to the `git_config_get*()` family described in
-"Querying For Specific Variables" above.
-
-Writing Config Files
---------------------
-
-Git gives multiple entry points in the Config API to write config values to
-files namely `git_config_set_in_file` and `git_config_set`, which write to
-a specific config file or to `.git/config` respectively. They both take a
-key/value pair as parameter.
-In the end they both call `git_config_set_multivar_in_file` which takes four
-parameters:
-
-- the name of the file, as a string, to which key/value pairs will be written.
-
-- the name of key, as a string. This is in canonical "flat" form: the section,
-  subsection, and variable segments will be separated by dots, and the section
-  and variable segments will be all lowercase.
-  E.g., `core.ignorecase`, `diff.SomeType.textconv`.
-
-- the value of the variable, as a string. If value is equal to NULL, it will
-  remove the matching key from the config file.
-
-- the value regex, as a string. It will disregard key/value pairs where value
-  does not match.
-
-- a multi_replace value, as an int. If value is equal to zero, nothing or only
-  one matching key/value is replaced, else all matching key/values (regardless
-  how many) are removed, before the new pair is written.
-
-It returns 0 on success.
-
-Also, there are functions `git_config_rename_section` and
-`git_config_rename_section_in_file` with parameters `old_name` and `new_name`
-for renaming or removing sections in the config files. If NULL is passed
-through `new_name` parameter, the section will be removed from the config file.
diff --git a/Documentation/technical/api-credentials.txt b/Documentation/technical/api-credentials.txt
deleted file mode 100644
index 75368f2..0000000
--- a/Documentation/technical/api-credentials.txt
+++ /dev/null
@@ -1,271 +0,0 @@
-credentials API
-===============
-
-The credentials API provides an abstracted way of gathering username and
-password credentials from the user (even though credentials in the wider
-world can take many forms, in this document the word "credential" always
-refers to a username and password pair).
-
-This document describes two interfaces: the C API that the credential
-subsystem provides to the rest of Git, and the protocol that Git uses to
-communicate with system-specific "credential helpers". If you are
-writing Git code that wants to look up or prompt for credentials, see
-the section "C API" below. If you want to write your own helper, see
-the section on "Credential Helpers" below.
-
-Typical setup
--------------
-
-------------
-+-----------------------+
-| Git code (C)          |--- to server requiring --->
-|                       |        authentication
-|.......................|
-| C credential API      |--- prompt ---> User
-+-----------------------+
-	^      |
-	| pipe |
-	|      v
-+-----------------------+
-| Git credential helper |
-+-----------------------+
-------------
-
-The Git code (typically a remote-helper) will call the C API to obtain
-credential data like a login/password pair (credential_fill). The
-API will itself call a remote helper (e.g. "git credential-cache" or
-"git credential-store") that may retrieve credential data from a
-store. If the credential helper cannot find the information, the C API
-will prompt the user. Then, the caller of the API takes care of
-contacting the server, and does the actual authentication.
-
-C API
------
-
-The credential C API is meant to be called by Git code which needs to
-acquire or store a credential. It is centered around an object
-representing a single credential and provides three basic operations:
-fill (acquire credentials by calling helpers and/or prompting the user),
-approve (mark a credential as successfully used so that it can be stored
-for later use), and reject (mark a credential as unsuccessful so that it
-can be erased from any persistent storage).
-
-Data Structures
-~~~~~~~~~~~~~~~
-
-`struct credential`::
-
-	This struct represents a single username/password combination
-	along with any associated context. All string fields should be
-	heap-allocated (or NULL if they are not known or not applicable).
-	The meaning of the individual context fields is the same as
-	their counterparts in the helper protocol; see the section below
-	for a description of each field.
-+
-The `helpers` member of the struct is a `string_list` of helpers.  Each
-string specifies an external helper which will be run, in order, to
-either acquire or store credentials. See the section on credential
-helpers below. This list is filled-in by the API functions
-according to the corresponding configuration variables before
-consulting helpers, so there usually is no need for a caller to
-modify the helpers field at all.
-+
-This struct should always be initialized with `CREDENTIAL_INIT` or
-`credential_init`.
-
-
-Functions
-~~~~~~~~~
-
-`credential_init`::
-
-	Initialize a credential structure, setting all fields to empty.
-
-`credential_clear`::
-
-	Free any resources associated with the credential structure,
-	returning it to a pristine initialized state.
-
-`credential_fill`::
-
-	Instruct the credential subsystem to fill the username and
-	password fields of the passed credential struct by first
-	consulting helpers, then asking the user. After this function
-	returns, the username and password fields of the credential are
-	guaranteed to be non-NULL. If an error occurs, the function will
-	die().
-
-`credential_reject`::
-
-	Inform the credential subsystem that the provided credentials
-	have been rejected. This will cause the credential subsystem to
-	notify any helpers of the rejection (which allows them, for
-	example, to purge the invalid credentials from storage).  It
-	will also free() the username and password fields of the
-	credential and set them to NULL (readying the credential for
-	another call to `credential_fill`). Any errors from helpers are
-	ignored.
-
-`credential_approve`::
-
-	Inform the credential subsystem that the provided credentials
-	were successfully used for authentication.  This will cause the
-	credential subsystem to notify any helpers of the approval, so
-	that they may store the result to be used again.  Any errors
-	from helpers are ignored.
-
-`credential_from_url`::
-
-	Parse a URL into broken-down credential fields.
-
-Example
-~~~~~~~
-
-The example below shows how the functions of the credential API could be
-used to login to a fictitious "foo" service on a remote host:
-
------------------------------------------------------------------------
-int foo_login(struct foo_connection *f)
-{
-	int status;
-	/*
-	 * Create a credential with some context; we don't yet know the
-	 * username or password.
-	 */
-
-	struct credential c = CREDENTIAL_INIT;
-	c.protocol = xstrdup("foo");
-	c.host = xstrdup(f->hostname);
-
-	/*
-	 * Fill in the username and password fields by contacting
-	 * helpers and/or asking the user. The function will die if it
-	 * fails.
-	 */
-	credential_fill(&c);
-
-	/*
-	 * Otherwise, we have a username and password. Try to use it.
-	 */
-	status = send_foo_login(f, c.username, c.password);
-	switch (status) {
-	case FOO_OK:
-		/* It worked. Store the credential for later use. */
-		credential_accept(&c);
-		break;
-	case FOO_BAD_LOGIN:
-		/* Erase the credential from storage so we don't try it
-		 * again. */
-		credential_reject(&c);
-		break;
-	default:
-		/*
-		 * Some other error occurred. We don't know if the
-		 * credential is good or bad, so report nothing to the
-		 * credential subsystem.
-		 */
-	}
-
-	/* Free any associated resources. */
-	credential_clear(&c);
-
-	return status;
-}
------------------------------------------------------------------------
-
-
-Credential Helpers
-------------------
-
-Credential helpers are programs executed by Git to fetch or save
-credentials from and to long-term storage (where "long-term" is simply
-longer than a single Git process; e.g., credentials may be stored
-in-memory for a few minutes, or indefinitely on disk).
-
-Each helper is specified by a single string in the configuration
-variable `credential.helper` (and others, see linkgit:git-config[1]).
-The string is transformed by Git into a command to be executed using
-these rules:
-
-  1. If the helper string begins with "!", it is considered a shell
-     snippet, and everything after the "!" becomes the command.
-
-  2. Otherwise, if the helper string begins with an absolute path, the
-     verbatim helper string becomes the command.
-
-  3. Otherwise, the string "git credential-" is prepended to the helper
-     string, and the result becomes the command.
-
-The resulting command then has an "operation" argument appended to it
-(see below for details), and the result is executed by the shell.
-
-Here are some example specifications:
-
-----------------------------------------------------
-# run "git credential-foo"
-foo
-
-# same as above, but pass an argument to the helper
-foo --bar=baz
-
-# the arguments are parsed by the shell, so use shell
-# quoting if necessary
-foo --bar="whitespace arg"
-
-# you can also use an absolute path, which will not use the git wrapper
-/path/to/my/helper --with-arguments
-
-# or you can specify your own shell snippet
-!f() { echo "password=`cat $HOME/.secret`"; }; f
-----------------------------------------------------
-
-Generally speaking, rule (3) above is the simplest for users to specify.
-Authors of credential helpers should make an effort to assist their
-users by naming their program "git-credential-$NAME", and putting it in
-the $PATH or $GIT_EXEC_PATH during installation, which will allow a user
-to enable it with `git config credential.helper $NAME`.
-
-When a helper is executed, it will have one "operation" argument
-appended to its command line, which is one of:
-
-`get`::
-
-	Return a matching credential, if any exists.
-
-`store`::
-
-	Store the credential, if applicable to the helper.
-
-`erase`::
-
-	Remove a matching credential, if any, from the helper's storage.
-
-The details of the credential will be provided on the helper's stdin
-stream. The exact format is the same as the input/output format of the
-`git credential` plumbing command (see the section `INPUT/OUTPUT
-FORMAT` in linkgit:git-credential[1] for a detailed specification).
-
-For a `get` operation, the helper should produce a list of attributes
-on stdout in the same format. A helper is free to produce a subset, or
-even no values at all if it has nothing useful to provide. Any provided
-attributes will overwrite those already known about by Git.  If a helper
-outputs a `quit` attribute with a value of `true` or `1`, no further
-helpers will be consulted, nor will the user be prompted (if no
-credential has been provided, the operation will then fail).
-
-For a `store` or `erase` operation, the helper's output is ignored.
-If it fails to perform the requested operation, it may complain to
-stderr to inform the user. If it does not support the requested
-operation (e.g., a read-only store), it should silently ignore the
-request.
-
-If a helper receives any other operation, it should silently ignore the
-request. This leaves room for future operations to be added (older
-helpers will just ignore the new requests).
-
-See also
---------
-
-linkgit:gitcredentials[7]
-
-linkgit:git-config[1] (See configuration variables `credential.*`)
diff --git a/Documentation/technical/api-diff.txt b/Documentation/technical/api-diff.txt
deleted file mode 100644
index 30fc0e9..0000000
--- a/Documentation/technical/api-diff.txt
+++ /dev/null
@@ -1,174 +0,0 @@
-diff API
-========
-
-The diff API is for programs that compare two sets of files (e.g. two
-trees, one tree and the index) and present the found difference in
-various ways.  The calling program is responsible for feeding the API
-pairs of files, one from the "old" set and the corresponding one from
-"new" set, that are different.  The library called through this API is
-called diffcore, and is responsible for two things.
-
-* finding total rewrites (`-B`), renames (`-M`) and copies (`-C`), and
-  changes that touch a string (`-S`), as specified by the caller.
-
-* outputting the differences in various formats, as specified by the
-  caller.
-
-Calling sequence
-----------------
-
-* Prepare `struct diff_options` to record the set of diff options, and
-  then call `repo_diff_setup()` to initialize this structure.  This
-  sets up the vanilla default.
-
-* Fill in the options structure to specify desired output format, rename
-  detection, etc.  `diff_opt_parse()` can be used to parse options given
-  from the command line in a way consistent with existing git-diff
-  family of programs.
-
-* Call `diff_setup_done()`; this inspects the options set up so far for
-  internal consistency and make necessary tweaking to it (e.g. if
-  textual patch output was asked, recursive behaviour is turned on);
-  the callback set_default in diff_options can be used to tweak this more.
-
-* As you find different pairs of files, call `diff_change()` to feed
-  modified files, `diff_addremove()` to feed created or deleted files,
-  or `diff_unmerge()` to feed a file whose state is 'unmerged' to the
-  API.  These are thin wrappers to a lower-level `diff_queue()` function
-  that is flexible enough to record any of these kinds of changes.
-
-* Once you finish feeding the pairs of files, call `diffcore_std()`.
-  This will tell the diffcore library to go ahead and do its work.
-
-* Calling `diff_flush()` will produce the output.
-
-
-Data structures
----------------
-
-* `struct diff_filespec`
-
-This is the internal representation for a single file (blob).  It
-records the blob object name (if known -- for a work tree file it
-typically is a NUL SHA-1), filemode and pathname.  This is what the
-`diff_addremove()`, `diff_change()` and `diff_unmerge()` synthesize and
-feed `diff_queue()` function with.
-
-* `struct diff_filepair`
-
-This records a pair of `struct diff_filespec`; the filespec for a file
-in the "old" set (i.e. preimage) is called `one`, and the filespec for a
-file in the "new" set (i.e. postimage) is called `two`.  A change that
-represents file creation has NULL in `one`, and file deletion has NULL
-in `two`.
-
-A `filepair` starts pointing at `one` and `two` that are from the same
-filename, but `diffcore_std()` can break pairs and match component
-filespecs with other filespecs from a different filepair to form new
-filepair.  This is called 'rename detection'.
-
-* `struct diff_queue`
-
-This is a collection of filepairs.  Notable members are:
-
-`queue`::
-
-	An array of pointers to `struct diff_filepair`.  This
-	dynamically grows as you add filepairs;
-
-`alloc`::
-
-	The allocated size of the `queue` array;
-
-`nr`::
-
-	The number of elements in the `queue` array.
-
-
-* `struct diff_options`
-
-This describes the set of options the calling program wants to affect
-the operation of diffcore library with.
-
-Notable members are:
-
-`output_format`::
-	The output format used when `diff_flush()` is run.
-
-`context`::
-	Number of context lines to generate in patch output.
-
-`break_opt`, `detect_rename`, `rename-score`, `rename_limit`::
-	Affects the way detection logic for complete rewrites, renames
-	and copies.
-
-`abbrev`::
-	Number of hexdigits to abbreviate raw format output to.
-
-`pickaxe`::
-	A constant string (can and typically does contain newlines to
-	look for a block of text, not just a single line) to filter out
-	the filepairs that do not change the number of strings contained
-	in its preimage and postimage of the diff_queue.
-
-`flags`::
-	This is mostly a collection of boolean options that affects the
-	operation, but some do not have anything to do with the diffcore
-	library.
-
-`touched_flags`::
-	Records whether a flag has been changed due to user request
-	(rather than just set/unset by default).
-
-`set_default`::
-	Callback which allows tweaking the options in diff_setup_done().
-
-BINARY, TEXT;;
-	Affects the way how a file that is seemingly binary is treated.
-
-FULL_INDEX;;
-	Tells the patch output format not to use abbreviated object
-	names on the "index" lines.
-
-FIND_COPIES_HARDER;;
-	Tells the diffcore library that the caller is feeding unchanged
-	filepairs to allow copies from unmodified files be detected.
-
-COLOR_DIFF;;
-	Output should be colored.
-
-COLOR_DIFF_WORDS;;
-	Output is a colored word-diff.
-
-NO_INDEX;;
-	Tells diff-files that the input is not tracked files but files
-	in random locations on the filesystem.
-
-ALLOW_EXTERNAL;;
-	Tells output routine that it is Ok to call user specified patch
-	output routine.  Plumbing disables this to ensure stable output.
-
-QUIET;;
-	Do not show any output.
-
-REVERSE_DIFF;;
-	Tells the library that the calling program is feeding the
-	filepairs reversed; `one` is two, and `two` is one.
-
-EXIT_WITH_STATUS;;
-	For communication between the calling program and the options
-	parser; tell the calling program to signal the presence of
-	difference using program exit code.
-
-HAS_CHANGES;;
-	Internal; used for optimization to see if there is any change.
-
-SILENT_ON_REMOVE;;
-	Affects if diff-files shows removed files.
-
-RECURSIVE, TREE_IN_RECURSIVE;;
-	Tells if tree traversal done by tree-diff should recursively
-	descend into a tree object pair that are different in preimage
-	and postimage set.
-
-(JC)
diff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt
deleted file mode 100644
index 76b6e4f..0000000
--- a/Documentation/technical/api-directory-listing.txt
+++ /dev/null
@@ -1,130 +0,0 @@
-directory listing API
-=====================
-
-The directory listing API is used to enumerate paths in the work tree,
-optionally taking `.git/info/exclude` and `.gitignore` files per
-directory into account.
-
-Data structure
---------------
-
-`struct dir_struct` structure is used to pass directory traversal
-options to the library and to record the paths discovered.  A single
-`struct dir_struct` is used regardless of whether or not the traversal
-recursively descends into subdirectories.
-
-The notable options are:
-
-`exclude_per_dir`::
-
-	The name of the file to be read in each directory for excluded
-	files (typically `.gitignore`).
-
-`flags`::
-
-	A bit-field of options:
-
-`DIR_SHOW_IGNORED`:::
-
-	Return just ignored files in `entries[]`, not untracked
-	files. This flag is mutually exclusive with
-	`DIR_SHOW_IGNORED_TOO`.
-
-`DIR_SHOW_IGNORED_TOO`:::
-
-	Similar to `DIR_SHOW_IGNORED`, but return ignored files in
-	`ignored[]` in addition to untracked files in
-	`entries[]`. This flag is mutually exclusive with
-	`DIR_SHOW_IGNORED`.
-
-`DIR_KEEP_UNTRACKED_CONTENTS`:::
-
-	Only has meaning if `DIR_SHOW_IGNORED_TOO` is also set; if this is set, the
-	untracked contents of untracked directories are also returned in
-	`entries[]`.
-
-`DIR_SHOW_IGNORED_TOO_MODE_MATCHING`:::
-
-	Only has meaning if `DIR_SHOW_IGNORED_TOO` is also set; if
-	this is set, returns ignored files and directories that match
-	an exclude pattern. If a directory matches an exclude pattern,
-	then the directory is returned and the contained paths are
-	not. A directory that does not match an exclude pattern will
-	not be returned even if all of its contents are ignored. In
-	this case, the contents are returned as individual entries.
-+
-If this is set, files and directories that explicitly match an ignore
-pattern are reported. Implicitly ignored directories (directories that
-do not match an ignore pattern, but whose contents are all ignored)
-are not reported, instead all of the contents are reported.
-
-`DIR_COLLECT_IGNORED`:::
-
-	Special mode for git-add. Return ignored files in `ignored[]` and
-	untracked files in `entries[]`. Only returns ignored files that match
-	pathspec exactly (no wildcards). Does not recurse into ignored
-	directories.
-
-`DIR_SHOW_OTHER_DIRECTORIES`:::
-
-	Include a directory that is not tracked.
-
-`DIR_HIDE_EMPTY_DIRECTORIES`:::
-
-	Do not include a directory that is not tracked and is empty.
-
-`DIR_NO_GITLINKS`:::
-
-	If set, recurse into a directory that looks like a Git
-	directory.  Otherwise it is shown as a directory.
-
-The result of the enumeration is left in these fields:
-
-`entries[]`::
-
-	An array of `struct dir_entry`, each element of which describes
-	a path.
-
-`nr`::
-
-	The number of members in `entries[]` array.
-
-`alloc`::
-
-	Internal use; keeps track of allocation of `entries[]` array.
-
-`ignored[]`::
-
-	An array of `struct dir_entry`, used for ignored paths with the
-	`DIR_SHOW_IGNORED_TOO` and `DIR_COLLECT_IGNORED` flags.
-
-`ignored_nr`::
-
-	The number of members in `ignored[]` array.
-
-Calling sequence
-----------------
-
-Note: index may be looked at for .gitignore files that are CE_SKIP_WORKTREE
-marked. If you to exclude files, make sure you have loaded index first.
-
-* Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0,
-  sizeof(dir))`.
-
-* To add single exclude pattern, call `add_pattern_list()` and then
-  `add_pattern()`.
-
-* To add patterns from a file (e.g. `.git/info/exclude`), call
-  `add_patterns_from_file()` , and/or set `dir.exclude_per_dir`.  A
-  short-hand function `setup_standard_excludes()` can be used to set
-  up the standard set of exclude settings.
-
-* Set options described in the Data Structure section above.
-
-* Call `read_directory()`.
-
-* Use `dir.entries[]`.
-
-* Call `clear_directory()` when none of the contained elements are no longer in use.
-
-(JC)
diff --git a/Documentation/technical/api-gitattributes.txt b/Documentation/technical/api-gitattributes.txt
deleted file mode 100644
index 45f0df6..0000000
--- a/Documentation/technical/api-gitattributes.txt
+++ /dev/null
@@ -1,154 +0,0 @@
-gitattributes API
-=================
-
-gitattributes mechanism gives a uniform way to associate various
-attributes to set of paths.
-
-
-Data Structure
---------------
-
-`struct git_attr`::
-
-	An attribute is an opaque object that is identified by its name.
-	Pass the name to `git_attr()` function to obtain the object of
-	this type.  The internal representation of this structure is
-	of no interest to the calling programs.  The name of the
-	attribute can be retrieved by calling `git_attr_name()`.
-
-`struct attr_check_item`::
-
-	This structure represents one attribute and its value.
-
-`struct attr_check`::
-
-	This structure represents a collection of `attr_check_item`.
-	It is passed to `git_check_attr()` function, specifying the
-	attributes to check, and receives their values.
-
-
-Attribute Values
-----------------
-
-An attribute for a path can be in one of four states: Set, Unset,
-Unspecified or set to a string, and `.value` member of `struct
-attr_check_item` records it.  There are three macros to check these:
-
-`ATTR_TRUE()`::
-
-	Returns true if the attribute is Set for the path.
-
-`ATTR_FALSE()`::
-
-	Returns true if the attribute is Unset for the path.
-
-`ATTR_UNSET()`::
-
-	Returns true if the attribute is Unspecified for the path.
-
-If none of the above returns true, `.value` member points at a string
-value of the attribute for the path.
-
-
-Querying Specific Attributes
-----------------------------
-
-* Prepare `struct attr_check` using attr_check_initl()
-  function, enumerating the names of attributes whose values you are
-  interested in, terminated with a NULL pointer.  Alternatively, an
-  empty `struct attr_check` can be prepared by calling
-  `attr_check_alloc()` function and then attributes you want to
-  ask about can be added to it with `attr_check_append()`
-  function.
-
-* Call `git_check_attr()` to check the attributes for the path.
-
-* Inspect `attr_check` structure to see how each of the
-  attribute in the array is defined for the path.
-
-
-Example
--------
-
-To see how attributes "crlf" and "ident" are set for different paths.
-
-. Prepare a `struct attr_check` with two elements (because
-  we are checking two attributes):
-
-------------
-static struct attr_check *check;
-static void setup_check(void)
-{
-	if (check)
-		return; /* already done */
-	check = attr_check_initl("crlf", "ident", NULL);
-}
-------------
-
-. Call `git_check_attr()` with the prepared `struct attr_check`:
-
-------------
-	const char *path;
-
-	setup_check();
-	git_check_attr(path, check);
-------------
-
-. Act on `.value` member of the result, left in `check->items[]`:
-
-------------
-	const char *value = check->items[0].value;
-
-	if (ATTR_TRUE(value)) {
-		The attribute is Set, by listing only the name of the
-		attribute in the gitattributes file for the path.
-	} else if (ATTR_FALSE(value)) {
-		The attribute is Unset, by listing the name of the
-		attribute prefixed with a dash - for the path.
-	} else if (ATTR_UNSET(value)) {
-		The attribute is neither set nor unset for the path.
-	} else if (!strcmp(value, "input")) {
-		If none of ATTR_TRUE(), ATTR_FALSE(), or ATTR_UNSET() is
-		true, the value is a string set in the gitattributes
-		file for the path by saying "attr=value".
-	} else if (... other check using value as string ...) {
-		...
-	}
-------------
-
-To see how attributes in argv[] are set for different paths, only
-the first step in the above would be different.
-
-------------
-static struct attr_check *check;
-static void setup_check(const char **argv)
-{
-	check = attr_check_alloc();
-	while (*argv) {
-		struct git_attr *attr = git_attr(*argv);
-		attr_check_append(check, attr);
-		argv++;
-	}
-}
-------------
-
-
-Querying All Attributes
------------------------
-
-To get the values of all attributes associated with a file:
-
-* Prepare an empty `attr_check` structure by calling
-  `attr_check_alloc()`.
-
-* Call `git_all_attrs()`, which populates the `attr_check`
-  with the attributes attached to the path.
-
-* Iterate over the `attr_check.items[]` array to examine
-  the attribute names and values.  The name of the attribute
-  described by an `attr_check.items[]` object can be retrieved via
-  `git_attr_name(check->items[i].attr)`.  (Please note that no items
-  will be returned for unset attributes, so `ATTR_UNSET()` will return
-  false for all returned `attr_check.items[]` objects.)
-
-* Free the `attr_check` struct by calling `attr_check_free()`.
diff --git a/Documentation/technical/api-history-graph.txt b/Documentation/technical/api-history-graph.txt
deleted file mode 100644
index d0d1707..0000000
--- a/Documentation/technical/api-history-graph.txt
+++ /dev/null
@@ -1,173 +0,0 @@
-history graph API
-=================
-
-The graph API is used to draw a text-based representation of the commit
-history.  The API generates the graph in a line-by-line fashion.
-
-Functions
----------
-
-Core functions:
-
-* `graph_init()` creates a new `struct git_graph`
-
-* `graph_update()` moves the graph to a new commit.
-
-* `graph_next_line()` outputs the next line of the graph into a strbuf.  It
-  does not add a terminating newline.
-
-* `graph_padding_line()` outputs a line of vertical padding in the graph.  It
-  is similar to `graph_next_line()`, but is guaranteed to never print the line
-  containing the current commit.  Where `graph_next_line()` would print the
-  commit line next, `graph_padding_line()` prints a line that simply extends
-  all branch lines downwards one row, leaving their positions unchanged.
-
-* `graph_is_commit_finished()` determines if the graph has output all lines
-  necessary for the current commit.  If `graph_update()` is called before all
-  lines for the current commit have been printed, the next call to
-  `graph_next_line()` will output an ellipsis, to indicate that a portion of
-  the graph was omitted.
-
-The following utility functions are wrappers around `graph_next_line()` and
-`graph_is_commit_finished()`.  They always print the output to stdout.
-They can all be called with a NULL graph argument, in which case no graph
-output will be printed.
-
-* `graph_show_commit()` calls `graph_next_line()` and
-  `graph_is_commit_finished()` until one of them return non-zero.  This prints
-  all graph lines up to, and including, the line containing this commit.
-  Output is printed to stdout.  The last line printed does not contain a
-  terminating newline.
-
-* `graph_show_oneline()` calls `graph_next_line()` and prints the result to
-  stdout.  The line printed does not contain a terminating newline.
-
-* `graph_show_padding()` calls `graph_padding_line()` and prints the result to
-  stdout.  The line printed does not contain a terminating newline.
-
-* `graph_show_remainder()` calls `graph_next_line()` until
-  `graph_is_commit_finished()` returns non-zero.  Output is printed to stdout.
-  The last line printed does not contain a terminating newline.  Returns 1 if
-  output was printed, and 0 if no output was necessary.
-
-* `graph_show_strbuf()` prints the specified strbuf to stdout, prefixing all
-  lines but the first with a graph line.  The caller is responsible for
-  ensuring graph output for the first line has already been printed to stdout.
-  (This can be done with `graph_show_commit()` or `graph_show_oneline()`.)  If
-  a NULL graph is supplied, the strbuf is printed as-is.
-
-* `graph_show_commit_msg()` is similar to `graph_show_strbuf()`, but it also
-  prints the remainder of the graph, if more lines are needed after the strbuf
-  ends.  It is better than directly calling `graph_show_strbuf()` followed by
-  `graph_show_remainder()` since it properly handles buffers that do not end in
-  a terminating newline.  The output printed by `graph_show_commit_msg()` will
-  end in a newline if and only if the strbuf ends in a newline.
-
-Data structure
---------------
-`struct git_graph` is an opaque data type used to store the current graph
-state.
-
-Calling sequence
-----------------
-
-* Create a `struct git_graph` by calling `graph_init()`.  When using the
-  revision walking API, this is done automatically by `setup_revisions()` if
-  the '--graph' option is supplied.
-
-* Use the revision walking API to walk through a group of contiguous commits.
-  The `get_revision()` function automatically calls `graph_update()` each time
-  it is invoked.
-
-* For each commit, call `graph_next_line()` repeatedly, until
-  `graph_is_commit_finished()` returns non-zero.  Each call to
-  `graph_next_line()` will output a single line of the graph.  The resulting
-  lines will not contain any newlines.  `graph_next_line()` returns 1 if the
-  resulting line contains the current commit, or 0 if this is merely a line
-  needed to adjust the graph before or after the current commit.  This return
-  value can be used to determine where to print the commit summary information
-  alongside the graph output.
-
-Limitations
------------
-
-* `graph_update()` must be called with commits in topological order.  It should
-  not be called on a commit if it has already been invoked with an ancestor of
-  that commit, or the graph output will be incorrect.
-
-* `graph_update()` must be called on a contiguous group of commits.  If
-  `graph_update()` is called on a particular commit, it should later be called
-  on all parents of that commit.  Parents must not be skipped, or the graph
-  output will appear incorrect.
-+
-`graph_update()` may be used on a pruned set of commits only if the parent list
-has been rewritten so as to include only ancestors from the pruned set.
-
-* The graph API does not currently support reverse commit ordering.  In
-  order to implement reverse ordering, the graphing API needs an
-  (efficient) mechanism to find the children of a commit.
-
-Sample usage
-------------
-
-------------
-struct commit *commit;
-struct git_graph *graph = graph_init(opts);
-
-while ((commit = get_revision(opts)) != NULL) {
-	while (!graph_is_commit_finished(graph))
-	{
-		struct strbuf sb;
-		int is_commit_line;
-
-		strbuf_init(&sb, 0);
-		is_commit_line = graph_next_line(graph, &sb);
-		fputs(sb.buf, stdout);
-
-		if (is_commit_line)
-			log_tree_commit(opts, commit);
-		else
-			putchar(opts->diffopt.line_termination);
-	}
-}
-------------
-
-Sample output
--------------
-
-The following is an example of the output from the graph API.  This output does
-not include any commit summary information--callers are responsible for
-outputting that information, if desired.
-
-------------
-*
-*
-*
-|\
-* |
-| | *
-| \ \
-|  \ \
-*-. \ \
-|\ \ \ \
-| | * | |
-| | | | | *
-| | | | | *
-| | | | | *
-| | | | | |\
-| | | | | | *
-| * | | | | |
-| | | | | *  \
-| | | | | |\  |
-| | | | * | | |
-| | | | * | | |
-* | | | | | | |
-| |/ / / / / /
-|/| / / / / /
-* | | | | | |
-|/ / / / / /
-* | | | | |
-| | | | | *
-| | | | |/
-| | | | *
-------------
diff --git a/Documentation/technical/api-merge.txt b/Documentation/technical/api-merge.txt
index 9dc1bed..487d4d8 100644
--- a/Documentation/technical/api-merge.txt
+++ b/Documentation/technical/api-merge.txt
@@ -28,77 +28,9 @@
 
 * `struct ll_merge_options`
 
-This describes the set of options the calling program wants to affect
-the operation of a low-level (single file) merge.  Some options:
-
-`virtual_ancestor`::
-	Behave as though this were part of a merge between common
-	ancestors in a recursive merge.
-	If a helper program is specified by the
-	`[merge "<driver>"] recursive` configuration, it will
-	be used (see linkgit:gitattributes[5]).
-
-`variant`::
-	Resolve local conflicts automatically in favor
-	of one side or the other (as in 'git merge-file'
-	`--ours`/`--theirs`/`--union`).  Can be `0`,
-	`XDL_MERGE_FAVOR_OURS`, `XDL_MERGE_FAVOR_THEIRS`, or
-	`XDL_MERGE_FAVOR_UNION`.
-
-`renormalize`::
-	Resmudge and clean the "base", "theirs" and "ours" files
-	before merging.  Use this when the merge is likely to have
-	overlapped with a change in smudge/clean or end-of-line
-	normalization rules.
+Check ll-merge.h for details.
 
 Low-level (single file) merge
 -----------------------------
 
-`ll_merge`::
-
-	Perform a three-way single-file merge in core.  This is
-	a thin wrapper around `xdl_merge` that takes the path and
-	any merge backend specified in `.gitattributes` or
-	`.git/info/attributes` into account.  Returns 0 for a
-	clean merge.
-
-Calling sequence:
-
-* Prepare a `struct ll_merge_options` to record options.
-  If you have no special requests, skip this and pass `NULL`
-  as the `opts` parameter to use the default options.
-
-* Allocate an mmbuffer_t variable for the result.
-
-* Allocate and fill variables with the file's original content
-  and two modified versions (using `read_mmfile`, for example).
-
-* Call `ll_merge()`.
-
-* Read the merged content from `result_buf.ptr` and `result_buf.size`.
-
-* Release buffers when finished.  A simple
-  `free(ancestor.ptr); free(ours.ptr); free(theirs.ptr);
-  free(result_buf.ptr);` will do.
-
-If the modifications do not merge cleanly, `ll_merge` will return a
-nonzero value and `result_buf` will generally include a description of
-the conflict bracketed by markers such as the traditional `<<<<<<<`
-and `>>>>>>>`.
-
-The `ancestor_label`, `our_label`, and `their_label` parameters are
-used to label the different sides of a conflict if the merge driver
-supports this.
-
-Everything else
----------------
-
-Talk about <merge-recursive.h> and merge_file():
-
- - merge_trees() to merge with rename detection
- - merge_recursive() for ancestor consolidation
- - try_merge_command() for other strategies
- - conflict format
- - merge options
-
-(Daniel, Miklos, Stephan, JC)
+Check ll-merge.h for details.
diff --git a/Documentation/technical/api-oid-array.txt b/Documentation/technical/api-oid-array.txt
deleted file mode 100644
index c97428c..0000000
--- a/Documentation/technical/api-oid-array.txt
+++ /dev/null
@@ -1,90 +0,0 @@
-oid-array API
-==============
-
-The oid-array API provides storage and manipulation of sets of object
-identifiers. The emphasis is on storage and processing efficiency,
-making them suitable for large lists. Note that the ordering of items is
-not preserved over some operations.
-
-Data Structures
----------------
-
-`struct oid_array`::
-
-	A single array of object IDs. This should be initialized by
-	assignment from `OID_ARRAY_INIT`.  The `oid` member contains
-	the actual data. The `nr` member contains the number of items in
-	the set.  The `alloc` and `sorted` members are used internally,
-	and should not be needed by API callers.
-
-Functions
----------
-
-`oid_array_append`::
-	Add an item to the set. The object ID will be placed at the end of
-	the array (but note that some operations below may lose this
-	ordering).
-
-`oid_array_lookup`::
-	Perform a binary search of the array for a specific object ID.
-	If found, returns the offset (in number of elements) of the
-	object ID. If not found, returns a negative integer. If the array
-	is not sorted, this function has the side effect of sorting it.
-
-`oid_array_clear`::
-	Free all memory associated with the array and return it to the
-	initial, empty state.
-
-`oid_array_for_each`::
-	Iterate over each element of the list, executing the callback
-	function for each one. Does not sort the list, so any custom
-	hash order is retained. If the callback returns a non-zero
-	value, the iteration ends immediately and the callback's
-	return is propagated; otherwise, 0 is returned.
-
-`oid_array_for_each_unique`::
-	Iterate over each unique element of the list in sorted order,
-	but otherwise behave like `oid_array_for_each`. If the array
-	is not sorted, this function has the side effect of sorting
-	it.
-
-`oid_array_filter`::
-	Apply the callback function `want` to each entry in the array,
-	retaining only the entries for which the function returns true.
-	Preserve the order of the entries that are retained.
-
-Examples
---------
-
------------------------------------------
-int print_callback(const struct object_id *oid,
-		    void *data)
-{
-	printf("%s\n", oid_to_hex(oid));
-	return 0; /* always continue */
-}
-
-void some_func(void)
-{
-	struct sha1_array hashes = OID_ARRAY_INIT;
-	struct object_id oid;
-
-	/* Read objects into our set */
-	while (read_object_from_stdin(oid.hash))
-		oid_array_append(&hashes, &oid);
-
-	/* Check if some objects are in our set */
-	while (read_object_from_stdin(oid.hash)) {
-		if (oid_array_lookup(&hashes, &oid) >= 0)
-			printf("it's in there!\n");
-
-	/*
-	 * Print the unique set of objects. We could also have
-	 * avoided adding duplicate objects in the first place,
-	 * but we would end up re-sorting the array repeatedly.
-	 * Instead, this will sort once and then skip duplicates
-	 * in linear time.
-	 */
-	oid_array_for_each_unique(&hashes, print_callback, NULL);
-}
------------------------------------------
diff --git a/Documentation/technical/api-ref-iteration.txt b/Documentation/technical/api-ref-iteration.txt
deleted file mode 100644
index ad9d019..0000000
--- a/Documentation/technical/api-ref-iteration.txt
+++ /dev/null
@@ -1,78 +0,0 @@
-ref iteration API
-=================
-
-
-Iteration of refs is done by using an iterate function which will call a
-callback function for every ref. The callback function has this
-signature:
-
-	int handle_one_ref(const char *refname, const struct object_id *oid,
-			   int flags, void *cb_data);
-
-There are different kinds of iterate functions which all take a
-callback of this type. The callback is then called for each found ref
-until the callback returns nonzero. The returned value is then also
-returned by the iterate function.
-
-Iteration functions
--------------------
-
-* `head_ref()` just iterates the head ref.
-
-* `for_each_ref()` iterates all refs.
-
-* `for_each_ref_in()` iterates all refs which have a defined prefix and
-  strips that prefix from the passed variable refname.
-
-* `for_each_tag_ref()`, `for_each_branch_ref()`, `for_each_remote_ref()`,
-  `for_each_replace_ref()` iterate refs from the respective area.
-
-* `for_each_glob_ref()` iterates all refs that match the specified glob
-  pattern.
-
-* `for_each_glob_ref_in()` the previous and `for_each_ref_in()` combined.
-
-* Use `refs_` API for accessing submodules. The submodule ref store could
-  be obtained with `get_submodule_ref_store()`.
-
-* `for_each_rawref()` can be used to learn about broken ref and symref.
-
-* `for_each_reflog()` iterates each reflog file.
-
-Submodules
-----------
-
-If you want to iterate the refs of a submodule you first need to add the
-submodules object database. You can do this by a code-snippet like
-this:
-
-	const char *path = "path/to/submodule"
-	if (add_submodule_odb(path))
-		die("Error submodule '%s' not populated.", path);
-
-`add_submodule_odb()` will return zero on success. If you
-do not do this you will get an error for each ref that it does not point
-to a valid object.
-
-Note: As a side-effect of this you cannot safely assume that all
-objects you lookup are available in superproject. All submodule objects
-will be available the same way as the superprojects objects.
-
-Example:
---------
-
-----
-static int handle_remote_ref(const char *refname,
-		const unsigned char *sha1, int flags, void *cb_data)
-{
-	struct strbuf *output = cb_data;
-	strbuf_addf(output, "%s\n", refname);
-	return 0;
-}
-
-...
-
-	struct strbuf output = STRBUF_INIT;
-	for_each_remote_ref(handle_remote_ref, &output);
-	printf("%s", output.buf);
-----
diff --git a/Documentation/technical/api-remote.txt b/Documentation/technical/api-remote.txt
deleted file mode 100644
index f10941b..0000000
--- a/Documentation/technical/api-remote.txt
+++ /dev/null
@@ -1,127 +0,0 @@
-Remotes configuration API
-=========================
-
-The API in remote.h gives access to the configuration related to
-remotes. It handles all three configuration mechanisms historically
-and currently used by Git, and presents the information in a uniform
-fashion. Note that the code also handles plain URLs without any
-configuration, giving them just the default information.
-
-struct remote
--------------
-
-`name`::
-
-	The user's nickname for the remote
-
-`url`::
-
-	An array of all of the url_nr URLs configured for the remote
-
-`pushurl`::
-
-	An array of all of the pushurl_nr push URLs configured for the remote
-
-`push`::
-
-	 An array of refspecs configured for pushing, with
-	 push_refspec being the literal strings, and push_refspec_nr
-	 being the quantity.
-
-`fetch`::
-
-	An array of refspecs configured for fetching, with
-	fetch_refspec being the literal strings, and fetch_refspec_nr
-	being the quantity.
-
-`fetch_tags`::
-
-	The setting for whether to fetch tags (as a separate rule from
-	the configured refspecs); -1 means never to fetch tags, 0
-	means to auto-follow tags based on the default heuristic, 1
-	means to always auto-follow tags, and 2 means to fetch all
-	tags.
-
-`receivepack`, `uploadpack`::
-
-	The configured helper programs to run on the remote side, for
-	Git-native protocols.
-
-`http_proxy`::
-
-	The proxy to use for curl (http, https, ftp, etc.) URLs.
-
-`http_proxy_authmethod`::
-
-	The method used for authenticating against `http_proxy`.
-
-struct remotes can be found by name with remote_get(), and iterated
-through with for_each_remote(). remote_get(NULL) will return the
-default remote, given the current branch and configuration.
-
-struct refspec
---------------
-
-A struct refspec holds the parsed interpretation of a refspec.  If it
-will force updates (starts with a '+'), force is true.  If it is a
-pattern (sides end with '*') pattern is true.  src and dest are the
-two sides (including '*' characters if present); if there is only one
-side, it is src, and dst is NULL; if sides exist but are empty (i.e.,
-the refspec either starts or ends with ':'), the corresponding side is
-"".
-
-An array of strings can be parsed into an array of struct refspecs
-using parse_fetch_refspec() or parse_push_refspec().
-
-remote_find_tracking(), given a remote and a struct refspec with
-either src or dst filled out, will fill out the other such that the
-result is in the "fetch" specification for the remote (note that this
-evaluates patterns and returns a single result).
-
-struct branch
--------------
-
-Note that this may end up moving to branch.h
-
-struct branch holds the configuration for a branch. It can be looked
-up with branch_get(name) for "refs/heads/{name}", or with
-branch_get(NULL) for HEAD.
-
-It contains:
-
-`name`::
-
-	The short name of the branch.
-
-`refname`::
-
-	The full path for the branch ref.
-
-`remote_name`::
-
-	The name of the remote listed in the configuration.
-
-`merge_name`::
-
-	An array of the "merge" lines in the configuration.
-
-`merge`::
-
-	An array of the struct refspecs used for the merge lines. That
-	is, merge[i]->dst is a local tracking ref which should be
-	merged into this branch by default.
-
-`merge_nr`::
-
-	The number of merge configurations
-
-branch_has_merge_config() returns true if the given branch has merge
-configuration given.
-
-Other stuff
------------
-
-There is other stuff in remote.h that is related, in general, to the
-process of interacting with remotes.
-
-(Daniel Barkalow)
diff --git a/Documentation/technical/api-revision-walking.txt b/Documentation/technical/api-revision-walking.txt
deleted file mode 100644
index 03f9ea6..0000000
--- a/Documentation/technical/api-revision-walking.txt
+++ /dev/null
@@ -1,72 +0,0 @@
-revision walking API
-====================
-
-The revision walking API offers functions to build a list of revisions
-and then iterate over that list.
-
-Calling sequence
-----------------
-
-The walking API has a given calling sequence: first you need to
-initialize a rev_info structure, then add revisions to control what kind
-of revision list do you want to get, finally you can iterate over the
-revision list.
-
-Functions
----------
-
-`repo_init_revisions`::
-
-	Initialize a rev_info structure with default values. The third
-	parameter may be NULL or can be prefix path, and then the `.prefix`
-	variable will be set to it. This is typically the first function you
-	want to call when you want to deal with a revision list. After calling
-	this function, you are free to customize options, like set
-	`.ignore_merges` to 0 if you don't want to ignore merges, and so on. See
-	`revision.h` for a complete list of available options.
-
-`add_pending_object`::
-
-	This function can be used if you want to add commit objects as revision
-	information. You can use the `UNINTERESTING` object flag to indicate if
-	you want to include or exclude the given commit (and commits reachable
-	from the given commit) from the revision list.
-+
-NOTE: If you have the commits as a string list then you probably want to
-use setup_revisions(), instead of parsing each string and using this
-function.
-
-`setup_revisions`::
-
-	Parse revision information, filling in the `rev_info` structure, and
-	removing the used arguments from the argument list. Returns the number
-	of arguments left that weren't recognized, which are also moved to the
-	head of the argument list. The last parameter is used in case no
-	parameter given by the first two arguments.
-
-`prepare_revision_walk`::
-
-	Prepares the rev_info structure for a walk. You should check if it
-	returns any error (non-zero return code) and if it does not, you can
-	start using get_revision() to do the iteration.
-
-`get_revision`::
-
-	Takes a pointer to a `rev_info` structure and iterates over it,
-	returning a `struct commit *` each time you call it. The end of the
-	revision list is indicated by returning a NULL pointer.
-
-`reset_revision_walk`::
-
-	Reset the flags used by the revision walking api. You can use
-	this to do multiple sequential revision walks.
-
-Data structures
----------------
-
-Talk about <revision.h>, things like:
-
-* two diff_options, one for path limiting, another for output;
-* remaining functions;
-
-(Linus, JC, Dscho)
diff --git a/Documentation/technical/api-run-command.txt b/Documentation/technical/api-run-command.txt
deleted file mode 100644
index 8bf3e37..0000000
--- a/Documentation/technical/api-run-command.txt
+++ /dev/null
@@ -1,264 +0,0 @@
-run-command API
-===============
-
-The run-command API offers a versatile tool to run sub-processes with
-redirected input and output as well as with a modified environment
-and an alternate current directory.
-
-A similar API offers the capability to run a function asynchronously,
-which is primarily used to capture the output that the function
-produces in the caller in order to process it.
-
-
-Functions
----------
-
-`child_process_init`::
-
-	Initialize a struct child_process variable.
-
-`start_command`::
-
-	Start a sub-process. Takes a pointer to a `struct child_process`
-	that specifies the details and returns pipe FDs (if requested).
-	See below for details.
-
-`finish_command`::
-
-	Wait for the completion of a sub-process that was started with
-	start_command().
-
-`run_command`::
-
-	A convenience function that encapsulates a sequence of
-	start_command() followed by finish_command(). Takes a pointer
-	to a `struct child_process` that specifies the details.
-
-`run_command_v_opt`, `run_command_v_opt_cd_env`::
-
-	Convenience functions that encapsulate a sequence of
-	start_command() followed by finish_command(). The argument argv
-	specifies the program and its arguments. The argument opt is zero
-	or more of the flags `RUN_COMMAND_NO_STDIN`, `RUN_GIT_CMD`,
-	`RUN_COMMAND_STDOUT_TO_STDERR`, or `RUN_SILENT_EXEC_FAILURE`
-	that correspond to the members .no_stdin, .git_cmd,
-	.stdout_to_stderr, .silent_exec_failure of `struct child_process`.
-	The argument dir corresponds the member .dir. The argument env
-	corresponds to the member .env.
-
-`child_process_clear`::
-
-	Release the memory associated with the struct child_process.
-	Most users of the run-command API don't need to call this
-	function explicitly because `start_command` invokes it on
-	failure and `finish_command` calls it automatically already.
-
-The functions above do the following:
-
-. If a system call failed, errno is set and -1 is returned. A diagnostic
-  is printed.
-
-. If the program was not found, then -1 is returned and errno is set to
-  ENOENT; a diagnostic is printed only if .silent_exec_failure is 0.
-
-. Otherwise, the program is run. If it terminates regularly, its exit
-  code is returned. No diagnostic is printed, even if the exit code is
-  non-zero.
-
-. If the program terminated due to a signal, then the return value is the
-  signal number + 128, ie. the same value that a POSIX shell's $? would
-  report.  A diagnostic is printed.
-
-
-`start_async`::
-
-	Run a function asynchronously. Takes a pointer to a `struct
-	async` that specifies the details and returns a set of pipe FDs
-	for communication with the function. See below for details.
-
-`finish_async`::
-
-	Wait for the completion of an asynchronous function that was
-	started with start_async().
-
-`run_hook`::
-
-	Run a hook.
-	The first argument is a pathname to an index file, or NULL
-	if the hook uses the default index file or no index is needed.
-	The second argument is the name of the hook.
-	The further arguments correspond to the hook arguments.
-	The last argument has to be NULL to terminate the arguments list.
-	If the hook does not exist or is not executable, the return
-	value will be zero.
-	If it is executable, the hook will be executed and the exit
-	status of the hook is returned.
-	On execution, .stdout_to_stderr and .no_stdin will be set.
-	(See below.)
-
-
-Data structures
----------------
-
-* `struct child_process`
-
-This describes the arguments, redirections, and environment of a
-command to run in a sub-process.
-
-The caller:
-
-1. allocates and clears (using child_process_init() or
-   CHILD_PROCESS_INIT) a struct child_process variable;
-2. initializes the members;
-3. calls start_command();
-4. processes the data;
-5. closes file descriptors (if necessary; see below);
-6. calls finish_command().
-
-The .argv member is set up as an array of string pointers (NULL
-terminated), of which .argv[0] is the program name to run (usually
-without a path). If the command to run is a git command, set argv[0] to
-the command name without the 'git-' prefix and set .git_cmd = 1.
-
-Note that the ownership of the memory pointed to by .argv stays with the
-caller, but it should survive until `finish_command` completes. If the
-.argv member is NULL, `start_command` will point it at the .args
-`argv_array` (so you may use one or the other, but you must use exactly
-one). The memory in .args will be cleaned up automatically during
-`finish_command` (or during `start_command` when it is unsuccessful).
-
-The members .in, .out, .err are used to redirect stdin, stdout,
-stderr as follows:
-
-. Specify 0 to request no special redirection. No new file descriptor
-  is allocated. The child process simply inherits the channel from the
-  parent.
-
-. Specify -1 to have a pipe allocated; start_command() replaces -1
-  by the pipe FD in the following way:
-
-	.in: Returns the writable pipe end into which the caller writes;
-		the readable end of the pipe becomes the child's stdin.
-
-	.out, .err: Returns the readable pipe end from which the caller
-		reads; the writable end of the pipe end becomes child's
-		stdout/stderr.
-
-  The caller of start_command() must close the so returned FDs
-  after it has completed reading from/writing to it!
-
-. Specify a file descriptor > 0 to be used by the child:
-
-	.in: The FD must be readable; it becomes child's stdin.
-	.out: The FD must be writable; it becomes child's stdout.
-	.err: The FD must be writable; it becomes child's stderr.
-
-  The specified FD is closed by start_command(), even if it fails to
-  run the sub-process!
-
-. Special forms of redirection are available by setting these members
-  to 1:
-
-	.no_stdin, .no_stdout, .no_stderr: The respective channel is
-		redirected to /dev/null.
-
-	.stdout_to_stderr: stdout of the child is redirected to its
-		stderr. This happens after stderr is itself redirected.
-		So stdout will follow stderr to wherever it is
-		redirected.
-
-To modify the environment of the sub-process, specify an array of
-string pointers (NULL terminated) in .env:
-
-. If the string is of the form "VAR=value", i.e. it contains '='
-  the variable is added to the child process's environment.
-
-. If the string does not contain '=', it names an environment
-  variable that will be removed from the child process's environment.
-
-If the .env member is NULL, `start_command` will point it at the
-.env_array `argv_array` (so you may use one or the other, but not both).
-The memory in .env_array will be cleaned up automatically during
-`finish_command` (or during `start_command` when it is unsuccessful).
-
-To specify a new initial working directory for the sub-process,
-specify it in the .dir member.
-
-If the program cannot be found, the functions return -1 and set
-errno to ENOENT. Normally, an error message is printed, but if
-.silent_exec_failure is set to 1, no message is printed for this
-special error condition.
-
-
-* `struct async`
-
-This describes a function to run asynchronously, whose purpose is
-to produce output that the caller reads.
-
-The caller:
-
-1. allocates and clears (memset(&asy, 0, sizeof(asy));) a
-   struct async variable;
-2. initializes .proc and .data;
-3. calls start_async();
-4. processes communicates with proc through .in and .out;
-5. closes .in and .out;
-6. calls finish_async().
-
-The members .in, .out are used to provide a set of fd's for
-communication between the caller and the callee as follows:
-
-. Specify 0 to have no file descriptor passed.  The callee will
-  receive -1 in the corresponding argument.
-
-. Specify < 0 to have a pipe allocated; start_async() replaces
-  with the pipe FD in the following way:
-
-	.in: Returns the writable pipe end into which the caller
-	writes; the readable end of the pipe becomes the function's
-	in argument.
-
-	.out: Returns the readable pipe end from which the caller
-	reads; the writable end of the pipe becomes the function's
-	out argument.
-
-  The caller of start_async() must close the returned FDs after it
-  has completed reading from/writing from them.
-
-. Specify a file descriptor > 0 to be used by the function:
-
-	.in: The FD must be readable; it becomes the function's in.
-	.out: The FD must be writable; it becomes the function's out.
-
-  The specified FD is closed by start_async(), even if it fails to
-  run the function.
-
-The function pointer in .proc has the following signature:
-
-	int proc(int in, int out, void *data);
-
-. in, out specifies a set of file descriptors to which the function
-  must read/write the data that it needs/produces.  The function
-  *must* close these descriptors before it returns.  A descriptor
-  may be -1 if the caller did not configure a descriptor for that
-  direction.
-
-. data is the value that the caller has specified in the .data member
-  of struct async.
-
-. The return value of the function is 0 on success and non-zero
-  on failure. If the function indicates failure, finish_async() will
-  report failure as well.
-
-
-There are serious restrictions on what the asynchronous function can do
-because this facility is implemented by a thread in the same address
-space on most platforms (when pthreads is available), but by a pipe to
-a forked process otherwise:
-
-. It cannot change the program's state (global variables, environment,
-  etc.) in a way that the caller notices; in other words, .in and .out
-  are the only communication channels to the caller.
-
-. It must not change the program's state that the caller of the
-  facility also uses.
diff --git a/Documentation/technical/api-setup.txt b/Documentation/technical/api-setup.txt
deleted file mode 100644
index eb1fa98..0000000
--- a/Documentation/technical/api-setup.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-setup API
-=========
-
-Talk about
-
-* setup_git_directory()
-* setup_git_directory_gently()
-* is_inside_git_dir()
-* is_inside_work_tree()
-* setup_work_tree()
-
-(Dscho)
-
-Pathspec
---------
-
-See glossary-context.txt for the syntax of pathspec. In memory, a
-pathspec set is represented by "struct pathspec" and is prepared by
-parse_pathspec(). This function takes several arguments:
-
-- magic_mask specifies what features that are NOT supported by the
-  following code. If a user attempts to use such a feature,
-  parse_pathspec() can reject it early.
-
-- flags specifies other things that the caller wants parse_pathspec to
-  perform.
-
-- prefix and args come from cmd_* functions
-
-parse_pathspec() helps catch unsupported features and reject them
-politely. At a lower level, different pathspec-related functions may
-not support the same set of features. Such pathspec-sensitive
-functions are guarded with GUARD_PATHSPEC(), which will die in an
-unfriendly way when an unsupported feature is requested.
-
-The command designers are supposed to make sure that GUARD_PATHSPEC()
-never dies. They have to make sure all unsupported features are caught
-by parse_pathspec(), not by GUARD_PATHSPEC. grepping GUARD_PATHSPEC()
-should give the designers all pathspec-sensitive codepaths and what
-features they support.
-
-A similar process is applied when a new pathspec magic is added. The
-designer lifts the GUARD_PATHSPEC restriction in the functions that
-support the new magic. At the same time (s)he has to make sure this
-new feature will be caught at parse_pathspec() in commands that cannot
-handle the new magic in some cases. grepping parse_pathspec() should
-help.
diff --git a/Documentation/technical/api-sigchain.txt b/Documentation/technical/api-sigchain.txt
deleted file mode 100644
index 9e1189e..0000000
--- a/Documentation/technical/api-sigchain.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-sigchain API
-============
-
-Code often wants to set a signal handler to clean up temporary files or
-other work-in-progress when we die unexpectedly. For multiple pieces of
-code to do this without conflicting, each piece of code must remember
-the old value of the handler and restore it either when:
-
-  1. The work-in-progress is finished, and the handler is no longer
-     necessary. The handler should revert to the original behavior
-     (either another handler, SIG_DFL, or SIG_IGN).
-
-  2. The signal is received. We should then do our cleanup, then chain
-     to the next handler (or die if it is SIG_DFL).
-
-Sigchain is a tiny library for keeping a stack of handlers. Your handler
-and installation code should look something like:
-
-------------------------------------------
-  void clean_foo_on_signal(int sig)
-  {
-	  clean_foo();
-	  sigchain_pop(sig);
-	  raise(sig);
-  }
-
-  void other_func()
-  {
-	  sigchain_push_common(clean_foo_on_signal);
-	  mess_up_foo();
-	  clean_foo();
-  }
-------------------------------------------
-
-Handlers are given the typedef of sigchain_fun. This is the same type
-that is given to signal() or sigaction(). It is perfectly reasonable to
-push SIG_DFL or SIG_IGN onto the stack.
-
-You can sigchain_push and sigchain_pop individual signals. For
-convenience, sigchain_push_common will push the handler onto the stack
-for many common signals.
diff --git a/Documentation/technical/api-submodule-config.txt b/Documentation/technical/api-submodule-config.txt
deleted file mode 100644
index fb06089..0000000
--- a/Documentation/technical/api-submodule-config.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-submodule config cache API
-==========================
-
-The submodule config cache API allows to read submodule
-configurations/information from specified revisions. Internally
-information is lazily read into a cache that is used to avoid
-unnecessary parsing of the same .gitmodules files. Lookups can be done by
-submodule path or name.
-
-Usage
------
-
-To initialize the cache with configurations from the worktree the caller
-typically first calls `gitmodules_config()` to read values from the
-worktree .gitmodules and then to overlay the local git config values
-`parse_submodule_config_option()` from the config parsing
-infrastructure.
-
-The caller can look up information about submodules by using the
-`submodule_from_path()` or `submodule_from_name()` functions. They return
-a `struct submodule` which contains the values. The API automatically
-initializes and allocates the needed infrastructure on-demand. If the
-caller does only want to lookup values from revisions the initialization
-can be skipped.
-
-If the internal cache might grow too big or when the caller is done with
-the API, all internally cached values can be freed with submodule_free().
-
-Data Structures
----------------
-
-`struct submodule`::
-
-	This structure is used to return the information about one
-	submodule for a certain revision. It is returned by the lookup
-	functions.
-
-Functions
----------
-
-`void submodule_free(struct repository *r)`::
-
-	Use these to free the internally cached values.
-
-`int parse_submodule_config_option(const char *var, const char *value)`::
-
-	Can be passed to the config parsing infrastructure to parse
-	local (worktree) submodule configurations.
-
-`const struct submodule *submodule_from_path(const unsigned char *treeish_name, const char *path)`::
-
-	Given a tree-ish in the superproject and a path, return the
-	submodule that is bound at the path in the named tree.
-
-`const struct submodule *submodule_from_name(const unsigned char *treeish_name, const char *name)`::
-
-	The same as above but lookup by name.
-
-Whenever a submodule configuration is parsed in `parse_submodule_config_option`
-via e.g. `gitmodules_config()`, it will overwrite the null_sha1 entry.
-So in the normal case, when HEAD:.gitmodules is parsed first and then overlayed
-with the repository configuration, the null_sha1 entry contains the local
-configuration of a submodule (e.g. consolidated values from local git
-configuration and the .gitmodules file in the worktree).
-
-For an example usage see test-submodule-config.c.
diff --git a/Documentation/technical/api-trace.txt b/Documentation/technical/api-trace.txt
deleted file mode 100644
index fadb597..0000000
--- a/Documentation/technical/api-trace.txt
+++ /dev/null
@@ -1,140 +0,0 @@
-trace API
-=========
-
-The trace API can be used to print debug messages to stderr or a file. Trace
-code is inactive unless explicitly enabled by setting `GIT_TRACE*` environment
-variables.
-
-The trace implementation automatically adds `timestamp file:line ... \n` to
-all trace messages. E.g.:
-
-------------
-23:59:59.123456 git.c:312               trace: built-in: git 'foo'
-00:00:00.000001 builtin/foo.c:99        foo: some message
-------------
-
-Data Structures
----------------
-
-`struct trace_key`::
-
-	Defines a trace key (or category). The default (for API functions that
-	don't take a key) is `GIT_TRACE`.
-+
-E.g. to define a trace key controlled by environment variable `GIT_TRACE_FOO`:
-+
-------------
-static struct trace_key trace_foo = TRACE_KEY_INIT(FOO);
-
-static void trace_print_foo(const char *message)
-{
-	trace_printf_key(&trace_foo, "%s", message);
-}
-------------
-+
-Note: don't use `const` as the trace implementation stores internal state in
-the `trace_key` structure.
-
-Functions
----------
-
-`int trace_want(struct trace_key *key)`::
-
-	Checks whether the trace key is enabled. Used to prevent expensive
-	string formatting before calling one of the printing APIs.
-
-`void trace_disable(struct trace_key *key)`::
-
-	Disables tracing for the specified key, even if the environment
-	variable was set.
-
-`void trace_printf(const char *format, ...)`::
-`void trace_printf_key(struct trace_key *key, const char *format, ...)`::
-
-	Prints a formatted message, similar to printf.
-
-`void trace_argv_printf(const char **argv, const char *format, ...)``::
-
-	Prints a formatted message, followed by a quoted list of arguments.
-
-`void trace_strbuf(struct trace_key *key, const struct strbuf *data)`::
-
-	Prints the strbuf, without additional formatting (i.e. doesn't
-	choke on `%` or even `\0`).
-
-`uint64_t getnanotime(void)`::
-
-	Returns nanoseconds since the epoch (01/01/1970), typically used
-	for performance measurements.
-+
-Currently there are high precision timer implementations for Linux (using
-`clock_gettime(CLOCK_MONOTONIC)`) and Windows (`QueryPerformanceCounter`).
-Other platforms use `gettimeofday` as time source.
-
-`void trace_performance(uint64_t nanos, const char *format, ...)`::
-`void trace_performance_since(uint64_t start, const char *format, ...)`::
-
-	Prints the elapsed time (in nanoseconds), or elapsed time since
-	`start`, followed by a formatted message. Enabled via environment
-	variable `GIT_TRACE_PERFORMANCE`. Used for manual profiling, e.g.:
-+
-------------
-uint64_t start = getnanotime();
-/* code section to measure */
-trace_performance_since(start, "foobar");
-------------
-+
-------------
-uint64_t t = 0;
-for (;;) {
-	/* ignore */
-	t -= getnanotime();
-	/* code section to measure */
-	t += getnanotime();
-	/* ignore */
-}
-trace_performance(t, "frotz");
-------------
-
-Bugs & Caveats
---------------
-
-GIT_TRACE_* environment variables can be used to tell Git to show
-trace output to its standard error stream. Git can often spawn a pager
-internally to run its subcommand and send its standard output and
-standard error to it.
-
-Because GIT_TRACE_PERFORMANCE trace is generated only at the very end
-of the program with atexit(), which happens after the pager exits, it
-would not work well if you send its log to the standard error output
-and let Git spawn the pager at the same time.
-
-As a work around, you can for example use '--no-pager', or set
-GIT_TRACE_PERFORMANCE to another file descriptor which is redirected
-to stderr, or set GIT_TRACE_PERFORMANCE to a file specified by its
-absolute path.
-
-For example instead of the following command which by default may not
-print any performance information:
-
-------------
-GIT_TRACE_PERFORMANCE=2 git log -1
-------------
-
-you may want to use:
-
-------------
-GIT_TRACE_PERFORMANCE=2 git --no-pager log -1
-------------
-
-or:
-
-------------
-GIT_TRACE_PERFORMANCE=3 3>&2 git log -1
-------------
-
-or:
-
-------------
-GIT_TRACE_PERFORMANCE=/path/to/log/file git log -1
-------------
diff --git a/Documentation/technical/api-trace2.txt b/Documentation/technical/api-trace2.txt
index a045dbe..4f07cea 100644
--- a/Documentation/technical/api-trace2.txt
+++ b/Documentation/technical/api-trace2.txt
@@ -178,7 +178,7 @@
 
 == Public API
 
-All Trace2 API functions send a messsage to all of the active
+All Trace2 API functions send a message to all of the active
 Trace2 Targets.  This section describes the set of available
 messages.
 
@@ -188,261 +188,36 @@
 === Basic Command Messages
 
 These are concerned with the lifetime of the overall git process.
-
-`void trace2_initialize_clock()`::
-
-	Initialize the Trace2 start clock and nothing else.  This should
-	be called at the very top of main() to capture the process start
-	time and reduce startup order dependencies.
-
-`void trace2_initialize()`::
-
-	Determines if any Trace2 Targets should be enabled and
-	initializes the Trace2 facility.  This includes setting up the
-	Trace2 thread local storage (TLS).
-+
-This function emits a "version" message containing the version of git
-and the Trace2 protocol.
-+
-This function should be called from `main()` as early as possible in
-the life of the process after essential process initialization.
-
-`int trace2_is_enabled()`::
-
-	Returns 1 if Trace2 is enabled (at least one target is
-	active).
-
-`void trace2_cmd_start(int argc, const char **argv)`::
-
-	Emits a "start" message containing the process command line
-	arguments.
-
-`int trace2_cmd_exit(int exit_code)`::
-
-	Emits an "exit" message containing the process exit-code and
-	elapsed time.
-+
-Returns the exit-code.
-
-`void trace2_cmd_error(const char *fmt, va_list ap)`::
-
-	Emits an "error" message containing a formatted error message.
-
-`void trace2_cmd_path(const char *pathname)`::
-
-	Emits a "cmd_path" message with the full pathname of the
-	current process.
+e.g: `void trace2_initialize_clock()`, `void trace2_initialize()`,
+`int trace2_is_enabled()`, `void trace2_cmd_start(int argc, const char **argv)`.
 
 === Command Detail Messages
 
 These are concerned with describing the specific Git command
 after the command line, config, and environment are inspected.
-
-`void trace2_cmd_name(const char *name)`::
-
-	Emits a "cmd_name" message with the canonical name of the
-	command, for example "status" or "checkout".
-
-`void trace2_cmd_mode(const char *mode)`::
-
-	Emits a "cmd_mode" message with a qualifier name to further
-	describe the current git command.
-+
-This message is intended to be used with git commands having multiple
-major modes.  For example, a "checkout" command can checkout a new
-branch or it can checkout a single file, so the checkout code could
-emit a cmd_mode message of "branch" or "file".
-
-`void trace2_cmd_alias(const char *alias, const char **argv_expansion)`::
-
-	Emits an "alias" message containing the alias used and the
-	argument expansion.
-
-`void trace2_def_param(const char *parameter, const char *value)`::
-
-	Emits a "def_param" message containing a key/value pair.
-+
-This message is intended to report some global aspect of the current
-command, such as a configuration setting or command line switch that
-significantly affects program performance or behavior, such as
-`core.abbrev`, `status.showUntrackedFiles`, or `--no-ahead-behind`.
-
-`void trace2_cmd_list_config()`::
-
-	Emits a "def_param" messages for "important" configuration
-	settings.
-+
-The environment variable `GIT_TRACE2_CONFIG_PARAMS` or the `trace2.configParams`
-config value can be set to a
-list of patterns of important configuration settings, for example:
-`core.*,remote.*.url`.  This function will iterate over all config
-settings and emit a "def_param" message for each match.
-
-`void trace2_cmd_set_config(const char *key, const char *value)`::
-
-	Emits a "def_param" message for a new or updated key/value
-	pair IF `key` is considered important.
-+
-This is used to hook into `git_config_set()` and catch any
-configuration changes and update a value previously reported by
-`trace2_cmd_list_config()`.
-
-`void trace2_def_repo(struct repository *repo)`::
-
-	Registers a repository with the Trace2 layer.  Assigns a
-	unique "repo-id" to `repo->trace2_repo_id`.
-+
-Emits a "worktree" messages containing the repo-id and the worktree
-pathname.
-+
-Region and data messages (described later) may refer to this repo-id.
-+
-The main/top-level repository will have repo-id value 1 (aka "r1").
-+
-The repo-id field is in anticipation of future in-proc submodule
-repositories.
+e.g: `void trace2_cmd_name(const char *name)`,
+`void trace2_cmd_mode(const char *mode)`.
 
 === Child Process Messages
 
 These are concerned with the various spawned child processes,
 including shell scripts, git commands, editors, pagers, and hooks.
 
-`void trace2_child_start(struct child_process *cmd)`::
-
-	Emits a "child_start" message containing the "child-id",
-	"child-argv", and "child-classification".
-+
-Before calling this, set `cmd->trace2_child_class` to a name
-describing the type of child process, for example "editor".
-+
-This function assigns a unique "child-id" to `cmd->trace2_child_id`.
-This field is used later during the "child_exit" message to associate
-it with the "child_start" message.
-+
-This function should be called before spawning the child process.
-
-`void trace2_child_exit(struct child_proess *cmd, int child_exit_code)`::
-
-	Emits a "child_exit" message containing the "child-id",
-	the child's elapsed time and exit-code.
-+
-The reported elapsed time includes the process creation overhead and
-time spend waiting for it to exit, so it may be slightly longer than
-the time reported by the child itself.
-+
-This function should be called after reaping the child process.
-
-`int trace2_exec(const char *exe, const char **argv)`::
-
-	Emits a "exec" message containing the "exec-id" and the
-	argv of the new process.
-+
-This function should be called before calling one of the `exec()`
-variants, such as `execvp()`.
-+
-This function returns a unique "exec-id".  This value is used later
-if the exec() fails and a "exec-result" message is necessary.
-
-`void trace2_exec_result(int exec_id, int error_code)`::
-
-	Emits a "exec_result" message containing the "exec-id"
-	and the error code.
-+
-On Unix-based systems, `exec()` does not return if successful.
-This message is used to indicate that the `exec()` failed and
-that the current program is continuing.
+e.g: `void trace2_child_start(struct child_process *cmd)`.
 
 === Git Thread Messages
 
 These messages are concerned with Git thread usage.
 
-`void trace2_thread_start(const char *thread_name)`::
-
-	Emits a "thread_start" message.
-+
-The `thread_name` field should be a descriptive name, such as the
-unique name of the thread-proc.  A unique "thread-id" will be added
-to the name to uniquely identify thread instances.
-+
-Region and data messages (described later) may refer to this thread
-name.
-+
-This function must be called by the thread-proc of the new thread
-(so that TLS data is properly initialized) and not by the caller
-of `pthread_create()`.
-
-`void trace2_thread_exit()`::
-
-	Emits a "thread_exit" message containing the thread name
-	and the thread elapsed time.
-+
-This function must be called by the thread-proc before it returns
-(so that the coorect TLS data is used and cleaned up.  It should
-not be called by the caller of `pthread_join()`.
+e.g: `void trace2_thread_start(const char *thread_name)`.
 
 === Region and Data Messages
 
 These are concerned with recording performance data
-over regions or spans of code.
+over regions or spans of code. e.g:
+`void trace2_region_enter(const char *category, const char *label, const struct repository *repo)`.
 
-`void trace2_region_enter(const char *category, const char *label, const struct repository *repo)`::
-
-`void trace2_region_enter_printf(const char *category, const char *label, const struct repository *repo, const char *fmt, ...)`::
-
-`void trace2_region_enter_printf_va(const char *category, const char *label, const struct repository *repo, const char *fmt, va_list ap)`::
-
-	Emits a thread-relative "region_enter" message with optional
-	printf string.
-+
-This function pushes a new region nesting stack level on the current
-thread and starts a clock for the new stack frame.
-+
-The `category` field is an arbitrary category name used to classify
-regions by feature area, such as "status" or "index".  At this time
-it is only just printed along with the rest of the message.  It may
-be used in the future to filter messages.
-+
-The `label` field is an arbitrary label used to describe the activity
-being started, such as "read_recursive" or "do_read_index".
-+
-The `repo` field, if set, will be used to get the "repo-id", so that
-recursive oerations can be attributed to the correct repository.
-
-`void trace2_region_leave(const char *category, const char *label, const struct repository *repo)`::
-
-`void trace2_region_leave_printf(const char *category, const char *label, const struct repository *repo, const char *fmt, ...)`::
-
-`void trace2_region_leave_printf_va(const char *category, const char *label, const struct repository *repo, const char *fmt, va_list ap)`::
-
-	Emits a thread-relative "region_leave" message with optional
-	printf string.
-+
-This function pops the region nesting stack on the current thread
-and reports the elapsed time of the stack frame.
-+
-The `category`, `label`, and `repo` fields are the same as above.
-The `category` and `label` do not need to match the correpsonding
-"region_enter" message, but it makes the data stream easier to
-understand.
-
-`void trace2_data_string(const char *category, const struct repository *repo, const char *key, const char * value)`::
-
-`void trace2_data_intmax(const char *category, const struct repository *repo, const char *key, intmax value)`::
-
-`void trace2_data_json(const char *category, const struct repository *repo, const char *key, const struct json_writer *jw)`::
-
-	Emits a region- and thread-relative "data" or "data_json" message.
-+
-This is a key/value pair message containing information about the
-current thread, region stack, and repository.  This could be used
-to print the number of files in a directory during a multi-threaded
-recursive tree walk.
-
-`void trace2_printf(const char *fmt, ...)`::
-
-`void trace2_printf_va(const char *fmt, va_list ap)`::
-
-	Emits a region- and thread-relative "printf" message.
+Refer to trace2.h for details about all trace2 functions.
 
 == Trace2 Target Formats
 
@@ -816,7 +591,7 @@
 Note that the session-id of the child process is not available to
 the current/spawning process, so the child's PID is reported here as
 a hint for post-processing.  (But it is only a hint because the child
-proces may be a shell script which doesn't have a session-id.)
+process may be a shell script which doesn't have a session-id.)
 +
 Note that the `t_rel` field contains the observed run time in seconds
 for the child process (starting before the fork/exec/spawn and
@@ -1176,7 +951,7 @@
 +
 Regions may be nested.  This causes messages to be indented in the
 PERF target, for example.
-Elapsed times are relative to the start of the correpsonding nesting
+Elapsed times are relative to the start of the corresponding nesting
 level as expected.  For example, if we add region message to:
 +
 ----------------
@@ -1371,7 +1146,7 @@
 In this example, the preload region took 0.009122 seconds.  The 7 threads
 took between 0.006069 and 0.008947 seconds to work on their portion of
 the index.  Thread "th01" worked on 508 items at offset 0.  Thread "th02"
-worked on 508 items at offset 2032.  Thread "th04" worked on 508 itemts
+worked on 508 items at offset 2032.  Thread "th04" worked on 508 items
 at offset 508.
 +
 This example also shows that thread names are assigned in a racy manner
diff --git a/Documentation/technical/api-tree-walking.txt b/Documentation/technical/api-tree-walking.txt
deleted file mode 100644
index 7962e32..0000000
--- a/Documentation/technical/api-tree-walking.txt
+++ /dev/null
@@ -1,149 +0,0 @@
-tree walking API
-================
-
-The tree walking API is used to traverse and inspect trees.
-
-Data Structures
----------------
-
-`struct name_entry`::
-
-	An entry in a tree. Each entry has a sha1 identifier, pathname, and
-	mode.
-
-`struct tree_desc`::
-
-	A semi-opaque data structure used to maintain the current state of the
-	walk.
-+
-* `buffer` is a pointer into the memory representation of the tree. It always
-points at the current entry being visited.
-
-* `size` counts the number of bytes left in the `buffer`.
-
-* `entry` points to the current entry being visited.
-
-`struct traverse_info`::
-
-	A structure used to maintain the state of a traversal.
-+
-* `prev` points to the traverse_info which was used to descend into the
-current tree. If this is the top-level tree `prev` will point to
-a dummy traverse_info.
-
-* `name` is the entry for the current tree (if the tree is a subtree).
-
-* `pathlen` is the length of the full path for the current tree.
-
-* `conflicts` can be used by callbacks to maintain directory-file conflicts.
-
-* `fn` is a callback called for each entry in the tree. See Traversing for more
-information.
-
-* `data` can be anything the `fn` callback would want to use.
-
-* `show_all_errors` tells whether to stop at the first error or not.
-
-Initializing
-------------
-
-`init_tree_desc`::
-
-	Initialize a `tree_desc` and decode its first entry. The buffer and
-	size parameters are assumed to be the same as the buffer and size
-	members of `struct tree`.
-
-`fill_tree_descriptor`::
-
-	Initialize a `tree_desc` and decode its first entry given the
-	object ID of a tree. Returns the `buffer` member if the latter
-	is a valid tree identifier and NULL otherwise.
-
-`setup_traverse_info`::
-
-	Initialize a `traverse_info` given the pathname of the tree to start
-	traversing from.
-
-Walking
--------
-
-`tree_entry`::
-
-	Visit the next entry in a tree. Returns 1 when there are more entries
-	left to visit and 0 when all entries have been visited. This is
-	commonly used in the test of a while loop.
-
-`tree_entry_len`::
-
-	Calculate the length of a tree entry's pathname. This utilizes the
-	memory structure of a tree entry to avoid the overhead of using a
-	generic strlen().
-
-`update_tree_entry`::
-
-	Walk to the next entry in a tree. This is commonly used in conjunction
-	with `tree_entry_extract` to inspect the current entry.
-
-`tree_entry_extract`::
-
-	Decode the entry currently being visited (the one pointed to by
-	`tree_desc's` `entry` member) and return the sha1 of the entry. The
-	`pathp` and `modep` arguments are set to the entry's pathname and mode
-	respectively.
-
-`get_tree_entry`::
-
-	Find an entry in a tree given a pathname and the sha1 of a tree to
-	search. Returns 0 if the entry is found and -1 otherwise. The third
-	and fourth parameters are set to the entry's sha1 and mode
-	respectively.
-
-Traversing
-----------
-
-`traverse_trees`::
-
-	Traverse `n` number of trees in parallel. The `fn` callback member of
-	`traverse_info` is called once for each tree entry.
-
-`traverse_callback_t`::
-	The arguments passed to the traverse callback are as follows:
-+
-* `n` counts the number of trees being traversed.
-
-* `mask` has its nth bit set if something exists in the nth entry.
-
-* `dirmask` has its nth bit set if the nth tree's entry is a directory.
-
-* `entry` is an array of size `n` where the nth entry is from the nth tree.
-
-* `info` maintains the state of the traversal.
-
-+
-Returning a negative value will terminate the traversal. Otherwise the
-return value is treated as an update mask. If the nth bit is set the nth tree
-will be updated and if the bit is not set the nth tree entry will be the
-same in the next callback invocation.
-
-`make_traverse_path`::
-
-	Generate the full pathname of a tree entry based from the root of the
-	traversal. For example, if the traversal has recursed into another
-	tree named "bar" the pathname of an entry "baz" in the "bar"
-	tree would be "bar/baz".
-
-`traverse_path_len`::
-
-	Calculate the length of a pathname returned by `make_traverse_path`.
-	This utilizes the memory structure of a tree entry to avoid the
-	overhead of using a generic strlen().
-
-`strbuf_make_traverse_path`::
-
-	Convenience wrapper to `make_traverse_path` into a strbuf.
-
-Authors
--------
-
-Written by Junio C Hamano <gitster@pobox.com> and Linus Torvalds
-<torvalds@linux-foundation.org>
diff --git a/Documentation/technical/commit-graph.txt b/Documentation/technical/commit-graph.txt
index 729fbcb..808fa30 100644
--- a/Documentation/technical/commit-graph.txt
+++ b/Documentation/technical/commit-graph.txt
@@ -22,11 +22,11 @@
 directory of an alternate.
 
 The commit-graph file stores the commit graph structure along with some
-extra metadata to speed up graph walks. By listing commit OIDs in lexi-
-cographic order, we can identify an integer position for each commit and
-refer to the parents of a commit using those integer positions. We use
-binary search to find initial commits and then use the integer positions
-for fast lookups during the walk.
+extra metadata to speed up graph walks. By listing commit OIDs in
+lexicographic order, we can identify an integer position for each commit
+and refer to the parents of a commit using those integer positions. We
+use binary search to find initial commits and then use the integer
+positions for fast lookups during the walk.
 
 A consumer may load the following info for a commit from the graph:
 
@@ -85,7 +85,7 @@
 Since the commit-graph file is closed under reachability, we can guarantee
 the following weaker condition on all commits:
 
-    If A and B are commits with generation numbers N amd M, respectively,
+    If A and B are commits with generation numbers N and M, respectively,
     and N < M, then A cannot reach B.
 
 Note how the strict inequality differs from the inequality when we have
@@ -323,14 +323,14 @@
 [0] https://bugs.chromium.org/p/git/issues/detail?id=8
     Chromium work item for: Serialized Commit Graph
 
-[1] https://public-inbox.org/git/20110713070517.GC18566@sigill.intra.peff.net/
+[1] https://lore.kernel.org/git/20110713070517.GC18566@sigill.intra.peff.net/
     An abandoned patch that introduced generation numbers.
 
-[2] https://public-inbox.org/git/20170908033403.q7e6dj7benasrjes@sigill.intra.peff.net/
+[2] https://lore.kernel.org/git/20170908033403.q7e6dj7benasrjes@sigill.intra.peff.net/
     Discussion about generation numbers on commits and how they interact
     with fsck.
 
-[3] https://public-inbox.org/git/20170908034739.4op3w4f2ma5s65ku@sigill.intra.peff.net/
+[3] https://lore.kernel.org/git/20170908034739.4op3w4f2ma5s65ku@sigill.intra.peff.net/
     More discussion about generation numbers and not storing them inside
     commit objects. A valuable quote:
 
@@ -342,9 +342,9 @@
      commit objects (i.e., packv4 or something like the "metapacks" I
      proposed a few years ago)."
 
-[4] https://public-inbox.org/git/20180108154822.54829-1-git@jeffhostetler.com/T/#u
+[4] https://lore.kernel.org/git/20180108154822.54829-1-git@jeffhostetler.com/T/#u
     A patch to remove the ahead-behind calculation from 'status'.
 
-[5] https://public-inbox.org/git/f27db281-abad-5043-6d71-cbb083b1c877@gmail.com/
+[5] https://lore.kernel.org/git/f27db281-abad-5043-6d71-cbb083b1c877@gmail.com/
     A discussion of a "two-dimensional graph position" that can allow reading
     multiple commit-graph chains at the same time.
diff --git a/Documentation/technical/hash-function-transition.txt b/Documentation/technical/hash-function-transition.txt
index 2ae8fa4..5b2db3b 100644
--- a/Documentation/technical/hash-function-transition.txt
+++ b/Documentation/technical/hash-function-transition.txt
@@ -531,7 +531,7 @@
 on public-facing Git servers is strongly discouraged. Once Git
 protocol gains SHA-256 support, SHA-256 based servers are likely not
 to support SHA-1 compatibility, to avoid what may be a very expensive
-hash reencode during clone and to encourage peers to modernize.
+hash re-encode during clone and to encourage peers to modernize.
 
 The design described here allows fetches by SHA-1 clients of a
 personal SHA-256 repository because it's not much more difficult than
@@ -602,7 +602,7 @@
 
 Choice of Hash
 --------------
-In early 2005, around the time that Git was written,  Xiaoyun Wang,
+In early 2005, around the time that Git was written, Xiaoyun Wang,
 Yiqun Lisa Yin, and Hongbo Yu announced an attack finding SHA-1
 collisions in 2^69 operations. In August they published details.
 Luckily, no practical demonstrations of a collision in full SHA-1 were
@@ -730,7 +730,7 @@
 
 Using hash functions in parallel
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-(e.g. https://public-inbox.org/git/22708.8913.864049.452252@chiark.greenend.org.uk/ )
+(e.g. https://lore.kernel.org/git/22708.8913.864049.452252@chiark.greenend.org.uk/ )
 Objects newly created would be addressed by the new hash, but inside
 such an object (e.g. commit) it is still possible to address objects
 using the old hash function.
@@ -783,7 +783,7 @@
 sbeller@google.com
 
 Initial version sent to
-http://public-inbox.org/git/20170304011251.GA26789@aiede.mtv.corp.google.com
+http://lore.kernel.org/git/20170304011251.GA26789@aiede.mtv.corp.google.com
 
 2017-03-03 jrnieder@gmail.com
 Incorporated suggestions from jonathantanmy and sbeller:
@@ -820,8 +820,8 @@
  edits. This document history is no longer being maintained as it
  would now be superfluous to the commit log
 
-[1] http://public-inbox.org/git/CA+55aFzJtejiCjV0e43+9oR3QuJK2PiFiLQemytoLpyJWe6P9w@mail.gmail.com/
-[2] http://public-inbox.org/git/CA+55aFz+gkAsDZ24zmePQuEs1XPS9BP_s8O7Q4wQ7LV7X5-oDA@mail.gmail.com/
-[3] http://public-inbox.org/git/20170306084353.nrns455dvkdsfgo5@sigill.intra.peff.net/
-[4] http://public-inbox.org/git/20170304224936.rqqtkdvfjgyezsht@genre.crustytoothpaste.net
-[5] https://public-inbox.org/git/CAJo=hJtoX9=AyLHHpUJS7fueV9ciZ_MNpnEPHUz8Whui6g9F0A@mail.gmail.com/
+[1] http://lore.kernel.org/git/CA+55aFzJtejiCjV0e43+9oR3QuJK2PiFiLQemytoLpyJWe6P9w@mail.gmail.com/
+[2] http://lore.kernel.org/git/CA+55aFz+gkAsDZ24zmePQuEs1XPS9BP_s8O7Q4wQ7LV7X5-oDA@mail.gmail.com/
+[3] http://lore.kernel.org/git/20170306084353.nrns455dvkdsfgo5@sigill.intra.peff.net/
+[4] http://lore.kernel.org/git/20170304224936.rqqtkdvfjgyezsht@genre.crustytoothpaste.net
+[5] https://lore.kernel.org/git/CAJo=hJtoX9=AyLHHpUJS7fueV9ciZ_MNpnEPHUz8Whui6g9F0A@mail.gmail.com/
diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt
index 7c4d67a..faa25c5 100644
--- a/Documentation/technical/index-format.txt
+++ b/Documentation/technical/index-format.txt
@@ -318,7 +318,7 @@
 == End of Index Entry
 
   The End of Index Entry (EOIE) is used to locate the end of the variable
-  length index entries and the begining of the extensions. Code can take
+  length index entries and the beginning of the extensions. Code can take
   advantage of this to quickly locate the index extensions without having
   to parse through all of the index entries.
 
@@ -351,7 +351,7 @@
 
   - A number of index offset entries each consisting of:
 
-    - 32-bit offset from the begining of the file to the first cache entry
+    - 32-bit offset from the beginning of the file to the first cache entry
 	in this block of entries.
 
     - 32-bit count of cache entries in this block
diff --git a/Documentation/technical/multi-pack-index.txt b/Documentation/technical/multi-pack-index.txt
index d7e5763..1e31239 100644
--- a/Documentation/technical/multi-pack-index.txt
+++ b/Documentation/technical/multi-pack-index.txt
@@ -102,8 +102,8 @@
 [0] https://bugs.chromium.org/p/git/issues/detail?id=6
     Chromium work item for: Multi-Pack Index (MIDX)
 
-[1] https://public-inbox.org/git/20180107181459.222909-1-dstolee@microsoft.com/
+[1] https://lore.kernel.org/git/20180107181459.222909-1-dstolee@microsoft.com/
     An earlier RFC for the multi-pack-index feature
 
-[2] https://public-inbox.org/git/alpine.DEB.2.20.1803091557510.23109@alexmv-linux/
+[2] https://lore.kernel.org/git/alpine.DEB.2.20.1803091557510.23109@alexmv-linux/
     Git Merge 2018 Contributor's summit notes (includes discussion of MIDX)
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index c73e72d..d5ce4ee 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -644,7 +644,7 @@
   command-ok        = PKT-LINE("ok" SP refname)
   command-fail      = PKT-LINE("ng" SP refname SP error-msg)
 
-  error-msg         = 1*(OCTECT) ; where not "ok"
+  error-msg         = 1*(OCTET) ; where not "ok"
 ----
 
 Updates can be unsuccessful for a number of reasons.  The reference can have
diff --git a/Documentation/technical/partial-clone.txt b/Documentation/technical/partial-clone.txt
index 210373e..b9e17e7 100644
--- a/Documentation/technical/partial-clone.txt
+++ b/Documentation/technical/partial-clone.txt
@@ -32,7 +32,7 @@
 
 A remote that can later provide the missing objects is called a
 promisor remote, as it promises to send the objects when
-requested. Initialy Git supported only one promisor remote, the origin
+requested. Initially Git supported only one promisor remote, the origin
 remote from which the user cloned and that was configured in the
 "extensions.partialClone" config option. Later support for more than
 one promisor remote has been implemented.
@@ -350,26 +350,26 @@
 [0] https://crbug.com/git/2
     Bug#2: Partial Clone
 
-[1] https://public-inbox.org/git/20170113155253.1644-1-benpeart@microsoft.com/ +
+[1] https://lore.kernel.org/git/20170113155253.1644-1-benpeart@microsoft.com/ +
     Subject: [RFC] Add support for downloading blobs on demand +
     Date: Fri, 13 Jan 2017 10:52:53 -0500
 
-[2] https://public-inbox.org/git/cover.1506714999.git.jonathantanmy@google.com/ +
+[2] https://lore.kernel.org/git/cover.1506714999.git.jonathantanmy@google.com/ +
     Subject: [PATCH 00/18] Partial clone (from clone to lazy fetch in 18 patches) +
     Date: Fri, 29 Sep 2017 13:11:36 -0700
 
-[3] https://public-inbox.org/git/20170426221346.25337-1-jonathantanmy@google.com/ +
+[3] https://lore.kernel.org/git/20170426221346.25337-1-jonathantanmy@google.com/ +
     Subject: Proposal for missing blob support in Git repos +
     Date: Wed, 26 Apr 2017 15:13:46 -0700
 
-[4] https://public-inbox.org/git/1488999039-37631-1-git-send-email-git@jeffhostetler.com/ +
+[4] https://lore.kernel.org/git/1488999039-37631-1-git-send-email-git@jeffhostetler.com/ +
     Subject: [PATCH 00/10] RFC Partial Clone and Fetch +
     Date: Wed,  8 Mar 2017 18:50:29 +0000
 
-[5] https://public-inbox.org/git/20170505152802.6724-1-benpeart@microsoft.com/ +
+[5] https://lore.kernel.org/git/20170505152802.6724-1-benpeart@microsoft.com/ +
     Subject: [PATCH v7 00/10] refactor the filter process code into a reusable module +
     Date: Fri,  5 May 2017 11:27:52 -0400
 
-[6] https://public-inbox.org/git/20170714132651.170708-1-benpeart@microsoft.com/ +
+[6] https://lore.kernel.org/git/20170714132651.170708-1-benpeart@microsoft.com/ +
     Subject: [RFC/PATCH v2 0/1] Add support for downloading blobs on demand +
     Date: Fri, 14 Jul 2017 09:26:50 -0400
diff --git a/Documentation/technical/protocol-v2.txt b/Documentation/technical/protocol-v2.txt
index 40f91f6..7e3766c 100644
--- a/Documentation/technical/protocol-v2.txt
+++ b/Documentation/technical/protocol-v2.txt
@@ -252,7 +252,7 @@
     ofs-delta
 	Indicate that the client understands PACKv2 with delta referring
 	to its base by position in pack rather than by an oid.  That is,
-	they can read OBJ_OFS_DELTA (ake type 6) in a packfile.
+	they can read OBJ_OFS_DELTA (aka type 6) in a packfile.
 
 If the 'shallow' feature is advertised the following arguments can be
 included in the clients request as well as the potential addition of the
diff --git a/Documentation/technical/racy-git.txt b/Documentation/technical/racy-git.txt
index 4a8be4d..ceda4bb 100644
--- a/Documentation/technical/racy-git.txt
+++ b/Documentation/technical/racy-git.txt
@@ -51,7 +51,7 @@
 only fixes the issue for file systems with exactly 1 ns or 1 s
 resolution. Other file systems are still broken in current Linux
 kernels (e.g. CEPH, CIFS, NTFS, UDF), see
-https://lkml.org/lkml/2015/6/9/714
+https://lore.kernel.org/lkml/5577240D.7020309@gmail.com/
 
 Racy Git
 --------
diff --git a/Documentation/technical/rerere.txt b/Documentation/technical/rerere.txt
index aa22d7a..af5f9fc 100644
--- a/Documentation/technical/rerere.txt
+++ b/Documentation/technical/rerere.txt
@@ -117,7 +117,7 @@
 4 combinations of ("B or C", "C or B") x ("X or Y", "Y or X").
 
 By sorting, the conflict is given its canonical name, namely, "an
-early part became B or C, a late part becames X or Y", and whenever
+early part became B or C, a late part became X or Y", and whenever
 any of these four patterns appear, and we can get to the same conflict
 and resolution that we saw earlier.
 
diff --git a/Documentation/urls.txt b/Documentation/urls.txt
index bc354fe..1c229d7 100644
--- a/Documentation/urls.txt
+++ b/Documentation/urls.txt
@@ -53,6 +53,9 @@
 --local option.
 endif::git-clone[]
 
+'git clone', 'git fetch' and 'git pull', but not 'git push', will also
+accept a suitable bundle file. See linkgit:git-bundle[1].
+
 When Git doesn't know how to handle a certain transport protocol, it
 attempts to use the 'remote-<transport>' remote helper, if one
 exists. To explicitly request a remote helper, the following syntax
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index 06bd899..8336529 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -4574,5 +4574,5 @@
 Alternates, clone -reference, etc.
 
 More on recovery from repository corruption.  See:
-	http://marc.info/?l=git&m=117263864820799&w=2
-	http://marc.info/?l=git&m=117147855503798&w=2
+	https://lore.kernel.org/git/Pine.LNX.4.64.0702272039540.12485@woody.linux-foundation.org/
+	https://lore.kernel.org/git/Pine.LNX.4.64.0702141033400.3604@woody.linux-foundation.org/
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 22e8d83..5867391 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.24.GIT
+DEF_VER=v2.25.0-rc1
 
 LF='
 '
diff --git a/INSTALL b/INSTALL
index c39006e..22c364f 100644
--- a/INSTALL
+++ b/INSTALL
@@ -109,15 +109,15 @@
 
  - Git is reasonably self-sufficient, but does depend on a few external
    programs and libraries.  Git can be used without most of them by adding
-   the approriate "NO_<LIBRARY>=YesPlease" to the make command line or
+   the appropriate "NO_<LIBRARY>=YesPlease" to the make command line or
    config.mak file.
 
 	- "zlib", the compression library. Git won't build without it.
 
 	- "ssh" is used to push and pull over the net.
 
-	- A POSIX-compliant shell is required to run many scripts needed
-	  for everyday use (e.g. "bisect", "pull").
+	- A POSIX-compliant shell is required to run some scripts needed
+	  for everyday use (e.g. "bisect", "request-pull").
 
 	- "Perl" version 5.8 or later is needed to use some of the
 	  features (e.g. preparing a partial commit using "git add -i/-p",
diff --git a/Makefile b/Makefile
index 254b07a..09f98b7 100644
--- a/Makefile
+++ b/Makefile
@@ -481,7 +481,7 @@
 #
 # When DEVELOPER is set, DEVOPTS can be used to control compiler
 # options.  This variable contains keywords separated by
-# whitespace. The following keywords are are recognized:
+# whitespace. The following keywords are recognized:
 #
 #    no-error:
 #
@@ -727,6 +727,7 @@
 TEST_BUILTINS_OBJS += test-progress.o
 TEST_BUILTINS_OBJS += test-reach.o
 TEST_BUILTINS_OBJS += test-read-cache.o
+TEST_BUILTINS_OBJS += test-read-graph.o
 TEST_BUILTINS_OBJS += test-read-midx.o
 TEST_BUILTINS_OBJS += test-ref-store.o
 TEST_BUILTINS_OBJS += test-regex.o
@@ -823,6 +824,8 @@
 	-name '*.h' -print)))
 
 LIB_OBJS += abspath.o
+LIB_OBJS += add-interactive.o
+LIB_OBJS += add-patch.o
 LIB_OBJS += advice.o
 LIB_OBJS += alias.o
 LIB_OBJS += alloc.o
@@ -2778,8 +2781,7 @@
 .PHONY: sparse $(SP_OBJ)
 sparse: $(SP_OBJ)
 
-GEN_HDRS := command-list.h unicode-width.h
-EXCEPT_HDRS := $(GEN_HDRS) compat/% xdiff/%
+EXCEPT_HDRS := command-list.h unicode-width.h compat/% xdiff/%
 ifndef GCRYPT_SHA256
 	EXCEPT_HDRS += sha256/gcrypt.h
 endif
@@ -3104,7 +3106,7 @@
 	$(RM) $(HCC)
 	$(RM) -r bin-wrappers $(dep_dirs)
 	$(RM) -r po/build/
-	$(RM) *.pyc *.pyo */*.pyc */*.pyo command-list.h $(ETAGS_TARGET) tags cscope*
+	$(RM) *.pyc *.pyo */*.pyc */*.pyo $(GENERATED_H) $(ETAGS_TARGET) tags cscope*
 	$(RM) -r $(GIT_TARNAME) .doc-tmp-dir
 	$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
 	$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
diff --git a/README.md b/README.md
index e1d2b82..9d4564c 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,7 @@
 [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 <https://public-inbox.org/git/>,
+available at <https://lore.kernel.org/git/>,
 <http://marc.info/?l=git> and other archival sites.
 
 Issues which are security relevant should be disclosed privately to
diff --git a/add-interactive.c b/add-interactive.c
new file mode 100644
index 0000000..6a5048c
--- /dev/null
+++ b/add-interactive.c
@@ -0,0 +1,1154 @@
+#include "cache.h"
+#include "add-interactive.h"
+#include "color.h"
+#include "config.h"
+#include "diffcore.h"
+#include "revision.h"
+#include "refs.h"
+#include "string-list.h"
+#include "lockfile.h"
+#include "dir.h"
+#include "run-command.h"
+
+static void init_color(struct repository *r, struct add_i_state *s,
+		       const char *slot_name, char *dst,
+		       const char *default_color)
+{
+	char *key = xstrfmt("color.interactive.%s", slot_name);
+	const char *value;
+
+	if (!s->use_color)
+		dst[0] = '\0';
+	else if (repo_config_get_value(r, key, &value) ||
+		 color_parse(value, dst))
+		strlcpy(dst, default_color, COLOR_MAXLEN);
+
+	free(key);
+}
+
+void init_add_i_state(struct add_i_state *s, struct repository *r)
+{
+	const char *value;
+
+	s->r = r;
+
+	if (repo_config_get_value(r, "color.interactive", &value))
+		s->use_color = -1;
+	else
+		s->use_color =
+			git_config_colorbool("color.interactive", value);
+	s->use_color = want_color(s->use_color);
+
+	init_color(r, s, "header", s->header_color, GIT_COLOR_BOLD);
+	init_color(r, s, "help", s->help_color, GIT_COLOR_BOLD_RED);
+	init_color(r, s, "prompt", s->prompt_color, GIT_COLOR_BOLD_BLUE);
+	init_color(r, s, "error", s->error_color, GIT_COLOR_BOLD_RED);
+	init_color(r, s, "reset", s->reset_color, GIT_COLOR_RESET);
+	init_color(r, s, "fraginfo", s->fraginfo_color,
+		   diff_get_color(s->use_color, DIFF_FRAGINFO));
+	init_color(r, s, "context", s->context_color,
+		diff_get_color(s->use_color, DIFF_CONTEXT));
+	init_color(r, s, "old", s->file_old_color,
+		diff_get_color(s->use_color, DIFF_FILE_OLD));
+	init_color(r, s, "new", s->file_new_color,
+		diff_get_color(s->use_color, DIFF_FILE_NEW));
+}
+
+/*
+ * A "prefix item list" is a list of items that are identified by a string, and
+ * a unique prefix (if any) is determined for each item.
+ *
+ * It is implemented in the form of a pair of `string_list`s, the first one
+ * duplicating the strings, with the `util` field pointing at a structure whose
+ * first field must be `size_t prefix_length`.
+ *
+ * That `prefix_length` field will be computed by `find_unique_prefixes()`; It
+ * will be set to zero if no valid, unique prefix could be found.
+ *
+ * The second `string_list` is called `sorted` and does _not_ duplicate the
+ * strings but simply reuses the first one's, with the `util` field pointing at
+ * the `string_item_list` of the first `string_list`. It  will be populated and
+ * sorted by `find_unique_prefixes()`.
+ */
+struct prefix_item_list {
+	struct string_list items;
+	struct string_list sorted;
+	int *selected; /* for multi-selections */
+	size_t min_length, max_length;
+};
+#define PREFIX_ITEM_LIST_INIT \
+	{ STRING_LIST_INIT_DUP, STRING_LIST_INIT_NODUP, NULL, 1, 4 }
+
+static void prefix_item_list_clear(struct prefix_item_list *list)
+{
+	string_list_clear(&list->items, 1);
+	string_list_clear(&list->sorted, 0);
+	FREE_AND_NULL(list->selected);
+}
+
+static void extend_prefix_length(struct string_list_item *p,
+				 const char *other_string, size_t max_length)
+{
+	size_t *len = p->util;
+
+	if (!*len || memcmp(p->string, other_string, *len))
+		return;
+
+	for (;;) {
+		char c = p->string[*len];
+
+		/*
+		 * Is `p` a strict prefix of `other`? Or have we exhausted the
+		 * maximal length of the prefix? Or is the current character a
+		 * multi-byte UTF-8 one? If so, there is no valid, unique
+		 * prefix.
+		 */
+		if (!c || ++*len > max_length || !isascii(c)) {
+			*len = 0;
+			break;
+		}
+
+		if (c != other_string[*len - 1])
+			break;
+	}
+}
+
+static void find_unique_prefixes(struct prefix_item_list *list)
+{
+	size_t i;
+
+	if (list->sorted.nr == list->items.nr)
+		return;
+
+	string_list_clear(&list->sorted, 0);
+	/* Avoid reallocating incrementally */
+	list->sorted.items = xmalloc(st_mult(sizeof(*list->sorted.items),
+					     list->items.nr));
+	list->sorted.nr = list->sorted.alloc = list->items.nr;
+
+	for (i = 0; i < list->items.nr; i++) {
+		list->sorted.items[i].string = list->items.items[i].string;
+		list->sorted.items[i].util = list->items.items + i;
+	}
+
+	string_list_sort(&list->sorted);
+
+	for (i = 0; i < list->sorted.nr; i++) {
+		struct string_list_item *sorted_item = list->sorted.items + i;
+		struct string_list_item *item = sorted_item->util;
+		size_t *len = item->util;
+
+		*len = 0;
+		while (*len < list->min_length) {
+			char c = item->string[(*len)++];
+
+			if (!c || !isascii(c)) {
+				*len = 0;
+				break;
+			}
+		}
+
+		if (i > 0)
+			extend_prefix_length(item, sorted_item[-1].string,
+					     list->max_length);
+		if (i + 1 < list->sorted.nr)
+			extend_prefix_length(item, sorted_item[1].string,
+					     list->max_length);
+	}
+}
+
+static ssize_t find_unique(const char *string, struct prefix_item_list *list)
+{
+	int index = string_list_find_insert_index(&list->sorted, string, 1);
+	struct string_list_item *item;
+
+	if (list->items.nr != list->sorted.nr)
+		BUG("prefix_item_list in inconsistent state (%"PRIuMAX
+		    " vs %"PRIuMAX")",
+		    (uintmax_t)list->items.nr, (uintmax_t)list->sorted.nr);
+
+	if (index < 0)
+		item = list->sorted.items[-1 - index].util;
+	else if (index > 0 &&
+		 starts_with(list->sorted.items[index - 1].string, string))
+		return -1;
+	else if (index + 1 < list->sorted.nr &&
+		 starts_with(list->sorted.items[index + 1].string, string))
+		return -1;
+	else if (index < list->sorted.nr)
+		item = list->sorted.items[index].util;
+	else
+		return -1;
+	return item - list->items.items;
+}
+
+struct list_options {
+	int columns;
+	const char *header;
+	void (*print_item)(int i, int selected, struct string_list_item *item,
+			   void *print_item_data);
+	void *print_item_data;
+};
+
+static void list(struct add_i_state *s, struct string_list *list, int *selected,
+		 struct list_options *opts)
+{
+	int i, last_lf = 0;
+
+	if (!list->nr)
+		return;
+
+	if (opts->header)
+		color_fprintf_ln(stdout, s->header_color,
+				 "%s", opts->header);
+
+	for (i = 0; i < list->nr; i++) {
+		opts->print_item(i, selected ? selected[i] : 0, list->items + i,
+				 opts->print_item_data);
+
+		if ((opts->columns) && ((i + 1) % (opts->columns))) {
+			putchar('\t');
+			last_lf = 0;
+		}
+		else {
+			putchar('\n');
+			last_lf = 1;
+		}
+	}
+
+	if (!last_lf)
+		putchar('\n');
+}
+struct list_and_choose_options {
+	struct list_options list_opts;
+
+	const char *prompt;
+	enum {
+		SINGLETON = (1<<0),
+		IMMEDIATE = (1<<1),
+	} flags;
+	void (*print_help)(struct add_i_state *s);
+};
+
+#define LIST_AND_CHOOSE_ERROR (-1)
+#define LIST_AND_CHOOSE_QUIT  (-2)
+
+/*
+ * Returns the selected index in singleton mode, the number of selected items
+ * otherwise.
+ *
+ * If an error occurred, returns `LIST_AND_CHOOSE_ERROR`. Upon EOF,
+ * `LIST_AND_CHOOSE_QUIT` is returned.
+ */
+static ssize_t list_and_choose(struct add_i_state *s,
+			       struct prefix_item_list *items,
+			       struct list_and_choose_options *opts)
+{
+	int singleton = opts->flags & SINGLETON;
+	int immediate = opts->flags & IMMEDIATE;
+
+	struct strbuf input = STRBUF_INIT;
+	ssize_t res = singleton ? LIST_AND_CHOOSE_ERROR : 0;
+
+	if (!singleton) {
+		free(items->selected);
+		CALLOC_ARRAY(items->selected, items->items.nr);
+	}
+
+	if (singleton && !immediate)
+		BUG("singleton requires immediate");
+
+	find_unique_prefixes(items);
+
+	for (;;) {
+		char *p;
+
+		strbuf_reset(&input);
+
+		list(s, &items->items, items->selected, &opts->list_opts);
+
+		color_fprintf(stdout, s->prompt_color, "%s", opts->prompt);
+		fputs(singleton ? "> " : ">> ", stdout);
+		fflush(stdout);
+
+		if (strbuf_getline(&input, stdin) == EOF) {
+			putchar('\n');
+			if (immediate)
+				res = LIST_AND_CHOOSE_QUIT;
+			break;
+		}
+		strbuf_trim(&input);
+
+		if (!input.len)
+			break;
+
+		if (!strcmp(input.buf, "?")) {
+			opts->print_help(s);
+			continue;
+		}
+
+		p = input.buf;
+		for (;;) {
+			size_t sep = strcspn(p, " \t\r\n,");
+			int choose = 1;
+			/* `from` is inclusive, `to` is exclusive */
+			ssize_t from = -1, to = -1;
+
+			if (!sep) {
+				if (!*p)
+					break;
+				p++;
+				continue;
+			}
+
+			/* Input that begins with '-'; de-select */
+			if (*p == '-') {
+				choose = 0;
+				p++;
+				sep--;
+			}
+
+			if (sep == 1 && *p == '*') {
+				from = 0;
+				to = items->items.nr;
+			} else if (isdigit(*p)) {
+				char *endp;
+				/*
+				 * A range can be specified like 5-7 or 5-.
+				 *
+				 * Note: `from` is 0-based while the user input
+				 * is 1-based, hence we have to decrement by
+				 * one. We do not have to decrement `to` even
+				 * if it is 0-based because it is an exclusive
+				 * boundary.
+				 */
+				from = strtoul(p, &endp, 10) - 1;
+				if (endp == p + sep)
+					to = from + 1;
+				else if (*endp == '-') {
+					to = strtoul(++endp, &endp, 10);
+					/* extra characters after the range? */
+					if (endp != p + sep)
+						from = -1;
+				}
+			}
+
+			if (p[sep])
+				p[sep++] = '\0';
+			if (from < 0) {
+				from = find_unique(p, items);
+				if (from >= 0)
+					to = from + 1;
+			}
+
+			if (from < 0 || from >= items->items.nr ||
+			    (singleton && from + 1 != to)) {
+				color_fprintf_ln(stdout, s->error_color,
+						 _("Huh (%s)?"), p);
+				break;
+			} else if (singleton) {
+				res = from;
+				break;
+			}
+
+			if (to > items->items.nr)
+				to = items->items.nr;
+
+			for (; from < to; from++)
+				if (items->selected[from] != choose) {
+					items->selected[from] = choose;
+					res += choose ? +1 : -1;
+				}
+
+			p += sep;
+		}
+
+		if ((immediate && res != LIST_AND_CHOOSE_ERROR) ||
+		    !strcmp(input.buf, "*"))
+			break;
+	}
+
+	strbuf_release(&input);
+	return res;
+}
+
+struct adddel {
+	uintmax_t add, del;
+	unsigned seen:1, unmerged:1, binary:1;
+};
+
+struct file_item {
+	size_t prefix_length;
+	struct adddel index, worktree;
+};
+
+static void add_file_item(struct string_list *files, const char *name)
+{
+	struct file_item *item = xcalloc(sizeof(*item), 1);
+
+	string_list_append(files, name)->util = item;
+}
+
+struct pathname_entry {
+	struct hashmap_entry ent;
+	const char *name;
+	struct file_item *item;
+};
+
+static int pathname_entry_cmp(const void *unused_cmp_data,
+			      const struct hashmap_entry *he1,
+			      const struct hashmap_entry *he2,
+			      const void *name)
+{
+	const struct pathname_entry *e1 =
+		container_of(he1, const struct pathname_entry, ent);
+	const struct pathname_entry *e2 =
+		container_of(he2, const struct pathname_entry, ent);
+
+	return strcmp(e1->name, name ? (const char *)name : e2->name);
+}
+
+struct collection_status {
+	enum { FROM_WORKTREE = 0, FROM_INDEX = 1 } mode;
+
+	const char *reference;
+
+	unsigned skip_unseen:1;
+	size_t unmerged_count, binary_count;
+	struct string_list *files;
+	struct hashmap file_map;
+};
+
+static void collect_changes_cb(struct diff_queue_struct *q,
+			       struct diff_options *options,
+			       void *data)
+{
+	struct collection_status *s = data;
+	struct diffstat_t stat = { 0 };
+	int i;
+
+	if (!q->nr)
+		return;
+
+	compute_diffstat(options, &stat, q);
+
+	for (i = 0; i < stat.nr; i++) {
+		const char *name = stat.files[i]->name;
+		int hash = strhash(name);
+		struct pathname_entry *entry;
+		struct file_item *file_item;
+		struct adddel *adddel, *other_adddel;
+
+		entry = hashmap_get_entry_from_hash(&s->file_map, hash, name,
+						    struct pathname_entry, ent);
+		if (!entry) {
+			if (s->skip_unseen)
+				continue;
+
+			add_file_item(s->files, name);
+
+			entry = xcalloc(sizeof(*entry), 1);
+			hashmap_entry_init(&entry->ent, hash);
+			entry->name = s->files->items[s->files->nr - 1].string;
+			entry->item = s->files->items[s->files->nr - 1].util;
+			hashmap_add(&s->file_map, &entry->ent);
+		}
+
+		file_item = entry->item;
+		adddel = s->mode == FROM_INDEX ?
+			&file_item->index : &file_item->worktree;
+		other_adddel = s->mode == FROM_INDEX ?
+			&file_item->worktree : &file_item->index;
+		adddel->seen = 1;
+		adddel->add = stat.files[i]->added;
+		adddel->del = stat.files[i]->deleted;
+		if (stat.files[i]->is_binary) {
+			if (!other_adddel->binary)
+				s->binary_count++;
+			adddel->binary = 1;
+		}
+		if (stat.files[i]->is_unmerged) {
+			if (!other_adddel->unmerged)
+				s->unmerged_count++;
+			adddel->unmerged = 1;
+		}
+	}
+	free_diffstat_info(&stat);
+}
+
+enum modified_files_filter {
+	NO_FILTER = 0,
+	WORKTREE_ONLY = 1,
+	INDEX_ONLY = 2,
+};
+
+static int get_modified_files(struct repository *r,
+			      enum modified_files_filter filter,
+			      struct prefix_item_list *files,
+			      const struct pathspec *ps,
+			      size_t *unmerged_count,
+			      size_t *binary_count)
+{
+	struct object_id head_oid;
+	int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
+					     &head_oid, NULL);
+	struct collection_status s = { 0 };
+	int i;
+
+	if (discard_index(r->index) < 0 ||
+	    repo_read_index_preload(r, ps, 0) < 0)
+		return error(_("could not read index"));
+
+	prefix_item_list_clear(files);
+	s.files = &files->items;
+	hashmap_init(&s.file_map, pathname_entry_cmp, NULL, 0);
+
+	for (i = 0; i < 2; i++) {
+		struct rev_info rev;
+		struct setup_revision_opt opt = { 0 };
+
+		if (filter == INDEX_ONLY)
+			s.mode = (i == 0) ? FROM_INDEX : FROM_WORKTREE;
+		else
+			s.mode = (i == 0) ? FROM_WORKTREE : FROM_INDEX;
+		s.skip_unseen = filter && i;
+
+		opt.def = is_initial ?
+			empty_tree_oid_hex() : oid_to_hex(&head_oid);
+
+		init_revisions(&rev, NULL);
+		setup_revisions(0, NULL, &rev, &opt);
+
+		rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
+		rev.diffopt.format_callback = collect_changes_cb;
+		rev.diffopt.format_callback_data = &s;
+
+		if (ps)
+			copy_pathspec(&rev.prune_data, ps);
+
+		if (s.mode == FROM_INDEX)
+			run_diff_index(&rev, 1);
+		else {
+			rev.diffopt.flags.ignore_dirty_submodules = 1;
+			run_diff_files(&rev, 0);
+		}
+
+		if (ps)
+			clear_pathspec(&rev.prune_data);
+	}
+	hashmap_free_entries(&s.file_map, struct pathname_entry, ent);
+	if (unmerged_count)
+		*unmerged_count = s.unmerged_count;
+	if (binary_count)
+		*binary_count = s.binary_count;
+
+	/* While the diffs are ordered already, we ran *two* diffs... */
+	string_list_sort(&files->items);
+
+	return 0;
+}
+
+static void render_adddel(struct strbuf *buf,
+				struct adddel *ad, const char *no_changes)
+{
+	if (ad->binary)
+		strbuf_addstr(buf, _("binary"));
+	else if (ad->seen)
+		strbuf_addf(buf, "+%"PRIuMAX"/-%"PRIuMAX,
+			    (uintmax_t)ad->add, (uintmax_t)ad->del);
+	else
+		strbuf_addstr(buf, no_changes);
+}
+
+/* filters out prefixes which have special meaning to list_and_choose() */
+static int is_valid_prefix(const char *prefix, size_t prefix_len)
+{
+	return prefix_len && prefix &&
+		/*
+		 * We expect `prefix` to be NUL terminated, therefore this
+		 * `strcspn()` call is okay, even if it might do much more
+		 * work than strictly necessary.
+		 */
+		strcspn(prefix, " \t\r\n,") >= prefix_len &&	/* separators */
+		*prefix != '-' &&				/* deselection */
+		!isdigit(*prefix) &&				/* selection */
+		(prefix_len != 1 ||
+		 (*prefix != '*' &&				/* "all" wildcard */
+		  *prefix != '?'));				/* prompt help */
+}
+
+struct print_file_item_data {
+	const char *modified_fmt, *color, *reset;
+	struct strbuf buf, name, index, worktree;
+	unsigned only_names:1;
+};
+
+static void print_file_item(int i, int selected, struct string_list_item *item,
+			    void *print_file_item_data)
+{
+	struct file_item *c = item->util;
+	struct print_file_item_data *d = print_file_item_data;
+	const char *highlighted = NULL;
+
+	strbuf_reset(&d->index);
+	strbuf_reset(&d->worktree);
+	strbuf_reset(&d->buf);
+
+	/* Format the item with the prefix highlighted. */
+	if (c->prefix_length > 0 &&
+	    is_valid_prefix(item->string, c->prefix_length)) {
+		strbuf_reset(&d->name);
+		strbuf_addf(&d->name, "%s%.*s%s%s", d->color,
+			    (int)c->prefix_length, item->string, d->reset,
+			    item->string + c->prefix_length);
+		highlighted = d->name.buf;
+	}
+
+	if (d->only_names) {
+		printf("%c%2d: %s", selected ? '*' : ' ', i + 1,
+		       highlighted ? highlighted : item->string);
+		return;
+	}
+
+	render_adddel(&d->worktree, &c->worktree, _("nothing"));
+	render_adddel(&d->index, &c->index, _("unchanged"));
+
+	strbuf_addf(&d->buf, d->modified_fmt, d->index.buf, d->worktree.buf,
+		    highlighted ? highlighted : item->string);
+
+	printf("%c%2d: %s", selected ? '*' : ' ', i + 1, d->buf.buf);
+}
+
+static int run_status(struct add_i_state *s, const struct pathspec *ps,
+		      struct prefix_item_list *files,
+		      struct list_and_choose_options *opts)
+{
+	if (get_modified_files(s->r, NO_FILTER, files, ps, NULL, NULL) < 0)
+		return -1;
+
+	list(s, &files->items, NULL, &opts->list_opts);
+	putchar('\n');
+
+	return 0;
+}
+
+static int run_update(struct add_i_state *s, const struct pathspec *ps,
+		      struct prefix_item_list *files,
+		      struct list_and_choose_options *opts)
+{
+	int res = 0, fd;
+	size_t count, i;
+	struct lock_file index_lock;
+
+	if (get_modified_files(s->r, WORKTREE_ONLY, files, ps, NULL, NULL) < 0)
+		return -1;
+
+	if (!files->items.nr) {
+		putchar('\n');
+		return 0;
+	}
+
+	opts->prompt = N_("Update");
+	count = list_and_choose(s, files, opts);
+	if (count <= 0) {
+		putchar('\n');
+		return 0;
+	}
+
+	fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR);
+	if (fd < 0) {
+		putchar('\n');
+		return -1;
+	}
+
+	for (i = 0; i < files->items.nr; i++) {
+		const char *name = files->items.items[i].string;
+		if (files->selected[i] &&
+		    add_file_to_index(s->r->index, name, 0) < 0) {
+			res = error(_("could not stage '%s'"), name);
+			break;
+		}
+	}
+
+	if (!res && write_locked_index(s->r->index, &index_lock, COMMIT_LOCK) < 0)
+		res = error(_("could not write index"));
+
+	if (!res)
+		printf(Q_("updated %d path\n",
+			  "updated %d paths\n", count), (int)count);
+
+	putchar('\n');
+	return res;
+}
+
+static void revert_from_diff(struct diff_queue_struct *q,
+			     struct diff_options *opt, void *data)
+{
+	int i, add_flags = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE;
+
+	for (i = 0; i < q->nr; i++) {
+		struct diff_filespec *one = q->queue[i]->one;
+		struct cache_entry *ce;
+
+		if (!(one->mode && !is_null_oid(&one->oid))) {
+			remove_file_from_index(opt->repo->index, one->path);
+			printf(_("note: %s is untracked now.\n"), one->path);
+		} else {
+			ce = make_cache_entry(opt->repo->index, one->mode,
+					      &one->oid, one->path, 0, 0);
+			if (!ce)
+				die(_("make_cache_entry failed for path '%s'"),
+				    one->path);
+			add_index_entry(opt->repo->index, ce, add_flags);
+		}
+	}
+}
+
+static int run_revert(struct add_i_state *s, const struct pathspec *ps,
+		      struct prefix_item_list *files,
+		      struct list_and_choose_options *opts)
+{
+	int res = 0, fd;
+	size_t count, i, j;
+
+	struct object_id oid;
+	int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &oid,
+					     NULL);
+	struct lock_file index_lock;
+	const char **paths;
+	struct tree *tree;
+	struct diff_options diffopt = { NULL };
+
+	if (get_modified_files(s->r, INDEX_ONLY, files, ps, NULL, NULL) < 0)
+		return -1;
+
+	if (!files->items.nr) {
+		putchar('\n');
+		return 0;
+	}
+
+	opts->prompt = N_("Revert");
+	count = list_and_choose(s, files, opts);
+	if (count <= 0)
+		goto finish_revert;
+
+	fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR);
+	if (fd < 0) {
+		res = -1;
+		goto finish_revert;
+	}
+
+	if (is_initial)
+		oidcpy(&oid, s->r->hash_algo->empty_tree);
+	else {
+		tree = parse_tree_indirect(&oid);
+		if (!tree) {
+			res = error(_("Could not parse HEAD^{tree}"));
+			goto finish_revert;
+		}
+		oidcpy(&oid, &tree->object.oid);
+	}
+
+	ALLOC_ARRAY(paths, count + 1);
+	for (i = j = 0; i < files->items.nr; i++)
+		if (files->selected[i])
+			paths[j++] = files->items.items[i].string;
+	paths[j] = NULL;
+
+	parse_pathspec(&diffopt.pathspec, 0,
+		       PATHSPEC_PREFER_FULL | PATHSPEC_LITERAL_PATH,
+		       NULL, paths);
+
+	diffopt.output_format = DIFF_FORMAT_CALLBACK;
+	diffopt.format_callback = revert_from_diff;
+	diffopt.flags.override_submodule_config = 1;
+	diffopt.repo = s->r;
+
+	if (do_diff_cache(&oid, &diffopt))
+		res = -1;
+	else {
+		diffcore_std(&diffopt);
+		diff_flush(&diffopt);
+	}
+	free(paths);
+	clear_pathspec(&diffopt.pathspec);
+
+	if (!res && write_locked_index(s->r->index, &index_lock,
+				       COMMIT_LOCK) < 0)
+		res = -1;
+	else
+		res = repo_refresh_and_write_index(s->r, REFRESH_QUIET, 0, 1,
+						   NULL, NULL, NULL);
+
+	if (!res)
+		printf(Q_("reverted %d path\n",
+			  "reverted %d paths\n", count), (int)count);
+
+finish_revert:
+	putchar('\n');
+	return res;
+}
+
+static int get_untracked_files(struct repository *r,
+			       struct prefix_item_list *files,
+			       const struct pathspec *ps)
+{
+	struct dir_struct dir = { 0 };
+	size_t i;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (repo_read_index(r) < 0)
+		return error(_("could not read index"));
+
+	prefix_item_list_clear(files);
+	setup_standard_excludes(&dir);
+	add_pattern_list(&dir, EXC_CMDL, "--exclude option");
+	fill_directory(&dir, r->index, ps);
+
+	for (i = 0; i < dir.nr; i++) {
+		struct dir_entry *ent = dir.entries[i];
+
+		if (index_name_is_other(r->index, ent->name, ent->len)) {
+			strbuf_reset(&buf);
+			strbuf_add(&buf, ent->name, ent->len);
+			add_file_item(&files->items, buf.buf);
+		}
+	}
+
+	strbuf_release(&buf);
+	return 0;
+}
+
+static int run_add_untracked(struct add_i_state *s, const struct pathspec *ps,
+		      struct prefix_item_list *files,
+		      struct list_and_choose_options *opts)
+{
+	struct print_file_item_data *d = opts->list_opts.print_item_data;
+	int res = 0, fd;
+	size_t count, i;
+	struct lock_file index_lock;
+
+	if (get_untracked_files(s->r, files, ps) < 0)
+		return -1;
+
+	if (!files->items.nr) {
+		printf(_("No untracked files.\n"));
+		goto finish_add_untracked;
+	}
+
+	opts->prompt = N_("Add untracked");
+	d->only_names = 1;
+	count = list_and_choose(s, files, opts);
+	d->only_names = 0;
+	if (count <= 0)
+		goto finish_add_untracked;
+
+	fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR);
+	if (fd < 0) {
+		res = -1;
+		goto finish_add_untracked;
+	}
+
+	for (i = 0; i < files->items.nr; i++) {
+		const char *name = files->items.items[i].string;
+		if (files->selected[i] &&
+		    add_file_to_index(s->r->index, name, 0) < 0) {
+			res = error(_("could not stage '%s'"), name);
+			break;
+		}
+	}
+
+	if (!res &&
+	    write_locked_index(s->r->index, &index_lock, COMMIT_LOCK) < 0)
+		res = error(_("could not write index"));
+
+	if (!res)
+		printf(Q_("added %d path\n",
+			  "added %d paths\n", count), (int)count);
+
+finish_add_untracked:
+	putchar('\n');
+	return res;
+}
+
+static int run_patch(struct add_i_state *s, const struct pathspec *ps,
+		     struct prefix_item_list *files,
+		     struct list_and_choose_options *opts)
+{
+	int res = 0;
+	ssize_t count, i, j;
+	size_t unmerged_count = 0, binary_count = 0;
+
+	if (get_modified_files(s->r, WORKTREE_ONLY, files, ps,
+			       &unmerged_count, &binary_count) < 0)
+		return -1;
+
+	if (unmerged_count || binary_count) {
+		for (i = j = 0; i < files->items.nr; i++) {
+			struct file_item *item = files->items.items[i].util;
+
+			if (item->index.binary || item->worktree.binary) {
+				free(item);
+				free(files->items.items[i].string);
+			} else if (item->index.unmerged ||
+				 item->worktree.unmerged) {
+				color_fprintf_ln(stderr, s->error_color,
+						 _("ignoring unmerged: %s"),
+						 files->items.items[i].string);
+				free(item);
+				free(files->items.items[i].string);
+			} else
+				files->items.items[j++] = files->items.items[i];
+		}
+		files->items.nr = j;
+	}
+
+	if (!files->items.nr) {
+		if (binary_count)
+			fprintf(stderr, _("Only binary files changed.\n"));
+		else
+			fprintf(stderr, _("No changes.\n"));
+		return 0;
+	}
+
+	opts->prompt = N_("Patch update");
+	count = list_and_choose(s, files, opts);
+	if (count >= 0) {
+		struct argv_array args = ARGV_ARRAY_INIT;
+		struct pathspec ps_selected = { 0 };
+
+		for (i = 0; i < files->items.nr; i++)
+			if (files->selected[i])
+				argv_array_push(&args,
+						files->items.items[i].string);
+		parse_pathspec(&ps_selected,
+			       PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
+			       PATHSPEC_LITERAL_PATH, "", args.argv);
+		res = run_add_p(s->r, &ps_selected);
+		argv_array_clear(&args);
+		clear_pathspec(&ps_selected);
+	}
+
+	return res;
+}
+
+static int run_diff(struct add_i_state *s, const struct pathspec *ps,
+		    struct prefix_item_list *files,
+		    struct list_and_choose_options *opts)
+{
+	int res = 0;
+	ssize_t count, i;
+
+	struct object_id oid;
+	int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &oid,
+					     NULL);
+	if (get_modified_files(s->r, INDEX_ONLY, files, ps, NULL, NULL) < 0)
+		return -1;
+
+	if (!files->items.nr) {
+		putchar('\n');
+		return 0;
+	}
+
+	opts->prompt = N_("Review diff");
+	opts->flags = IMMEDIATE;
+	count = list_and_choose(s, files, opts);
+	opts->flags = 0;
+	if (count >= 0) {
+		struct argv_array args = ARGV_ARRAY_INIT;
+
+		argv_array_pushl(&args, "git", "diff", "-p", "--cached",
+				 oid_to_hex(!is_initial ? &oid :
+					    s->r->hash_algo->empty_tree),
+				 "--", NULL);
+		for (i = 0; i < files->items.nr; i++)
+			if (files->selected[i])
+				argv_array_push(&args,
+						files->items.items[i].string);
+		res = run_command_v_opt(args.argv, 0);
+		argv_array_clear(&args);
+	}
+
+	putchar('\n');
+	return res;
+}
+
+static int run_help(struct add_i_state *s, const struct pathspec *unused_ps,
+		    struct prefix_item_list *unused_files,
+		    struct list_and_choose_options *unused_opts)
+{
+	color_fprintf_ln(stdout, s->help_color, "status        - %s",
+			 _("show paths with changes"));
+	color_fprintf_ln(stdout, s->help_color, "update        - %s",
+			 _("add working tree state to the staged set of changes"));
+	color_fprintf_ln(stdout, s->help_color, "revert        - %s",
+			 _("revert staged set of changes back to the HEAD version"));
+	color_fprintf_ln(stdout, s->help_color, "patch         - %s",
+			 _("pick hunks and update selectively"));
+	color_fprintf_ln(stdout, s->help_color, "diff          - %s",
+			 _("view diff between HEAD and index"));
+	color_fprintf_ln(stdout, s->help_color, "add untracked - %s",
+			 _("add contents of untracked files to the staged set of changes"));
+
+	return 0;
+}
+
+static void choose_prompt_help(struct add_i_state *s)
+{
+	color_fprintf_ln(stdout, s->help_color, "%s",
+			 _("Prompt help:"));
+	color_fprintf_ln(stdout, s->help_color, "1          - %s",
+			 _("select a single item"));
+	color_fprintf_ln(stdout, s->help_color, "3-5        - %s",
+			 _("select a range of items"));
+	color_fprintf_ln(stdout, s->help_color, "2-3,6-9    - %s",
+			 _("select multiple ranges"));
+	color_fprintf_ln(stdout, s->help_color, "foo        - %s",
+			 _("select item based on unique prefix"));
+	color_fprintf_ln(stdout, s->help_color, "-...       - %s",
+			 _("unselect specified items"));
+	color_fprintf_ln(stdout, s->help_color, "*          - %s",
+			 _("choose all items"));
+	color_fprintf_ln(stdout, s->help_color, "           - %s",
+			 _("(empty) finish selecting"));
+}
+
+typedef int (*command_t)(struct add_i_state *s, const struct pathspec *ps,
+			 struct prefix_item_list *files,
+			 struct list_and_choose_options *opts);
+
+struct command_item {
+	size_t prefix_length;
+	command_t command;
+};
+
+struct print_command_item_data {
+	const char *color, *reset;
+};
+
+static void print_command_item(int i, int selected,
+			       struct string_list_item *item,
+			       void *print_command_item_data)
+{
+	struct print_command_item_data *d = print_command_item_data;
+	struct command_item *util = item->util;
+
+	if (!util->prefix_length ||
+	    !is_valid_prefix(item->string, util->prefix_length))
+		printf(" %2d: %s", i + 1, item->string);
+	else
+		printf(" %2d: %s%.*s%s%s", i + 1,
+		       d->color, (int)util->prefix_length, item->string,
+		       d->reset, item->string + util->prefix_length);
+}
+
+static void command_prompt_help(struct add_i_state *s)
+{
+	const char *help_color = s->help_color;
+	color_fprintf_ln(stdout, help_color, "%s", _("Prompt help:"));
+	color_fprintf_ln(stdout, help_color, "1          - %s",
+			 _("select a numbered item"));
+	color_fprintf_ln(stdout, help_color, "foo        - %s",
+			 _("select item based on unique prefix"));
+	color_fprintf_ln(stdout, help_color, "           - %s",
+			 _("(empty) select nothing"));
+}
+
+int run_add_i(struct repository *r, const struct pathspec *ps)
+{
+	struct add_i_state s = { NULL };
+	struct print_command_item_data data = { "[", "]" };
+	struct list_and_choose_options main_loop_opts = {
+		{ 4, N_("*** Commands ***"), print_command_item, &data },
+		N_("What now"), SINGLETON | IMMEDIATE, command_prompt_help
+	};
+	struct {
+		const char *string;
+		command_t command;
+	} command_list[] = {
+		{ "status", run_status },
+		{ "update", run_update },
+		{ "revert", run_revert },
+		{ "add untracked", run_add_untracked },
+		{ "patch", run_patch },
+		{ "diff", run_diff },
+		{ "quit", NULL },
+		{ "help", run_help },
+	};
+	struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT;
+
+	struct print_file_item_data print_file_item_data = {
+		"%12s %12s %s", NULL, NULL,
+		STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
+	};
+	struct list_and_choose_options opts = {
+		{ 0, NULL, print_file_item, &print_file_item_data },
+		NULL, 0, choose_prompt_help
+	};
+	struct strbuf header = STRBUF_INIT;
+	struct prefix_item_list files = PREFIX_ITEM_LIST_INIT;
+	ssize_t i;
+	int res = 0;
+
+	for (i = 0; i < ARRAY_SIZE(command_list); i++) {
+		struct command_item *util = xcalloc(sizeof(*util), 1);
+		util->command = command_list[i].command;
+		string_list_append(&commands.items, command_list[i].string)
+			->util = util;
+	}
+
+	init_add_i_state(&s, r);
+
+	/*
+	 * When color was asked for, use the prompt color for
+	 * highlighting, otherwise use square brackets.
+	 */
+	if (s.use_color) {
+		data.color = s.prompt_color;
+		data.reset = s.reset_color;
+	}
+	print_file_item_data.color = data.color;
+	print_file_item_data.reset = data.reset;
+
+	strbuf_addstr(&header, "      ");
+	strbuf_addf(&header, print_file_item_data.modified_fmt,
+		    _("staged"), _("unstaged"), _("path"));
+	opts.list_opts.header = header.buf;
+
+	if (discard_index(r->index) < 0 ||
+	    repo_read_index(r) < 0 ||
+	    repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1,
+					 NULL, NULL, NULL) < 0)
+		warning(_("could not refresh index"));
+
+	res = run_status(&s, ps, &files, &opts);
+
+	for (;;) {
+		struct command_item *util;
+
+		i = list_and_choose(&s, &commands, &main_loop_opts);
+		if (i < 0 || i >= commands.items.nr)
+			util = NULL;
+		else
+			util = commands.items.items[i].util;
+
+		if (i == LIST_AND_CHOOSE_QUIT || (util && !util->command)) {
+			printf(_("Bye.\n"));
+			res = 0;
+			break;
+		}
+
+		if (util)
+			res = util->command(&s, ps, &files, &opts);
+	}
+
+	prefix_item_list_clear(&files);
+	strbuf_release(&print_file_item_data.buf);
+	strbuf_release(&print_file_item_data.name);
+	strbuf_release(&print_file_item_data.index);
+	strbuf_release(&print_file_item_data.worktree);
+	strbuf_release(&header);
+	prefix_item_list_clear(&commands);
+
+	return res;
+}
diff --git a/add-interactive.h b/add-interactive.h
new file mode 100644
index 0000000..062dc36
--- /dev/null
+++ b/add-interactive.h
@@ -0,0 +1,27 @@
+#ifndef ADD_INTERACTIVE_H
+#define ADD_INTERACTIVE_H
+
+#include "color.h"
+
+struct add_i_state {
+	struct repository *r;
+	int use_color;
+	char header_color[COLOR_MAXLEN];
+	char help_color[COLOR_MAXLEN];
+	char prompt_color[COLOR_MAXLEN];
+	char error_color[COLOR_MAXLEN];
+	char reset_color[COLOR_MAXLEN];
+	char fraginfo_color[COLOR_MAXLEN];
+	char context_color[COLOR_MAXLEN];
+	char file_old_color[COLOR_MAXLEN];
+	char file_new_color[COLOR_MAXLEN];
+};
+
+void init_add_i_state(struct add_i_state *s, struct repository *r);
+
+struct repository;
+struct pathspec;
+int run_add_i(struct repository *r, const struct pathspec *ps);
+int run_add_p(struct repository *r, const struct pathspec *ps);
+
+#endif
diff --git a/add-patch.c b/add-patch.c
new file mode 100644
index 0000000..2c46fe5
--- /dev/null
+++ b/add-patch.c
@@ -0,0 +1,1338 @@
+#include "cache.h"
+#include "add-interactive.h"
+#include "strbuf.h"
+#include "run-command.h"
+#include "argv-array.h"
+#include "pathspec.h"
+#include "color.h"
+#include "diff.h"
+
+enum prompt_mode_type {
+	PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_HUNK
+};
+
+static const char *prompt_mode[] = {
+	N_("Stage mode change [y,n,a,q,d%s,?]? "),
+	N_("Stage deletion [y,n,a,q,d%s,?]? "),
+	N_("Stage this hunk [y,n,a,q,d%s,?]? ")
+};
+
+struct hunk_header {
+	unsigned long old_offset, old_count, new_offset, new_count;
+	/*
+	 * Start/end offsets to the extra text after the second `@@` in the
+	 * hunk header, e.g. the function signature. This is expected to
+	 * include the newline.
+	 */
+	size_t extra_start, extra_end, colored_extra_start, colored_extra_end;
+};
+
+struct hunk {
+	size_t start, end, colored_start, colored_end, splittable_into;
+	ssize_t delta;
+	enum { UNDECIDED_HUNK = 0, SKIP_HUNK, USE_HUNK } use;
+	struct hunk_header header;
+};
+
+struct add_p_state {
+	struct add_i_state s;
+	struct strbuf answer, buf;
+
+	/* parsed diff */
+	struct strbuf plain, colored;
+	struct file_diff {
+		struct hunk head;
+		struct hunk *hunk;
+		size_t hunk_nr, hunk_alloc;
+		unsigned deleted:1, mode_change:1,binary:1;
+	} *file_diff;
+	size_t file_diff_nr;
+};
+
+static void err(struct add_p_state *s, const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	fputs(s->s.error_color, stderr);
+	vfprintf(stderr, fmt, args);
+	fputs(s->s.reset_color, stderr);
+	fputc('\n', stderr);
+	va_end(args);
+}
+
+static void setup_child_process(struct add_p_state *s,
+				struct child_process *cp, ...)
+{
+	va_list ap;
+	const char *arg;
+
+	va_start(ap, cp);
+	while ((arg = va_arg(ap, const char *)))
+		argv_array_push(&cp->args, arg);
+	va_end(ap);
+
+	cp->git_cmd = 1;
+	argv_array_pushf(&cp->env_array,
+			 INDEX_ENVIRONMENT "=%s", s->s.r->index_file);
+}
+
+static int parse_range(const char **p,
+		       unsigned long *offset, unsigned long *count)
+{
+	char *pend;
+
+	*offset = strtoul(*p, &pend, 10);
+	if (pend == *p)
+		return -1;
+	if (*pend != ',') {
+		*count = 1;
+		*p = pend;
+		return 0;
+	}
+	*count = strtoul(pend + 1, (char **)p, 10);
+	return *p == pend + 1 ? -1 : 0;
+}
+
+static int parse_hunk_header(struct add_p_state *s, struct hunk *hunk)
+{
+	struct hunk_header *header = &hunk->header;
+	const char *line = s->plain.buf + hunk->start, *p = line;
+	char *eol = memchr(p, '\n', s->plain.len - hunk->start);
+
+	if (!eol)
+		eol = s->plain.buf + s->plain.len;
+
+	if (!skip_prefix(p, "@@ -", &p) ||
+	    parse_range(&p, &header->old_offset, &header->old_count) < 0 ||
+	    !skip_prefix(p, " +", &p) ||
+	    parse_range(&p, &header->new_offset, &header->new_count) < 0 ||
+	    !skip_prefix(p, " @@", &p))
+		return error(_("could not parse hunk header '%.*s'"),
+			     (int)(eol - line), line);
+
+	hunk->start = eol - s->plain.buf + (*eol == '\n');
+	header->extra_start = p - s->plain.buf;
+	header->extra_end = hunk->start;
+
+	if (!s->colored.len) {
+		header->colored_extra_start = header->colored_extra_end = 0;
+		return 0;
+	}
+
+	/* Now find the extra text in the colored diff */
+	line = s->colored.buf + hunk->colored_start;
+	eol = memchr(line, '\n', s->colored.len - hunk->colored_start);
+	if (!eol)
+		eol = s->colored.buf + s->colored.len;
+	p = memmem(line, eol - line, "@@ -", 4);
+	if (!p)
+		return error(_("could not parse colored hunk header '%.*s'"),
+			     (int)(eol - line), line);
+	p = memmem(p + 4, eol - p - 4, " @@", 3);
+	if (!p)
+		return error(_("could not parse colored hunk header '%.*s'"),
+			     (int)(eol - line), line);
+	hunk->colored_start = eol - s->colored.buf + (*eol == '\n');
+	header->colored_extra_start = p + 3 - s->colored.buf;
+	header->colored_extra_end = hunk->colored_start;
+
+	return 0;
+}
+
+static int is_octal(const char *p, size_t len)
+{
+	if (!len)
+		return 0;
+
+	while (len--)
+		if (*p < '0' || *(p++) > '7')
+			return 0;
+	return 1;
+}
+
+static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
+{
+	struct argv_array args = ARGV_ARRAY_INIT;
+	struct strbuf *plain = &s->plain, *colored = NULL;
+	struct child_process cp = CHILD_PROCESS_INIT;
+	char *p, *pend, *colored_p = NULL, *colored_pend = NULL, marker = '\0';
+	size_t file_diff_alloc = 0, i, color_arg_index;
+	struct file_diff *file_diff = NULL;
+	struct hunk *hunk = NULL;
+	int res;
+
+	/* Use `--no-color` explicitly, just in case `diff.color = always`. */
+	argv_array_pushl(&args, "diff-files", "-p", "--no-color", "--", NULL);
+	color_arg_index = args.argc - 2;
+	for (i = 0; i < ps->nr; i++)
+		argv_array_push(&args, ps->items[i].original);
+
+	setup_child_process(s, &cp, NULL);
+	cp.argv = args.argv;
+	res = capture_command(&cp, plain, 0);
+	if (res) {
+		argv_array_clear(&args);
+		return error(_("could not parse diff"));
+	}
+	if (!plain->len) {
+		argv_array_clear(&args);
+		return 0;
+	}
+	strbuf_complete_line(plain);
+
+	if (want_color_fd(1, -1)) {
+		struct child_process colored_cp = CHILD_PROCESS_INIT;
+
+		setup_child_process(s, &colored_cp, NULL);
+		xsnprintf((char *)args.argv[color_arg_index], 8, "--color");
+		colored_cp.argv = args.argv;
+		colored = &s->colored;
+		res = capture_command(&colored_cp, colored, 0);
+		argv_array_clear(&args);
+		if (res)
+			return error(_("could not parse colored diff"));
+		strbuf_complete_line(colored);
+		colored_p = colored->buf;
+		colored_pend = colored_p + colored->len;
+	}
+	argv_array_clear(&args);
+
+	/* parse files and hunks */
+	p = plain->buf;
+	pend = p + plain->len;
+	while (p != pend) {
+		char *eol = memchr(p, '\n', pend - p);
+		const char *deleted = NULL, *mode_change = NULL;
+
+		if (!eol)
+			eol = pend;
+
+		if (starts_with(p, "diff ")) {
+			s->file_diff_nr++;
+			ALLOC_GROW(s->file_diff, s->file_diff_nr,
+				   file_diff_alloc);
+			file_diff = s->file_diff + s->file_diff_nr - 1;
+			memset(file_diff, 0, sizeof(*file_diff));
+			hunk = &file_diff->head;
+			hunk->start = p - plain->buf;
+			if (colored_p)
+				hunk->colored_start = colored_p - colored->buf;
+			marker = '\0';
+		} else if (p == plain->buf)
+			BUG("diff starts with unexpected line:\n"
+			    "%.*s\n", (int)(eol - p), p);
+		else if (file_diff->deleted)
+			; /* keep the rest of the file in a single "hunk" */
+		else if (starts_with(p, "@@ ") ||
+			 (hunk == &file_diff->head &&
+			  skip_prefix(p, "deleted file", &deleted))) {
+			if (marker == '-' || marker == '+')
+				/*
+				 * Should not happen; previous hunk did not end
+				 * in a context line? Handle it anyway.
+				 */
+				hunk->splittable_into++;
+
+			file_diff->hunk_nr++;
+			ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr,
+				   file_diff->hunk_alloc);
+			hunk = file_diff->hunk + file_diff->hunk_nr - 1;
+			memset(hunk, 0, sizeof(*hunk));
+
+			hunk->start = p - plain->buf;
+			if (colored)
+				hunk->colored_start = colored_p - colored->buf;
+
+			if (deleted)
+				file_diff->deleted = 1;
+			else if (parse_hunk_header(s, hunk) < 0)
+				return -1;
+
+			/*
+			 * Start counting into how many hunks this one can be
+			 * split
+			 */
+			marker = *p;
+		} else if (hunk == &file_diff->head &&
+			   skip_prefix(p, "old mode ", &mode_change) &&
+			   is_octal(mode_change, eol - mode_change)) {
+			if (file_diff->mode_change)
+				BUG("double mode change?\n\n%.*s",
+				    (int)(eol - plain->buf), plain->buf);
+			if (file_diff->hunk_nr++)
+				BUG("mode change in the middle?\n\n%.*s",
+				    (int)(eol - plain->buf), plain->buf);
+
+			/*
+			 * Do *not* change `hunk`: the mode change pseudo-hunk
+			 * is _part of_ the header "hunk".
+			 */
+			file_diff->mode_change = 1;
+			ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr,
+				   file_diff->hunk_alloc);
+			memset(file_diff->hunk, 0, sizeof(struct hunk));
+			file_diff->hunk->start = p - plain->buf;
+			if (colored_p)
+				file_diff->hunk->colored_start =
+					colored_p - colored->buf;
+		} else if (hunk == &file_diff->head &&
+			   skip_prefix(p, "new mode ", &mode_change) &&
+			   is_octal(mode_change, eol - mode_change)) {
+
+			/*
+			 * Extend the "mode change" pseudo-hunk to include also
+			 * the "new mode" line.
+			 */
+			if (!file_diff->mode_change)
+				BUG("'new mode' without 'old mode'?\n\n%.*s",
+				    (int)(eol - plain->buf), plain->buf);
+			if (file_diff->hunk_nr != 1)
+				BUG("mode change in the middle?\n\n%.*s",
+				    (int)(eol - plain->buf), plain->buf);
+			if (p - plain->buf != file_diff->hunk->end)
+				BUG("'new mode' does not immediately follow "
+				    "'old mode'?\n\n%.*s",
+				    (int)(eol - plain->buf), plain->buf);
+		} else if (hunk == &file_diff->head &&
+			   starts_with(p, "Binary files "))
+			file_diff->binary = 1;
+
+		if (file_diff->deleted && file_diff->mode_change)
+			BUG("diff contains delete *and* a mode change?!?\n%.*s",
+			    (int)(eol - (plain->buf + file_diff->head.start)),
+			    plain->buf + file_diff->head.start);
+
+		if ((marker == '-' || marker == '+') && *p == ' ')
+			hunk->splittable_into++;
+		if (marker && *p != '\\')
+			marker = *p;
+
+		p = eol == pend ? pend : eol + 1;
+		hunk->end = p - plain->buf;
+
+		if (colored) {
+			char *colored_eol = memchr(colored_p, '\n',
+						   colored_pend - colored_p);
+			if (colored_eol)
+				colored_p = colored_eol + 1;
+			else
+				colored_p = colored_pend;
+
+			hunk->colored_end = colored_p - colored->buf;
+		}
+
+		if (mode_change) {
+			if (file_diff->hunk_nr != 1)
+				BUG("mode change in hunk #%d???",
+				    (int)file_diff->hunk_nr);
+			/* Adjust the end of the "mode change" pseudo-hunk */
+			file_diff->hunk->end = hunk->end;
+			if (colored)
+				file_diff->hunk->colored_end = hunk->colored_end;
+		}
+	}
+
+	if (marker == '-' || marker == '+')
+		/*
+		 * Last hunk ended in non-context line (i.e. it appended lines
+		 * to the file, so there are no trailing context lines).
+		 */
+		hunk->splittable_into++;
+
+	return 0;
+}
+
+static size_t find_next_line(struct strbuf *sb, size_t offset)
+{
+	char *eol;
+
+	if (offset >= sb->len)
+		BUG("looking for next line beyond buffer (%d >= %d)\n%s",
+		    (int)offset, (int)sb->len, sb->buf);
+
+	eol = memchr(sb->buf + offset, '\n', sb->len - offset);
+	if (!eol)
+		return sb->len;
+	return eol - sb->buf + 1;
+}
+
+static void render_hunk(struct add_p_state *s, struct hunk *hunk,
+			ssize_t delta, int colored, struct strbuf *out)
+{
+	struct hunk_header *header = &hunk->header;
+
+	if (hunk->header.old_offset != 0 || hunk->header.new_offset != 0) {
+		/*
+		 * Generate the hunk header dynamically, except for special
+		 * hunks (such as the diff header).
+		 */
+		const char *p;
+		size_t len;
+		unsigned long old_offset = header->old_offset;
+		unsigned long new_offset = header->new_offset;
+
+		if (!colored) {
+			p = s->plain.buf + header->extra_start;
+			len = header->extra_end - header->extra_start;
+		} else {
+			strbuf_addstr(out, s->s.fraginfo_color);
+			p = s->colored.buf + header->colored_extra_start;
+			len = header->colored_extra_end
+				- header->colored_extra_start;
+		}
+
+		new_offset += delta;
+
+		strbuf_addf(out, "@@ -%lu,%lu +%lu,%lu @@",
+			    old_offset, header->old_count,
+			    new_offset, header->new_count);
+		if (len)
+			strbuf_add(out, p, len);
+		else if (colored)
+			strbuf_addf(out, "%s\n", GIT_COLOR_RESET);
+		else
+			strbuf_addch(out, '\n');
+	}
+
+	if (colored)
+		strbuf_add(out, s->colored.buf + hunk->colored_start,
+			   hunk->colored_end - hunk->colored_start);
+	else
+		strbuf_add(out, s->plain.buf + hunk->start,
+			   hunk->end - hunk->start);
+}
+
+static void render_diff_header(struct add_p_state *s,
+			       struct file_diff *file_diff, int colored,
+			       struct strbuf *out)
+{
+	/*
+	 * If there was a mode change, the first hunk is a pseudo hunk that
+	 * corresponds to the mode line in the header. If the user did not want
+	 * to stage that "hunk", we actually have to cut it out from the header.
+	 */
+	int skip_mode_change =
+		file_diff->mode_change && file_diff->hunk->use != USE_HUNK;
+	struct hunk *head = &file_diff->head, *first = file_diff->hunk;
+
+	if (!skip_mode_change) {
+		render_hunk(s, head, 0, colored, out);
+		return;
+	}
+
+	if (colored) {
+		const char *p = s->colored.buf;
+
+		strbuf_add(out, p + head->colored_start,
+			    first->colored_start - head->colored_start);
+		strbuf_add(out, p + first->colored_end,
+			    head->colored_end - first->colored_end);
+	} else {
+		const char *p = s->plain.buf;
+
+		strbuf_add(out, p + head->start, first->start - head->start);
+		strbuf_add(out, p + first->end, head->end - first->end);
+	}
+}
+
+/* Coalesce hunks again that were split */
+static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
+		       size_t *hunk_index, int use_all, struct hunk *merged)
+{
+	size_t i = *hunk_index, delta;
+	struct hunk *hunk = file_diff->hunk + i;
+	/* `header` corresponds to the merged hunk */
+	struct hunk_header *header = &merged->header, *next;
+
+	if (!use_all && hunk->use != USE_HUNK)
+		return 0;
+
+	*merged = *hunk;
+	/* We simply skip the colored part (if any) when merging hunks */
+	merged->colored_start = merged->colored_end = 0;
+
+	for (; i + 1 < file_diff->hunk_nr; i++) {
+		hunk++;
+		next = &hunk->header;
+
+		/*
+		 * Stop merging hunks when:
+		 *
+		 * - the hunk is not selected for use, or
+		 * - the hunk does not overlap with the already-merged hunk(s)
+		 */
+		if ((!use_all && hunk->use != USE_HUNK) ||
+		    header->new_offset >= next->new_offset + merged->delta ||
+		    header->new_offset + header->new_count
+		    < next->new_offset + merged->delta)
+			break;
+
+		/*
+		 * If the hunks were not edited, and overlap, we can simply
+		 * extend the line range.
+		 */
+		if (merged->start < hunk->start && merged->end > hunk->start) {
+			merged->end = hunk->end;
+			merged->colored_end = hunk->colored_end;
+			delta = 0;
+		} else {
+			const char *plain = s->plain.buf;
+			size_t  overlapping_line_count = header->new_offset
+				+ header->new_count - merged->delta
+				- next->new_offset;
+			size_t overlap_end = hunk->start;
+			size_t overlap_start = overlap_end;
+			size_t overlap_next, len, j;
+
+			/*
+			 * One of the hunks was edited: the modified hunk was
+			 * appended to the strbuf `s->plain`.
+			 *
+			 * Let's ensure that at least the last context line of
+			 * the first hunk overlaps with the corresponding line
+			 * of the second hunk, and then merge.
+			 */
+			for (j = 0; j < overlapping_line_count; j++) {
+				overlap_next = find_next_line(&s->plain,
+							      overlap_end);
+
+				if (overlap_next > hunk->end)
+					BUG("failed to find %d context lines "
+					    "in:\n%.*s",
+					    (int)overlapping_line_count,
+					    (int)(hunk->end - hunk->start),
+					    plain + hunk->start);
+
+				if (plain[overlap_end] != ' ')
+					return error(_("expected context line "
+						       "#%d in\n%.*s"),
+						     (int)(j + 1),
+						     (int)(hunk->end
+							   - hunk->start),
+						     plain + hunk->start);
+
+				overlap_start = overlap_end;
+				overlap_end = overlap_next;
+			}
+			len = overlap_end - overlap_start;
+
+			if (len > merged->end - merged->start ||
+			    memcmp(plain + merged->end - len,
+				   plain + overlap_start, len))
+				return error(_("hunks do not overlap:\n%.*s\n"
+					       "\tdoes not end with:\n%.*s"),
+					     (int)(merged->end - merged->start),
+					     plain + merged->start,
+					     (int)len, plain + overlap_start);
+
+			/*
+			 * Since the start-end ranges are not adjacent, we
+			 * cannot simply take the union of the ranges. To
+			 * address that, we temporarily append the union of the
+			 * lines to the `plain` strbuf.
+			 */
+			if (merged->end != s->plain.len) {
+				size_t start = s->plain.len;
+
+				strbuf_add(&s->plain, plain + merged->start,
+					   merged->end - merged->start);
+				plain = s->plain.buf;
+				merged->start = start;
+				merged->end = s->plain.len;
+			}
+
+			strbuf_add(&s->plain,
+				   plain + overlap_end,
+				   hunk->end - overlap_end);
+			merged->end = s->plain.len;
+			merged->splittable_into += hunk->splittable_into;
+			delta = merged->delta;
+			merged->delta += hunk->delta;
+		}
+
+		header->old_count = next->old_offset + next->old_count
+			- header->old_offset;
+		header->new_count = next->new_offset + delta
+			+ next->new_count - header->new_offset;
+	}
+
+	if (i == *hunk_index)
+		return 0;
+
+	*hunk_index = i;
+	return 1;
+}
+
+static void reassemble_patch(struct add_p_state *s,
+			     struct file_diff *file_diff, int use_all,
+			     struct strbuf *out)
+{
+	struct hunk *hunk;
+	size_t save_len = s->plain.len, i;
+	ssize_t delta = 0;
+
+	render_diff_header(s, file_diff, 0, out);
+
+	for (i = file_diff->mode_change; i < file_diff->hunk_nr; i++) {
+		struct hunk merged = { 0 };
+
+		hunk = file_diff->hunk + i;
+		if (!use_all && hunk->use != USE_HUNK)
+			delta += hunk->header.old_count
+				- hunk->header.new_count;
+		else {
+			/* merge overlapping hunks into a temporary hunk */
+			if (merge_hunks(s, file_diff, &i, use_all, &merged))
+				hunk = &merged;
+
+			render_hunk(s, hunk, delta, 0, out);
+
+			/*
+			 * In case `merge_hunks()` used `plain` as a scratch
+			 * pad (this happens when an edited hunk had to be
+			 * coalesced with another hunk).
+			 */
+			strbuf_setlen(&s->plain, save_len);
+
+			delta += hunk->delta;
+		}
+	}
+}
+
+static int split_hunk(struct add_p_state *s, struct file_diff *file_diff,
+		       size_t hunk_index)
+{
+	int colored = !!s->colored.len, first = 1;
+	struct hunk *hunk = file_diff->hunk + hunk_index;
+	size_t splittable_into;
+	size_t end, colored_end, current, colored_current = 0, context_line_count;
+	struct hunk_header remaining, *header;
+	char marker, ch;
+
+	if (hunk_index >= file_diff->hunk_nr)
+		BUG("invalid hunk index: %d (must be >= 0 and < %d)",
+		    (int)hunk_index, (int)file_diff->hunk_nr);
+
+	if (hunk->splittable_into < 2)
+		return 0;
+	splittable_into = hunk->splittable_into;
+
+	end = hunk->end;
+	colored_end = hunk->colored_end;
+
+	remaining = hunk->header;
+
+	file_diff->hunk_nr += splittable_into - 1;
+	ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr, file_diff->hunk_alloc);
+	if (hunk_index + splittable_into < file_diff->hunk_nr)
+		memmove(file_diff->hunk + hunk_index + splittable_into,
+			file_diff->hunk + hunk_index + 1,
+			(file_diff->hunk_nr - hunk_index - splittable_into)
+			* sizeof(*hunk));
+	hunk = file_diff->hunk + hunk_index;
+	hunk->splittable_into = 1;
+	memset(hunk + 1, 0, (splittable_into - 1) * sizeof(*hunk));
+
+	header = &hunk->header;
+	header->old_count = header->new_count = 0;
+
+	current = hunk->start;
+	if (colored)
+		colored_current = hunk->colored_start;
+	marker = '\0';
+	context_line_count = 0;
+
+	while (splittable_into > 1) {
+		ch = s->plain.buf[current];
+
+		if (!ch)
+			BUG("buffer overrun while splitting hunks");
+
+		/*
+		 * Is this the first context line after a chain of +/- lines?
+		 * Then record the start of the next split hunk.
+		 */
+		if ((marker == '-' || marker == '+') && ch == ' ') {
+			first = 0;
+			hunk[1].start = current;
+			if (colored)
+				hunk[1].colored_start = colored_current;
+			context_line_count = 0;
+		}
+
+		/*
+		 * Was the previous line a +/- one? Alternatively, is this the
+		 * first line (and not a +/- one)?
+		 *
+		 * Then just increment the appropriate counter and continue
+		 * with the next line.
+		 */
+		if (marker != ' ' || (ch != '-' && ch != '+')) {
+next_hunk_line:
+			/* Comment lines are attached to the previous line */
+			if (ch == '\\')
+				ch = marker ? marker : ' ';
+
+			/* current hunk not done yet */
+			if (ch == ' ')
+				context_line_count++;
+			else if (ch == '-')
+				header->old_count++;
+			else if (ch == '+')
+				header->new_count++;
+			else
+				BUG("unhandled diff marker: '%c'", ch);
+			marker = ch;
+			current = find_next_line(&s->plain, current);
+			if (colored)
+				colored_current =
+					find_next_line(&s->colored,
+						       colored_current);
+			continue;
+		}
+
+		/*
+		 * We got us the start of a new hunk!
+		 *
+		 * This is a context line, so it is shared with the previous
+		 * hunk, if any.
+		 */
+
+		if (first) {
+			if (header->old_count || header->new_count)
+				BUG("counts are off: %d/%d",
+				    (int)header->old_count,
+				    (int)header->new_count);
+
+			header->old_count = context_line_count;
+			header->new_count = context_line_count;
+			context_line_count = 0;
+			first = 0;
+			goto next_hunk_line;
+		}
+
+		remaining.old_offset += header->old_count;
+		remaining.old_count -= header->old_count;
+		remaining.new_offset += header->new_count;
+		remaining.new_count -= header->new_count;
+
+		/* initialize next hunk header's offsets */
+		hunk[1].header.old_offset =
+			header->old_offset + header->old_count;
+		hunk[1].header.new_offset =
+			header->new_offset + header->new_count;
+
+		/* add one split hunk */
+		header->old_count += context_line_count;
+		header->new_count += context_line_count;
+
+		hunk->end = current;
+		if (colored)
+			hunk->colored_end = colored_current;
+
+		hunk++;
+		hunk->splittable_into = 1;
+		hunk->use = hunk[-1].use;
+		header = &hunk->header;
+
+		header->old_count = header->new_count = context_line_count;
+		context_line_count = 0;
+
+		splittable_into--;
+		marker = ch;
+	}
+
+	/* last hunk simply gets the rest */
+	if (header->old_offset != remaining.old_offset)
+		BUG("miscounted old_offset: %lu != %lu",
+		    header->old_offset, remaining.old_offset);
+	if (header->new_offset != remaining.new_offset)
+		BUG("miscounted new_offset: %lu != %lu",
+		    header->new_offset, remaining.new_offset);
+	header->old_count = remaining.old_count;
+	header->new_count = remaining.new_count;
+	hunk->end = end;
+	if (colored)
+		hunk->colored_end = colored_end;
+
+	return 0;
+}
+
+static void recolor_hunk(struct add_p_state *s, struct hunk *hunk)
+{
+	const char *plain = s->plain.buf;
+	size_t current, eol, next;
+
+	if (!s->colored.len)
+		return;
+
+	hunk->colored_start = s->colored.len;
+	for (current = hunk->start; current < hunk->end; ) {
+		for (eol = current; eol < hunk->end; eol++)
+			if (plain[eol] == '\n')
+				break;
+		next = eol + (eol < hunk->end);
+		if (eol > current && plain[eol - 1] == '\r')
+			eol--;
+
+		strbuf_addstr(&s->colored,
+			      plain[current] == '-' ?
+			      s->s.file_old_color :
+			      plain[current] == '+' ?
+			      s->s.file_new_color :
+			      s->s.context_color);
+		strbuf_add(&s->colored, plain + current, eol - current);
+		strbuf_addstr(&s->colored, GIT_COLOR_RESET);
+		if (next > eol)
+			strbuf_add(&s->colored, plain + eol, next - eol);
+		current = next;
+	}
+	hunk->colored_end = s->colored.len;
+}
+
+static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
+{
+	size_t i;
+
+	strbuf_reset(&s->buf);
+	strbuf_commented_addf(&s->buf, _("Manual hunk edit mode -- see bottom for "
+				      "a quick guide.\n"));
+	render_hunk(s, hunk, 0, 0, &s->buf);
+	strbuf_commented_addf(&s->buf,
+			      _("---\n"
+				"To remove '%c' lines, make them ' ' lines "
+				"(context).\n"
+				"To remove '%c' lines, delete them.\n"
+				"Lines starting with %c will be removed.\n"),
+			      '-', '+', comment_line_char);
+	strbuf_commented_addf(&s->buf,
+			      _("If the patch applies cleanly, the edited hunk "
+				"will immediately be\n"
+				"marked for staging.\n"));
+	/*
+	 * TRANSLATORS: 'it' refers to the patch mentioned in the previous
+	 * messages.
+	 */
+	strbuf_commented_addf(&s->buf,
+			      _("If it does not apply cleanly, you will be "
+				"given an opportunity to\n"
+				"edit again.  If all lines of the hunk are "
+				"removed, then the edit is\n"
+				"aborted and the hunk is left unchanged.\n"));
+
+	if (strbuf_edit_interactively(&s->buf, "addp-hunk-edit.diff", NULL) < 0)
+		return -1;
+
+	/* strip out commented lines */
+	hunk->start = s->plain.len;
+	for (i = 0; i < s->buf.len; ) {
+		size_t next = find_next_line(&s->buf, i);
+
+		if (s->buf.buf[i] != comment_line_char)
+			strbuf_add(&s->plain, s->buf.buf + i, next - i);
+		i = next;
+	}
+
+	hunk->end = s->plain.len;
+	if (hunk->end == hunk->start)
+		/* The user aborted editing by deleting everything */
+		return 0;
+
+	recolor_hunk(s, hunk);
+
+	/*
+	 * If the hunk header is intact, parse it, otherwise simply use the
+	 * hunk header prior to editing (which will adjust `hunk->start` to
+	 * skip the hunk header).
+	 */
+	if (s->plain.buf[hunk->start] == '@' &&
+	    parse_hunk_header(s, hunk) < 0)
+		return error(_("could not parse hunk header"));
+
+	return 1;
+}
+
+static ssize_t recount_edited_hunk(struct add_p_state *s, struct hunk *hunk,
+				   size_t orig_old_count, size_t orig_new_count)
+{
+	struct hunk_header *header = &hunk->header;
+	size_t i;
+
+	header->old_count = header->new_count = 0;
+	for (i = hunk->start; i < hunk->end; ) {
+		switch (s->plain.buf[i]) {
+		case '-':
+			header->old_count++;
+			break;
+		case '+':
+			header->new_count++;
+			break;
+		case ' ': case '\r': case '\n':
+			header->old_count++;
+			header->new_count++;
+			break;
+		}
+
+		i = find_next_line(&s->plain, i);
+	}
+
+	return orig_old_count - orig_new_count
+		- header->old_count + header->new_count;
+}
+
+static int run_apply_check(struct add_p_state *s,
+			   struct file_diff *file_diff)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+
+	strbuf_reset(&s->buf);
+	reassemble_patch(s, file_diff, 1, &s->buf);
+
+	setup_child_process(s, &cp,
+			    "apply", "--cached", "--check", NULL);
+	if (pipe_command(&cp, s->buf.buf, s->buf.len, NULL, 0, NULL, 0))
+		return error(_("'git apply --cached' failed"));
+
+	return 0;
+}
+
+static int prompt_yesno(struct add_p_state *s, const char *prompt)
+{
+	for (;;) {
+		color_fprintf(stdout, s->s.prompt_color, "%s", _(prompt));
+		fflush(stdout);
+		if (strbuf_getline(&s->answer, stdin) == EOF)
+			return -1;
+		strbuf_trim_trailing_newline(&s->answer);
+		switch (tolower(s->answer.buf[0])) {
+		case 'n': return 0;
+		case 'y': return 1;
+		}
+	}
+}
+
+static int edit_hunk_loop(struct add_p_state *s,
+			  struct file_diff *file_diff, struct hunk *hunk)
+{
+	size_t plain_len = s->plain.len, colored_len = s->colored.len;
+	struct hunk backup;
+
+	backup = *hunk;
+
+	for (;;) {
+		int res = edit_hunk_manually(s, hunk);
+		if (res == 0) {
+			/* abandonded */
+			*hunk = backup;
+			return -1;
+		}
+
+		if (res > 0) {
+			hunk->delta +=
+				recount_edited_hunk(s, hunk,
+						    backup.header.old_count,
+						    backup.header.new_count);
+			if (!run_apply_check(s, file_diff))
+				return 0;
+		}
+
+		/* Drop edits (they were appended to s->plain) */
+		strbuf_setlen(&s->plain, plain_len);
+		strbuf_setlen(&s->colored, colored_len);
+		*hunk = backup;
+
+		/*
+		 * TRANSLATORS: do not translate [y/n]
+		 * The program will only accept that input at this point.
+		 * Consider translating (saying "no" discards!) as
+		 * (saying "n" for "no" discards!) if the translation
+		 * of the word "no" does not start with n.
+		 */
+		res = prompt_yesno(s, _("Your edited hunk does not apply. "
+					"Edit again (saying \"no\" discards!) "
+					"[y/n]? "));
+		if (res < 1)
+			return -1;
+	}
+}
+
+#define SUMMARY_HEADER_WIDTH 20
+#define SUMMARY_LINE_WIDTH 80
+static void summarize_hunk(struct add_p_state *s, struct hunk *hunk,
+			   struct strbuf *out)
+{
+	struct hunk_header *header = &hunk->header;
+	struct strbuf *plain = &s->plain;
+	size_t len = out->len, i;
+
+	strbuf_addf(out, " -%lu,%lu +%lu,%lu ",
+		    header->old_offset, header->old_count,
+		    header->new_offset, header->new_count);
+	if (out->len - len < SUMMARY_HEADER_WIDTH)
+		strbuf_addchars(out, ' ',
+				SUMMARY_HEADER_WIDTH + len - out->len);
+	for (i = hunk->start; i < hunk->end; i = find_next_line(plain, i))
+		if (plain->buf[i] != ' ')
+			break;
+	if (i < hunk->end)
+		strbuf_add(out, plain->buf + i, find_next_line(plain, i) - i);
+	if (out->len - len > SUMMARY_LINE_WIDTH)
+		strbuf_setlen(out, len + SUMMARY_LINE_WIDTH);
+	strbuf_complete_line(out);
+}
+
+#define DISPLAY_HUNKS_LINES 20
+static size_t display_hunks(struct add_p_state *s,
+			    struct file_diff *file_diff, size_t start_index)
+{
+	size_t end_index = start_index + DISPLAY_HUNKS_LINES;
+
+	if (end_index > file_diff->hunk_nr)
+		end_index = file_diff->hunk_nr;
+
+	while (start_index < end_index) {
+		struct hunk *hunk = file_diff->hunk + start_index++;
+
+		strbuf_reset(&s->buf);
+		strbuf_addf(&s->buf, "%c%2d: ", hunk->use == USE_HUNK ? '+'
+			    : hunk->use == SKIP_HUNK ? '-' : ' ',
+			    (int)start_index);
+		summarize_hunk(s, hunk, &s->buf);
+		fputs(s->buf.buf, stdout);
+	}
+
+	return end_index;
+}
+
+static const char help_patch_text[] =
+N_("y - stage this hunk\n"
+   "n - do not stage this hunk\n"
+   "q - quit; do not stage this hunk or any of the remaining ones\n"
+   "a - stage this and all the remaining hunks\n"
+   "d - do not stage this hunk nor any of the remaining hunks\n");
+
+static const char help_patch_remainder[] =
+N_("j - leave this hunk undecided, see next undecided hunk\n"
+   "J - leave this hunk undecided, see next hunk\n"
+   "k - leave this hunk undecided, see previous undecided hunk\n"
+   "K - leave this hunk undecided, see previous hunk\n"
+   "g - select a hunk to go to\n"
+   "/ - search for a hunk matching the given regex\n"
+   "s - split the current hunk into smaller hunks\n"
+   "e - manually edit the current hunk\n"
+   "? - print help\n");
+
+static int patch_update_file(struct add_p_state *s,
+			     struct file_diff *file_diff)
+{
+	size_t hunk_index = 0;
+	ssize_t i, undecided_previous, undecided_next;
+	struct hunk *hunk;
+	char ch;
+	struct child_process cp = CHILD_PROCESS_INIT;
+	int colored = !!s->colored.len, quit = 0;
+	enum prompt_mode_type prompt_mode_type;
+
+	if (!file_diff->hunk_nr)
+		return 0;
+
+	strbuf_reset(&s->buf);
+	render_diff_header(s, file_diff, colored, &s->buf);
+	fputs(s->buf.buf, stdout);
+	for (;;) {
+		if (hunk_index >= file_diff->hunk_nr)
+			hunk_index = 0;
+		hunk = file_diff->hunk + hunk_index;
+
+		undecided_previous = -1;
+		for (i = hunk_index - 1; i >= 0; i--)
+			if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
+				undecided_previous = i;
+				break;
+			}
+
+		undecided_next = -1;
+		for (i = hunk_index + 1; i < file_diff->hunk_nr; i++)
+			if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
+				undecided_next = i;
+				break;
+			}
+
+		/* Everything decided? */
+		if (undecided_previous < 0 && undecided_next < 0 &&
+		    hunk->use != UNDECIDED_HUNK)
+			break;
+
+		strbuf_reset(&s->buf);
+		render_hunk(s, hunk, 0, colored, &s->buf);
+		fputs(s->buf.buf, stdout);
+
+		strbuf_reset(&s->buf);
+		if (undecided_previous >= 0)
+			strbuf_addstr(&s->buf, ",k");
+		if (hunk_index)
+			strbuf_addstr(&s->buf, ",K");
+		if (undecided_next >= 0)
+			strbuf_addstr(&s->buf, ",j");
+		if (hunk_index + 1 < file_diff->hunk_nr)
+			strbuf_addstr(&s->buf, ",J");
+		if (file_diff->hunk_nr > 1)
+			strbuf_addstr(&s->buf, ",g,/");
+		if (hunk->splittable_into > 1)
+			strbuf_addstr(&s->buf, ",s");
+		if (hunk_index + 1 > file_diff->mode_change &&
+		    !file_diff->deleted)
+			strbuf_addstr(&s->buf, ",e");
+
+		if (file_diff->deleted)
+			prompt_mode_type = PROMPT_DELETION;
+		else if (file_diff->mode_change && !hunk_index)
+			prompt_mode_type = PROMPT_MODE_CHANGE;
+		else
+			prompt_mode_type = PROMPT_HUNK;
+
+		color_fprintf(stdout, s->s.prompt_color,
+			      "(%"PRIuMAX"/%"PRIuMAX") ",
+			      (uintmax_t)hunk_index + 1,
+			      (uintmax_t)file_diff->hunk_nr);
+		color_fprintf(stdout, s->s.prompt_color,
+			      _(prompt_mode[prompt_mode_type]), s->buf.buf);
+		fflush(stdout);
+		if (strbuf_getline(&s->answer, stdin) == EOF)
+			break;
+		strbuf_trim_trailing_newline(&s->answer);
+
+		if (!s->answer.len)
+			continue;
+		ch = tolower(s->answer.buf[0]);
+		if (ch == 'y') {
+			hunk->use = USE_HUNK;
+soft_increment:
+			hunk_index = undecided_next < 0 ?
+				file_diff->hunk_nr : undecided_next;
+		} else if (ch == 'n') {
+			hunk->use = SKIP_HUNK;
+			goto soft_increment;
+		} else if (ch == 'a') {
+			for (; hunk_index < file_diff->hunk_nr; hunk_index++) {
+				hunk = file_diff->hunk + hunk_index;
+				if (hunk->use == UNDECIDED_HUNK)
+					hunk->use = USE_HUNK;
+			}
+		} else if (ch == 'd' || ch == 'q') {
+			for (; hunk_index < file_diff->hunk_nr; hunk_index++) {
+				hunk = file_diff->hunk + hunk_index;
+				if (hunk->use == UNDECIDED_HUNK)
+					hunk->use = SKIP_HUNK;
+			}
+			if (ch == 'q') {
+				quit = 1;
+				break;
+			}
+		} else if (s->answer.buf[0] == 'K') {
+			if (hunk_index)
+				hunk_index--;
+			else
+				err(s, _("No previous hunk"));
+		} else if (s->answer.buf[0] == 'J') {
+			if (hunk_index + 1 < file_diff->hunk_nr)
+				hunk_index++;
+			else
+				err(s, _("No next hunk"));
+		} else if (s->answer.buf[0] == 'k') {
+			if (undecided_previous >= 0)
+				hunk_index = undecided_previous;
+			else
+				err(s, _("No previous hunk"));
+		} else if (s->answer.buf[0] == 'j') {
+			if (undecided_next >= 0)
+				hunk_index = undecided_next;
+			else
+				err(s, _("No next hunk"));
+		} else if (s->answer.buf[0] == 'g') {
+			char *pend;
+			unsigned long response;
+
+			if (file_diff->hunk_nr < 2) {
+				err(s, _("No other hunks to goto"));
+				continue;
+			}
+			strbuf_remove(&s->answer, 0, 1);
+			strbuf_trim(&s->answer);
+			i = hunk_index - DISPLAY_HUNKS_LINES / 2;
+			if (i < file_diff->mode_change)
+				i = file_diff->mode_change;
+			while (s->answer.len == 0) {
+				i = display_hunks(s, file_diff, i);
+				printf("%s", i < file_diff->hunk_nr ?
+				       _("go to which hunk (<ret> to see "
+					 "more)? ") : _("go to which hunk? "));
+				fflush(stdout);
+				if (strbuf_getline(&s->answer,
+						   stdin) == EOF)
+					break;
+				strbuf_trim_trailing_newline(&s->answer);
+			}
+
+			strbuf_trim(&s->answer);
+			response = strtoul(s->answer.buf, &pend, 10);
+			if (*pend || pend == s->answer.buf)
+				err(s, _("Invalid number: '%s'"),
+				    s->answer.buf);
+			else if (0 < response && response <= file_diff->hunk_nr)
+				hunk_index = response - 1;
+			else
+				err(s, Q_("Sorry, only %d hunk available.",
+					  "Sorry, only %d hunks available.",
+					  file_diff->hunk_nr),
+				    (int)file_diff->hunk_nr);
+		} else if (s->answer.buf[0] == '/') {
+			regex_t regex;
+			int ret;
+
+			if (file_diff->hunk_nr < 2) {
+				err(s, _("No other hunks to search"));
+				continue;
+			}
+			strbuf_remove(&s->answer, 0, 1);
+			strbuf_trim_trailing_newline(&s->answer);
+			if (s->answer.len == 0) {
+				printf("%s", _("search for regex? "));
+				fflush(stdout);
+				if (strbuf_getline(&s->answer,
+						   stdin) == EOF)
+					break;
+				strbuf_trim_trailing_newline(&s->answer);
+				if (s->answer.len == 0)
+					continue;
+			}
+			ret = regcomp(&regex, s->answer.buf,
+				      REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+			if (ret) {
+				char errbuf[1024];
+
+				regerror(ret, &regex, errbuf, sizeof(errbuf));
+				err(s, _("Malformed search regexp %s: %s"),
+				    s->answer.buf, errbuf);
+				continue;
+			}
+			i = hunk_index;
+			for (;;) {
+				/* render the hunk into a scratch buffer */
+				render_hunk(s, file_diff->hunk + i, 0, 0,
+					    &s->buf);
+				if (regexec(&regex, s->buf.buf, 0, NULL, 0)
+				    != REG_NOMATCH)
+					break;
+				i++;
+				if (i == file_diff->hunk_nr)
+					i = 0;
+				if (i != hunk_index)
+					continue;
+				err(s, _("No hunk matches the given pattern"));
+				break;
+			}
+			hunk_index = i;
+		} else if (s->answer.buf[0] == 's') {
+			size_t splittable_into = hunk->splittable_into;
+			if (splittable_into < 2)
+				err(s, _("Sorry, cannot split this hunk"));
+			else if (!split_hunk(s, file_diff,
+					     hunk - file_diff->hunk))
+				color_fprintf_ln(stdout, s->s.header_color,
+						 _("Split into %d hunks."),
+						 (int)splittable_into);
+		} else if (s->answer.buf[0] == 'e') {
+			if (hunk_index + 1 == file_diff->mode_change)
+				err(s, _("Sorry, cannot edit this hunk"));
+			else if (edit_hunk_loop(s, file_diff, hunk) >= 0) {
+				hunk->use = USE_HUNK;
+				goto soft_increment;
+			}
+		} else {
+			const char *p = _(help_patch_remainder), *eol = p;
+
+			color_fprintf(stdout, s->s.help_color, "%s",
+				      _(help_patch_text));
+
+			/*
+			 * Show only those lines of the remainder that are
+			 * actually applicable with the current hunk.
+			 */
+			for (; *p; p = eol + (*eol == '\n')) {
+				eol = strchrnul(p, '\n');
+
+				/*
+				 * `s->buf` still contains the part of the
+				 * commands shown in the prompt that are not
+				 * always available.
+				 */
+				if (*p != '?' && !strchr(s->buf.buf, *p))
+					continue;
+
+				color_fprintf_ln(stdout, s->s.help_color,
+						 "%.*s", (int)(eol - p), p);
+			}
+		}
+	}
+
+	/* Any hunk to be used? */
+	for (i = 0; i < file_diff->hunk_nr; i++)
+		if (file_diff->hunk[i].use == USE_HUNK)
+			break;
+
+	if (i < file_diff->hunk_nr) {
+		/* At least one hunk selected: apply */
+		strbuf_reset(&s->buf);
+		reassemble_patch(s, file_diff, 0, &s->buf);
+
+		discard_index(s->s.r->index);
+		setup_child_process(s, &cp, "apply", "--cached", NULL);
+		if (pipe_command(&cp, s->buf.buf, s->buf.len,
+				 NULL, 0, NULL, 0))
+			error(_("'git apply --cached' failed"));
+		if (!repo_read_index(s->s.r))
+			repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0,
+						     1, NULL, NULL, NULL);
+	}
+
+	putchar('\n');
+	return quit;
+}
+
+int run_add_p(struct repository *r, const struct pathspec *ps)
+{
+	struct add_p_state s = {
+		{ r }, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
+	};
+	size_t i, binary_count = 0;
+
+	init_add_i_state(&s.s, r);
+
+	if (discard_index(r->index) < 0 || repo_read_index(r) < 0 ||
+	    repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1,
+					 NULL, NULL, NULL) < 0 ||
+	    parse_diff(&s, ps) < 0) {
+		strbuf_release(&s.plain);
+		strbuf_release(&s.colored);
+		return -1;
+	}
+
+	for (i = 0; i < s.file_diff_nr; i++)
+		if (s.file_diff[i].binary && !s.file_diff[i].hunk_nr)
+			binary_count++;
+		else if (patch_update_file(&s, s.file_diff + i))
+			break;
+
+	if (s.file_diff_nr == 0)
+		fprintf(stderr, _("No changes.\n"));
+	else if (binary_count == s.file_diff_nr)
+		fprintf(stderr, _("Only binary files changed.\n"));
+
+	strbuf_release(&s.answer);
+	strbuf_release(&s.buf);
+	strbuf_release(&s.plain);
+	strbuf_release(&s.colored);
+	return 0;
+}
diff --git a/advice.c b/advice.c
index 3ee0ee2..249c60d 100644
--- a/advice.c
+++ b/advice.c
@@ -30,6 +30,7 @@
 int advice_graft_file_deprecated = 1;
 int advice_checkout_ambiguous_remote_branch_name = 1;
 int advice_nested_tag = 1;
+int advice_submodule_alternate_error_strategy_die = 1;
 
 static int advice_use_color = -1;
 static char advice_colors[][COLOR_MAXLEN] = {
@@ -89,6 +90,7 @@
 	{ "graftFileDeprecated", &advice_graft_file_deprecated },
 	{ "checkoutAmbiguousRemoteBranchName", &advice_checkout_ambiguous_remote_branch_name },
 	{ "nestedTag", &advice_nested_tag },
+	{ "submoduleAlternateErrorStrategyDie", &advice_submodule_alternate_error_strategy_die },
 
 	/* make this an alias for backward compatibility */
 	{ "pushNonFastForward", &advice_push_update_rejected }
diff --git a/advice.h b/advice.h
index d015404..b706780 100644
--- a/advice.h
+++ b/advice.h
@@ -30,6 +30,7 @@
 extern int advice_graft_file_deprecated;
 extern int advice_checkout_ambiguous_remote_branch_name;
 extern int advice_nested_tag;
+extern int advice_submodule_alternate_error_strategy_die;
 
 int git_default_advice_config(const char *var, const char *value);
 __attribute__((format (printf, 1, 2)))
diff --git a/apply.c b/apply.c
index b9291f5..fab4432 100644
--- a/apply.c
+++ b/apply.c
@@ -450,7 +450,7 @@
 
 	/*
 	 * Proposed "new-style" GNU patch/diff format; see
-	 * https://public-inbox.org/git/7vll0wvb2a.fsf@assigned-by-dhcp.cox.net/
+	 * https://lore.kernel.org/git/7vll0wvb2a.fsf@assigned-by-dhcp.cox.net/
 	 */
 	if (unquote_c_style(&name, line, NULL)) {
 		strbuf_release(&name);
@@ -2662,6 +2662,16 @@
 	int backwards_lno, forwards_lno, current_lno;
 
 	/*
+	 * When running with --allow-overlap, it is possible that a hunk is
+	 * seen that pretends to start at the beginning (but no longer does),
+	 * and that *still* needs to match the end. So trust `match_end` more
+	 * than `match_beginning`.
+	 */
+	if (state->allow_overlap && match_beginning && match_end &&
+	    img->nr - preimage->nr != 0)
+		match_beginning = 0;
+
+	/*
 	 * If match_beginning or match_end is specified, there is no
 	 * point starting from a wrong line that will never match and
 	 * wander around and wait for a match at the specified end.
@@ -4183,8 +4193,8 @@
 		old_name = slash_old + 1;
 		new_name = slash_new + 1;
 	}
-	/* p->old_name thru old_name is the common prefix, and old_name and new_name
-	 * through the end of names are renames
+	/* p->old_name through old_name is the common prefix, and old_name and
+	 * new_name through the end of names are renames
 	 */
 	if (old_name != p->old_name)
 		printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
diff --git a/archive-zip.c b/archive-zip.c
index 4d66b5b..11f5b19 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -24,6 +24,11 @@
 #define ZIP_STREAM	(1 <<  3)
 #define ZIP_UTF8	(1 << 11)
 
+enum zip_method {
+	ZIP_METHOD_STORE = 0,
+	ZIP_METHOD_DEFLATE = 8
+};
+
 struct zip_local_header {
 	unsigned char magic[4];
 	unsigned char version[2];
@@ -291,7 +296,7 @@
 	unsigned long attr2;
 	unsigned long compressed_size;
 	unsigned long crc;
-	int method;
+	enum zip_method method;
 	unsigned char *out;
 	void *deflated = NULL;
 	void *buffer;
@@ -320,7 +325,7 @@
 	}
 
 	if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
-		method = 0;
+		method = ZIP_METHOD_STORE;
 		attr2 = 16;
 		out = NULL;
 		size = 0;
@@ -330,13 +335,13 @@
 		enum object_type type = oid_object_info(args->repo, oid,
 							&size);
 
-		method = 0;
+		method = ZIP_METHOD_STORE;
 		attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) :
 			(mode & 0111) ? ((mode) << 16) : 0;
 		if (S_ISLNK(mode) || (mode & 0111))
 			creator_version = 0x0317;
 		if (S_ISREG(mode) && args->compression_level != 0 && size > 0)
-			method = 8;
+			method = ZIP_METHOD_DEFLATE;
 
 		if (S_ISREG(mode) && type == OBJ_BLOB && !args->convert &&
 		    size > big_file_threshold) {
@@ -358,7 +363,7 @@
 						    buffer, size);
 			out = buffer;
 		}
-		compressed_size = (method == 0) ? size : 0;
+		compressed_size = (method == ZIP_METHOD_STORE) ? size : 0;
 	} else {
 		return error(_("unsupported file mode: 0%o (SHA1: %s)"), mode,
 				oid_to_hex(oid));
@@ -367,13 +372,13 @@
 	if (creator_version > max_creator_version)
 		max_creator_version = creator_version;
 
-	if (buffer && method == 8) {
+	if (buffer && method == ZIP_METHOD_DEFLATE) {
 		out = deflated = zlib_deflate_raw(buffer, size,
 						  args->compression_level,
 						  &compressed_size);
 		if (!out || compressed_size >= size) {
 			out = buffer;
-			method = 0;
+			method = ZIP_METHOD_STORE;
 			compressed_size = size;
 		}
 	}
@@ -420,7 +425,7 @@
 		zip_offset += ZIP64_EXTRA_SIZE;
 	}
 
-	if (stream && method == 0) {
+	if (stream && method == ZIP_METHOD_STORE) {
 		unsigned char buf[STREAM_BUFFER_SIZE];
 		ssize_t readlen;
 
@@ -443,7 +448,7 @@
 		zip_offset += compressed_size;
 
 		write_zip_data_desc(size, compressed_size, crc);
-	} else if (stream && method == 8) {
+	} else if (stream && method == ZIP_METHOD_DEFLATE) {
 		unsigned char buf[STREAM_BUFFER_SIZE];
 		ssize_t readlen;
 		git_zstream zstream;
@@ -603,18 +608,18 @@
 static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time)
 {
 	time_t time;
-	struct tm *t;
+	struct tm tm;
 
 	if (date_overflows(*timestamp))
 		die(_("timestamp too large for this system: %"PRItime),
 		    *timestamp);
 	time = (time_t)*timestamp;
-	t = localtime(&time);
+	localtime_r(&time, &tm);
 	*timestamp = time;
 
-	*dos_date = t->tm_mday + (t->tm_mon + 1) * 32 +
-	            (t->tm_year + 1900 - 1980) * 512;
-	*dos_time = t->tm_sec / 2 + t->tm_min * 32 + t->tm_hour * 2048;
+	*dos_date = tm.tm_mday + (tm.tm_mon + 1) * 32 +
+		    (tm.tm_year + 1900 - 1980) * 512;
+	*dos_time = tm.tm_sec / 2 + tm.tm_min * 32 + tm.tm_hour * 2048;
 }
 
 static int archive_zip_config(const char *var, const char *value, void *data)
diff --git a/argv-array.c b/argv-array.c
index f352ea9..61ef8c0 100644
--- a/argv-array.c
+++ b/argv-array.c
@@ -46,7 +46,7 @@
 	const char *arg;
 
 	va_start(ap, array);
-	while((arg = va_arg(ap, const char *)))
+	while ((arg = va_arg(ap, const char *)))
 		argv_array_push(array, arg);
 	va_end(ap);
 }
diff --git a/argv-array.h b/argv-array.h
index a39ba43..a7d3b10 100644
--- a/argv-array.h
+++ b/argv-array.h
@@ -1,8 +1,32 @@
 #ifndef ARGV_ARRAY_H
 #define ARGV_ARRAY_H
 
+/**
+ * The argv-array API allows one to dynamically build and store
+ * NULL-terminated lists.  An argv-array maintains the invariant that the
+ * `argv` member always points to a non-NULL array, and that the array is
+ * always NULL-terminated at the element pointed to by `argv[argc]`. This
+ * makes the result suitable for passing to functions expecting to receive
+ * argv from main().
+ *
+ * The string-list API (documented in string-list.h) is similar, but cannot be
+ * used for these purposes; instead of storing a straight string pointer,
+ * it contains an item structure with a `util` field that is not compatible
+ * with the traditional argv interface.
+ *
+ * Each `argv_array` manages its own memory. Any strings pushed into the
+ * array are duplicated, and all memory is freed by argv_array_clear().
+ */
+
 extern const char *empty_argv[];
 
+/**
+ * A single array. This should be initialized by assignment from
+ * `ARGV_ARRAY_INIT`, or by calling `argv_array_init`. The `argv`
+ * member contains the actual array; the `argc` member contains the
+ * number of elements in the array, not including the terminating
+ * NULL.
+ */
 struct argv_array {
 	const char **argv;
 	int argc;
@@ -11,17 +35,55 @@
 
 #define ARGV_ARRAY_INIT { empty_argv, 0, 0 }
 
+/**
+ * Initialize an array. This is no different than assigning from
+ * `ARGV_ARRAY_INIT`.
+ */
 void argv_array_init(struct argv_array *);
+
+/* Push a copy of a string onto the end of the array. */
 const char *argv_array_push(struct argv_array *, const char *);
+
+/**
+ * Format a string and push it onto the end of the array. This is a
+ * convenience wrapper combining `strbuf_addf` and `argv_array_push`.
+ */
 __attribute__((format (printf,2,3)))
 const char *argv_array_pushf(struct argv_array *, const char *fmt, ...);
+
+/**
+ * Push a list of strings onto the end of the array. The arguments
+ * should be a list of `const char *` strings, terminated by a NULL
+ * argument.
+ */
 LAST_ARG_MUST_BE_NULL
 void argv_array_pushl(struct argv_array *, ...);
+
+/* Push a null-terminated array of strings onto the end of the array. */
 void argv_array_pushv(struct argv_array *, const char **);
+
+/**
+ * Remove the final element from the array. If there are no
+ * elements in the array, do nothing.
+ */
 void argv_array_pop(struct argv_array *);
+
 /* Splits by whitespace; does not handle quoted arguments! */
 void argv_array_split(struct argv_array *, const char *);
+
+/**
+ * Free all memory associated with the array and return it to the
+ * initial, empty state.
+ */
 void argv_array_clear(struct argv_array *);
+
+/**
+ * Disconnect the `argv` member from the `argv_array` struct and
+ * return it. The caller is responsible for freeing the memory used
+ * by the array, and by the strings it references. After detaching,
+ * the `argv_array` is in a reinitialized state and can be pushed
+ * into again.
+ */
 const char **argv_array_detach(struct argv_array *);
 
 #endif /* ARGV_ARRAY_H */
diff --git a/attr.c b/attr.c
index 11f19b5..a826b2e 100644
--- a/attr.c
+++ b/attr.c
@@ -1,7 +1,6 @@
 /*
  * Handle git attributes.  See gitattributes(5) for a description of
- * the file syntax, and Documentation/technical/api-gitattributes.txt
- * for a description of the API.
+ * the file syntax, and attr.h for a description of the API.
  *
  * One basic design decision here is that we are not going to support
  * an insanely large number of attributes.
diff --git a/attr.h b/attr.h
index b0378bf..404548f 100644
--- a/attr.h
+++ b/attr.h
@@ -1,9 +1,121 @@
 #ifndef ATTR_H
 #define ATTR_H
 
+/**
+ * gitattributes mechanism gives a uniform way to associate various attributes
+ * to set of paths.
+ *
+ *
+ * Querying Specific Attributes
+ * ----------------------------
+ *
+ * - Prepare `struct attr_check` using attr_check_initl() function, enumerating
+ *   the names of attributes whose values you are interested in, terminated with
+ *   a NULL pointer.  Alternatively, an empty `struct attr_check` can be
+ *   prepared by calling `attr_check_alloc()` function and then attributes you
+ *   want to ask about can be added to it with `attr_check_append()` function.
+ *
+ * - Call `git_check_attr()` to check the attributes for the path.
+ *
+ * - Inspect `attr_check` structure to see how each of the attribute in the
+ *   array is defined for the path.
+ *
+ *
+ * Example
+ * -------
+ *
+ * To see how attributes "crlf" and "ident" are set for different paths.
+ *
+ * - Prepare a `struct attr_check` with two elements (because we are checking
+ *   two attributes):
+ *
+ * ------------
+ * static struct attr_check *check;
+ * static void setup_check(void)
+ * {
+ * 	if (check)
+ * 		return; // already done
+ * check = attr_check_initl("crlf", "ident", NULL);
+ * }
+ * ------------
+ *
+ * - Call `git_check_attr()` with the prepared `struct attr_check`:
+ *
+ * ------------
+ * const char *path;
+ *
+ * setup_check();
+ * git_check_attr(path, check);
+ * ------------
+ *
+ * - Act on `.value` member of the result, left in `check->items[]`:
+ *
+ * ------------
+ * const char *value = check->items[0].value;
+ *
+ * if (ATTR_TRUE(value)) {
+ * The attribute is Set, by listing only the name of the
+ * attribute in the gitattributes file for the path.
+ * } else if (ATTR_FALSE(value)) {
+ * The attribute is Unset, by listing the name of the
+ *         attribute prefixed with a dash - for the path.
+ * } else if (ATTR_UNSET(value)) {
+ * The attribute is neither set nor unset for the path.
+ * } else if (!strcmp(value, "input")) {
+ * If none of ATTR_TRUE(), ATTR_FALSE(), or ATTR_UNSET() is
+ *         true, the value is a string set in the gitattributes
+ * file for the path by saying "attr=value".
+ * } else if (... other check using value as string ...) {
+ * ...
+ * }
+ * ------------
+ *
+ * To see how attributes in argv[] are set for different paths, only
+ * the first step in the above would be different.
+ *
+ * ------------
+ * static struct attr_check *check;
+ * static void setup_check(const char **argv)
+ * {
+ *     check = attr_check_alloc();
+ *     while (*argv) {
+ *         struct git_attr *attr = git_attr(*argv);
+ *         attr_check_append(check, attr);
+ *         argv++;
+ *     }
+ * }
+ * ------------
+ *
+ *
+ * Querying All Attributes
+ * -----------------------
+ *
+ * To get the values of all attributes associated with a file:
+ *
+ * - Prepare an empty `attr_check` structure by calling `attr_check_alloc()`.
+ *
+ * - Call `git_all_attrs()`, which populates the `attr_check` with the
+ * attributes attached to the path.
+ *
+ * - Iterate over the `attr_check.items[]` array to examine the attribute
+ * names and values. The name of the attribute described by an
+ * `attr_check.items[]` object can be retrieved via
+ * `git_attr_name(check->items[i].attr)`. (Please note that no items will be
+ * returned for unset attributes, so `ATTR_UNSET()` will return false for all
+ * returned `attr_check.items[]` objects.)
+ *
+ * - Free the `attr_check` struct by calling `attr_check_free()`.
+ */
+
 struct index_state;
 
-/* An attribute is a pointer to this opaque structure */
+/**
+ * An attribute is an opaque object that is identified by its name. Pass the
+ * name to `git_attr()` function to obtain the object of this type.
+ * The internal representation of this structure is of no interest to the
+ * calling programs. The name of the attribute can be retrieved by calling
+ * `git_attr_name()`.
+ */
 struct git_attr;
 
 /* opaque structures used internally for attribute collection */
@@ -21,21 +133,36 @@
 extern const char git_attr__true[];
 extern const char git_attr__false[];
 
-/* For public to check git_attr_check results */
+/**
+ * Attribute Values
+ * ----------------
+ *
+ * An attribute for a path can be in one of four states: Set, Unset, Unspecified
+ * or set to a string, and `.value` member of `struct attr_check_item` records
+ * it. The three macros check these, if none of them returns true, `.value`
+ * member points at a string value of the attribute for the path.
+ */
+
+/* Returns true if the attribute is Set for the path. */
 #define ATTR_TRUE(v) ((v) == git_attr__true)
+
+/* Returns true if the attribute is Unset for the path. */
 #define ATTR_FALSE(v) ((v) == git_attr__false)
+
+/* Returns true if the attribute is Unspecified for the path. */
 #define ATTR_UNSET(v) ((v) == NULL)
 
-/*
- * Send one or more git_attr_check to git_check_attrs(), and
- * each 'value' member tells what its value is.
- * Unset one is returned as NULL.
- */
+/* This structure represents one attribute and its value. */
 struct attr_check_item {
 	const struct git_attr *attr;
 	const char *value;
 };
 
+/**
+ * This structure represents a collection of `attr_check_item`. It is passed to
+ * `git_check_attr()` function, specifying the attributes to check, and
+ * receives their values.
+ */
 struct attr_check {
 	int nr;
 	int alloc;
diff --git a/builtin/add.c b/builtin/add.c
index dd18e5c..4c38aff 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -20,6 +20,7 @@
 #include "bulk-checkin.h"
 #include "argv-array.h"
 #include "submodule.h"
+#include "add-interactive.h"
 
 static const char * const builtin_add_usage[] = {
 	N_("git add [<options>] [--] <pathspec>..."),
@@ -28,6 +29,8 @@
 static int patch_interactive, add_interactive, edit_interactive;
 static int take_worktree_changes;
 static int add_renormalize;
+static int pathspec_file_nul;
+static const char *pathspec_from_file;
 
 struct update_callback_data {
 	int flags;
@@ -185,6 +188,21 @@
 {
 	int status, i;
 	struct argv_array argv = ARGV_ARRAY_INIT;
+	int use_builtin_add_i =
+		git_env_bool("GIT_TEST_ADD_I_USE_BUILTIN", -1);
+
+	if (use_builtin_add_i < 0)
+		git_config_get_bool("add.interactive.usebuiltin",
+				    &use_builtin_add_i);
+
+	if (use_builtin_add_i == 1) {
+		if (!patch_mode)
+			return !!run_add_i(the_repository, pathspec);
+		if (strcmp(patch_mode, "--patch"))
+			die("'%s' not yet supported in the built-in add -p",
+			    patch_mode);
+		return !!run_add_p(the_repository, pathspec);
+	}
 
 	argv_array_push(&argv, "add--interactive");
 	if (patch_mode)
@@ -309,6 +327,8 @@
 		   N_("override the executable bit of the listed files")),
 	OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo,
 			N_("warn when adding an embedded repository")),
+	OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
+	OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
 	OPT_END(),
 };
 
@@ -319,6 +339,7 @@
 		ignore_add_errors = git_config_bool(var, value);
 		return 0;
 	}
+
 	return git_default_config(var, value, cb);
 }
 
@@ -402,11 +423,17 @@
 			  builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
 	if (patch_interactive)
 		add_interactive = 1;
-	if (add_interactive)
+	if (add_interactive) {
+		if (pathspec_from_file)
+			die(_("--pathspec-from-file is incompatible with --interactive/--patch"));
 		exit(interactive_add(argc - 1, argv + 1, prefix, patch_interactive));
+	}
 
-	if (edit_interactive)
+	if (edit_interactive) {
+		if (pathspec_from_file)
+			die(_("--pathspec-from-file is incompatible with --edit"));
 		return(edit_patch(argc, argv, prefix));
+	}
 	argc--;
 	argv++;
 
@@ -418,10 +445,6 @@
 	if (addremove && take_worktree_changes)
 		die(_("-A and -u are mutually incompatible"));
 
-	if (!take_worktree_changes && addremove_explicit < 0 && argc)
-		/* Turn "git add pathspec..." to "git add -A pathspec..." */
-		addremove = 1;
-
 	if (!show_only && ignore_missing)
 		die(_("Option --ignore-missing can only be used together with --dry-run"));
 
@@ -434,19 +457,6 @@
 
 	hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
 
-	flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
-		 (show_only ? ADD_CACHE_PRETEND : 0) |
-		 (intent_to_add ? ADD_CACHE_INTENT : 0) |
-		 (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
-		 (!(addremove || take_worktree_changes)
-		  ? ADD_CACHE_IGNORE_REMOVAL : 0));
-
-	if (require_pathspec && argc == 0) {
-		fprintf(stderr, _("Nothing specified, nothing added.\n"));
-		fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n"));
-		return 0;
-	}
-
 	/*
 	 * Check the "pathspec '%s' did not match any files" block
 	 * below before enabling new magic.
@@ -456,6 +466,35 @@
 		       PATHSPEC_SYMLINK_LEADING_PATH,
 		       prefix, argv);
 
+	if (pathspec_from_file) {
+		if (pathspec.nr)
+			die(_("--pathspec-from-file is incompatible with pathspec arguments"));
+
+		parse_pathspec_file(&pathspec, PATHSPEC_ATTR,
+				    PATHSPEC_PREFER_FULL |
+				    PATHSPEC_SYMLINK_LEADING_PATH,
+				    prefix, pathspec_from_file, pathspec_file_nul);
+	} else if (pathspec_file_nul) {
+		die(_("--pathspec-file-nul requires --pathspec-from-file"));
+	}
+
+	if (require_pathspec && pathspec.nr == 0) {
+		fprintf(stderr, _("Nothing specified, nothing added.\n"));
+		fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n"));
+		return 0;
+	}
+
+	if (!take_worktree_changes && addremove_explicit < 0 && pathspec.nr)
+		/* Turn "git add pathspec..." to "git add -A pathspec..." */
+		addremove = 1;
+
+	flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
+		 (show_only ? ADD_CACHE_PRETEND : 0) |
+		 (intent_to_add ? ADD_CACHE_INTENT : 0) |
+		 (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
+		 (!(addremove || take_worktree_changes)
+		  ? ADD_CACHE_IGNORE_REMOVAL : 0));
+
 	if (read_cache_preload(&pathspec) < 0)
 		die(_("index file corrupt"));
 
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 1fbe156..1718df7 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -169,11 +169,12 @@
 
 		argv_array_pushl(&argv, "checkout", branch.buf, "--", NULL);
 		if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
+			error(_("could not check out original"
+				" HEAD '%s'. Try 'git bisect"
+				" reset <commit>'."), branch.buf);
 			strbuf_release(&branch);
 			argv_array_clear(&argv);
-			return error(_("could not check out original"
-				       " HEAD '%s'. Try 'git bisect"
-				       " reset <commit>'."), branch.buf);
+			return -1;
 		}
 		argv_array_clear(&argv);
 	}
@@ -281,11 +282,11 @@
 	return 1;
 }
 
-static const char *need_bad_and_good_revision_warning =
+static const char need_bad_and_good_revision_warning[] =
 	N_("You need to give me at least one %s and %s revision.\n"
 	   "You can use \"git bisect %s\" and \"git bisect %s\" for that.");
 
-static const char *need_bisect_start_warning =
+static const char need_bisect_start_warning[] =
 	N_("You need to start by \"git bisect start\".\n"
 	   "You then need to give me at least one %s and %s revision.\n"
 	   "You can use \"git bisect %s\" and \"git bisect %s\" for that.");
diff --git a/builtin/blame.c b/builtin/blame.c
index 10185cc..bf1cecd 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -861,14 +861,6 @@
 		OPT_STRING_LIST(0, "ignore-revs-file", &ignore_revs_file_list, N_("file"), N_("Ignore revisions from <file>")),
 		OPT_BIT(0, "color-lines", &output_option, N_("color redundant metadata from previous line differently"), OUTPUT_COLOR_LINE),
 		OPT_BIT(0, "color-by-age", &output_option, N_("color lines by age"), OUTPUT_SHOW_AGE_WITH_COLOR),
-
-		/*
-		 * The following two options are parsed by parse_revision_opt()
-		 * and are only included here to get included in the "-h"
-		 * output:
-		 */
-		{ OPTION_LOWLEVEL_CALLBACK, 0, "indent-heuristic", NULL, NULL, N_("Use an experimental heuristic to improve diffs"), PARSE_OPT_NOARG, NULL, 0, parse_opt_unknown_cb },
-
 		OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL),
 		OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")),
 		OPT_STRING(0, "contents", &contents_from, N_("file"), N_("Use <file>'s contents as the final image")),
diff --git a/builtin/branch.c b/builtin/branch.c
index 2ef2146..d8297f8 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -624,7 +624,7 @@
 		OPT_SET_INT_F(0, "set-upstream", &track, N_("do not use"),
 			BRANCH_TRACK_OVERRIDE, PARSE_OPT_HIDDEN),
 		OPT_STRING('u', "set-upstream-to", &new_upstream, N_("upstream"), N_("change the upstream info")),
-		OPT_BOOL(0, "unset-upstream", &unset_upstream, N_("Unset the upstream info")),
+		OPT_BOOL(0, "unset-upstream", &unset_upstream, N_("unset the upstream info")),
 		OPT__COLOR(&branch_use_color, N_("use colored output")),
 		OPT_SET_INT('r', "remotes",     &filter.kind, N_("act on remote-tracking branches"),
 			FILTER_REFS_REMOTES),
diff --git a/builtin/bundle.c b/builtin/bundle.c
index 1ea4bfd..f049d27 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -1,4 +1,6 @@
 #include "builtin.h"
+#include "argv-array.h"
+#include "parse-options.h"
 #include "cache.h"
 #include "bundle.h"
 
@@ -9,59 +11,184 @@
  * bundle supporting "fetch", "pull", and "ls-remote".
  */
 
-static const char builtin_bundle_usage[] =
-  "git bundle create <file> <git-rev-list args>\n"
-  "   or: git bundle verify <file>\n"
-  "   or: git bundle list-heads <file> [<refname>...]\n"
-  "   or: git bundle unbundle <file> [<refname>...]";
+static const char * const builtin_bundle_usage[] = {
+  N_("git bundle create [<options>] <file> <git-rev-list args>"),
+  N_("git bundle verify [<options>] <file>"),
+  N_("git bundle list-heads <file> [<refname>...]"),
+  N_("git bundle unbundle <file> [<refname>...]"),
+  NULL
+};
+
+static const char * const builtin_bundle_create_usage[] = {
+  N_("git bundle create [<options>] <file> <git-rev-list args>"),
+  NULL
+};
+
+static const char * const builtin_bundle_verify_usage[] = {
+  N_("git bundle verify [<options>] <file>"),
+  NULL
+};
+
+static const char * const builtin_bundle_list_heads_usage[] = {
+  N_("git bundle list-heads <file> [<refname>...]"),
+  NULL
+};
+
+static const char * const builtin_bundle_unbundle_usage[] = {
+  N_("git bundle unbundle <file> [<refname>...]"),
+  NULL
+};
+
+static int verbose;
+
+static int parse_options_cmd_bundle(int argc,
+		const char **argv,
+		const char* prefix,
+		const char * const usagestr[],
+		const struct option options[],
+		const char **bundle_file) {
+	int newargc;
+	newargc = parse_options(argc, argv, NULL, options, usagestr,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+	if (argc < 1)
+		usage_with_options(usagestr, options);
+	*bundle_file = prefix_filename(prefix, argv[0]);
+	return newargc;
+}
+
+static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
+	int all_progress_implied = 0;
+	int progress = isatty(STDERR_FILENO);
+	struct argv_array pack_opts;
+
+	struct option options[] = {
+		OPT_SET_INT('q', "quiet", &progress,
+			    N_("do not show progress meter"), 0),
+		OPT_SET_INT(0, "progress", &progress,
+			    N_("show progress meter"), 1),
+		OPT_SET_INT(0, "all-progress", &progress,
+			    N_("show progress meter during object writing phase"), 2),
+		OPT_BOOL(0, "all-progress-implied",
+			 &all_progress_implied,
+			 N_("similar to --all-progress when progress meter is shown")),
+		OPT_END()
+	};
+	const char* bundle_file;
+
+	argc = parse_options_cmd_bundle(argc, argv, prefix,
+			builtin_bundle_create_usage, options, &bundle_file);
+	/* bundle internals use argv[1] as further parameters */
+
+	argv_array_init(&pack_opts);
+	if (progress == 0)
+		argv_array_push(&pack_opts, "--quiet");
+	else if (progress == 1)
+		argv_array_push(&pack_opts, "--progress");
+	else if (progress == 2)
+		argv_array_push(&pack_opts, "--all-progress");
+	if (progress && all_progress_implied)
+		argv_array_push(&pack_opts, "--all-progress-implied");
+
+	if (!startup_info->have_repository)
+		die(_("Need a repository to create a bundle."));
+	return !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts);
+}
+
+static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
+	struct bundle_header header;
+	int bundle_fd = -1;
+	int quiet = 0;
+
+	struct option options[] = {
+		OPT_BOOL('q', "quiet", &quiet,
+			    N_("do not show bundle details")),
+		OPT_END()
+	};
+	const char* bundle_file;
+
+	argc = parse_options_cmd_bundle(argc, argv, prefix,
+			builtin_bundle_verify_usage, options, &bundle_file);
+	/* bundle internals use argv[1] as further parameters */
+
+	memset(&header, 0, sizeof(header));
+	if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0)
+		return 1;
+	close(bundle_fd);
+	if (verify_bundle(the_repository, &header, !quiet))
+		return 1;
+	fprintf(stderr, _("%s is okay\n"), bundle_file);
+	return 0;
+}
+
+static int cmd_bundle_list_heads(int argc, const char **argv, const char *prefix) {
+	struct bundle_header header;
+	int bundle_fd = -1;
+
+	struct option options[] = {
+		OPT_END()
+	};
+	const char* bundle_file;
+
+	argc = parse_options_cmd_bundle(argc, argv, prefix,
+			builtin_bundle_list_heads_usage, options, &bundle_file);
+	/* bundle internals use argv[1] as further parameters */
+
+	memset(&header, 0, sizeof(header));
+	if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0)
+		return 1;
+	close(bundle_fd);
+	return !!list_bundle_refs(&header, argc, argv);
+}
+
+static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix) {
+	struct bundle_header header;
+	int bundle_fd = -1;
+
+	struct option options[] = {
+		OPT_END()
+	};
+	const char* bundle_file;
+
+	argc = parse_options_cmd_bundle(argc, argv, prefix,
+			builtin_bundle_unbundle_usage, options, &bundle_file);
+	/* bundle internals use argv[1] as further parameters */
+
+	memset(&header, 0, sizeof(header));
+	if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0)
+		return 1;
+	if (!startup_info->have_repository)
+		die(_("Need a repository to unbundle."));
+	return !!unbundle(the_repository, &header, bundle_fd, 0) ||
+		list_bundle_refs(&header, argc, argv);
+}
 
 int cmd_bundle(int argc, const char **argv, const char *prefix)
 {
-	struct bundle_header header;
-	const char *cmd, *bundle_file;
-	int bundle_fd = -1;
+	struct option options[] = {
+		OPT__VERBOSE(&verbose, N_("be verbose; must be placed before a subcommand")),
+		OPT_END()
+	};
+	int result;
 
-	if (argc < 3)
-		usage(builtin_bundle_usage);
+	argc = parse_options(argc, argv, prefix, options, builtin_bundle_usage,
+		PARSE_OPT_STOP_AT_NON_OPTION);
 
-	cmd = argv[1];
-	bundle_file = prefix_filename(prefix, argv[2]);
-	argc -= 2;
-	argv += 2;
+	packet_trace_identity("bundle");
 
-	memset(&header, 0, sizeof(header));
-	if (strcmp(cmd, "create") && (bundle_fd =
-				read_bundle_header(bundle_file, &header)) < 0)
-		return 1;
+	if (argc < 2)
+		usage_with_options(builtin_bundle_usage, options);
 
-	if (!strcmp(cmd, "verify")) {
-		close(bundle_fd);
-		if (argc != 1) {
-			usage(builtin_bundle_usage);
-			return 1;
-		}
-		if (verify_bundle(the_repository, &header, 1))
-			return 1;
-		fprintf(stderr, _("%s is okay\n"), bundle_file);
-		return 0;
+	else if (!strcmp(argv[0], "create"))
+		result = cmd_bundle_create(argc, argv, prefix);
+	else if (!strcmp(argv[0], "verify"))
+		result = cmd_bundle_verify(argc, argv, prefix);
+	else if (!strcmp(argv[0], "list-heads"))
+		result = cmd_bundle_list_heads(argc, argv, prefix);
+	else if (!strcmp(argv[0], "unbundle"))
+		result = cmd_bundle_unbundle(argc, argv, prefix);
+	else {
+		error(_("Unknown subcommand: %s"), argv[0]);
+		usage_with_options(builtin_bundle_usage, options);
 	}
-	if (!strcmp(cmd, "list-heads")) {
-		close(bundle_fd);
-		return !!list_bundle_refs(&header, argc, argv);
-	}
-	if (!strcmp(cmd, "create")) {
-		if (argc < 2) {
-			usage(builtin_bundle_usage);
-			return 1;
-		}
-		if (!startup_info->have_repository)
-			die(_("Need a repository to create a bundle."));
-		return !!create_bundle(the_repository, bundle_file, argc, argv);
-	} else if (!strcmp(cmd, "unbundle")) {
-		if (!startup_info->have_repository)
-			die(_("Need a repository to unbundle."));
-		return !!unbundle(the_repository, &header, bundle_fd, 0) ||
-			list_bundle_refs(&header, argc, argv);
-	} else
-		usage(builtin_bundle_usage);
+	return result ? 1 : 0;
 }
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 3634a3d..b52c490 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -70,6 +70,8 @@
 	int checkout_worktree;
 	const char *ignore_unmerged_opt;
 	int ignore_unmerged;
+	int pathspec_file_nul;
+	const char *pathspec_from_file;
 
 	const char *new_branch;
 	const char *new_branch_force;
@@ -1480,6 +1482,8 @@
 		OPT_BOOL('p', "patch", &opts->patch_mode, N_("select hunks interactively")),
 		OPT_BOOL(0, "ignore-skip-worktree-bits", &opts->ignore_skipworktree,
 			 N_("do not limit pathspecs to sparse entries only")),
+		OPT_PATHSPEC_FROM_FILE(&opts->pathspec_from_file),
+		OPT_PATHSPEC_FILE_NUL(&opts->pathspec_file_nul),
 		OPT_END()
 	};
 	struct option *newopts = parse_options_concat(prevopts, options);
@@ -1618,10 +1622,6 @@
 			die(_("reference is not a tree: %s"), opts->from_treeish);
 	}
 
-	if (opts->accept_pathspec && !opts->empty_pathspec_ok && !argc &&
-	    !opts->patch_mode)	/* patch mode is special */
-		die(_("you must specify path(s) to restore"));
-
 	if (argc) {
 		parse_pathspec(&opts->pathspec, 0,
 			       opts->patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,
@@ -1641,10 +1641,33 @@
 		if (opts->force_detach)
 			die(_("git checkout: --detach does not take a path argument '%s'"),
 			    argv[0]);
+	}
 
+	if (opts->pathspec_from_file) {
+		if (opts->pathspec.nr)
+			die(_("--pathspec-from-file is incompatible with pathspec arguments"));
+
+		if (opts->force_detach)
+			die(_("--pathspec-from-file is incompatible with --detach"));
+
+		if (opts->patch_mode)
+			die(_("--pathspec-from-file is incompatible with --patch"));
+
+		parse_pathspec_file(&opts->pathspec, 0,
+				    0,
+				    prefix, opts->pathspec_from_file, opts->pathspec_file_nul);
+	} else if (opts->pathspec_file_nul) {
+		die(_("--pathspec-file-nul requires --pathspec-from-file"));
+	}
+
+	if (opts->pathspec.nr) {
 		if (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)
 			die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
 			      "checking out of the index."));
+	} else {
+		if (opts->accept_pathspec && !opts->empty_pathspec_ok &&
+		    !opts->patch_mode)	/* patch mode is special */
+			die(_("you must specify path(s) to restore"));
 	}
 
 	if (opts->new_branch) {
diff --git a/builtin/clone.c b/builtin/clone.c
index 4348d96..0fc89ae 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -813,7 +813,7 @@
 
 	if (!err && (option_recurse_submodules.nr > 0)) {
 		struct argv_array args = ARGV_ARRAY_INIT;
-		argv_array_pushl(&args, "submodule", "update", "--init", "--recursive", NULL);
+		argv_array_pushl(&args, "submodule", "update", "--require-init", "--recursive", NULL);
 
 		if (option_shallow_submodules == 1)
 			argv_array_push(&args, "--depth=1");
@@ -923,7 +923,7 @@
 	free(alternates);
 }
 
-static int dir_exists(const char *path)
+static int path_exists(const char *path)
 {
 	struct stat sb;
 	return !stat(path, &sb);
@@ -951,8 +951,6 @@
 
 	struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
 
-	fetch_if_missing = 0;
-
 	packet_trace_identity("clone");
 	argc = parse_options(argc, argv, prefix, builtin_clone_options,
 			     builtin_clone_usage, 0);
@@ -1005,7 +1003,7 @@
 		dir = guess_dir_name(repo_name, is_bundle, option_bare);
 	strip_trailing_slashes(dir);
 
-	dest_exists = dir_exists(dir);
+	dest_exists = path_exists(dir);
 	if (dest_exists && !is_empty_dir(dir))
 		die(_("destination path '%s' already exists and is not "
 			"an empty directory."), dir);
@@ -1016,7 +1014,7 @@
 		work_tree = NULL;
 	else {
 		work_tree = getenv("GIT_WORK_TREE");
-		if (work_tree && dir_exists(work_tree))
+		if (work_tree && path_exists(work_tree))
 			die(_("working tree '%s' already exists."), work_tree);
 	}
 
@@ -1044,7 +1042,7 @@
 	}
 
 	if (real_git_dir) {
-		if (dir_exists(real_git_dir))
+		if (path_exists(real_git_dir))
 			junk_git_dir_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
 		junk_git_dir = real_git_dir;
 	} else {
@@ -1292,7 +1290,6 @@
 	}
 
 	junk_mode = JUNK_LEAVE_REPO;
-	fetch_if_missing = 1;
 	err = checkout(submodule_progress);
 
 	strbuf_release(&reflog_msg);
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index ec0fc93..e0c6fc4 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -8,7 +8,6 @@
 #include "object-store.h"
 
 static char const * const builtin_commit_graph_usage[] = {
-	N_("git commit-graph read [--object-dir <objdir>]"),
 	N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
 	N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--[no-]progress] <split options>"),
 	NULL
@@ -19,11 +18,6 @@
 	NULL
 };
 
-static const char * const builtin_commit_graph_read_usage[] = {
-	N_("git commit-graph read [--object-dir <objdir>]"),
-	NULL
-};
-
 static const char * const builtin_commit_graph_write_usage[] = {
 	N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--[no-]progress] <split options>"),
 	NULL
@@ -93,66 +87,6 @@
 	return verify_commit_graph(the_repository, graph, flags);
 }
 
-static int graph_read(int argc, const char **argv)
-{
-	struct commit_graph *graph = NULL;
-	char *graph_name;
-	int open_ok;
-	int fd;
-	struct stat st;
-
-	static struct option builtin_commit_graph_read_options[] = {
-		OPT_STRING(0, "object-dir", &opts.obj_dir,
-			N_("dir"),
-			N_("The object directory to store the graph")),
-		OPT_END(),
-	};
-
-	trace2_cmd_mode("read");
-
-	argc = parse_options(argc, argv, NULL,
-			     builtin_commit_graph_read_options,
-			     builtin_commit_graph_read_usage, 0);
-
-	if (!opts.obj_dir)
-		opts.obj_dir = get_object_directory();
-
-	graph_name = get_commit_graph_filename(opts.obj_dir);
-
-	open_ok = open_commit_graph(graph_name, &fd, &st);
-	if (!open_ok)
-		die_errno(_("Could not open commit-graph '%s'"), graph_name);
-
-	graph = load_commit_graph_one_fd_st(fd, &st);
-	if (!graph)
-		return 1;
-
-	FREE_AND_NULL(graph_name);
-
-	printf("header: %08x %d %d %d %d\n",
-		ntohl(*(uint32_t*)graph->data),
-		*(unsigned char*)(graph->data + 4),
-		*(unsigned char*)(graph->data + 5),
-		*(unsigned char*)(graph->data + 6),
-		*(unsigned char*)(graph->data + 7));
-	printf("num_commits: %u\n", graph->num_commits);
-	printf("chunks:");
-
-	if (graph->chunk_oid_fanout)
-		printf(" oid_fanout");
-	if (graph->chunk_oid_lookup)
-		printf(" oid_lookup");
-	if (graph->chunk_commit_data)
-		printf(" commit_metadata");
-	if (graph->chunk_extra_edges)
-		printf(" extra_edges");
-	printf("\n");
-
-	UNLEAK(graph);
-
-	return 0;
-}
-
 extern int read_replace_refs;
 static struct split_commit_graph_opts split_opts;
 
@@ -268,8 +202,6 @@
 	save_commit_buffer = 0;
 
 	if (argc > 0) {
-		if (!strcmp(argv[0], "read"))
-			return graph_read(argc, argv);
 		if (!strcmp(argv[0], "verify"))
 			return graph_verify(argc, argv);
 		if (!strcmp(argv[0], "write"))
diff --git a/builtin/commit.c b/builtin/commit.c
index 294dc57..aa13323 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -107,9 +107,9 @@
 static int edit_flag = -1; /* unspecified */
 static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
 static int config_commit_verbose = -1; /* unspecified */
-static int no_post_rewrite, allow_empty_message;
+static int no_post_rewrite, allow_empty_message, pathspec_file_nul;
 static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg;
-static char *sign_commit;
+static char *sign_commit, *pathspec_from_file;
 
 /*
  * The default commit message cleanup mode will remove the lines
@@ -343,6 +343,26 @@
 		       PATHSPEC_PREFER_FULL,
 		       prefix, argv);
 
+	if (pathspec_from_file) {
+		if (interactive)
+			die(_("--pathspec-from-file is incompatible with --interactive/--patch"));
+
+		if (all)
+			die(_("--pathspec-from-file with -a does not make sense"));
+
+		if (pathspec.nr)
+			die(_("--pathspec-from-file is incompatible with pathspec arguments"));
+
+		parse_pathspec_file(&pathspec, 0,
+				    PATHSPEC_PREFER_FULL,
+				    prefix, pathspec_from_file, pathspec_file_nul);
+	} else if (pathspec_file_nul) {
+		die(_("--pathspec-file-nul requires --pathspec-from-file"));
+	}
+
+	if (!pathspec.nr && (also || (only && !amend && !allow_empty)))
+		die(_("No paths with --include/--only does not make sense."));
+
 	if (read_cache_preload(&pathspec) < 0)
 		die(_("index file corrupt"));
 
@@ -537,7 +557,7 @@
 	struct strbuf buf = STRBUF_INIT;
 	if (hack)
 		strbuf_addch(&buf, hack);
-	strbuf_addf(&buf, "%.*s", (int)(e - s), s);
+	strbuf_add(&buf, s, e - s);
 	setenv(var, buf.buf, 1);
 	strbuf_release(&buf);
 }
@@ -1198,8 +1218,6 @@
 
 	if (also + only + all + interactive > 1)
 		die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
-	if (argc == 0 && (also || (only && !amend && !allow_empty)))
-		die(_("No paths with --include/--only does not make sense."));
 	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
 
 	handle_untracked_files_arg(s);
@@ -1513,6 +1531,8 @@
 		OPT_BOOL(0, "amend", &amend, N_("amend previous commit")),
 		OPT_BOOL(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")),
 		{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, N_("mode"), N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
+		OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
+		OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
 		/* end commit contents options */
 
 		OPT_HIDDEN_BOOL(0, "allow-empty", &allow_empty,
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 863c858..f8765b3 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -77,6 +77,7 @@
 static struct list_objects_filter_options filter_options;
 static struct string_list server_options = STRING_LIST_INIT_DUP;
 static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
+static int fetch_write_commit_graph = -1;
 
 static int git_fetch_config(const char *k, const char *v, void *cb)
 {
@@ -198,6 +199,8 @@
 		 N_("run 'gc --auto' after fetching")),
 	OPT_BOOL(0, "show-forced-updates", &fetch_show_forced_updates,
 		 N_("check for forced-updates on all updated branches")),
+	OPT_BOOL(0, "write-commit-graph", &fetch_write_commit_graph,
+		 N_("write the commit-graph after fetching")),
 	OPT_END()
 };
 
@@ -954,18 +957,12 @@
 				kind = "";
 				what = "";
 			}
-			else if (starts_with(rm->name, "refs/heads/")) {
+			else if (skip_prefix(rm->name, "refs/heads/", &what))
 				kind = "branch";
-				what = rm->name + 11;
-			}
-			else if (starts_with(rm->name, "refs/tags/")) {
+			else if (skip_prefix(rm->name, "refs/tags/", &what))
 				kind = "tag";
-				what = rm->name + 10;
-			}
-			else if (starts_with(rm->name, "refs/remotes/")) {
+			else if (skip_prefix(rm->name, "refs/remotes/", &what))
 				kind = "remote-tracking branch";
-				what = rm->name + 13;
-			}
 			else {
 				kind = "";
 				what = rm->name;
@@ -1074,7 +1071,8 @@
 	 * we need all direct targets to exist.
 	 */
 	for (r = rm; r; r = r->next) {
-		if (!has_object_file(&r->old_oid))
+		if (!has_object_file_with_flags(&r->old_oid,
+						OBJECT_INFO_SKIP_FETCH_OBJECT))
 			return -1;
 	}
 
@@ -1400,7 +1398,7 @@
 
 		/*
 		 * We're setting the upstream configuration for the
-		 * current branch. The relevent upstream is the
+		 * current branch. The relevant upstream is the
 		 * fetched branch that is meant to be merged with the
 		 * current one, i.e. the one fetched to FETCH_HEAD.
 		 *
@@ -1411,7 +1409,7 @@
 		for (rm = ref_map; rm; rm = rm->next) {
 			if (!rm->peer_ref) {
 				if (source_ref) {
-					warning(_("multiple branch detected, incompatible with --set-upstream"));
+					warning(_("multiple branches detected, incompatible with --set-upstream"));
 					goto skip;
 				} else {
 					source_ref = rm;
@@ -1599,7 +1597,8 @@
 			return errcode;
 	}
 
-	argv_array_pushl(&argv, "fetch", "--append", "--no-auto-gc", NULL);
+	argv_array_pushl(&argv, "fetch", "--append", "--no-auto-gc",
+			"--no-write-commit-graph", NULL);
 	add_options_to_argv(&argv);
 
 	if (max_children != 1 && list->nr != 1) {
@@ -1822,8 +1821,6 @@
 		}
 	}
 
-	fetch_if_missing = 0;
-
 	if (remote) {
 		if (filter_options.choice || has_promisor_remote())
 			fetch_one_setup_partial(remote);
@@ -1865,7 +1862,9 @@
 	string_list_clear(&list, 0);
 
 	prepare_repo_settings(the_repository);
-	if (the_repository->settings.fetch_write_commit_graph) {
+	if (fetch_write_commit_graph > 0 ||
+	    (fetch_write_commit_graph < 0 &&
+	     the_repository->settings.fetch_write_commit_graph)) {
 		int commit_graph_flags = COMMIT_GRAPH_WRITE_SPLIT;
 		struct split_commit_graph_opts split_opts;
 		memset(&split_opts, 0, sizeof(struct split_commit_graph_opts));
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index a461558..05a92c5 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -106,7 +106,7 @@
 	int i, len = strlen(line);
 	struct origin_data *origin_data;
 	char *src;
-	const char *origin;
+	const char *origin, *tag_name;
 	struct src_data *src_data;
 	struct string_list_item *item;
 	int pulling_head = 0;
@@ -162,14 +162,13 @@
 	if (pulling_head) {
 		origin = src;
 		src_data->head_status |= 1;
-	} else if (starts_with(line, "branch ")) {
+	} else if (skip_prefix(line, "branch ", &origin)) {
 		origin_data->is_local_branch = 1;
-		origin = line + 7;
 		string_list_append(&src_data->branch, origin);
 		src_data->head_status |= 2;
-	} else if (starts_with(line, "tag ")) {
+	} else if (skip_prefix(line, "tag ", &tag_name)) {
 		origin = line;
-		string_list_append(&src_data->tag, origin + 4);
+		string_list_append(&src_data->tag, tag_name);
 		src_data->head_status |= 2;
 	} else if (skip_prefix(line, "remote-tracking branch ", &origin)) {
 		string_list_append(&src_data->r_branch, origin);
@@ -495,6 +494,7 @@
 		enum object_type type;
 		unsigned long size, len;
 		char *buf = read_object_file(oid, &type, &size);
+		struct signature_check sigc = { 0 };
 		struct strbuf sig = STRBUF_INIT;
 
 		if (!buf || type != OBJ_TAG)
@@ -503,10 +503,12 @@
 
 		if (size == len)
 			; /* merely annotated */
-		else if (verify_signed_buffer(buf, len, buf + len, size - len, &sig, NULL)) {
-			if (!sig.len)
-				strbuf_addstr(&sig, "gpg verification failed.\n");
-		}
+		else if (!check_signature(buf, len, buf + len, size - len,
+					  &sigc)) {
+			strbuf_addstr(&sig, sigc.gpg_output);
+			signature_check_clear(&sigc);
+		} else
+			strbuf_addstr(&sig, "gpg verification failed.\n");
 
 		if (!tag_number++) {
 			fmt_tag_signature(&tagbuf, &sig, buf, len);
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 18403a9..8d13794 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -50,40 +50,20 @@
 #define ERROR_REFS 010
 #define ERROR_COMMIT_GRAPH 020
 
-static const char *describe_object(struct object *obj)
+static const char *describe_object(const struct object_id *oid)
 {
-	static struct strbuf bufs[] = {
-		STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
-	};
-	static int b = 0;
-	struct strbuf *buf;
-	char *name = NULL;
-
-	if (name_objects)
-		name = lookup_decoration(fsck_walk_options.object_names, obj);
-
-	buf = bufs + b;
-	b = (b + 1) % ARRAY_SIZE(bufs);
-	strbuf_reset(buf);
-	strbuf_addstr(buf, oid_to_hex(&obj->oid));
-	if (name)
-		strbuf_addf(buf, " (%s)", name);
-
-	return buf->buf;
+	return fsck_describe_object(&fsck_walk_options, oid);
 }
 
-static const char *printable_type(struct object *obj)
+static const char *printable_type(const struct object_id *oid,
+				  enum object_type type)
 {
 	const char *ret;
 
-	if (obj->type == OBJ_NONE) {
-		enum object_type type = oid_object_info(the_repository,
-							&obj->oid, NULL);
-		if (type > 0)
-			object_as_type(the_repository, obj, type, 0);
-	}
+	if (type == OBJ_NONE)
+		type = oid_object_info(the_repository, oid, NULL);
 
-	ret = type_name(obj->type);
+	ret = type_name(type);
 	if (!ret)
 		ret = _("unknown");
 
@@ -118,26 +98,32 @@
 	errors_found |= ERROR_OBJECT;
 	/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */
 	fprintf_ln(stderr, _("error in %s %s: %s"),
-		   printable_type(obj), describe_object(obj), err);
+		   printable_type(&obj->oid, obj->type),
+		   describe_object(&obj->oid), err);
 	return -1;
 }
 
 static int fsck_error_func(struct fsck_options *o,
-	struct object *obj, int type, const char *message)
+			   const struct object_id *oid,
+			   enum object_type object_type,
+			   int msg_type, const char *message)
 {
-	switch (type) {
+	switch (msg_type) {
 	case FSCK_WARN:
 		/* TRANSLATORS: e.g. warning in tree 01bfda: <more explanation> */
 		fprintf_ln(stderr, _("warning in %s %s: %s"),
-			   printable_type(obj), describe_object(obj), message);
+			   printable_type(oid, object_type),
+			   describe_object(oid), message);
 		return 0;
 	case FSCK_ERROR:
 		/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */
 		fprintf_ln(stderr, _("error in %s %s: %s"),
-			   printable_type(obj), describe_object(obj), message);
+			   printable_type(oid, object_type),
+			   describe_object(oid), message);
 		return 1;
 	default:
-		BUG("%d (FSCK_IGNORE?) should never trigger this callback", type);
+		BUG("%d (FSCK_IGNORE?) should never trigger this callback",
+		    msg_type);
 	}
 }
 
@@ -155,7 +141,8 @@
 	if (!obj) {
 		/* ... these references to parent->fld are safe here */
 		printf_ln(_("broken link from %7s %s"),
-			  printable_type(parent), describe_object(parent));
+			  printable_type(&parent->oid, parent->type),
+			  describe_object(&parent->oid));
 		printf_ln(_("broken link from %7s %s"),
 			  (type == OBJ_ANY ? _("unknown") : type_name(type)),
 			  _("unknown"));
@@ -183,10 +170,10 @@
 		if (parent && !has_object_file(&obj->oid)) {
 			printf_ln(_("broken link from %7s %s\n"
 				    "              to %7s %s"),
-				  printable_type(parent),
-				  describe_object(parent),
-				  printable_type(obj),
-				  describe_object(obj));
+				  printable_type(&parent->oid, parent->type),
+				  describe_object(&parent->oid),
+				  printable_type(&obj->oid, obj->type),
+				  describe_object(&obj->oid));
 			errors_found |= ERROR_REACHABLE;
 		}
 		return 1;
@@ -292,8 +279,9 @@
 			return;
 		if (has_object_pack(&obj->oid))
 			return; /* it is in pack - forget about it */
-		printf_ln(_("missing %s %s"), printable_type(obj),
-			  describe_object(obj));
+		printf_ln(_("missing %s %s"),
+			  printable_type(&obj->oid, obj->type),
+			  describe_object(&obj->oid));
 		errors_found |= ERROR_REACHABLE;
 		return;
 	}
@@ -318,8 +306,9 @@
 	 * since this is something that is prunable.
 	 */
 	if (show_unreachable) {
-		printf_ln(_("unreachable %s %s"), printable_type(obj),
-			  describe_object(obj));
+		printf_ln(_("unreachable %s %s"),
+			  printable_type(&obj->oid, obj->type),
+			  describe_object(&obj->oid));
 		return;
 	}
 
@@ -337,12 +326,13 @@
 	 */
 	if (!(obj->flags & USED)) {
 		if (show_dangling)
-			printf_ln(_("dangling %s %s"), printable_type(obj),
-				  describe_object(obj));
+			printf_ln(_("dangling %s %s"),
+				  printable_type(&obj->oid, obj->type),
+				  describe_object(&obj->oid));
 		if (write_lost_and_found) {
 			char *filename = git_pathdup("lost-found/%s/%s",
 				obj->type == OBJ_COMMIT ? "commit" : "other",
-				describe_object(obj));
+				describe_object(&obj->oid));
 			FILE *f;
 
 			if (safe_create_leading_directories_const(filename)) {
@@ -355,7 +345,7 @@
 				if (stream_blob_to_fd(fileno(f), &obj->oid, NULL, 1))
 					die_errno(_("could not write '%s'"), filename);
 			} else
-				fprintf(f, "%s\n", describe_object(obj));
+				fprintf(f, "%s\n", describe_object(&obj->oid));
 			if (fclose(f))
 				die_errno(_("could not finish '%s'"),
 					  filename);
@@ -374,7 +364,7 @@
 static void check_object(struct object *obj)
 {
 	if (verbose)
-		fprintf_ln(stderr, _("Checking %s"), describe_object(obj));
+		fprintf_ln(stderr, _("Checking %s"), describe_object(&obj->oid));
 
 	if (obj->flags & REACHABLE)
 		check_reachable_object(obj);
@@ -432,7 +422,8 @@
 
 	if (verbose)
 		fprintf_ln(stderr, _("Checking %s %s"),
-			   printable_type(obj), describe_object(obj));
+			   printable_type(&obj->oid, obj->type),
+			   describe_object(&obj->oid));
 
 	if (fsck_walk(obj, NULL, &fsck_obj_options))
 		objerror(obj, _("broken links"));
@@ -445,7 +436,7 @@
 
 		if (!commit->parents && show_root)
 			printf_ln(_("root %s"),
-				  describe_object(&commit->object));
+				  describe_object(&commit->object.oid));
 	}
 
 	if (obj->type == OBJ_TAG) {
@@ -453,10 +444,10 @@
 
 		if (show_tags && tag->tagged) {
 			printf_ln(_("tagged %s %s (%s) in %s"),
-				  printable_type(tag->tagged),
-				  describe_object(tag->tagged),
+				  printable_type(&tag->tagged->oid, tag->tagged->type),
+				  describe_object(&tag->tagged->oid),
 				  tag->tag,
-				  describe_object(&tag->object));
+				  describe_object(&tag->object.oid));
 		}
 	}
 
@@ -499,10 +490,10 @@
 	if (!is_null_oid(oid)) {
 		obj = lookup_object(the_repository, oid);
 		if (obj && (obj->flags & HAS_OBJ)) {
-			if (timestamp && name_objects)
-				add_decoration(fsck_walk_options.object_names,
-					obj,
-					xstrfmt("%s@{%"PRItime"}", refname, timestamp));
+			if (timestamp)
+				fsck_put_object_name(&fsck_walk_options, oid,
+						     "%s@{%"PRItime"}",
+						     refname, timestamp);
 			obj->flags |= USED;
 			mark_object_reachable(obj);
 		} else if (!is_promisor_object(oid)) {
@@ -566,9 +557,8 @@
 	}
 	default_refs++;
 	obj->flags |= USED;
-	if (name_objects)
-		add_decoration(fsck_walk_options.object_names,
-			obj, xstrdup(refname));
+	fsck_put_object_name(&fsck_walk_options,
+			     oid, "%s", refname);
 	mark_object_reachable(obj);
 
 	return 0;
@@ -742,9 +732,7 @@
 			return 1;
 		}
 		obj->flags |= USED;
-		if (name_objects)
-			add_decoration(fsck_walk_options.object_names,
-				obj, xstrdup(":"));
+		fsck_put_object_name(&fsck_walk_options, &it->oid, ":");
 		mark_object_reachable(obj);
 		if (obj->type != OBJ_TREE)
 			err |= objerror(obj, _("non-tree in cache-tree"));
@@ -830,8 +818,7 @@
 	}
 
 	if (name_objects)
-		fsck_walk_options.object_names =
-			xcalloc(1, sizeof(struct decoration));
+		fsck_enable_object_names(&fsck_walk_options);
 
 	git_config(fsck_config, NULL);
 
@@ -890,9 +877,8 @@
 			}
 
 			obj->flags |= USED;
-			if (name_objects)
-				add_decoration(fsck_walk_options.object_names,
-					obj, xstrdup(arg));
+			fsck_put_object_name(&fsck_walk_options, &oid,
+					     "%s", arg);
 			mark_object_reachable(obj);
 			continue;
 		}
@@ -928,10 +914,8 @@
 				continue;
 			obj = &blob->object;
 			obj->flags |= USED;
-			if (name_objects)
-				add_decoration(fsck_walk_options.object_names,
-					obj,
-					xstrfmt(":%s", active_cache[i]->name));
+			fsck_put_object_name(&fsck_walk_options, &obj->oid,
+					     ":%s", active_cache[i]->name);
 			mark_object_reachable(obj);
 		}
 		if (active_cache_tree)
diff --git a/builtin/gc.c b/builtin/gc.c
index fadb454..3f76bf4 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -458,7 +458,7 @@
 /*
  * Returns 0 if there was no previous error and gc can proceed, 1 if
  * gc should not proceed due to an error in the last run. Prints a
- * message and returns -1 if an error occured while reading gc.log
+ * message and returns -1 if an error occurred while reading gc.log
  */
 static int report_last_gc_error(void)
 {
@@ -601,7 +601,7 @@
 		if (detach_auto) {
 			int ret = report_last_gc_error();
 			if (ret < 0)
-				/* an I/O error occured, already reported */
+				/* an I/O error occurred, already reported */
 				exit(128);
 			if (ret == 1)
 				/* Last gc --auto failed. Skip this one. */
diff --git a/builtin/log.c b/builtin/log.c
index a26f223..83a4a61 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -208,7 +208,7 @@
 	if (!rev->show_notes_given && (!rev->pretty_given || w.notes))
 		rev->show_notes = 1;
 	if (rev->show_notes)
-		init_display_notes(&rev->notes_opt);
+		load_display_notes(&rev->notes_opt);
 
 	if ((rev->diffopt.pickaxe_opts & DIFF_PICKAXE_KINDS_MASK) ||
 	    rev->diffopt.filter || rev->diffopt.flags.follow_renames)
@@ -795,6 +795,8 @@
 static enum cover_setting config_cover_letter;
 static const char *config_output_directory;
 static enum cover_from_description cover_from_description_mode = COVER_FROM_MESSAGE;
+static int show_notes;
+static struct display_notes_opt notes_opt;
 
 static enum cover_from_description parse_cover_from_description(const char *arg)
 {
@@ -814,8 +816,6 @@
 
 static int git_format_config(const char *var, const char *value, void *cb)
 {
-	struct rev_info *rev = cb;
-
 	if (!strcmp(var, "format.headers")) {
 		if (!value)
 			die(_("format.headers without value"));
@@ -902,19 +902,13 @@
 		return 0;
 	}
 	if (!strcmp(var, "format.notes")) {
-		struct strbuf buf = STRBUF_INIT;
 		int b = git_parse_maybe_bool(value);
-		if (!b)
-			return 0;
-		rev->show_notes = 1;
-		if (b < 0) {
-			strbuf_addstr(&buf, value);
-			expand_notes_ref(&buf);
-			string_list_append(&rev->notes_opt.extra_notes_refs,
-					strbuf_detach(&buf, NULL));
-		} else {
-			rev->notes_opt.use_default_notes = 1;
-		}
+		if (b < 0)
+			enable_ref_display_notes(&notes_opt, &show_notes, value);
+		else if (b)
+			enable_default_display_notes(&notes_opt, &show_notes);
+		else
+			disable_display_notes(&notes_opt, &show_notes);
 		return 0;
 	}
 	if (!strcmp(var, "format.coverfromdescription")) {
@@ -1111,6 +1105,25 @@
 	strbuf_release(&subject_sb);
 }
 
+static int get_notes_refs(struct string_list_item *item, void *arg)
+{
+	argv_array_pushf(arg, "--notes=%s", item->string);
+	return 0;
+}
+
+static void get_notes_args(struct argv_array *arg, struct rev_info *rev)
+{
+	if (!rev->show_notes) {
+		argv_array_push(arg, "--no-notes");
+	} else if (rev->notes_opt.use_default_notes > 0 ||
+		   (rev->notes_opt.use_default_notes == -1 &&
+		    !rev->notes_opt.extra_notes_refs.nr)) {
+		argv_array_push(arg, "--notes");
+	} else {
+		for_each_string_list(&rev->notes_opt.extra_notes_refs, get_notes_refs, arg);
+	}
+}
+
 static void make_cover_letter(struct rev_info *rev, int use_stdout,
 			      struct commit *origin,
 			      int nr, struct commit **list,
@@ -1183,13 +1196,16 @@
 		 * can be added later if deemed desirable.
 		 */
 		struct diff_options opts;
+		struct argv_array other_arg = ARGV_ARRAY_INIT;
 		diff_setup(&opts);
 		opts.file = rev->diffopt.file;
 		opts.use_color = rev->diffopt.use_color;
 		diff_setup_done(&opts);
 		fprintf_ln(rev->diffopt.file, "%s", rev->rdiff_title);
+		get_notes_args(&other_arg, rev);
 		show_range_diff(rev->rdiff1, rev->rdiff2,
-				rev->creation_factor, 1, &opts);
+				rev->creation_factor, 1, &opts, &other_arg);
+		argv_array_clear(&other_arg);
 	}
 }
 
@@ -1350,7 +1366,7 @@
 		string_list_clear(&extra_to, 0);
 		string_list_clear(&extra_cc, 0);
 	} else {
-	    add_header(arg);
+		add_header(arg);
 	}
 	return 0;
 }
@@ -1406,7 +1422,7 @@
 		base = lookup_commit_reference_by_name(base_commit);
 		if (!base)
 			die(_("unknown commit %s"), base_commit);
-	} else if ((base_commit && !strcmp(base_commit, "auto")) || base_auto) {
+	} else if ((base_commit && !strcmp(base_commit, "auto"))) {
 		struct branch *curr_branch = branch_get(NULL);
 		const char *upstream = branch_get_upstream(curr_branch, NULL);
 		if (upstream) {
@@ -1697,8 +1713,11 @@
 	extra_to.strdup_strings = 1;
 	extra_cc.strdup_strings = 1;
 	init_log_defaults();
+	init_display_notes(&notes_opt);
+	git_config(git_format_config, NULL);
 	repo_init_revisions(the_repository, &rev, prefix);
-	git_config(git_format_config, &rev);
+	rev.show_notes = show_notes;
+	memcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));
 	rev.commit_format = CMIT_FMT_EMAIL;
 	rev.expand_tabs_in_log_default = 0;
 	rev.verbose_header = 1;
@@ -1710,6 +1729,9 @@
 	s_r_opt.def = "HEAD";
 	s_r_opt.revarg_opt = REVARG_COMMITTISH;
 
+	if (base_auto)
+		base_commit = "auto";
+
 	if (default_attach) {
 		rev.mime_boundary = default_attach;
 		rev.no_inline = 1;
@@ -1814,7 +1836,7 @@
 		rev.diffopt.flags.binary = 1;
 
 	if (rev.show_notes)
-		init_display_notes(&rev.notes_opt);
+		load_display_notes(&rev.notes_opt);
 
 	if (!output_directory && !use_stdout)
 		output_directory = config_output_directory;
@@ -1973,7 +1995,7 @@
 	}
 
 	memset(&bases, 0, sizeof(bases));
-	if (base_commit || base_auto) {
+	if (base_commit) {
 		struct commit *base = get_base_commit(base_commit, list, nr);
 		reset_revision_walk();
 		clear_object_flags(UNINTERESTING);
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index b0f0776..6b9e8c8 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -6,6 +6,7 @@
 #include "tag.h"
 #include "refs.h"
 #include "parse-options.h"
+#include "prio-queue.h"
 #include "sha1-lookup.h"
 #include "commit-slab.h"
 
@@ -79,30 +80,16 @@
 	return 0;
 }
 
-static void name_rev(struct commit *commit,
-		const char *tip_name, timestamp_t taggerdate,
-		int generation, int distance, int from_tag,
-		int deref)
+static struct rev_name *create_or_update_name(struct commit *commit,
+					      const char *tip_name,
+					      timestamp_t taggerdate,
+					      int generation, int distance,
+					      int from_tag)
 {
 	struct rev_name *name = get_commit_rev_name(commit);
-	struct commit_list *parents;
-	int parent_number = 1;
-	char *to_free = NULL;
-
-	parse_commit(commit);
-
-	if (commit->date < cutoff)
-		return;
-
-	if (deref) {
-		tip_name = to_free = xstrfmt("%s^0", tip_name);
-
-		if (generation)
-			die("generation: %d, but deref?", generation);
-	}
 
 	if (name == NULL) {
-		name = xmalloc(sizeof(rev_name));
+		name = xmalloc(sizeof(*name));
 		set_commit_rev_name(commit, name);
 		goto copy_data;
 	} else if (is_better_name(name, taggerdate, distance, from_tag)) {
@@ -112,35 +99,97 @@
 		name->generation = generation;
 		name->distance = distance;
 		name->from_tag = from_tag;
-	} else {
+
+		return name;
+	} else
+		return NULL;
+}
+
+static void name_rev(struct commit *start_commit,
+		const char *tip_name, timestamp_t taggerdate,
+		int from_tag, int deref)
+{
+	struct prio_queue queue;
+	struct commit *commit;
+	struct commit **parents_to_queue = NULL;
+	size_t parents_to_queue_nr, parents_to_queue_alloc = 0;
+	char *to_free = NULL;
+
+	parse_commit(start_commit);
+	if (start_commit->date < cutoff)
+		return;
+
+	if (deref)
+		tip_name = to_free = xstrfmt("%s^0", tip_name);
+
+	if (!create_or_update_name(start_commit, tip_name, taggerdate, 0, 0,
+				   from_tag)) {
 		free(to_free);
 		return;
 	}
 
-	for (parents = commit->parents;
-			parents;
-			parents = parents->next, parent_number++) {
-		if (parent_number > 1) {
-			size_t len;
-			char *new_name;
+	memset(&queue, 0, sizeof(queue)); /* Use the prio_queue as LIFO */
+	prio_queue_put(&queue, start_commit);
 
-			strip_suffix(tip_name, "^0", &len);
-			if (generation > 0)
-				new_name = xstrfmt("%.*s~%d^%d", (int)len, tip_name,
-						   generation, parent_number);
-			else
-				new_name = xstrfmt("%.*s^%d", (int)len, tip_name,
-						   parent_number);
+	while ((commit = prio_queue_get(&queue))) {
+		struct rev_name *name = get_commit_rev_name(commit);
+		struct commit_list *parents;
+		int parent_number = 1;
 
-			name_rev(parents->item, new_name, taggerdate, 0,
-				 distance + MERGE_TRAVERSAL_WEIGHT,
-				 from_tag, 0);
-		} else {
-			name_rev(parents->item, tip_name, taggerdate,
-				 generation + 1, distance + 1,
-				 from_tag, 0);
+		parents_to_queue_nr = 0;
+
+		for (parents = commit->parents;
+				parents;
+				parents = parents->next, parent_number++) {
+			struct commit *parent = parents->item;
+			const char *new_name;
+			int generation, distance;
+
+			parse_commit(parent);
+			if (parent->date < cutoff)
+				continue;
+
+			if (parent_number > 1) {
+				size_t len;
+
+				strip_suffix(name->tip_name, "^0", &len);
+				if (name->generation > 0)
+					new_name = xstrfmt("%.*s~%d^%d",
+							   (int)len,
+							   name->tip_name,
+							   name->generation,
+							   parent_number);
+				else
+					new_name = xstrfmt("%.*s^%d", (int)len,
+							   name->tip_name,
+							   parent_number);
+				generation = 0;
+				distance = name->distance + MERGE_TRAVERSAL_WEIGHT;
+			} else {
+				new_name = name->tip_name;
+				generation = name->generation + 1;
+				distance = name->distance + 1;
+			}
+
+			if (create_or_update_name(parent, new_name, taggerdate,
+						  generation, distance,
+						  from_tag)) {
+				ALLOC_GROW(parents_to_queue,
+					   parents_to_queue_nr + 1,
+					   parents_to_queue_alloc);
+				parents_to_queue[parents_to_queue_nr] = parent;
+				parents_to_queue_nr++;
+			}
 		}
+
+		/* The first parent must come out first from the prio_queue */
+		while (parents_to_queue_nr)
+			prio_queue_put(&queue,
+				       parents_to_queue[--parents_to_queue_nr]);
 	}
+
+	clear_prio_queue(&queue);
+	free(parents_to_queue);
 }
 
 static int subpath_matches(const char *path, const char *filter)
@@ -161,10 +210,10 @@
 {
 	if (shorten_unambiguous)
 		refname = shorten_unambiguous_ref(refname, 0);
-	else if (starts_with(refname, "refs/heads/"))
-		refname = refname + 11;
-	else if (starts_with(refname, "refs/"))
-		refname = refname + 5;
+	else if (skip_prefix(refname, "refs/heads/", &refname))
+		; /* refname already advanced */
+	else
+		skip_prefix(refname, "refs/", &refname);
 	return refname;
 }
 
@@ -272,10 +321,9 @@
 		int from_tag = starts_with(path, "refs/tags/");
 
 		if (taggerdate == TIME_MAX)
-			taggerdate = ((struct commit *)o)->date;
+			taggerdate = commit->date;
 		path = name_ref_abbrev(path, can_abbreviate_output);
-		name_rev(commit, xstrdup(path), taggerdate, 0, 0,
-			 from_tag, deref);
+		name_rev(commit, xstrdup(path), taggerdate, from_tag, deref);
 	}
 	return 0;
 }
@@ -321,11 +369,10 @@
 	if (!n->generation)
 		return n->tip_name;
 	else {
-		int len = strlen(n->tip_name);
-		if (len > 2 && !strcmp(n->tip_name + len - 2, "^0"))
-			len -= 2;
 		strbuf_reset(buf);
-		strbuf_addf(buf, "%.*s~%d", len, n->tip_name, n->generation);
+		strbuf_addstr(buf, n->tip_name);
+		strbuf_strip_suffix(buf, "^0");
+		strbuf_addf(buf, "~%d", n->generation);
 		return buf->buf;
 	}
 }
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 5876583..393c20a 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -163,7 +163,7 @@
 	delta_buf = diff_delta(base_buf, base_size,
 			       buf, size, &delta_size, 0);
 	/*
-	 * We succesfully computed this delta once but dropped it for
+	 * We successfully computed this delta once but dropped it for
 	 * memory reasons. Something is very wrong if this time we
 	 * recompute and create a different delta.
 	 */
diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index 3059e52..822ffff 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -5,13 +5,8 @@
 
 static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result)
 {
-	char name[GIT_MAX_HEXSZ + 1];
-
-	if (!patchlen)
-		return;
-
-	memcpy(name, oid_to_hex(id), the_hash_algo->hexsz + 1);
-	printf("%s %s\n", oid_to_hex(result), name);
+	if (patchlen)
+		printf("%s %s\n", oid_to_hex(result), oid_to_hex(id));
 }
 
 static int remove_space(char *line)
diff --git a/builtin/push.c b/builtin/push.c
index 843f5b2..6dbf0f0 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -64,6 +64,7 @@
 static const char *map_refspec(const char *ref,
 			       struct remote *remote, struct ref *local_refs)
 {
+	const char *branch_name;
 	struct ref *matched = NULL;
 
 	/* Does "ref" uniquely name our ref? */
@@ -84,8 +85,8 @@
 	}
 
 	if (push_default == PUSH_DEFAULT_UPSTREAM &&
-	    starts_with(matched->name, "refs/heads/")) {
-		struct branch *branch = branch_get(matched->name + 11);
+	    skip_prefix(matched->name, "refs/heads/", &branch_name)) {
+		struct branch *branch = branch_get(branch_name);
 		if (branch->merge_nr == 1 && branch->merge[0]->src) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "%s:%s",
diff --git a/builtin/range-diff.c b/builtin/range-diff.c
index 9202e75..d8a4670 100644
--- a/builtin/range-diff.c
+++ b/builtin/range-diff.c
@@ -15,12 +15,16 @@
 {
 	int creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT;
 	struct diff_options diffopt = { NULL };
+	struct argv_array other_arg = ARGV_ARRAY_INIT;
 	int simple_color = -1;
 	struct option range_diff_options[] = {
 		OPT_INTEGER(0, "creation-factor", &creation_factor,
 			    N_("Percentage by which creation is weighted")),
 		OPT_BOOL(0, "no-dual-color", &simple_color,
 			    N_("use simple diff colors")),
+		OPT_PASSTHRU_ARGV(0, "notes", &other_arg,
+				  N_("notes"), N_("passed to 'git log'"),
+				  PARSE_OPT_OPTARG),
 		OPT_END()
 	};
 	struct option *options;
@@ -78,8 +82,9 @@
 	FREE_AND_NULL(options);
 
 	res = show_range_diff(range1.buf, range2.buf, creation_factor,
-			      simple_color < 1, &diffopt);
+			      simple_color < 1, &diffopt, &other_arg);
 
+	argv_array_clear(&other_arg);
 	strbuf_release(&range1);
 	strbuf_release(&range2);
 
diff --git a/builtin/rebase.c b/builtin/rebase.c
index e755087..e354ec8 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -79,8 +79,11 @@
 	int allow_rerere_autoupdate;
 	int keep_empty;
 	int autosquash;
+	int ignore_whitespace;
 	char *gpg_sign_opt;
 	int autostash;
+	int committer_date_is_author_date;
+	int ignore_date;
 	char *cmd;
 	int allow_empty_message;
 	int rebase_merges, rebase_cousins;
@@ -99,6 +102,7 @@
 
 static struct replay_opts get_replay_opts(const struct rebase_options *opts)
 {
+	struct strbuf strategy_buf = STRBUF_INIT;
 	struct replay_opts replay = REPLAY_OPTS_INIT;
 
 	replay.action = REPLAY_INTERACTIVE_REBASE;
@@ -112,10 +116,25 @@
 	replay.allow_empty_message = opts->allow_empty_message;
 	replay.verbose = opts->flags & REBASE_VERBOSE;
 	replay.reschedule_failed_exec = opts->reschedule_failed_exec;
+	replay.committer_date_is_author_date =
+					opts->committer_date_is_author_date;
+	replay.ignore_date = opts->ignore_date;
 	replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
 	replay.strategy = opts->strategy;
+
 	if (opts->strategy_opts)
-		parse_strategy_opts(&replay, opts->strategy_opts);
+		strbuf_addstr(&strategy_buf, opts->strategy_opts);
+	if (opts->ignore_whitespace)
+		strbuf_addstr(&strategy_buf, " --ignore-space-change");
+	if (strategy_buf.len)
+		parse_strategy_opts(&replay, strategy_buf.buf);
+
+	strbuf_release(&strategy_buf);
+
+	if (opts->squash_onto) {
+		oidcpy(&replay.squash_onto, opts->squash_onto);
+		replay.have_squash_onto = 1;
+	}
 
 	return replay;
 }
@@ -512,6 +531,8 @@
 	argc = parse_options(argc, argv, prefix, options,
 			builtin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0);
 
+	opts.strategy_opts = xstrdup_or_null(opts.strategy_opts);
+
 	if (!is_null_oid(&squash_onto))
 		opts.squash_onto = &squash_onto;
 
@@ -685,7 +706,7 @@
 		write_file(state_dir_path("gpg_sign_opt", opts), "%s",
 			   opts->gpg_sign_opt);
 	if (opts->signoff)
-		write_file(state_dir_path("strategy", opts), "--signoff");
+		write_file(state_dir_path("signoff", opts), "--signoff");
 
 	return 0;
 }
@@ -965,6 +986,12 @@
 	am.git_cmd = 1;
 	argv_array_push(&am.args, "am");
 
+	if (opts->ignore_whitespace)
+		argv_array_push(&am.args, "--ignore-whitespace");
+	if (opts->committer_date_is_author_date)
+		argv_array_push(&opts->git_am_opts, "--committer-date-is-author-date");
+	if (opts->ignore_date)
+		argv_array_push(&opts->git_am_opts, "--ignore-date");
 	if (opts->action && !strcmp("continue", opts->action)) {
 		argv_array_push(&am.args, "--resolved");
 		argv_array_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
@@ -1012,7 +1039,8 @@
 	argv_array_pushl(&format_patch.args, "format-patch", "-k", "--stdout",
 			 "--full-index", "--cherry-pick", "--right-only",
 			 "--src-prefix=a/", "--dst-prefix=b/", "--no-renames",
-			 "--no-cover-letter", "--pretty=mboxrd", "--topo-order", NULL);
+			 "--no-cover-letter", "--pretty=mboxrd", "--topo-order",
+			 "--no-base", NULL);
 	if (opts->git_format_patch_opt.len)
 		argv_array_split(&format_patch.args,
 				 opts->git_format_patch_opt.buf);
@@ -1431,16 +1459,17 @@
 			PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
 		OPT_BOOL(0, "signoff", &options.signoff,
 			 N_("add a Signed-off-by: line to each commit")),
-		OPT_PASSTHRU_ARGV(0, "ignore-whitespace", &options.git_am_opts,
-				  NULL, N_("passed to 'git am'"),
-				  PARSE_OPT_NOARG),
-		OPT_PASSTHRU_ARGV(0, "committer-date-is-author-date",
-				  &options.git_am_opts, NULL,
-				  N_("passed to 'git am'"), PARSE_OPT_NOARG),
-		OPT_PASSTHRU_ARGV(0, "ignore-date", &options.git_am_opts, NULL,
-				  N_("passed to 'git am'"), PARSE_OPT_NOARG),
+		OPT_BOOL(0, "committer-date-is-author-date",
+			 &options.committer_date_is_author_date,
+			 N_("make committer date match author date")),
+		OPT_BOOL(0, "reset-author-date", &options.ignore_date,
+			 N_("ignore author date and use current date")),
+		OPT_HIDDEN_BOOL(0, "ignore-date", &options.ignore_date,
+				N_("synonym of --reset-author-date")),
 		OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),
 				  N_("passed to 'git apply'"), 0),
+		OPT_BOOL(0, "ignore-whitespace", &options.ignore_whitespace,
+			 N_("ignore changes in whitespace")),
 		OPT_PASSTHRU_ARGV(0, "whitespace", &options.git_am_opts,
 				  N_("action"), N_("passed to 'git apply'"), 0),
 		OPT_BIT('f', "force-rebase", &options.flags,
@@ -1713,11 +1742,13 @@
 		    state_dir_base, cmd_live_rebase, buf.buf);
 	}
 
+	if (options.committer_date_is_author_date ||
+	    options.ignore_date)
+		options.flags |= REBASE_FORCE;
+
 	for (i = 0; i < options.git_am_opts.argc; i++) {
 		const char *option = options.git_am_opts.argv[i], *p;
-		if (!strcmp(option, "--committer-date-is-author-date") ||
-		    !strcmp(option, "--ignore-date") ||
-		    !strcmp(option, "--whitespace=fix") ||
+		if (!strcmp(option, "--whitespace=fix") ||
 		    !strcmp(option, "--whitespace=strip"))
 			options.flags |= REBASE_FORCE;
 		else if (skip_prefix(option, "-C", &p)) {
diff --git a/builtin/remote.c b/builtin/remote.c
index 5591cef..96bbe82 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -693,9 +693,8 @@
 	for (i = 0; i < remote_branches.nr; i++) {
 		struct string_list_item *item = remote_branches.items + i;
 		int flag = 0;
-		struct object_id oid;
 
-		read_ref_full(item->string, RESOLVE_REF_READING, &oid, &flag);
+		read_ref_full(item->string, RESOLVE_REF_READING, NULL, &flag);
 		if (!(flag & REF_ISSYMREF))
 			continue;
 		if (delete_ref(NULL, item->string, NULL, REF_NO_DEREF))
diff --git a/builtin/reset.c b/builtin/reset.c
index fdd5721..18228c3 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -30,8 +30,9 @@
 
 static const char * const git_reset_usage[] = {
 	N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
-	N_("git reset [-q] [<tree-ish>] [--] <paths>..."),
-	N_("git reset --patch [<tree-ish>] [--] [<paths>...]"),
+	N_("git reset [-q] [<tree-ish>] [--] <pathspec>..."),
+	N_("git reset [-q] [--pathspec-from-file [--pathspec-file-nul]] [<tree-ish>]"),
+	N_("git reset --patch [<tree-ish>] [--] [<pathspec>...]"),
 	NULL
 };
 
@@ -284,8 +285,8 @@
 int cmd_reset(int argc, const char **argv, const char *prefix)
 {
 	int reset_type = NONE, update_ref_status = 0, quiet = 0;
-	int patch_mode = 0, unborn;
-	const char *rev;
+	int patch_mode = 0, pathspec_file_nul = 0, unborn;
+	const char *rev, *pathspec_from_file = NULL;
 	struct object_id oid;
 	struct pathspec pathspec;
 	int intent_to_add = 0;
@@ -306,6 +307,8 @@
 		OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
 		OPT_BOOL('N', "intent-to-add", &intent_to_add,
 				N_("record only the fact that removed paths will be added later")),
+		OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
+		OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
 		OPT_END()
 	};
 
@@ -316,11 +319,25 @@
 						PARSE_OPT_KEEP_DASHDASH);
 	parse_args(&pathspec, argv, prefix, patch_mode, &rev);
 
+	if (pathspec_from_file) {
+		if (patch_mode)
+			die(_("--pathspec-from-file is incompatible with --patch"));
+
+		if (pathspec.nr)
+			die(_("--pathspec-from-file is incompatible with pathspec arguments"));
+
+		parse_pathspec_file(&pathspec, 0,
+				    PATHSPEC_PREFER_FULL,
+				    prefix, pathspec_from_file, pathspec_file_nul);
+	} else if (pathspec_file_nul) {
+		die(_("--pathspec-file-nul requires --pathspec-from-file"));
+	}
+
 	unborn = !strcmp(rev, "HEAD") && get_oid("HEAD", &oid);
 	if (unborn) {
 		/* reset on unborn branch: treat as reset to empty tree */
 		oidcpy(&oid, the_hash_algo->empty_tree);
-	} else if (!pathspec.nr) {
+	} else if (!pathspec.nr && !patch_mode) {
 		struct commit *commit;
 		if (get_oid_committish(rev, &oid))
 			die(_("Failed to resolve '%s' as a valid revision."), rev);
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 85ce209..7a00da8 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -803,6 +803,8 @@
 				const char *work_tree = get_git_work_tree();
 				if (work_tree)
 					puts(work_tree);
+				else
+					die("this operation must be run in a work tree");
 				continue;
 			}
 			if (!strcmp(arg, "--show-superproject-working-tree")) {
diff --git a/builtin/stash.c b/builtin/stash.c
index d913487..4ad3adf 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -483,13 +483,12 @@
 		if (ret)
 			return -1;
 
+		/* read back the result of update_index() back from the disk */
 		discard_cache();
+		read_cache();
 	}
 
-	if (quiet) {
-		if (refresh_and_write_cache(REFRESH_QUIET, 0, 0))
-			warning("could not refresh index");
-	} else {
+	if (!quiet) {
 		struct child_process cp = CHILD_PROCESS_INIT;
 
 		/*
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 2c2395a..c72931e 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -19,6 +19,8 @@
 #include "diffcore.h"
 #include "diff.h"
 #include "object-store.h"
+#include "dir.h"
+#include "advice.h"
 
 #define OPT_QUIET (1 << 0)
 #define OPT_CACHED (1 << 1)
@@ -802,7 +804,8 @@
 			 path, NULL);
 
 	git_config(git_diff_basic_config, NULL);
-	repo_init_revisions(the_repository, &rev, prefix);
+
+	repo_init_revisions(the_repository, &rev, NULL);
 	rev.abbrev = 0;
 	diff_files_args.argc = setup_revisions(diff_files_args.argc,
 					       diff_files_args.argv,
@@ -1268,6 +1271,13 @@
 #define SUBMODULE_ALTERNATE_SETUP_INIT { NULL, \
 	SUBMODULE_ALTERNATE_ERROR_IGNORE, NULL }
 
+static const char alternate_error_advice[] = N_(
+"An alternate computed from a superproject's alternate is invalid.\n"
+"To allow Git to clone without an alternate in such a case, set\n"
+"submodule.alternateErrorStrategy to 'info' or, equivalently, clone with\n"
+"'--reference-if-able' instead of '--reference'."
+);
+
 static int add_possible_reference_from_superproject(
 		struct object_directory *odb, void *sas_cb)
 {
@@ -1299,6 +1309,8 @@
 		} else {
 			switch (sas->error_mode) {
 			case SUBMODULE_ALTERNATE_ERROR_DIE:
+				if (advice_submodule_alternate_error_strategy_die)
+					advise(_(alternate_error_advice));
 				die(_("submodule '%s' cannot add alternate: %s"),
 				    sas->submodule_name, err.buf);
 			case SUBMODULE_ALTERNATE_ERROR_INFO:
@@ -1359,7 +1371,7 @@
 	char *p, *path = NULL, *sm_gitdir;
 	struct strbuf sb = STRBUF_INIT;
 	struct string_list reference = STRING_LIST_INIT_NODUP;
-	int dissociate = 0;
+	int dissociate = 0, require_init = 0;
 	char *sm_alternate = NULL, *error_strategy = NULL;
 
 	struct option module_clone_options[] = {
@@ -1386,6 +1398,8 @@
 		OPT__QUIET(&quiet, "Suppress output for cloning a submodule"),
 		OPT_BOOL(0, "progress", &progress,
 			   N_("force cloning progress")),
+		OPT_BOOL(0, "require-init", &require_init,
+			   N_("disallow cloning into non-empty directory")),
 		OPT_END()
 	};
 
@@ -1413,6 +1427,10 @@
 	} else
 		path = xstrdup(path);
 
+	if (validate_submodule_git_dir(sm_gitdir, name) < 0)
+		die(_("refusing to create/use '%s' in another submodule's "
+			"git dir"), sm_gitdir);
+
 	if (!file_exists(sm_gitdir)) {
 		if (safe_create_leading_directories_const(sm_gitdir) < 0)
 			die(_("could not create directory '%s'"), sm_gitdir);
@@ -1424,6 +1442,8 @@
 			die(_("clone of '%s' into submodule path '%s' failed"),
 			    url, path);
 	} else {
+		if (require_init && !access(path, X_OK) && !is_empty_dir(path))
+			die(_("directory not empty: '%s'"), path);
 		if (safe_create_leading_directories_const(path) < 0)
 			die(_("could not create directory '%s'"), path);
 		strbuf_addf(&sb, "%s/index", sm_gitdir);
@@ -1478,6 +1498,8 @@
 			die(_("Invalid update mode '%s' configured for submodule path '%s'"),
 				val, path);
 	} else if (sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
+		if (sub->update_strategy.type == SM_UPDATE_COMMAND)
+			BUG("how did we read update = !command from .gitmodules?");
 		out->type = sub->update_strategy.type;
 		out->command = sub->update_strategy.command;
 	} else
@@ -1536,6 +1558,7 @@
 	int recommend_shallow;
 	struct string_list references;
 	int dissociate;
+	unsigned require_init;
 	const char *depth;
 	const char *recursive_prefix;
 	const char *prefix;
@@ -1554,7 +1577,7 @@
 	int max_jobs;
 };
 #define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
-	SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, \
+	SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, 0, \
 	NULL, NULL, NULL, \
 	NULL, 0, 0, 0, NULL, 0, 0, 1}
 
@@ -1681,6 +1704,8 @@
 		argv_array_pushl(&child->args, "--prefix", suc->prefix, NULL);
 	if (suc->recommend_shallow && sub->recommend_shallow == 1)
 		argv_array_push(&child->args, "--depth=1");
+	if (suc->require_init)
+		argv_array_push(&child->args, "--require-init");
 	argv_array_pushl(&child->args, "--path", sub->path, NULL);
 	argv_array_pushl(&child->args, "--name", sub->name, NULL);
 	argv_array_pushl(&child->args, "--url", url, NULL);
@@ -1870,6 +1895,8 @@
 		OPT__QUIET(&suc.quiet, N_("don't print cloning progress")),
 		OPT_BOOL(0, "progress", &suc.progress,
 			    N_("force cloning progress")),
+		OPT_BOOL(0, "require-init", &suc.require_init,
+			   N_("disallow cloning into non-empty directory")),
 		OPT_END()
 	};
 
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index a87a4bf..9100964 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -24,6 +24,7 @@
 static off_t max_input_size;
 static git_hash_ctx ctx;
 static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
+static struct progress *progress;
 
 /*
  * When running under --strict mode, objects whose reachability are
@@ -92,6 +93,7 @@
 	consumed_bytes += bytes;
 	if (max_input_size && consumed_bytes > max_input_size)
 		die(_("pack exceeds maximum allowed size"));
+	display_throughput(progress, consumed_bytes);
 }
 
 static void *get_data(unsigned long size)
@@ -484,7 +486,6 @@
 static void unpack_all(void)
 {
 	int i;
-	struct progress *progress = NULL;
 	struct pack_header *hdr = fill(sizeof(struct pack_header));
 
 	nr_objects = ntohl(hdr->hdr_entries);
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 4de44f5..d6bc526 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -376,7 +376,7 @@
 	if (opts->checkout) {
 		cp.argv = NULL;
 		argv_array_clear(&cp.args);
-		argv_array_pushl(&cp.args, "reset", "--hard", NULL);
+		argv_array_pushl(&cp.args, "reset", "--hard", "--no-recurse-submodules", NULL);
 		if (opts->quiet)
 			argv_array_push(&cp.args, "--quiet");
 		cp.env = child_env.argv;
diff --git a/bundle.c b/bundle.c
index a85ed3f..99439e0 100644
--- a/bundle.c
+++ b/bundle.c
@@ -249,15 +249,16 @@
 
 
 /* Write the pack data to bundle_fd */
-static int write_pack_data(int bundle_fd, struct rev_info *revs)
+static int write_pack_data(int bundle_fd, struct rev_info *revs, struct argv_array *pack_options)
 {
 	struct child_process pack_objects = CHILD_PROCESS_INIT;
 	int i;
 
 	argv_array_pushl(&pack_objects.args,
-			 "pack-objects", "--all-progress-implied",
+			 "pack-objects",
 			 "--stdout", "--thin", "--delta-base-offset",
 			 NULL);
+	argv_array_pushv(&pack_objects.args, pack_options->argv);
 	pack_objects.in = -1;
 	pack_objects.out = bundle_fd;
 	pack_objects.git_cmd = 1;
@@ -428,7 +429,7 @@
 }
 
 int create_bundle(struct repository *r, const char *path,
-		  int argc, const char **argv)
+		  int argc, const char **argv, struct argv_array *pack_options)
 {
 	struct lock_file lock = LOCK_INIT;
 	int bundle_fd = -1;
@@ -470,7 +471,7 @@
 		goto err;
 
 	/* write pack */
-	if (write_pack_data(bundle_fd, &revs))
+	if (write_pack_data(bundle_fd, &revs, pack_options))
 		goto err;
 
 	if (!bundle_to_stdout) {
diff --git a/bundle.h b/bundle.h
index 37c37d7..ceab0c7 100644
--- a/bundle.h
+++ b/bundle.h
@@ -1,6 +1,7 @@
 #ifndef BUNDLE_H
 #define BUNDLE_H
 
+#include "argv-array.h"
 #include "cache.h"
 
 struct ref_list {
@@ -19,7 +20,7 @@
 int is_bundle(const char *path, int quiet);
 int read_bundle_header(const char *path, struct bundle_header *header);
 int create_bundle(struct repository *r, const char *path,
-		  int argc, const char **argv);
+		  int argc, const char **argv, struct argv_array *pack_options);
 int verify_bundle(struct repository *r, struct bundle_header *header, int verbose);
 #define BUNDLE_VERBOSE 1
 int unbundle(struct repository *r, struct bundle_header *header,
diff --git a/cache.h b/cache.h
index d3c89e7..1554488 100644
--- a/cache.h
+++ b/cache.h
@@ -634,10 +634,43 @@
 
 #define alloc_nr(x) (((x)+16)*3/2)
 
-/*
- * Realloc the buffer pointed at by variable 'x' so that it can hold
- * at least 'nr' entries; the number of entries currently allocated
- * is 'alloc', using the standard growing factor alloc_nr() macro.
+/**
+ * Dynamically growing an array using realloc() is error prone and boring.
+ *
+ * Define your array with:
+ *
+ * - a pointer (`item`) that points at the array, initialized to `NULL`
+ *   (although please name the variable based on its contents, not on its
+ *   type);
+ *
+ * - an integer variable (`alloc`) that keeps track of how big the current
+ *   allocation is, initialized to `0`;
+ *
+ * - another integer variable (`nr`) to keep track of how many elements the
+ *   array currently has, initialized to `0`.
+ *
+ * Then before adding `n`th element to the item, call `ALLOC_GROW(item, n,
+ * alloc)`.  This ensures that the array can hold at least `n` elements by
+ * calling `realloc(3)` and adjusting `alloc` variable.
+ *
+ * ------------
+ * sometype *item;
+ * size_t nr;
+ * size_t alloc
+ *
+ * for (i = 0; i < nr; i++)
+ * 	if (we like item[i] already)
+ * 		return;
+ *
+ * // we did not like any existing one, so add one
+ * ALLOC_GROW(item, nr + 1, alloc);
+ * item[nr++] = value you like;
+ * ------------
+ *
+ * You are responsible for updating the `nr` variable.
+ *
+ * If you need to specify the number of elements to allocate explicitly
+ * then use the macro `REALLOC_ARRAY(item, alloc)` instead of `ALLOC_GROW`.
  *
  * Consider using ALLOC_GROW_BY instead of ALLOC_GROW as it has some
  * added niceties.
@@ -1455,7 +1488,8 @@
 int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
 
 /*
- * Convert a binary hash to its hex equivalent. The `_r` variant is reentrant,
+ * Convert a binary hash in "unsigned char []" or an object name in
+ * "struct object_id *" to its hex equivalent. The `_r` variant is reentrant,
  * and writes the NUL-terminated output to the buffer `out`, which must be at
  * least `GIT_MAX_HEXSZ + 1` bytes, and returns a pointer to out for
  * convenience.
@@ -1463,13 +1497,12 @@
  * The non-`_r` variant returns a static buffer, but uses a ring of 4
  * buffers, making it safe to make multiple calls for a single statement, like:
  *
- *   printf("%s -> %s", sha1_to_hex(one), sha1_to_hex(two));
+ *   printf("%s -> %s", hash_to_hex(one), hash_to_hex(two));
+ *   printf("%s -> %s", oid_to_hex(one), oid_to_hex(two));
  */
 char *hash_to_hex_algop_r(char *buffer, const unsigned char *hash, const struct git_hash_algo *);
-char *sha1_to_hex_r(char *out, const unsigned char *sha1);
 char *oid_to_hex_r(char *out, const struct object_id *oid);
 char *hash_to_hex_algop(const unsigned char *hash, const struct git_hash_algo *);	/* static buffer result! */
-char *sha1_to_hex(const unsigned char *sha1);						/* same static buffer */
 char *hash_to_hex(const unsigned char *hash);						/* same static buffer */
 char *oid_to_hex(const struct object_id *oid);						/* same static buffer */
 
diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh
index 4e64a19..cd59855 100755
--- a/ci/install-dependencies.sh
+++ b/ci/install-dependencies.sh
@@ -42,14 +42,17 @@
 	brew link --force gettext
 	brew cask install perforce || {
 		# Update the definitions and try again
-		git -C "$(brew --repository)"/Library/Taps/homebrew/homebrew-cask pull &&
+		cask_repo="$(brew --repository)"/Library/Taps/homebrew/homebrew-cask &&
+		git -C "$cask_repo" pull --no-stat &&
 		brew cask install perforce
 	} ||
 	brew install caskroom/cask/perforce
 	case "$jobname" in
 	osx-gcc)
-		brew link gcc ||
-		brew link gcc@8
+		brew install gcc@9
+		# Just in case the image is updated to contain gcc@9
+		# pre-installed but not linked.
+		brew link gcc@9
 		;;
 	esac
 	;;
diff --git a/ci/lib.sh b/ci/lib.sh
index c8c2c38..a90d0dc 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -131,7 +131,6 @@
 		echo "$SYSTEM_TASKDEFINITIONSURI$SYSTEM_TEAMPROJECT/_build/results?buildId=$1"
 	}
 
-	BREW_INSTALL_PACKAGES=gcc@8
 	export GIT_PROVE_OPTS="--timer --jobs 10 --state=failed,slow,save"
 	export GIT_TEST_OPTS="--verbose-log -x --write-junit-xml"
 	MAKEFLAGS="$MAKEFLAGS --jobs=10"
@@ -156,7 +155,7 @@
 
 export DEVELOPER=1
 export DEFAULT_TEST_TARGET=prove
-export GIT_TEST_CLONE_2GB=YesPlease
+export GIT_TEST_CLONE_2GB=true
 
 case "$jobname" in
 linux-clang|linux-gcc)
@@ -182,7 +181,7 @@
 osx-clang|osx-gcc)
 	if [ "$jobname" = osx-gcc ]
 	then
-		export CC=gcc-8
+		export CC=gcc-9
 	fi
 
 	# t9810 occasionally fails on Travis CI OS X
diff --git a/command-list.txt b/command-list.txt
index d3d2825..2087894 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -204,6 +204,7 @@
 gitnamespaces                           guide
 gitrepository-layout                    guide
 gitrevisions                            guide
+gitsubmodules                           guide
 gittutorial-2                           guide
 gittutorial                             guide
 gitworkflows                            guide
diff --git a/commit-graph.c b/commit-graph.c
index 0aea7b2..e771394 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -464,7 +464,7 @@
 /*
  * Return 1 if commit_graph is non-NULL, and 0 otherwise.
  *
- * On the first invocation, this function attemps to load the commit
+ * On the first invocation, this function attempts to load the commit
  * graph if the_repository is configured to have one.
  */
 static int prepare_commit_graph(struct repository *r)
@@ -858,9 +858,6 @@
 			die(_("unable to parse commit %s"),
 				oid_to_hex(&(*list)->object.oid));
 		tree = get_commit_tree_oid(*list);
-		if (!tree)
-			die(_("unable to get tree for %s"),
-				oid_to_hex(&(*list)->object.oid));
 		hashwrite(f, tree->hash, hash_len);
 
 		parent = (*list)->parents;
@@ -1103,7 +1100,7 @@
 	struct commit_list *list = NULL;
 
 	if (ctx->report_progress)
-		ctx->progress = start_progress(
+		ctx->progress = start_delayed_progress(
 					_("Computing commit graph generation numbers"),
 					ctx->commits.nr);
 	for (i = 0; i < ctx->commits.nr; i++) {
diff --git a/commit.c b/commit.c
index 52036bc..434ec03 100644
--- a/commit.c
+++ b/commit.c
@@ -402,10 +402,22 @@
 	struct commit_graft *graft;
 	const int tree_entry_len = the_hash_algo->hexsz + 5;
 	const int parent_entry_len = the_hash_algo->hexsz + 7;
+	struct tree *tree;
 
 	if (item->object.parsed)
 		return 0;
-	item->object.parsed = 1;
+
+	if (item->parents) {
+		/*
+		 * Presumably this is leftover from an earlier failed parse;
+		 * clear it out in preparation for us re-parsing (we'll hit the
+		 * same error, but that's good, since it lets our caller know
+		 * the result cannot be trusted.
+		 */
+		free_commit_list(item->parents);
+		item->parents = NULL;
+	}
+
 	tail += size;
 	if (tail <= bufptr + tree_entry_len + 1 || memcmp(bufptr, "tree ", 5) ||
 			bufptr[tree_entry_len] != '\n')
@@ -413,7 +425,12 @@
 	if (get_oid_hex(bufptr + 5, &parent) < 0)
 		return error("bad tree pointer in commit %s",
 			     oid_to_hex(&item->object.oid));
-	set_commit_tree(item, lookup_tree(r, &parent));
+	tree = lookup_tree(r, &parent);
+	if (!tree)
+		return error("bad tree pointer %s in commit %s",
+			     oid_to_hex(&parent),
+			     oid_to_hex(&item->object.oid));
+	set_commit_tree(item, tree);
 	bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
 	pptr = &item->parents;
 
@@ -433,8 +450,11 @@
 		if (graft && (graft->nr_parent < 0 || grafts_replace_parents))
 			continue;
 		new_parent = lookup_commit(r, &parent);
-		if (new_parent)
-			pptr = &commit_list_insert(new_parent, pptr)->next;
+		if (!new_parent)
+			return error("bad parent %s in commit %s",
+				     oid_to_hex(&parent),
+				     oid_to_hex(&item->object.oid));
+		pptr = &commit_list_insert(new_parent, pptr)->next;
 	}
 	if (graft) {
 		int i;
@@ -443,7 +463,9 @@
 			new_parent = lookup_commit(r,
 						   &graft->parent[i]);
 			if (!new_parent)
-				continue;
+				return error("bad graft parent %s in commit %s",
+					     oid_to_hex(&graft->parent[i]),
+					     oid_to_hex(&item->object.oid));
 			pptr = &commit_list_insert(new_parent, pptr)->next;
 		}
 	}
@@ -452,6 +474,7 @@
 	if (check_graph)
 		load_commit_graph_info(r, item);
 
+	item->object.parsed = 1;
 	return 0;
 }
 
diff --git a/commit.h b/commit.h
index f5295ca..221cdaa 100644
--- a/commit.h
+++ b/commit.h
@@ -132,7 +132,7 @@
 #endif
 
 /*
- * Tell the commit subsytem that we are done with a particular commit buffer.
+ * Tell the commit subsystem that we are done with a particular commit buffer.
  * The commit and buffer should be the input and return value, respectively,
  * from an earlier call to get_commit_buffer.  The buffer may or may not be
  * freed by this call; callers should not access the memory afterwards.
diff --git a/compat/mingw.c b/compat/mingw.c
index fe60923..402c1ad 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -114,6 +114,7 @@
 	case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break;
 	case ERROR_SHARING_VIOLATION: error = EACCES; break;
 	case ERROR_STACK_OVERFLOW: error = ENOMEM; break;
+	case ERROR_SUCCESS: BUG("err_win_to_posix() called without an error!");
 	case ERROR_SWAPERROR: error = ENOENT; break;
 	case ERROR_TOO_MANY_MODULES: error = EMFILE; break;
 	case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break;
@@ -212,6 +213,7 @@
 	HIDE_DOTFILES_DOTGITONLY
 };
 
+static int core_restrict_inherited_handles = -1;
 static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 static char *unset_environment_variables;
 
@@ -231,6 +233,15 @@
 		return 0;
 	}
 
+	if (!strcmp(var, "core.restrictinheritedhandles")) {
+		if (value && !strcasecmp(value, "auto"))
+			core_restrict_inherited_handles = -1;
+		else
+			core_restrict_inherited_handles =
+				git_config_bool(var, value);
+		return 0;
+	}
+
 	return 0;
 }
 
@@ -392,6 +403,12 @@
 {
 	int ret;
 	wchar_t wpath[MAX_PATH];
+
+	if (!is_valid_win32_path(path, 0)) {
+		errno = EINVAL;
+		return -1;
+	}
+
 	if (xutftowcs_path(wpath, path) < 0)
 		return -1;
 	ret = _wmkdir(wpath);
@@ -465,7 +482,7 @@
 	typedef int (*open_fn_t)(wchar_t const *wfilename, int oflags, ...);
 	va_list args;
 	unsigned mode;
-	int fd;
+	int fd, create = (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL);
 	wchar_t wfilename[MAX_PATH];
 	open_fn_t open_fn;
 
@@ -473,16 +490,21 @@
 	mode = va_arg(args, int);
 	va_end(args);
 
-	if (filename && !strcmp(filename, "/dev/null"))
-		filename = "nul";
+	if (!is_valid_win32_path(filename, !create)) {
+		errno = create ? EINVAL : ENOENT;
+		return -1;
+	}
 
 	if ((oflags & O_APPEND) && !is_local_named_pipe_path(filename))
 		open_fn = mingw_open_append;
 	else
 		open_fn = _wopen;
 
-	if (xutftowcs_path(wfilename, filename) < 0)
+	if (filename && !strcmp(filename, "/dev/null"))
+		wcscpy(wfilename, L"nul");
+	else if (xutftowcs_path(wfilename, filename) < 0)
 		return -1;
+
 	fd = open_fn(wfilename, oflags, mode);
 
 	if (fd < 0 && (oflags & O_ACCMODE) != O_RDONLY && errno == EACCES) {
@@ -540,10 +562,17 @@
 	FILE *file;
 	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (filename && !strcmp(filename, "/dev/null"))
-		filename = "nul";
-	if (xutftowcs_path(wfilename, filename) < 0 ||
-		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		wcscpy(wfilename, L"nul");
+	else if (!is_valid_win32_path(filename, 1)) {
+		int create = otype && strchr(otype, 'w');
+		errno = create ? EINVAL : ENOENT;
 		return NULL;
+	} else if (xutftowcs_path(wfilename, filename) < 0)
+		return NULL;
+
+	if (xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+
 	if (hide && !access(filename, F_OK) && set_hidden_flag(wfilename, 0)) {
 		error("could not unhide %s", filename);
 		return NULL;
@@ -562,10 +591,17 @@
 	FILE *file;
 	wchar_t wfilename[MAX_PATH], wotype[4];
 	if (filename && !strcmp(filename, "/dev/null"))
-		filename = "nul";
-	if (xutftowcs_path(wfilename, filename) < 0 ||
-		xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		wcscpy(wfilename, L"nul");
+	else if (!is_valid_win32_path(filename, 1)) {
+		int create = otype && strchr(otype, 'w');
+		errno = create ? EINVAL : ENOENT;
 		return NULL;
+	} else if (xutftowcs_path(wfilename, filename) < 0)
+		return NULL;
+
+	if (xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+
 	if (hide && !access(filename, F_OK) && set_hidden_flag(wfilename, 0)) {
 		error("could not unhide %s", filename);
 		return NULL;
@@ -986,16 +1022,16 @@
 
 struct tm *gmtime_r(const time_t *timep, struct tm *result)
 {
-	/* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */
-	memcpy(result, gmtime(timep), sizeof(struct tm));
-	return result;
+	if (gmtime_s(result, timep) == 0)
+		return result;
+	return NULL;
 }
 
 struct tm *localtime_r(const time_t *timep, struct tm *result)
 {
-	/* localtime() in MSVCRT.DLL is thread-safe, but not reentrant */
-	memcpy(result, localtime(timep), sizeof(struct tm));
-	return result;
+	if (localtime_s(result, timep) == 0)
+		return result;
+	return NULL;
 }
 
 char *mingw_getcwd(char *pointer, int len)
@@ -1054,7 +1090,7 @@
 				p++;
 				len++;
 			}
-			if (*p == '"')
+			if (*p == '"' || !*p)
 				n += count*2 + 1;
 			continue;
 		}
@@ -1076,16 +1112,19 @@
 				count++;
 				*d++ = *arg++;
 			}
-			if (*arg == '"') {
+			if (*arg == '"' || !*arg) {
 				while (count-- > 0)
 					*d++ = '\\';
+				/* don't escape the surrounding end quote */
+				if (!*arg)
+					break;
 				*d++ = '\\';
 			}
 		}
 		*d++ = *arg++;
 	}
 	*d++ = '"';
-	*d++ = 0;
+	*d++ = '\0';
 	return q;
 }
 
@@ -1098,13 +1137,14 @@
 
 	for (p = arg; *p; p++) {
 		int ws = isspace(*p);
-		if (!ws && *p != '\\' && *p != '"' && *p != '{')
+		if (!ws && *p != '\\' && *p != '"' && *p != '{' && *p != '\'' &&
+		    *p != '?' && *p != '*' && *p != '~')
 			continue;
 		if (!buf.len)
 			strbuf_addch(&buf, '"');
 		if (p != p2)
 			strbuf_add(&buf, p2, p - p2);
-		if (!ws && *p != '{')
+		if (*p == '\\' || *p == '"')
 			strbuf_addch(&buf, '\\');
 		p2 = p;
 	}
@@ -1114,7 +1154,7 @@
 	else if (!buf.len)
 		return arg;
 	else
-		strbuf_add(&buf, p2, p - p2),
+		strbuf_add(&buf, p2, p - p2);
 
 	strbuf_addch(&buf, '"');
 	return strbuf_detach(&buf, 0);
@@ -1371,7 +1411,10 @@
 
 static int is_msys2_sh(const char *cmd)
 {
-	if (cmd && !strcmp(cmd, "sh")) {
+	if (!cmd)
+		return 0;
+
+	if (!strcmp(cmd, "sh")) {
 		static int ret = -1;
 		char *p;
 
@@ -1391,6 +1434,16 @@
 		}
 		return ret;
 	}
+
+	if (ends_with(cmd, "\\sh.exe")) {
+		static char *sh;
+
+		if (!sh)
+			sh = path_lookup("sh", 0);
+
+		return !fspathcmp(cmd, sh);
+	}
+
 	return 0;
 }
 
@@ -1398,15 +1451,34 @@
 			      const char *dir,
 			      int prepend_cmd, int fhin, int fhout, int fherr)
 {
-	STARTUPINFOW si;
+	static int restrict_handle_inheritance = -1;
+	STARTUPINFOEXW si;
 	PROCESS_INFORMATION pi;
+	LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL;
+	HANDLE stdhandles[3];
+	DWORD stdhandles_count = 0;
+	SIZE_T size;
 	struct strbuf args;
 	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
 	unsigned flags = CREATE_UNICODE_ENVIRONMENT;
 	BOOL ret;
 	HANDLE cons;
 	const char *(*quote_arg)(const char *arg) =
-		is_msys2_sh(*argv) ? quote_arg_msys2 : quote_arg_msvc;
+		is_msys2_sh(cmd ? cmd : *argv) ?
+		quote_arg_msys2 : quote_arg_msvc;
+
+	/* Make sure to override previous errors, if any */
+	errno = 0;
+
+	if (restrict_handle_inheritance < 0)
+		restrict_handle_inheritance = core_restrict_inherited_handles;
+	/*
+	 * The following code to restrict which handles are inherited seems
+	 * to work properly only on Windows 7 and later, so let's disable it
+	 * on Windows Vista and 2008.
+	 */
+	if (restrict_handle_inheritance < 0)
+		restrict_handle_inheritance = GetVersion() >> 16 >= 7601;
 
 	do_unset_environment_variables();
 
@@ -1435,11 +1507,23 @@
 		CloseHandle(cons);
 	}
 	memset(&si, 0, sizeof(si));
-	si.cb = sizeof(si);
-	si.dwFlags = STARTF_USESTDHANDLES;
-	si.hStdInput = winansi_get_osfhandle(fhin);
-	si.hStdOutput = winansi_get_osfhandle(fhout);
-	si.hStdError = winansi_get_osfhandle(fherr);
+	si.StartupInfo.cb = sizeof(si);
+	si.StartupInfo.hStdInput = winansi_get_osfhandle(fhin);
+	si.StartupInfo.hStdOutput = winansi_get_osfhandle(fhout);
+	si.StartupInfo.hStdError = winansi_get_osfhandle(fherr);
+
+	/* The list of handles cannot contain duplicates */
+	if (si.StartupInfo.hStdInput != INVALID_HANDLE_VALUE)
+		stdhandles[stdhandles_count++] = si.StartupInfo.hStdInput;
+	if (si.StartupInfo.hStdOutput != INVALID_HANDLE_VALUE &&
+	    si.StartupInfo.hStdOutput != si.StartupInfo.hStdInput)
+		stdhandles[stdhandles_count++] = si.StartupInfo.hStdOutput;
+	if (si.StartupInfo.hStdError != INVALID_HANDLE_VALUE &&
+	    si.StartupInfo.hStdError != si.StartupInfo.hStdInput &&
+	    si.StartupInfo.hStdError != si.StartupInfo.hStdOutput)
+		stdhandles[stdhandles_count++] = si.StartupInfo.hStdError;
+	if (stdhandles_count)
+		si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
 
 	if (*argv && !strcmp(cmd, *argv))
 		wcmd[0] = L'\0';
@@ -1472,16 +1556,98 @@
 	wenvblk = make_environment_block(deltaenv);
 
 	memset(&pi, 0, sizeof(pi));
-	ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL, TRUE,
-		flags, wenvblk, dir ? wdir : NULL, &si, &pi);
+	if (restrict_handle_inheritance && stdhandles_count &&
+	    (InitializeProcThreadAttributeList(NULL, 1, 0, &size) ||
+	     GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
+	    (attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST)
+			(HeapAlloc(GetProcessHeap(), 0, size))) &&
+	    InitializeProcThreadAttributeList(attr_list, 1, 0, &size) &&
+	    UpdateProcThreadAttribute(attr_list, 0,
+				      PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+				      stdhandles,
+				      stdhandles_count * sizeof(HANDLE),
+				      NULL, NULL)) {
+		si.lpAttributeList = attr_list;
+		flags |= EXTENDED_STARTUPINFO_PRESENT;
+	}
+
+	ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL,
+			     stdhandles_count ? TRUE : FALSE,
+			     flags, wenvblk, dir ? wdir : NULL,
+			     &si.StartupInfo, &pi);
+
+	/*
+	 * On Windows 2008 R2, it seems that specifying certain types of handles
+	 * (such as FILE_TYPE_CHAR or FILE_TYPE_PIPE) will always produce an
+	 * error. Rather than playing finicky and fragile games, let's just try
+	 * to detect this situation and simply try again without restricting any
+	 * handle inheritance. This is still better than failing to create
+	 * processes.
+	 */
+	if (!ret && restrict_handle_inheritance && stdhandles_count) {
+		DWORD err = GetLastError();
+		struct strbuf buf = STRBUF_INIT;
+
+		if (err != ERROR_NO_SYSTEM_RESOURCES &&
+		    /*
+		     * On Windows 7 and earlier, handles on pipes and character
+		     * devices are inherited automatically, and cannot be
+		     * specified in the thread handle list. Rather than trying
+		     * to catch each and every corner case (and running the
+		     * chance of *still* forgetting a few), let's just fall
+		     * back to creating the process without trying to limit the
+		     * handle inheritance.
+		     */
+		    !(err == ERROR_INVALID_PARAMETER &&
+		      GetVersion() >> 16 < 9200) &&
+		    !getenv("SUPPRESS_HANDLE_INHERITANCE_WARNING")) {
+			DWORD fl = 0;
+			int i;
+
+			setenv("SUPPRESS_HANDLE_INHERITANCE_WARNING", "1", 1);
+
+			for (i = 0; i < stdhandles_count; i++) {
+				HANDLE h = stdhandles[i];
+				strbuf_addf(&buf, "handle #%d: %p (type %lx, "
+					    "handle info (%d) %lx\n", i, h,
+					    GetFileType(h),
+					    GetHandleInformation(h, &fl),
+					    fl);
+			}
+			strbuf_addstr(&buf, "\nThis is a bug; please report it "
+				      "at\nhttps://github.com/git-for-windows/"
+				      "git/issues/new\n\n"
+				      "To suppress this warning, please set "
+				      "the environment variable\n\n"
+				      "\tSUPPRESS_HANDLE_INHERITANCE_WARNING=1"
+				      "\n");
+		}
+		restrict_handle_inheritance = 0;
+		flags &= ~EXTENDED_STARTUPINFO_PRESENT;
+		ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL,
+				     TRUE, flags, wenvblk, dir ? wdir : NULL,
+				     &si.StartupInfo, &pi);
+		if (!ret)
+			errno = err_win_to_posix(GetLastError());
+		if (ret && buf.len) {
+			warning("failed to restrict file handles (%ld)\n\n%s",
+				err, buf.buf);
+		}
+		strbuf_release(&buf);
+	} else if (!ret)
+		errno = err_win_to_posix(GetLastError());
+
+	if (si.lpAttributeList)
+		DeleteProcThreadAttributeList(si.lpAttributeList);
+	if (attr_list)
+		HeapFree(GetProcessHeap(), 0, attr_list);
 
 	free(wenvblk);
 	free(wargs);
 
-	if (!ret) {
-		errno = ENOENT;
+	if (!ret)
 		return -1;
-	}
+
 	CloseHandle(pi.hThread);
 
 	/*
@@ -1566,7 +1732,7 @@
 		while (argv[argc]) argc++;
 		ALLOC_ARRAY(argv2, argc + 1);
 		argv2[0] = (char *)cmd;	/* full path to the script file */
-		memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
+		COPY_ARRAY(&argv2[1], &argv[1], argc);
 		exec_id = trace2_exec(prog, argv2);
 		pid = mingw_spawnv(prog, argv2, 1);
 		if (pid >= 0) {
@@ -2367,6 +2533,128 @@
 	}
 }
 
+int is_valid_win32_path(const char *path, int allow_literal_nul)
+{
+	const char *p = path;
+	int preceding_space_or_period = 0, i = 0, periods = 0;
+
+	if (!protect_ntfs)
+		return 1;
+
+	skip_dos_drive_prefix((char **)&path);
+	goto segment_start;
+
+	for (;;) {
+		char c = *(path++);
+		switch (c) {
+		case '\0':
+		case '/': case '\\':
+			/* cannot end in ` ` or `.`, except for `.` and `..` */
+			if (preceding_space_or_period &&
+			    (i != periods || periods > 2))
+				return 0;
+			if (!c)
+				return 1;
+
+			i = periods = preceding_space_or_period = 0;
+
+segment_start:
+			switch (*path) {
+			case 'a': case 'A': /* AUX */
+				if (((c = path[++i]) != 'u' && c != 'U') ||
+				    ((c = path[++i]) != 'x' && c != 'X')) {
+not_a_reserved_name:
+					path += i;
+					continue;
+				}
+				break;
+			case 'c': case 'C': /* COM<N>, CON, CONIN$, CONOUT$ */
+				if ((c = path[++i]) != 'o' && c != 'O')
+					goto not_a_reserved_name;
+				c = path[++i];
+				if (c == 'm' || c == 'M') { /* COM<N> */
+					if (!isdigit(path[++i]))
+						goto not_a_reserved_name;
+				} else if (c == 'n' || c == 'N') { /* CON */
+					c = path[i + 1];
+					if ((c == 'i' || c == 'I') &&
+					    ((c = path[i + 2]) == 'n' ||
+					     c == 'N') &&
+					    path[i + 3] == '$')
+						i += 3; /* CONIN$ */
+					else if ((c == 'o' || c == 'O') &&
+						 ((c = path[i + 2]) == 'u' ||
+						  c == 'U') &&
+						 ((c = path[i + 3]) == 't' ||
+						  c == 'T') &&
+						 path[i + 4] == '$')
+						i += 4; /* CONOUT$ */
+				} else
+					goto not_a_reserved_name;
+				break;
+			case 'l': case 'L': /* LPT<N> */
+				if (((c = path[++i]) != 'p' && c != 'P') ||
+				    ((c = path[++i]) != 't' && c != 'T') ||
+				    !isdigit(path[++i]))
+					goto not_a_reserved_name;
+				break;
+			case 'n': case 'N': /* NUL */
+				if (((c = path[++i]) != 'u' && c != 'U') ||
+				    ((c = path[++i]) != 'l' && c != 'L') ||
+				    (allow_literal_nul &&
+				     !path[i + 1] && p == path))
+					goto not_a_reserved_name;
+				break;
+			case 'p': case 'P': /* PRN */
+				if (((c = path[++i]) != 'r' && c != 'R') ||
+				    ((c = path[++i]) != 'n' && c != 'N'))
+					goto not_a_reserved_name;
+				break;
+			default:
+				continue;
+			}
+
+			/*
+			 * So far, this looks like a reserved name. Let's see
+			 * whether it actually is one: trailing spaces, a file
+			 * extension, or an NTFS Alternate Data Stream do not
+			 * matter, the name is still reserved if any of those
+			 * follow immediately after the actual name.
+			 */
+			i++;
+			if (path[i] == ' ') {
+				preceding_space_or_period = 1;
+				while (path[++i] == ' ')
+					; /* skip all spaces */
+			}
+
+			c = path[i];
+			if (c && c != '.' && c != ':' && c != '/' && c != '\\')
+				goto not_a_reserved_name;
+
+			/* contains reserved name */
+			return 0;
+		case '.':
+			periods++;
+			/* fallthru */
+		case ' ':
+			preceding_space_or_period = 1;
+			i++;
+			continue;
+		case ':': /* DOS drive prefix was already skipped */
+		case '<': case '>': case '"': case '|': case '?': case '*':
+			/* illegal character */
+			return 0;
+		default:
+			if (c > '\0' && c < '\x20')
+				/* illegal character */
+				return 0;
+		}
+		preceding_space_or_period = 0;
+		i++;
+	}
+}
+
 #if !defined(_MSC_VER)
 /*
  * Disable MSVCRT command line wildcard expansion (__getmainargs called from
diff --git a/compat/mingw.h b/compat/mingw.h
index 9ad204c..714bc1d 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -453,6 +453,27 @@
 #endif
 
 /**
+ * Verifies that the given path is a valid one on Windows.
+ *
+ * In particular, path segments are disallowed which
+ *
+ * - end in a period or a space (except the special directories `.` and `..`).
+ *
+ * - contain any of the reserved characters, e.g. `:`, `;`, `*`, etc
+ *
+ * - correspond to reserved names (such as `AUX`, `PRN`, etc)
+ *
+ * The `allow_literal_nul` parameter controls whether the path `NUL` should
+ * be considered valid (this makes sense e.g. before opening files, as it is
+ * perfectly legitimate to open `NUL` on Windows, just as it is to open
+ * `/dev/null` on Unix/Linux).
+ *
+ * Returns 1 upon success, otherwise 0.
+ */
+int is_valid_win32_path(const char *path, int allow_literal_nul);
+#define is_valid_path(path) is_valid_win32_path(path, 0)
+
+/**
  * Converts UTF-8 encoded string to UTF-16LE.
  *
  * To support repositories with legacy-encoded file names, invalid UTF-8 bytes
@@ -558,7 +579,7 @@
 
 /*
  * A critical section used in the implementation of the spawn
- * functions (mingw_spawnv[p]e()) and waitpid(). Intialised in
+ * functions (mingw_spawnv[p]e()) and waitpid(). Initialised in
  * the replacement main() macro below.
  */
 extern CRITICAL_SECTION pinfo_cs;
diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h
index 9134349..814845d 100644
--- a/compat/nedmalloc/malloc.c.h
+++ b/compat/nedmalloc/malloc.c.h
@@ -1564,7 +1564,7 @@
   return (ptr != 0)? ptr: MFAIL;
 }
 
-/* This function supports releasing coalesed segments */
+/* This function supports releasing coalesced segments */
 static FORCEINLINE int win32munmap(void* ptr, size_t size) {
   MEMORY_BASIC_INFORMATION minfo;
   char* cptr = (char*)ptr;
@@ -1655,7 +1655,7 @@
     #define CALL_MREMAP(addr, osz, nsz, mv)     MFAIL
 #endif /* HAVE_MMAP && HAVE_MREMAP */
 
-/* mstate bit set if continguous morecore disabled or failed */
+/* mstate bit set if contiguous morecore disabled or failed */
 #define USE_NONCONTIGUOUS_BIT (4U)
 
 /* segment bit set in create_mspace_with_base */
@@ -2485,7 +2485,7 @@
 
   Trim support
     Fields holding the amount of unused topmost memory that should trigger
-    timming, and a counter to force periodic scanning to release unused
+    timing, and a counter to force periodic scanning to release unused
     non-topmost segments.
 
   Locking
diff --git a/compat/obstack.h b/compat/obstack.h
index ae36ed6..01e7c81 100644
--- a/compat/obstack.h
+++ b/compat/obstack.h
@@ -79,7 +79,7 @@
 When the chars burst over a chunk boundary, we allocate a larger
 chunk, and then copy the partly formed object from the end of the old
 chunk to the beginning of the new larger chunk.  We then carry on
-accreting characters to the end of the object as we normally would.
+accrediting characters to the end of the object as we normally would.
 
 A special macro is provided to add a single char at a time to a
 growing object.  This allows the use of register variables, which
diff --git a/compat/regex/regcomp.c b/compat/regex/regcomp.c
index c0d8388..d1bc09e 100644
--- a/compat/regex/regcomp.c
+++ b/compat/regex/regcomp.c
@@ -3462,7 +3462,7 @@
 	/* This isn't a valid character.  */
 	return REG_ECOLLATE;
 
-      /* Build single byte matcing table for this equivalence class.  */
+      /* Build single byte matching table for this equivalence class.  */
       char_buf[1] = (unsigned char) '\0';
       len = weights[idx1 & 0xffffff];
       for (ch = 0; ch < SBC_MAX; ++ch)
diff --git a/compat/regex/regex.h b/compat/regex/regex.h
index 4d81358..08a2609 100644
--- a/compat/regex/regex.h
+++ b/compat/regex/regex.h
@@ -322,7 +322,7 @@
   /* POSIX regcomp return error codes.  (In the order listed in the
      standard.)  */
   REG_BADPAT,		/* Invalid pattern.  */
-  REG_ECOLLATE,		/* Inalid collating element.  */
+  REG_ECOLLATE,		/* Invalid collating element.  */
   REG_ECTYPE,		/* Invalid character class name.  */
   REG_EESCAPE,		/* Trailing backslash.  */
   REG_ESUBREG,		/* Invalid back reference.  */
diff --git a/compat/regex/regex_internal.c b/compat/regex/regex_internal.c
index 59bf151..ec51cf3 100644
--- a/compat/regex/regex_internal.c
+++ b/compat/regex/regex_internal.c
@@ -1616,7 +1616,7 @@
   re_free (state);
 }
 
-/* Create the new state which is independ of contexts.
+/* Create the new state which is independent of contexts.
    Return the new state if succeeded, otherwise return NULL.  */
 
 static re_dfastate_t *
diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c
index 1b5d89f..49358ae 100644
--- a/compat/regex/regexec.c
+++ b/compat/regex/regexec.c
@@ -2420,7 +2420,7 @@
 /* From the node set CUR_NODES, pick up the nodes whose types are
    OP_OPEN_SUBEXP and which have corresponding back references in the regular
    expression. And register them to use them later for evaluating the
-   correspoding back references.  */
+   corresponding back references.  */
 
 static reg_errcode_t
 internal_function
@@ -3347,7 +3347,7 @@
   dests_node = dests_alloc->dests_node;
   dests_ch = dests_alloc->dests_ch;
 
-  /* Initialize transiton table.  */
+  /* Initialize transition table.  */
   state->word_trtable = state->trtable = NULL;
 
   /* At first, group all nodes belonging to `state' into several
diff --git a/compat/vcbuild/find_vs_env.bat b/compat/vcbuild/find_vs_env.bat
index 40194dd..b35d264 100644
--- a/compat/vcbuild/find_vs_env.bat
+++ b/compat/vcbuild/find_vs_env.bat
@@ -18,7 +18,7 @@
 REM attempts to do that.
 REM ================================================================
 REM This BAT file starts in a plain (non-developer) command prompt,
-REM searches for the "best" commmand prompt setup script, installs
+REM searches for the "best" command prompt setup script, installs
 REM it into the current CMD process, and exports the various MSVC
 REM environment variables for use by MAKE.
 REM
diff --git a/compat/win32/path-utils.c b/compat/win32/path-utils.c
index d9d3641..ebf2f12 100644
--- a/compat/win32/path-utils.c
+++ b/compat/win32/path-utils.c
@@ -1,5 +1,29 @@
 #include "../../git-compat-util.h"
 
+int win32_has_dos_drive_prefix(const char *path)
+{
+	int i;
+
+	/*
+	 * Does it start with an ASCII letter (i.e. highest bit not set),
+	 * followed by a colon?
+	 */
+	if (!(0x80 & (unsigned char)*path))
+		return *path && path[1] == ':' ? 2 : 0;
+
+	/*
+	 * While drive letters must be letters of the English alphabet, it is
+	 * possible to assign virtually _any_ Unicode character via `subst` as
+	 * a drive letter to "virtual drives". Even `1`, or `ä`. Or fun stuff
+	 * like this:
+	 *
+	 *      subst ֍: %USERPROFILE%\Desktop
+	 */
+	for (i = 1; i < 4 && (0x80 & (unsigned char)path[i]); i++)
+		; /* skip first UTF-8 character */
+	return path[i] == ':' ? i + 1 : 0;
+}
+
 int win32_skip_dos_drive_prefix(char **path)
 {
 	int ret = has_dos_drive_prefix(*path);
diff --git a/compat/win32/path-utils.h b/compat/win32/path-utils.h
index 8ed062a..f2e7087 100644
--- a/compat/win32/path-utils.h
+++ b/compat/win32/path-utils.h
@@ -1,8 +1,9 @@
 #ifndef WIN32_PATH_UTILS_H
 #define WIN32_PATH_UTILS_H
 
-#define has_dos_drive_prefix(path) \
-	(isalpha(*(path)) && (path)[1] == ':' ? 2 : 0)
+int win32_has_dos_drive_prefix(const char *path);
+#define has_dos_drive_prefix win32_has_dos_drive_prefix
+
 int win32_skip_dos_drive_prefix(char **path);
 #define skip_dos_drive_prefix win32_skip_dos_drive_prefix
 static inline int win32_is_dir_sep(int c)
diff --git a/compat/winansi.c b/compat/winansi.c
index 54fd701..c27b20a 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -662,10 +662,20 @@
  */
 HANDLE winansi_get_osfhandle(int fd)
 {
+	HANDLE ret;
+
 	if (fd == 1 && (fd_is_interactive[1] & FD_SWAPPED))
 		return hconsole1;
 	if (fd == 2 && (fd_is_interactive[2] & FD_SWAPPED))
 		return hconsole2;
 
-	return (HANDLE)_get_osfhandle(fd);
+	ret = (HANDLE)_get_osfhandle(fd);
+
+	/*
+	 * There are obviously circumstances under which _get_osfhandle()
+	 * returns (HANDLE)-2. This is not documented anywhere, but that is so
+	 * clearly an invalid handle value that we can just work around this
+	 * and return the correct value for invalid handles.
+	 */
+	return ret == (HANDLE)-2 ? INVALID_HANDLE_VALUE : ret;
 }
diff --git a/config.h b/config.h
index f0ed464..91fd4c5 100644
--- a/config.h
+++ b/config.h
@@ -4,6 +4,22 @@
 #include "hashmap.h"
 #include "string-list.h"
 
+
+/**
+ * The config API gives callers a way to access Git configuration files
+ * (and files which have the same syntax).
+ *
+ * General Usage
+ * -------------
+ *
+ * Config files are parsed linearly, and each variable found is passed to a
+ * caller-provided callback function. The callback function is responsible
+ * for any actions to be taken on the config option, and is free to ignore
+ * some options. It is not uncommon for the configuration to be parsed
+ * several times during the run of a Git program, with different callbacks
+ * picking out different variables useful to themselves.
+ */
+
 struct object_id;
 
 /* git_config_parse_key() returns these negated: */
@@ -71,9 +87,34 @@
 	} error_action;
 };
 
+/**
+ * A config callback function takes three parameters:
+ *
+ * - the name of the parsed variable. This is in canonical "flat" form: the
+ *   section, subsection, and variable segments will be separated by dots,
+ *   and the section and variable segments will be all lowercase. E.g.,
+ *   `core.ignorecase`, `diff.SomeType.textconv`.
+ *
+ * - the value of the found variable, as a string. If the variable had no
+ *   value specified, the value will be NULL (typically this means it
+ *   should be interpreted as boolean true).
+ *
+ * - a void pointer passed in by the caller of the config API; this can
+ *   contain callback-specific data
+ *
+ * A config callback should return 0 for success, or -1 if the variable
+ * could not be parsed properly.
+ */
 typedef int (*config_fn_t)(const char *, const char *, void *);
+
 int git_default_config(const char *, const char *, void *);
+
+/**
+ * Read a specific file in git-config format.
+ * This function takes the same callback and data parameters as `git_config`.
+ */
 int git_config_from_file(config_fn_t fn, const char *, void *);
+
 int git_config_from_file_with_options(config_fn_t fn, const char *,
 				      void *,
 				      const struct config_options *);
@@ -88,34 +129,157 @@
 int git_config_from_parameters(config_fn_t fn, void *data);
 void read_early_config(config_fn_t cb, void *data);
 void read_very_early_config(config_fn_t cb, void *data);
+
+/**
+ * Most programs will simply want to look up variables in all config files
+ * that Git knows about, using the normal precedence rules. To do this,
+ * call `git_config` with a callback function and void data pointer.
+ *
+ * `git_config` will read all config sources in order of increasing
+ * priority. Thus a callback should typically overwrite previously-seen
+ * entries with new ones (e.g., if both the user-wide `~/.gitconfig` and
+ * repo-specific `.git/config` contain `color.ui`, the config machinery
+ * will first feed the user-wide one to the callback, and then the
+ * repo-specific one; by overwriting, the higher-priority repo-specific
+ * value is left at the end).
+ */
 void git_config(config_fn_t fn, void *);
+
+/**
+ * Lets the caller examine config while adjusting some of the default
+ * behavior of `git_config`. It should almost never be used by "regular"
+ * Git code that is looking up configuration variables.
+ * It is intended for advanced callers like `git-config`, which are
+ * intentionally tweaking the normal config-lookup process.
+ * It takes two extra parameters:
+ *
+ * - `config_source`
+ * If this parameter is non-NULL, it specifies the source to parse for
+ * configuration, rather than looking in the usual files. See `struct
+ * git_config_source` in `config.h` for details. Regular `git_config` defaults
+ * to `NULL`.
+ *
+ * - `opts`
+ * Specify options to adjust the behavior of parsing config files. See `struct
+ * config_options` in `config.h` for details. As an example: regular `git_config`
+ * sets `opts.respect_includes` to `1` by default.
+ */
 int config_with_options(config_fn_t fn, void *,
 			struct git_config_source *config_source,
 			const struct config_options *opts);
+
+/**
+ * Value Parsing Helpers
+ * ---------------------
+ *
+ * The following helper functions aid in parsing string values
+ */
+
 int git_parse_ssize_t(const char *, ssize_t *);
 int git_parse_ulong(const char *, unsigned long *);
+
+/**
+ * Same as `git_config_bool`, except that it returns -1 on error rather
+ * than dying.
+ */
 int git_parse_maybe_bool(const char *);
+
+/**
+ * Parse the string to an integer, including unit factors. Dies on error;
+ * otherwise, returns the parsed result.
+ */
 int git_config_int(const char *, const char *);
+
 int64_t git_config_int64(const char *, const char *);
+
+/**
+ * Identical to `git_config_int`, but for unsigned longs.
+ */
 unsigned long git_config_ulong(const char *, const char *);
+
 ssize_t git_config_ssize_t(const char *, const char *);
+
+/**
+ * Same as `git_config_bool`, except that integers are returned as-is, and
+ * an `is_bool` flag is unset.
+ */
 int git_config_bool_or_int(const char *, const char *, int *);
+
+/**
+ * Parse a string into a boolean value, respecting keywords like "true" and
+ * "false". Integer values are converted into true/false values (when they
+ * are non-zero or zero, respectively). Other values cause a die(). If
+ * parsing is successful, the return value is the result.
+ */
 int git_config_bool(const char *, const char *);
+
+/**
+ * Allocates and copies the value string into the `dest` parameter; if no
+ * string is given, prints an error message and returns -1.
+ */
 int git_config_string(const char **, const char *, const char *);
+
+/**
+ * Similar to `git_config_string`, but expands `~` or `~user` into the
+ * user's home directory when found at the beginning of the path.
+ */
 int git_config_pathname(const char **, const char *, const char *);
+
 int git_config_expiry_date(timestamp_t *, const char *, const char *);
 int git_config_color(char *, const char *, const char *);
 int git_config_set_in_file_gently(const char *, const char *, const char *);
+
+/**
+ * write config values to a specific config file, takes a key/value pair as
+ * parameter.
+ */
 void git_config_set_in_file(const char *, const char *, const char *);
+
 int git_config_set_gently(const char *, const char *);
+
+/**
+ * write config values to `.git/config`, takes a key/value pair as parameter.
+ */
 void git_config_set(const char *, const char *);
+
 int git_config_parse_key(const char *, char **, int *);
 int git_config_key_is_valid(const char *key);
 int git_config_set_multivar_gently(const char *, const char *, const char *, int);
 void git_config_set_multivar(const char *, const char *, const char *, int);
 int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int);
+
+/**
+ * takes four parameters:
+ *
+ * - the name of the file, as a string, to which key/value pairs will be written.
+ *
+ * - the name of key, as a string. This is in canonical "flat" form: the section,
+ *   subsection, and variable segments will be separated by dots, and the section
+ *   and variable segments will be all lowercase.
+ *   E.g., `core.ignorecase`, `diff.SomeType.textconv`.
+ *
+ * - the value of the variable, as a string. If value is equal to NULL, it will
+ *   remove the matching key from the config file.
+ *
+ * - the value regex, as a string. It will disregard key/value pairs where value
+ *   does not match.
+ *
+ * - a multi_replace value, as an int. If value is equal to zero, nothing or only
+ *   one matching key/value is replaced, else all matching key/values (regardless
+ *   how many) are removed, before the new pair is written.
+ *
+ * It returns 0 on success.
+ */
 void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
+
+/**
+ * rename or remove sections in the config file
+ * parameters `old_name` and `new_name`
+ * If NULL is passed through `new_name` parameter,
+ * the section will be removed from the config file.
+ */
 int git_config_rename_section(const char *, const char *);
+
 int git_config_rename_section_in_file(const char *, const char *, const char *);
 int git_config_copy_section(const char *, const char *);
 int git_config_copy_section_in_file(const char *, const char *, const char *);
@@ -142,6 +306,30 @@
 const char *current_config_origin_type(void);
 const char *current_config_name(void);
 
+/**
+ * Include Directives
+ * ------------------
+ *
+ * By default, the config parser does not respect include directives.
+ * However, a caller can use the special `git_config_include` wrapper
+ * callback to support them. To do so, you simply wrap your "real" callback
+ * function and data pointer in a `struct config_include_data`, and pass
+ * the wrapper to the regular config-reading functions. For example:
+ *
+ * -------------------------------------------
+ * int read_file_with_include(const char *file, config_fn_t fn, void *data)
+ * {
+ * struct config_include_data inc = CONFIG_INCLUDE_INIT;
+ * inc.fn = fn;
+ * inc.data = data;
+ * return git_config_from_file(git_config_include, file, &inc);
+ * }
+ * -------------------------------------------
+ *
+ * `git_config` respects includes automatically. The lower-level
+ * `git_config_from_file` does not.
+ *
+ */
 struct config_include_data {
 	int depth;
 	config_fn_t fn;
@@ -169,6 +357,33 @@
 		     const char **subsection, int *subsection_len,
 		     const char **key);
 
+/**
+ * Custom Configsets
+ * -----------------
+ *
+ * A `config_set` can be used to construct an in-memory cache for
+ * config-like files that the caller specifies (i.e., files like `.gitmodules`,
+ * `~/.gitconfig` etc.). For example,
+ *
+ * ----------------------------------------
+ * struct config_set gm_config;
+ * git_configset_init(&gm_config);
+ * int b;
+ * //we add config files to the config_set
+ * git_configset_add_file(&gm_config, ".gitmodules");
+ * git_configset_add_file(&gm_config, ".gitmodules_alt");
+ *
+ * if (!git_configset_get_bool(gm_config, "submodule.frotz.ignore", &b)) {
+ * //hack hack hack
+ * }
+ *
+ * when we are done with the configset:
+ * git_configset_clear(&gm_config);
+ * ----------------------------------------
+ *
+ * Configset API provides functions for the above mentioned work flow
+ */
+
 struct config_set_element {
 	struct hashmap_entry ent;
 	char *key;
@@ -197,16 +412,47 @@
 	struct configset_list list;
 };
 
+/**
+ * Initializes the config_set `cs`.
+ */
 void git_configset_init(struct config_set *cs);
+
+/**
+ * Parses the file and adds the variable-value pairs to the `config_set`,
+ * dies if there is an error in parsing the file. Returns 0 on success, or
+ * -1 if the file does not exist or is inaccessible. The user has to decide
+ * if he wants to free the incomplete configset or continue using it when
+ * the function returns -1.
+ */
 int git_configset_add_file(struct config_set *cs, const char *filename);
+
+/**
+ * Finds and returns the value list, sorted in order of increasing priority
+ * for the configuration variable `key` and config set `cs`. When the
+ * configuration variable `key` is not found, returns NULL. The caller
+ * should not free or modify the returned pointer, as it is owned by the cache.
+ */
 const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);
+
+/**
+ * Clears `config_set` structure, removes all saved variable-value pairs.
+ */
 void git_configset_clear(struct config_set *cs);
 
 /*
  * These functions return 1 if not found, and 0 if found, leaving the found
  * value in the 'dest' pointer.
  */
+
+/*
+ * Finds the highest-priority value for the configuration variable `key`
+ * and config set `cs`, stores the pointer to it in `value` and returns 0.
+ * When the configuration variable `key` is not found, returns 1 without
+ * touching `value`. The caller should not free or modify `value`, as it
+ * is owned by the cache.
+ */
 int git_configset_get_value(struct config_set *cs, const char *key, const char **dest);
+
 int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest);
 int git_configset_get_string(struct config_set *cs, const char *key, char **dest);
 int git_configset_get_int(struct config_set *cs, const char *key, int *dest);
@@ -240,17 +486,94 @@
 int repo_config_get_pathname(struct repository *repo,
 			     const char *key, const char **dest);
 
+/**
+ * Querying For Specific Variables
+ * -------------------------------
+ *
+ * For programs wanting to query for specific variables in a non-callback
+ * manner, the config API provides two functions `git_config_get_value`
+ * and `git_config_get_value_multi`. They both read values from an internal
+ * cache generated previously from reading the config files.
+ */
+
+/**
+ * Finds the highest-priority value for the configuration variable `key`,
+ * stores the pointer to it in `value` and returns 0. When the
+ * configuration variable `key` is not found, returns 1 without touching
+ * `value`. The caller should not free or modify `value`, as it is owned
+ * by the cache.
+ */
 int git_config_get_value(const char *key, const char **value);
+
+/**
+ * Finds and returns the value list, sorted in order of increasing priority
+ * for the configuration variable `key`. When the configuration variable
+ * `key` is not found, returns NULL. The caller should not free or modify
+ * the returned pointer, as it is owned by the cache.
+ */
 const struct string_list *git_config_get_value_multi(const char *key);
+
+/**
+ * Resets and invalidates the config cache.
+ */
 void git_config_clear(void);
+
+/**
+ * Allocates and copies the retrieved string into the `dest` parameter for
+ * the configuration variable `key`; if NULL string is given, prints an
+ * error message and returns -1. When the configuration variable `key` is
+ * not found, returns 1 without touching `dest`.
+ */
 int git_config_get_string_const(const char *key, const char **dest);
+
+/**
+ * Similar to `git_config_get_string_const`, except that retrieved value
+ * copied into the `dest` parameter is a mutable string.
+ */
 int git_config_get_string(const char *key, char **dest);
+
+/**
+ * Finds and parses the value to an integer for the configuration variable
+ * `key`. Dies on error; otherwise, stores the value of the parsed integer in
+ * `dest` and returns 0. When the configuration variable `key` is not found,
+ * returns 1 without touching `dest`.
+ */
 int git_config_get_int(const char *key, int *dest);
+
+/**
+ * Similar to `git_config_get_int` but for unsigned longs.
+ */
 int git_config_get_ulong(const char *key, unsigned long *dest);
+
+/**
+ * Finds and parses the value into a boolean value, for the configuration
+ * variable `key` respecting keywords like "true" and "false". Integer
+ * values are converted into true/false values (when they are non-zero or
+ * zero, respectively). Other values cause a die(). If parsing is successful,
+ * stores the value of the parsed result in `dest` and returns 0. When the
+ * configuration variable `key` is not found, returns 1 without touching
+ * `dest`.
+ */
 int git_config_get_bool(const char *key, int *dest);
+
+/**
+ * Similar to `git_config_get_bool`, except that integers are copied as-is,
+ * and `is_bool` flag is unset.
+ */
 int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);
+
+/**
+ * Similar to `git_config_get_bool`, except that it returns -1 on error
+ * rather than dying.
+ */
 int git_config_get_maybe_bool(const char *key, int *dest);
+
+/**
+ * Similar to `git_config_get_string`, but expands `~` or `~user` into
+ * the user's home directory when found at the beginning of the path.
+ */
 int git_config_get_pathname(const char *key, const char **dest);
+
 int git_config_get_index_threads(int *dest);
 int git_config_get_untracked_cache(void);
 int git_config_get_split_index(void);
@@ -270,7 +593,19 @@
 	enum config_scope scope;
 };
 
+/**
+ * First prints the error message specified by the caller in `err` and then
+ * dies printing the line number and the file name of the highest priority
+ * value for the configuration variable `key`.
+ */
 NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
+
+/**
+ * Helper function which formats the die error message according to the
+ * parameters entered. Used by `git_die_config()`. It can be used by callers
+ * handling `git_config_get_value_multi()` to print the correct error message
+ * for the desired value.
+ */
 NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);
 
 #define LOOKUP_CONFIG(mapping, var) \
diff --git a/config.mak.uname b/config.mak.uname
index cc8efd9..0ab8e00 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -454,7 +454,6 @@
 	# Optionally enable memory leak reporting.
 	BASIC_CFLAGS += -DUSE_MSVC_CRTDBG
 endif
-	BASIC_CFLAGS += -DPROTECT_NTFS_DEFAULT=1
 	# Always give "-Zi" to the compiler and "-debug" to linker (even in
 	# release mode) to force a PDB to be generated (like RelWithDebInfo).
 	BASIC_CFLAGS += -Zi
@@ -616,7 +615,7 @@
 		compat/win32/path-utils.o \
 		compat/win32/pthread.o compat/win32/syslog.o \
 		compat/win32/dirent.o
-	BASIC_CFLAGS += -DWIN32 -DPROTECT_NTFS_DEFAULT=1
+	BASIC_CFLAGS += -DWIN32
 	EXTLIBS += -lws2_32
 	GITLIBS += git.res
 	PTHREAD_LIBS =
diff --git a/configure.ac b/configure.ac
index a43b476..66aedb9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -85,7 +85,7 @@
 
 # GIT_PARSE_WITH_SET_MAKE_VAR(WITHNAME, VAR, HELP_TEXT)
 # -----------------------------------------------------
-# Set VAR to the value specied by --with-WITHNAME.
+# Set VAR to the value specified by --with-WITHNAME.
 # No verification of arguments is performed, but warnings are issued
 # if either 'yes' or 'no' is specified.
 # HELP_TEXT is presented when --help is called.
@@ -844,12 +844,61 @@
 AC_COMPILE_IFELSE([OLDICONVTEST_SRC],
 	[AC_MSG_RESULT([no])],
 	[AC_MSG_RESULT([yes])
+	AC_DEFINE(HAVE_OLD_ICONV, 1)
 	OLD_ICONV=UnfortunatelyYes])
 
 GIT_UNSTASH_FLAGS($ICONVDIR)
 
 GIT_CONF_SUBST([OLD_ICONV])
 
+#
+# Define ICONV_OMITS_BOM if you are on a system which
+# iconv omits bom for utf-{16,32}
+if test -z "$NO_ICONV"; then
+AC_CACHE_CHECK([whether iconv omits bom for utf-16 and utf-32],
+ [ac_cv_iconv_omits_bom],
+[
+old_LIBS="$LIBS"
+if test -n "$NEEDS_LIBICONV"; then
+	LIBS="$LIBS -liconv"
+fi
+
+AC_RUN_IFELSE(
+	[AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
+	#include <iconv.h>
+	#ifdef HAVE_OLD_ICONV
+	typedef const char *iconv_ibp;
+	#else
+	typedef char *iconv_ibp;
+	#endif
+	],
+	[[
+	int v;
+	iconv_t conv;
+	char in[] = "a"; iconv_ibp pin = in;
+	char out[20] = ""; char *pout = out;
+	size_t isz = sizeof in;
+	size_t osz = sizeof out;
+
+	conv = iconv_open("UTF-16", "UTF-8");
+	iconv(conv, &pin, &isz, &pout, &osz);
+	iconv_close(conv);
+	v = (unsigned char)(out[0]) + (unsigned char)(out[1]);
+	return v != 0xfe + 0xff;
+	]])],
+	[ac_cv_iconv_omits_bom=no],
+	[ac_cv_iconv_omits_bom=yes])
+
+LIBS="$old_LIBS"
+])
+if test "x$ac_cv_iconv_omits_bom" = xyes; then
+	ICONV_OMITS_BOM=Yes
+else
+	ICONV_OMITS_BOM=
+fi
+GIT_CONF_SUBST([ICONV_OMITS_BOM])
+fi
+
 ## Checks for typedefs, structures, and compiler characteristics.
 AC_MSG_NOTICE([CHECKS for typedefs, structures, and compiler characteristics])
 #
diff --git a/connect.c b/connect.c
index da7daa2..b6451ab 100644
--- a/connect.c
+++ b/connect.c
@@ -511,7 +511,7 @@
 	const char *colon = strchr(url, ':');
 	const char *slash = strchr(url, '/');
 	return !colon || (slash && slash < colon) ||
-		has_dos_drive_prefix(url);
+		(has_dos_drive_prefix(url) && is_valid_path(url));
 }
 
 static const char *prot_name(enum protocol protocol)
diff --git a/connected.c b/connected.c
index 36c4e5d..c337f5f 100644
--- a/connected.c
+++ b/connected.c
@@ -62,7 +62,8 @@
 		 * received the objects pointed to by each wanted ref.
 		 */
 		do {
-			if (!repo_has_object_file(the_repository, &oid))
+			if (!repo_has_object_file_with_flags(the_repository, &oid,
+							     OBJECT_INFO_SKIP_FETCH_OBJECT))
 				return 1;
 		} while (!fn(cb_data, &oid));
 		return 0;
diff --git a/contrib/coccinelle/commit.cocci b/contrib/coccinelle/commit.cocci
index d034533..778e470 100644
--- a/contrib/coccinelle/commit.cocci
+++ b/contrib/coccinelle/commit.cocci
@@ -20,7 +20,7 @@
 + set_commit_tree(c, s)
   ...>}
 
-// These excluded functions must access c->maybe_tree direcly.
+// These excluded functions must access c->maybe_tree directly.
 // Note that if c->maybe_tree is written somewhere outside of these
 // functions, then the recommended transformation will be bogus with
 // repo_get_commit_tree() on the LHS.
diff --git a/contrib/coccinelle/object_id.cocci b/contrib/coccinelle/object_id.cocci
index 3e536a9..ddf4f22 100644
--- a/contrib/coccinelle/object_id.cocci
+++ b/contrib/coccinelle/object_id.cocci
@@ -13,38 +13,6 @@
 @@
 struct object_id OID;
 @@
-- sha1_to_hex(OID.hash)
-+ oid_to_hex(&OID)
-
-@@
-identifier f != oid_to_hex;
-struct object_id *OIDPTR;
-@@
-  f(...) {<...
-- sha1_to_hex(OIDPTR->hash)
-+ oid_to_hex(OIDPTR)
-  ...>}
-
-@@
-expression E;
-struct object_id OID;
-@@
-- sha1_to_hex_r(E, OID.hash)
-+ oid_to_hex_r(E, &OID)
-
-@@
-identifier f != oid_to_hex_r;
-expression E;
-struct object_id *OIDPTR;
-@@
-   f(...) {<...
-- sha1_to_hex_r(E, OIDPTR->hash)
-+ oid_to_hex_r(E, OIDPTR)
-  ...>}
-
-@@
-struct object_id OID;
-@@
 - hashclr(OID.hash)
 + oidclr(&OID)
 
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 00fbe6c..e4d9ff4 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -550,7 +550,7 @@
 						 esc_idx, 1)
 			} else if (esc == "n") {
 				# Uh-oh, a newline character.
-				# We cant reliably put a pathname
+				# We cannot reliably put a pathname
 				# containing a newline into COMPREPLY,
 				# and the newline would create a mess.
 				# Skip this path.
@@ -565,7 +565,7 @@
 			}
 		}
 		# Drop closing double quote, if there is one.
-		# (There isnt any if this is a directory, as it was
+		# (There is not any if this is a directory, as it was
 		# already stripped with the trailing path components.)
 		if (substr(p, length(p), 1) == "\"")
 			out = out substr(p, 1, length(p) - 1)
@@ -1749,7 +1749,7 @@
 	--all-match --invert-grep
 "
 
-__git_log_pretty_formats="oneline short medium full fuller email raw format: mboxrd"
+__git_log_pretty_formats="oneline short medium full fuller reference email raw format: tformat: mboxrd"
 __git_log_date_formats="relative iso8601 iso8601-strict rfc2822 short local default raw unix format:"
 
 _git_log ()
@@ -2043,6 +2043,10 @@
 		__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
 		return
 		;;
+	--onto=*)
+		__git_complete_refs --cur="${cur##--onto=}"
+		return
+		;;
 	--*)
 		__gitcomp_builtin rebase "" \
 			"$__git_rebase_interactive_inprogress_options"
@@ -2779,7 +2783,7 @@
 {
 	__git_has_doubledash && return
 
-	local subcommands="add status init deinit update set-branch summary foreach sync absorbgitdirs"
+	local subcommands="add status init deinit update set-branch set-url summary foreach sync absorbgitdirs"
 	local subcommand="$(__git_find_on_cmdline "$subcommands")"
 	if [ -z "$subcommand" ]; then
 		case "$cur" in
@@ -2843,6 +2847,7 @@
 			--log-window-size= --no-checkout --quiet
 			--repack-flags --use-log-author --localtime
 			--add-author-from
+			--recursive
 			--ignore-paths= --include-paths= $remote_opts
 			"
 		local init_opts="
diff --git a/contrib/hooks/multimail/git_multimail.py b/contrib/hooks/multimail/git_multimail.py
index 8823399..f563be8 100755
--- a/contrib/hooks/multimail/git_multimail.py
+++ b/contrib/hooks/multimail/git_multimail.py
@@ -95,7 +95,7 @@
     unicode = str
 
     def write_str(f, msg):
-        # Try outputing with the default encoding. If it fails,
+        # Try outputting with the default encoding. If it fails,
         # try UTF-8.
         try:
             f.buffer.write(msg.encode(sys.getdefaultencoding()))
@@ -2129,7 +2129,7 @@
                 # equivalent to
                 #     self.smtp.ehlo()
                 #     self.smtp.starttls()
-                # with acces to the ssl layer
+                # with access to the ssl layer
                 self.smtp.ehlo()
                 if not self.smtp.has_extn("starttls"):
                     raise smtplib.SMTPException("STARTTLS extension not supported by server")
@@ -2148,7 +2148,7 @@
                         cert_reqs=ssl.CERT_NONE
                         )
                     self.environment.get_logger().error(
-                        '*** Warning, the server certificat is not verified (smtp) ***\n'
+                        '*** Warning, the server certificate is not verified (smtp) ***\n'
                         '***          set the option smtpCACerts                   ***\n'
                         )
                 if not hasattr(self.smtp.sock, "read"):
@@ -3189,7 +3189,7 @@
         self.COMPUTED_KEYS += ['projectdesc']
 
     def get_projectdesc(self):
-        """Return a one-line descripition of the project."""
+        """Return a one-line description of the project."""
 
         git_dir = get_git_dir()
         try:
diff --git a/contrib/hooks/multimail/post-receive.example b/contrib/hooks/multimail/post-receive.example
index b9bb118..0f98c5a 100755
--- a/contrib/hooks/multimail/post-receive.example
+++ b/contrib/hooks/multimail/post-receive.example
@@ -56,7 +56,7 @@
 
 # Set some Git configuration variables. Equivalent to passing var=val
 # to "git -c var=val" each time git is called, or to adding the
-# configuration in .git/config (must come before instanciating the
+# configuration in .git/config (must come before instantiating the
 # environment) :
 #git_multimail.Config.add_config_parameters('multimailhook.commitEmailFormat=html')
 #git_multimail.Config.add_config_parameters(('user.name=foo', 'user.email=foo@example.com'))
diff --git a/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email
index 8747b84..ff565eb 100755
--- a/contrib/hooks/post-receive-email
+++ b/contrib/hooks/post-receive-email
@@ -329,7 +329,7 @@
 	#
 	#  git rev-parse --not --all | grep -v $(git rev-parse $refname)
 	#
-	# Get's us to something pretty safe (apart from the small time
+	# Gets us to something pretty safe (apart from the small time
 	# between refname being read, and git rev-parse running - for that,
 	# I give up)
 	#
diff --git a/contrib/hooks/update-paranoid b/contrib/hooks/update-paranoid
index d18b317..0092d67 100755
--- a/contrib/hooks/update-paranoid
+++ b/contrib/hooks/update-paranoid
@@ -49,7 +49,7 @@
 Repository sections are matched on the basename of the repository
 (after removing the .git suffix).
 
-The opcode abbrevations are:
+The opcode abbreviations are:
 
   C: create new ref
   D: delete existing ref
diff --git a/contrib/mw-to-git/.perlcriticrc b/contrib/mw-to-git/.perlcriticrc
index 158958d..b733326 100644
--- a/contrib/mw-to-git/.perlcriticrc
+++ b/contrib/mw-to-git/.perlcriticrc
@@ -14,7 +14,7 @@
 
 # This rule states that each system call should have its return value checked
 # The problem is that it includes the print call. Checking every print call's
-# return value would be harmful to the code readabilty.
+# return value would be harmful to the code readability.
 # This configuration keeps all default function but print.
 [InputOutput::RequireCheckedSyscalls]
 functions = open say close
diff --git a/contrib/mw-to-git/git-remote-mediawiki.perl b/contrib/mw-to-git/git-remote-mediawiki.perl
index af9cbc9..d8ff2e6 100755
--- a/contrib/mw-to-git/git-remote-mediawiki.perl
+++ b/contrib/mw-to-git/git-remote-mediawiki.perl
@@ -79,7 +79,7 @@
 $export_media = !($export_media eq 'false');
 
 my $wiki_login = run_git("config --get remote.${remotename}.mwLogin");
-# Note: mwPassword is discourraged. Use the credential system instead.
+# Note: mwPassword is discouraged. Use the credential system instead.
 my $wiki_passwd = run_git("config --get remote.${remotename}.mwPassword");
 my $wiki_domain = run_git("config --get remote.${remotename}.mwDomain");
 chomp($wiki_login);
diff --git a/contrib/mw-to-git/t/install-wiki/db_install.php b/contrib/mw-to-git/t/install-wiki/db_install.php
index 0f3f4e0..b033849 100644
--- a/contrib/mw-to-git/t/install-wiki/db_install.php
+++ b/contrib/mw-to-git/t/install-wiki/db_install.php
@@ -24,7 +24,7 @@
 $db_dir = urlencode($tmp);
 $tmp_cookie = tempnam($tmp, "COOKIE_");
 /*
- * Fetchs a page with cURL.
+ * Fetches a page with cURL.
  */
 function get($page_name = "") {
 	$curl = curl_init();
diff --git a/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh b/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh
index cfbfe7d..9106833 100755
--- a/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh
+++ b/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh
@@ -143,7 +143,7 @@
 test_expect_success 'Git clone works with multiple specific page cloned ' '
 	wiki_reset &&
 	wiki_editpage foo "I will be there" false &&
-	wiki_editpage bar "I will not disapear" false &&
+	wiki_editpage bar "I will not disappear" false &&
 	wiki_editpage namnam "I be erased" false &&
 	wiki_editpage nyancat "nyan nyan nyan you will not erase me" false &&
 	wiki_delete_page namnam &&
diff --git a/contrib/mw-to-git/t/test-gitmw-lib.sh b/contrib/mw-to-git/t/test-gitmw-lib.sh
index 6546294..3948a00 100755
--- a/contrib/mw-to-git/t/test-gitmw-lib.sh
+++ b/contrib/mw-to-git/t/test-gitmw-lib.sh
@@ -279,7 +279,7 @@
 	"$LIGHTTPD_DIR"/lighttpd -f "$WEB"/lighttpd.conf
 
 	if test $? -ne 0 ; then
-		echo "Could not execute http deamon lighttpd"
+		echo "Could not execute http daemon lighttpd"
 		exit 1
 	fi
 }
diff --git a/contrib/svn-fe/svnrdump_sim.py b/contrib/svn-fe/svnrdump_sim.py
index 50c6a4f..8a3cee6 100755
--- a/contrib/svn-fe/svnrdump_sim.py
+++ b/contrib/svn-fe/svnrdump_sim.py
@@ -54,7 +54,7 @@
         print("usage: %s dump URL -rLOWER:UPPER")
         sys.exit(1)
     if not sys.argv[1] == 'dump':
-        raise NotImplementedError('only "dump" is suppported.')
+        raise NotImplementedError('only "dump" is supported.')
     url = sys.argv[2]
     r = ('0', 'HEAD')
     if len(sys.argv) == 4 and sys.argv[3][0:2] == '-r':
diff --git a/convert.c b/convert.c
index 25ac525..797e0bd 100644
--- a/convert.c
+++ b/convert.c
@@ -270,8 +270,12 @@
 static int validate_encoding(const char *path, const char *enc,
 		      const char *data, size_t len, int die_on_error)
 {
+	const char *stripped;
+
 	/* We only check for UTF here as UTF?? can be an alias for UTF-?? */
-	if (istarts_with(enc, "UTF")) {
+	if (skip_iprefix(enc, "UTF", &stripped)) {
+		skip_prefix(stripped, "-", &stripped);
+
 		/*
 		 * Check for detectable errors in UTF encodings
 		 */
@@ -285,15 +289,10 @@
 			 */
 			const char *advise_msg = _(
 				"The file '%s' contains a byte order "
-				"mark (BOM). Please use UTF-%s as "
+				"mark (BOM). Please use UTF-%.*s as "
 				"working-tree-encoding.");
-			const char *stripped = NULL;
-			char *upper = xstrdup_toupper(enc);
-			upper[strlen(upper)-2] = '\0';
-			if (skip_prefix(upper, "UTF", &stripped))
-				skip_prefix(stripped, "-", &stripped);
-			advise(advise_msg, path, stripped);
-			free(upper);
+			int stripped_len = strlen(stripped) - strlen("BE");
+			advise(advise_msg, path, stripped_len, stripped);
 			if (die_on_error)
 				die(error_msg, path, enc);
 			else {
@@ -308,12 +307,7 @@
 				"mark (BOM). Please use UTF-%sBE or UTF-%sLE "
 				"(depending on the byte order) as "
 				"working-tree-encoding.");
-			const char *stripped = NULL;
-			char *upper = xstrdup_toupper(enc);
-			if (skip_prefix(upper, "UTF", &stripped))
-				skip_prefix(stripped, "-", &stripped);
 			advise(advise_msg, path, stripped, stripped);
-			free(upper);
 			if (die_on_error)
 				die(error_msg, path, enc);
 			else {
@@ -418,7 +412,7 @@
 	if (!dst) {
 		/*
 		 * We could add the blob "as-is" to Git. However, on checkout
-		 * we would try to reencode to the original encoding. This
+		 * we would try to re-encode to the original encoding. This
 		 * would fail and we would leave the user with a messed-up
 		 * working tree. Let's try to avoid this by screaming loud.
 		 */
diff --git a/credential.h b/credential.h
index 6b0cd16..5772d50 100644
--- a/credential.h
+++ b/credential.h
@@ -3,8 +3,208 @@
 
 #include "string-list.h"
 
+/**
+ * The credentials API provides an abstracted way of gathering username and
+ * password credentials from the user.
+ *
+ * Typical setup
+ * -------------
+ *
+ * ------------
+ * +-----------------------+
+ * | Git code (C)          |--- to server requiring --->
+ * |                       |        authentication
+ * |.......................|
+ * | C credential API      |--- prompt ---> User
+ * +-----------------------+
+ * 	^      |
+ * 	| pipe |
+ * 	|      v
+ * +-----------------------+
+ * | Git credential helper |
+ * +-----------------------+
+ * ------------
+ *
+ * The Git code (typically a remote-helper) will call the C API to obtain
+ * credential data like a login/password pair (credential_fill). The
+ * API will itself call a remote helper (e.g. "git credential-cache" or
+ * "git credential-store") that may retrieve credential data from a
+ * store. If the credential helper cannot find the information, the C API
+ * will prompt the user. Then, the caller of the API takes care of
+ * contacting the server, and does the actual authentication.
+ *
+ * C API
+ * -----
+ *
+ * The credential C API is meant to be called by Git code which needs to
+ * acquire or store a credential. It is centered around an object
+ * representing a single credential and provides three basic operations:
+ * fill (acquire credentials by calling helpers and/or prompting the user),
+ * approve (mark a credential as successfully used so that it can be stored
+ * for later use), and reject (mark a credential as unsuccessful so that it
+ * can be erased from any persistent storage).
+ *
+ * Example
+ * ~~~~~~~
+ *
+ * The example below shows how the functions of the credential API could be
+ * used to login to a fictitious "foo" service on a remote host:
+ *
+ * -----------------------------------------------------------------------
+ * int foo_login(struct foo_connection *f)
+ * {
+ * 	int status;
+ * 	// Create a credential with some context; we don't yet know the
+ * 	// username or password.
+ *
+ * struct credential c = CREDENTIAL_INIT;
+ * c.protocol = xstrdup("foo");
+ * c.host = xstrdup(f->hostname);
+ *
+ * // Fill in the username and password fields by contacting
+ * // helpers and/or asking the user. The function will die if it
+ * // fails.
+ * credential_fill(&c);
+ *
+ * // Otherwise, we have a username and password. Try to use it.
+ *
+ * status = send_foo_login(f, c.username, c.password);
+ * switch (status) {
+ * case FOO_OK:
+ * // It worked. Store the credential for later use.
+ * credential_accept(&c);
+ * break;
+ * case FOO_BAD_LOGIN:
+ * // Erase the credential from storage so we don't try it again.
+ * credential_reject(&c);
+ * break;
+ * default:
+ * // Some other error occurred. We don't know if the
+ * // credential is good or bad, so report nothing to the
+ * // credential subsystem.
+ * }
+ *
+ * // Free any associated resources.
+ * credential_clear(&c);
+ *
+ * return status;
+ * }
+ * -----------------------------------------------------------------------
+ *
+ * Credential Helpers
+ * ------------------
+ *
+ * Credential helpers are programs executed by Git to fetch or save
+ * credentials from and to long-term storage (where "long-term" is simply
+ * longer than a single Git process; e.g., credentials may be stored
+ * in-memory for a few minutes, or indefinitely on disk).
+ *
+ * Each helper is specified by a single string in the configuration
+ * variable `credential.helper` (and others, see Documentation/git-config.txt).
+ * The string is transformed by Git into a command to be executed using
+ * these rules:
+ *
+ *   1. If the helper string begins with "!", it is considered a shell
+ *      snippet, and everything after the "!" becomes the command.
+ *
+ *   2. Otherwise, if the helper string begins with an absolute path, the
+ *      verbatim helper string becomes the command.
+ *
+ *   3. Otherwise, the string "git credential-" is prepended to the helper
+ *      string, and the result becomes the command.
+ *
+ * The resulting command then has an "operation" argument appended to it
+ * (see below for details), and the result is executed by the shell.
+ *
+ * Here are some example specifications:
+ *
+ * ----------------------------------------------------
+ * # run "git credential-foo"
+ * foo
+ *
+ * # same as above, but pass an argument to the helper
+ * foo --bar=baz
+ *
+ * # the arguments are parsed by the shell, so use shell
+ * # quoting if necessary
+ * foo --bar="whitespace arg"
+ *
+ * # you can also use an absolute path, which will not use the git wrapper
+ * /path/to/my/helper --with-arguments
+ *
+ * # or you can specify your own shell snippet
+ * !f() { echo "password=`cat $HOME/.secret`"; }; f
+ * ----------------------------------------------------
+ *
+ * Generally speaking, rule (3) above is the simplest for users to specify.
+ * Authors of credential helpers should make an effort to assist their
+ * users by naming their program "git-credential-$NAME", and putting it in
+ * the $PATH or $GIT_EXEC_PATH during installation, which will allow a user
+ * to enable it with `git config credential.helper $NAME`.
+ *
+ * When a helper is executed, it will have one "operation" argument
+ * appended to its command line, which is one of:
+ *
+ * `get`::
+ *
+ * 	Return a matching credential, if any exists.
+ *
+ * `store`::
+ *
+ * 	Store the credential, if applicable to the helper.
+ *
+ * `erase`::
+ *
+ * 	Remove a matching credential, if any, from the helper's storage.
+ *
+ * The details of the credential will be provided on the helper's stdin
+ * stream. The exact format is the same as the input/output format of the
+ * `git credential` plumbing command (see the section `INPUT/OUTPUT
+ * FORMAT` in Documentation/git-credential.txt for a detailed specification).
+ *
+ * For a `get` operation, the helper should produce a list of attributes
+ * on stdout in the same format. A helper is free to produce a subset, or
+ * even no values at all if it has nothing useful to provide. Any provided
+ * attributes will overwrite those already known about by Git.  If a helper
+ * outputs a `quit` attribute with a value of `true` or `1`, no further
+ * helpers will be consulted, nor will the user be prompted (if no
+ * credential has been provided, the operation will then fail).
+ *
+ * For a `store` or `erase` operation, the helper's output is ignored.
+ * If it fails to perform the requested operation, it may complain to
+ * stderr to inform the user. If it does not support the requested
+ * operation (e.g., a read-only store), it should silently ignore the
+ * request.
+ *
+ * If a helper receives any other operation, it should silently ignore the
+ * request. This leaves room for future operations to be added (older
+ * helpers will just ignore the new requests).
+ *
+ */
+
+
+/**
+ * This struct represents a single username/password combination
+ * along with any associated context. All string fields should be
+ * heap-allocated (or NULL if they are not known or not applicable).
+ * The meaning of the individual context fields is the same as
+ * their counterparts in the helper protocol.
+ *
+ * This struct should always be initialized with `CREDENTIAL_INIT` or
+ * `credential_init`.
+ */
 struct credential {
+
+	/**
+	 * A `string_list` of helpers. Each string specifies an external
+	 * helper which will be run, in order, to either acquire or store
+	 * credentials. This list is filled-in by the API functions
+	 * according to the corresponding configuration variables before
+	 * consulting helpers, so there usually is no need for a caller to
+	 * modify the helpers field at all.
+	 */
 	struct string_list helpers;
+
 	unsigned approved:1,
 		 configured:1,
 		 quit:1,
@@ -19,16 +219,52 @@
 
 #define CREDENTIAL_INIT { STRING_LIST_INIT_DUP }
 
+/* Initialize a credential structure, setting all fields to empty. */
 void credential_init(struct credential *);
+
+/**
+ * Free any resources associated with the credential structure, returning
+ * it to a pristine initialized state.
+ */
 void credential_clear(struct credential *);
 
+/**
+ * Instruct the credential subsystem to fill the username and
+ * password fields of the passed credential struct by first
+ * consulting helpers, then asking the user. After this function
+ * returns, the username and password fields of the credential are
+ * guaranteed to be non-NULL. If an error occurs, the function will
+ * die().
+ */
 void credential_fill(struct credential *);
+
+/**
+ * Inform the credential subsystem that the provided credentials
+ * were successfully used for authentication.  This will cause the
+ * credential subsystem to notify any helpers of the approval, so
+ * that they may store the result to be used again.  Any errors
+ * from helpers are ignored.
+ */
 void credential_approve(struct credential *);
+
+/**
+ * Inform the credential subsystem that the provided credentials
+ * have been rejected. This will cause the credential subsystem to
+ * notify any helpers of the rejection (which allows them, for
+ * example, to purge the invalid credentials from storage). It
+ * will also free() the username and password fields of the
+ * credential and set them to NULL (readying the credential for
+ * another call to `credential_fill`). Any errors from helpers are
+ * ignored.
+ */
 void credential_reject(struct credential *);
 
 int credential_read(struct credential *, FILE *);
 void credential_write(const struct credential *, FILE *);
+
+/* Parse a URL into broken-down credential fields. */
 void credential_from_url(struct credential *, const char *url);
+
 int credential_match(const struct credential *have,
 		     const struct credential *want);
 
diff --git a/daemon.c b/daemon.c
index 9d2e0d2..fd669ed 100644
--- a/daemon.c
+++ b/daemon.c
@@ -598,7 +598,7 @@
  * Read the host as supplied by the client connection.
  *
  * Returns a pointer to the character after the NUL byte terminating the host
- * arguemnt, or 'extra_args' if there is no host arguemnt.
+ * argument, or 'extra_args' if there is no host argument.
  */
 static char *parse_host_arg(struct hostinfo *hi, char *extra_args, int buflen)
 {
@@ -652,7 +652,7 @@
 		 * service that will be run.
 		 *
 		 * If there ends up being a particular arg in the future that
-		 * git-daemon needs to parse specificly (like the 'host' arg)
+		 * git-daemon needs to parse specifically (like the 'host' arg)
 		 * then it can be parsed here and not added to 'git_protocol'.
 		 */
 		if (*arg) {
diff --git a/date.c b/date.c
index 041db7d..b0d9a84 100644
--- a/date.c
+++ b/date.c
@@ -64,16 +64,16 @@
  * thing, which means that tz -0100 is passed in as the integer -100,
  * even though it means "sixty minutes off"
  */
-static struct tm *time_to_tm(timestamp_t time, int tz)
+static struct tm *time_to_tm(timestamp_t time, int tz, struct tm *tm)
 {
 	time_t t = gm_time_t(time, tz);
-	return gmtime(&t);
+	return gmtime_r(&t, tm);
 }
 
-static struct tm *time_to_tm_local(timestamp_t time)
+static struct tm *time_to_tm_local(timestamp_t time, struct tm *tm)
 {
 	time_t t = time;
-	return localtime(&t);
+	return localtime_r(&t, tm);
 }
 
 /*
@@ -283,6 +283,7 @@
 const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
 {
 	struct tm *tm;
+	struct tm tmbuf = { 0 };
 	struct tm human_tm = { 0 };
 	int human_tz = -1;
 	static struct strbuf timebuf = STRBUF_INIT;
@@ -318,11 +319,11 @@
 	}
 
 	if (mode->local)
-		tm = time_to_tm_local(time);
+		tm = time_to_tm_local(time, &tmbuf);
 	else
-		tm = time_to_tm(time, tz);
+		tm = time_to_tm(time, tz, &tmbuf);
 	if (!tm) {
-		tm = time_to_tm(0, 0);
+		tm = time_to_tm(0, 0, &tmbuf);
 		tz = 0;
 	}
 
@@ -959,10 +960,11 @@
 {
 	time_t now;
 	int offset;
+	struct tm tm = { 0 };
 
 	time(&now);
 
-	offset = tm_to_time_t(localtime(&now)) - now;
+	offset = tm_to_time_t(localtime_r(&now, &tm)) - now;
 	offset /= 60;
 
 	date_string(now, offset, out);
diff --git a/diff.c b/diff.c
index afe4400..8e2914c 100644
--- a/diff.c
+++ b/diff.c
@@ -2495,22 +2495,6 @@
 	}
 }
 
-struct diffstat_t {
-	int nr;
-	int alloc;
-	struct diffstat_file {
-		char *from_name;
-		char *name;
-		char *print_name;
-		const char *comments;
-		unsigned is_unmerged:1;
-		unsigned is_binary:1;
-		unsigned is_renamed:1;
-		unsigned is_interesting:1;
-		uintmax_t added, deleted;
-	} **files;
-};
-
 static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat,
 					  const char *name_a,
 					  const char *name_b)
@@ -2551,7 +2535,7 @@
 	/*
 	 * make sure that at least one '-' or '+' is printed if
 	 * there is any change to this path. The easiest way is to
-	 * scale linearly as if the alloted width is one column shorter
+	 * scale linearly as if the allotted width is one column shorter
 	 * than it is, and then add 1 to the result.
 	 */
 	return 1 + (it * (width - 1) / max_change);
@@ -3157,7 +3141,7 @@
 	gather_dirstat(options, &dir, changed, "", 0);
 }
 
-static void free_diffstat_info(struct diffstat_t *diffstat)
+void free_diffstat_info(struct diffstat_t *diffstat)
 {
 	int i;
 	for (i = 0; i < diffstat->nr; i++) {
@@ -3196,7 +3180,7 @@
 	for (cnt = 1; cnt < marker_size; cnt++)
 		if (line[cnt] != firstchar)
 			return 0;
-	/* line[1] thru line[marker_size-1] are same as firstchar */
+	/* line[1] through line[marker_size-1] are same as firstchar */
 	if (len < marker_size + 1 || !isspace(line[marker_size]))
 		return 0;
 	return 1;
@@ -6283,12 +6267,7 @@
 	    dirstat_by_line) {
 		struct diffstat_t diffstat;
 
-		memset(&diffstat, 0, sizeof(struct diffstat_t));
-		for (i = 0; i < q->nr; i++) {
-			struct diff_filepair *p = q->queue[i];
-			if (check_pair_status(p))
-				diff_flush_stat(p, options, &diffstat);
-		}
+		compute_diffstat(options, &diffstat, q);
 		if (output_format & DIFF_FORMAT_NUMSTAT)
 			show_numstat(&diffstat, options);
 		if (output_format & DIFF_FORMAT_DIFFSTAT)
@@ -6621,6 +6600,20 @@
 	return ignored;
 }
 
+void compute_diffstat(struct diff_options *options,
+		      struct diffstat_t *diffstat,
+		      struct diff_queue_struct *q)
+{
+	int i;
+
+	memset(diffstat, 0, sizeof(struct diffstat_t));
+	for (i = 0; i < q->nr; i++) {
+		struct diff_filepair *p = q->queue[i];
+		if (check_pair_status(p))
+			diff_flush_stat(p, options, diffstat);
+	}
+}
+
 void diff_addremove(struct diff_options *options,
 		    int addremove, unsigned mode,
 		    const struct object_id *oid,
diff --git a/diff.h b/diff.h
index 7f8f024..6febe7e 100644
--- a/diff.h
+++ b/diff.h
@@ -9,6 +9,49 @@
 #include "object.h"
 #include "oidset.h"
 
+/**
+ * The diff API is for programs that compare two sets of files (e.g. two trees,
+ * one tree and the index) and present the found difference in various ways.
+ * The calling program is responsible for feeding the API pairs of files, one
+ * from the "old" set and the corresponding one from "new" set, that are
+ * different.
+ * The library called through this API is called diffcore, and is responsible
+ * for two things.
+ *
+ * - finding total rewrites (`-B`), renames (`-M`) and copies (`-C`), and
+ * changes that touch a string (`-S`), as specified by the caller.
+ *
+ * - outputting the differences in various formats, as specified by the caller.
+ *
+ * Calling sequence
+ * ----------------
+ *
+ * - Prepare `struct diff_options` to record the set of diff options, and then
+ * call `repo_diff_setup()` to initialize this structure.  This sets up the
+ * vanilla default.
+ *
+ * - Fill in the options structure to specify desired output format, rename
+ * detection, etc.  `diff_opt_parse()` can be used to parse options given
+ * from the command line in a way consistent with existing git-diff family
+ * of programs.
+ *
+ * - Call `diff_setup_done()`; this inspects the options set up so far for
+ * internal consistency and make necessary tweaking to it (e.g. if textual
+ * patch output was asked, recursive behaviour is turned on); the callback
+ * set_default in diff_options can be used to tweak this more.
+ *
+ * - As you find different pairs of files, call `diff_change()` to feed
+ * modified files, `diff_addremove()` to feed created or deleted files, or
+ * `diff_unmerge()` to feed a file whose state is 'unmerged' to the API.
+ * These are thin wrappers to a lower-level `diff_queue()` function that is
+ * flexible enough to record any of these kinds of changes.
+ *
+ * - Once you finish feeding the pairs of files, call `diffcore_std()`.
+ * This will tell the diffcore library to go ahead and do its work.
+ *
+ * - Calling `diff_flush()` will produce the output.
+ */
+
 struct combine_diff_path;
 struct commit;
 struct diff_filespec;
@@ -65,21 +108,66 @@
 
 #define DIFF_FLAGS_INIT { 0 }
 struct diff_flags {
+
+	/**
+	 * Tells if tree traversal done by tree-diff should recursively descend
+	 * into a tree object pair that are different in preimage and postimage set.
+	 */
 	unsigned recursive;
 	unsigned tree_in_recursive;
+
+	/* Affects the way how a file that is seemingly binary is treated. */
 	unsigned binary;
 	unsigned text;
+
+	/**
+	 * Tells the patch output format not to use abbreviated object names on the
+	 * "index" lines.
+	 */
 	unsigned full_index;
+
+	/* Affects if diff-files shows removed files. */
 	unsigned silent_on_remove;
+
+	/**
+	 * Tells the diffcore library that the caller is feeding unchanged
+	 * filepairs to allow copies from unmodified files be detected.
+	 */
 	unsigned find_copies_harder;
+
 	unsigned follow_renames;
 	unsigned rename_empty;
+
+	/* Internal; used for optimization to see if there is any change. */
 	unsigned has_changes;
+
 	unsigned quick;
+
+	/**
+	 * Tells diff-files that the input is not tracked files but files in random
+	 * locations on the filesystem.
+	 */
 	unsigned no_index;
+
+	/**
+	 * Tells output routine that it is Ok to call user specified patch output
+	 * routine.  Plumbing disables this to ensure stable output.
+	 */
 	unsigned allow_external;
+
+	/**
+	 * For communication between the calling program and the options parser;
+	 * tell the calling program to signal the presence of difference using
+	 * program exit code.
+	 */
 	unsigned exit_with_status;
+
+	/**
+	 * Tells the library that the calling program is feeding the filepairs
+	 * reversed; `one` is two, and `two` is one.
+	 */
 	unsigned reverse_diff;
+
 	unsigned check_failed;
 	unsigned relative_name;
 	unsigned ignore_submodules;
@@ -131,36 +219,72 @@
 	DIFF_SUBMODULE_INLINE_DIFF
 };
 
+/**
+ * the set of options the calling program wants to affect the operation of
+ * diffcore library with.
+ */
 struct diff_options {
 	const char *orderfile;
+
+	/**
+	 * A constant string (can and typically does contain newlines to look for
+	 * a block of text, not just a single line) to filter out the filepairs
+	 * that do not change the number of strings contained in its preimage and
+	 * postimage of the diff_queue.
+	 */
 	const char *pickaxe;
+
 	const char *single_follow;
 	const char *a_prefix, *b_prefix;
 	const char *line_prefix;
 	size_t line_prefix_length;
+
+	/**
+	 * collection of boolean options that affects the operation, but some do
+	 * not have anything to do with the diffcore library.
+	 */
 	struct diff_flags flags;
 
 	/* diff-filter bits */
 	unsigned int filter;
 
 	int use_color;
+
+	/* Number of context lines to generate in patch output. */
 	int context;
+
 	int interhunkcontext;
+
+	/* Affects the way detection logic for complete rewrites, renames and
+	 * copies.
+	 */
 	int break_opt;
 	int detect_rename;
+
 	int irreversible_delete;
 	int skip_stat_unmatch;
 	int line_termination;
+
+	/* The output format used when `diff_flush()` is run. */
 	int output_format;
+
 	unsigned pickaxe_opts;
+
+	/* Affects the way detection logic for complete rewrites, renames and
+	 * copies.
+	 */
 	int rename_score;
 	int rename_limit;
+
 	int needed_rename_limit;
 	int degraded_cc_to_c;
 	int show_rename_progress;
 	int dirstat_permille;
 	int setup;
+
+	/* Number of hexdigits to abbreviate raw format output to. */
 	int abbrev;
+
 	int ita_invisible_in_index;
 /* white-space error highlighting */
 #define WSEH_NEW (1<<12)
@@ -192,6 +316,7 @@
 	/* to support internal diff recursion by --follow hack*/
 	int found_follow;
 
+	/* Callback which allows tweaking the options in diff_setup_done(). */
 	void (*set_default)(struct diff_options *);
 
 	FILE *file;
@@ -245,6 +370,22 @@
 void diff_emit_submodule_pipethrough(struct diff_options *o,
 				     const char *line, int len);
 
+struct diffstat_t {
+	int nr;
+	int alloc;
+	struct diffstat_file {
+		char *from_name;
+		char *name;
+		char *print_name;
+		const char *comments;
+		unsigned is_unmerged:1;
+		unsigned is_binary:1;
+		unsigned is_renamed:1;
+		unsigned is_interesting:1;
+		uintmax_t added, deleted;
+	} **files;
+};
+
 enum color_diff {
 	DIFF_RESET = 0,
 	DIFF_CONTEXT = 1,
@@ -270,6 +411,7 @@
 	DIFF_FILE_OLD_BOLD = 21,
 	DIFF_FILE_NEW_BOLD = 22,
 };
+
 const char *diff_get_color(int diff_use_color, enum color_diff ix);
 #define diff_get_color_opt(o, ix) \
 	diff_get_color((o)->use_color, ix)
@@ -334,6 +476,10 @@
 
 struct diff_filepair *diff_unmerge(struct diff_options *, const char *path);
 
+void compute_diffstat(struct diff_options *options, struct diffstat_t *diffstat,
+		      struct diff_queue_struct *q);
+void free_diffstat_info(struct diffstat_t *diffstat);
+
 #define DIFF_SETUP_REVERSE      	1
 #define DIFF_SETUP_USE_SIZE_CACHE	4
 
diff --git a/diffcore.h b/diffcore.h
index b651061..7c07347 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -28,6 +28,12 @@
 
 #define MINIMUM_BREAK_SIZE     400 /* do not break a file smaller than this */
 
+/**
+ * the internal representation for a single file (blob).  It records the blob
+ * object name (if known -- for a work tree file it typically is a NUL SHA-1),
+ * filemode and pathname.  This is what the `diff_addremove()`, `diff_change()`
+ * and `diff_unmerge()` synthesize and feed `diff_queue()` function with.
+ */
 struct diff_filespec {
 	struct object_id oid;
 	char *path;
@@ -66,6 +72,17 @@
 void diff_free_filespec_blob(struct diff_filespec *);
 int diff_filespec_is_binary(struct repository *, struct diff_filespec *);
 
+/**
+ * This records a pair of `struct diff_filespec`; the filespec for a file in
+ * the "old" set (i.e. preimage) is called `one`, and the filespec for a file
+ * in the "new" set (i.e. postimage) is called `two`.  A change that represents
+ * file creation has NULL in `one`, and file deletion has NULL in `two`.
+ *
+ * A `filepair` starts pointing at `one` and `two` that are from the same
+ * filename, but `diffcore_std()` can break pairs and match component filespecs
+ * with other filespecs from a different filepair to form new filepair. This is
+ * called 'rename detection'.
+ */
 struct diff_filepair {
 	struct diff_filespec *one;
 	struct diff_filespec *two;
@@ -77,6 +94,7 @@
 	unsigned done_skip_stat_unmatch : 1;
 	unsigned skip_stat_unmatch_result : 1;
 };
+
 #define DIFF_PAIR_UNMERGED(p) ((p)->is_unmerged)
 
 #define DIFF_PAIR_RENAME(p) ((p)->renamed_pair)
@@ -94,11 +112,25 @@
 
 int diff_unmodified_pair(struct diff_filepair *);
 
+/**
+ * This is a collection of filepairs.  Notable members are:
+ *
+ * - `queue`:
+ * An array of pointers to `struct diff_filepair`. This dynamically grows as
+ * you add filepairs;
+ *
+ * - `alloc`:
+ * The allocated size of the `queue` array;
+ *
+ * - `nr`:
+ * The number of elements in the `queue` array.
+ */
 struct diff_queue_struct {
 	struct diff_filepair **queue;
 	int alloc;
 	int nr;
 };
+
 #define DIFF_QUEUE_CLEAR(q) \
 	do { \
 		(q)->queue = NULL; \
diff --git a/dir.c b/dir.c
index 22d08e6..7d25522 100644
--- a/dir.c
+++ b/dir.c
@@ -2,8 +2,6 @@
  * This handles recursive filename detection with exclude
  * files, index knowledge etc..
  *
- * See Documentation/technical/api-directory-listing.txt
- *
  * Copyright (C) Linus Torvalds, 2005-2006
  *		 Junio Hamano, 2005-2006
  */
@@ -373,13 +371,20 @@
 		    !ps_strncmp(item, match, name, namelen))
 			return MATCHED_RECURSIVELY_LEADING_PATHSPEC;
 
-		/* name" doesn't match up to the first wild character */
+		/* name doesn't match up to the first wild character */
 		if (item->nowildcard_len < item->len &&
 		    ps_strncmp(item, match, name,
 			       item->nowildcard_len - prefix))
 			return 0;
 
 		/*
+		 * name has no wildcard, and it didn't match as a leading
+		 * pathspec so return.
+		 */
+		if (item->nowildcard_len == item->len)
+			return 0;
+
+		/*
 		 * Here is where we would perform a wildmatch to check if
 		 * "name" can be matched as a directory (or a prefix) against
 		 * the pathspec.  Since wildmatch doesn't have this capability
@@ -1654,6 +1659,8 @@
 	const char *dirname, int len, int baselen, int exclude,
 	const struct pathspec *pathspec)
 {
+	int nested_repo = 0;
+
 	/* The "len-1" is to strip the final '/' */
 	switch (directory_exists_in_index(istate, dirname, len-1)) {
 	case index_directory:
@@ -1663,15 +1670,16 @@
 		return path_none;
 
 	case index_nonexistent:
-		if (dir->flags & DIR_SKIP_NESTED_GIT) {
-			int nested_repo;
+		if ((dir->flags & DIR_SKIP_NESTED_GIT) ||
+		    !(dir->flags & DIR_NO_GITLINKS)) {
 			struct strbuf sb = STRBUF_INIT;
 			strbuf_addstr(&sb, dirname);
 			nested_repo = is_nonbare_repository_dir(&sb);
 			strbuf_release(&sb);
-			if (nested_repo)
-				return path_none;
 		}
+		if (nested_repo)
+			return ((dir->flags & DIR_SKIP_NESTED_GIT) ? path_none :
+				(exclude ? path_excluded : path_untracked));
 
 		if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
 			break;
@@ -1699,13 +1707,6 @@
 
 			return path_none;
 		}
-		if (!(dir->flags & DIR_NO_GITLINKS)) {
-			struct strbuf sb = STRBUF_INIT;
-			strbuf_addstr(&sb, dirname);
-			if (is_nonbare_repository_dir(&sb))
-				return exclude ? path_excluded : path_untracked;
-			strbuf_release(&sb);
-		}
 		return path_recurse;
 	}
 
@@ -2125,6 +2126,40 @@
 	}
 }
 
+static void add_path_to_appropriate_result_list(struct dir_struct *dir,
+	struct untracked_cache_dir *untracked,
+	struct cached_dir *cdir,
+	struct index_state *istate,
+	struct strbuf *path,
+	int baselen,
+	const struct pathspec *pathspec,
+	enum path_treatment state)
+{
+	/* add the path to the appropriate result list */
+	switch (state) {
+	case path_excluded:
+		if (dir->flags & DIR_SHOW_IGNORED)
+			dir_add_name(dir, istate, path->buf, path->len);
+		else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||
+			((dir->flags & DIR_COLLECT_IGNORED) &&
+			exclude_matches_pathspec(path->buf, path->len,
+						 pathspec)))
+			dir_add_ignored(dir, istate, path->buf, path->len);
+		break;
+
+	case path_untracked:
+		if (dir->flags & DIR_SHOW_IGNORED)
+			break;
+		dir_add_name(dir, istate, path->buf, path->len);
+		if (cdir->fdir)
+			add_untracked(untracked, path->buf + baselen);
+		break;
+
+	default:
+		break;
+	}
+}
+
 /*
  * Read a directory tree. We currently ignore anything but
  * directories, regular files and symlinks. That's because git
@@ -2149,6 +2184,15 @@
 	struct untracked_cache_dir *untracked, int check_only,
 	int stop_at_first_file, const struct pathspec *pathspec)
 {
+	/*
+	 * WARNING WARNING WARNING:
+	 *
+	 * Any updates to the traversal logic here may need corresponding
+	 * updates in treat_leading_path().  See the commit message for the
+	 * commit adding this warning as well as the commit preceding it
+	 * for details.
+	 */
+
 	struct cached_dir cdir;
 	enum path_treatment state, subdir_state, dir_state = path_none;
 	struct strbuf path = STRBUF_INIT;
@@ -2228,29 +2272,9 @@
 			continue;
 		}
 
-		/* add the path to the appropriate result list */
-		switch (state) {
-		case path_excluded:
-			if (dir->flags & DIR_SHOW_IGNORED)
-				dir_add_name(dir, istate, path.buf, path.len);
-			else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||
-				((dir->flags & DIR_COLLECT_IGNORED) &&
-				exclude_matches_pathspec(path.buf, path.len,
-							 pathspec)))
-				dir_add_ignored(dir, istate, path.buf, path.len);
-			break;
-
-		case path_untracked:
-			if (dir->flags & DIR_SHOW_IGNORED)
-				break;
-			dir_add_name(dir, istate, path.buf, path.len);
-			if (cdir.fdir)
-				add_untracked(untracked, path.buf + baselen);
-			break;
-
-		default:
-			break;
-		}
+		add_path_to_appropriate_result_list(dir, untracked, &cdir,
+						    istate, &path, baselen,
+						    pathspec, state);
 	}
 	close_cached_dir(&cdir);
  out:
@@ -2280,41 +2304,104 @@
 			      const char *path, int len,
 			      const struct pathspec *pathspec)
 {
+	/*
+	 * WARNING WARNING WARNING:
+	 *
+	 * Any updates to the traversal logic here may need corresponding
+	 * updates in treat_leading_path().  See the commit message for the
+	 * commit adding this warning as well as the commit preceding it
+	 * for details.
+	 */
+
 	struct strbuf sb = STRBUF_INIT;
-	int baselen, rc = 0;
+	int prevlen, baselen;
 	const char *cp;
-	int old_flags = dir->flags;
+	struct cached_dir cdir;
+	struct dirent *de;
+	enum path_treatment state = path_none;
+
+	/*
+	 * For each directory component of path, we are going to check whether
+	 * that path is relevant given the pathspec.  For example, if path is
+	 *    foo/bar/baz/
+	 * then we will ask treat_path() whether we should go into foo, then
+	 * whether we should go into bar, then whether baz is relevant.
+	 * Checking each is important because e.g. if path is
+	 *    .git/info/
+	 * then we need to check .git to know we shouldn't traverse it.
+	 * If the return from treat_path() is:
+	 *    * path_none, for any path, we return false.
+	 *    * path_recurse, for all path components, we return true
+	 *    * <anything else> for some intermediate component, we make sure
+	 *        to add that path to the relevant list but return false
+	 *        signifying that we shouldn't recurse into it.
+	 */
 
 	while (len && path[len - 1] == '/')
 		len--;
 	if (!len)
 		return 1;
+
+	/*
+	 * We need a manufactured dirent with sufficient space to store a
+	 * leading directory component of path in its d_name.  Here, we
+	 * assume that the dirent's d_name is either declared as
+	 *    char d_name[BIG_ENOUGH]
+	 * or that it is declared at the end of the struct as
+	 *    char d_name[]
+	 * For either case, padding with len+1 bytes at the end will ensure
+	 * sufficient storage space.
+	 */
+	de = xcalloc(1, st_add3(sizeof(struct dirent), len, 1));
+	memset(&cdir, 0, sizeof(cdir));
+	cdir.de = de;
+#if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
+	de->d_type = DT_DIR;
+#endif
 	baselen = 0;
-	dir->flags &= ~DIR_SHOW_OTHER_DIRECTORIES;
+	prevlen = 0;
 	while (1) {
-		cp = path + baselen + !!baselen;
+		prevlen = baselen + !!baselen;
+		cp = path + prevlen;
 		cp = memchr(cp, '/', path + len - cp);
 		if (!cp)
 			baselen = len;
 		else
 			baselen = cp - path;
-		strbuf_setlen(&sb, 0);
+		strbuf_reset(&sb);
 		strbuf_add(&sb, path, baselen);
 		if (!is_directory(sb.buf))
 			break;
-		if (simplify_away(sb.buf, sb.len, pathspec))
-			break;
-		if (treat_one_path(dir, NULL, istate, &sb, baselen, pathspec,
-				   DT_DIR, NULL) == path_none)
-			break; /* do not recurse into it */
-		if (len <= baselen) {
-			rc = 1;
-			break; /* finished checking */
+		strbuf_reset(&sb);
+		strbuf_add(&sb, path, prevlen);
+		memcpy(de->d_name, path+prevlen, baselen-prevlen);
+		de->d_name[baselen-prevlen] = '\0';
+		state = treat_path(dir, NULL, &cdir, istate, &sb, prevlen,
+				    pathspec);
+		if (state == path_untracked &&
+		    get_dtype(cdir.de, istate, sb.buf, sb.len) == DT_DIR &&
+		    (dir->flags & DIR_SHOW_IGNORED_TOO ||
+		     do_match_pathspec(istate, pathspec, sb.buf, sb.len,
+				       baselen, NULL, DO_MATCH_LEADING_PATHSPEC) == MATCHED_RECURSIVELY_LEADING_PATHSPEC)) {
+			add_path_to_appropriate_result_list(dir, NULL, &cdir,
+							    istate,
+							    &sb, baselen,
+							    pathspec, state);
+			state = path_recurse;
 		}
+
+		if (state != path_recurse)
+			break; /* do not recurse into it */
+		if (len <= baselen)
+			break; /* finished checking */
 	}
+	add_path_to_appropriate_result_list(dir, NULL, &cdir, istate,
+					    &sb, baselen, pathspec,
+					    state);
+
+	free(de);
 	strbuf_release(&sb);
-	dir->flags = old_flags;
-	return rc;
+	return state == path_recurse;
 }
 
 static const char *get_ident_string(void)
@@ -2689,7 +2776,7 @@
 				 * wanted anyway
 				 */
 				continue;
-			/* fall thru */
+			/* fall through */
 		} else if (S_ISDIR(st.st_mode)) {
 			if (!remove_dir_recurse(path, flag, &kept_down))
 				continue; /* happy */
diff --git a/dir.h b/dir.h
index 77a43db..5855c06 100644
--- a/dir.h
+++ b/dir.h
@@ -1,12 +1,45 @@
 #ifndef DIR_H
 #define DIR_H
 
-/* See Documentation/technical/api-directory-listing.txt */
-
 #include "cache.h"
 #include "hashmap.h"
 #include "strbuf.h"
 
+/**
+ * The directory listing API is used to enumerate paths in the work tree,
+ * optionally taking `.git/info/exclude` and `.gitignore` files per directory
+ * into account.
+ */
+
+/**
+ * Calling sequence
+ * ----------------
+ *
+ * Note: The index may be checked for .gitignore files that are
+ * CE_SKIP_WORKTREE marked. If you want to exclude files, make sure you have
+ * loaded the index first.
+ *
+ * - Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0,
+ * sizeof(dir))`.
+ *
+ * - To add single exclude pattern, call `add_pattern_list()` and then
+ *   `add_pattern()`.
+ *
+ * - To add patterns from a file (e.g. `.git/info/exclude`), call
+ *   `add_patterns_from_file()` , and/or set `dir.exclude_per_dir`.  A
+ *   short-hand function `setup_standard_excludes()` can be used to set
+ *   up the standard set of exclude settings.
+ *
+ * - Set options described in the Data Structure section above.
+ *
+ * - Call `read_directory()`.
+ *
+ * - Use `dir.entries[]`.
+ *
+ * - Call `clear_directory()` when none of the contained elements are no longer in use.
+ *
+ */
+
 struct dir_entry {
 	unsigned int len;
 	char name[FLEX_ARRAY]; /* more */
@@ -172,25 +205,101 @@
 	unsigned int use_fsmonitor : 1;
 };
 
+/**
+ * structure is used to pass directory traversal options to the library and to
+ * record the paths discovered. A single `struct dir_struct` is used regardless
+ * of whether or not the traversal recursively descends into subdirectories.
+ */
 struct dir_struct {
-	int nr, alloc;
-	int ignored_nr, ignored_alloc;
+
+	/* The number of members in `entries[]` array. */
+	int nr;
+
+	/* Internal use; keeps track of allocation of `entries[]` array.*/
+	int alloc;
+
+	/* The number of members in `ignored[]` array. */
+	int ignored_nr;
+
+	int ignored_alloc;
+
+	/* bit-field of options */
 	enum {
+
+		/**
+		 * Return just ignored files in `entries[]`, not untracked files.
+		 * This flag is mutually exclusive with `DIR_SHOW_IGNORED_TOO`.
+		 */
 		DIR_SHOW_IGNORED = 1<<0,
+
+		/* Include a directory that is not tracked. */
 		DIR_SHOW_OTHER_DIRECTORIES = 1<<1,
+
+		/* Do not include a directory that is not tracked and is empty. */
 		DIR_HIDE_EMPTY_DIRECTORIES = 1<<2,
+
+		/**
+		 * If set, recurse into a directory that looks like a Git directory.
+		 * Otherwise it is shown as a directory.
+		 */
 		DIR_NO_GITLINKS = 1<<3,
+
+		/**
+		 * Special mode for git-add. Return ignored files in `ignored[]` and
+		 * untracked files in `entries[]`. Only returns ignored files that match
+		 * pathspec exactly (no wildcards). Does not recurse into ignored
+		 * directories.
+		 */
 		DIR_COLLECT_IGNORED = 1<<4,
+
+		/**
+		 * Similar to `DIR_SHOW_IGNORED`, but return ignored files in
+		 * `ignored[]` in addition to untracked files in `entries[]`.
+		 * This flag is mutually exclusive with `DIR_SHOW_IGNORED`.
+		 */
 		DIR_SHOW_IGNORED_TOO = 1<<5,
+
 		DIR_COLLECT_KILLED_ONLY = 1<<6,
+
+		/**
+		 * Only has meaning if `DIR_SHOW_IGNORED_TOO` is also set; if this is
+		 * set, the untracked contents of untracked directories are also
+		 * returned in `entries[]`.
+		 */
 		DIR_KEEP_UNTRACKED_CONTENTS = 1<<7,
+
+		/**
+		 * Only has meaning if `DIR_SHOW_IGNORED_TOO` is also set; if this is
+		 * set, returns ignored files and directories that match an exclude
+		 * pattern. If a directory matches an exclude pattern, then the
+		 * directory is returned and the contained paths are not. A directory
+		 * that does not match an exclude pattern will not be returned even if
+		 * all of its contents are ignored. In this case, the contents are
+		 * returned as individual entries.
+		 *
+		 * If this is set, files and directories that explicitly match an ignore
+		 * pattern are reported. Implicitly ignored directories (directories that
+		 * do not match an ignore pattern, but whose contents are all ignored)
+		 * are not reported, instead all of the contents are reported.
+		 */
 		DIR_SHOW_IGNORED_TOO_MODE_MATCHING = 1<<8,
+
 		DIR_SKIP_NESTED_GIT = 1<<9
 	} flags;
+
+	/* An array of `struct dir_entry`, each element of which describes a path. */
 	struct dir_entry **entries;
+
+	/**
+	 * used for ignored paths with the `DIR_SHOW_IGNORED_TOO` and
+	 * `DIR_COLLECT_IGNORED` flags.
+	 */
 	struct dir_entry **ignored;
 
-	/* Exclude info */
+	/**
+	 * The name of the file to be read in each directory for excluded files
+	 * (typically `.gitignore`).
+	 */
 	const char *exclude_per_dir;
 
 	/*
diff --git a/environment.c b/environment.c
index 2a1a866..e72a02d 100644
--- a/environment.c
+++ b/environment.c
@@ -79,7 +79,7 @@
 int protect_hfs = PROTECT_HFS_DEFAULT;
 
 #ifndef PROTECT_NTFS_DEFAULT
-#define PROTECT_NTFS_DEFAULT 0
+#define PROTECT_NTFS_DEFAULT 1
 #endif
 int protect_ntfs = PROTECT_NTFS_DEFAULT;
 const char *core_fsmonitor;
diff --git a/fast-import.c b/fast-import.c
index 9503d08..b8b65a8 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -217,6 +217,7 @@
 static struct strbuf new_data = STRBUF_INIT;
 static int seen_data_command;
 static int require_explicit_termination;
+static int allow_unsafe_features;
 
 /* Signal handling */
 static volatile sig_atomic_t checkpoint_requested;
@@ -1682,6 +1683,12 @@
 	if (!export_marks_file || (import_marks_file && !import_marks_file_done))
 		return;
 
+	if (safe_create_leading_directories_const(export_marks_file)) {
+		failure |= error_errno("unable to create leading directories of %s",
+				       export_marks_file);
+		return;
+	}
+
 	if (hold_lock_file_for_update(&mark_lock, export_marks_file, 0) < 0) {
 		failure |= error_errno("Unable to write marks file %s",
 				       export_marks_file);
@@ -3146,7 +3153,6 @@
 	}
 
 	import_marks_file = make_fast_import_path(marks);
-	safe_create_leading_directories_const(import_marks_file);
 	import_marks_file_from_stream = from_stream;
 	import_marks_file_ignore_missing = ignore_missing;
 }
@@ -3187,7 +3193,6 @@
 static void option_export_marks(const char *marks)
 {
 	export_marks_file = make_fast_import_path(marks);
-	safe_create_leading_directories_const(export_marks_file);
 }
 
 static void option_cat_blob_fd(const char *fd)
@@ -3230,10 +3235,12 @@
 		option_active_branches(option);
 	} else if (skip_prefix(option, "export-pack-edges=", &option)) {
 		option_export_pack_edges(option);
-	} else if (starts_with(option, "quiet")) {
+	} else if (!strcmp(option, "quiet")) {
 		show_stats = 0;
-	} else if (starts_with(option, "stats")) {
+	} else if (!strcmp(option, "stats")) {
 		show_stats = 1;
+	} else if (!strcmp(option, "allow-unsafe-features")) {
+		; /* already handled during early option parsing */
 	} else {
 		return 0;
 	}
@@ -3241,6 +3248,13 @@
 	return 1;
 }
 
+static void check_unsafe_feature(const char *feature, int from_stream)
+{
+	if (from_stream && !allow_unsafe_features)
+		die(_("feature '%s' forbidden in input without --allow-unsafe-features"),
+		    feature);
+}
+
 static int parse_one_feature(const char *feature, int from_stream)
 {
 	const char *arg;
@@ -3248,10 +3262,13 @@
 	if (skip_prefix(feature, "date-format=", &arg)) {
 		option_date_format(arg);
 	} else if (skip_prefix(feature, "import-marks=", &arg)) {
+		check_unsafe_feature("import-marks", from_stream);
 		option_import_marks(arg, from_stream, 0);
 	} else if (skip_prefix(feature, "import-marks-if-exists=", &arg)) {
+		check_unsafe_feature("import-marks-if-exists", from_stream);
 		option_import_marks(arg, from_stream, 1);
 	} else if (skip_prefix(feature, "export-marks=", &arg)) {
+		check_unsafe_feature(feature, from_stream);
 		option_export_marks(arg);
 	} else if (!strcmp(feature, "alias")) {
 		; /* Don't die - this feature is supported */
@@ -3380,6 +3397,20 @@
 	avail_tree_table = xcalloc(avail_tree_table_sz, sizeof(struct avail_tree_content*));
 	marks = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct mark_set));
 
+	/*
+	 * We don't parse most options until after we've seen the set of
+	 * "feature" lines at the start of the stream (which allows the command
+	 * line to override stream data). But we must do an early parse of any
+	 * command-line options that impact how we interpret the feature lines.
+	 */
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+		if (*arg != '-' || !strcmp(arg, "--"))
+			break;
+		if (!strcmp(arg, "--allow-unsafe-features"))
+			allow_unsafe_features = 1;
+	}
+
 	global_argc = argc;
 	global_argv = argv;
 
diff --git a/fetch-pack.c b/fetch-pack.c
index f80e2d1..1734a57 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -669,17 +669,20 @@
 
 	save_commit_buffer = 0;
 
+	trace2_region_enter("fetch-pack", "parse_remote_refs_and_find_cutoff", NULL);
 	for (ref = *refs; ref; ref = ref->next) {
 		struct object *o;
 
 		if (!has_object_file_with_flags(&ref->old_oid,
-						OBJECT_INFO_QUICK))
+						OBJECT_INFO_QUICK |
+							OBJECT_INFO_SKIP_FETCH_OBJECT))
 			continue;
 		o = parse_object(the_repository, &ref->old_oid);
 		if (!o)
 			continue;
 
-		/* We already have it -- which may mean that we were
+		/*
+		 * We already have it -- which may mean that we were
 		 * in sync with the other side at some time after
 		 * that (it is OK if we guess wrong here).
 		 */
@@ -689,7 +692,13 @@
 				cutoff = commit->date;
 		}
 	}
+	trace2_region_leave("fetch-pack", "parse_remote_refs_and_find_cutoff", NULL);
 
+	/*
+	 * This block marks all local refs as COMPLETE, and then recursively marks all
+	 * parents of those refs as COMPLETE.
+	 */
+	trace2_region_enter("fetch-pack", "mark_complete_local_refs", NULL);
 	if (!args->deepen) {
 		for_each_ref(mark_complete_oid, NULL);
 		for_each_cached_alternate(NULL, mark_alternate_complete);
@@ -697,11 +706,13 @@
 		if (cutoff)
 			mark_recent_complete_commits(args, cutoff);
 	}
+	trace2_region_leave("fetch-pack", "mark_complete_local_refs", NULL);
 
 	/*
 	 * Mark all complete remote refs as common refs.
 	 * Don't mark them common yet; the server has to be told so first.
 	 */
+	trace2_region_enter("fetch-pack", "mark_common_remote_refs", NULL);
 	for (ref = *refs; ref; ref = ref->next) {
 		struct object *o = deref_tag(the_repository,
 					     lookup_object(the_repository,
@@ -714,6 +725,7 @@
 		negotiator->known_common(negotiator,
 					 (struct commit *)o);
 	}
+	trace2_region_leave("fetch-pack", "mark_common_remote_refs", NULL);
 
 	save_commit_buffer = old_save_commit_buffer;
 }
@@ -934,8 +946,15 @@
 	struct object_id oid;
 	const char *agent_feature;
 	int agent_len;
-	struct fetch_negotiator negotiator;
-	fetch_negotiator_init(r, &negotiator);
+	struct fetch_negotiator negotiator_alloc;
+	struct fetch_negotiator *negotiator;
+
+	if (args->no_dependents) {
+		negotiator = NULL;
+	} else {
+		negotiator = &negotiator_alloc;
+		fetch_negotiator_init(r, negotiator);
+	}
 
 	sort_ref_list(&ref, ref_compare_name);
 	QSORT(sought, nr_sought, cmp_ref_by_name);
@@ -1022,7 +1041,7 @@
 		die(_("Server does not support --deepen"));
 
 	if (!args->no_dependents) {
-		mark_complete_and_common_ref(&negotiator, args, &ref);
+		mark_complete_and_common_ref(negotiator, args, &ref);
 		filter_refs(args, &ref, sought, nr_sought);
 		if (everything_local(args, &ref)) {
 			packet_flush(fd[1]);
@@ -1031,7 +1050,7 @@
 	} else {
 		filter_refs(args, &ref, sought, nr_sought);
 	}
-	if (find_common(&negotiator, args, fd, &oid, ref) < 0)
+	if (find_common(negotiator, args, fd, &oid, ref) < 0)
 		if (!args->keep_pack)
 			/* When cloning, it is not unusual to have
 			 * no common commit.
@@ -1051,7 +1070,8 @@
 		die(_("git fetch-pack: fetch failed."));
 
  all_done:
-	negotiator.release(&negotiator);
+	if (negotiator)
+		negotiator->release(negotiator);
 	return ref;
 }
 
@@ -1269,7 +1289,8 @@
 				struct commit *commit;
 				oidset_insert(common, &oid);
 				commit = lookup_commit(the_repository, &oid);
-				negotiator->ack(negotiator, commit);
+				if (negotiator)
+					negotiator->ack(negotiator, commit);
 			}
 			continue;
 		}
@@ -1421,8 +1442,16 @@
 	struct packet_reader reader;
 	int in_vain = 0, negotiation_started = 0;
 	int haves_to_send = INITIAL_FLUSH;
-	struct fetch_negotiator negotiator;
-	fetch_negotiator_init(r, &negotiator);
+	struct fetch_negotiator negotiator_alloc;
+	struct fetch_negotiator *negotiator;
+
+	if (args->no_dependents) {
+		negotiator = NULL;
+	} else {
+		negotiator = &negotiator_alloc;
+		fetch_negotiator_init(r, negotiator);
+	}
+
 	packet_reader_init(&reader, fd[0], NULL, 0,
 			   PACKET_READ_CHOMP_NEWLINE |
 			   PACKET_READ_DIE_ON_ERR_PACKET);
@@ -1446,15 +1475,15 @@
 
 			/* Filter 'ref' by 'sought' and those that aren't local */
 			if (!args->no_dependents) {
-				mark_complete_and_common_ref(&negotiator, args, &ref);
+				mark_complete_and_common_ref(negotiator, args, &ref);
 				filter_refs(args, &ref, sought, nr_sought);
 				if (everything_local(args, &ref))
 					state = FETCH_DONE;
 				else
 					state = FETCH_SEND_REQUEST;
 
-				mark_tips(&negotiator, args->negotiation_tips);
-				for_each_cached_alternate(&negotiator,
+				mark_tips(negotiator, args->negotiation_tips);
+				for_each_cached_alternate(negotiator,
 							  insert_one_alternate_object);
 			} else {
 				filter_refs(args, &ref, sought, nr_sought);
@@ -1468,7 +1497,7 @@
 						    "negotiation_v2",
 						    the_repository);
 			}
-			if (send_fetch_request(&negotiator, fd[1], args, ref,
+			if (send_fetch_request(negotiator, fd[1], args, ref,
 					       &common,
 					       &haves_to_send, &in_vain,
 					       reader.use_sideband))
@@ -1478,7 +1507,7 @@
 			break;
 		case FETCH_PROCESS_ACKS:
 			/* Process ACKs/NAKs */
-			switch (process_acks(&negotiator, &reader, &common)) {
+			switch (process_acks(negotiator, &reader, &common)) {
 			case 2:
 				state = FETCH_GET_PACK;
 				break;
@@ -1513,7 +1542,8 @@
 		}
 	}
 
-	negotiator.release(&negotiator);
+	if (negotiator)
+		negotiator->release(negotiator);
 	oidset_clear(&common);
 	return ref;
 }
diff --git a/fsck.c b/fsck.c
index cdb7d8d..640d813 100644
--- a/fsck.c
+++ b/fsck.c
@@ -43,21 +43,17 @@
 	FUNC(MISSING_AUTHOR, ERROR) \
 	FUNC(MISSING_COMMITTER, ERROR) \
 	FUNC(MISSING_EMAIL, ERROR) \
-	FUNC(MISSING_GRAFT, ERROR) \
 	FUNC(MISSING_NAME_BEFORE_EMAIL, ERROR) \
 	FUNC(MISSING_OBJECT, ERROR) \
-	FUNC(MISSING_PARENT, ERROR) \
 	FUNC(MISSING_SPACE_BEFORE_DATE, ERROR) \
 	FUNC(MISSING_SPACE_BEFORE_EMAIL, ERROR) \
 	FUNC(MISSING_TAG, ERROR) \
 	FUNC(MISSING_TAG_ENTRY, ERROR) \
-	FUNC(MISSING_TAG_OBJECT, ERROR) \
 	FUNC(MISSING_TREE, ERROR) \
 	FUNC(MISSING_TREE_OBJECT, ERROR) \
 	FUNC(MISSING_TYPE, ERROR) \
 	FUNC(MISSING_TYPE_ENTRY, ERROR) \
 	FUNC(MULTIPLE_AUTHORS, ERROR) \
-	FUNC(TAG_OBJECT_NOT_TAG, ERROR) \
 	FUNC(TREE_NOT_SORTED, ERROR) \
 	FUNC(UNKNOWN_TYPE, ERROR) \
 	FUNC(ZERO_PADDED_DATE, ERROR) \
@@ -68,6 +64,7 @@
 	FUNC(GITMODULES_SYMLINK, ERROR) \
 	FUNC(GITMODULES_URL, ERROR) \
 	FUNC(GITMODULES_PATH, ERROR) \
+	FUNC(GITMODULES_UPDATE, ERROR) \
 	/* warnings */ \
 	FUNC(BAD_FILEMODE, WARN) \
 	FUNC(EMPTY_NAME, WARN) \
@@ -281,14 +278,16 @@
 	strbuf_addstr(sb, ": ");
 }
 
-static int object_on_skiplist(struct fsck_options *opts, struct object *obj)
+static int object_on_skiplist(struct fsck_options *opts,
+			      const struct object_id *oid)
 {
-	return opts && obj && oidset_contains(&opts->skiplist, &obj->oid);
+	return opts && oid && oidset_contains(&opts->skiplist, oid);
 }
 
-__attribute__((format (printf, 4, 5)))
-static int report(struct fsck_options *options, struct object *object,
-	enum fsck_msg_id id, const char *fmt, ...)
+__attribute__((format (printf, 5, 6)))
+static int report(struct fsck_options *options,
+		  const struct object_id *oid, enum object_type object_type,
+		  enum fsck_msg_id id, const char *fmt, ...)
 {
 	va_list ap;
 	struct strbuf sb = STRBUF_INIT;
@@ -297,7 +296,7 @@
 	if (msg_type == FSCK_IGNORE)
 		return 0;
 
-	if (object_on_skiplist(options, object))
+	if (object_on_skiplist(options, oid))
 		return 0;
 
 	if (msg_type == FSCK_FATAL)
@@ -309,49 +308,71 @@
 
 	va_start(ap, fmt);
 	strbuf_vaddf(&sb, fmt, ap);
-	result = options->error_func(options, object, msg_type, sb.buf);
+	result = options->error_func(options, oid, object_type,
+				     msg_type, sb.buf);
 	strbuf_release(&sb);
 	va_end(ap);
 
 	return result;
 }
 
-static char *get_object_name(struct fsck_options *options, struct object *obj)
+void fsck_enable_object_names(struct fsck_options *options)
 {
 	if (!options->object_names)
-		return NULL;
-	return lookup_decoration(options->object_names, obj);
+		options->object_names = kh_init_oid_map();
 }
 
-static void put_object_name(struct fsck_options *options, struct object *obj,
-	const char *fmt, ...)
+const char *fsck_get_object_name(struct fsck_options *options,
+				 const struct object_id *oid)
+{
+	khiter_t pos;
+	if (!options->object_names)
+		return NULL;
+	pos = kh_get_oid_map(options->object_names, *oid);
+	if (pos >= kh_end(options->object_names))
+		return NULL;
+	return kh_value(options->object_names, pos);
+}
+
+void fsck_put_object_name(struct fsck_options *options,
+			  const struct object_id *oid,
+			  const char *fmt, ...)
 {
 	va_list ap;
 	struct strbuf buf = STRBUF_INIT;
-	char *existing;
+	khiter_t pos;
+	int hashret;
 
 	if (!options->object_names)
 		return;
-	existing = lookup_decoration(options->object_names, obj);
-	if (existing)
+
+	pos = kh_put_oid_map(options->object_names, *oid, &hashret);
+	if (!hashret)
 		return;
 	va_start(ap, fmt);
 	strbuf_vaddf(&buf, fmt, ap);
-	add_decoration(options->object_names, obj, strbuf_detach(&buf, NULL));
+	kh_value(options->object_names, pos) = strbuf_detach(&buf, NULL);
 	va_end(ap);
 }
 
-static const char *describe_object(struct fsck_options *o, struct object *obj)
+const char *fsck_describe_object(struct fsck_options *options,
+				 const struct object_id *oid)
 {
-	static struct strbuf buf = STRBUF_INIT;
-	char *name;
+	static struct strbuf bufs[] = {
+		STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
+	};
+	static int b = 0;
+	struct strbuf *buf;
+	const char *name = fsck_get_object_name(options, oid);
 
-	strbuf_reset(&buf);
-	strbuf_addstr(&buf, oid_to_hex(&obj->oid));
-	if (o->object_names && (name = lookup_decoration(o->object_names, obj)))
-		strbuf_addf(&buf, " (%s)", name);
+	buf = bufs + b;
+	b = (b + 1) % ARRAY_SIZE(bufs);
+	strbuf_reset(buf);
+	strbuf_addstr(buf, oid_to_hex(oid));
+	if (name)
+		strbuf_addf(buf, " (%s)", name);
 
-	return buf.buf;
+	return buf->buf;
 }
 
 static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *options)
@@ -364,7 +385,7 @@
 	if (parse_tree(tree))
 		return -1;
 
-	name = get_object_name(options, &tree->object);
+	name = fsck_get_object_name(options, &tree->object.oid);
 	if (init_tree_desc_gently(&desc, tree->buffer, tree->size))
 		return -1;
 	while (tree_entry_gently(&desc, &entry)) {
@@ -377,20 +398,21 @@
 		if (S_ISDIR(entry.mode)) {
 			obj = (struct object *)lookup_tree(the_repository, &entry.oid);
 			if (name && obj)
-				put_object_name(options, obj, "%s%s/", name,
-					entry.path);
+				fsck_put_object_name(options, &entry.oid, "%s%s/",
+						     name, entry.path);
 			result = options->walk(obj, OBJ_TREE, data, options);
 		}
 		else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
 			obj = (struct object *)lookup_blob(the_repository, &entry.oid);
 			if (name && obj)
-				put_object_name(options, obj, "%s%s", name,
-					entry.path);
+				fsck_put_object_name(options, &entry.oid, "%s%s",
+						     name, entry.path);
 			result = options->walk(obj, OBJ_BLOB, data, options);
 		}
 		else {
 			result = error("in tree %s: entry %s has bad mode %.6o",
-					describe_object(options, &tree->object), entry.path, entry.mode);
+				       fsck_describe_object(options, &tree->object.oid),
+				       entry.path, entry.mode);
 		}
 		if (result < 0)
 			return result;
@@ -411,10 +433,10 @@
 	if (parse_commit(commit))
 		return -1;
 
-	name = get_object_name(options, &commit->object);
+	name = fsck_get_object_name(options, &commit->object.oid);
 	if (name)
-		put_object_name(options, &get_commit_tree(commit)->object,
-				"%s:", name);
+		fsck_put_object_name(options, get_commit_tree_oid(commit),
+				     "%s:", name);
 
 	result = options->walk((struct object *)get_commit_tree(commit),
 			       OBJ_TREE, data, options);
@@ -442,16 +464,17 @@
 
 	while (parents) {
 		if (name) {
-			struct object *obj = &parents->item->object;
+			struct object_id *oid = &parents->item->object.oid;
 
 			if (counter++)
-				put_object_name(options, obj, "%s^%d",
-					name, counter);
+				fsck_put_object_name(options, oid, "%s^%d",
+						     name, counter);
 			else if (generation > 0)
-				put_object_name(options, obj, "%.*s~%d",
-					name_prefix_len, name, generation + 1);
+				fsck_put_object_name(options, oid, "%.*s~%d",
+						     name_prefix_len, name,
+						     generation + 1);
 			else
-				put_object_name(options, obj, "%s^", name);
+				fsck_put_object_name(options, oid, "%s^", name);
 		}
 		result = options->walk((struct object *)parents->item, OBJ_COMMIT, data, options);
 		if (result < 0)
@@ -465,12 +488,12 @@
 
 static int fsck_walk_tag(struct tag *tag, void *data, struct fsck_options *options)
 {
-	char *name = get_object_name(options, &tag->object);
+	const char *name = fsck_get_object_name(options, &tag->object.oid);
 
 	if (parse_tag(tag))
 		return -1;
 	if (name)
-		put_object_name(options, tag->tagged, "%s", name);
+		fsck_put_object_name(options, &tag->tagged->oid, "%s", name);
 	return options->walk(tag->tagged, OBJ_ANY, data, options);
 }
 
@@ -492,7 +515,8 @@
 	case OBJ_TAG:
 		return fsck_walk_tag((struct tag *)obj, data, options);
 	default:
-		error("Unknown object type for %s", describe_object(options, obj));
+		error("Unknown object type for %s",
+		      fsck_describe_object(options, &obj->oid));
 		return -1;
 	}
 }
@@ -543,7 +567,9 @@
 	return c1 < c2 ? 0 : TREE_UNORDERED;
 }
 
-static int fsck_tree(struct tree *item, struct fsck_options *options)
+static int fsck_tree(const struct object_id *oid,
+		     const char *buffer, unsigned long size,
+		     struct fsck_options *options)
 {
 	int retval = 0;
 	int has_null_sha1 = 0;
@@ -560,8 +586,8 @@
 	unsigned o_mode;
 	const char *o_name;
 
-	if (init_tree_desc_gently(&desc, item->buffer, item->size)) {
-		retval += report(options, &item->object, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
+	if (init_tree_desc_gently(&desc, buffer, size)) {
+		retval += report(options, oid, OBJ_TREE, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
 		return retval;
 	}
 
@@ -570,7 +596,7 @@
 
 	while (desc.size) {
 		unsigned short mode;
-		const char *name;
+		const char *name, *backslash;
 		const struct object_id *oid;
 
 		oid = tree_entry_extract(&desc, &name, &mode);
@@ -587,13 +613,30 @@
 			if (!S_ISLNK(mode))
 				oidset_insert(&gitmodules_found, oid);
 			else
-				retval += report(options, &item->object,
+				retval += report(options,
+						 oid, OBJ_TREE,
 						 FSCK_MSG_GITMODULES_SYMLINK,
 						 ".gitmodules is a symbolic link");
 		}
 
+		if ((backslash = strchr(name, '\\'))) {
+			while (backslash) {
+				backslash++;
+				has_dotgit |= is_ntfs_dotgit(backslash);
+				if (is_ntfs_dotgitmodules(backslash)) {
+					if (!S_ISLNK(mode))
+						oidset_insert(&gitmodules_found, oid);
+					else
+						retval += report(options, oid, OBJ_TREE,
+								 FSCK_MSG_GITMODULES_SYMLINK,
+								 ".gitmodules is a symbolic link");
+				}
+				backslash = strchr(backslash, '\\');
+			}
+		}
+
 		if (update_tree_entry_gently(&desc)) {
-			retval += report(options, &item->object, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
+			retval += report(options, oid, OBJ_TREE, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
 			break;
 		}
 
@@ -638,30 +681,31 @@
 	}
 
 	if (has_null_sha1)
-		retval += report(options, &item->object, FSCK_MSG_NULL_SHA1, "contains entries pointing to null sha1");
+		retval += report(options, oid, OBJ_TREE, FSCK_MSG_NULL_SHA1, "contains entries pointing to null sha1");
 	if (has_full_path)
-		retval += report(options, &item->object, FSCK_MSG_FULL_PATHNAME, "contains full pathnames");
+		retval += report(options, oid, OBJ_TREE, FSCK_MSG_FULL_PATHNAME, "contains full pathnames");
 	if (has_empty_name)
-		retval += report(options, &item->object, FSCK_MSG_EMPTY_NAME, "contains empty pathname");
+		retval += report(options, oid, OBJ_TREE, FSCK_MSG_EMPTY_NAME, "contains empty pathname");
 	if (has_dot)
-		retval += report(options, &item->object, FSCK_MSG_HAS_DOT, "contains '.'");
+		retval += report(options, oid, OBJ_TREE, FSCK_MSG_HAS_DOT, "contains '.'");
 	if (has_dotdot)
-		retval += report(options, &item->object, FSCK_MSG_HAS_DOTDOT, "contains '..'");
+		retval += report(options, oid, OBJ_TREE, FSCK_MSG_HAS_DOTDOT, "contains '..'");
 	if (has_dotgit)
-		retval += report(options, &item->object, FSCK_MSG_HAS_DOTGIT, "contains '.git'");
+		retval += report(options, oid, OBJ_TREE, FSCK_MSG_HAS_DOTGIT, "contains '.git'");
 	if (has_zero_pad)
-		retval += report(options, &item->object, FSCK_MSG_ZERO_PADDED_FILEMODE, "contains zero-padded file modes");
+		retval += report(options, oid, OBJ_TREE, FSCK_MSG_ZERO_PADDED_FILEMODE, "contains zero-padded file modes");
 	if (has_bad_modes)
-		retval += report(options, &item->object, FSCK_MSG_BAD_FILEMODE, "contains bad file modes");
+		retval += report(options, oid, OBJ_TREE, FSCK_MSG_BAD_FILEMODE, "contains bad file modes");
 	if (has_dup_entries)
-		retval += report(options, &item->object, FSCK_MSG_DUPLICATE_ENTRIES, "contains duplicate file entries");
+		retval += report(options, oid, OBJ_TREE, FSCK_MSG_DUPLICATE_ENTRIES, "contains duplicate file entries");
 	if (not_properly_sorted)
-		retval += report(options, &item->object, FSCK_MSG_TREE_NOT_SORTED, "not properly sorted");
+		retval += report(options, oid, OBJ_TREE, FSCK_MSG_TREE_NOT_SORTED, "not properly sorted");
 	return retval;
 }
 
 static int verify_headers(const void *data, unsigned long size,
-			  struct object *obj, struct fsck_options *options)
+			  const struct object_id *oid, enum object_type type,
+			  struct fsck_options *options)
 {
 	const char *buffer = (const char *)data;
 	unsigned long i;
@@ -669,7 +713,7 @@
 	for (i = 0; i < size; i++) {
 		switch (buffer[i]) {
 		case '\0':
-			return report(options, obj,
+			return report(options, oid, type,
 				FSCK_MSG_NUL_IN_HEADER,
 				"unterminated header: NUL at offset %ld", i);
 		case '\n':
@@ -687,11 +731,13 @@
 	if (size && buffer[size - 1] == '\n')
 		return 0;
 
-	return report(options, obj,
+	return report(options, oid, type,
 		FSCK_MSG_UNTERMINATED_HEADER, "unterminated header");
 }
 
-static int fsck_ident(const char **ident, struct object *obj, struct fsck_options *options)
+static int fsck_ident(const char **ident,
+		      const struct object_id *oid, enum object_type type,
+		      struct fsck_options *options)
 {
 	const char *p = *ident;
 	char *end;
@@ -701,28 +747,28 @@
 		(*ident)++;
 
 	if (*p == '<')
-		return report(options, obj, FSCK_MSG_MISSING_NAME_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
+		return report(options, oid, type, FSCK_MSG_MISSING_NAME_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
 	p += strcspn(p, "<>\n");
 	if (*p == '>')
-		return report(options, obj, FSCK_MSG_BAD_NAME, "invalid author/committer line - bad name");
+		return report(options, oid, type, FSCK_MSG_BAD_NAME, "invalid author/committer line - bad name");
 	if (*p != '<')
-		return report(options, obj, FSCK_MSG_MISSING_EMAIL, "invalid author/committer line - missing email");
+		return report(options, oid, type, FSCK_MSG_MISSING_EMAIL, "invalid author/committer line - missing email");
 	if (p[-1] != ' ')
-		return report(options, obj, FSCK_MSG_MISSING_SPACE_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
+		return report(options, oid, type, FSCK_MSG_MISSING_SPACE_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
 	p++;
 	p += strcspn(p, "<>\n");
 	if (*p != '>')
-		return report(options, obj, FSCK_MSG_BAD_EMAIL, "invalid author/committer line - bad email");
+		return report(options, oid, type, FSCK_MSG_BAD_EMAIL, "invalid author/committer line - bad email");
 	p++;
 	if (*p != ' ')
-		return report(options, obj, FSCK_MSG_MISSING_SPACE_BEFORE_DATE, "invalid author/committer line - missing space before date");
+		return report(options, oid, type, FSCK_MSG_MISSING_SPACE_BEFORE_DATE, "invalid author/committer line - missing space before date");
 	p++;
 	if (*p == '0' && p[1] != ' ')
-		return report(options, obj, FSCK_MSG_ZERO_PADDED_DATE, "invalid author/committer line - zero-padded date");
+		return report(options, oid, type, FSCK_MSG_ZERO_PADDED_DATE, "invalid author/committer line - zero-padded date");
 	if (date_overflows(parse_timestamp(p, &end, 10)))
-		return report(options, obj, FSCK_MSG_BAD_DATE_OVERFLOW, "invalid author/committer line - date causes integer overflow");
+		return report(options, oid, type, FSCK_MSG_BAD_DATE_OVERFLOW, "invalid author/committer line - date causes integer overflow");
 	if ((end == p || *end != ' '))
-		return report(options, obj, FSCK_MSG_BAD_DATE, "invalid author/committer line - bad date");
+		return report(options, oid, type, FSCK_MSG_BAD_DATE, "invalid author/committer line - bad date");
 	p = end + 1;
 	if ((*p != '+' && *p != '-') ||
 	    !isdigit(p[1]) ||
@@ -730,83 +776,60 @@
 	    !isdigit(p[3]) ||
 	    !isdigit(p[4]) ||
 	    (p[5] != '\n'))
-		return report(options, obj, FSCK_MSG_BAD_TIMEZONE, "invalid author/committer line - bad time zone");
+		return report(options, oid, type, FSCK_MSG_BAD_TIMEZONE, "invalid author/committer line - bad time zone");
 	p += 6;
 	return 0;
 }
 
-static int fsck_commit_buffer(struct commit *commit, const char *buffer,
-	unsigned long size, struct fsck_options *options)
+static int fsck_commit(const struct object_id *oid,
+		       const char *buffer, unsigned long size,
+		       struct fsck_options *options)
 {
-	struct object_id tree_oid, oid;
-	struct commit_graft *graft;
-	unsigned parent_count, parent_line_count = 0, author_count;
+	struct object_id tree_oid, parent_oid;
+	unsigned author_count;
 	int err;
 	const char *buffer_begin = buffer;
 	const char *p;
 
-	if (verify_headers(buffer, size, &commit->object, options))
+	if (verify_headers(buffer, size, oid, OBJ_COMMIT, options))
 		return -1;
 
 	if (!skip_prefix(buffer, "tree ", &buffer))
-		return report(options, &commit->object, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line");
+		return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line");
 	if (parse_oid_hex(buffer, &tree_oid, &p) || *p != '\n') {
-		err = report(options, &commit->object, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1");
+		err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1");
 		if (err)
 			return err;
 	}
 	buffer = p + 1;
 	while (skip_prefix(buffer, "parent ", &buffer)) {
-		if (parse_oid_hex(buffer, &oid, &p) || *p != '\n') {
-			err = report(options, &commit->object, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1");
+		if (parse_oid_hex(buffer, &parent_oid, &p) || *p != '\n') {
+			err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1");
 			if (err)
 				return err;
 		}
 		buffer = p + 1;
-		parent_line_count++;
-	}
-	graft = lookup_commit_graft(the_repository, &commit->object.oid);
-	parent_count = commit_list_count(commit->parents);
-	if (graft) {
-		if (graft->nr_parent == -1 && !parent_count)
-			; /* shallow commit */
-		else if (graft->nr_parent != parent_count) {
-			err = report(options, &commit->object, FSCK_MSG_MISSING_GRAFT, "graft objects missing");
-			if (err)
-				return err;
-		}
-	} else {
-		if (parent_count != parent_line_count) {
-			err = report(options, &commit->object, FSCK_MSG_MISSING_PARENT, "parent objects missing");
-			if (err)
-				return err;
-		}
 	}
 	author_count = 0;
 	while (skip_prefix(buffer, "author ", &buffer)) {
 		author_count++;
-		err = fsck_ident(&buffer, &commit->object, options);
+		err = fsck_ident(&buffer, oid, OBJ_COMMIT, options);
 		if (err)
 			return err;
 	}
 	if (author_count < 1)
-		err = report(options, &commit->object, FSCK_MSG_MISSING_AUTHOR, "invalid format - expected 'author' line");
+		err = report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_AUTHOR, "invalid format - expected 'author' line");
 	else if (author_count > 1)
-		err = report(options, &commit->object, FSCK_MSG_MULTIPLE_AUTHORS, "invalid format - multiple 'author' lines");
+		err = report(options, oid, OBJ_COMMIT, FSCK_MSG_MULTIPLE_AUTHORS, "invalid format - multiple 'author' lines");
 	if (err)
 		return err;
 	if (!skip_prefix(buffer, "committer ", &buffer))
-		return report(options, &commit->object, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line");
-	err = fsck_ident(&buffer, &commit->object, options);
+		return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line");
+	err = fsck_ident(&buffer, oid, OBJ_COMMIT, options);
 	if (err)
 		return err;
-	if (!get_commit_tree(commit)) {
-		err = report(options, &commit->object, FSCK_MSG_BAD_TREE, "could not load commit's tree %s", oid_to_hex(&tree_oid));
-		if (err)
-			return err;
-	}
 	if (memchr(buffer_begin, '\0', size)) {
-		err = report(options, &commit->object, FSCK_MSG_NUL_IN_COMMIT,
+		err = report(options, oid, OBJ_COMMIT, FSCK_MSG_NUL_IN_COMMIT,
 			     "NUL byte in the commit object body");
 		if (err)
 			return err;
@@ -814,91 +837,60 @@
 	return 0;
 }
 
-static int fsck_commit(struct commit *commit, const char *data,
-	unsigned long size, struct fsck_options *options)
+static int fsck_tag(const struct object_id *oid, const char *buffer,
+		    unsigned long size, struct fsck_options *options)
 {
-	const char *buffer = data ?  data : get_commit_buffer(commit, &size);
-	int ret = fsck_commit_buffer(commit, buffer, size, options);
-	if (!data)
-		unuse_commit_buffer(commit, buffer);
-	return ret;
-}
-
-static int fsck_tag_buffer(struct tag *tag, const char *data,
-	unsigned long size, struct fsck_options *options)
-{
-	struct object_id oid;
+	struct object_id tagged_oid;
 	int ret = 0;
-	const char *buffer;
-	char *to_free = NULL, *eol;
+	char *eol;
 	struct strbuf sb = STRBUF_INIT;
 	const char *p;
 
-	if (data)
-		buffer = data;
-	else {
-		enum object_type type;
-
-		buffer = to_free =
-			read_object_file(&tag->object.oid, &type, &size);
-		if (!buffer)
-			return report(options, &tag->object,
-				FSCK_MSG_MISSING_TAG_OBJECT,
-				"cannot read tag object");
-
-		if (type != OBJ_TAG) {
-			ret = report(options, &tag->object,
-				FSCK_MSG_TAG_OBJECT_NOT_TAG,
-				"expected tag got %s",
-			    type_name(type));
-			goto done;
-		}
-	}
-
-	ret = verify_headers(buffer, size, &tag->object, options);
+	ret = verify_headers(buffer, size, oid, OBJ_TAG, options);
 	if (ret)
 		goto done;
 
 	if (!skip_prefix(buffer, "object ", &buffer)) {
-		ret = report(options, &tag->object, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line");
+		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line");
 		goto done;
 	}
-	if (parse_oid_hex(buffer, &oid, &p) || *p != '\n') {
-		ret = report(options, &tag->object, FSCK_MSG_BAD_OBJECT_SHA1, "invalid 'object' line format - bad sha1");
+	if (parse_oid_hex(buffer, &tagged_oid, &p) || *p != '\n') {
+		ret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_OBJECT_SHA1, "invalid 'object' line format - bad sha1");
 		if (ret)
 			goto done;
 	}
 	buffer = p + 1;
 
 	if (!skip_prefix(buffer, "type ", &buffer)) {
-		ret = report(options, &tag->object, FSCK_MSG_MISSING_TYPE_ENTRY, "invalid format - expected 'type' line");
+		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE_ENTRY, "invalid format - expected 'type' line");
 		goto done;
 	}
 	eol = strchr(buffer, '\n');
 	if (!eol) {
-		ret = report(options, &tag->object, FSCK_MSG_MISSING_TYPE, "invalid format - unexpected end after 'type' line");
+		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE, "invalid format - unexpected end after 'type' line");
 		goto done;
 	}
 	if (type_from_string_gently(buffer, eol - buffer, 1) < 0)
-		ret = report(options, &tag->object, FSCK_MSG_BAD_TYPE, "invalid 'type' value");
+		ret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_TYPE, "invalid 'type' value");
 	if (ret)
 		goto done;
 	buffer = eol + 1;
 
 	if (!skip_prefix(buffer, "tag ", &buffer)) {
-		ret = report(options, &tag->object, FSCK_MSG_MISSING_TAG_ENTRY, "invalid format - expected 'tag' line");
+		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAG_ENTRY, "invalid format - expected 'tag' line");
 		goto done;
 	}
 	eol = strchr(buffer, '\n');
 	if (!eol) {
-		ret = report(options, &tag->object, FSCK_MSG_MISSING_TAG, "invalid format - unexpected end after 'type' line");
+		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAG, "invalid format - unexpected end after 'type' line");
 		goto done;
 	}
 	strbuf_addf(&sb, "refs/tags/%.*s", (int)(eol - buffer), buffer);
 	if (check_refname_format(sb.buf, 0)) {
-		ret = report(options, &tag->object, FSCK_MSG_BAD_TAG_NAME,
-			   "invalid 'tag' name: %.*s",
-			   (int)(eol - buffer), buffer);
+		ret = report(options, oid, OBJ_TAG,
+			     FSCK_MSG_BAD_TAG_NAME,
+			     "invalid 'tag' name: %.*s",
+			     (int)(eol - buffer), buffer);
 		if (ret)
 			goto done;
 	}
@@ -906,32 +898,20 @@
 
 	if (!skip_prefix(buffer, "tagger ", &buffer)) {
 		/* early tags do not contain 'tagger' lines; warn only */
-		ret = report(options, &tag->object, FSCK_MSG_MISSING_TAGGER_ENTRY, "invalid format - expected 'tagger' line");
+		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAGGER_ENTRY, "invalid format - expected 'tagger' line");
 		if (ret)
 			goto done;
 	}
 	else
-		ret = fsck_ident(&buffer, &tag->object, options);
+		ret = fsck_ident(&buffer, oid, OBJ_TAG, options);
 
 done:
 	strbuf_release(&sb);
-	free(to_free);
 	return ret;
 }
 
-static int fsck_tag(struct tag *tag, const char *data,
-	unsigned long size, struct fsck_options *options)
-{
-	struct object *tagged = tag->tagged;
-
-	if (!tagged)
-		return report(options, &tag->object, FSCK_MSG_BAD_TAG_OBJECT, "could not load tagged object");
-
-	return fsck_tag_buffer(tag, data, size, options);
-}
-
 struct fsck_gitmodules_data {
-	struct object *obj;
+	const struct object_id *oid;
 	struct fsck_options *options;
 	int ret;
 };
@@ -949,38 +929,47 @@
 
 	name = xmemdupz(subsection, subsection_len);
 	if (check_submodule_name(name) < 0)
-		data->ret |= report(data->options, data->obj,
+		data->ret |= report(data->options,
+				    data->oid, OBJ_BLOB,
 				    FSCK_MSG_GITMODULES_NAME,
 				    "disallowed submodule name: %s",
 				    name);
 	if (!strcmp(key, "url") && value &&
 	    looks_like_command_line_option(value))
-		data->ret |= report(data->options, data->obj,
+		data->ret |= report(data->options,
+				    data->oid, OBJ_BLOB,
 				    FSCK_MSG_GITMODULES_URL,
 				    "disallowed submodule url: %s",
 				    value);
 	if (!strcmp(key, "path") && value &&
 	    looks_like_command_line_option(value))
-		data->ret |= report(data->options, data->obj,
+		data->ret |= report(data->options,
+				    data->oid, OBJ_BLOB,
 				    FSCK_MSG_GITMODULES_PATH,
 				    "disallowed submodule path: %s",
 				    value);
+	if (!strcmp(key, "update") && value &&
+	    parse_submodule_update_type(value) == SM_UPDATE_COMMAND)
+		data->ret |= report(data->options, data->oid, OBJ_BLOB,
+				    FSCK_MSG_GITMODULES_UPDATE,
+				    "disallowed submodule update setting: %s",
+				    value);
 	free(name);
 
 	return 0;
 }
 
-static int fsck_blob(struct blob *blob, const char *buf,
+static int fsck_blob(const struct object_id *oid, const char *buf,
 		     unsigned long size, struct fsck_options *options)
 {
 	struct fsck_gitmodules_data data;
 	struct config_options config_opts = { 0 };
 
-	if (!oidset_contains(&gitmodules_found, &blob->object.oid))
+	if (!oidset_contains(&gitmodules_found, oid))
 		return 0;
-	oidset_insert(&gitmodules_done, &blob->object.oid);
+	oidset_insert(&gitmodules_done, oid);
 
-	if (object_on_skiplist(options, &blob->object))
+	if (object_on_skiplist(options, oid))
 		return 0;
 
 	if (!buf) {
@@ -989,18 +978,18 @@
 		 * blob too gigantic to load into memory. Let's just consider
 		 * that an error.
 		 */
-		return report(options, &blob->object,
+		return report(options, oid, OBJ_BLOB,
 			      FSCK_MSG_GITMODULES_LARGE,
 			      ".gitmodules too large to parse");
 	}
 
-	data.obj = &blob->object;
+	data.oid = oid;
 	data.options = options;
 	data.ret = 0;
 	config_opts.error_action = CONFIG_ERROR_SILENT;
 	if (git_config_from_mem(fsck_gitmodules_fn, CONFIG_ORIGIN_BLOB,
 				".gitmodules", buf, size, &data, &config_opts))
-		data.ret |= report(options, &blob->object,
+		data.ret |= report(options, oid, OBJ_BLOB,
 				   FSCK_MSG_GITMODULES_PARSE,
 				   "could not parse gitmodules blob");
 
@@ -1011,31 +1000,33 @@
 	struct fsck_options *options)
 {
 	if (!obj)
-		return report(options, obj, FSCK_MSG_BAD_OBJECT_SHA1, "no valid object to fsck");
+		return report(options, NULL, OBJ_NONE, FSCK_MSG_BAD_OBJECT_SHA1, "no valid object to fsck");
 
 	if (obj->type == OBJ_BLOB)
-		return fsck_blob((struct blob *)obj, data, size, options);
+		return fsck_blob(&obj->oid, data, size, options);
 	if (obj->type == OBJ_TREE)
-		return fsck_tree((struct tree *) obj, options);
+		return fsck_tree(&obj->oid, data, size, options);
 	if (obj->type == OBJ_COMMIT)
-		return fsck_commit((struct commit *) obj, (const char *) data,
-			size, options);
+		return fsck_commit(&obj->oid, data, size, options);
 	if (obj->type == OBJ_TAG)
-		return fsck_tag((struct tag *) obj, (const char *) data,
-			size, options);
+		return fsck_tag(&obj->oid, data, size, options);
 
-	return report(options, obj, FSCK_MSG_UNKNOWN_TYPE, "unknown type '%d' (internal fsck error)",
-			  obj->type);
+	return report(options, &obj->oid, obj->type,
+		      FSCK_MSG_UNKNOWN_TYPE,
+		      "unknown type '%d' (internal fsck error)",
+		      obj->type);
 }
 
 int fsck_error_function(struct fsck_options *o,
-	struct object *obj, int msg_type, const char *message)
+			const struct object_id *oid,
+			enum object_type object_type,
+			int msg_type, const char *message)
 {
 	if (msg_type == FSCK_WARN) {
-		warning("object %s: %s", describe_object(o, obj), message);
+		warning("object %s: %s", fsck_describe_object(o, oid), message);
 		return 0;
 	}
-	error("object %s: %s", describe_object(o, obj), message);
+	error("object %s: %s", fsck_describe_object(o, oid), message);
 	return 1;
 }
 
@@ -1047,7 +1038,6 @@
 
 	oidset_iter_init(&gitmodules_found, &iter);
 	while ((oid = oidset_iter_next(&iter))) {
-		struct blob *blob;
 		enum object_type type;
 		unsigned long size;
 		char *buf;
@@ -1055,29 +1045,22 @@
 		if (oidset_contains(&gitmodules_done, oid))
 			continue;
 
-		blob = lookup_blob(the_repository, oid);
-		if (!blob) {
-			struct object *obj = lookup_unknown_object(oid);
-			ret |= report(options, obj,
-				      FSCK_MSG_GITMODULES_BLOB,
-				      "non-blob found at .gitmodules");
-			continue;
-		}
-
 		buf = read_object_file(oid, &type, &size);
 		if (!buf) {
-			if (is_promisor_object(&blob->object.oid))
+			if (is_promisor_object(oid))
 				continue;
-			ret |= report(options, &blob->object,
+			ret |= report(options,
+				      oid, OBJ_BLOB,
 				      FSCK_MSG_GITMODULES_MISSING,
 				      "unable to read .gitmodules blob");
 			continue;
 		}
 
 		if (type == OBJ_BLOB)
-			ret |= fsck_blob(blob, buf, size, options);
+			ret |= fsck_blob(oid, buf, size, options);
 		else
-			ret |= report(options, &blob->object,
+			ret |= report(options,
+				      oid, type,
 				      FSCK_MSG_GITMODULES_BLOB,
 				      "non-blob found at .gitmodules");
 		free(buf);
diff --git a/fsck.h b/fsck.h
index b95595a..69cf715 100644
--- a/fsck.h
+++ b/fsck.h
@@ -27,10 +27,12 @@
 
 /* callback for fsck_object, type is FSCK_ERROR or FSCK_WARN */
 typedef int (*fsck_error)(struct fsck_options *o,
-	struct object *obj, int type, const char *message);
+			  const struct object_id *oid, enum object_type object_type,
+			  int msg_type, const char *message);
 
 int fsck_error_function(struct fsck_options *o,
-	struct object *obj, int type, const char *message);
+			const struct object_id *oid, enum object_type object_type,
+			int msg_type, const char *message);
 
 struct fsck_options {
 	fsck_walk_func walk;
@@ -38,7 +40,7 @@
 	unsigned strict:1;
 	int *msg_type;
 	struct oidset skiplist;
-	struct decoration *object_names;
+	kh_oid_map_t *object_names;
 };
 
 #define FSCK_OPTIONS_DEFAULT { NULL, fsck_error_function, 0, NULL, OIDSET_INIT }
@@ -52,7 +54,11 @@
  *    0		everything OK
  */
 int fsck_walk(struct object *obj, void *data, struct fsck_options *options);
-/* If NULL is passed for data, we assume the object is local and read it. */
+
+/*
+ * Blob objects my pass a NULL data pointer, which indicates they are too large
+ * to fit in memory. All other types must pass a real buffer.
+ */
 int fsck_object(struct object *obj, void *data, unsigned long size,
 	struct fsck_options *options);
 
@@ -63,4 +69,29 @@
  */
 int fsck_finish(struct fsck_options *options);
 
+/*
+ * Subsystem for storing human-readable names for each object.
+ *
+ * If fsck_enable_object_names() has not been called, all other functions are
+ * noops.
+ *
+ * Use fsck_put_object_name() to seed initial names (e.g. from refnames); the
+ * fsck code will extend that while walking trees, etc.
+ *
+ * Use fsck_get_object_name() to get a single name (or NULL if none). Or the
+ * more convenient describe_object(), which always produces an output string
+ * with the oid combined with the name (if any). Note that the return value
+ * points to a rotating array of static buffers, and may be invalidated by a
+ * subsequent call.
+ */
+void fsck_enable_object_names(struct fsck_options *options);
+const char *fsck_get_object_name(struct fsck_options *options,
+				 const struct object_id *oid);
+__attribute__((format (printf,3,4)))
+void fsck_put_object_name(struct fsck_options *options,
+			  const struct object_id *oid,
+			  const char *fmt, ...);
+const char *fsck_describe_object(struct fsck_options *options,
+				 const struct object_id *oid);
+
 #endif
diff --git a/fsmonitor.c b/fsmonitor.c
index 1f4aa1b..868cca0 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -55,7 +55,8 @@
 	}
 	istate->fsmonitor_dirty = fsmonitor_dirty;
 
-	if (istate->fsmonitor_dirty->bit_size > istate->cache_nr)
+	if (!istate->split_index &&
+	    istate->fsmonitor_dirty->bit_size > istate->cache_nr)
 		BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)",
 		    (uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr);
 
@@ -83,7 +84,8 @@
 	uint32_t ewah_size = 0;
 	int fixup = 0;
 
-	if (istate->fsmonitor_dirty->bit_size > istate->cache_nr)
+	if (!istate->split_index &&
+	    istate->fsmonitor_dirty->bit_size > istate->cache_nr)
 		BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)",
 		    (uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr);
 
@@ -189,13 +191,26 @@
 		}
 		if (bol < query_result.len)
 			fsmonitor_refresh_callback(istate, buf + bol);
+
+		/* Now mark the untracked cache for fsmonitor usage */
+		if (istate->untracked)
+			istate->untracked->use_fsmonitor = 1;
 	} else {
+
+		/* We only want to run the post index changed hook if we've actually changed entries, so keep track
+		 * if we actually changed entries or not */
+		int is_cache_changed = 0;
 		/* Mark all entries invalid */
-		for (i = 0; i < istate->cache_nr; i++)
-			istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
+		for (i = 0; i < istate->cache_nr; i++) {
+			if (istate->cache[i]->ce_flags & CE_FSMONITOR_VALID) {
+				is_cache_changed = 1;
+				istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
+			}
+		}
 
 		/* If we're going to check every file, ensure we save the results */
-		istate->cache_changed |= FSMONITOR_CHANGED;
+		if (is_cache_changed)
+			istate->cache_changed |= FSMONITOR_CHANGED;
 
 		if (istate->untracked)
 			istate->untracked->use_fsmonitor = 0;
@@ -257,9 +272,7 @@
 				    (uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr);
 			ewah_each_bit(istate->fsmonitor_dirty, fsmonitor_ewah_callback, istate);
 
-			/* Now mark the untracked cache for fsmonitor usage */
-			if (istate->untracked)
-				istate->untracked->use_fsmonitor = 1;
+			refresh_fsmonitor(istate);
 		}
 
 		ewah_free(istate->fsmonitor_dirty);
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index 52659bb..10fd30a 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -177,7 +177,9 @@
 	} else {
 		my $fh = undef;
 		open($fh, '-|', @_) or die;
-		return <$fh>;
+		my @out = <$fh>;
+		close $fh || die "Cannot close @_ ($!)";
+		return @out;
 	}
 }
 
@@ -224,7 +226,7 @@
 	sub get_empty_tree {
 		return $empty_tree if defined $empty_tree;
 
-		$empty_tree = run_cmd_pipe(qw(git hash-object -t tree /dev/null));
+		($empty_tree) = run_cmd_pipe(qw(git hash-object -t tree /dev/null));
 		chomp $empty_tree;
 		return $empty_tree;
 	}
@@ -1127,7 +1129,7 @@
 EOF2
 	close $fh;
 
-	chomp(my $editor = run_cmd_pipe(qw(git var GIT_EDITOR)));
+	chomp(my ($editor) = run_cmd_pipe(qw(git var GIT_EDITOR)));
 	system('sh', '-c', $editor.' "$@"', $editor, $hunkfile);
 
 	if ($? != 0) {
diff --git a/git-compat-util.h b/git-compat-util.h
index 607dca7..aed0b5d 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -320,26 +320,6 @@
 #define PATH_MAX 4096
 #endif
 
-#ifndef PRIuMAX
-#define PRIuMAX "llu"
-#endif
-
-#ifndef SCNuMAX
-#define SCNuMAX PRIuMAX
-#endif
-
-#ifndef PRIu32
-#define PRIu32 "u"
-#endif
-
-#ifndef PRIx32
-#define PRIx32 "x"
-#endif
-
-#ifndef PRIo32
-#define PRIo32 "o"
-#endif
-
 typedef uintmax_t timestamp_t;
 #define PRItime PRIuMAX
 #define parse_timestamp strtoumax
@@ -397,6 +377,10 @@
 #define offset_1st_component git_offset_1st_component
 #endif
 
+#ifndef is_valid_path
+#define is_valid_path(path) 1
+#endif
+
 #ifndef find_last_dir_sep
 static inline char *git_find_last_dir_sep(const char *path)
 {
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index b31613c..1057f38 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -600,7 +600,7 @@
 sub pdate($) {
 	my ($d) = @_;
 	m#(\d{2,4})/(\d\d)/(\d\d)\s(\d\d):(\d\d)(?::(\d\d))?#
-		or die "Unparseable date: $d\n";
+		or die "Unparsable date: $d\n";
 	my $y=$1;
 	$y+=100 if $y<70;
 	$y+=1900 if $y<1000;
diff --git a/git-p4.py b/git-p4.py
index 60c73b6..40d9e7c 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -167,6 +167,21 @@
         sys.stderr.write(msg + "\n")
         sys.exit(1)
 
+def prompt(prompt_text):
+    """ Prompt the user to choose one of the choices
+
+    Choices are identified in the prompt_text by square brackets around
+    a single letter option.
+    """
+    choices = set(m.group(1) for m in re.finditer(r"\[(.)\]", prompt_text))
+    while True:
+        response = raw_input(prompt_text).strip().lower()
+        if not response:
+            continue
+        response = response[0]
+        if response in choices:
+            return response
+
 def write_pipe(c, stdin):
     if verbose:
         sys.stderr.write('Writing pipe: %s\n' % str(c))
@@ -1257,9 +1272,15 @@
             pointerFile = re.sub(r'Git LFS pointer for.*\n\n', '', pointerFile)
 
         oid = re.search(r'^oid \w+:(\w+)', pointerFile, re.MULTILINE).group(1)
+        # if someone use external lfs.storage ( not in local repo git )
+        lfs_path = gitConfig('lfs.storage')
+        if not lfs_path:
+            lfs_path = 'lfs'
+        if not os.path.isabs(lfs_path):
+            lfs_path = os.path.join(os.getcwd(), '.git', lfs_path)
         localLargeFile = os.path.join(
-            os.getcwd(),
-            '.git', 'lfs', 'objects', oid[:2], oid[2:4],
+            lfs_path,
+            'objects', oid[:2], oid[2:4],
             oid,
         )
         # LFS Spec states that pointer files should not have the executable bit set.
@@ -1778,12 +1799,11 @@
         if os.stat(template_file).st_mtime > mtime:
             return True
 
-        while True:
-            response = raw_input("Submit template unchanged. Submit anyway? [y]es, [n]o (skip this patch) ")
-            if response == 'y':
-                return True
-            if response == 'n':
-                return False
+        response = prompt("Submit template unchanged. Submit anyway? [y]es, [n]o (skip this patch) ")
+        if response == 'y':
+            return True
+        if response == 'n':
+            return False
 
     def get_diff_description(self, editedFiles, filesToAdd, symlinks):
         # diff
@@ -2345,31 +2365,22 @@
                           " --prepare-p4-only")
                     break
                 if i < last:
-                    quit = False
-                    while True:
-                        # prompt for what to do, or use the option/variable
-                        if self.conflict_behavior == "ask":
-                            print("What do you want to do?")
-                            response = raw_input("[s]kip this commit but apply"
-                                                 " the rest, or [q]uit? ")
-                            if not response:
-                                continue
-                        elif self.conflict_behavior == "skip":
-                            response = "s"
-                        elif self.conflict_behavior == "quit":
-                            response = "q"
-                        else:
-                            die("Unknown conflict_behavior '%s'" %
-                                self.conflict_behavior)
+                    # prompt for what to do, or use the option/variable
+                    if self.conflict_behavior == "ask":
+                        print("What do you want to do?")
+                        response = prompt("[s]kip this commit but apply the rest, or [q]uit? ")
+                    elif self.conflict_behavior == "skip":
+                        response = "s"
+                    elif self.conflict_behavior == "quit":
+                        response = "q"
+                    else:
+                        die("Unknown conflict_behavior '%s'" %
+                            self.conflict_behavior)
 
-                        if response[0] == "s":
-                            print("Skipping this commit, but applying the rest")
-                            break
-                        if response[0] == "q":
-                            print("Quitting")
-                            quit = True
-                            break
-                    if quit:
+                    if response == "s":
+                        print("Skipping this commit, but applying the rest")
+                    if response == "q":
+                        print("Quitting")
                         break
 
         chdir(self.oldWorkingDirectory)
@@ -4140,7 +4151,12 @@
                                    description = cmd.description,
                                    formatter = HelpFormatter())
 
-    (cmd, args) = parser.parse_args(sys.argv[2:], cmd);
+    try:
+        (cmd, args) = parser.parse_args(sys.argv[2:], cmd);
+    except:
+        parser.print_help()
+        raise
+
     global verbose
     verbose = cmd.verbose
     if cmd.needsGit:
diff --git a/git-send-email.perl b/git-send-email.perl
index 5f92c89..dc95656 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1228,7 +1228,7 @@
 # domain name that corresponds the IP address in the HELO/EHLO
 # handshake. This is used to verify the connection and prevent
 # spammers from trying to hide their identity. If the DNS and IP don't
-# match, the receiveing MTA may deny the connection.
+# match, the receiving MTA may deny the connection.
 #
 # Here is a deny example of Net::SMTP with the default "localhost.localdomain"
 #
diff --git a/git-submodule.sh b/git-submodule.sh
index c7f58c5..aaa1809 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -12,6 +12,7 @@
    or: $dashless [--quiet] deinit [-f|--force] (--all| [--] <path>...)
    or: $dashless [--quiet] update [--init] [--remote] [-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-shallow] [--reference <repository>] [--recursive] [--] [<path>...]
    or: $dashless [--quiet] set-branch (--default|--branch <branch>) [--] <path>
+   or: $dashless [--quiet] set-url [--] <path> <newurl>
    or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
    or: $dashless [--quiet] foreach [--recursive] <command>
    or: $dashless [--quiet] sync [--recursive] [--] [<path>...]
@@ -36,6 +37,7 @@
 cached=
 recursive=
 init=
+require_init=
 files=
 remote=
 nofetch=
@@ -466,6 +468,10 @@
 		-i|--init)
 			init=1
 			;;
+		--require-init)
+			init=1
+			require_init=1
+			;;
 		--remote)
 			remote=1
 			;;
@@ -548,6 +554,7 @@
 		${reference:+"$reference"} \
 		${dissociate:+"--dissociate"} \
 		${depth:+--depth "$depth"} \
+		${require_init:+--require-init} \
 		$recommend_shallow \
 		$jobs \
 		-- \
@@ -761,6 +768,55 @@
 }
 
 #
+# Configures a submodule's remote url
+#
+# $@ = requested path, requested url
+#
+cmd_set_url() {
+	while test $# -ne 0
+	do
+		case "$1" in
+		-q|--quiet)
+			GIT_QUIET=1
+			;;
+		--)
+			shift
+			break
+			;;
+		-*)
+			usage
+			;;
+		*)
+			break
+			;;
+		esac
+		shift
+	done
+
+	if test $# -ne 2
+	then
+		usage
+	fi
+
+	# we can't use `git submodule--helper name` here because internally, it
+	# hashes the path so a trailing slash could lead to an unintentional no match
+	name="$(git submodule--helper list "$1" | cut -f2)"
+	if test -z "$name"
+	then
+		exit 1
+	fi
+
+	url="$2"
+	if test -z "$url"
+	then
+		exit 1
+	fi
+
+	git submodule--helper config submodule."$name".url "$url"
+	git submodule--helper sync ${GIT_QUIET:+--quiet} "$name"
+}
+
+#
 # Show commit summary for submodules in index or working tree
 #
 # If '--cached' is given, show summary between index and given commit,
@@ -1059,7 +1115,7 @@
 while test $# != 0 && test -z "$command"
 do
 	case "$1" in
-	add | foreach | init | deinit | update | set-branch | status | summary | sync | absorbgitdirs)
+	add | foreach | init | deinit | update | set-branch | set-url | status | summary | sync | absorbgitdirs)
 		command=$1
 		;;
 	-q|--quiet)
diff --git a/git-svn.perl b/git-svn.perl
index 050f2a3..4aa208f 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -110,7 +110,7 @@
 	$_template, $_shared,
 	$_version, $_fetch_all, $_no_rebase, $_fetch_parent,
 	$_before, $_after,
-	$_merge, $_strategy, $_preserve_merges, $_dry_run, $_parents, $_local,
+	$_merge, $_strategy, $_rebase_merges, $_dry_run, $_parents, $_local,
 	$_prefix, $_no_checkout, $_url, $_verbose,
 	$_commit_url, $_tag, $_merge_info, $_interactive, $_set_svn_props);
 
@@ -270,7 +270,8 @@
 			  'local|l' => \$_local,
 			  'fetch-all|all' => \$_fetch_all,
 			  'dry-run|n' => \$_dry_run,
-			  'preserve-merges|p' => \$_preserve_merges,
+			  'rebase-merges|p' => \$_rebase_merges,
+			  'preserve-merges|p' => \$_rebase_merges,
 			  %fc_opts } ],
 	'commit-diff' => [ \&cmd_commit_diff,
 	                   'Commit a diff between two trees',
@@ -1054,7 +1055,7 @@
 					  'If you are attempting to commit ',
 					  "merges, try running:\n\t",
 					  'git rebase --interactive',
-					  '--preserve-merges ',
+					  '--rebase-merges ',
 					  $gs->refname,
 					  "\nBefore dcommitting";
 				}
@@ -1717,7 +1718,7 @@
 	push @cmd, '-v' if $_verbose;
 	push @cmd, qw/--merge/ if $_merge;
 	push @cmd, "--strategy=$_strategy" if $_strategy;
-	push @cmd, "--preserve-merges" if $_preserve_merges;
+	push @cmd, "--rebase-merges" if $_rebase_merges;
 	@cmd;
 }
 
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 7fef19f..0f857d7 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1657,15 +1657,15 @@
 	my $cntrl = shift;
 	my %opts = @_;
 	my %es = ( # character escape codes, aka escape sequences
-		"\t" => '\t',   # tab            (HT)
-		"\n" => '\n',   # line feed      (LF)
-		"\r" => '\r',   # carrige return (CR)
-		"\f" => '\f',   # form feed      (FF)
-		"\b" => '\b',   # backspace      (BS)
-		"\a" => '\a',   # alarm (bell)   (BEL)
-		"\e" => '\e',   # escape         (ESC)
-		"\013" => '\v', # vertical tab   (VT)
-		"\000" => '\0', # nul character  (NUL)
+		"\t" => '\t',   # tab             (HT)
+		"\n" => '\n',   # line feed       (LF)
+		"\r" => '\r',   # carriage return (CR)
+		"\f" => '\f',   # form feed       (FF)
+		"\b" => '\b',   # backspace       (BS)
+		"\a" => '\a',   # alarm (bell)    (BEL)
+		"\e" => '\e',   # escape          (ESC)
+		"\013" => '\v', # vertical tab    (VT)
+		"\000" => '\0', # nul character   (NUL)
 	);
 	my $chr = ( (exists $es{$cntrl})
 		    ? $es{$cntrl}
@@ -4048,7 +4048,7 @@
 
 			$href_params{'extra_options'} = undef;
 			$href_params{'action'} = $type;
-			$link_attr{'-href'} = href(%href_params);
+			$link_attr{'-href'} = esc_attr(href(%href_params));
 			print "<link ".
 			      "rel=\"$link_attr{'-rel'}\" ".
 			      "title=\"$link_attr{'-title'}\" ".
@@ -4057,7 +4057,7 @@
 			      "/>\n";
 
 			$href_params{'extra_options'} = '--no-merges';
-			$link_attr{'-href'} = href(%href_params);
+			$link_attr{'-href'} = esc_attr(href(%href_params));
 			$link_attr{'-title'} .= ' (no merges)';
 			print "<link ".
 			      "rel=\"$link_attr{'-rel'}\" ".
@@ -4070,10 +4070,12 @@
 	} else {
 		printf('<link rel="alternate" title="%s projects list" '.
 		       'href="%s" type="text/plain; charset=utf-8" />'."\n",
-		       esc_attr($site_name), href(project=>undef, action=>"project_index"));
+		       esc_attr($site_name),
+		       esc_attr(href(project=>undef, action=>"project_index")));
 		printf('<link rel="alternate" title="%s projects feeds" '.
 		       'href="%s" type="text/x-opml" />'."\n",
-		       esc_attr($site_name), href(project=>undef, action=>"opml"));
+		       esc_attr($site_name),
+		       esc_attr(href(project=>undef, action=>"opml")));
 	}
 }
 
@@ -4287,8 +4289,8 @@
 	if (defined $action &&
 	    $action eq 'blame_incremental') {
 		print qq!<script type="text/javascript">\n!.
-		      qq!startBlame("!. href(action=>"blame_data", -replay=>1) .qq!",\n!.
-		      qq!           "!. href() .qq!");\n!.
+		      qq!startBlame("!. esc_attr(href(action=>"blame_data", -replay=>1)) .qq!",\n!.
+		      qq!           "!. esc_attr(href()) .qq!");\n!.
 		      qq!</script>\n!;
 	} else {
 		my ($jstimezone, $tz_cookie, $datetime_class) =
@@ -7155,8 +7157,8 @@
 			print qq! alt="!.esc_attr($file_name).qq!" title="!.esc_attr($file_name).qq!"!;
 		}
 		print qq! src="! .
-		      href(action=>"blob_plain", hash=>$hash,
-		           hash_base=>$hash_base, file_name=>$file_name) .
+		      esc_attr(href(action=>"blob_plain", hash=>$hash,
+		           hash_base=>$hash_base, file_name=>$file_name)) .
 		      qq!" />\n!;
 	} else {
 		my $nr;
@@ -8239,6 +8241,7 @@
 	} else {
 		$alt_url = href(-full=>1, action=>"summary");
 	}
+	$alt_url = esc_attr($alt_url);
 	print qq!<?xml version="1.0" encoding="utf-8"?>\n!;
 	if ($format eq 'rss') {
 		print <<XML;
@@ -8276,7 +8279,7 @@
 		      $alt_url . '" />' . "\n" .
 		      '<link rel="self" type="' . $content_type . '" href="' .
 		      $cgi->self_url() . '" />' . "\n" .
-		      "<id>" . href(-full=>1) . "</id>\n" .
+		      "<id>" . esc_url(href(-full=>1)) . "</id>\n" .
 		      # use project owner for feed author
 		      "<author><name>$owner</name></author>\n";
 		if (defined $favicon) {
@@ -8322,7 +8325,7 @@
 			      "<author>" . esc_html($co{'author'}) . "</author>\n" .
 			      "<pubDate>$cd{'rfc2822'}</pubDate>\n" .
 			      "<guid isPermaLink=\"true\">$co_url</guid>\n" .
-			      "<link>$co_url</link>\n" .
+			      "<link>" . esc_html($co_url) . "</link>\n" .
 			      "<description>" . esc_html($co{'title'}) . "</description>\n" .
 			      "<content:encoded>" .
 			      "<![CDATA[\n";
@@ -8344,8 +8347,8 @@
 			}
 			print "</contributor>\n" .
 			      "<published>$cd{'iso-8601'}</published>\n" .
-			      "<link rel=\"alternate\" type=\"text/html\" href=\"$co_url\" />\n" .
-			      "<id>$co_url</id>\n" .
+			      "<link rel=\"alternate\" type=\"text/html\" href=\"" . esc_attr($co_url) . "\" />\n" .
+			      "<id>" . esc_html($co_url) . "</id>\n" .
 			      "<content type=\"xhtml\" xml:base=\"" . esc_url($my_url) . "\">\n" .
 			      "<div xmlns=\"http://www.w3.org/1999/xhtml\">\n";
 		}
@@ -8452,8 +8455,8 @@
 		}
 
 		my $path = esc_html(chop_str($proj{'path'}, 25, 5));
-		my $rss  = href('project' => $proj{'path'}, 'action' => 'rss', -full => 1);
-		my $html = href('project' => $proj{'path'}, 'action' => 'summary', -full => 1);
+		my $rss  = esc_attr(href('project' => $proj{'path'}, 'action' => 'rss', -full => 1));
+		my $html = esc_attr(href('project' => $proj{'path'}, 'action' => 'summary', -full => 1));
 		print "<outline type=\"rss\" text=\"$path\" title=\"$path\" xmlUrl=\"$rss\" htmlUrl=\"$html\"/>\n";
 	}
 	print <<XML;
diff --git a/gpg-interface.c b/gpg-interface.c
index d60115c..5134ce2 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -105,6 +105,16 @@
 	{ 0, "VALIDSIG ", GPG_STATUS_FINGERPRINT },
 };
 
+static void replace_cstring(char **field, const char *line, const char *next)
+{
+	free(*field);
+
+	if (line && next)
+		*field = xmemdupz(line, next - line);
+	else
+		*field = NULL;
+}
+
 static void parse_gpg_output(struct signature_check *sigc)
 {
 	const char *buf = sigc->gpg_status;
@@ -136,33 +146,43 @@
 				/* Do we have key information? */
 				if (sigcheck_gpg_status[i].flags & GPG_STATUS_KEYID) {
 					next = strchrnul(line, ' ');
-					free(sigc->key);
-					sigc->key = xmemdupz(line, next - line);
+					replace_cstring(&sigc->key, line, next);
 					/* Do we have signer information? */
 					if (*next && (sigcheck_gpg_status[i].flags & GPG_STATUS_UID)) {
 						line = next + 1;
 						next = strchrnul(line, '\n');
-						free(sigc->signer);
-						sigc->signer = xmemdupz(line, next - line);
+						replace_cstring(&sigc->signer, line, next);
 					}
 				}
 				/* Do we have fingerprint? */
 				if (sigcheck_gpg_status[i].flags & GPG_STATUS_FINGERPRINT) {
-					next = strchrnul(line, ' ');
-					free(sigc->fingerprint);
-					sigc->fingerprint = xmemdupz(line, next - line);
+					const char *limit;
+					char **field;
 
-					/* Skip interim fields */
+					next = strchrnul(line, ' ');
+					replace_cstring(&sigc->fingerprint, line, next);
+
+					/*
+					 * Skip interim fields.  The search is
+					 * limited to the same line since only
+					 * OpenPGP signatures has a field with
+					 * the primary fingerprint.
+					 */
+					limit = strchrnul(line, '\n');
 					for (j = 9; j > 0; j--) {
-						if (!*next)
+						if (!*next || limit <= next)
 							break;
 						line = next + 1;
 						next = strchrnul(line, ' ');
 					}
 
-					next = strchrnul(line, '\n');
-					free(sigc->primary_key_fingerprint);
-					sigc->primary_key_fingerprint = xmemdupz(line, next - line);
+					field = &sigc->primary_key_fingerprint;
+					if (!j) {
+						next = strchrnul(line, '\n');
+						replace_cstring(field, line, next);
+					} else {
+						replace_cstring(field, NULL, NULL);
+					}
 				}
 
 				break;
@@ -187,6 +207,55 @@
 	FREE_AND_NULL(sigc->key);
 }
 
+static int verify_signed_buffer(const char *payload, size_t payload_size,
+				const char *signature, size_t signature_size,
+				struct strbuf *gpg_output,
+				struct strbuf *gpg_status)
+{
+	struct child_process gpg = CHILD_PROCESS_INIT;
+	struct gpg_format *fmt;
+	struct tempfile *temp;
+	int ret;
+	struct strbuf buf = STRBUF_INIT;
+
+	temp = mks_tempfile_t(".git_vtag_tmpXXXXXX");
+	if (!temp)
+		return error_errno(_("could not create temporary file"));
+	if (write_in_full(temp->fd, signature, signature_size) < 0 ||
+	    close_tempfile_gently(temp) < 0) {
+		error_errno(_("failed writing detached signature to '%s'"),
+			    temp->filename.buf);
+		delete_tempfile(&temp);
+		return -1;
+	}
+
+	fmt = get_format_by_sig(signature);
+	if (!fmt)
+		BUG("bad signature '%s'", signature);
+
+	argv_array_push(&gpg.args, fmt->program);
+	argv_array_pushv(&gpg.args, fmt->verify_args);
+	argv_array_pushl(&gpg.args,
+			 "--status-fd=1",
+			 "--verify", temp->filename.buf, "-",
+			 NULL);
+
+	if (!gpg_status)
+		gpg_status = &buf;
+
+	sigchain_push(SIGPIPE, SIG_IGN);
+	ret = pipe_command(&gpg, payload, payload_size,
+			   gpg_status, 0, gpg_output, 0);
+	sigchain_pop(SIGPIPE);
+
+	delete_tempfile(&temp);
+
+	ret |= !strstr(gpg_status->buf, "\n[GNUPG:] GOODSIG ");
+	strbuf_release(&buf); /* no matter it was used or not */
+
+	return ret;
+}
+
 int check_signature(const char *payload, size_t plen, const char *signature,
 	size_t slen, struct signature_check *sigc)
 {
@@ -331,51 +400,3 @@
 
 	return 0;
 }
-
-int verify_signed_buffer(const char *payload, size_t payload_size,
-			 const char *signature, size_t signature_size,
-			 struct strbuf *gpg_output, struct strbuf *gpg_status)
-{
-	struct child_process gpg = CHILD_PROCESS_INIT;
-	struct gpg_format *fmt;
-	struct tempfile *temp;
-	int ret;
-	struct strbuf buf = STRBUF_INIT;
-
-	temp = mks_tempfile_t(".git_vtag_tmpXXXXXX");
-	if (!temp)
-		return error_errno(_("could not create temporary file"));
-	if (write_in_full(temp->fd, signature, signature_size) < 0 ||
-	    close_tempfile_gently(temp) < 0) {
-		error_errno(_("failed writing detached signature to '%s'"),
-			    temp->filename.buf);
-		delete_tempfile(&temp);
-		return -1;
-	}
-
-	fmt = get_format_by_sig(signature);
-	if (!fmt)
-		BUG("bad signature '%s'", signature);
-
-	argv_array_push(&gpg.args, fmt->program);
-	argv_array_pushv(&gpg.args, fmt->verify_args);
-	argv_array_pushl(&gpg.args,
-			 "--status-fd=1",
-			 "--verify", temp->filename.buf, "-",
-			 NULL);
-
-	if (!gpg_status)
-		gpg_status = &buf;
-
-	sigchain_push(SIGPIPE, SIG_IGN);
-	ret = pipe_command(&gpg, payload, payload_size,
-			   gpg_status, 0, gpg_output, 0);
-	sigchain_pop(SIGPIPE);
-
-	delete_tempfile(&temp);
-
-	ret |= !strstr(gpg_status->buf, "\n[GNUPG:] GOODSIG ");
-	strbuf_release(&buf); /* no matter it was used or not */
-
-	return ret;
-}
diff --git a/gpg-interface.h b/gpg-interface.h
index 3e624ec..93cc3af 100644
--- a/gpg-interface.h
+++ b/gpg-interface.h
@@ -46,15 +46,6 @@
 int sign_buffer(struct strbuf *buffer, struct strbuf *signature,
 		const char *signing_key);
 
-/*
- * Run "gpg" to see if the payload matches the detached signature.
- * gpg_output, when set, receives the diagnostic output from GPG.
- * gpg_status, when set, receives the status output from GPG.
- */
-int verify_signed_buffer(const char *payload, size_t payload_size,
-			 const char *signature, size_t signature_size,
-			 struct strbuf *gpg_output, struct strbuf *gpg_status);
-
 int git_gpg_config(const char *, const char *, void *);
 void set_signing_key(const char *);
 const char *get_signing_key(void);
diff --git a/graph.c b/graph.c
index f531354..66ae18a 100644
--- a/graph.c
+++ b/graph.c
@@ -34,6 +34,7 @@
  * handle directly. It is assumed that this is the same file handle as the
  * file specified by the graph diff options. This is necessary so that
  * graph_show_strbuf can be called even with a NULL graph.
+ * If a NULL graph is supplied, the strbuf is printed as-is.
  */
 static void graph_show_strbuf(struct git_graph *graph,
 			      FILE *file,
@@ -112,14 +113,42 @@
 	return column_colors[color];
 }
 
-static void strbuf_write_column(struct strbuf *sb, const struct column *c,
-				char col_char)
+struct graph_line {
+	struct strbuf *buf;
+	size_t width;
+};
+
+static inline void graph_line_addch(struct graph_line *line, int c)
+{
+	strbuf_addch(line->buf, c);
+	line->width++;
+}
+
+static inline void graph_line_addchars(struct graph_line *line, int c, size_t n)
+{
+	strbuf_addchars(line->buf, c, n);
+	line->width += n;
+}
+
+static inline void graph_line_addstr(struct graph_line *line, const char *s)
+{
+	strbuf_addstr(line->buf, s);
+	line->width += strlen(s);
+}
+
+static inline void graph_line_addcolor(struct graph_line *line, unsigned short color)
+{
+	strbuf_addstr(line->buf, column_get_color_code(color));
+}
+
+static void graph_line_write_column(struct graph_line *line, const struct column *c,
+				    char col_char)
 {
 	if (c->color < column_colors_max)
-		strbuf_addstr(sb, column_get_color_code(c->color));
-	strbuf_addch(sb, col_char);
+		graph_line_addcolor(line, c->color);
+	graph_line_addch(line, col_char);
 	if (c->color < column_colors_max)
-		strbuf_addstr(sb, column_get_color_code(column_colors_max));
+		graph_line_addcolor(line, column_colors_max);
 }
 
 struct git_graph {
@@ -175,9 +204,63 @@
 	 */
 	int prev_commit_index;
 	/*
+	 * Which layout variant to use to display merge commits. If the
+	 * commit's first parent is known to be in a column to the left of the
+	 * merge, then this value is 0 and we use the layout on the left.
+	 * Otherwise, the value is 1 and the layout on the right is used. This
+	 * field tells us how many columns the first parent occupies.
+	 *
+	 * 		0)			1)
+	 *
+	 * 		| | | *-.		| | *---.
+	 * 		| |_|/|\ \		| | |\ \ \
+	 * 		|/| | | | |		| | | | | *
+	 */
+	int merge_layout;
+	/*
+	 * The number of columns added to the graph by the current commit. For
+	 * 2-way and octopus merges, this is usually one less than the
+	 * number of parents:
+	 *
+	 * 		| | |			| |    \
+	 *		| * |			| *---. \
+	 *		| |\ \			| |\ \ \ \
+	 *		| | | |         	| | | | | |
+	 *
+	 *		num_parents: 2		num_parents: 4
+	 *		edges_added: 1		edges_added: 3
+	 *
+	 * For left-skewed merges, the first parent fuses with its neighbor and
+	 * so one less column is added:
+	 *
+	 *		| | |			| |  \
+	 *		| * |			| *-. \
+	 *		|/| |			|/|\ \ \
+	 *		| | |			| | | | |
+	 *
+	 *		num_parents: 2		num_parents: 4
+	 *		edges_added: 0		edges_added: 2
+	 *
+	 * This number determines how edges to the right of the merge are
+	 * displayed in commit and post-merge lines; if no columns have been
+	 * added then a vertical line should be used where a right-tracking
+	 * line would otherwise be used.
+	 *
+	 *		| * \			| * |
+	 *		| |\ \			|/| |
+	 *		| | * \			| * |
+	 */
+	int edges_added;
+	/*
+	 * The number of columns added by the previous commit, which is used to
+	 * smooth edges appearing to the right of a commit in a commit line
+	 * following a post-merge line.
+	 */
+	int prev_edges_added;
+	/*
 	 * The maximum number of columns that can be stored in the columns
 	 * and new_columns arrays.  This is also half the number of entries
-	 * that can be stored in the mapping and new_mapping arrays.
+	 * that can be stored in the mapping and old_mapping arrays.
 	 */
 	int column_capacity;
 	/*
@@ -215,12 +298,12 @@
 	 */
 	int *mapping;
 	/*
-	 * A temporary array for computing the next mapping state
-	 * while we are outputting a mapping line.  This is stored as part
-	 * of the git_graph simply so we don't have to allocate a new
-	 * temporary array each time we have to output a collapsing line.
+	 * A copy of the contents of the mapping array from the last commit,
+	 * which we use to improve the display of columns that are tracking
+	 * from right to left through a commit line.  We also use this to
+	 * avoid allocating a fresh array when we compute the next mapping.
 	 */
-	int *new_mapping;
+	int *old_mapping;
 	/*
 	 * The current default column color being used.  This is
 	 * stored as an index into the array column_colors.
@@ -285,6 +368,9 @@
 	graph->prev_state = GRAPH_PADDING;
 	graph->commit_index = 0;
 	graph->prev_commit_index = 0;
+	graph->merge_layout = 0;
+	graph->edges_added = 0;
+	graph->prev_edges_added = 0;
 	graph->num_columns = 0;
 	graph->num_new_columns = 0;
 	graph->mapping_size = 0;
@@ -303,7 +389,7 @@
 	ALLOC_ARRAY(graph->columns, graph->column_capacity);
 	ALLOC_ARRAY(graph->new_columns, graph->column_capacity);
 	ALLOC_ARRAY(graph->mapping, 2 * graph->column_capacity);
-	ALLOC_ARRAY(graph->new_mapping, 2 * graph->column_capacity);
+	ALLOC_ARRAY(graph->old_mapping, 2 * graph->column_capacity);
 
 	/*
 	 * The diff output prefix callback, with this we can make
@@ -333,7 +419,7 @@
 	REALLOC_ARRAY(graph->columns, graph->column_capacity);
 	REALLOC_ARRAY(graph->new_columns, graph->column_capacity);
 	REALLOC_ARRAY(graph->mapping, graph->column_capacity * 2);
-	REALLOC_ARRAY(graph->new_mapping, graph->column_capacity * 2);
+	REALLOC_ARRAY(graph->old_mapping, graph->column_capacity * 2);
 }
 
 /*
@@ -432,74 +518,76 @@
 	return graph_get_current_column_color(graph);
 }
 
-static void graph_insert_into_new_columns(struct git_graph *graph,
-					  struct commit *commit,
-					  int *mapping_index)
+static int graph_find_new_column_by_commit(struct git_graph *graph,
+					   struct commit *commit)
 {
 	int i;
-
-	/*
-	 * If the commit is already in the new_columns list, we don't need to
-	 * add it.  Just update the mapping correctly.
-	 */
 	for (i = 0; i < graph->num_new_columns; i++) {
-		if (graph->new_columns[i].commit == commit) {
-			graph->mapping[*mapping_index] = i;
-			*mapping_index += 2;
-			return;
-		}
+		if (graph->new_columns[i].commit == commit)
+			return i;
 	}
-
-	/*
-	 * This commit isn't already in new_columns.  Add it.
-	 */
-	graph->new_columns[graph->num_new_columns].commit = commit;
-	graph->new_columns[graph->num_new_columns].color = graph_find_commit_color(graph, commit);
-	graph->mapping[*mapping_index] = graph->num_new_columns;
-	*mapping_index += 2;
-	graph->num_new_columns++;
+	return -1;
 }
 
-static void graph_update_width(struct git_graph *graph,
-			       int is_commit_in_existing_columns)
+static void graph_insert_into_new_columns(struct git_graph *graph,
+					  struct commit *commit,
+					  int idx)
 {
-	/*
-	 * Compute the width needed to display the graph for this commit.
-	 * This is the maximum width needed for any row.  All other rows
-	 * will be padded to this width.
-	 *
-	 * Compute the number of columns in the widest row:
-	 * Count each existing column (graph->num_columns), and each new
-	 * column added by this commit.
-	 */
-	int max_cols = graph->num_columns + graph->num_parents;
+	int i = graph_find_new_column_by_commit(graph, commit);
+	int mapping_idx;
 
 	/*
-	 * Even if the current commit has no parents to be printed, it
-	 * still takes up a column for itself.
+	 * If the commit is not already in the new_columns array, then add it
+	 * and record it as being in the final column.
 	 */
-	if (graph->num_parents < 1)
-		max_cols++;
+	if (i < 0) {
+		i = graph->num_new_columns++;
+		graph->new_columns[i].commit = commit;
+		graph->new_columns[i].color = graph_find_commit_color(graph, commit);
+	}
 
-	/*
-	 * We added a column for the current commit as part of
-	 * graph->num_parents.  If the current commit was already in
-	 * graph->columns, then we have double counted it.
-	 */
-	if (is_commit_in_existing_columns)
-		max_cols--;
+	if (graph->num_parents > 1 && idx > -1 && graph->merge_layout == -1) {
+		/*
+		 * If this is the first parent of a merge, choose a layout for
+		 * the merge line based on whether the parent appears in a
+		 * column to the left of the merge
+		 */
+		int dist, shift;
 
-	/*
-	 * Each column takes up 2 spaces
-	 */
-	graph->width = max_cols * 2;
+		dist = idx - i;
+		shift = (dist > 1) ? 2 * dist - 3 : 1;
+
+		graph->merge_layout = (dist > 0) ? 0 : 1;
+		graph->edges_added = graph->num_parents + graph->merge_layout  - 2;
+
+		mapping_idx = graph->width + (graph->merge_layout - 1) * shift;
+		graph->width += 2 * graph->merge_layout;
+
+	} else if (graph->edges_added > 0 && i == graph->mapping[graph->width - 2]) {
+		/*
+		 * If some columns have been added by a merge, but this commit
+		 * was found in the last existing column, then adjust the
+		 * numbers so that the two edges immediately join, i.e.:
+		 *
+		 *		* |		* |
+		 *		|\ \	=>	|\|
+		 *		| |/		| *
+		 *		| *
+		 */
+		mapping_idx = graph->width - 2;
+		graph->edges_added = -1;
+	} else {
+		mapping_idx = graph->width;
+		graph->width += 2;
+	}
+
+	graph->mapping[mapping_idx] = i;
 }
 
 static void graph_update_columns(struct git_graph *graph)
 {
 	struct commit_list *parent;
 	int max_new_columns;
-	int mapping_idx;
 	int i, seen_this, is_commit_in_columns;
 
 	/*
@@ -532,6 +620,10 @@
 	for (i = 0; i < graph->mapping_size; i++)
 		graph->mapping[i] = -1;
 
+	graph->width = 0;
+	graph->prev_edges_added = graph->edges_added;
+	graph->edges_added = 0;
+
 	/*
 	 * Populate graph->new_columns and graph->mapping
 	 *
@@ -542,7 +634,6 @@
 	 * supposed to end up after the collapsing is performed.
 	 */
 	seen_this = 0;
-	mapping_idx = 0;
 	is_commit_in_columns = 1;
 	for (i = 0; i <= graph->num_columns; i++) {
 		struct commit *col_commit;
@@ -556,9 +647,9 @@
 		}
 
 		if (col_commit == graph->commit) {
-			int old_mapping_idx = mapping_idx;
 			seen_this = 1;
 			graph->commit_index = i;
+			graph->merge_layout = -1;
 			for (parent = first_interesting_parent(graph);
 			     parent;
 			     parent = next_interesting_parent(graph, parent)) {
@@ -571,21 +662,18 @@
 				    !is_commit_in_columns) {
 					graph_increment_column_color(graph);
 				}
-				graph_insert_into_new_columns(graph,
-							      parent->item,
-							      &mapping_idx);
+				graph_insert_into_new_columns(graph, parent->item, i);
 			}
 			/*
-			 * We always need to increment mapping_idx by at
+			 * We always need to increment graph->width by at
 			 * least 2, even if it has no interesting parents.
 			 * The current commit always takes up at least 2
 			 * spaces.
 			 */
-			if (mapping_idx == old_mapping_idx)
-				mapping_idx += 2;
+			if (graph->num_parents == 0)
+				graph->width += 2;
 		} else {
-			graph_insert_into_new_columns(graph, col_commit,
-						      &mapping_idx);
+			graph_insert_into_new_columns(graph, col_commit, -1);
 		}
 	}
 
@@ -595,11 +683,43 @@
 	while (graph->mapping_size > 1 &&
 	       graph->mapping[graph->mapping_size - 1] < 0)
 		graph->mapping_size--;
+}
 
+static int graph_num_dashed_parents(struct git_graph *graph)
+{
+	return graph->num_parents + graph->merge_layout - 3;
+}
+
+static int graph_num_expansion_rows(struct git_graph *graph)
+{
 	/*
-	 * Compute graph->width for this commit
+	 * Normally, we need two expansion rows for each dashed parent line from
+	 * an octopus merge:
+	 *
+	 * 		| *
+	 * 		| |\
+	 * 		| | \
+	 * 		| |  \
+	 * 		| *-. \
+	 * 		| |\ \ \
+	 *
+	 * If the merge is skewed to the left, then its parents occupy one less
+	 * column, and we don't need as many expansion rows to route around it;
+	 * in some cases that means we don't need any expansion rows at all:
+	 *
+	 * 		| *
+	 * 		| |\
+	 * 		| * \
+	 * 		|/|\ \
 	 */
-	graph_update_width(graph, is_commit_in_columns);
+	return graph_num_dashed_parents(graph) * 2;
+}
+
+static int graph_needs_pre_commit_line(struct git_graph *graph)
+{
+	return graph->num_parents >= 3 &&
+	       graph->commit_index < (graph->num_columns - 1) &&
+	       graph->expansion_row < graph_num_expansion_rows(graph);
 }
 
 void graph_update(struct git_graph *graph, struct commit *commit)
@@ -657,8 +777,7 @@
 	 */
 	if (graph->state != GRAPH_PADDING)
 		graph->state = GRAPH_SKIP;
-	else if (graph->num_parents >= 3 &&
-		 graph->commit_index < (graph->num_columns - 1))
+	else if (graph_needs_pre_commit_line(graph))
 		graph->state = GRAPH_PRE_COMMIT;
 	else
 		graph->state = GRAPH_COMMIT;
@@ -686,8 +805,7 @@
 	return 1;
 }
 
-static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb,
-				   int chars_written)
+static void graph_pad_horizontally(struct git_graph *graph, struct graph_line *line)
 {
 	/*
 	 * Add additional spaces to the end of the strbuf, so that all
@@ -696,34 +814,22 @@
 	 * This way, fields printed to the right of the graph will remain
 	 * aligned for the entire commit.
 	 */
-	if (chars_written < graph->width)
-		strbuf_addchars(sb, ' ', graph->width - chars_written);
+	if (line->width < graph->width)
+		graph_line_addchars(line, ' ', graph->width - line->width);
 }
 
 static void graph_output_padding_line(struct git_graph *graph,
-				      struct strbuf *sb)
+				      struct graph_line *line)
 {
 	int i;
 
 	/*
-	 * We could conceivable be called with a NULL commit
-	 * if our caller has a bug, and invokes graph_next_line()
-	 * immediately after graph_init(), without first calling
-	 * graph_update().  Return without outputting anything in this
-	 * case.
-	 */
-	if (!graph->commit)
-		return;
-
-	/*
 	 * Output a padding row, that leaves all branch lines unchanged
 	 */
 	for (i = 0; i < graph->num_new_columns; i++) {
-		strbuf_write_column(sb, &graph->new_columns[i], '|');
-		strbuf_addch(sb, ' ');
+		graph_line_write_column(line, &graph->new_columns[i], '|');
+		graph_line_addch(line, ' ');
 	}
-
-	graph_pad_horizontally(graph, sb, graph->num_new_columns * 2);
 }
 
 
@@ -733,28 +839,24 @@
 }
 
 
-static void graph_output_skip_line(struct git_graph *graph, struct strbuf *sb)
+static void graph_output_skip_line(struct git_graph *graph, struct graph_line *line)
 {
 	/*
 	 * Output an ellipsis to indicate that a portion
 	 * of the graph is missing.
 	 */
-	strbuf_addstr(sb, "...");
-	graph_pad_horizontally(graph, sb, 3);
+	graph_line_addstr(line, "...");
 
-	if (graph->num_parents >= 3 &&
-	    graph->commit_index < (graph->num_columns - 1))
+	if (graph_needs_pre_commit_line(graph))
 		graph_update_state(graph, GRAPH_PRE_COMMIT);
 	else
 		graph_update_state(graph, GRAPH_COMMIT);
 }
 
 static void graph_output_pre_commit_line(struct git_graph *graph,
-					 struct strbuf *sb)
+					 struct graph_line *line)
 {
-	int num_expansion_rows;
 	int i, seen_this;
-	int chars_written;
 
 	/*
 	 * This function formats a row that increases the space around a commit
@@ -764,27 +866,24 @@
 	 * We need 2 extra rows for every parent over 2.
 	 */
 	assert(graph->num_parents >= 3);
-	num_expansion_rows = (graph->num_parents - 2) * 2;
 
 	/*
 	 * graph->expansion_row tracks the current expansion row we are on.
 	 * It should be in the range [0, num_expansion_rows - 1]
 	 */
 	assert(0 <= graph->expansion_row &&
-	       graph->expansion_row < num_expansion_rows);
+	       graph->expansion_row < graph_num_expansion_rows(graph));
 
 	/*
 	 * Output the row
 	 */
 	seen_this = 0;
-	chars_written = 0;
 	for (i = 0; i < graph->num_columns; i++) {
 		struct column *col = &graph->columns[i];
 		if (col->commit == graph->commit) {
 			seen_this = 1;
-			strbuf_write_column(sb, col, '|');
-			strbuf_addchars(sb, ' ', graph->expansion_row);
-			chars_written += 1 + graph->expansion_row;
+			graph_line_write_column(line, col, '|');
+			graph_line_addchars(line, ' ', graph->expansion_row);
 		} else if (seen_this && (graph->expansion_row == 0)) {
 			/*
 			 * This is the first line of the pre-commit output.
@@ -797,33 +896,27 @@
 			 */
 			if (graph->prev_state == GRAPH_POST_MERGE &&
 			    graph->prev_commit_index < i)
-				strbuf_write_column(sb, col, '\\');
+				graph_line_write_column(line, col, '\\');
 			else
-				strbuf_write_column(sb, col, '|');
-			chars_written++;
+				graph_line_write_column(line, col, '|');
 		} else if (seen_this && (graph->expansion_row > 0)) {
-			strbuf_write_column(sb, col, '\\');
-			chars_written++;
+			graph_line_write_column(line, col, '\\');
 		} else {
-			strbuf_write_column(sb, col, '|');
-			chars_written++;
+			graph_line_write_column(line, col, '|');
 		}
-		strbuf_addch(sb, ' ');
-		chars_written++;
+		graph_line_addch(line, ' ');
 	}
 
-	graph_pad_horizontally(graph, sb, chars_written);
-
 	/*
 	 * Increment graph->expansion_row,
 	 * and move to state GRAPH_COMMIT if necessary
 	 */
 	graph->expansion_row++;
-	if (graph->expansion_row >= num_expansion_rows)
+	if (!graph_needs_pre_commit_line(graph))
 		graph_update_state(graph, GRAPH_COMMIT);
 }
 
-static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)
+static void graph_output_commit_char(struct git_graph *graph, struct graph_line *line)
 {
 	/*
 	 * For boundary commits, print 'o'
@@ -831,72 +924,67 @@
 	 */
 	if (graph->commit->object.flags & BOUNDARY) {
 		assert(graph->revs->boundary);
-		strbuf_addch(sb, 'o');
+		graph_line_addch(line, 'o');
 		return;
 	}
 
 	/*
 	 * get_revision_mark() handles all other cases without assert()
 	 */
-	strbuf_addstr(sb, get_revision_mark(graph->revs, graph->commit));
+	graph_line_addstr(line, get_revision_mark(graph->revs, graph->commit));
 }
 
 /*
- * Draw the horizontal dashes of an octopus merge and return the number of
- * characters written.
+ * Draw the horizontal dashes of an octopus merge.
  */
-static int graph_draw_octopus_merge(struct git_graph *graph,
-				    struct strbuf *sb)
+static void graph_draw_octopus_merge(struct git_graph *graph, struct graph_line *line)
 {
 	/*
-	 * Here dashless_parents represents the number of parents which don't
-	 * need to have dashes (the edges labeled "0" and "1").  And
-	 * dashful_parents are the remaining ones.
+	 * The parents of a merge commit can be arbitrarily reordered as they
+	 * are mapped onto display columns, for example this is a valid merge:
 	 *
-	 * | *---.
-	 * | |\ \ \
-	 * | | | | |
-	 * x 0 1 2 3
+	 *	| | *---.
+	 *	| | |\ \ \
+	 *	| | |/ / /
+	 *	| |/| | /
+	 *	| |_|_|/
+	 *	|/| | |
+	 *	3 1 0 2
 	 *
+	 * The numbers denote which parent of the merge each visual column
+	 * corresponds to; we can't assume that the parents will initially
+	 * display in the order given by new_columns.
+	 *
+	 * To find the right color for each dash, we need to consult the
+	 * mapping array, starting from the column 2 places to the right of the
+	 * merge commit, and use that to find out which logical column each
+	 * edge will collapse to.
+	 *
+	 * Commits are rendered once all edges have collapsed to their correct
+	 * logcial column, so commit_index gives us the right visual offset for
+	 * the merge commit.
 	 */
-	const int dashless_parents = 2;
-	int dashful_parents = graph->num_parents - dashless_parents;
 
-	/*
-	 * Usually, we add one new column for each parent (like the diagram
-	 * above) but sometimes the first parent goes into an existing column,
-	 * like this:
-	 *
-	 * | *---.
-	 * | |\ \ \
-	 * |/ / / /
-	 * x 0 1 2
-	 *
-	 * In which case the number of parents will be one greater than the
-	 * number of added columns.
-	 */
-	int added_cols = (graph->num_new_columns - graph->num_columns);
-	int parent_in_old_cols = graph->num_parents - added_cols;
+	int i, j;
+	struct column *col;
 
-	/*
-	 * In both cases, commit_index corresponds to the edge labeled "0".
-	 */
-	int first_col = graph->commit_index + dashless_parents
-	    - parent_in_old_cols;
+	int dashed_parents = graph_num_dashed_parents(graph);
 
-	int i;
-	for (i = 0; i < dashful_parents; i++) {
-		strbuf_write_column(sb, &graph->new_columns[i+first_col], '-');
-		strbuf_write_column(sb, &graph->new_columns[i+first_col],
-				    i == dashful_parents-1 ? '.' : '-');
+	for (i = 0; i < dashed_parents; i++) {
+		j = graph->mapping[(graph->commit_index + i + 2) * 2];
+		col = &graph->new_columns[j];
+
+		graph_line_write_column(line, col, '-');
+		graph_line_write_column(line, col, (i == dashed_parents - 1) ? '.' : '-');
 	}
-	return 2 * dashful_parents;
+
+	return;
 }
 
-static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
+static void graph_output_commit_line(struct git_graph *graph, struct graph_line *line)
 {
 	int seen_this = 0;
-	int i, chars_written;
+	int i;
 
 	/*
 	 * Output the row containing this commit
@@ -906,7 +994,6 @@
 	 * children that we have already processed.)
 	 */
 	seen_this = 0;
-	chars_written = 0;
 	for (i = 0; i <= graph->num_columns; i++) {
 		struct column *col = &graph->columns[i];
 		struct commit *col_commit;
@@ -920,19 +1007,17 @@
 
 		if (col_commit == graph->commit) {
 			seen_this = 1;
-			graph_output_commit_char(graph, sb);
-			chars_written++;
+			graph_output_commit_char(graph, line);
 
 			if (graph->num_parents > 2)
-				chars_written += graph_draw_octopus_merge(graph,
-									  sb);
-		} else if (seen_this && (graph->num_parents > 2)) {
-			strbuf_write_column(sb, col, '\\');
-			chars_written++;
-		} else if (seen_this && (graph->num_parents == 2)) {
+				graph_draw_octopus_merge(graph, line);
+		} else if (seen_this && (graph->edges_added > 1)) {
+			graph_line_write_column(line, col, '\\');
+		} else if (seen_this && (graph->edges_added == 1)) {
 			/*
-			 * This is a 2-way merge commit.
-			 * There is no GRAPH_PRE_COMMIT stage for 2-way
+			 * This is either a right-skewed 2-way merge
+			 * commit, or a left-skewed 3-way merge.
+			 * There is no GRAPH_PRE_COMMIT stage for such
 			 * merges, so this is the first line of output
 			 * for this commit.  Check to see what the previous
 			 * line of output was.
@@ -944,21 +1029,21 @@
 			 * makes the output look nicer.
 			 */
 			if (graph->prev_state == GRAPH_POST_MERGE &&
+			    graph->prev_edges_added > 0 &&
 			    graph->prev_commit_index < i)
-				strbuf_write_column(sb, col, '\\');
+				graph_line_write_column(line, col, '\\');
 			else
-				strbuf_write_column(sb, col, '|');
-			chars_written++;
+				graph_line_write_column(line, col, '|');
+		} else if (graph->prev_state == GRAPH_COLLAPSING &&
+			   graph->old_mapping[2 * i + 1] == i &&
+			   graph->mapping[2 * i] < i) {
+			graph_line_write_column(line, col, '/');
 		} else {
-			strbuf_write_column(sb, col, '|');
-			chars_written++;
+			graph_line_write_column(line, col, '|');
 		}
-		strbuf_addch(sb, ' ');
-		chars_written++;
+		graph_line_addch(line, ' ');
 	}
 
-	graph_pad_horizontally(graph, sb, chars_written);
-
 	/*
 	 * Update graph->state
 	 */
@@ -970,26 +1055,19 @@
 		graph_update_state(graph, GRAPH_COLLAPSING);
 }
 
-static struct column *find_new_column_by_commit(struct git_graph *graph,
-						struct commit *commit)
-{
-	int i;
-	for (i = 0; i < graph->num_new_columns; i++) {
-		if (graph->new_columns[i].commit == commit)
-			return &graph->new_columns[i];
-	}
-	return NULL;
-}
+const char merge_chars[] = {'/', '|', '\\'};
 
-static void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb)
+static void graph_output_post_merge_line(struct git_graph *graph, struct graph_line *line)
 {
 	int seen_this = 0;
-	int i, j, chars_written;
+	int i, j;
+
+	struct commit_list *first_parent = first_interesting_parent(graph);
+	int seen_parent = 0;
 
 	/*
 	 * Output the post-merge row
 	 */
-	chars_written = 0;
 	for (i = 0; i <= graph->num_columns; i++) {
 		struct column *col = &graph->columns[i];
 		struct commit *col_commit;
@@ -1008,37 +1086,44 @@
 			 * new_columns and use those to format the
 			 * edges.
 			 */
-			struct commit_list *parents = NULL;
-			struct column *par_column;
+			struct commit_list *parents = first_parent;
+			int par_column;
+			int idx = graph->merge_layout;
+			char c;
 			seen_this = 1;
-			parents = first_interesting_parent(graph);
-			assert(parents);
-			par_column = find_new_column_by_commit(graph, parents->item);
-			assert(par_column);
 
-			strbuf_write_column(sb, par_column, '|');
-			chars_written++;
-			for (j = 0; j < graph->num_parents - 1; j++) {
+			for (j = 0; j < graph->num_parents; j++) {
+				par_column = graph_find_new_column_by_commit(graph, parents->item);
+				assert(par_column >= 0);
+
+				c = merge_chars[idx];
+				graph_line_write_column(line, &graph->new_columns[par_column], c);
+				if (idx == 2) {
+					if (graph->edges_added > 0 || j < graph->num_parents - 1)
+						graph_line_addch(line, ' ');
+				} else {
+					idx++;
+				}
 				parents = next_interesting_parent(graph, parents);
-				assert(parents);
-				par_column = find_new_column_by_commit(graph, parents->item);
-				assert(par_column);
-				strbuf_write_column(sb, par_column, '\\');
-				strbuf_addch(sb, ' ');
 			}
-			chars_written += j * 2;
-		} else if (seen_this) {
-			strbuf_write_column(sb, col, '\\');
-			strbuf_addch(sb, ' ');
-			chars_written += 2;
-		} else {
-			strbuf_write_column(sb, col, '|');
-			strbuf_addch(sb, ' ');
-			chars_written += 2;
-		}
-	}
+			if (graph->edges_added == 0)
+				graph_line_addch(line, ' ');
 
-	graph_pad_horizontally(graph, sb, chars_written);
+		} else if (seen_this) {
+			if (graph->edges_added > 0)
+				graph_line_write_column(line, col, '\\');
+			else
+				graph_line_write_column(line, col, '|');
+			graph_line_addch(line, ' ');
+		} else {
+			graph_line_write_column(line, col, '|');
+			if (graph->merge_layout != 0 || i != graph->commit_index - 1)
+				graph_line_addch(line, seen_parent ? '_' : ' ');
+		}
+
+		if (col_commit == first_parent->item)
+			seen_parent = 1;
+	}
 
 	/*
 	 * Update graph->state
@@ -1049,7 +1134,7 @@
 		graph_update_state(graph, GRAPH_COLLAPSING);
 }
 
-static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf *sb)
+static void graph_output_collapsing_line(struct git_graph *graph, struct graph_line *line)
 {
 	int i;
 	short used_horizontal = 0;
@@ -1057,13 +1142,18 @@
 	int horizontal_edge_target = -1;
 
 	/*
-	 * Clear out the new_mapping array
+	 * Swap the mapping and old_mapping arrays
+	 */
+	SWAP(graph->mapping, graph->old_mapping);
+
+	/*
+	 * Clear out the mapping array
 	 */
 	for (i = 0; i < graph->mapping_size; i++)
-		graph->new_mapping[i] = -1;
+		graph->mapping[i] = -1;
 
 	for (i = 0; i < graph->mapping_size; i++) {
-		int target = graph->mapping[i];
+		int target = graph->old_mapping[i];
 		if (target < 0)
 			continue;
 
@@ -1084,14 +1174,14 @@
 			 * This column is already in the
 			 * correct place
 			 */
-			assert(graph->new_mapping[i] == -1);
-			graph->new_mapping[i] = target;
-		} else if (graph->new_mapping[i - 1] < 0) {
+			assert(graph->mapping[i] == -1);
+			graph->mapping[i] = target;
+		} else if (graph->mapping[i - 1] < 0) {
 			/*
 			 * Nothing is to the left.
 			 * Move to the left by one
 			 */
-			graph->new_mapping[i - 1] = target;
+			graph->mapping[i - 1] = target;
 			/*
 			 * If there isn't already an edge moving horizontally
 			 * select this one.
@@ -1107,9 +1197,9 @@
 				 * line.
 				 */
 				for (j = (target * 2)+3; j < (i - 2); j += 2)
-					graph->new_mapping[j] = target;
+					graph->mapping[j] = target;
 			}
-		} else if (graph->new_mapping[i - 1] == target) {
+		} else if (graph->mapping[i - 1] == target) {
 			/*
 			 * There is a branch line to our left
 			 * already, and it is our target.  We
@@ -1117,7 +1207,7 @@
 			 * the same parent commit.
 			 *
 			 * We don't have to add anything to the
-			 * output or new_mapping, since the
+			 * output or mapping, since the
 			 * existing branch line has already taken
 			 * care of it.
 			 */
@@ -1133,10 +1223,10 @@
 			 * The branch to the left of that space
 			 * should be our eventual target.
 			 */
-			assert(graph->new_mapping[i - 1] > target);
-			assert(graph->new_mapping[i - 2] < 0);
-			assert(graph->new_mapping[i - 3] == target);
-			graph->new_mapping[i - 2] = target;
+			assert(graph->mapping[i - 1] > target);
+			assert(graph->mapping[i - 2] < 0);
+			assert(graph->mapping[i - 3] == target);
+			graph->mapping[i - 2] = target;
 			/*
 			 * Mark this branch as the horizontal edge to
 			 * prevent any other edges from moving
@@ -1148,20 +1238,25 @@
 	}
 
 	/*
+	 * Copy the current mapping array into old_mapping
+	 */
+	COPY_ARRAY(graph->old_mapping, graph->mapping, graph->mapping_size);
+
+	/*
 	 * The new mapping may be 1 smaller than the old mapping
 	 */
-	if (graph->new_mapping[graph->mapping_size - 1] < 0)
+	if (graph->mapping[graph->mapping_size - 1] < 0)
 		graph->mapping_size--;
 
 	/*
 	 * Output out a line based on the new mapping info
 	 */
 	for (i = 0; i < graph->mapping_size; i++) {
-		int target = graph->new_mapping[i];
+		int target = graph->mapping[i];
 		if (target < 0)
-			strbuf_addch(sb, ' ');
+			graph_line_addch(line, ' ');
 		else if (target * 2 == i)
-			strbuf_write_column(sb, &graph->new_columns[target], '|');
+			graph_line_write_column(line, &graph->new_columns[target], '|');
 		else if (target == horizontal_edge_target &&
 			 i != horizontal_edge - 1) {
 				/*
@@ -1170,24 +1265,17 @@
 				 * won't continue into the next line.
 				 */
 				if (i != (target * 2)+3)
-					graph->new_mapping[i] = -1;
+					graph->mapping[i] = -1;
 				used_horizontal = 1;
-			strbuf_write_column(sb, &graph->new_columns[target], '_');
+			graph_line_write_column(line, &graph->new_columns[target], '_');
 		} else {
 			if (used_horizontal && i < horizontal_edge)
-				graph->new_mapping[i] = -1;
-			strbuf_write_column(sb, &graph->new_columns[target], '/');
+				graph->mapping[i] = -1;
+			graph_line_write_column(line, &graph->new_columns[target], '/');
 
 		}
 	}
 
-	graph_pad_horizontally(graph, sb, graph->mapping_size);
-
-	/*
-	 * Swap mapping and new_mapping
-	 */
-	SWAP(graph->mapping, graph->new_mapping);
-
 	/*
 	 * If graph->mapping indicates that all of the branch lines
 	 * are already in the correct positions, we are done.
@@ -1199,35 +1287,49 @@
 
 int graph_next_line(struct git_graph *graph, struct strbuf *sb)
 {
+	int shown_commit_line = 0;
+	struct graph_line line = { .buf = sb, .width = 0 };
+
+	/*
+	 * We could conceivable be called with a NULL commit
+	 * if our caller has a bug, and invokes graph_next_line()
+	 * immediately after graph_init(), without first calling
+	 * graph_update().  Return without outputting anything in this
+	 * case.
+	 */
+	if (!graph->commit)
+		return -1;
+
 	switch (graph->state) {
 	case GRAPH_PADDING:
-		graph_output_padding_line(graph, sb);
-		return 0;
+		graph_output_padding_line(graph, &line);
+		break;
 	case GRAPH_SKIP:
-		graph_output_skip_line(graph, sb);
-		return 0;
+		graph_output_skip_line(graph, &line);
+		break;
 	case GRAPH_PRE_COMMIT:
-		graph_output_pre_commit_line(graph, sb);
-		return 0;
+		graph_output_pre_commit_line(graph, &line);
+		break;
 	case GRAPH_COMMIT:
-		graph_output_commit_line(graph, sb);
-		return 1;
+		graph_output_commit_line(graph, &line);
+		shown_commit_line = 1;
+		break;
 	case GRAPH_POST_MERGE:
-		graph_output_post_merge_line(graph, sb);
-		return 0;
+		graph_output_post_merge_line(graph, &line);
+		break;
 	case GRAPH_COLLAPSING:
-		graph_output_collapsing_line(graph, sb);
-		return 0;
+		graph_output_collapsing_line(graph, &line);
+		break;
 	}
 
-	assert(0);
-	return 0;
+	graph_pad_horizontally(graph, &line);
+	return shown_commit_line;
 }
 
 static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
 {
 	int i;
-	int chars_written = 0;
+	struct graph_line line = { .buf = sb, .width = 0 };
 
 	if (graph->state != GRAPH_COMMIT) {
 		graph_next_line(graph, sb);
@@ -1244,20 +1346,17 @@
 	for (i = 0; i < graph->num_columns; i++) {
 		struct column *col = &graph->columns[i];
 
-		strbuf_write_column(sb, col, '|');
-		chars_written++;
+		graph_line_write_column(&line, col, '|');
 
 		if (col->commit == graph->commit && graph->num_parents > 2) {
 			int len = (graph->num_parents - 2) * 2;
-			strbuf_addchars(sb, ' ', len);
-			chars_written += len;
+			graph_line_addchars(&line, ' ', len);
 		} else {
-			strbuf_addch(sb, ' ');
-			chars_written++;
+			graph_line_addch(&line, ' ');
 		}
 	}
 
-	graph_pad_horizontally(graph, sb, chars_written);
+	graph_pad_horizontally(graph, &line);
 
 	/*
 	 * Update graph->prev_state since we have output a padding line
diff --git a/graph.h b/graph.h
index af62339..8313e29 100644
--- a/graph.h
+++ b/graph.h
@@ -2,6 +2,103 @@
 #define GRAPH_H
 #include "diff.h"
 
+/**
+ * The graph API is used to draw a text-based representation of the commit
+ * history. The API generates the graph in a line-by-line fashion.
+ *
+ * Calling sequence
+ * ----------------
+ *
+ * - Create a `struct git_graph` by calling `graph_init()`.  When using the
+ *   revision walking API, this is done automatically by `setup_revisions()` if
+ *   the '--graph' option is supplied.
+ *
+ * - Use the revision walking API to walk through a group of contiguous commits.
+ *   The `get_revision()` function automatically calls `graph_update()` each time
+ *   it is invoked.
+ *
+ * - For each commit, call `graph_next_line()` repeatedly, until
+ *   `graph_is_commit_finished()` returns non-zero.  Each call to
+ *   `graph_next_line()` will output a single line of the graph.  The resulting
+ *   lines will not contain any newlines.  `graph_next_line()` returns 1 if the
+ *   resulting line contains the current commit, or 0 if this is merely a line
+ *   needed to adjust the graph before or after the current commit.  This return
+ *   value can be used to determine where to print the commit summary information
+ *   alongside the graph output.
+ *
+ * Limitations
+ * -----------
+ * - Check the graph_update() function for its limitations.
+ *
+ * - The graph API does not currently support reverse commit ordering.  In
+ *   order to implement reverse ordering, the graphing API needs an
+ *   (efficient) mechanism to find the children of a commit.
+ *
+ * Sample usage
+ * ------------
+ *
+ * ------------
+ * struct commit *commit;
+ * struct git_graph *graph = graph_init(opts);
+ *
+ * while ((commit = get_revision(opts)) != NULL) {
+ * 	while (!graph_is_commit_finished(graph))
+ * 	{
+ * 		struct strbuf sb;
+ * 		int is_commit_line;
+ *
+ * 		strbuf_init(&sb, 0);
+ * 		is_commit_line = graph_next_line(graph, &sb);
+ * 		fputs(sb.buf, stdout);
+ *
+ * 		if (is_commit_line)
+ * 			log_tree_commit(opts, commit);
+ * 		else
+ * 			putchar(opts->diffopt.line_termination);
+ * 	}
+ * }
+ * ------------
+ * Sample output
+ * -------------
+ *
+ * The following is an example of the output from the graph API.  This output does
+ * not include any commit summary information--callers are responsible for
+ * outputting that information, if desired.
+ * ------------
+ * *
+ * *
+ * *
+ * |\
+ * * |
+ * | | *
+ * | \ \
+ * |  \ \
+ * *-. \ \
+ * |\ \ \ \
+ * | | * | |
+ * | | | | | *
+ * | | | | | *
+ * | | | | | *
+ * | | | | | |\
+ * | | | | | | *
+ * | * | | | | |
+ * | | | | | *  \
+ * | | | | | |\  |
+ * | | | | * | | |
+ * | | | | * | | |
+ * * | | | | | | |
+ * | |/ / / / / /
+ * |/| / / / / /
+ * * | | | | | |
+ * |/ / / / / /
+ * * | | | | |
+ * | | | | | *
+ * | | | | |/
+ * | | | | *
+ * ------------
+ *
+ */
+
 /* A graph is a pointer to this opaque structure */
 struct git_graph;
 
@@ -50,6 +147,21 @@
  * If graph_update() is called before graph_is_commit_finished() returns 1,
  * the next call to graph_next_line() will output an ellipsis ("...")
  * to indicate that a portion of the graph is missing.
+ *
+ * Limitations:
+ * -----------
+ *
+ * - `graph_update()` must be called with commits in topological order.  It should
+ *   not be called on a commit if it has already been invoked with an ancestor of
+ *   that commit, or the graph output will be incorrect.
+ *
+ * - `graph_update()` must be called on a contiguous group of commits.  If
+ *   `graph_update()` is called on a particular commit, it should later be called
+ *   on all parents of that commit.  Parents must not be skipped, or the graph
+ *   output will appear incorrect.
+ *
+ * - `graph_update()` may be used on a pruned set of commits only if the parent list
+ *   has been rewritten so as to include only ancestors from the pruned set.
  */
 void graph_update(struct git_graph *graph, struct commit *commit);
 
@@ -62,6 +174,10 @@
  * for this commit.  If 0 is returned, graph_next_line() may still be
  * called without calling graph_update(), and it will merely output
  * appropriate "vertical padding" in the graph.
+ *
+ * If `graph_update()` is called before all lines for the current commit have
+ * been printed, the next call to `graph_next_line()` will output an ellipsis,
+ * to indicate that a portion of the graph was omitted.
  */
 int graph_is_commit_finished(struct git_graph const *graph);
 
@@ -112,6 +228,7 @@
 /*
  * If the graph is non-NULL, print the rest of the history graph for this
  * commit to stdout.  Does not print a terminating newline on the last line.
+ * Returns 1 if output was printed, and 0 if no output was necessary.
  */
 int graph_show_remainder(struct git_graph *graph);
 
@@ -121,6 +238,10 @@
  * This is similar to graph_show_strbuf(), but it always prints the
  * remainder of the graph.
  *
+ * It is better than directly calling `graph_show_strbuf()` followed by
+ * `graph_show_remainder()` since it properly handles buffers that do not end in
+ * a terminating newline.
+ *
  * If the strbuf ends with a newline, the output printed by
  * graph_show_commit_msg() will end with a newline.  If the strbuf is
  * missing a terminating newline (including if it is empty), the output
diff --git a/grep.c b/grep.c
index b7ae5a4..0552b12 100644
--- a/grep.c
+++ b/grep.c
@@ -26,7 +26,7 @@
 
 static void pcre2_free(void *pointer, MAYBE_UNUSED void *memory_data)
 {
-	return free(pointer);
+	free(pointer);
 }
 #endif
 
diff --git a/hashmap.c b/hashmap.c
index 39c1311..09813e1 100644
--- a/hashmap.c
+++ b/hashmap.c
@@ -51,7 +51,7 @@
 }
 
 /*
- * Incoporate another chunk of data into a memihash
+ * Incorporate another chunk of data into a memihash
  * computation.
  */
 unsigned int memihash_cont(unsigned int hash_seed, const void *buf, size_t len)
diff --git a/hashmap.h b/hashmap.h
index bd27015..79ae9f8 100644
--- a/hashmap.h
+++ b/hashmap.h
@@ -59,7 +59,7 @@
  *
  *         if (!strcmp("print_all_by_key", action)) {
  *             struct long2string k, *e;
- *             hashmap_entry_init(&k->ent, memhash(&key, sizeof(long)));
+ *             hashmap_entry_init(&k.ent, memhash(&key, sizeof(long)));
  *             k.key = key;
  *
  *             flags &= ~COMPARE_VALUE;
@@ -87,12 +87,12 @@
  *
  *         if (!strcmp("has_exact_match_no_heap_alloc", action)) {
  *             struct long2string k;
- *             hashmap_entry_init(&k->ent, memhash(&key, sizeof(long)));
+ *             hashmap_entry_init(&k.ent, memhash(&key, sizeof(long)));
  *             k.key = key;
  *
  *             flags |= COMPARE_VALUE;
  *             printf("%sfound\n",
- *                    hashmap_get(&map, &k->ent, value) ? "" : "not ");
+ *                    hashmap_get(&map, &k.ent, value) ? "" : "not ");
  *         }
  *
  *         if (!strcmp("end", action)) {
@@ -502,7 +502,7 @@
 }
 
 /*
- * Re-enable item couting when adding/removing items.
+ * Re-enable item counting when adding/removing items.
  * If counting is currently disabled, it will force count them.
  * It WILL NOT automatically rehash them.
  */
diff --git a/help.c b/help.c
index 9ff2be6..cf67624 100644
--- a/help.c
+++ b/help.c
@@ -34,7 +34,7 @@
 	{ CAT_foreignscminterface, N_("Interacting with Others") },
 	{ CAT_plumbingmanipulators, N_("Low-level Commands / Manipulators") },
 	{ CAT_plumbinginterrogators, N_("Low-level Commands / Interrogators") },
-	{ CAT_synchingrepositories, N_("Low-level Commands / Synching Repositories") },
+	{ CAT_synchingrepositories, N_("Low-level Commands / Syncing Repositories") },
 	{ CAT_purehelpers, N_("Low-level Commands / Internal Helpers") },
 	{ 0, NULL }
 };
diff --git a/hex.c b/hex.c
index 7850a88..fd7f00c 100644
--- a/hex.c
+++ b/hex.c
@@ -90,11 +90,6 @@
 	return buffer;
 }
 
-char *sha1_to_hex_r(char *buffer, const unsigned char *sha1)
-{
-	return hash_to_hex_algop_r(buffer, sha1, &hash_algos[GIT_HASH_SHA1]);
-}
-
 char *oid_to_hex_r(char *buffer, const struct object_id *oid)
 {
 	return hash_to_hex_algop_r(buffer, oid->hash, the_hash_algo);
@@ -108,11 +103,6 @@
 	return hash_to_hex_algop_r(hexbuffer[bufno], hash, algop);
 }
 
-char *sha1_to_hex(const unsigned char *sha1)
-{
-	return hash_to_hex_algop(sha1, &hash_algos[GIT_HASH_SHA1]);
-}
-
 char *hash_to_hex(const unsigned char *hash)
 {
 	return hash_to_hex_algop(hash, the_hash_algo);
diff --git a/http.c b/http.c
index 027a86d..5f34816 100644
--- a/http.c
+++ b/http.c
@@ -150,7 +150,7 @@
 
 static struct curl_slist *pragma_header;
 static struct curl_slist *no_pragma_header;
-static struct curl_slist *extra_http_headers;
+static struct string_list extra_http_headers = STRING_LIST_INIT_DUP;
 
 static struct active_request_slot *active_queue_head;
 
@@ -414,11 +414,9 @@
 		if (!value) {
 			return config_error_nonbool(var);
 		} else if (!*value) {
-			curl_slist_free_all(extra_http_headers);
-			extra_http_headers = NULL;
+			string_list_clear(&extra_http_headers, 0);
 		} else {
-			extra_http_headers =
-				curl_slist_append(extra_http_headers, value);
+			string_list_append(&extra_http_headers, value);
 		}
 		return 0;
 	}
@@ -1202,8 +1200,7 @@
 #endif
 	curl_global_cleanup();
 
-	curl_slist_free_all(extra_http_headers);
-	extra_http_headers = NULL;
+	string_list_clear(&extra_http_headers, 0);
 
 	curl_slist_free_all(pragma_header);
 	pragma_header = NULL;
@@ -1627,10 +1624,11 @@
 
 struct curl_slist *http_copy_default_headers(void)
 {
-	struct curl_slist *headers = NULL, *h;
+	struct curl_slist *headers = NULL;
+	const struct string_list_item *item;
 
-	for (h = extra_http_headers; h; h = h->next)
-		headers = curl_slist_append(headers, h->data);
+	for_each_string_list_item(item, &extra_http_headers)
+		headers = curl_slist_append(headers, item->string);
 
 	return headers;
 }
diff --git a/kwset.h b/kwset.h
index df99a92..f50ecae 100644
--- a/kwset.h
+++ b/kwset.h
@@ -1,3 +1,6 @@
+#ifndef KWSET_H
+#define KWSET_H
+
 /* This file has been copied from commit e7ac713d^ in the GNU grep git
  * repository. A few small changes have been made to adapt the code to
  * Git.
@@ -59,3 +62,4 @@
 /* Deallocate the given keyword set and all its associated storage. */
 void kwsfree(kwset_t);
 
+#endif /* KWSET_H */
diff --git a/ll-merge.h b/ll-merge.h
index e78973d..aceb1b2 100644
--- a/ll-merge.h
+++ b/ll-merge.h
@@ -7,16 +7,87 @@
 
 #include "xdiff/xdiff.h"
 
+/**
+ *
+ * Calling sequence:
+ * ----------------
+ *
+ * - Prepare a `struct ll_merge_options` to record options.
+ *   If you have no special requests, skip this and pass `NULL`
+ *   as the `opts` parameter to use the default options.
+ *
+ * - Allocate an mmbuffer_t variable for the result.
+ *
+ * - Allocate and fill variables with the file's original content
+ *   and two modified versions (using `read_mmfile`, for example).
+ *
+ * - Call `ll_merge()`.
+ *
+ * - Read the merged content from `result_buf.ptr` and `result_buf.size`.
+ *
+ * - Release buffers when finished.  A simple
+ *   `free(ancestor.ptr); free(ours.ptr); free(theirs.ptr);
+ *   free(result_buf.ptr);` will do.
+ *
+ * If the modifications do not merge cleanly, `ll_merge` will return a
+ * nonzero value and `result_buf` will generally include a description of
+ * the conflict bracketed by markers such as the traditional `<<<<<<<`
+ * and `>>>>>>>`.
+ *
+ * The `ancestor_label`, `our_label`, and `their_label` parameters are
+ * used to label the different sides of a conflict if the merge driver
+ * supports this.
+ */
+
+
 struct index_state;
 
+/**
+ * This describes the set of options the calling program wants to affect
+ * the operation of a low-level (single file) merge.
+ */
 struct ll_merge_options {
+
+	/**
+	 * Behave as though this were part of a merge between common ancestors in
+	 * a recursive merge (merges of binary files may need to be handled
+	 * differently in such cases, for example). If a helper program is
+	 * specified by the `[merge "<driver>"] recursive` configuration, it will
+	 * be used.
+	 */
 	unsigned virtual_ancestor : 1;
-	unsigned variant : 2;	/* favor ours, favor theirs, or union merge */
+
+	/**
+	 * Resolve local conflicts automatically in favor of one side or the other
+	 * (as in 'git merge-file' `--ours`/`--theirs`/`--union`).  Can be `0`,
+	 * `XDL_MERGE_FAVOR_OURS`, `XDL_MERGE_FAVOR_THEIRS`,
+	 * or `XDL_MERGE_FAVOR_UNION`.
+	 */
+	unsigned variant : 2;
+
+	/**
+	 * Resmudge and clean the "base", "theirs" and "ours" files before merging.
+	 * Use this when the merge is likely to have overlapped with a change in
+	 * smudge/clean or end-of-line normalization rules.
+	 */
 	unsigned renormalize : 1;
+
+	/**
+	 * Increase the length of conflict markers so that nested conflicts
+	 * can be differentiated.
+	 */
 	unsigned extra_marker_size;
+
+	/* Extra xpparam_t flags as defined in xdiff/xdiff.h. */
 	long xdl_opts;
 };
 
+/**
+ * Perform a three-way single-file merge in core.  This is a thin wrapper
+ * around `xdl_merge` that takes the path and any merge backend specified in
+ * `.gitattributes` or `.git/info/attributes` into account.
+ * Returns 0 for a clean merge.
+ */
 int ll_merge(mmbuffer_t *result_buf,
 	     const char *path,
 	     mmfile_t *ancestor, const char *ancestor_label,
diff --git a/log-tree.c b/log-tree.c
index 923a299..4e32638 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -449,22 +449,22 @@
 {
 	struct strbuf payload = STRBUF_INIT;
 	struct strbuf signature = STRBUF_INIT;
-	struct strbuf gpg_output = STRBUF_INIT;
+	struct signature_check sigc = { 0 };
 	int status;
 
 	if (parse_signed_commit(commit, &payload, &signature) <= 0)
 		goto out;
 
-	status = verify_signed_buffer(payload.buf, payload.len,
-				      signature.buf, signature.len,
-				      &gpg_output, NULL);
-	if (status && !gpg_output.len)
-		strbuf_addstr(&gpg_output, "No signature\n");
-
-	show_sig_lines(opt, status, gpg_output.buf);
+	status = check_signature(payload.buf, payload.len, signature.buf,
+				 signature.len, &sigc);
+	if (status && sigc.result == 'N')
+		show_sig_lines(opt, status, "No signature\n");
+	else {
+		show_sig_lines(opt, status, sigc.gpg_output);
+		signature_check_clear(&sigc);
+	}
 
  out:
-	strbuf_release(&gpg_output);
 	strbuf_release(&payload);
 	strbuf_release(&signature);
 }
@@ -497,6 +497,7 @@
 	struct object_id oid;
 	struct tag *tag;
 	struct strbuf verify_message;
+	struct signature_check sigc = { 0 };
 	int status, nth;
 	size_t payload_size, gpg_message_offset;
 
@@ -525,12 +526,13 @@
 	status = -1;
 	if (extra->len > payload_size) {
 		/* could have a good signature */
-		if (!verify_signed_buffer(extra->value, payload_size,
-					  extra->value + payload_size,
-					  extra->len - payload_size,
-					  &verify_message, NULL))
+		if (!check_signature(extra->value, payload_size,
+				     extra->value + payload_size,
+				     extra->len - payload_size, &sigc)) {
+			strbuf_addstr(&verify_message, sigc.gpg_output);
+			signature_check_clear(&sigc);
 			status = 0; /* good */
-		else if (verify_message.len <= gpg_message_offset)
+		} else if (verify_message.len <= gpg_message_offset)
 			strbuf_addstr(&verify_message, "No signature\n");
 		/* otherwise we couldn't verify, which is shown as bad */
 	}
@@ -770,7 +772,7 @@
 		opts.use_color = opt->diffopt.use_color;
 		diff_setup_done(&opts);
 		show_range_diff(opt->rdiff1, opt->rdiff2,
-				opt->creation_factor, 1, &opts);
+				opt->creation_factor, 1, &opts, NULL);
 
 		memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff));
 	}
diff --git a/name-hash.c b/name-hash.c
index ceb1d7b..fb526a3 100644
--- a/name-hash.c
+++ b/name-hash.c
@@ -138,7 +138,7 @@
 
 /*
  * Set a minimum number of cache_entries that we will handle per
- * thread and use that to decide how many threads to run (upto
+ * thread and use that to decide how many threads to run (up to
  * the number on the system).
  *
  * For guidance setting the lower per-thread bound, see:
@@ -218,7 +218,7 @@
  * However, the hashmap is going to put items into bucket
  * chains based on their hash values.  Use that to create n
  * mutexes and lock on mutex[bucket(hash) % n].  This will
- * decrease the collision rate by (hopefully) by a factor of n.
+ * decrease the collision rate by (hopefully) a factor of n.
  */
 static void init_dir_mutex(void)
 {
diff --git a/notes.c b/notes.c
index 03e7d0c..0c79964 100644
--- a/notes.c
+++ b/notes.c
@@ -1043,6 +1043,39 @@
 
 void init_display_notes(struct display_notes_opt *opt)
 {
+	memset(opt, 0, sizeof(*opt));
+	opt->use_default_notes = -1;
+}
+
+void enable_default_display_notes(struct display_notes_opt *opt, int *show_notes)
+{
+	opt->use_default_notes = 1;
+	*show_notes = 1;
+}
+
+void enable_ref_display_notes(struct display_notes_opt *opt, int *show_notes,
+		const char *ref) {
+	struct strbuf buf = STRBUF_INIT;
+	strbuf_addstr(&buf, ref);
+	expand_notes_ref(&buf);
+	string_list_append(&opt->extra_notes_refs,
+			strbuf_detach(&buf, NULL));
+	*show_notes = 1;
+}
+
+void disable_display_notes(struct display_notes_opt *opt, int *show_notes)
+{
+	opt->use_default_notes = -1;
+	/* we have been strdup'ing ourselves, so trick
+	 * string_list into free()ing strings */
+	opt->extra_notes_refs.strdup_strings = 1;
+	string_list_clear(&opt->extra_notes_refs, 0);
+	opt->extra_notes_refs.strdup_strings = 0;
+	*show_notes = 0;
+}
+
+void load_display_notes(struct display_notes_opt *opt)
+{
 	char *display_ref_env;
 	int load_config_refs = 0;
 	display_notes_refs.strdup_strings = 1;
diff --git a/notes.h b/notes.h
index 76337f2..c1682c3 100644
--- a/notes.h
+++ b/notes.h
@@ -261,6 +261,26 @@
 };
 
 /*
+ * Initialize a display_notes_opt to its default value.
+ */
+void init_display_notes(struct display_notes_opt *opt);
+
+/*
+ * This family of functions enables or disables the display of notes. In
+ * particular, 'enable_default_display_notes' will display the default notes,
+ * 'enable_ref_display_notes' will display the notes ref 'ref' and
+ * 'disable_display_notes' will disable notes, including those added by previous
+ * invocations of the 'enable_*_display_notes' functions.
+ *
+ * 'show_notes' is a pointer to a boolean which will be set to 1 if notes are
+ * displayed, else 0. It must not be NULL.
+ */
+void enable_default_display_notes(struct display_notes_opt *opt, int *show_notes);
+void enable_ref_display_notes(struct display_notes_opt *opt, int *show_notes,
+		const char *ref);
+void disable_display_notes(struct display_notes_opt *opt, int *show_notes);
+
+/*
  * Load the notes machinery for displaying several notes trees.
  *
  * If 'opt' is not NULL, then it specifies additional settings for the
@@ -272,16 +292,16 @@
  * - extra_notes_refs may contain a list of globs (in the same style
  *   as notes.displayRef) where notes should be loaded from.
  */
-void init_display_notes(struct display_notes_opt *opt);
+void load_display_notes(struct display_notes_opt *opt);
 
 /*
  * Append notes for the given 'object_sha1' from all trees set up by
- * init_display_notes() to 'sb'.
+ * load_display_notes() to 'sb'.
  *
  * If 'raw' is false the note will be indented by 4 places and
  * a 'Notes (refname):' header added.
  *
- * You *must* call init_display_notes() before using this function.
+ * You *must* call load_display_notes() before using this function.
  */
 void format_display_notes(const struct object_id *object_oid,
 			  struct strbuf *sb, const char *output_encoding, int raw);
diff --git a/object-store.h b/object-store.h
index 7f7b3cd..55ee639 100644
--- a/object-store.h
+++ b/object-store.h
@@ -60,6 +60,7 @@
 void odb_clear_loose_cache(struct object_directory *odb);
 
 struct packed_git {
+	struct hashmap_entry packmap_ent;
 	struct packed_git *next;
 	struct list_head mru;
 	struct pack_window *windows;
@@ -88,6 +89,20 @@
 
 struct multi_pack_index;
 
+static inline int pack_map_entry_cmp(const void *unused_cmp_data,
+				     const struct hashmap_entry *entry,
+				     const struct hashmap_entry *entry2,
+				     const void *keydata)
+{
+	const char *key = keydata;
+	const struct packed_git *pg1, *pg2;
+
+	pg1 = container_of(entry, const struct packed_git, packmap_ent);
+	pg2 = container_of(entry2, const struct packed_git, packmap_ent);
+
+	return strcmp(pg1->pack_name, key ? key : pg2->pack_name);
+}
+
 struct raw_object_store {
 	/*
 	 * Set of all object directories; the main directory is first (and
@@ -132,6 +147,12 @@
 	struct list_head packed_git_mru;
 
 	/*
+	 * A map of packfiles to packed_git structs for tracking which
+	 * packs have been loaded already.
+	 */
+	struct hashmap pack_map;
+
+	/*
 	 * A fast, rough count of the number of objects in the repository.
 	 * These two fields are not meant for direct access. Use
 	 * approximate_object_count() instead.
diff --git a/object.c b/object.c
index 3b8b8c5..142ef69 100644
--- a/object.c
+++ b/object.c
@@ -479,6 +479,7 @@
 
 	memset(o, 0, sizeof(*o));
 	INIT_LIST_HEAD(&o->packed_git_mru);
+	hashmap_init(&o->pack_map, pack_map_entry_cmp, NULL, 0);
 	return o;
 }
 
@@ -518,6 +519,8 @@
 	INIT_LIST_HEAD(&o->packed_git_mru);
 	close_object_store(o);
 	o->packed_git = NULL;
+
+	hashmap_free(&o->pack_map);
 }
 
 void parsed_object_pool_clear(struct parsed_object_pool *o)
diff --git a/pack-objects.c b/pack-objects.c
index c6250d7..5e5a3c6 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -119,7 +119,10 @@
 {
 	uint32_t i;
 
-	REALLOC_ARRAY(pack->in_pack, pack->nr_alloc);
+	if (pack->in_pack)
+		BUG("packing_data has already been converted to pack array");
+
+	ALLOC_ARRAY(pack->in_pack, pack->nr_alloc);
 
 	for (i = 0; i < pack->nr_objects; i++)
 		pack->in_pack[i] = oe_in_pack(pack, pack->objects + i);
diff --git a/pack-objects.h b/pack-objects.h
index 6fe6ae5..d3975e0 100644
--- a/pack-objects.h
+++ b/pack-objects.h
@@ -251,12 +251,21 @@
 				  struct object_entry *e,
 				  struct packed_git *p)
 {
-	if (!p->index)
+	if (pack->in_pack_by_idx) {
+		if (p->index) {
+			e->in_pack_idx = p->index;
+			return;
+		}
+		/*
+		 * We're accessing packs by index, but this pack doesn't have
+		 * an index (e.g., because it was added since we created the
+		 * in_pack_by_idx array). Bail to oe_map_new_pack(), which
+		 * will convert us to using the full in_pack array, and then
+		 * fall through to our in_pack handling.
+		 */
 		oe_map_new_pack(pack);
-	if (pack->in_pack_by_idx)
-		e->in_pack_idx = p->index;
-	else
-		pack->in_pack[e - pack->objects] = p;
+	}
+	pack->in_pack[e - pack->objects] = p;
 }
 
 static inline struct object_entry *oe_delta(
diff --git a/packfile.c b/packfile.c
index 355066d..7e7c04e 100644
--- a/packfile.c
+++ b/packfile.c
@@ -510,7 +510,6 @@
 	struct pack_header hdr;
 	unsigned char hash[GIT_MAX_RAWSZ];
 	unsigned char *idx_hash;
-	long fd_flag;
 	ssize_t read_result;
 	const unsigned hashsz = the_hash_algo->rawsz;
 
@@ -554,16 +553,6 @@
 	} else if (p->pack_size != st.st_size)
 		return error("packfile %s size changed", p->pack_name);
 
-	/* We leave these file descriptors open with sliding mmap;
-	 * there is no point keeping them open across exec(), though.
-	 */
-	fd_flag = fcntl(p->pack_fd, F_GETFD, 0);
-	if (fd_flag < 0)
-		return error("cannot determine file descriptor flags");
-	fd_flag |= FD_CLOEXEC;
-	if (fcntl(p->pack_fd, F_SETFD, fd_flag) == -1)
-		return error("cannot set FD_CLOEXEC");
-
 	/* Verify we recognize this pack file format. */
 	read_result = read_in_full(p->pack_fd, &hdr, sizeof(hdr));
 	if (read_result < 0)
@@ -587,9 +576,8 @@
 			     " while index indicates %"PRIu32" objects",
 			     p->pack_name, ntohl(hdr.hdr_entries),
 			     p->num_objects);
-	if (lseek(p->pack_fd, p->pack_size - hashsz, SEEK_SET) == -1)
-		return error("end of packfile %s is unavailable", p->pack_name);
-	read_result = read_in_full(p->pack_fd, hash, hashsz);
+	read_result = pread_in_full(p->pack_fd, hash, hashsz,
+					p->pack_size - hashsz);
 	if (read_result < 0)
 		return error_errno("error reading from %s", p->pack_name);
 	if (read_result != hashsz)
@@ -757,6 +745,9 @@
 
 	pack->next = r->objects->packed_git;
 	r->objects->packed_git = pack;
+
+	hashmap_entry_init(&pack->packmap_ent, strhash(pack->pack_name));
+	hashmap_add(&r->objects->pack_map, &pack->packmap_ent);
 }
 
 void (*report_garbage)(unsigned seen_bits, const char *path);
@@ -856,20 +847,18 @@
 
 	if (strip_suffix_mem(full_name, &base_len, ".idx") &&
 	    !(data->m && midx_contains_pack(data->m, file_name))) {
-		/* Don't reopen a pack we already have. */
-		for (p = data->r->objects->packed_git; p; p = p->next) {
-			size_t len;
-			if (strip_suffix(p->pack_name, ".pack", &len) &&
-			    len == base_len &&
-			    !memcmp(p->pack_name, full_name, len))
-				break;
-		}
+		struct hashmap_entry hent;
+		char *pack_name = xstrfmt("%.*s.pack", (int)base_len, full_name);
+		unsigned int hash = strhash(pack_name);
+		hashmap_entry_init(&hent, hash);
 
-		if (!p) {
+		/* Don't reopen a pack we already have. */
+		if (!hashmap_get(&data->r->objects->pack_map, &hent, pack_name)) {
 			p = add_packed_git(full_name, full_name_len, data->local);
 			if (p)
 				install_packed_git(data->r, p);
 		}
+		free(pack_name);
 	}
 
 	if (!report_garbage)
diff --git a/parse-options-cb.c b/parse-options-cb.c
index 1240a85..c2062ae 100644
--- a/parse-options-cb.c
+++ b/parse-options-cb.c
@@ -161,6 +161,7 @@
 
 struct option *parse_options_dup(const struct option *o)
 {
+	const struct option *orig = o;
 	struct option *opts;
 	int nr = 0;
 
@@ -170,7 +171,7 @@
 	}
 
 	ALLOC_ARRAY(opts, nr + 1);
-	memcpy(opts, o - nr, sizeof(*o) * nr);
+	COPY_ARRAY(opts, orig, nr);
 	memset(opts + nr, 0, sizeof(*opts));
 	opts[nr].type = OPTION_END;
 	return opts;
diff --git a/parse-options.c b/parse-options.c
index b42f54d..60fae3a 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -623,7 +623,7 @@
  * Scan and may produce a new option[] array, which should be used
  * instead of the original 'options'.
  *
- * Right now this is only used to preprocess and substitue
+ * Right now this is only used to preprocess and substitute
  * OPTION_ALIAS.
  */
 static struct option *preprocess_options(struct parse_opt_ctx_t *ctx,
diff --git a/parse-options.h b/parse-options.h
index 38a33a0..fdc0c1c 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -1,6 +1,10 @@
 #ifndef PARSE_OPTIONS_H
 #define PARSE_OPTIONS_H
 
+/**
+ * Refer to Documentation/technical/api-parse-options.txt for the API doc.
+ */
+
 enum parse_opt_type {
 	/* special types */
 	OPTION_END,
@@ -330,5 +334,7 @@
 #define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH("with", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG)
 #define OPT_WITHOUT(v, h) _OPT_CONTAINS_OR_WITH("without", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG)
 #define OPT_CLEANUP(v) OPT_STRING(0, "cleanup", v, N_("mode"), N_("how to strip spaces and #comments from message"))
+#define OPT_PATHSPEC_FROM_FILE(v) OPT_FILENAME(0, "pathspec-from-file", v, N_("read pathspec from file"))
+#define OPT_PATHSPEC_FILE_NUL(v)  OPT_BOOL(0, "pathspec-file-nul", v, N_("with --pathspec-from-file, pathspec elements are separated with NUL character"))
 
 #endif
diff --git a/path.c b/path.c
index e21b00c..a76eec8 100644
--- a/path.c
+++ b/path.c
@@ -11,6 +11,7 @@
 #include "path.h"
 #include "packfile.h"
 #include "object-store.h"
+#include "lockfile.h"
 
 static int get_st_mode_bits(const char *path, int *mode)
 {
@@ -362,9 +363,14 @@
 			      const char *common_dir)
 {
 	char *base = buf->buf + git_dir_len;
+	int has_lock_suffix = strbuf_strip_suffix(buf, LOCK_SUFFIX);
+
 	init_common_trie();
 	if (trie_find(&common_trie, base, check_common, NULL) > 0)
 		replace_dir(buf, git_dir_len, common_dir);
+
+	if (has_lock_suffix)
+		strbuf_addstr(buf, LOCK_SUFFIX);
 }
 
 void report_linked_checkout_garbage(void)
@@ -1328,37 +1334,77 @@
 	}
 }
 
-static int only_spaces_and_periods(const char *path, size_t len, size_t skip)
-{
-	if (len < skip)
-		return 0;
-	len -= skip;
-	path += skip;
-	while (len-- > 0) {
-		char c = *(path++);
-		if (c != ' ' && c != '.')
-			return 0;
-	}
-	return 1;
-}
-
+/*
+ * On NTFS, we need to be careful to disallow certain synonyms of the `.git/`
+ * directory:
+ *
+ * - For historical reasons, file names that end in spaces or periods are
+ *   automatically trimmed. Therefore, `.git . . ./` is a valid way to refer
+ *   to `.git/`.
+ *
+ * - For other historical reasons, file names that do not conform to the 8.3
+ *   format (up to eight characters for the basename, three for the file
+ *   extension, certain characters not allowed such as `+`, etc) are associated
+ *   with a so-called "short name", at least on the `C:` drive by default.
+ *   Which means that `git~1/` is a valid way to refer to `.git/`.
+ *
+ *   Note: Technically, `.git/` could receive the short name `git~2` if the
+ *   short name `git~1` were already used. In Git, however, we guarantee that
+ *   `.git` is the first item in a directory, therefore it will be associated
+ *   with the short name `git~1` (unless short names are disabled).
+ *
+ * - For yet other historical reasons, NTFS supports so-called "Alternate Data
+ *   Streams", i.e. metadata associated with a given file, referred to via
+ *   `<filename>:<stream-name>:<stream-type>`. There exists a default stream
+ *   type for directories, allowing `.git/` to be accessed via
+ *   `.git::$INDEX_ALLOCATION/`.
+ *
+ * When this function returns 1, it indicates that the specified file/directory
+ * name refers to a `.git` file or directory, or to any of these synonyms, and
+ * Git should therefore not track it.
+ *
+ * For performance reasons, _all_ Alternate Data Streams of `.git/` are
+ * forbidden, not just `::$INDEX_ALLOCATION`.
+ *
+ * This function is intended to be used by `git fsck` even on platforms where
+ * the backslash is a regular filename character, therefore it needs to handle
+ * backlash characters in the provided `name` specially: they are interpreted
+ * as directory separators.
+ */
 int is_ntfs_dotgit(const char *name)
 {
-	size_t len;
+	char c;
 
-	for (len = 0; ; len++)
-		if (!name[len] || name[len] == '\\' || is_dir_sep(name[len])) {
-			if (only_spaces_and_periods(name, len, 4) &&
-					!strncasecmp(name, ".git", 4))
-				return 1;
-			if (only_spaces_and_periods(name, len, 5) &&
-					!strncasecmp(name, "git~1", 5))
-				return 1;
-			if (name[len] != '\\')
-				return 0;
-			name += len + 1;
-			len = -1;
-		}
+	/*
+	 * Note that when we don't find `.git` or `git~1` we end up with `name`
+	 * advanced partway through the string. That's okay, though, as we
+	 * return immediately in those cases, without looking at `name` any
+	 * further.
+	 */
+	c = *(name++);
+	if (c == '.') {
+		/* .git */
+		if (((c = *(name++)) != 'g' && c != 'G') ||
+		    ((c = *(name++)) != 'i' && c != 'I') ||
+		    ((c = *(name++)) != 't' && c != 'T'))
+			return 0;
+	} else if (c == 'g' || c == 'G') {
+		/* git ~1 */
+		if (((c = *(name++)) != 'i' && c != 'I') ||
+		    ((c = *(name++)) != 't' && c != 'T') ||
+		    *(name++) != '~' ||
+		    *(name++) != '1')
+			return 0;
+	} else
+		return 0;
+
+	for (;;) {
+		c = *(name++);
+		if (!c || c == '\\' || c == '/' || c == ':')
+			return 1;
+		if (c != '.' && c != ' ')
+			return 0;
+	}
 }
 
 static int is_ntfs_dot_generic(const char *name,
@@ -1374,7 +1420,7 @@
 only_spaces_and_periods:
 		for (;;) {
 			char c = name[i++];
-			if (!c)
+			if (!c || c == ':')
 				return 1;
 			if (c != ' ' && c != '.')
 				return 0;
diff --git a/pathspec.c b/pathspec.c
index 12c2b32..128f27f 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -3,6 +3,8 @@
 #include "dir.h"
 #include "pathspec.h"
 #include "attr.h"
+#include "argv-array.h"
+#include "quote.h"
 
 /*
  * Finds which of the given pathspecs match items in the index.
@@ -613,6 +615,42 @@
 	}
 }
 
+void parse_pathspec_file(struct pathspec *pathspec, unsigned magic_mask,
+			 unsigned flags, const char *prefix,
+			 const char *file, int nul_term_line)
+{
+	struct argv_array parsed_file = ARGV_ARRAY_INIT;
+	strbuf_getline_fn getline_fn = nul_term_line ? strbuf_getline_nul :
+						       strbuf_getline;
+	struct strbuf buf = STRBUF_INIT;
+	struct strbuf unquoted = STRBUF_INIT;
+	FILE *in;
+
+	if (!strcmp(file, "-"))
+		in = stdin;
+	else
+		in = xfopen(file, "r");
+
+	while (getline_fn(&buf, in) != EOF) {
+		if (!nul_term_line && buf.buf[0] == '"') {
+			strbuf_reset(&unquoted);
+			if (unquote_c_style(&unquoted, buf.buf, NULL))
+				die(_("line is badly quoted: %s"), buf.buf);
+			strbuf_swap(&buf, &unquoted);
+		}
+		argv_array_push(&parsed_file, buf.buf);
+		strbuf_reset(&buf);
+	}
+
+	strbuf_release(&unquoted);
+	strbuf_release(&buf);
+	if (in != stdin)
+		fclose(in);
+
+	parse_pathspec(pathspec, magic_mask, flags, prefix, parsed_file.argv);
+	argv_array_clear(&parsed_file);
+}
+
 void copy_pathspec(struct pathspec *dst, const struct pathspec *src)
 {
 	int i, j;
diff --git a/pathspec.h b/pathspec.h
index 1c18a2c..454ce36 100644
--- a/pathspec.h
+++ b/pathspec.h
@@ -22,6 +22,11 @@
 
 #define PATHSPEC_ONESTAR 1	/* the pathspec pattern satisfies GFNM_ONESTAR */
 
+/**
+ * See glossary-context.txt for the syntax of pathspec.
+ * In memory, a pathspec set is represented by "struct pathspec" and is
+ * prepared by parse_pathspec().
+ */
 struct pathspec {
 	int nr;
 	unsigned int has_wildcard:1;
@@ -73,18 +78,56 @@
  */
 #define PATHSPEC_LITERAL_PATH (1<<6)
 
-/*
+/**
  * Given command line arguments and a prefix, convert the input to
  * pathspec. die() if any magic in magic_mask is used.
  *
  * Any arguments used are copied. It is safe for the caller to modify
  * or free 'prefix' and 'args' after calling this function.
+ *
+ * - magic_mask specifies what features that are NOT supported by the following
+ * code. If a user attempts to use such a feature, parse_pathspec() can reject
+ * it early.
+ *
+ * - flags specifies other things that the caller wants parse_pathspec to
+ * perform.
+ *
+ * - prefix and args come from cmd_* functions
+ *
+ * parse_pathspec() helps catch unsupported features and reject them politely.
+ * At a lower level, different pathspec-related functions may not support the
+ * same set of features. Such pathspec-sensitive functions are guarded with
+ * GUARD_PATHSPEC(), which will die in an unfriendly way when an unsupported
+ * feature is requested.
+ *
+ * The command designers are supposed to make sure that GUARD_PATHSPEC() never
+ * dies. They have to make sure all unsupported features are caught by
+ * parse_pathspec(), not by GUARD_PATHSPEC. grepping GUARD_PATHSPEC() should
+ * give the designers all pathspec-sensitive codepaths and what features they
+ * support.
+ *
+ * A similar process is applied when a new pathspec magic is added. The designer
+ * lifts the GUARD_PATHSPEC restriction in the functions that support the new
+ * magic. At the same time (s)he has to make sure this new feature will be
+ * caught at parse_pathspec() in commands that cannot handle the new magic in
+ * some cases. grepping parse_pathspec() should help.
  */
 void parse_pathspec(struct pathspec *pathspec,
 		    unsigned magic_mask,
 		    unsigned flags,
 		    const char *prefix,
 		    const char **args);
+/*
+ * Same as parse_pathspec() but uses file as input.
+ * When 'file' is exactly "-" it uses 'stdin' instead.
+ */
+void parse_pathspec_file(struct pathspec *pathspec,
+			 unsigned magic_mask,
+			 unsigned flags,
+			 const char *prefix,
+			 const char *file,
+			 int nul_term_line);
+
 void copy_pathspec(struct pathspec *dst, const struct pathspec *src);
 void clear_pathspec(struct pathspec *);
 
diff --git a/perl/Git.pm b/perl/Git.pm
index 62c472e..54c9ed0 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -563,7 +563,7 @@
 Query user C<PROMPT> and return answer from user.
 
 Honours GIT_ASKPASS and SSH_ASKPASS environment variables for querying
-the user. If no *_ASKPASS variable is set or an error occoured,
+the user. If no *_ASKPASS variable is set or an error occurred,
 the terminal is tried as a fallback.
 If C<ISPASSWORD> is set and true, the terminal disables echo.
 
diff --git a/pkt-line.h b/pkt-line.h
index 5c62015..fef3a0d 100644
--- a/pkt-line.h
+++ b/pkt-line.h
@@ -77,7 +77,7 @@
 /*
  * Read a packetized line into a buffer like the 'packet_read()' function but
  * returns an 'enum packet_read_status' which indicates the status of the read.
- * The number of bytes read will be assigined to *pktlen if the status of the
+ * The number of bytes read will be assigned to *pktlen if the status of the
  * read was 'PACKET_READ_NORMAL'.
  */
 enum packet_read_status {
diff --git a/pretty.c b/pretty.c
index 93eb6e8..305e903 100644
--- a/pretty.c
+++ b/pretty.c
@@ -20,6 +20,7 @@
 	int is_tformat;
 	int expand_tabs_in_log;
 	int is_alias;
+	enum date_mode_type default_date_mode_type;
 	const char *user_format;
 } *commit_formats;
 static size_t builtin_formats_len;
@@ -97,7 +98,9 @@
 		{ "mboxrd",	CMIT_FMT_MBOXRD,	0,	0 },
 		{ "fuller",	CMIT_FMT_FULLER,	0,	8 },
 		{ "full",	CMIT_FMT_FULL,		0,	8 },
-		{ "oneline",	CMIT_FMT_ONELINE,	1,	0 }
+		{ "oneline",	CMIT_FMT_ONELINE,	1,	0 },
+		{ "reference",	CMIT_FMT_USERFORMAT,	1,	0,
+			0, DATE_SHORT, "%C(auto)%h (%s, %ad)" },
 		/*
 		 * Please update $__git_log_pretty_formats in
 		 * git-completion.bash when you add new formats.
@@ -181,6 +184,8 @@
 	rev->commit_format = commit_format->format;
 	rev->use_terminator = commit_format->is_tformat;
 	rev->expand_tabs_in_log_default = commit_format->expand_tabs_in_log;
+	if (!rev->date_mode_explicit && commit_format->default_date_mode_type)
+		rev->date_mode.type = commit_format->default_date_mode_type;
 	if (commit_format->format == CMIT_FMT_USERFORMAT) {
 		save_user_format(rev, commit_format->user_format,
 				 commit_format->is_tformat);
@@ -738,6 +743,9 @@
 	case 'I':	/* date, ISO 8601 strict */
 		strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(ISO8601_STRICT)));
 		return placeholder_len;
+	case 's':
+		strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(SHORT)));
+		return placeholder_len;
 	}
 
 skip:
@@ -1617,14 +1625,14 @@
 				const char *format, struct strbuf *sb,
 				const struct pretty_print_context *pretty_ctx)
 {
-	struct format_commit_context context;
+	struct format_commit_context context = {
+		.commit = commit,
+		.pretty_ctx = pretty_ctx,
+		.wrap_start = sb->len
+	};
 	const char *output_enc = pretty_ctx->output_encoding;
 	const char *utf8 = "UTF-8";
 
-	memset(&context, 0, sizeof(context));
-	context.commit = commit;
-	context.pretty_ctx = pretty_ctx;
-	context.wrap_start = sb->len;
 	/*
 	 * convert a commit message to UTF-8 first
 	 * as far as 'format_commit_item' assumes it in UTF-8
diff --git a/progress.c b/progress.c
index 0063559..19805ac 100644
--- a/progress.c
+++ b/progress.c
@@ -14,6 +14,7 @@
 #include "strbuf.h"
 #include "trace.h"
 #include "utf8.h"
+#include "config.h"
 
 #define TP_IDX_MAX      8
 
@@ -267,9 +268,19 @@
 	return progress;
 }
 
+static int get_default_delay(void)
+{
+	static int delay_in_secs = -1;
+
+	if (delay_in_secs < 0)
+		delay_in_secs = git_env_ulong("GIT_PROGRESS_DELAY", 2);
+
+	return delay_in_secs;
+}
+
 struct progress *start_delayed_progress(const char *title, uint64_t total)
 {
-	return start_progress_delay(title, total, 2, 0);
+	return start_progress_delay(title, total, get_default_delay(), 0);
 }
 
 struct progress *start_progress(const char *title, uint64_t total)
@@ -294,7 +305,7 @@
 struct progress *start_delayed_sparse_progress(const char *title,
 					       uint64_t total)
 {
-	return start_progress_delay(title, total, 2, 1);
+	return start_progress_delay(title, total, get_default_delay(), 1);
 }
 
 static void finish_if_sparse(struct progress *progress)
diff --git a/promisor-remote.c b/promisor-remote.c
index 9bd5b79..9f338c9 100644
--- a/promisor-remote.c
+++ b/promisor-remote.c
@@ -16,10 +16,8 @@
 {
 	struct remote *remote;
 	struct transport *transport;
-	int original_fetch_if_missing = fetch_if_missing;
 	int res;
 
-	fetch_if_missing = 0;
 	remote = remote_get(remote_name);
 	if (!remote->url[0])
 		die(_("Remote with no URL"));
@@ -28,7 +26,6 @@
 	transport_set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
 	transport_set_option(transport, TRANS_OPT_NO_DEPENDENTS, "1");
 	res = transport_fetch_refs(transport, ref);
-	fetch_if_missing = original_fetch_if_missing;
 
 	return res;
 }
diff --git a/range-diff.c b/range-diff.c
index 7fed5a3..f745567 100644
--- a/range-diff.c
+++ b/range-diff.c
@@ -40,7 +40,8 @@
  * Reads the patches into a string list, with the `util` field being populated
  * as struct object_id (will need to be free()d).
  */
-static int read_patches(const char *range, struct string_list *list)
+static int read_patches(const char *range, struct string_list *list,
+			const struct argv_array *other_arg)
 {
 	struct child_process cp = CHILD_PROCESS_INIT;
 	struct strbuf buf = STRBUF_INIT, contents = STRBUF_INIT;
@@ -61,8 +62,11 @@
 			"--output-indicator-new=>",
 			"--output-indicator-old=<",
 			"--output-indicator-context=#",
-			"--no-abbrev-commit", range,
+			"--no-abbrev-commit",
 			NULL);
+	if (other_arg)
+		argv_array_pushv(&cp.args, other_arg->argv);
+	argv_array_push(&cp.args, range);
 	cp.out = -1;
 	cp.no_stdin = 1;
 	cp.git_cmd = 1;
@@ -144,6 +148,12 @@
 				strbuf_addstr(&buf, line);
 				strbuf_addstr(&buf, "\n\n");
 				strbuf_addstr(&buf, " ## Commit message ##\n");
+			} else if (starts_with(line, "Notes") &&
+				   line[strlen(line) - 1] == ':') {
+				strbuf_addstr(&buf, "\n\n");
+				/* strip the trailing colon */
+				strbuf_addf(&buf, " ## %.*s ##\n",
+					    (int)(strlen(line) - 1), line);
 			} else if (starts_with(line, "    ")) {
 				p = line + len - 2;
 				while (isspace(*p) && p >= line)
@@ -496,16 +506,17 @@
 
 int show_range_diff(const char *range1, const char *range2,
 		    int creation_factor, int dual_color,
-		    struct diff_options *diffopt)
+		    const struct diff_options *diffopt,
+		    const struct argv_array *other_arg)
 {
 	int res = 0;
 
 	struct string_list branch1 = STRING_LIST_INIT_DUP;
 	struct string_list branch2 = STRING_LIST_INIT_DUP;
 
-	if (read_patches(range1, &branch1))
+	if (read_patches(range1, &branch1, other_arg))
 		res = error(_("could not parse log for '%s'"), range1);
-	if (!res && read_patches(range2, &branch2))
+	if (!res && read_patches(range2, &branch2, other_arg))
 		res = error(_("could not parse log for '%s'"), range2);
 
 	if (!res) {
diff --git a/range-diff.h b/range-diff.h
index 08a50b6..e11976d 100644
--- a/range-diff.h
+++ b/range-diff.h
@@ -2,16 +2,18 @@
 #define RANGE_DIFF_H
 
 #include "diff.h"
+#include "argv-array.h"
 
 #define RANGE_DIFF_CREATION_FACTOR_DEFAULT 60
 
 /*
- * Compare series of commmits in RANGE1 and RANGE2, and emit to the
+ * Compare series of commits in RANGE1 and RANGE2, and emit to the
  * standard output.  NULL can be passed to DIFFOPT to use the built-in
  * default.
  */
 int show_range_diff(const char *range1, const char *range2,
 		    int creation_factor, int dual_color,
-		    struct diff_options *diffopt);
+		    const struct diff_options *diffopt,
+		    const struct argv_array *other_arg);
 
 #endif
diff --git a/read-cache.c b/read-cache.c
index 133f790..737916e 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -964,6 +964,9 @@
 	if (has_dos_drive_prefix(path))
 		return 0;
 
+	if (!is_valid_path(path))
+		return 0;
+
 	goto inside;
 	for (;;) {
 		if (!c)
@@ -991,7 +994,15 @@
 			if ((c == '.' && !verify_dotfile(path, mode)) ||
 			    is_dir_sep(c) || c == '\0')
 				return 0;
+		} else if (c == '\\' && protect_ntfs) {
+			if (is_ntfs_dotgit(path))
+				return 0;
+			if (S_ISLNK(mode)) {
+				if (is_ntfs_dotgitmodules(path))
+					return 0;
+			}
 		}
+
 		c = *path++;
 	}
 }
@@ -1267,6 +1278,11 @@
 	int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;
 	int new_only = option & ADD_CACHE_NEW_ONLY;
 
+#ifdef GIT_WINDOWS_NATIVE
+	if (protect_ntfs && strchr(ce->name, '\\'))
+		return error(_("filename in tree entry contains backslash: '%s'"), ce->name);
+#endif
+
 	if (!(option & ADD_CACHE_KEEP_CACHE_TREE))
 		cache_tree_invalidate_path(istate, ce->name);
 
@@ -1790,7 +1806,7 @@
 		const unsigned char *cp = (const unsigned char *)name;
 		size_t strip_len, previous_len;
 
-		/* If we're at the begining of a block, ignore the previous name */
+		/* If we're at the beginning of a block, ignore the previous name */
 		strip_len = decode_varint(&cp);
 		if (previous_ce) {
 			previous_len = previous_ce->ce_namelen;
diff --git a/refs.h b/refs.h
index 730d05a..545029c 100644
--- a/refs.h
+++ b/refs.h
@@ -310,19 +310,35 @@
 int refs_for_each_remote_ref(struct ref_store *refs,
 			     each_ref_fn fn, void *cb_data);
 
+/* just iterates the head ref. */
 int head_ref(each_ref_fn fn, void *cb_data);
+
+/* iterates all refs. */
 int for_each_ref(each_ref_fn fn, void *cb_data);
+
+/**
+ * iterates all refs which have a defined prefix and strips that prefix from
+ * the passed variable refname.
+ */
 int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data);
+
 int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
 			     each_ref_fn fn, void *cb_data,
 			     unsigned int broken);
 int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data,
 			unsigned int broken);
+
+/**
+ * iterate refs from the respective area.
+ */
 int for_each_tag_ref(each_ref_fn fn, void *cb_data);
 int for_each_branch_ref(each_ref_fn fn, void *cb_data);
 int for_each_remote_ref(each_ref_fn fn, void *cb_data);
 int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data);
+
+/* iterates all refs that match the specified glob pattern. */
 int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);
+
 int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
 			 const char *prefix, void *cb_data);
 
@@ -791,6 +807,41 @@
 int ref_storage_backend_exists(const char *name);
 
 struct ref_store *get_main_ref_store(struct repository *r);
+
+/**
+ * Submodules
+ * ----------
+ *
+ * If you want to iterate the refs of a submodule you first need to add the
+ * submodules object database. You can do this by a code-snippet like
+ * this:
+ *
+ * 	const char *path = "path/to/submodule"
+ * 	if (add_submodule_odb(path))
+ * 		die("Error submodule '%s' not populated.", path);
+ *
+ * `add_submodule_odb()` will return zero on success. If you
+ * do not do this you will get an error for each ref that it does not point
+ * to a valid object.
+ *
+ * Note: As a side-effect of this you cannot safely assume that all
+ * objects you lookup are available in superproject. All submodule objects
+ * will be available the same way as the superprojects objects.
+ *
+ * Example:
+ * --------
+ *
+ * ----
+ * static int handle_remote_ref(const char *refname,
+ * 		const unsigned char *sha1, int flags, void *cb_data)
+ * {
+ * 	struct strbuf *output = cb_data;
+ * 	strbuf_addf(output, "%s\n", refname);
+ * 	return 0;
+ * }
+ *
+ */
+
 /*
  * Return the ref_store instance for the specified submodule. For the
  * main repository, use submodule==NULL; such a call cannot fail. For
diff --git a/refs/files-backend.c b/refs/files-backend.c
index d60767a..0ea66a2 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1327,7 +1327,7 @@
 {
 	struct files_ref_store *refs =
 		files_downcast(ref_store, REF_STORE_WRITE, "rename_ref");
-	struct object_id oid, orig_oid;
+	struct object_id orig_oid;
 	int flag = 0, logmoved = 0;
 	struct ref_lock *lock;
 	struct stat loginfo;
@@ -1395,7 +1395,7 @@
 	 */
 	if (!copy && !refs_read_ref_full(&refs->base, newrefname,
 				RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
-				&oid, NULL) &&
+				NULL, NULL) &&
 	    refs_delete_ref(&refs->base, NULL, newrefname,
 			    NULL, REF_NO_DEREF)) {
 		if (errno == EISDIR) {
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index f2d8c01..ff2436c 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -262,7 +262,7 @@
  * after calling ref_iterator_advance() again or calling
  * ref_iterator_abort(), you must make a copy. When the iteration has
  * been exhausted, ref_iterator_advance() releases any resources
- * assocated with the iteration, frees the ref_iterator object, and
+ * associated with the iteration, frees the ref_iterator object, and
  * returns ITER_DONE. If you want to abort the iteration early, call
  * ref_iterator_abort(), which also frees the ref_iterator object and
  * any associated resources. If there was an internal error advancing
diff --git a/refspec.h b/refspec.h
index 9b6e64a..3f2bd4a 100644
--- a/refspec.h
+++ b/refspec.h
@@ -20,6 +20,22 @@
 #define REFSPEC_INIT_FETCH { .fetch = REFSPEC_FETCH }
 #define REFSPEC_INIT_PUSH { .fetch = REFSPEC_PUSH }
 
+/**
+ * A struct refspec holds the parsed interpretation of a refspec.  If it will
+ * force updates (starts with a '+'), force is true.  If it is a pattern
+ * (sides end with '*') pattern is true.  src and dest are the two sides
+ * (including '*' characters if present); if there is only one side, it is src,
+ * and dst is NULL; if sides exist but are empty (i.e., the refspec either
+ * starts or ends with ':'), the corresponding side is "".
+ *
+ * An array of strings can be parsed into an array of struct refspecs using
+ * parse_fetch_refspec() or parse_push_refspec().
+ *
+ * remote_find_tracking(), given a remote and a struct refspec with either src
+ * or dst filled out, will fill out the other such that the result is in the
+ * "fetch" specification for the remote (note that this evaluates patterns and
+ * returns a single result).
+ */
 struct refspec {
 	struct refspec_item *items;
 	int alloc;
diff --git a/remote.h b/remote.h
index 0e1d2b2..b134cc2 100644
--- a/remote.h
+++ b/remote.h
@@ -6,6 +6,14 @@
 #include "hashmap.h"
 #include "refspec.h"
 
+/**
+ * The API gives access to the configuration related to remotes. It handles
+ * all three configuration mechanisms historically and currently used by Git,
+ * and presents the information in a uniform fashion. Note that the code also
+ * handles plain URLs without any configuration, giving them just the default
+ * information.
+ */
+
 enum {
 	REMOTE_UNCONFIGURED = 0,
 	REMOTE_CONFIG,
@@ -16,16 +24,22 @@
 struct remote {
 	struct hashmap_entry ent;
 
+	/* The user's nickname for the remote */
 	const char *name;
+
 	int origin, configured_in_repo;
 
 	const char *foreign_vcs;
 
+	/* An array of all of the url_nr URLs configured for the remote */
 	const char **url;
+
 	int url_nr;
 	int url_alloc;
 
+	/* An array of all of the pushurl_nr push URLs configured for the remote */
 	const char **pushurl;
+
 	int pushurl_nr;
 	int pushurl_alloc;
 
@@ -34,32 +48,47 @@
 	struct refspec fetch;
 
 	/*
+	 * The setting for whether to fetch tags (as a separate rule from the
+	 * configured refspecs);
 	 * -1 to never fetch tags
 	 * 0 to auto-follow tags on heuristic (default)
 	 * 1 to always auto-follow tags
 	 * 2 to always fetch tags
 	 */
 	int fetch_tags;
+
 	int skip_default_update;
 	int mirror;
 	int prune;
 	int prune_tags;
 
+	/**
+	 * The configured helper programs to run on the remote side, for
+	 * Git-native protocols.
+	 */
 	const char *receivepack;
 	const char *uploadpack;
 
-	/*
-	 * for curl remotes only
-	 */
+	/* The proxy to use for curl (http, https, ftp, etc.) URLs. */
 	char *http_proxy;
+
+	/* The method used for authenticating against `http_proxy`. */
 	char *http_proxy_authmethod;
 };
 
+/**
+ * struct remotes can be found by name with remote_get().
+ * remote_get(NULL) will return the default remote, given the current branch
+ * and configuration.
+ */
 struct remote *remote_get(const char *name);
+
 struct remote *pushremote_get(const char *name);
 int remote_is_configured(struct remote *remote, int in_repo);
 
 typedef int each_remote_fn(struct remote *remote, void *priv);
+
+/* iterate through struct remotes */
 int for_each_remote(each_remote_fn fn, void *priv);
 
 int remote_has_url(struct remote *remote, const char *url);
@@ -194,16 +223,36 @@
  */
 int remote_find_tracking(struct remote *remote, struct refspec_item *refspec);
 
+/**
+ * struct branch holds the configuration for a branch. It can be looked up with
+ * branch_get(name) for "refs/heads/{name}", or with branch_get(NULL) for HEAD.
+ */
 struct branch {
+
+	/* The short name of the branch. */
 	const char *name;
+
+	/* The full path for the branch ref. */
 	const char *refname;
 
+	/* The name of the remote listed in the configuration. */
 	const char *remote_name;
+
 	const char *pushremote_name;
 
+	/* An array of the "merge" lines in the configuration. */
 	const char **merge_name;
+
+	/**
+	 * An array of the struct refspecs used for the merge lines. That is,
+	 * merge[i]->dst is a local tracking ref which should be merged into this
+	 * branch by default.
+	 */
 	struct refspec_item **merge;
+
+	/* The number of merge configurations */
 	int merge_nr;
+
 	int merge_alloc;
 
 	const char *push_tracking_ref;
@@ -215,7 +264,9 @@
 const char *remote_ref_for_branch(struct branch *branch, int for_push,
 				  int *explicit);
 
+/* returns true if the given branch has merge configuration given. */
 int branch_has_merge_config(struct branch *branch);
+
 int branch_merge_matches(struct branch *, int n, const char *);
 
 /**
diff --git a/repository.c b/repository.c
index 682c239..a4174dd 100644
--- a/repository.c
+++ b/repository.c
@@ -200,9 +200,9 @@
 
 	if (repo_init(subrepo, gitdir.buf, worktree.buf)) {
 		/*
-		 * If initilization fails then it may be due to the submodule
+		 * If initialization fails then it may be due to the submodule
 		 * not being populated in the superproject's worktree.  Instead
-		 * we can try to initilize the submodule by finding it's gitdir
+		 * we can try to initialize the submodule by finding it's gitdir
 		 * in the superproject's 'modules' directory.  In this case the
 		 * submodule would not have a worktree.
 		 */
diff --git a/repository.h b/repository.h
index fe42197..040057d 100644
--- a/repository.h
+++ b/repository.h
@@ -172,7 +172,7 @@
  * be allocated if needed.
  *
  * Return the number of index entries in the populated index or a value less
- * than zero if an error occured.  If the repository's index has already been
+ * than zero if an error occurred.  If the repository's index has already been
  * populated then the number of entries will simply be returned.
  */
 int repo_read_index(struct repository *repo);
diff --git a/rerere.c b/rerere.c
index 3e51fdf..9281131 100644
--- a/rerere.c
+++ b/rerere.c
@@ -431,7 +431,7 @@
  * and NUL concatenated together.
  *
  * Return 1 if conflict hunks are found, 0 if there are no conflict
- * hunks and -1 if an error occured.
+ * hunks and -1 if an error occurred.
  */
 static int handle_path(unsigned char *hash, struct rerere_io *io, int marker_size)
 {
diff --git a/revision.c b/revision.c
index 0e39b2b..8136929 100644
--- a/revision.c
+++ b/revision.c
@@ -1668,7 +1668,7 @@
 		revs->diffopt.prefix_length = strlen(prefix);
 	}
 
-	revs->notes_opt.use_default_notes = -1;
+	init_display_notes(&revs->notes_opt);
 }
 
 static void add_pending_commit_list(struct rev_info *revs,
@@ -2203,9 +2203,8 @@
 			die("'%s': not a non-negative integer", arg);
 		revs->expand_tabs_in_log = val;
 	} else if (!strcmp(arg, "--show-notes") || !strcmp(arg, "--notes")) {
-		revs->show_notes = 1;
+		enable_default_display_notes(&revs->notes_opt, &revs->show_notes);
 		revs->show_notes_given = 1;
-		revs->notes_opt.use_default_notes = 1;
 	} else if (!strcmp(arg, "--show-signature")) {
 		revs->show_signature = 1;
 	} else if (!strcmp(arg, "--no-show-signature")) {
@@ -2220,25 +2219,14 @@
 		revs->track_first_time = 1;
 	} else if (skip_prefix(arg, "--show-notes=", &optarg) ||
 		   skip_prefix(arg, "--notes=", &optarg)) {
-		struct strbuf buf = STRBUF_INIT;
-		revs->show_notes = 1;
-		revs->show_notes_given = 1;
 		if (starts_with(arg, "--show-notes=") &&
 		    revs->notes_opt.use_default_notes < 0)
 			revs->notes_opt.use_default_notes = 1;
-		strbuf_addstr(&buf, optarg);
-		expand_notes_ref(&buf);
-		string_list_append(&revs->notes_opt.extra_notes_refs,
-				   strbuf_detach(&buf, NULL));
-	} else if (!strcmp(arg, "--no-notes")) {
-		revs->show_notes = 0;
+		enable_ref_display_notes(&revs->notes_opt, &revs->show_notes, optarg);
 		revs->show_notes_given = 1;
-		revs->notes_opt.use_default_notes = -1;
-		/* we have been strdup'ing ourselves, so trick
-		 * string_list into free()ing strings */
-		revs->notes_opt.extra_notes_refs.strdup_strings = 1;
-		string_list_clear(&revs->notes_opt.extra_notes_refs, 0);
-		revs->notes_opt.extra_notes_refs.strdup_strings = 0;
+	} else if (!strcmp(arg, "--no-notes")) {
+		disable_display_notes(&revs->notes_opt, &revs->show_notes);
+		revs->show_notes_given = 1;
 	} else if (!strcmp(arg, "--standard-notes")) {
 		revs->show_notes_given = 1;
 		revs->notes_opt.use_default_notes = 1;
@@ -3098,7 +3086,7 @@
 
 void reset_revision_walk(void)
 {
-	clear_object_flags(SEEN | ADDED | SHOWN);
+	clear_object_flags(SEEN | ADDED | SHOWN | TOPO_WALK_EXPLORED | TOPO_WALK_INDEGREE);
 }
 
 static int mark_uninteresting(const struct object_id *oid,
@@ -3211,10 +3199,26 @@
 		indegree_walk_step(revs);
 }
 
+static void reset_topo_walk(struct rev_info *revs)
+{
+	struct topo_walk_info *info = revs->topo_walk_info;
+
+	clear_prio_queue(&info->explore_queue);
+	clear_prio_queue(&info->indegree_queue);
+	clear_prio_queue(&info->topo_queue);
+	clear_indegree_slab(&info->indegree);
+	clear_author_date_slab(&info->author_date);
+
+	FREE_AND_NULL(revs->topo_walk_info);
+}
+
 static void init_topo_walk(struct rev_info *revs)
 {
 	struct topo_walk_info *info;
 	struct commit_list *list;
+	if (revs->topo_walk_info)
+		reset_topo_walk(revs);
+
 	revs->topo_walk_info = xmalloc(sizeof(struct topo_walk_info));
 	info = revs->topo_walk_info;
 	memset(info, 0, sizeof(struct topo_walk_info));
@@ -3944,7 +3948,7 @@
 	return c;
 }
 
-char *get_revision_mark(const struct rev_info *revs, const struct commit *commit)
+const char *get_revision_mark(const struct rev_info *revs, const struct commit *commit)
 {
 	if (commit->object.flags & BOUNDARY)
 		return "-";
@@ -3966,7 +3970,7 @@
 
 void put_revision_mark(const struct rev_info *revs, const struct commit *commit)
 {
-	char *mark = get_revision_mark(revs, commit);
+	const char *mark = get_revision_mark(revs, commit);
 	if (!strlen(mark))
 		return;
 	fputs(mark, stdout);
diff --git a/revision.h b/revision.h
index 4134dc6..475f048 100644
--- a/revision.h
+++ b/revision.h
@@ -9,6 +9,19 @@
 #include "diff.h"
 #include "commit-slab-decl.h"
 
+/**
+ * The revision walking API offers functions to build a list of revisions
+ * and then iterate over that list.
+ *
+ * Calling sequence
+ * ----------------
+ *
+ * The walking API has a given calling sequence: first you need to initialize
+ * a rev_info structure, then add revisions to control what kind of revision
+ * list do you want to get, finally you can iterate over the revision list.
+ *
+ */
+
 /* Remember to update object flag allocation in object.h */
 #define SEEN		(1u<<0)
 #define UNINTERESTING   (1u<<1)
@@ -177,10 +190,10 @@
 			always_show_header:1;
 
 	/* Format info */
+	int		show_notes;
 	unsigned int	shown_one:1,
 			shown_dashes:1,
 			show_merge:1,
-			show_notes:1,
 			show_notes_given:1,
 			show_signature:1,
 			pretty_given:1,
@@ -306,11 +319,29 @@
 #ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
 #define init_revisions(revs, prefix) repo_init_revisions(the_repository, revs, prefix)
 #endif
+
+/**
+ * Initialize a rev_info structure with default values. The third parameter may
+ * be NULL or can be prefix path, and then the `.prefix` variable will be set
+ * to it. This is typically the first function you want to call when you want
+ * to deal with a revision list. After calling this function, you are free to
+ * customize options, like set `.ignore_merges` to 0 if you don't want to
+ * ignore merges, and so on.
+ */
 void repo_init_revisions(struct repository *r,
 			 struct rev_info *revs,
 			 const char *prefix);
+
+/**
+ * Parse revision information, filling in the `rev_info` structure, and
+ * removing the used arguments from the argument list. Returns the number
+ * of arguments left that weren't recognized, which are also moved to the
+ * head of the argument list. The last parameter is used in case no
+ * parameter given by the first two arguments.
+ */
 int setup_revisions(int argc, const char **argv, struct rev_info *revs,
 		    struct setup_revision_opt *);
+
 void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,
 			const struct option *options,
 			const char * const usagestr[]);
@@ -319,11 +350,28 @@
 int handle_revision_arg(const char *arg, struct rev_info *revs,
 			int flags, unsigned revarg_opt);
 
+/**
+ * Reset the flags used by the revision walking api. You can use this to do
+ * multiple sequential revision walks.
+ */
 void reset_revision_walk(void);
+
+/**
+ * Prepares the rev_info structure for a walk. You should check if it returns
+ * any error (non-zero return code) and if it does not, you can start using
+ * get_revision() to do the iteration.
+ */
 int prepare_revision_walk(struct rev_info *revs);
+
+/**
+ * Takes a pointer to a `rev_info` structure and iterates over it, returning a
+ * `struct commit *` each time you call it. The end of the revision list is
+ * indicated by returning a NULL pointer.
+ */
 struct commit *get_revision(struct rev_info *revs);
-char *get_revision_mark(const struct rev_info *revs,
-			const struct commit *commit);
+
+const char *get_revision_mark(const struct rev_info *revs,
+			      const struct commit *commit);
 void put_revision_mark(const struct rev_info *revs,
 		       const struct commit *commit);
 
@@ -333,8 +381,19 @@
 
 void show_object_with_name(FILE *, struct object *, const char *);
 
+/**
+ * This function can be used if you want to add commit objects as revision
+ * information. You can use the `UNINTERESTING` object flag to indicate if
+ * you want to include or exclude the given commit (and commits reachable
+ * from the given commit) from the revision list.
+ *
+ * NOTE: If you have the commits as a string list then you probably want to
+ * use setup_revisions(), instead of parsing each string and using this
+ * function.
+ */
 void add_pending_object(struct rev_info *revs,
 			struct object *obj, const char *name);
+
 void add_pending_oid(struct rev_info *revs,
 		     const char *name, const struct object_id *oid,
 		     unsigned int flags);
diff --git a/run-command.c b/run-command.c
index 3449db3..9942f12 100644
--- a/run-command.c
+++ b/run-command.c
@@ -412,8 +412,7 @@
 	argv_array_push(out, SHELL_PATH);
 
 	if (cmd->git_cmd) {
-		argv_array_push(out, "git");
-		argv_array_pushv(out, cmd->argv);
+		prepare_git_cmd(out, cmd->argv);
 	} else if (cmd->use_shell) {
 		prepare_shell_cmd(out, cmd->argv);
 	} else {
diff --git a/run-command.h b/run-command.h
index f769e03..592d9dc 100644
--- a/run-command.h
+++ b/run-command.h
@@ -5,8 +5,60 @@
 
 #include "argv-array.h"
 
+/**
+ * The run-command API offers a versatile tool to run sub-processes with
+ * redirected input and output as well as with a modified environment
+ * and an alternate current directory.
+ *
+ * A similar API offers the capability to run a function asynchronously,
+ * which is primarily used to capture the output that the function
+ * produces in the caller in order to process it.
+ */
+
+
+/**
+ * This describes the arguments, redirections, and environment of a
+ * command to run in a sub-process.
+ *
+ * The caller:
+ *
+ * 1. allocates and clears (using child_process_init() or
+ *    CHILD_PROCESS_INIT) a struct child_process variable;
+ * 2. initializes the members;
+ * 3. calls start_command();
+ * 4. processes the data;
+ * 5. closes file descriptors (if necessary; see below);
+ * 6. calls finish_command().
+ *
+ * Special forms of redirection are available by setting these members
+ * to 1:
+ *
+ *  .no_stdin, .no_stdout, .no_stderr: The respective channel is
+ *		redirected to /dev/null.
+ *
+ *	.stdout_to_stderr: stdout of the child is redirected to its
+ *		stderr. This happens after stderr is itself redirected.
+ *		So stdout will follow stderr to wherever it is
+ *		redirected.
+ */
 struct child_process {
+
+	/**
+	 * The .argv member is set up as an array of string pointers (NULL
+	 * terminated), of which .argv[0] is the program name to run (usually
+	 * without a path). If the command to run is a git command, set argv[0] to
+	 * the command name without the 'git-' prefix and set .git_cmd = 1.
+	 *
+	 * Note that the ownership of the memory pointed to by .argv stays with the
+	 * caller, but it should survive until `finish_command` completes. If the
+	 * .argv member is NULL, `start_command` will point it at the .args
+	 * `argv_array` (so you may use one or the other, but you must use exactly
+	 * one). The memory in .args will be cleaned up automatically during
+	 * `finish_command` (or during `start_command` when it is unsuccessful).
+	 *
+	 */
 	const char **argv;
+
 	struct argv_array args;
 	struct argv_array env_array;
 	pid_t pid;
@@ -18,8 +70,8 @@
 
 	/*
 	 * Using .in, .out, .err:
-	 * - Specify 0 for no redirections (child inherits stdin, stdout,
-	 *   stderr from parent).
+	 * - Specify 0 for no redirections. No new file descriptor is allocated.
+	 * (child inherits stdin, stdout, stderr from parent).
 	 * - Specify -1 to have a pipe allocated as follows:
 	 *     .in: returns the writable pipe end; parent writes to it,
 	 *          the readable pipe end becomes child's stdin
@@ -37,13 +89,43 @@
 	int in;
 	int out;
 	int err;
+
+	/**
+	 * To specify a new initial working directory for the sub-process,
+	 * specify it in the .dir member.
+	 */
 	const char *dir;
+
+	/**
+	 * To modify the environment of the sub-process, specify an array of
+	 * string pointers (NULL terminated) in .env:
+	 *
+	 * - If the string is of the form "VAR=value", i.e. it contains '='
+	 *   the variable is added to the child process's environment.
+	 *
+	 * - If the string does not contain '=', it names an environment
+	 *   variable that will be removed from the child process's environment.
+	 *
+	 * If the .env member is NULL, `start_command` will point it at the
+	 * .env_array `argv_array` (so you may use one or the other, but not both).
+	 * The memory in .env_array will be cleaned up automatically during
+	 * `finish_command` (or during `start_command` when it is unsuccessful).
+	 */
 	const char *const *env;
+
 	unsigned no_stdin:1;
 	unsigned no_stdout:1;
 	unsigned no_stderr:1;
-	unsigned git_cmd:1; /* if this is to be git sub-command */
+    unsigned git_cmd:1; /* if this is to be git sub-command */
+
+	/**
+	 * If the program cannot be found, the functions return -1 and set
+	 * errno to ENOENT. Normally, an error message is printed, but if
+	 * .silent_exec_failure is set to 1, no message is printed for this
+	 * special error condition.
+	 */
 	unsigned silent_exec_failure:1;
+
 	unsigned stdout_to_stderr:1;
 	unsigned use_shell:1;
 	unsigned clean_on_exit:1;
@@ -53,13 +135,63 @@
 };
 
 #define CHILD_PROCESS_INIT { NULL, ARGV_ARRAY_INIT, ARGV_ARRAY_INIT }
+
+/**
+ * The functions: child_process_init, start_command, finish_command,
+ * run_command, run_command_v_opt, run_command_v_opt_cd_env, child_process_clear
+ * do the following:
+ *
+ * - If a system call failed, errno is set and -1 is returned. A diagnostic
+ *   is printed.
+ *
+ * - If the program was not found, then -1 is returned and errno is set to
+ *   ENOENT; a diagnostic is printed only if .silent_exec_failure is 0.
+ *
+ * - Otherwise, the program is run. If it terminates regularly, its exit
+ *   code is returned. No diagnostic is printed, even if the exit code is
+ *   non-zero.
+ *
+ * - If the program terminated due to a signal, then the return value is the
+ *   signal number + 128, ie. the same value that a POSIX shell's $? would
+ *   report.  A diagnostic is printed.
+ *
+ */
+
+/**
+ * Initialize a struct child_process variable.
+ */
 void child_process_init(struct child_process *);
+
+/**
+ * Release the memory associated with the struct child_process.
+ * Most users of the run-command API don't need to call this
+ * function explicitly because `start_command` invokes it on
+ * failure and `finish_command` calls it automatically already.
+ */
 void child_process_clear(struct child_process *);
+
 int is_executable(const char *name);
 
+/**
+ * Start a sub-process. Takes a pointer to a `struct child_process`
+ * that specifies the details and returns pipe FDs (if requested).
+ * See below for details.
+ */
 int start_command(struct child_process *);
+
+/**
+ * Wait for the completion of a sub-process that was started with
+ * start_command().
+ */
 int finish_command(struct child_process *);
+
 int finish_command_in_signal(struct child_process *);
+
+/**
+ * A convenience function that encapsulates a sequence of
+ * start_command() followed by finish_command(). Takes a pointer
+ * to a `struct child_process` that specifies the details.
+ */
 int run_command(struct child_process *);
 
 /*
@@ -68,6 +200,20 @@
  * overwritten by further calls to find_hook and run_hook_*.
  */
 const char *find_hook(const char *name);
+
+/**
+ * Run a hook.
+ * The first argument is a pathname to an index file, or NULL
+ * if the hook uses the default index file or no index is needed.
+ * The second argument is the name of the hook.
+ * The further arguments correspond to the hook arguments.
+ * The last argument has to be NULL to terminate the arguments list.
+ * If the hook does not exist or is not executable, the return
+ * value will be zero.
+ * If it is executable, the hook will be executed and the exit
+ * status of the hook is returned.
+ * On execution, .stdout_to_stderr and .no_stdin will be set.
+ */
 LAST_ARG_MUST_BE_NULL
 int run_hook_le(const char *const *env, const char *name, ...);
 int run_hook_ve(const char *const *env, const char *name, va_list args);
@@ -78,6 +224,18 @@
 #define RUN_SILENT_EXEC_FAILURE 8
 #define RUN_USING_SHELL 16
 #define RUN_CLEAN_ON_EXIT 32
+
+/**
+ * Convenience functions that encapsulate a sequence of
+ * start_command() followed by finish_command(). The argument argv
+ * specifies the program and its arguments. The argument opt is zero
+ * or more of the flags `RUN_COMMAND_NO_STDIN`, `RUN_GIT_CMD`,
+ * `RUN_COMMAND_STDOUT_TO_STDERR`, or `RUN_SILENT_EXEC_FAILURE`
+ * that correspond to the members .no_stdin, .git_cmd,
+ * .stdout_to_stderr, .silent_exec_failure of `struct child_process`.
+ * The argument dir corresponds the member .dir. The argument env
+ * corresponds to the member .env.
+ */
 int run_command_v_opt(const char **argv, int opt);
 int run_command_v_opt_tr2(const char **argv, int opt, const char *tr2_class);
 /*
@@ -125,15 +283,84 @@
  * It is expected that no synchronization and mutual exclusion between
  * the caller and the feed function is necessary so that the function
  * can run in a thread without interfering with the caller.
+ *
+ * The caller:
+ *
+ * 1. allocates and clears (memset(&asy, 0, sizeof(asy));) a
+ *    struct async variable;
+ * 2. initializes .proc and .data;
+ * 3. calls start_async();
+ * 4. processes communicates with proc through .in and .out;
+ * 5. closes .in and .out;
+ * 6. calls finish_async().
+ *
+ * There are serious restrictions on what the asynchronous function can do
+ * because this facility is implemented by a thread in the same address
+ * space on most platforms (when pthreads is available), but by a pipe to
+ * a forked process otherwise:
+ *
+ * - It cannot change the program's state (global variables, environment,
+ *   etc.) in a way that the caller notices; in other words, .in and .out
+ *   are the only communication channels to the caller.
+ *
+ * - It must not change the program's state that the caller of the
+ *   facility also uses.
+ *
  */
 struct async {
-	/*
-	 * proc reads from in; closes it before return
-	 * proc writes to out; closes it before return
-	 * returns 0 on success, non-zero on failure
+
+	/**
+	 * The function pointer in .proc has the following signature:
+	 *
+	 *	int proc(int in, int out, void *data);
+	 *
+	 * - in, out specifies a set of file descriptors to which the function
+	 *  must read/write the data that it needs/produces.  The function
+	 *  *must* close these descriptors before it returns.  A descriptor
+	 *  may be -1 if the caller did not configure a descriptor for that
+	 *  direction.
+	 *
+	 * - data is the value that the caller has specified in the .data member
+	 *  of struct async.
+	 *
+	 * - The return value of the function is 0 on success and non-zero
+	 *  on failure. If the function indicates failure, finish_async() will
+	 *  report failure as well.
+	 *
 	 */
 	int (*proc)(int in, int out, void *data);
+
 	void *data;
+
+	/**
+	 * The members .in, .out are used to provide a set of fd's for
+	 * communication between the caller and the callee as follows:
+	 *
+	 * - Specify 0 to have no file descriptor passed.  The callee will
+	 *   receive -1 in the corresponding argument.
+	 *
+	 * - Specify < 0 to have a pipe allocated; start_async() replaces
+	 *   with the pipe FD in the following way:
+	 *
+	 * 	.in: Returns the writable pipe end into which the caller
+	 * 	writes; the readable end of the pipe becomes the function's
+	 * 	in argument.
+	 *
+	 * 	.out: Returns the readable pipe end from which the caller
+	 * 	reads; the writable end of the pipe becomes the function's
+	 * 	out argument.
+	 *
+	 *   The caller of start_async() must close the returned FDs after it
+	 *   has completed reading from/writing from them.
+	 *
+	 * - Specify a file descriptor > 0 to be used by the function:
+	 *
+	 * 	.in: The FD must be readable; it becomes the function's in.
+	 * 	.out: The FD must be writable; it becomes the function's out.
+	 *
+	 *   The specified FD is closed by start_async(), even if it fails to
+	 *   run the function.
+	 */
 	int in;		/* caller writes here and closes it */
 	int out;	/* caller reads from here and closes it */
 #ifdef NO_PTHREADS
@@ -146,8 +373,19 @@
 	int isolate_sigpipe;
 };
 
+/**
+ * Run a function asynchronously. Takes a pointer to a `struct
+ * async` that specifies the details and returns a set of pipe FDs
+ * for communication with the function. See below for details.
+ */
 int start_async(struct async *async);
+
+/**
+ * Wait for the completion of an asynchronous function that was
+ * started with start_async().
+ */
 int finish_async(struct async *async);
+
 int in_async(void);
 int async_with_fork(void);
 void check_pipe(int err);
diff --git a/send-pack.c b/send-pack.c
index 34c77cb..0407841 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -41,7 +41,9 @@
 static void feed_object(const struct object_id *oid, FILE *fh, int negative)
 {
 	if (negative &&
-	    !has_object_file_with_flags(oid, OBJECT_INFO_SKIP_FETCH_OBJECT))
+	    !has_object_file_with_flags(oid,
+					OBJECT_INFO_SKIP_FETCH_OBJECT |
+					OBJECT_INFO_QUICK))
 		return;
 
 	if (negative)
@@ -565,8 +567,6 @@
 
 	if (need_pack_data && cmds_sent) {
 		if (pack_objects(out, remote_refs, extra_have, args) < 0) {
-			for (ref = remote_refs; ref; ref = ref->next)
-				ref->status = REF_STATUS_NONE;
 			if (args->stateless_rpc)
 				close(out);
 			if (git_connection_is_socket(conn))
@@ -574,10 +574,12 @@
 
 			/*
 			 * Do not even bother with the return value; we know we
-			 * are failing, and just want the error() side effects.
+			 * are failing, and just want the error() side effects,
+			 * as well as marking refs with their remote status (if
+			 * we get one).
 			 */
 			if (status_report)
-				receive_unpack_status(&reader);
+				receive_status(&reader, remote_refs);
 
 			if (use_sideband) {
 				close(demux.out);
diff --git a/sequencer.c b/sequencer.c
index 8952cfa..763ccbb 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -131,7 +131,7 @@
 	"rebase-merge/rewritten-pending")
 
 /*
- * The path of the file containig the OID of the "squash onto" commit, i.e.
+ * The path of the file containing the OID of the "squash onto" commit, i.e.
  * the dummy commit used for `reset [new root]`.
  */
 static GIT_PATH_FUNC(rebase_path_squash_onto, "rebase-merge/squash-onto")
@@ -147,6 +147,8 @@
  * command-line.
  */
 static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
+static GIT_PATH_FUNC(rebase_path_cdate_is_adate, "rebase-merge/cdate_is_adate")
+static GIT_PATH_FUNC(rebase_path_ignore_date, "rebase-merge/ignore_date")
 static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head")
 static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose")
 static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet")
@@ -823,9 +825,19 @@
 		error(_("missing 'GIT_AUTHOR_DATE'"));
 	if (date_i < 0 || email_i < 0 || date_i < 0 || err)
 		goto finish;
-	*name = kv.items[name_i].util;
-	*email = kv.items[email_i].util;
-	*date = kv.items[date_i].util;
+
+	if (name)
+		*name = kv.items[name_i].util;
+	else
+		free(kv.items[name_i].util);
+	if (email)
+		*email = kv.items[email_i].util;
+	else
+		free(kv.items[email_i].util);
+	if (date)
+		*date = kv.items[date_i].util;
+	else
+		free(kv.items[date_i].util);
 	retval = 0;
 finish:
 	string_list_clear(&kv, !!retval);
@@ -868,6 +880,47 @@
 	return NULL;
 }
 
+/* Returns a "date" string that needs to be free()'d by the caller */
+static char *read_author_date_or_null(void)
+{
+	char *date;
+
+	if (read_author_script(rebase_path_author_script(),
+			       NULL, NULL, &date, 0))
+		return NULL;
+	return date;
+}
+
+/* Construct a free()able author string with current time as the author date */
+static char *ignore_author_date(const char *author)
+{
+	int len = strlen(author);
+	struct ident_split ident;
+	struct strbuf new_author = STRBUF_INIT;
+
+	if (split_ident_line(&ident, author, len) < 0) {
+		error(_("malformed ident line"));
+		return NULL;
+	}
+	len = ident.mail_end - ident.name_begin + 1;
+
+	strbuf_addf(&new_author, "%.*s ", len, ident.name_begin);
+	datestamp(&new_author);
+	return strbuf_detach(&new_author, NULL);
+}
+
+static void push_dates(struct child_process *child, int change_committer_date)
+{
+	time_t now = time(NULL);
+	struct strbuf date = STRBUF_INIT;
+
+	strbuf_addf(&date, "@%"PRIuMAX, (uintmax_t)now);
+	argv_array_pushf(&child->env_array, "GIT_AUTHOR_DATE=%s", date.buf);
+	if (change_committer_date)
+		argv_array_pushf(&child->env_array, "GIT_COMMITTER_DATE=%s", date.buf);
+	strbuf_release(&date);
+}
+
 static const char staged_changes_advice[] =
 N_("you have staged changes in your working tree\n"
 "If these changes are meant to be squashed into the previous commit, run:\n"
@@ -927,6 +980,25 @@
 
 	cmd.git_cmd = 1;
 
+	if (opts->committer_date_is_author_date) {
+		int res = -1;
+		struct strbuf datebuf = STRBUF_INIT;
+		char *date = read_author_date_or_null();
+
+		if (!date)
+			return -1;
+
+		strbuf_addf(&datebuf, "@%s", date);
+		res = setenv("GIT_COMMITTER_DATE",
+			     opts->ignore_date ? "" : datebuf.buf, 1);
+
+		strbuf_release(&datebuf);
+		free(date);
+
+		if (res)
+			return -1;
+	}
+
 	if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) {
 		const char *gpg_opt = gpg_sign_opt_quoted(opts);
 
@@ -942,6 +1014,8 @@
 		argv_array_push(&cmd.args, "--amend");
 	if (opts->gpg_sign)
 		argv_array_pushf(&cmd.args, "-S%s", opts->gpg_sign);
+	if (opts->ignore_date)
+		push_dates(&cmd, opts->committer_date_is_author_date);
 	if (defmsg)
 		argv_array_pushl(&cmd.args, "-F", defmsg, NULL);
 	else if (!(flags & EDIT_MSG))
@@ -1310,14 +1384,13 @@
 	struct commit_extra_header *extra = NULL;
 	struct strbuf err = STRBUF_INIT;
 	struct strbuf commit_msg = STRBUF_INIT;
-	char *amend_author = NULL;
+	char *author_to_free = NULL;
 	const char *hook_commit = NULL;
 	enum commit_msg_cleanup_mode cleanup;
 	int res = 0;
 
 	if (parse_head(r, &current_head))
 		return -1;
-
 	if (flags & AMEND_MSG) {
 		const char *exclude_gpgsig[] = { "gpgsig", NULL };
 		const char *out_enc = get_commit_output_encoding();
@@ -1332,7 +1405,7 @@
 			strbuf_addstr(msg, orig_message);
 			hook_commit = "HEAD";
 		}
-		author = amend_author = get_author(message);
+		author = author_to_free = get_author(message);
 		unuse_commit_buffer(current_head, message);
 		if (!author) {
 			res = error(_("unable to parse commit author"));
@@ -1345,16 +1418,57 @@
 		commit_list_insert(current_head, &parents);
 	}
 
+	if (opts->committer_date_is_author_date) {
+		int len = strlen(author);
+		struct ident_split ident;
+		struct strbuf date = STRBUF_INIT;
+
+		if (split_ident_line(&ident, author, len) < 0) {
+			res = error(_("malformed ident line"));
+			goto out;
+		}
+		if (!ident.date_begin) {
+			res = error(_("corrupted author without date information"));
+			goto out;
+		}
+
+		strbuf_addf(&date, "@%.*s %.*s",
+			    (int)(ident.date_end - ident.date_begin), ident.date_begin,
+			    (int)(ident.tz_end - ident.tz_begin), ident.tz_begin);
+		res = setenv("GIT_COMMITTER_DATE",
+			     opts->ignore_date ? "" : date.buf, 1);
+		strbuf_release(&date);
+
+		if (res)
+			goto out;
+	}
+
 	if (write_index_as_tree(&tree, r->index, r->index_file, 0, NULL)) {
 		res = error(_("git write-tree failed to write a tree"));
 		goto out;
 	}
 
-	if (!(flags & ALLOW_EMPTY) && oideq(current_head ?
-					    get_commit_tree_oid(current_head) :
-					    the_hash_algo->empty_tree, &tree)) {
-		res = 1; /* run 'git commit' to display error message */
-		goto out;
+	if (!(flags & ALLOW_EMPTY)) {
+		struct commit *first_parent = current_head;
+
+		if (flags & AMEND_MSG) {
+			if (current_head->parents) {
+				first_parent = current_head->parents->item;
+				if (repo_parse_commit(r, first_parent)) {
+					res = error(_("could not parse HEAD commit"));
+					goto out;
+				}
+			} else {
+				first_parent = NULL;
+			}
+		}
+		if (oideq(first_parent
+			  ? get_commit_tree_oid(first_parent)
+			  : the_hash_algo->empty_tree,
+			  &tree)) {
+			res = 1; /* run 'git commit' to display error message */
+			goto out;
+		}
 	}
 
 	if (find_hook("prepare-commit-msg")) {
@@ -1388,6 +1502,15 @@
 
 	reset_ident_date();
 
+	if (opts->ignore_date) {
+		author = ignore_author_date(author);
+		if (!author) {
+			res = -1;
+			goto out;
+		}
+		free(author_to_free);
+		author_to_free = (char *)author;
+	}
 	if (commit_tree_extended(msg->buf, msg->len, &tree, parents,
 				 oid, author, opts->gpg_sign, extra)) {
 		res = error(_("failed to write commit object"));
@@ -1408,7 +1531,7 @@
 	free_commit_extra_headers(extra);
 	strbuf_release(&err);
 	strbuf_release(&commit_msg);
-	free(amend_author);
+	free(author_to_free);
 
 	return res;
 }
@@ -1574,6 +1697,7 @@
 	struct strbuf buf = STRBUF_INIT;
 	int res;
 	const char *message, *body;
+	const char *encoding = get_commit_output_encoding();
 
 	if (opts->current_fixup_count > 0) {
 		struct strbuf header = STRBUF_INIT;
@@ -1600,7 +1724,7 @@
 			return error(_("need a HEAD to fixup"));
 		if (!(head_commit = lookup_commit_reference(r, &head)))
 			return error(_("could not read HEAD"));
-		if (!(head_message = get_commit_buffer(head_commit, NULL)))
+		if (!(head_message = logmsg_reencode(head_commit, NULL, encoding)))
 			return error(_("could not read HEAD's commit message"));
 
 		find_commit_subject(head_message, &body);
@@ -1621,7 +1745,7 @@
 		unuse_commit_buffer(head_commit, head_message);
 	}
 
-	if (!(message = get_commit_buffer(commit, NULL)))
+	if (!(message = logmsg_reencode(commit, NULL, encoding)))
 		return error(_("could not read commit message of %s"),
 			     oid_to_hex(&commit->object.oid));
 	find_commit_subject(message, &body);
@@ -2006,6 +2130,7 @@
 static struct todo_item *append_new_todo(struct todo_list *todo_list)
 {
 	ALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc);
+	todo_list->total_nr++;
 	return todo_list->items + todo_list->nr++;
 }
 
@@ -2277,6 +2402,16 @@
 	sequencer_remove_state(&opts);
 }
 
+static void todo_list_write_total_nr(struct todo_list *todo_list)
+{
+	FILE *f = fopen_or_warn(rebase_path_msgtotal(), "w");
+
+	if (f) {
+		fprintf(f, "%d\n", todo_list->total_nr);
+		fclose(f);
+	}
+}
+
 static int read_populate_todo(struct repository *r,
 			      struct todo_list *todo_list,
 			      struct replay_opts *opts)
@@ -2322,7 +2457,6 @@
 
 	if (is_rebase_i(opts)) {
 		struct todo_list done = TODO_LIST_INIT;
-		FILE *f = fopen_or_warn(rebase_path_msgtotal(), "w");
 
 		if (strbuf_read_file(&done.buf, rebase_path_done(), 0) > 0 &&
 		    !todo_list_parse_insn_buffer(r, done.buf.buf, &done))
@@ -2334,10 +2468,7 @@
 			+ count_commands(todo_list);
 		todo_list_release(&done);
 
-		if (f) {
-			fprintf(f, "%d\n", todo_list->total_nr);
-			fclose(f);
-		}
+		todo_list_write_total_nr(todo_list);
 	}
 
 	return 0;
@@ -2468,6 +2599,16 @@
 			opts->signoff = 1;
 		}
 
+		if (file_exists(rebase_path_cdate_is_adate())) {
+			opts->allow_ff = 0;
+			opts->committer_date_is_author_date = 1;
+		}
+
+		if (file_exists(rebase_path_ignore_date())) {
+			opts->allow_ff = 0;
+			opts->ignore_date = 1;
+		}
+
 		if (file_exists(rebase_path_reschedule_failed_exec()))
 			opts->reschedule_failed_exec = 1;
 
@@ -2550,6 +2691,10 @@
 		write_file(rebase_path_gpg_sign_opt(), "-S%s\n", opts->gpg_sign);
 	if (opts->signoff)
 		write_file(rebase_path_signoff(), "--signoff\n");
+	if (opts->committer_date_is_author_date)
+		write_file(rebase_path_cdate_is_adate(), "%s", "");
+	if (opts->ignore_date)
+		write_file(rebase_path_ignore_date(), "%s", "");
 	if (opts->reschedule_failed_exec)
 		write_file(rebase_path_reschedule_failed_exec(), "%s", "");
 
@@ -2562,14 +2707,17 @@
 	enum todo_command command = opts->action == REPLAY_PICK ?
 		TODO_PICK : TODO_REVERT;
 	const char *command_string = todo_command_info[command].str;
+	const char *encoding;
 	struct commit *commit;
 
 	if (prepare_revs(opts))
 		return -1;
 
+	encoding = get_log_output_encoding();
+
 	while ((commit = get_revision(opts->revs))) {
 		struct todo_item *item = append_new_todo(todo_list);
-		const char *commit_buffer = get_commit_buffer(commit, NULL);
+		const char *commit_buffer = logmsg_reencode(commit, NULL, encoding);
 		const char *subject;
 		int subject_len;
 
@@ -2966,7 +3114,8 @@
 
 	strbuf_addf(&buf, "%s/message", get_dir(opts));
 	if (!file_exists(buf.buf)) {
-		const char *commit_buffer = get_commit_buffer(commit, NULL);
+		const char *encoding = get_commit_output_encoding();
+		const char *commit_buffer = logmsg_reencode(commit, NULL, encoding);
 		find_commit_subject(commit_buffer, &subject);
 		res |= write_message(subject, strlen(subject), buf.buf, 1);
 		unuse_commit_buffer(commit, commit_buffer);
@@ -3368,7 +3517,8 @@
 	}
 
 	if (commit) {
-		const char *message = get_commit_buffer(commit, NULL);
+		const char *encoding = get_commit_output_encoding();
+		const char *message = logmsg_reencode(commit, NULL, encoding);
 		const char *body;
 		int len;
 
@@ -3485,6 +3635,8 @@
 		argv_array_push(&cmd.args, git_path_merge_msg(r));
 		if (opts->gpg_sign)
 			argv_array_push(&cmd.args, opts->gpg_sign);
+		if (opts->ignore_date)
+			push_dates(&cmd, opts->committer_date_is_author_date);
 
 		/* Add the tips to be merged */
 		for (j = to_merge; j; j = j->next)
@@ -3757,7 +3909,9 @@
 	setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
 	if (opts->allow_ff)
 		assert(!(opts->signoff || opts->no_commit ||
-				opts->record_origin || opts->edit));
+				opts->record_origin || opts->edit ||
+				opts->committer_date_is_author_date ||
+				opts->ignore_date));
 	if (read_and_refresh_cache(r, opts))
 		return -1;
 
@@ -3908,7 +4062,7 @@
 							item->commit,
 							arg, item->arg_len,
 							opts, res, 0);
-		} else if (check_todo && !res) {
+		} else if (is_rebase_i(opts) && check_todo && !res) {
 			struct stat st;
 
 			if (stat(get_todo_path(opts), &st)) {
@@ -4149,9 +4303,10 @@
 				 */
 				struct commit *commit;
 				const char *path = rebase_path_squash_msg();
+				const char *encoding = get_commit_output_encoding();
 
 				if (parse_head(r, &commit) ||
-				    !(p = get_commit_buffer(commit, NULL)) ||
+				    !(p = logmsg_reencode(commit, NULL, encoding)) ||
 				    write_message(p, strlen(p), path, 0)) {
 					unuse_commit_buffer(commit, p);
 					return error(_("could not write file: "
@@ -4208,8 +4363,10 @@
 	if (is_rebase_i(opts)) {
 		if ((res = read_populate_todo(r, &todo_list, opts)))
 			goto release_todo_list;
-		if (commit_staged_changes(r, opts, &todo_list))
-			return -1;
+		if (commit_staged_changes(r, opts, &todo_list)) {
+			res = -1;
+			goto release_todo_list;
+		}
 	} else if (!file_exists(get_todo_path(opts)))
 		return continue_single_pick(r);
 	else if ((res = read_populate_todo(r, &todo_list, opts)))
@@ -4423,7 +4580,6 @@
 	struct labels_entry *labels_entry;
 	struct string_entry *string_entry;
 	struct object_id dummy;
-	size_t len;
 	int i;
 
 	string_entry = oidmap_get(&state->commit2label, oid);
@@ -4443,10 +4599,10 @@
 	 * abbreviation for any uninteresting commit's names that does not
 	 * clash with any other label.
 	 */
+	strbuf_reset(&state->buf);
 	if (!label) {
 		char *p;
 
-		strbuf_reset(&state->buf);
 		strbuf_grow(&state->buf, GIT_MAX_HEXSZ);
 		label = p = state->buf.buf;
 
@@ -4469,32 +4625,55 @@
 				p[i] = save;
 			}
 		}
-	} else if (((len = strlen(label)) == the_hash_algo->hexsz &&
-		    !get_oid_hex(label, &dummy)) ||
-		   (len == 1 && *label == '#') ||
-		   hashmap_get_from_hash(&state->labels,
-					 strihash(label), label)) {
-		/*
-		 * If the label already exists, or if the label is a valid full
-		 * OID, or the label is a '#' (which we use as a separator
-		 * between merge heads and oneline), we append a dash and a
-		 * number to make it unique.
-		 */
+	} else {
 		struct strbuf *buf = &state->buf;
 
-		strbuf_reset(buf);
-		strbuf_add(buf, label, len);
-
-		for (i = 2; ; i++) {
-			strbuf_setlen(buf, len);
-			strbuf_addf(buf, "-%d", i);
-			if (!hashmap_get_from_hash(&state->labels,
-						   strihash(buf->buf),
-						   buf->buf))
-				break;
+		/*
+		 * Sanitize labels by replacing non-alpha-numeric characters
+		 * (including white-space ones) by dashes, as they might be
+		 * illegal in file names (and hence in ref names).
+		 *
+		 * Note that we retain non-ASCII UTF-8 characters (identified
+		 * via the most significant bit). They should be all acceptable
+		 * in file names. We do not validate the UTF-8 here, that's not
+		 * the job of this function.
+		 */
+		for (; *label; label++)
+			if ((*label & 0x80) || isalnum(*label))
+				strbuf_addch(buf, *label);
+			/* avoid leading dash and double-dashes */
+			else if (buf->len && buf->buf[buf->len - 1] != '-')
+				strbuf_addch(buf, '-');
+		if (!buf->len) {
+			strbuf_addstr(buf, "rev-");
+			strbuf_add_unique_abbrev(buf, oid, default_abbrev);
 		}
-
 		label = buf->buf;
+
+		if ((buf->len == the_hash_algo->hexsz &&
+		     !get_oid_hex(label, &dummy)) ||
+		    (buf->len == 1 && *label == '#') ||
+		    hashmap_get_from_hash(&state->labels,
+					  strihash(label), label)) {
+			/*
+			 * If the label already exists, or if the label is a
+			 * valid full OID, or the label is a '#' (which we use
+			 * as a separator between merge heads and oneline), we
+			 * append a dash and a number to make it unique.
+			 */
+			size_t len = buf->len;
+
+			for (i = 2; ; i++) {
+				strbuf_setlen(buf, len);
+				strbuf_addf(buf, "-%d", i);
+				if (!hashmap_get_from_hash(&state->labels,
+							   strihash(buf->buf),
+							   buf->buf))
+					break;
+			}
+
+			label = buf->buf;
+		}
 	}
 
 	FLEX_ALLOC_STR(labels_entry, label, label);
@@ -4538,10 +4717,15 @@
 	strbuf_init(&state.buf, 32);
 
 	if (revs->cmdline.nr && (revs->cmdline.rev[0].flags & BOTTOM)) {
+		struct labels_entry *onto_label_entry;
 		struct object_id *oid = &revs->cmdline.rev[0].item->oid;
 		FLEX_ALLOC_STR(entry, string, "onto");
 		oidcpy(&entry->entry.oid, oid);
 		oidmap_put(&state.commit2label, entry);
+
+		FLEX_ALLOC_STR(onto_label_entry, label, "onto");
+		hashmap_entry_init(&onto_label_entry->entry, strihash("onto"));
+		hashmap_add(&state.labels, &onto_label_entry->entry);
 	}
 
 	/*
@@ -4596,10 +4780,6 @@
 		else
 			strbuf_addbuf(&label, &oneline);
 
-		for (p1 = label.buf; *p1; p1++)
-			if (isspace(*p1))
-				*(char *)p1 = '-';
-
 		strbuf_reset(&buf);
 		strbuf_addf(&buf, "%s -C %s",
 			    cmd_merge, oid_to_hex(&commit->object.oid));
@@ -4642,7 +4822,7 @@
 				label_oid(oid, "branch-point", &state);
 		}
 
-		/* Add HEAD as implict "tip of branch" */
+		/* Add HEAD as implicit "tip of branch" */
 		if (!iter->next)
 			tips_tail = &commit_list_insert(iter->item,
 							tips_tail)->next;
@@ -4824,7 +5004,7 @@
 	 * are considered part of the pick, so we insert the commands *after*
 	 * those chains if there are any.
 	 *
-	 * As we insert the exec commands immediatly after rearranging
+	 * As we insert the exec commands immediately after rearranging
 	 * any fixups and before the user edits the list, a fixup chain
 	 * can never contain comments (any comments are empty picks that
 	 * have been commented out because the user did not specify
@@ -5003,6 +5183,7 @@
 		MOVE_ARRAY(todo_list->items, todo_list->items + i, todo_list->nr - i);
 		todo_list->nr -= i;
 		todo_list->current = 0;
+		todo_list->done_nr += i;
 
 		if (is_fixup(peek_command(todo_list, 0)))
 			record_in_rewritten(base_oid, peek_command(todo_list, 0));
@@ -5082,15 +5263,21 @@
 		return error_errno(_("could not write '%s'"), todo_file);
 	}
 
-	todo_list_release(&new_todo);
+	res = -1;
 
 	if (checkout_onto(r, opts, onto_name, &oid, orig_head))
-		return -1;
+		goto cleanup;
 
 	if (require_clean_work_tree(r, "rebase", "", 1, 1))
-		return -1;
+		goto cleanup;
 
-	return sequencer_continue(r, opts);
+	todo_list_write_total_nr(&new_todo);
+	res = pick_commits(r, &new_todo, opts);
+
+cleanup:
+	todo_list_release(&new_todo);
+
+	return res;
 }
 
 struct subject2item_entry {
@@ -5167,7 +5354,7 @@
 		*commit_todo_item_at(&commit_todo, item->commit) = item;
 
 		parse_commit(item->commit);
-		commit_buffer = get_commit_buffer(item->commit, NULL);
+		commit_buffer = logmsg_reencode(item->commit, NULL, "UTF-8");
 		find_commit_subject(commit_buffer, &subject);
 		format_subject(&buf, subject, " ");
 		subject = subjects[i] = strbuf_detach(&buf, &subject_len);
diff --git a/sequencer.h b/sequencer.h
index 9f9ae29..e9a0e03 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -43,6 +43,8 @@
 	int verbose;
 	int quiet;
 	int reschedule_failed_exec;
+	int committer_date_is_author_date;
+	int ignore_date;
 
 	int mainline;
 
diff --git a/server-info.c b/server-info.c
index 4d8199b..bae2cdf 100644
--- a/server-info.c
+++ b/server-info.c
@@ -93,7 +93,7 @@
 		uic.old_fp = fopen_or_warn(path, "r");
 
 	/*
-	 * uic_printf will compare incremental comparison aginst old_fp
+	 * uic_printf will compare incremental comparison against old_fp
 	 * and mark uic as stale if needed
 	 */
 	ret = generate(&uic);
diff --git a/sha1-array.c b/sha1-array.c
index d922e94..3eeadfe 100644
--- a/sha1-array.c
+++ b/sha1-array.c
@@ -48,7 +48,7 @@
 {
 	int i;
 
-	/* No oid_array_sort() here! See the api-oid-array.txt docs! */
+	/* No oid_array_sort() here! See sha1-array.h */
 
 	for (i = 0; i < array->nr; i++) {
 		int ret = fn(array->oid + i, data);
diff --git a/sha1-array.h b/sha1-array.h
index 55d016c..dc1bca9 100644
--- a/sha1-array.h
+++ b/sha1-array.h
@@ -1,6 +1,52 @@
 #ifndef SHA1_ARRAY_H
 #define SHA1_ARRAY_H
 
+/**
+ * The API provides storage and manipulation of sets of object identifiers.
+ * The emphasis is on storage and processing efficiency, making them suitable
+ * for large lists. Note that the ordering of items is not preserved over some
+ * operations.
+ *
+ * Examples
+ * --------
+ * -----------------------------------------
+ * int print_callback(const struct object_id *oid,
+ * 		    void *data)
+ * {
+ * 	printf("%s\n", oid_to_hex(oid));
+ * 	return 0; // always continue
+ * }
+ *
+ * void some_func(void)
+ * {
+ *     struct sha1_array hashes = OID_ARRAY_INIT;
+ *     struct object_id oid;
+ *
+ *     // Read objects into our set
+ *     while (read_object_from_stdin(oid.hash))
+ *         oid_array_append(&hashes, &oid);
+ *
+ *     // Check if some objects are in our set
+ *     while (read_object_from_stdin(oid.hash)) {
+ *         if (oid_array_lookup(&hashes, &oid) >= 0)
+ *             printf("it's in there!\n");
+ *
+ *          // Print the unique set of objects. We could also have
+ *          // avoided adding duplicate objects in the first place,
+ *          // but we would end up re-sorting the array repeatedly.
+ *          // Instead, this will sort once and then skip duplicates
+ *          // in linear time.
+ *
+ *         oid_array_for_each_unique(&hashes, print_callback, NULL);
+ *     }
+ */
+
+/**
+ * A single array of object IDs. This should be initialized by assignment from
+ * `OID_ARRAY_INIT`. The `oid` member contains the actual data. The `nr` member
+ * contains the number of items in the set. The `alloc` and `sorted` members
+ * are used internally, and should not be needed by API callers.
+ */
 struct oid_array {
 	struct object_id *oid;
 	int nr;
@@ -10,18 +56,52 @@
 
 #define OID_ARRAY_INIT { NULL, 0, 0, 0 }
 
+/**
+ * Add an item to the set. The object ID will be placed at the end of the array
+ * (but note that some operations below may lose this ordering).
+ */
 void oid_array_append(struct oid_array *array, const struct object_id *oid);
+
+/**
+ * Perform a binary search of the array for a specific object ID. If found,
+ * returns the offset (in number of elements) of the object ID. If not found,
+ * returns a negative integer. If the array is not sorted, this function has
+ * the side effect of sorting it.
+ */
 int oid_array_lookup(struct oid_array *array, const struct object_id *oid);
+
+/**
+ * Free all memory associated with the array and return it to the initial,
+ * empty state.
+ */
 void oid_array_clear(struct oid_array *array);
 
 typedef int (*for_each_oid_fn)(const struct object_id *oid,
 			       void *data);
+/**
+ * Iterate over each element of the list, executing the callback function for
+ * each one. Does not sort the list, so any custom hash order is retained.
+ * If the callback returns a non-zero value, the iteration ends immediately
+ * and the callback's return is propagated; otherwise, 0 is returned.
+ */
 int oid_array_for_each(struct oid_array *array,
 		       for_each_oid_fn fn,
 		       void *data);
+
+/**
+ * Iterate over each unique element of the list in sorted order, but otherwise
+ * behave like `oid_array_for_each`. If the array is not sorted, this function
+ * has the side effect of sorting it.
+ */
 int oid_array_for_each_unique(struct oid_array *array,
 			      for_each_oid_fn fn,
 			      void *data);
+
+/**
+ * Apply the callback function `want` to each entry in the array, retaining
+ * only the entries for which the function returns true. Preserve the order
+ * of the entries that are retained.
+ */
 void oid_array_filter(struct oid_array *array,
 		      for_each_oid_fn want,
 		      void *cbdata);
diff --git a/sha1dc/sha1.c b/sha1dc/sha1.c
index 9d3cf81..dede2cb 100644
--- a/sha1dc/sha1.c
+++ b/sha1dc/sha1.c
@@ -72,7 +72,7 @@
 /* Not under GCC-alike or glibc */
 #elif defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN)
 /*
- * *BSD and newlib (embeded linux, cygwin, etc).
+ * *BSD and newlib (embedded linux, cygwin, etc).
  * the defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN) part prevents
  * this condition from matching with Solaris/sparc.
  * (Solaris defines only one endian macro)
@@ -98,7 +98,7 @@
 /*
  * Defines Big Endian on a whitelist of OSs that are known to be Big
  * Endian-only. See
- * https://public-inbox.org/git/93056823-2740-d072-1ebd-46b440b33d7e@felt.demon.nl/
+ * https://lore.kernel.org/git/93056823-2740-d072-1ebd-46b440b33d7e@felt.demon.nl/
  */
 #define SHA1DC_BIGENDIAN
 
diff --git a/sha1dc_git.c b/sha1dc_git.c
index e0cc9d9..5c300e8 100644
--- a/sha1dc_git.c
+++ b/sha1dc_git.c
@@ -19,7 +19,7 @@
 	if (!SHA1DCFinal(hash, ctx))
 		return;
 	die("SHA-1 appears to be part of a collision attack: %s",
-	    sha1_to_hex(hash));
+	    hash_to_hex_algop(hash, &hash_algos[GIT_HASH_SHA1]));
 }
 
 /*
diff --git a/shell.c b/shell.c
index 40084a3..54cca74 100644
--- a/shell.c
+++ b/shell.c
@@ -16,10 +16,10 @@
 	setup_path();
 	if (!arg || !(arg = sq_dequote(arg)) || *arg == '-')
 		die("bad argument");
-	if (!starts_with(me, "git-"))
+	if (!skip_prefix(me, "git-", &me))
 		die("bad command");
 
-	my_argv[0] = me + 4;
+	my_argv[0] = me;
 	my_argv[1] = arg;
 	my_argv[2] = NULL;
 
diff --git a/sigchain.h b/sigchain.h
index 138b20f..8e6bada 100644
--- a/sigchain.h
+++ b/sigchain.h
@@ -1,12 +1,57 @@
 #ifndef SIGCHAIN_H
 #define SIGCHAIN_H
 
+/**
+ * Code often wants to set a signal handler to clean up temporary files or
+ * other work-in-progress when we die unexpectedly. For multiple pieces of
+ * code to do this without conflicting, each piece of code must remember
+ * the old value of the handler and restore it either when:
+ *
+ *   1. The work-in-progress is finished, and the handler is no longer
+ *      necessary. The handler should revert to the original behavior
+ *      (either another handler, SIG_DFL, or SIG_IGN).
+ *
+ *   2. The signal is received. We should then do our cleanup, then chain
+ *      to the next handler (or die if it is SIG_DFL).
+ *
+ * Sigchain is a tiny library for keeping a stack of handlers. Your handler
+ * and installation code should look something like:
+ *
+ * ------------------------------------------
+ *   void clean_foo_on_signal(int sig)
+ *   {
+ * 	  clean_foo();
+ * 	  sigchain_pop(sig);
+ * 	  raise(sig);
+ *   }
+ *
+ *   void other_func()
+ *   {
+ * 	  sigchain_push_common(clean_foo_on_signal);
+ * 	  mess_up_foo();
+ * 	  clean_foo();
+ *   }
+ * ------------------------------------------
+ *
+ */
+
+/**
+ * Handlers are given the typedef of sigchain_fun. This is the same type
+ * that is given to signal() or sigaction(). It is perfectly reasonable to
+ * push SIG_DFL or SIG_IGN onto the stack.
+ */
 typedef void (*sigchain_fun)(int);
 
+/* You can sigchain_push and sigchain_pop individual signals. */
 int sigchain_push(int sig, sigchain_fun f);
 int sigchain_pop(int sig);
 
+/**
+ * push the handler onto the stack for the common signals:
+ * SIGINT, SIGHUP, SIGTERM, SIGQUIT and SIGPIPE.
+ */
 void sigchain_push_common(sigchain_fun f);
+
 void sigchain_pop_common(void);
 
 #endif /* SIGCHAIN_H */
diff --git a/strbuf.c b/strbuf.c
index aa48d17..f19da55 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -1125,3 +1125,31 @@
 	strbuf_release(&dst);
 	return 0;
 }
+
+int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
+			      const char *const *env)
+{
+	char *path2 = NULL;
+	int fd, res = 0;
+
+	if (!is_absolute_path(path))
+		path = path2 = xstrdup(git_path("%s", path));
+
+	fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+	if (fd < 0)
+		res = error_errno(_("could not open '%s' for writing"), path);
+	else if (write_in_full(fd, buffer->buf, buffer->len) < 0) {
+		res = error_errno(_("could not write to '%s'"), path);
+		close(fd);
+	} else if (close(fd) < 0)
+		res = error_errno(_("could not close '%s'"), path);
+	else {
+		strbuf_reset(buffer);
+		if (launch_editor(path, buffer, env) < 0)
+			res = error_errno(_("could not edit '%s'"), path);
+		unlink(path);
+	}
+
+	free(path2);
+	return res;
+}
diff --git a/strbuf.h b/strbuf.h
index 84cf969..bfa6656 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -621,6 +621,17 @@
 int launch_sequence_editor(const char *path, struct strbuf *buffer,
 			   const char *const *env);
 
+/*
+ * In contrast to `launch_editor()`, this function writes out the contents
+ * of the specified file first, then clears the `buffer`, then launches
+ * the editor and reads back in the file contents into the `buffer`.
+ * Finally, it deletes the temporary file.
+ *
+ * If `path` is relative, it refers to a file in the `.git` directory.
+ */
+int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
+			      const char *const *env);
+
 void strbuf_add_lines(struct strbuf *sb,
 		      const char *prefix,
 		      const char *buf,
diff --git a/string-list.h b/string-list.h
index f964399..7bb0ad0 100644
--- a/string-list.h
+++ b/string-list.h
@@ -179,7 +179,7 @@
 
 /**
  * Check if the given string is part of a sorted list. If it is part of the list,
- * return the coresponding string_list_item, NULL otherwise.
+ * return the corresponding string_list_item, NULL otherwise.
  */
 struct string_list_item *string_list_lookup(struct string_list *list, const char *string);
 
diff --git a/submodule-config.c b/submodule-config.c
index 401a9b2..8506481 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -409,6 +409,13 @@
 	int overwrite;
 };
 
+/*
+ * Parse a config item from .gitmodules.
+ *
+ * This does not handle submodule-related configuration from the main
+ * config store (.git/config, etc).  Callers are responsible for
+ * checking for overrides in the main config store when appropriate.
+ */
 static int parse_config(const char *var, const char *value, void *data)
 {
 	struct parse_config_parameter *me = data;
@@ -486,8 +493,9 @@
 			warn_multiple_config(me->treeish_name, submodule->name,
 					     "update");
 		else if (parse_submodule_update_strategy(value,
-			 &submodule->update_strategy) < 0)
-				die(_("invalid value for %s"), var);
+			 &submodule->update_strategy) < 0 ||
+			 submodule->update_strategy.type == SM_UPDATE_COMMAND)
+			die(_("invalid value for %s"), var);
 	} else if (!strcmp(item.buf, "shallow")) {
 		if (!me->overwrite && submodule->recommend_shallow != -1)
 			warn_multiple_config(me->treeish_name, submodule->name,
@@ -618,7 +626,7 @@
 
 /*
  * Note: This function is private for a reason, the '.gitmodules' file should
- * not be used as as a mechanism to retrieve arbitrary configuration stored in
+ * not be used as a mechanism to retrieve arbitrary configuration stored in
  * the repository.
  *
  * Runs the provided config function on the '.gitmodules' file found in the
diff --git a/submodule-config.h b/submodule-config.h
index 1b4e2da..42918b5 100644
--- a/submodule-config.h
+++ b/submodule-config.h
@@ -7,9 +7,31 @@
 #include "submodule.h"
 #include "strbuf.h"
 
+/**
+ * The submodule config cache API allows to read submodule
+ * configurations/information from specified revisions. Internally
+ * information is lazily read into a cache that is used to avoid
+ * unnecessary parsing of the same .gitmodules files. Lookups can be done by
+ * submodule path or name.
+ *
+ * Usage
+ * -----
+ *
+ * The caller can look up information about submodules by using the
+ * `submodule_from_path()` or `submodule_from_name()` functions. They return
+ * a `struct submodule` which contains the values. The API automatically
+ * initializes and allocates the needed infrastructure on-demand. If the
+ * caller does only want to lookup values from revisions the initialization
+ * can be skipped.
+ *
+ * If the internal cache might grow too big or when the caller is done with
+ * the API, all internally cached values can be freed with submodule_free().
+ *
+ */
+
 /*
  * Submodule entry containing the information about a certain submodule
- * in a certain revision.
+ * in a certain revision. It is returned by the lookup functions.
  */
 struct submodule {
 	const char *path;
@@ -41,13 +63,27 @@
 int parse_push_recurse_submodules_arg(const char *opt, const char *arg);
 void repo_read_gitmodules(struct repository *repo);
 void gitmodules_config_oid(const struct object_id *commit_oid);
+
+/**
+ * Same as submodule_from_path but lookup by name.
+ */
 const struct submodule *submodule_from_name(struct repository *r,
 					    const struct object_id *commit_or_tree,
 					    const char *name);
+
+/**
+ * Given a tree-ish in the superproject and a path, return the submodule that
+ * is bound at the path in the named tree.
+ */
 const struct submodule *submodule_from_path(struct repository *r,
 					    const struct object_id *commit_or_tree,
 					    const char *path);
+
+/**
+ * Use these to free the internally cached values.
+ */
 void submodule_free(struct repository *r);
+
 int print_config_from_gitmodules(struct repository *repo, const char *key);
 int config_set_in_gitmodules_file_gently(const char *key, const char *value);
 
diff --git a/submodule.c b/submodule.c
index 0f199c5..9da7181 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1993,6 +1993,47 @@
 	return ret;
 }
 
+int validate_submodule_git_dir(char *git_dir, const char *submodule_name)
+{
+	size_t len = strlen(git_dir), suffix_len = strlen(submodule_name);
+	char *p;
+	int ret = 0;
+
+	if (len <= suffix_len || (p = git_dir + len - suffix_len)[-1] != '/' ||
+	    strcmp(p, submodule_name))
+		BUG("submodule name '%s' not a suffix of git dir '%s'",
+		    submodule_name, git_dir);
+
+	/*
+	 * We prevent the contents of sibling submodules' git directories to
+	 * clash.
+	 *
+	 * Example: having a submodule named `hippo` and another one named
+	 * `hippo/hooks` would result in the git directories
+	 * `.git/modules/hippo/` and `.git/modules/hippo/hooks/`, respectively,
+	 * but the latter directory is already designated to contain the hooks
+	 * of the former.
+	 */
+	for (; *p; p++) {
+		if (is_dir_sep(*p)) {
+			char c = *p;
+
+			*p = '\0';
+			if (is_git_directory(git_dir))
+				ret = -1;
+			*p = c;
+
+			if (ret < 0)
+				return error(_("submodule git dir '%s' is "
+					       "inside git dir '%.*s'"),
+					     git_dir,
+					     (int)(p - git_dir), git_dir);
+		}
+	}
+
+	return 0;
+}
+
 /*
  * Embeds a single submodules git directory into the superprojects git dir,
  * non recursively.
@@ -2000,7 +2041,7 @@
 static void relocate_single_git_dir_into_superproject(const char *path)
 {
 	char *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;
-	const char *new_git_dir;
+	char *new_git_dir;
 	const struct submodule *sub;
 
 	if (submodule_uses_worktrees(path))
@@ -2018,10 +2059,14 @@
 	if (!sub)
 		die(_("could not lookup name for submodule '%s'"), path);
 
-	new_git_dir = git_path("modules/%s", sub->name);
+	new_git_dir = git_pathdup("modules/%s", sub->name);
+	if (validate_submodule_git_dir(new_git_dir, sub->name) < 0)
+		die(_("refusing to move '%s' into an existing git dir"),
+		    real_old_git_dir);
 	if (safe_create_leading_directories_const(new_git_dir) < 0)
 		die(_("could not create directory '%s'"), new_git_dir);
 	real_new_git_dir = real_pathdup(new_git_dir, 1);
+	free(new_git_dir);
 
 	fprintf(stderr, _("Migrating git directory of '%s%s' from\n'%s' to\n'%s'\n"),
 		get_super_prefix_or_empty(), path,
diff --git a/submodule.h b/submodule.h
index 8072e6d..c81ec1a 100644
--- a/submodule.h
+++ b/submodule.h
@@ -124,6 +124,11 @@
  */
 int submodule_to_gitdir(struct strbuf *buf, const char *submodule);
 
+/*
+ * Make sure that no submodule's git dir is nested in a sibling submodule's.
+ */
+int validate_submodule_git_dir(char *git_dir, const char *submodule_name);
+
 #define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0)
 #define SUBMODULE_MOVE_HEAD_FORCE   (1<<1)
 int submodule_move_head(const char *path,
diff --git a/t/README b/t/README
index 60d5b77..caa125b 100644
--- a/t/README
+++ b/t/README
@@ -397,6 +397,10 @@
 built-in version of git-stash. See 'stash.useBuiltin' in
 git-config(1).
 
+GIT_TEST_ADD_I_USE_BUILTIN=<boolean>, when true, enables the
+built-in version of git add -i. See 'add.interactive.useBuiltin' in
+git-config(1).
+
 GIT_TEST_INDEX_THREADS=<n> enables exercising the multi-threaded loading
 of the index for the whole test suite by bypassing the default number of
 cache entries and thread minimums. Setting this to 1 will make the
@@ -978,6 +982,15 @@
    output to the downstream---unlike the real version, it generates
    only up to 99 lines.
 
+ - test_bool_env <env-variable-name> <default-value>
+
+   Given the name of an environment variable with a bool value,
+   normalize its value to a 0 (true) or 1 (false or empty string)
+   return code.  Return with code corresponding to the given default
+   value if the variable is unset.
+   Abort the test script if either the value of the variable or the
+   default are not valid bool values.
+
 
 Prerequisites
 -------------
diff --git a/t/gitweb-lib.sh b/t/gitweb-lib.sh
index 006d2a8..1f32ca6 100644
--- a/t/gitweb-lib.sh
+++ b/t/gitweb-lib.sh
@@ -58,10 +58,11 @@
 	GATEWAY_INTERFACE='CGI/1.1'
 	HTTP_ACCEPT='*/*'
 	REQUEST_METHOD='GET'
-	QUERY_STRING=""$1""
-	PATH_INFO=""$2""
+	QUERY_STRING=$1
+	PATH_INFO=$2
+	REQUEST_URI=/gitweb.cgi$PATH_INFO
 	export GATEWAY_INTERFACE HTTP_ACCEPT REQUEST_METHOD \
-		QUERY_STRING PATH_INFO
+		QUERY_STRING PATH_INFO REQUEST_URI
 
 	GITWEB_CONFIG=$(pwd)/gitweb_config.perl
 	export GITWEB_CONFIG
diff --git a/t/helper/test-drop-caches.c b/t/helper/test-drop-caches.c
index f65e301..7b42784 100644
--- a/t/helper/test-drop-caches.c
+++ b/t/helper/test-drop-caches.c
@@ -8,18 +8,21 @@
 {
 	char Buffer[MAX_PATH];
 	DWORD dwRet;
-	char szVolumeAccessPath[] = "\\\\.\\X:";
+	char szVolumeAccessPath[] = "\\\\.\\XXXX:";
 	HANDLE hVolWrite;
-	int success = 0;
+	int success = 0, dos_drive_prefix;
 
 	dwRet = GetCurrentDirectory(MAX_PATH, Buffer);
 	if ((0 == dwRet) || (dwRet > MAX_PATH))
 		return error("Error getting current directory");
 
-	if (!has_dos_drive_prefix(Buffer))
+	dos_drive_prefix = has_dos_drive_prefix(Buffer);
+	if (!dos_drive_prefix)
 		return error("'%s': invalid drive letter", Buffer);
 
-	szVolumeAccessPath[4] = Buffer[0];
+	memcpy(szVolumeAccessPath, Buffer, dos_drive_prefix);
+	szVolumeAccessPath[dos_drive_prefix] = '\0';
+
 	hVolWrite = CreateFile(szVolumeAccessPath, GENERIC_READ | GENERIC_WRITE,
 		FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
 	if (INVALID_HANDLE_VALUE == hVolWrite)
diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c
index 5d543ad..409034c 100644
--- a/t/helper/test-path-utils.c
+++ b/t/helper/test-path-utils.c
@@ -185,6 +185,99 @@
 	return x > y ? -1 : (x < y ? +1 : 0);
 }
 
+/*
+ * A very simple, reproducible pseudo-random generator. Copied from
+ * `test-genrandom.c`.
+ */
+static uint64_t my_random_value = 1234;
+
+static uint64_t my_random(void)
+{
+	my_random_value = my_random_value * 1103515245 + 12345;
+	return my_random_value;
+}
+
+/*
+ * A fast approximation of the square root, without requiring math.h.
+ *
+ * It uses Newton's method to approximate the solution of 0 = x^2 - value.
+ */
+static double my_sqrt(double value)
+{
+	const double epsilon = 1e-6;
+	double x = value;
+
+	if (value == 0)
+		return 0;
+
+	for (;;) {
+		double delta = (value / x - x) / 2;
+		if (delta < epsilon && delta > -epsilon)
+			return x + delta;
+		x += delta;
+	}
+}
+
+static int protect_ntfs_hfs_benchmark(int argc, const char **argv)
+{
+	size_t i, j, nr, min_len = 3, max_len = 20;
+	char **names;
+	int repetitions = 15, file_mode = 0100644;
+	uint64_t begin, end;
+	double m[3][2], v[3][2];
+	uint64_t cumul;
+	double cumul2;
+
+	if (argc > 1 && !strcmp(argv[1], "--with-symlink-mode")) {
+		file_mode = 0120000;
+		argc--;
+		argv++;
+	}
+
+	nr = argc > 1 ? strtoul(argv[1], NULL, 0) : 1000000;
+	ALLOC_ARRAY(names, nr);
+
+	if (argc > 2) {
+		min_len = strtoul(argv[2], NULL, 0);
+		if (argc > 3)
+			max_len = strtoul(argv[3], NULL, 0);
+		if (min_len > max_len)
+			die("min_len > max_len");
+	}
+
+	for (i = 0; i < nr; i++) {
+		size_t len = min_len + (my_random() % (max_len + 1 - min_len));
+
+		names[i] = xmallocz(len);
+		while (len > 0)
+			names[i][--len] = (char)(' ' + (my_random() % ('\x7f' - ' ')));
+	}
+
+	for (protect_ntfs = 0; protect_ntfs < 2; protect_ntfs++)
+		for (protect_hfs = 0; protect_hfs < 2; protect_hfs++) {
+			cumul = 0;
+			cumul2 = 0;
+			for (i = 0; i < repetitions; i++) {
+				begin = getnanotime();
+				for (j = 0; j < nr; j++)
+					verify_path(names[j], file_mode);
+				end = getnanotime();
+				printf("protect_ntfs = %d, protect_hfs = %d: %lfms\n", protect_ntfs, protect_hfs, (end-begin) / (double)1e6);
+				cumul += end - begin;
+				cumul2 += (end - begin) * (end - begin);
+			}
+			m[protect_ntfs][protect_hfs] = cumul / (double)repetitions;
+			v[protect_ntfs][protect_hfs] = my_sqrt(cumul2 / (double)repetitions - m[protect_ntfs][protect_hfs] * m[protect_ntfs][protect_hfs]);
+			printf("mean: %lfms, stddev: %lfms\n", m[protect_ntfs][protect_hfs] / (double)1e6, v[protect_ntfs][protect_hfs] / (double)1e6);
+		}
+
+	for (protect_ntfs = 0; protect_ntfs < 2; protect_ntfs++)
+		for (protect_hfs = 0; protect_hfs < 2; protect_hfs++)
+			printf("ntfs=%d/hfs=%d: %lf%% slower\n", protect_ntfs, protect_hfs, (m[protect_ntfs][protect_hfs] - m[0][0]) * 100 / m[0][0]);
+
+	return 0;
+}
+
 int cmd__path_utils(int argc, const char **argv)
 {
 	if (argc == 3 && !strcmp(argv[1], "normalize_path_copy")) {
@@ -355,6 +448,26 @@
 		return !!res;
 	}
 
+	if (argc > 1 && !strcmp(argv[1], "protect_ntfs_hfs"))
+		return !!protect_ntfs_hfs_benchmark(argc - 1, argv + 1);
+
+	if (argc > 1 && !strcmp(argv[1], "is_valid_path")) {
+		int res = 0, expect = 1, i;
+
+		for (i = 2; i < argc; i++)
+			if (!strcmp("--not", argv[i]))
+				expect = 0;
+			else if (expect != is_valid_path(argv[i]))
+				res = error("'%s' is%s a valid path",
+					    argv[i], expect ? " not" : "");
+			else
+				fprintf(stderr,
+					"'%s' is%s a valid path\n",
+					argv[i], expect ? "" : " not");
+
+		return !!res;
+	}
+
 	fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
 		argv[1] ? argv[1] : "(there was none)");
 	return 1;
diff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c
new file mode 100644
index 0000000..d2884ef
--- /dev/null
+++ b/t/helper/test-read-graph.c
@@ -0,0 +1,53 @@
+#include "test-tool.h"
+#include "cache.h"
+#include "commit-graph.h"
+#include "repository.h"
+#include "object-store.h"
+
+int cmd__read_graph(int argc, const char **argv)
+{
+	struct commit_graph *graph = NULL;
+	char *graph_name;
+	int open_ok;
+	int fd;
+	struct stat st;
+	const char *object_dir;
+
+	setup_git_directory();
+	object_dir = get_object_directory();
+
+	graph_name = get_commit_graph_filename(object_dir);
+
+	open_ok = open_commit_graph(graph_name, &fd, &st);
+	if (!open_ok)
+		die_errno(_("Could not open commit-graph '%s'"), graph_name);
+
+	graph = load_commit_graph_one_fd_st(fd, &st);
+	if (!graph)
+		return 1;
+
+	FREE_AND_NULL(graph_name);
+
+	printf("header: %08x %d %d %d %d\n",
+		ntohl(*(uint32_t*)graph->data),
+		*(unsigned char*)(graph->data + 4),
+		*(unsigned char*)(graph->data + 5),
+		*(unsigned char*)(graph->data + 6),
+		*(unsigned char*)(graph->data + 7));
+	printf("num_commits: %u\n", graph->num_commits);
+	printf("chunks:");
+
+	if (graph->chunk_oid_fanout)
+		printf(" oid_fanout");
+	if (graph->chunk_oid_lookup)
+		printf(" oid_lookup");
+	if (graph->chunk_commit_data)
+		printf(" commit_metadata");
+	if (graph->chunk_extra_edges)
+		printf(" extra_edges");
+	printf("\n");
+
+	UNLEAK(graph);
+
+	return 0;
+}
diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c
index ead6dc6..1646aa2 100644
--- a/t/helper/test-run-command.c
+++ b/t/helper/test-run-command.c
@@ -18,8 +18,8 @@
 #include "string-list.h"
 #include "thread-utils.h"
 #include "wildmatch.h"
-#include <string.h>
-#include <errno.h>
+#include "gettext.h"
+#include "parse-options.h"
 
 static int number_callbacks;
 static int parallel_next(struct child_process *cp,
@@ -200,6 +200,174 @@
 	return !!ret;
 }
 
+static uint64_t my_random_next = 1234;
+
+static uint64_t my_random(void)
+{
+	uint64_t res = my_random_next;
+	my_random_next = my_random_next * 1103515245 + 12345;
+	return res;
+}
+
+static int quote_stress_test(int argc, const char **argv)
+{
+	/*
+	 * We are running a quote-stress test.
+	 * spawn a subprocess that runs quote-stress with a
+	 * special option that echoes back the arguments that
+	 * were passed in.
+	 */
+	char special[] = ".?*\\^_\"'`{}()[]<>@~&+:;$%"; // \t\r\n\a";
+	int i, j, k, trials = 100, skip = 0, msys2 = 0;
+	struct strbuf out = STRBUF_INIT;
+	struct argv_array args = ARGV_ARRAY_INIT;
+	struct option options[] = {
+		OPT_INTEGER('n', "trials", &trials, "Number of trials"),
+		OPT_INTEGER('s', "skip", &skip, "Skip <n> trials"),
+		OPT_BOOL('m', "msys2", &msys2, "Test quoting for MSYS2's sh"),
+		OPT_END()
+	};
+	const char * const usage[] = {
+		"test-tool run-command quote-stress-test <options>",
+		NULL
+	};
+
+	argc = parse_options(argc, argv, NULL, options, usage, 0);
+
+	setenv("MSYS_NO_PATHCONV", "1", 0);
+
+	for (i = 0; i < trials; i++) {
+		struct child_process cp = CHILD_PROCESS_INIT;
+		size_t arg_count, arg_offset;
+		int ret = 0;
+
+		argv_array_clear(&args);
+		if (msys2)
+			argv_array_pushl(&args, "sh", "-c",
+					 "printf %s\\\\0 \"$@\"", "skip", NULL);
+		else
+			argv_array_pushl(&args, "test-tool", "run-command",
+					 "quote-echo", NULL);
+		arg_offset = args.argc;
+
+		if (argc > 0) {
+			trials = 1;
+			arg_count = argc;
+			for (j = 0; j < arg_count; j++)
+				argv_array_push(&args, argv[j]);
+		} else {
+			arg_count = 1 + (my_random() % 5);
+			for (j = 0; j < arg_count; j++) {
+				char buf[20];
+				size_t min_len = 1;
+				size_t arg_len = min_len +
+					(my_random() % (ARRAY_SIZE(buf) - min_len));
+
+				for (k = 0; k < arg_len; k++)
+					buf[k] = special[my_random() %
+						ARRAY_SIZE(special)];
+				buf[arg_len] = '\0';
+
+				argv_array_push(&args, buf);
+			}
+		}
+
+		if (i < skip)
+			continue;
+
+		cp.argv = args.argv;
+		strbuf_reset(&out);
+		if (pipe_command(&cp, NULL, 0, &out, 0, NULL, 0) < 0)
+			return error("Failed to spawn child process");
+
+		for (j = 0, k = 0; j < arg_count; j++) {
+			const char *arg = args.argv[j + arg_offset];
+
+			if (strcmp(arg, out.buf + k))
+				ret = error("incorrectly quoted arg: '%s', "
+					    "echoed back as '%s'",
+					     arg, out.buf + k);
+			k += strlen(out.buf + k) + 1;
+		}
+
+		if (k != out.len)
+			ret = error("got %d bytes, but consumed only %d",
+				     (int)out.len, (int)k);
+
+		if (ret) {
+			fprintf(stderr, "Trial #%d failed. Arguments:\n", i);
+			for (j = 0; j < arg_count; j++)
+				fprintf(stderr, "arg #%d: '%s'\n",
+					(int)j, args.argv[j + arg_offset]);
+
+			strbuf_release(&out);
+			argv_array_clear(&args);
+
+			return ret;
+		}
+
+		if (i && (i % 100) == 0)
+			fprintf(stderr, "Trials completed: %d\n", (int)i);
+	}
+
+	strbuf_release(&out);
+	argv_array_clear(&args);
+
+	return 0;
+}
+
+static int quote_echo(int argc, const char **argv)
+{
+	while (argc > 1) {
+		fwrite(argv[1], strlen(argv[1]), 1, stdout);
+		fputc('\0', stdout);
+		argv++;
+		argc--;
+	}
+
+	return 0;
+}
+
+static int inherit_handle(const char *argv0)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+	char path[PATH_MAX];
+	int tmp;
+
+	/* First, open an inheritable handle */
+	xsnprintf(path, sizeof(path), "out-XXXXXX");
+	tmp = xmkstemp(path);
+
+	argv_array_pushl(&cp.args,
+			 "test-tool", argv0, "inherited-handle-child", NULL);
+	cp.in = -1;
+	cp.no_stdout = cp.no_stderr = 1;
+	if (start_command(&cp) < 0)
+		die("Could not start child process");
+
+	/* Then close it, and try to delete it. */
+	close(tmp);
+	if (unlink(path))
+		die("Could not delete '%s'", path);
+
+	if (close(cp.in) < 0 || finish_command(&cp) < 0)
+		die("Child did not finish");
+
+	return 0;
+}
+
+static int inherit_handle_child(void)
+{
+	struct strbuf buf = STRBUF_INIT;
+
+	if (strbuf_read(&buf, 0, 0) < 0)
+		die("Could not read stdin");
+	printf("Received %s\n", buf.buf);
+	strbuf_release(&buf);
+
+	return 0;
+}
+
 int cmd__run_command(int argc, const char **argv)
 {
 	struct child_process proc = CHILD_PROCESS_INIT;
@@ -207,6 +375,16 @@
 
 	if (argc > 1 && !strcmp(argv[1], "testsuite"))
 		exit(testsuite(argc - 1, argv + 1));
+	if (!strcmp(argv[1], "inherited-handle"))
+		exit(inherit_handle(argv[0]));
+	if (!strcmp(argv[1], "inherited-handle-child"))
+		exit(inherit_handle_child());
+
+	if (argc >= 2 && !strcmp(argv[1], "quote-stress-test"))
+		return !!quote_stress_test(argc - 1, argv + 1);
+
+	if (argc >= 2 && !strcmp(argv[1], "quote-echo"))
+		return !!quote_echo(argc - 1, argv + 1);
 
 	if (argc < 3)
 		return 1;
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 19ee26d..f20989d 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -45,6 +45,7 @@
 	{ "progress", cmd__progress },
 	{ "reach", cmd__reach },
 	{ "read-cache", cmd__read_cache },
+	{ "read-graph", cmd__read_graph },
 	{ "read-midx", cmd__read_midx },
 	{ "ref-store", cmd__ref_store },
 	{ "regex", cmd__regex },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index c2aa56e..8ed2af7 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -35,6 +35,7 @@
 int cmd__progress(int argc, const char **argv);
 int cmd__reach(int argc, const char **argv);
 int cmd__read_cache(int argc, const char **argv);
+int cmd__read_graph(int argc, const char **argv);
 int cmd__read_midx(int argc, const char **argv);
 int cmd__ref_store(int argc, const char **argv);
 int cmd__regex(int argc, const char **argv);
diff --git a/t/lib-bash.sh b/t/lib-bash.sh
index 2be955f..b0b6060 100644
--- a/t/lib-bash.sh
+++ b/t/lib-bash.sh
@@ -2,10 +2,12 @@
 # to run under Bash; primarily intended for tests of the completion
 # script.
 
-if test -n "$BASH" && test -z "$POSIXLY_CORRECT"; then
+if test -n "$BASH" && test -z "$POSIXLY_CORRECT"
+then
 	# we are in full-on bash mode
 	true
-elif type bash >/dev/null 2>&1; then
+elif type bash >/dev/null 2>&1
+then
 	# execute in full-on bash mode
 	unset POSIXLY_CORRECT
 	exec bash "$0" "$@"
diff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh
index fb8f887..e625692 100644
--- a/t/lib-git-daemon.sh
+++ b/t/lib-git-daemon.sh
@@ -15,7 +15,7 @@
 #
 #	test_done
 
-if ! git env--helper --type=bool --default=true --exit-code GIT_TEST_GIT_DAEMON
+if ! test_bool_env GIT_TEST_GIT_DAEMON true
 then
 	skip_all="git-daemon testing disabled (unset GIT_TEST_GIT_DAEMON to enable)"
 	test_done
diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh
index bc0b9c7..7d248e6 100644
--- a/t/lib-git-svn.sh
+++ b/t/lib-git-svn.sh
@@ -69,7 +69,7 @@
 maybe_start_httpd () {
 	loc=${1-svn}
 
-	if git env--helper --type=bool --default=false --exit-code GIT_TEST_SVN_HTTPD
+	if test_bool_env GIT_TEST_SVN_HTTPD false
 	then
 		. "$TEST_DIRECTORY"/lib-httpd.sh
 		LIB_HTTPD_SVN="$loc"
@@ -104,7 +104,7 @@
 }
 
 require_svnserve () {
-	if ! git env--helper --type=bool --default=false --exit-code GIT_TEST_SVNSERVE
+	if ! test_bool_env GIT_TEST_SVNSERVE false
 	then
 		skip_all='skipping svnserve test. (set $GIT_TEST_SVNSERVE to enable)'
 		test_done
diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index 0d98575..656997b 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -41,7 +41,7 @@
 	test_done
 fi
 
-if ! git env--helper --type=bool --default=true --exit-code GIT_TEST_HTTPD
+if ! test_bool_env GIT_TEST_HTTPD true
 then
 	skip_all="Network testing disabled (unset GIT_TEST_HTTPD to enable)"
 	test_done
diff --git a/t/lib-httpd/apply-one-time-sed.sh b/t/lib-httpd/apply-one-time-sed.sh
index fcef728..bf7689d 100644
--- a/t/lib-httpd/apply-one-time-sed.sh
+++ b/t/lib-httpd/apply-one-time-sed.sh
@@ -7,11 +7,13 @@
 #
 # This can be used to simulate the effects of the repository changing in
 # between HTTP request-response pairs.
-if [ -e one-time-sed ]; then
+if test -f one-time-sed
+then
 	"$GIT_EXEC_PATH/git-http-backend" >out
-	sed "$(cat one-time-sed)" <out >out_modified
+	sed "$(cat one-time-sed)" out >out_modified
 
-	if diff out out_modified >/dev/null; then
+	if cmp -s out out_modified
+	then
 		cat out
 	else
 		cat out_modified
diff --git a/t/perf/aggregate.perl b/t/perf/aggregate.perl
index 66554d2..14e4cda 100755
--- a/t/perf/aggregate.perl
+++ b/t/perf/aggregate.perl
@@ -4,7 +4,6 @@
 use strict;
 use warnings;
 use Getopt::Long;
-use Git;
 use Cwd qw(realpath);
 
 sub get_times {
@@ -85,6 +84,11 @@
 	return $out;
 }
 
+sub sane_backticks {
+	open(my $fh, '-|', @_);
+	return <$fh>;
+}
+
 my (@dirs, %dirnames, %dirabbrevs, %prefixes, @tests,
     $codespeed, $sortby, $subsection, $reponame);
 
@@ -102,7 +106,8 @@
 	my $prefix = '';
 	last if -f $arg or $arg eq "--";
 	if (! -d $arg) {
-		my $rev = Git::command_oneline(qw(rev-parse --verify), $arg);
+		my $rev = sane_backticks(qw(git rev-parse --verify), $arg);
+		chomp $rev;
 		$dir = "build/".$rev;
 	} elsif ($arg eq '.') {
 		$dir = '.';
@@ -219,13 +224,7 @@
 		for my $i (0..$#dirs) {
 			my $d = $dirs[$i];
 			my $base = "$resultsdir/$prefixes{$d}$t";
-			$times{$prefixes{$d}.$t} = [];
-			foreach my $type (qw(times size)) {
-				if (-e "$base.$type") {
-					$times{$prefixes{$d}.$t} = [get_times("$base.$type")];
-					last;
-				}
-			}
+			$times{$prefixes{$d}.$t} = [get_times("$base.result")];
 			my ($r,$u,$s) = @{$times{$prefixes{$d}.$t}};
 			my $w = length format_times($r,$u,$s,$firstr);
 			$colwidth[$i] = $w if $w > $colwidth[$i];
@@ -267,7 +266,7 @@
 		my ($prevr, $prevu, $prevs, $prevrev);
 		for my $i (0..$#dirs) {
 			my $d = $dirs[$i];
-			my ($r, $u, $s) = get_times("$resultsdir/$prefixes{$d}$t.times");
+			my ($r, $u, $s) = get_times("$resultsdir/$prefixes{$d}$t.result");
 			if ($i > 0 and defined $r and defined $prevr and $prevr > 0) {
 				my $percent = 100.0 * ($r - $prevr) / $prevr;
 				push @evolutions, { "percent"  => $percent,
@@ -327,7 +326,7 @@
 			my $commitid = $prefixes{$d};
 			$commitid =~ s/^build_//;
 			$commitid =~ s/\.$//;
-			my ($result_value, $u, $s) = get_times("$resultsdir/$prefixes{$d}$t.times");
+			my ($result_value, $u, $s) = get_times("$resultsdir/$prefixes{$d}$t.result");
 
 			my %vals = (
 				"commitid" => $commitid,
diff --git a/t/perf/bisect_regression b/t/perf/bisect_regression
index a94d995..ce47e16 100755
--- a/t/perf/bisect_regression
+++ b/t/perf/bisect_regression
@@ -51,7 +51,7 @@
 newtime=$(echo "$newtime" | sed -e 's/^\([0-9]\+\.[0-9]\+\).*$/\1/')
 
 test $(echo "$newtime" "$oldtime" | awk '{ print ($1 > $2) }') = 1 ||
-	die "New time '$newtime' shoud be greater than old time '$oldtime'"
+	die "New time '$newtime' should be greater than old time '$oldtime'"
 
 tmpdir=$(mktemp -d -t bisect_regression_XXXXXX) || die "Failed to create temp directory"
 echo "$oldtime" >"$tmpdir/oldtime" || die "Failed to write to '$tmpdir/oldtime'"
diff --git a/t/perf/p5303-many-packs.sh b/t/perf/p5303-many-packs.sh
index 3779851..7ee7916 100755
--- a/t/perf/p5303-many-packs.sh
+++ b/t/perf/p5303-many-packs.sh
@@ -77,6 +77,7 @@
 	# actual pack generation, without smudging the on-disk setup
 	# between trials.
 	test_perf "repack ($nr_packs)" '
+		GIT_TEST_FULL_IN_PACK_ARRAY=1 \
 		git pack-objects --keep-true-parents \
 		  --honor-pack-keep --non-empty --all \
 		  --reflog --indexed-objects --delta-base-offset \
@@ -84,4 +85,22 @@
 	'
 done
 
+# Measure pack loading with 10,000 packs.
+test_expect_success 'generate lots of packs' '
+	for i in $(test_seq 10000); do
+		echo "blob"
+		echo "data <<EOF"
+		echo "blob $i"
+		echo "EOF"
+		echo "checkpoint"
+	done |
+	git -c fastimport.unpackLimit=0 fast-import
+'
+
+# The purpose of this test is to evaluate load time for a large number
+# of packs while doing as little other work as possible.
+test_perf "load 10,000 packs" '
+	git rev-parse --verify "HEAD^{commit}"
+'
+
 test_done
diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh
index b58a43e..13e3893 100644
--- a/t/perf/perf-lib.sh
+++ b/t/perf/perf-lib.sh
@@ -214,7 +214,7 @@
 	else
 		test_ok_ "$1"
 	fi
-	"$TEST_DIRECTORY"/perf/min_time.perl test_time.* >"$base".times
+	"$TEST_DIRECTORY"/perf/min_time.perl test_time.* >"$base".result
 }
 
 test_perf () {
@@ -223,7 +223,7 @@
 
 test_size_ () {
 	say >&3 "running: $2"
-	if test_eval_ "$2" 3>"$base".size; then
+	if test_eval_ "$2" 3>"$base".result; then
 		test_ok_ "$1"
 	else
 		test_failure_ "$@"
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 4d3f7ba..8a81a24 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -20,9 +20,9 @@
 
 . ./test-lib.sh
 
-try_local_x () {
-	local x="local" &&
-	echo "$x"
+try_local_xy () {
+	local x="local" y="alsolocal" &&
+	echo "$x $y"
 }
 
 # Check whether the shell supports the "local" keyword. "local" is not
@@ -35,11 +35,12 @@
 # relying on "local".
 test_expect_success 'verify that the running shell supports "local"' '
 	x="notlocal" &&
-	echo "local" >expected1 &&
-	try_local_x >actual1 &&
+	y="alsonotlocal" &&
+	echo "local alsolocal" >expected1 &&
+	try_local_xy >actual1 &&
 	test_cmp expected1 actual1 &&
-	echo "notlocal" >expected2 &&
-	echo "$x" >actual2 &&
+	echo "notlocal alsonotlocal" >expected2 &&
+	echo "$x $y" >actual2 &&
 	test_cmp expected2 actual2
 '
 
@@ -126,7 +127,7 @@
 
 check_sub_test_lib_test_err () {
 	name="$1" # stdin is the expected output from the test
-	# expected error output is in descriptior 3
+	# expected error output is in descriptor 3
 	(
 		cd "$name" &&
 		sed -e 's/^> //' -e 's/Z$//' >expect.out &&
@@ -916,6 +917,40 @@
 	test "$hexsz" -eq 64
 '
 
+test_expect_success 'test_bool_env' '
+	(
+		sane_unset envvar &&
+
+		test_bool_env envvar true &&
+		! test_bool_env envvar false &&
+
+		envvar= &&
+		export envvar &&
+		! test_bool_env envvar true &&
+		! test_bool_env envvar false &&
+
+		envvar=true &&
+		test_bool_env envvar true &&
+		test_bool_env envvar false &&
+
+		envvar=false &&
+		! test_bool_env envvar true &&
+		! test_bool_env envvar false &&
+
+		envvar=invalid &&
+		# When encountering an invalid bool value, test_bool_env
+		# prints its error message to the original stderr of the
+		# test script, hence the redirection of fd 7, and aborts
+		# with "exit 1", hence the subshell.
+		! ( test_bool_env envvar true ) 7>err &&
+		grep "error: test_bool_env requires bool values" err &&
+
+		envvar=true &&
+		! ( test_bool_env envvar invalid ) 7>err &&
+		grep "error: test_bool_env requires bool values" err
+	)
+'
+
 ################################################################
 # Basics of the basics
 
diff --git a/t/t0014-alias.sh b/t/t0014-alias.sh
index 2694c81..8d3d914 100755
--- a/t/t0014-alias.sh
+++ b/t/t0014-alias.sh
@@ -38,8 +38,8 @@
 #'
 
 test_expect_success 'run-command formats empty args properly' '
-    GIT_TRACE=1 git frotz a "" b " " c 2>&1 |
-    sed -ne "/run_command:/s/.*trace: run_command: //p" >actual &&
+    test_must_fail env GIT_TRACE=1 git frotz a "" b " " c 2>actual.raw &&
+    sed -ne "/run_command:/s/.*trace: run_command: //p" actual.raw >actual &&
     echo "git-frotz a '\'''\'' b '\'' '\'' c" >expect &&
     test_cmp expect actual
 '
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index c954c70..6c6d77b 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -35,7 +35,7 @@
 # Compare two files and ensure that `clean` and `smudge` respectively are
 # called at least once if specified in the `expect` file. The actual
 # invocation count is not relevant because their number can vary.
-# c.f. http://public-inbox.org/git/xmqqshv18i8i.fsf@gitster.mtv.corp.google.com/
+# c.f. http://lore.kernel.org/git/xmqqshv18i8i.fsf@gitster.mtv.corp.google.com/
 test_cmp_count () {
 	expect=$1
 	actual=$2
@@ -50,7 +50,7 @@
 
 # Compare two files but exclude all `clean` invocations because Git can
 # call `clean` zero or more times.
-# c.f. http://public-inbox.org/git/xmqqshv18i8i.fsf@gitster.mtv.corp.google.com/
+# c.f. http://lore.kernel.org/git/xmqqshv18i8i.fsf@gitster.mtv.corp.google.com/
 test_cmp_exclude_clean () {
 	expect=$1
 	actual=$2
diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh
index 959b6da..9fcd56f 100755
--- a/t/t0027-auto-crlf.sh
+++ b/t/t0027-auto-crlf.sh
@@ -215,7 +215,7 @@
 }
 
 
-# contruct the attr/ returned by git ls-files --eol
+# construct the attr/ returned by git ls-files --eol
 # Take none (=empty), one or two args
 # convert.c: eol=XX overrides text=auto
 attr_ascii () {
diff --git a/t/t0028-working-tree-encoding.sh b/t/t0028-working-tree-encoding.sh
index 7aa0945..bfc4fb9 100755
--- a/t/t0028-working-tree-encoding.sh
+++ b/t/t0028-working-tree-encoding.sh
@@ -17,7 +17,7 @@
 write_utf16 () {
 	if test_have_prereq NO_UTF16_BOM
 	then
-		printf '\xfe\xff'
+		printf '\376\377'
 	fi &&
 	iconv -f UTF-8 -t UTF-16
 }
@@ -25,7 +25,7 @@
 write_utf32 () {
 	if test_have_prereq NO_UTF32_BOM
 	then
-		printf '\x00\x00\xfe\xff'
+		printf '\0\0\376\377'
 	fi &&
 	iconv -f UTF-8 -t UTF-32
 }
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 501e1a2..2ea2d00 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -165,6 +165,15 @@
 	test_must_fail test-tool path-utils absolute_path ""
 '
 
+test_expect_success MINGW '<drive-letter>:\\abc is an absolute path' '
+	for letter in : \" C Z 1 ä
+	do
+		path=$letter:\\abc &&
+		absolute="$(test-tool path-utils absolute_path "$path")" &&
+		test "$path" = "$absolute" || return 1
+	done
+'
+
 test_expect_success 'real path rejects the empty string' '
 	test_must_fail test-tool path-utils real_path ""
 '
@@ -285,8 +294,10 @@
 test_git_path GIT_OBJECT_DIRECTORY=foo objects2 .git/objects2
 test_expect_success 'setup common repository' 'git --git-dir=bar init'
 test_git_path GIT_COMMON_DIR=bar index                    .git/index
+test_git_path GIT_COMMON_DIR=bar index.lock               .git/index.lock
 test_git_path GIT_COMMON_DIR=bar HEAD                     .git/HEAD
 test_git_path GIT_COMMON_DIR=bar logs/HEAD                .git/logs/HEAD
+test_git_path GIT_COMMON_DIR=bar logs/HEAD.lock           .git/logs/HEAD.lock
 test_git_path GIT_COMMON_DIR=bar logs/refs/bisect/foo     .git/logs/refs/bisect/foo
 test_git_path GIT_COMMON_DIR=bar logs/refs                bar/logs/refs
 test_git_path GIT_COMMON_DIR=bar logs/refs/               bar/logs/refs/
@@ -425,6 +436,9 @@
 		~1000000 \
 		~9999999 \
 		\
+		.gitmodules:\$DATA \
+		"gitmod~4 . :\$DATA" \
+		\
 		--not \
 		".gitmodules x"  \
 		".gitmodules .x" \
@@ -449,7 +463,34 @@
 		\
 		GI7EB~1 \
 		GI7EB~01 \
-		GI7EB~1X
+		GI7EB~1X \
+		\
+		.gitmodules,:\$DATA
+'
+
+test_expect_success MINGW 'is_valid_path() on Windows' '
+	test-tool path-utils is_valid_path \
+		win32 \
+		"win32 x" \
+		../hello.txt \
+		C:\\git \
+		comm \
+		conout.c \
+		lptN \
+		\
+		--not \
+		"win32 "  \
+		"win32 /x "  \
+		"win32."  \
+		"win32 . ." \
+		.../hello.txt \
+		colon:test \
+		"AUX.c" \
+		"abc/conOut\$  .xyz/test" \
+		lpt8 \
+		"lpt*" \
+		Nul \
+		"PRN./abc"
 '
 
 test_done
diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh
index 17c9c0f..7d59967 100755
--- a/t/t0061-run-command.sh
+++ b/t/t0061-run-command.sh
@@ -12,6 +12,10 @@
 	cat hello-script
 EOF
 
+test_expect_success MINGW 'subprocess inherits only std handles' '
+	test-tool run-command inherited-handle
+'
+
 test_expect_success 'start_command reports ENOENT (slash)' '
 	test-tool run-command start-command-ENOENT ./does-not-exist 2>err &&
 	test_i18ngrep "\./does-not-exist" err
diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh
index ce9a4a5..5a63369 100755
--- a/t/t0090-cache-tree.sh
+++ b/t/t0090-cache-tree.sh
@@ -21,9 +21,10 @@
 	parent="$2" &&
 	# ls-files might have foo/bar, foo/bar/baz, and foo/bar/quux
 	# We want to count only foo because it's the only direct child
-	subtrees=$(git ls-files|grep /|cut -d / -f 1|uniq) &&
+	git ls-files >files &&
+	subtrees=$(grep / files|cut -d / -f 1|uniq) &&
 	subtree_count=$(echo "$subtrees"|awk -v c=0 '$1 != "" {++c} END {print c}') &&
-	entries=$(git ls-files|wc -l) &&
+	entries=$(wc -l <files) &&
 	printf "SHA $dir (%d entries, %d subtrees)\n" "$entries" "$subtree_count" &&
 	for subtree in $subtrees
 	do
diff --git a/t/t0500-progress-display.sh b/t/t0500-progress-display.sh
index 24ccbd8..d2d088d 100755
--- a/t/t0500-progress-display.sh
+++ b/t/t0500-progress-display.sh
@@ -76,7 +76,7 @@
 '
 
 test_expect_success 'progress display breaks long lines #2' '
-	# Note: we dont need that many spaces after the title to cover up
+	# Note: we do not need that many spaces after the title to cover up
 	# the last line before breaking the progress line.
 	sed -e "s/Z$//" >expect <<\EOF &&
 Working hard.......2.........3.........4.........5.........6:   0% (1/100000)<CR>
@@ -104,7 +104,7 @@
 '
 
 test_expect_success 'progress display breaks long lines #3 - even the first is too long' '
-	# Note: we dont actually need any spaces at the end of the title
+	# Note: we do not actually need any spaces at the end of the title
 	# line, because there is no previous progress line to cover up.
 	sed -e "s/Z$//" >expect <<\EOF &&
 Working hard.......2.........3.........4.........5.........6:                   Z
diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh
index ba71b15..eb44baf 100755
--- a/t/t1011-read-tree-sparse-checkout.sh
+++ b/t/t1011-read-tree-sparse-checkout.sh
@@ -215,7 +215,6 @@
 '
 
 test_expect_success 'index removal and worktree narrowing at the same time' '
-	>empty &&
 	echo init.t >.git/info/sparse-checkout &&
 	echo sub/added >>.git/info/sparse-checkout &&
 	git checkout -f top &&
@@ -223,7 +222,7 @@
 	git checkout removed &&
 	git ls-files sub/added >result &&
 	test ! -f sub/added &&
-	test_cmp empty result
+	test_must_be_empty result
 '
 
 test_expect_success 'read-tree --reset removes outside worktree' '
diff --git a/t/t1014-read-tree-confusing.sh b/t/t1014-read-tree-confusing.sh
index 2f5a25d..da3376b 100755
--- a/t/t1014-read-tree-confusing.sh
+++ b/t/t1014-read-tree-confusing.sh
@@ -49,6 +49,7 @@
 .git.SPACE .git.{space}
 .\\\\.GIT\\\\foobar backslashes
 .git\\\\foobar backslashes2
+.git...:alternate-stream
 EOF
 
 test_expect_success 'utf-8 paths allowed with core.protectHFS off' '
diff --git a/t/t1050-large.sh b/t/t1050-large.sh
index dcb4dbb..d3b2adb 100755
--- a/t/t1050-large.sh
+++ b/t/t1050-large.sh
@@ -194,15 +194,15 @@
 	test_cmp huge actual
 '
 
-test_expect_success 'tar achiving' '
+test_expect_success 'tar archiving' '
 	git archive --format=tar HEAD >/dev/null
 '
 
-test_expect_success 'zip achiving, store only' '
+test_expect_success 'zip archiving, store only' '
 	git archive --format=zip -0 HEAD >/dev/null
 '
 
-test_expect_success 'zip achiving, deflate' '
+test_expect_success 'zip archiving, deflate' '
 	git archive --format=zip HEAD >/dev/null
 '
 
diff --git a/t/t1309-early-config.sh b/t/t1309-early-config.sh
index 3a0de0d..ebb8e1a 100755
--- a/t/t1309-early-config.sh
+++ b/t/t1309-early-config.sh
@@ -29,7 +29,7 @@
 		cd sub &&
 		test-tool config read_early_config early.config
 	) >output &&
-	test -z "$(cat output)"
+	test_must_be_empty output
 '
 
 test_expect_success 'ceiling #2' '
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 1fbd940..b815cdd 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -344,14 +344,16 @@
 	test_cmp expect .git/logs/$m
 '
 
-git update-ref $m $D
-cat >.git/logs/$m <<EOF
-$Z $C $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150320 -0500
-$C $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150350 -0500
-$A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150380 -0500
-$F $Z $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150680 -0500
-$Z $E $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150980 -0500
-EOF
+test_expect_success 'set up for querying the reflog' '
+	git update-ref $m $D &&
+	cat >.git/logs/$m <<-EOF
+	$Z $C $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150320 -0500
+	$C $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150350 -0500
+	$A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150380 -0500
+	$F $Z $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150680 -0500
+	$Z $E $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150980 -0500
+	EOF
+'
 
 ed="Thu, 26 May 2005 18:32:00 -0500"
 gd="Thu, 26 May 2005 18:33:00 -0500"
@@ -378,13 +380,13 @@
 	test_when_finished "rm -f o e" &&
 	git rev-parse --verify "master@{May 26 2005 23:32:00}" >o 2>e &&
 	test $C = $(cat o) &&
-	test "" = "$(cat e)"
+	test_must_be_empty e
 '
 test_expect_success 'Query "master@{May 26 2005 23:32:30}" (first non-creation change)' '
 	test_when_finished "rm -f o e" &&
 	git rev-parse --verify "master@{May 26 2005 23:32:30}" >o 2>e &&
 	test $A = $(cat o) &&
-	test "" = "$(cat e)"
+	test_must_be_empty e
 '
 test_expect_success 'Query "master@{2005-05-26 23:33:01}" (middle of history with gap)' '
 	test_when_finished "rm -f o e" &&
@@ -396,13 +398,13 @@
 	test_when_finished "rm -f o e" &&
 	git rev-parse --verify "master@{2005-05-26 23:38:00}" >o 2>e &&
 	test $Z = $(cat o) &&
-	test "" = "$(cat e)"
+	test_must_be_empty e
 '
 test_expect_success 'Query "master@{2005-05-26 23:43:00}" (exact end of history)' '
 	test_when_finished "rm -f o e" &&
 	git rev-parse --verify "master@{2005-05-26 23:43:00}" >o 2>e &&
 	test $E = $(cat o) &&
-	test "" = "$(cat e)"
+	test_must_be_empty e
 '
 test_expect_success 'Query "master@{2005-05-28}" (past end of history)' '
 	test_when_finished "rm -f o e" &&
diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh
index 82950c0..76d9b74 100755
--- a/t/t1410-reflog.sh
+++ b/t/t1410-reflog.sh
@@ -195,7 +195,7 @@
 
 	git reflog delete master@{1} &&
 	git reflog show master > output &&
-	test $(($master_entry_count - 1)) = $(wc -l < output) &&
+	test_line_count = $(($master_entry_count - 1)) output &&
 	test $HEAD_entry_count = $(git reflog | wc -l) &&
 	! grep ox < output &&
 
@@ -209,7 +209,7 @@
 
 	git reflog delete master@{07.04.2005.15:15:00.-0700} &&
 	git reflog show master > output &&
-	test $(($master_entry_count - 1)) = $(wc -l < output) &&
+	test_line_count = $(($master_entry_count - 1)) output &&
 	! grep dragon < output
 
 '
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 50d28e6..02478bc 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -441,6 +441,7 @@
 		(
 			git init $name-$type &&
 			cd $name-$type &&
+			git config core.protectNTFS false &&
 			echo content >file &&
 			git add file &&
 			git commit -m base &&
@@ -616,7 +617,7 @@
 		remove_object $(git rev-parse julius:caesar.t) &&
 		test_must_fail git fsck --name-objects >out &&
 		tree=$(git rev-parse --verify julius:) &&
-		test_i18ngrep -E "$tree \((refs/heads/master|HEAD)@\{[0-9]*\}:" out
+		test_i18ngrep "$tree (refs/tags/julius:" out
 	)
 '
 
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
index 0177fd8..603019b 100755
--- a/t/t1500-rev-parse.sh
+++ b/t/t1500-rev-parse.sh
@@ -146,6 +146,16 @@
 	grep "unknown mode for --show-object-format: squeamish-ossifrage" err
 '
 
+test_expect_success '--show-toplevel from subdir of working tree' '
+	pwd >expect &&
+	git -C sub/dir rev-parse --show-toplevel >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success '--show-toplevel from inside .git' '
+	test_must_fail git -C .git rev-parse --show-toplevel
+'
+
 test_expect_success 'showing the superproject correctly' '
 	git rev-parse --show-superproject-working-tree >out &&
 	test_must_be_empty out &&
diff --git a/t/t1506-rev-parse-diagnosis.sh b/t/t1506-rev-parse-diagnosis.sh
index 624d0a5..6d951ca 100755
--- a/t/t1506-rev-parse-diagnosis.sh
+++ b/t/t1506-rev-parse-diagnosis.sh
@@ -138,10 +138,10 @@
 
 test_expect_success 'invalid @{n} reference' '
 	test_must_fail git rev-parse master@{99999} >output 2>error &&
-	test -z "$(cat output)" &&
+	test_must_be_empty output &&
 	grep "fatal: Log for [^ ]* only has [0-9][0-9]* entries." error  &&
 	test_must_fail git rev-parse --verify master@{99999} >output 2>error &&
-	test -z "$(cat output)" &&
+	test_must_be_empty output &&
 	grep "fatal: Log for [^ ]* only has [0-9][0-9]* entries." error
 '
 
@@ -155,13 +155,13 @@
 
 test_expect_success 'relative path outside worktree' '
 	test_must_fail git rev-parse HEAD:../file.txt >output 2>error &&
-	test -z "$(cat output)" &&
+	test_must_be_empty output &&
 	test_i18ngrep "outside repository" error
 '
 
 test_expect_success 'relative path when cwd is outside worktree' '
 	test_must_fail git --git-dir=.git --work-tree=subdir rev-parse HEAD:./file.txt >output 2>error &&
-	test -z "$(cat output)" &&
+	test_must_be_empty output &&
 	grep "relative path syntax can.t be used outside working tree." error
 '
 
diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh
index c19fb50..18fa6cf 100755
--- a/t/t1512-rev-parse-disambiguation.sh
+++ b/t/t1512-rev-parse-disambiguation.sh
@@ -282,7 +282,7 @@
 	# commits created by commit-tree in earlier tests share a
 	# different prefix.
 	git rev-parse --disambiguate=000000000 >actual &&
-	test $(wc -l <actual) = 16 &&
+	test_line_count = 16 actual &&
 	test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000
 '
 
@@ -339,7 +339,7 @@
 test_expect_success C_LOCALE_OUTPUT 'ambiguity hints respect type' '
 	test_must_fail git rev-parse 000000000^{commit} 2>stderr &&
 	grep ^hint: stderr >hints &&
-	# 5 commits, 1 tag (which is a commitish), plus intro line
+	# 5 commits, 1 tag (which is a committish), plus intro line
 	test_line_count = 7 hints
 '
 
diff --git a/t/t2026-checkout-pathspec-file.sh b/t/t2026-checkout-pathspec-file.sh
new file mode 100755
index 0000000..f62fd27
--- /dev/null
+++ b/t/t2026-checkout-pathspec-file.sh
@@ -0,0 +1,139 @@
+#!/bin/sh
+
+test_description='checkout --pathspec-from-file'
+
+. ./test-lib.sh
+
+test_tick
+
+test_expect_success setup '
+	test_commit file0 &&
+
+	echo 1 >fileA.t &&
+	echo 1 >fileB.t &&
+	echo 1 >fileC.t &&
+	echo 1 >fileD.t &&
+	git add fileA.t fileB.t fileC.t fileD.t &&
+	git commit -m "files 1" &&
+
+	echo 2 >fileA.t &&
+	echo 2 >fileB.t &&
+	echo 2 >fileC.t &&
+	echo 2 >fileD.t &&
+	git add fileA.t fileB.t fileC.t fileD.t &&
+	git commit -m "files 2" &&
+
+	git tag checkpoint
+'
+
+restore_checkpoint () {
+	git reset --hard checkpoint
+}
+
+verify_expect () {
+	git status --porcelain --untracked-files=no -- fileA.t fileB.t fileC.t fileD.t >actual &&
+	test_cmp expect actual
+}
+
+test_expect_success '--pathspec-from-file from stdin' '
+	restore_checkpoint &&
+
+	echo fileA.t | git checkout --pathspec-from-file=- HEAD^1 &&
+
+	cat >expect <<-\EOF &&
+	M  fileA.t
+	EOF
+	verify_expect
+'
+
+test_expect_success '--pathspec-from-file from file' '
+	restore_checkpoint &&
+
+	echo fileA.t >list &&
+	git checkout --pathspec-from-file=list HEAD^1 &&
+
+	cat >expect <<-\EOF &&
+	M  fileA.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'NUL delimiters' '
+	restore_checkpoint &&
+
+	printf "fileA.t\0fileB.t\0" | git checkout --pathspec-from-file=- --pathspec-file-nul HEAD^1 &&
+
+	cat >expect <<-\EOF &&
+	M  fileA.t
+	M  fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'LF delimiters' '
+	restore_checkpoint &&
+
+	printf "fileA.t\nfileB.t\n" | git checkout --pathspec-from-file=- HEAD^1 &&
+
+	cat >expect <<-\EOF &&
+	M  fileA.t
+	M  fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'no trailing delimiter' '
+	restore_checkpoint &&
+
+	printf "fileA.t\nfileB.t" | git checkout --pathspec-from-file=- HEAD^1 &&
+
+	cat >expect <<-\EOF &&
+	M  fileA.t
+	M  fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'CRLF delimiters' '
+	restore_checkpoint &&
+
+	printf "fileA.t\r\nfileB.t\r\n" | git checkout --pathspec-from-file=- HEAD^1 &&
+
+	cat >expect <<-\EOF &&
+	M  fileA.t
+	M  fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'quotes' '
+	restore_checkpoint &&
+
+	printf "\"file\\101.t\"" | git checkout --pathspec-from-file=- HEAD^1 &&
+
+	cat >expect <<-\EOF &&
+	M  fileA.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'quotes not compatible with --pathspec-file-nul' '
+	restore_checkpoint &&
+
+	printf "\"file\\101.t\"" >list &&
+	test_must_fail git checkout --pathspec-from-file=list --pathspec-file-nul HEAD^1
+'
+
+test_expect_success 'only touches what was listed' '
+	restore_checkpoint &&
+
+	printf "fileB.t\nfileC.t\n" | git checkout --pathspec-from-file=- HEAD^1 &&
+
+	cat >expect <<-\EOF &&
+	M  fileB.t
+	M  fileC.t
+	EOF
+	verify_expect
+'
+
+test_done
diff --git a/t/t2072-restore-pathspec-file.sh b/t/t2072-restore-pathspec-file.sh
new file mode 100755
index 0000000..db58e83
--- /dev/null
+++ b/t/t2072-restore-pathspec-file.sh
@@ -0,0 +1,139 @@
+#!/bin/sh
+
+test_description='restore --pathspec-from-file'
+
+. ./test-lib.sh
+
+test_tick
+
+test_expect_success setup '
+	test_commit file0 &&
+
+	echo 1 >fileA.t &&
+	echo 1 >fileB.t &&
+	echo 1 >fileC.t &&
+	echo 1 >fileD.t &&
+	git add fileA.t fileB.t fileC.t fileD.t &&
+	git commit -m "files 1" &&
+
+	echo 2 >fileA.t &&
+	echo 2 >fileB.t &&
+	echo 2 >fileC.t &&
+	echo 2 >fileD.t &&
+	git add fileA.t fileB.t fileC.t fileD.t &&
+	git commit -m "files 2" &&
+
+	git tag checkpoint
+'
+
+restore_checkpoint () {
+	git reset --hard checkpoint
+}
+
+verify_expect () {
+	git status --porcelain --untracked-files=no -- fileA.t fileB.t fileC.t fileD.t >actual &&
+	test_cmp expect actual
+}
+
+test_expect_success '--pathspec-from-file from stdin' '
+	restore_checkpoint &&
+
+	echo fileA.t | git restore --pathspec-from-file=- --source=HEAD^1 &&
+
+	cat >expect <<-\EOF &&
+	 M fileA.t
+	EOF
+	verify_expect
+'
+
+test_expect_success '--pathspec-from-file from file' '
+	restore_checkpoint &&
+
+	echo fileA.t >list &&
+	git restore --pathspec-from-file=list --source=HEAD^1 &&
+
+	cat >expect <<-\EOF &&
+	 M fileA.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'NUL delimiters' '
+	restore_checkpoint &&
+
+	printf "fileA.t\0fileB.t\0" | git restore --pathspec-from-file=- --pathspec-file-nul --source=HEAD^1 &&
+
+	cat >expect <<-\EOF &&
+	 M fileA.t
+	 M fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'LF delimiters' '
+	restore_checkpoint &&
+
+	printf "fileA.t\nfileB.t\n" | git restore --pathspec-from-file=- --source=HEAD^1 &&
+
+	cat >expect <<-\EOF &&
+	 M fileA.t
+	 M fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'no trailing delimiter' '
+	restore_checkpoint &&
+
+	printf "fileA.t\nfileB.t" | git restore --pathspec-from-file=- --source=HEAD^1 &&
+
+	cat >expect <<-\EOF &&
+	 M fileA.t
+	 M fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'CRLF delimiters' '
+	restore_checkpoint &&
+
+	printf "fileA.t\r\nfileB.t\r\n" | git restore --pathspec-from-file=- --source=HEAD^1 &&
+
+	cat >expect <<-\EOF &&
+	 M fileA.t
+	 M fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'quotes' '
+	restore_checkpoint &&
+
+	printf "\"file\\101.t\"" | git restore --pathspec-from-file=- --source=HEAD^1 &&
+
+	cat >expect <<-\EOF &&
+	 M fileA.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'quotes not compatible with --pathspec-file-nul' '
+	restore_checkpoint &&
+
+	printf "\"file\\101.t\"" >list &&
+	test_must_fail git restore --pathspec-from-file=list --pathspec-file-nul --source=HEAD^1
+'
+
+test_expect_success 'only touches what was listed' '
+	restore_checkpoint &&
+
+	printf "fileB.t\nfileC.t\n" | git restore --pathspec-from-file=- --source=HEAD^1 &&
+
+	cat >expect <<-\EOF &&
+	 M fileB.t
+	 M fileC.t
+	EOF
+	verify_expect
+'
+
+test_done
diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh
index e819ba7..b5ece19 100755
--- a/t/t2400-worktree-add.sh
+++ b/t/t2400-worktree-add.sh
@@ -438,7 +438,7 @@
 		cd foo &&
 		test_must_fail git config "branch.foo.remote" &&
 		test_must_fail git config "branch.foo.merge" &&
-		! test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
+		test_cmp_rev ! refs/remotes/repo_a/foo refs/heads/foo
 	)
 '
 
@@ -483,7 +483,7 @@
 		cd foo &&
 		test_must_fail git config "branch.foo.remote" &&
 		test_must_fail git config "branch.foo.merge" &&
-		! test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
+		test_cmp_rev ! refs/remotes/repo_a/foo refs/heads/foo
 	)
 '
 
@@ -587,4 +587,28 @@
 	)
 '
 
+test_expect_success '"add" with uninitialized submodule, with submodule.recurse unset' '
+	test_create_repo submodule &&
+	test_commit -C submodule first &&
+	test_create_repo project &&
+	git -C project submodule add ../submodule &&
+	git -C project add submodule &&
+	test_tick &&
+	git -C project commit -m add_sub &&
+	git clone project project-clone &&
+	git -C project-clone worktree add ../project-2
+'
+test_expect_success '"add" with uninitialized submodule, with submodule.recurse set' '
+	git -C project-clone -c submodule.recurse worktree add ../project-3
+'
+
+test_expect_success '"add" with initialized submodule, with submodule.recurse unset' '
+	git -C project-clone submodule update --init &&
+	git -C project-clone worktree add ../project-4
+'
+
+test_expect_success '"add" with initialized submodule, with submodule.recurse set' '
+	git -C project-clone -c submodule.recurse worktree add ../project-5
+'
+
 test_done
diff --git a/t/t3008-ls-files-lazy-init-name-hash.sh b/t/t3008-ls-files-lazy-init-name-hash.sh
index 64f0473..85f3704 100755
--- a/t/t3008-ls-files-lazy-init-name-hash.sh
+++ b/t/t3008-ls-files-lazy-init-name-hash.sh
@@ -4,7 +4,7 @@
 
 . ./test-lib.sh
 
-if test 1 -eq $($GIT_BUILD_DIR/t/helper/test-tool online-cpus)
+if test 1 -eq $(test-tool online-cpus)
 then
 	skip_all='skipping lazy-init tests, single cpu'
 	test_done
diff --git a/t/t3011-common-prefixes-and-directory-traversal.sh b/t/t3011-common-prefixes-and-directory-traversal.sh
new file mode 100755
index 0000000..3da5b2b
--- /dev/null
+++ b/t/t3011-common-prefixes-and-directory-traversal.sh
@@ -0,0 +1,209 @@
+#!/bin/sh
+
+test_description='directory traversal handling, especially with common prefixes'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	test_commit hello &&
+
+	>empty &&
+	mkdir untracked_dir &&
+	>untracked_dir/empty &&
+	git init untracked_repo &&
+	>untracked_repo/empty &&
+
+	cat <<-EOF >.gitignore &&
+	ignored
+	an_ignored_dir/
+	EOF
+	mkdir an_ignored_dir &&
+	mkdir an_untracked_dir &&
+	>an_ignored_dir/ignored &&
+	>an_ignored_dir/untracked &&
+	>an_untracked_dir/ignored &&
+	>an_untracked_dir/untracked
+'
+
+test_expect_success 'git ls-files -o shows the right entries' '
+	cat <<-EOF >expect &&
+	.gitignore
+	actual
+	an_ignored_dir/ignored
+	an_ignored_dir/untracked
+	an_untracked_dir/ignored
+	an_untracked_dir/untracked
+	empty
+	expect
+	untracked_dir/empty
+	untracked_repo/
+	EOF
+	git ls-files -o >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git ls-files -o --exclude-standard shows the right entries' '
+	cat <<-EOF >expect &&
+	.gitignore
+	actual
+	an_untracked_dir/untracked
+	empty
+	expect
+	untracked_dir/empty
+	untracked_repo/
+	EOF
+	git ls-files -o --exclude-standard >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git ls-files -o untracked_dir recurses' '
+	echo untracked_dir/empty >expect &&
+	git ls-files -o untracked_dir >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git ls-files -o untracked_dir/ recurses' '
+	echo untracked_dir/empty >expect &&
+	git ls-files -o untracked_dir/ >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git ls-files -o --directory untracked_dir does not recurse' '
+	echo untracked_dir/ >expect &&
+	git ls-files -o --directory untracked_dir >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git ls-files -o --directory untracked_dir/ does not recurse' '
+	echo untracked_dir/ >expect &&
+	git ls-files -o --directory untracked_dir/ >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git ls-files -o untracked_repo does not recurse' '
+	echo untracked_repo/ >expect &&
+	git ls-files -o untracked_repo >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git ls-files -o untracked_repo/ does not recurse' '
+	echo untracked_repo/ >expect &&
+	git ls-files -o untracked_repo/ >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git ls-files -o untracked_dir untracked_repo recurses into untracked_dir only' '
+	cat <<-EOF >expect &&
+	untracked_dir/empty
+	untracked_repo/
+	EOF
+	git ls-files -o untracked_dir untracked_repo >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git ls-files -o untracked_dir/ untracked_repo/ recurses into untracked_dir only' '
+	cat <<-EOF >expect &&
+	untracked_dir/empty
+	untracked_repo/
+	EOF
+	git ls-files -o untracked_dir/ untracked_repo/ >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git ls-files -o --directory untracked_dir untracked_repo does not recurse' '
+	cat <<-EOF >expect &&
+	untracked_dir/
+	untracked_repo/
+	EOF
+	git ls-files -o --directory untracked_dir untracked_repo >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git ls-files -o --directory untracked_dir/ untracked_repo/ does not recurse' '
+	cat <<-EOF >expect &&
+	untracked_dir/
+	untracked_repo/
+	EOF
+	git ls-files -o --directory untracked_dir/ untracked_repo/ >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git ls-files -o .git shows nothing' '
+	git ls-files -o .git >actual &&
+	test_must_be_empty actual
+'
+
+test_expect_success 'git ls-files -o .git/ shows nothing' '
+	git ls-files -o .git/ >actual &&
+	test_must_be_empty actual
+'
+
+test_expect_success FUNNYNAMES 'git ls-files -o untracked_* recurses appropriately' '
+	mkdir "untracked_*" &&
+	>"untracked_*/empty" &&
+
+	cat <<-EOF >expect &&
+	untracked_*/empty
+	untracked_dir/empty
+	untracked_repo/
+	EOF
+	git ls-files -o "untracked_*" >actual &&
+	test_cmp expect actual
+'
+
+# It turns out fill_directory returns the right paths, but ls-files' post-call
+# filtering in show_dir_entry() via calling dir_path_match() which ends up
+# in git_fnmatch() has logic for PATHSPEC_ONESTAR that assumes the pathspec
+# must match the full path; it doesn't check it for matching a leading
+# directory.
+test_expect_failure FUNNYNAMES 'git ls-files -o untracked_*/ recurses appropriately' '
+	cat <<-EOF >expect &&
+	untracked_*/empty
+	untracked_dir/empty
+	untracked_repo/
+	EOF
+	git ls-files -o "untracked_*/" >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success FUNNYNAMES 'git ls-files -o --directory untracked_* does not recurse' '
+	cat <<-EOF >expect &&
+	untracked_*/
+	untracked_dir/
+	untracked_repo/
+	EOF
+	git ls-files -o --directory "untracked_*" >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success FUNNYNAMES 'git ls-files -o --directory untracked_*/ does not recurse' '
+	cat <<-EOF >expect &&
+	untracked_*/
+	untracked_dir/
+	untracked_repo/
+	EOF
+	git ls-files -o --directory "untracked_*/" >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git ls-files -o consistent between one or two dirs' '
+	git ls-files -o --exclude-standard an_ignored_dir/ an_untracked_dir/ >tmp &&
+	! grep ^an_ignored_dir/ tmp >expect &&
+	git ls-files -o --exclude-standard an_ignored_dir/ >actual &&
+	test_cmp expect actual
+'
+
+# ls-files doesn't have a way to request showing both untracked and ignored
+# files at the same time, so use `git status --ignored`
+test_expect_success 'git status --ignored shows same files under dir with or without pathspec' '
+	cat <<-EOF >expect &&
+	?? an_untracked_dir/
+	!! an_untracked_dir/ignored
+	EOF
+	git status --porcelain --ignored >output &&
+	grep an_untracked_dir output >expect &&
+	git status --porcelain --ignored an_untracked_dir/ >actual &&
+	test_cmp expect actual
+'
+
+test_done
diff --git a/t/t3060-ls-files-with-tree.sh b/t/t3060-ls-files-with-tree.sh
index 44f378c..52ed665 100755
--- a/t/t3060-ls-files-with-tree.sh
+++ b/t/t3060-ls-files-with-tree.sh
@@ -47,7 +47,7 @@
 	git add .
 '
 
-test_expect_success 'git -ls-files --with-tree should succeed from subdir' '
+test_expect_success 'git ls-files --with-tree should succeed from subdir' '
 	# We have to run from a sub-directory to trigger prune_path
 	# Then we finally get to run our --with-tree test
 	(
@@ -57,7 +57,7 @@
 '
 
 test_expect_success \
-    'git -ls-files --with-tree should add entries from named tree.' \
+    'git ls-files --with-tree should add entries from named tree.' \
     'test_cmp expected output'
 
 test_done
diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh
index 0579cd9..0575dd7 100755
--- a/t/t3206-range-diff.sh
+++ b/t/t3206-range-diff.sh
@@ -8,8 +8,8 @@
 # harm than good.  We need some real history.
 
 test_expect_success 'setup' '
-	git fast-import < "$TEST_DIRECTORY"/t3206/history.export &&
-	test_oid_cache <<-EOF
+	git fast-import <"$TEST_DIRECTORY"/t3206/history.export &&
+	test_oid_cache <<-\EOF
 	# topic
 	t1 sha1:4de457d
 	t2 sha1:fccce22
@@ -121,88 +121,88 @@
 test_expect_success 'simple A..B A..C (unmodified)' '
 	git range-diff --no-color master..topic master..unmodified \
 		>actual &&
-	cat >expected <<-EOF &&
+	cat >expect <<-EOF &&
 	1:  $(test_oid t1) = 1:  $(test_oid u1) s/5/A/
 	2:  $(test_oid t2) = 2:  $(test_oid u2) s/4/A/
 	3:  $(test_oid t3) = 3:  $(test_oid u3) s/11/B/
 	4:  $(test_oid t4) = 4:  $(test_oid u4) s/12/B/
 	EOF
-	test_cmp expected actual
+	test_cmp expect actual
 '
 
 test_expect_success 'simple B...C (unmodified)' '
 	git range-diff --no-color topic...unmodified >actual &&
-	# same "expected" as above
-	test_cmp expected actual
+	# same "expect" as above
+	test_cmp expect actual
 '
 
 test_expect_success 'simple A B C (unmodified)' '
 	git range-diff --no-color master topic unmodified >actual &&
-	# same "expected" as above
-	test_cmp expected actual
+	# same "expect" as above
+	test_cmp expect actual
 '
 
 test_expect_success 'trivial reordering' '
 	git range-diff --no-color master topic reordered >actual &&
-	cat >expected <<-EOF &&
+	cat >expect <<-EOF &&
 	1:  $(test_oid t1) = 1:  $(test_oid r1) s/5/A/
 	3:  $(test_oid t3) = 2:  $(test_oid r2) s/11/B/
 	4:  $(test_oid t4) = 3:  $(test_oid r3) s/12/B/
 	2:  $(test_oid t2) = 4:  $(test_oid r4) s/4/A/
 	EOF
-	test_cmp expected actual
+	test_cmp expect actual
 '
 
 test_expect_success 'removed a commit' '
 	git range-diff --no-color master topic removed >actual &&
-	cat >expected <<-EOF &&
+	cat >expect <<-EOF &&
 	1:  $(test_oid t1) = 1:  $(test_oid d1) s/5/A/
 	2:  $(test_oid t2) < -:  $(test_oid __) s/4/A/
 	3:  $(test_oid t3) = 2:  $(test_oid d2) s/11/B/
 	4:  $(test_oid t4) = 3:  $(test_oid d3) s/12/B/
 	EOF
-	test_cmp expected actual
+	test_cmp expect actual
 '
 
 test_expect_success 'added a commit' '
 	git range-diff --no-color master topic added >actual &&
-	cat >expected <<-EOF &&
+	cat >expect <<-EOF &&
 	1:  $(test_oid t1) = 1:  $(test_oid a1) s/5/A/
 	2:  $(test_oid t2) = 2:  $(test_oid a2) s/4/A/
 	-:  $(test_oid __) > 3:  $(test_oid a3) s/6/A/
 	3:  $(test_oid t3) = 4:  $(test_oid a4) s/11/B/
 	4:  $(test_oid t4) = 5:  $(test_oid a5) s/12/B/
 	EOF
-	test_cmp expected actual
+	test_cmp expect actual
 '
 
 test_expect_success 'new base, A B C' '
 	git range-diff --no-color master topic rebased >actual &&
-	cat >expected <<-EOF &&
+	cat >expect <<-EOF &&
 	1:  $(test_oid t1) = 1:  $(test_oid b1) s/5/A/
 	2:  $(test_oid t2) = 2:  $(test_oid b2) s/4/A/
 	3:  $(test_oid t3) = 3:  $(test_oid b3) s/11/B/
 	4:  $(test_oid t4) = 4:  $(test_oid b4) s/12/B/
 	EOF
-	test_cmp expected actual
+	test_cmp expect actual
 '
 
 test_expect_success 'new base, B...C' '
 	# this syntax includes the commits from master!
 	git range-diff --no-color topic...rebased >actual &&
-	cat >expected <<-EOF &&
+	cat >expect <<-EOF &&
 	-:  $(test_oid __) > 1:  $(test_oid b5) unrelated
 	1:  $(test_oid t1) = 2:  $(test_oid b1) s/5/A/
 	2:  $(test_oid t2) = 3:  $(test_oid b2) s/4/A/
 	3:  $(test_oid t3) = 4:  $(test_oid b3) s/11/B/
 	4:  $(test_oid t4) = 5:  $(test_oid b4) s/12/B/
 	EOF
-	test_cmp expected actual
+	test_cmp expect actual
 '
 
 test_expect_success 'changed commit' '
 	git range-diff --no-color topic...changed >actual &&
-	cat >expected <<-EOF &&
+	cat >expect <<-EOF &&
 	1:  $(test_oid t1) = 1:  $(test_oid c1) s/5/A/
 	2:  $(test_oid t2) = 2:  $(test_oid c2) s/4/A/
 	3:  $(test_oid t3) ! 3:  $(test_oid c3) s/11/B/
@@ -226,23 +226,23 @@
 	     +B
 	      13
 	EOF
-	test_cmp expected actual
+	test_cmp expect actual
 '
 
 test_expect_success 'changed commit with --no-patch diff option' '
 	git range-diff --no-color --no-patch topic...changed >actual &&
-	cat >expected <<-EOF &&
+	cat >expect <<-EOF &&
 	1:  $(test_oid t1) = 1:  $(test_oid c1) s/5/A/
 	2:  $(test_oid t2) = 2:  $(test_oid c2) s/4/A/
 	3:  $(test_oid t3) ! 3:  $(test_oid c3) s/11/B/
 	4:  $(test_oid t4) ! 4:  $(test_oid c4) s/12/B/
 	EOF
-	test_cmp expected actual
+	test_cmp expect actual
 '
 
 test_expect_success 'changed commit with --stat diff option' '
 	git range-diff --no-color --stat topic...changed >actual &&
-	cat >expected <<-EOF &&
+	cat >expect <<-EOF &&
 	1:  $(test_oid t1) = 1:  $(test_oid c1) s/5/A/
 	     a => b | 0
 	     1 file changed, 0 insertions(+), 0 deletions(-)
@@ -256,12 +256,12 @@
 	     a => b | 0
 	     1 file changed, 0 insertions(+), 0 deletions(-)
 	EOF
-	test_cmp expected actual
+	test_cmp expect actual
 '
 
 test_expect_success 'changed commit with sm config' '
 	git range-diff --no-color --submodule=log topic...changed >actual &&
-	cat >expected <<-EOF &&
+	cat >expect <<-EOF &&
 	1:  $(test_oid t1) = 1:  $(test_oid c1) s/5/A/
 	2:  $(test_oid t2) = 2:  $(test_oid c2) s/4/A/
 	3:  $(test_oid t3) ! 3:  $(test_oid c3) s/11/B/
@@ -285,12 +285,12 @@
 	     +B
 	      13
 	EOF
-	test_cmp expected actual
+	test_cmp expect actual
 '
 
 test_expect_success 'renamed file' '
 	git range-diff --no-color --submodule=log topic...renamed-file >actual &&
-	sed s/Z/\ /g >expected <<-EOF &&
+	sed s/Z/\ /g >expect <<-EOF &&
 	1:  $(test_oid t1) = 1:  $(test_oid n1) s/5/A/
 	2:  $(test_oid t2) ! 2:  $(test_oid n2) s/4/A/
 	    @@ Metadata
@@ -330,12 +330,12 @@
 	    Z 10
 	    Z B
 	EOF
-	test_cmp expected actual
+	test_cmp expect actual
 '
 
 test_expect_success 'file with mode only change' '
 	git range-diff --no-color --submodule=log topic...mode-only-change >actual &&
-	sed s/Z/\ /g >expected <<-EOF &&
+	sed s/Z/\ /g >expect <<-EOF &&
 	1:  fccce22 ! 1:  4d39cb3 s/4/A/
 	    @@ Metadata
 	    ZAuthor: Thomas Rast <trast@inf.ethz.ch>
@@ -370,12 +370,12 @@
 	    + ## other-file (mode change 100644 => 100755) ##
 	3:  a63e992 = 3:  4c1e0f5 s/12/B/
 	EOF
-	test_cmp expected actual
+	test_cmp expect actual
 '
 
 test_expect_success 'file added and later removed' '
 	git range-diff --no-color --submodule=log topic...added-removed >actual &&
-	sed s/Z/\ /g >expected <<-EOF &&
+	sed s/Z/\ /g >expect <<-EOF &&
 	1:  $(test_oid t1) = 1:  $(test_oid s1) s/5/A/
 	2:  $(test_oid t2) ! 2:  $(test_oid s2) s/4/A/
 	    @@ Metadata
@@ -411,7 +411,7 @@
 	    + ## new-file (deleted) ##
 	4:  $(test_oid t4) = 4:  $(test_oid s4) s/12/B/
 	EOF
-	test_cmp expected actual
+	test_cmp expect actual
 '
 
 test_expect_success 'no commits on one side' '
@@ -421,7 +421,7 @@
 
 test_expect_success 'changed message' '
 	git range-diff --no-color topic...changed-message >actual &&
-	sed s/Z/\ /g >expected <<-EOF &&
+	sed s/Z/\ /g >expect <<-EOF &&
 	1:  $(test_oid t1) = 1:  $(test_oid m1) s/5/A/
 	2:  $(test_oid t2) ! 2:  $(test_oid m2) s/4/A/
 	    @@ Metadata
@@ -436,7 +436,7 @@
 	3:  $(test_oid t3) = 3:  $(test_oid m3) s/11/B/
 	4:  $(test_oid t4) = 4:  $(test_oid m4) s/12/B/
 	EOF
-	test_cmp expected actual
+	test_cmp expect actual
 '
 
 test_expect_success 'dual-coloring' '
@@ -505,4 +505,202 @@
 	git -c diff.noprefix=true range-diff HEAD^...
 '
 
+test_expect_success 'range-diff compares notes by default' '
+	git notes add -m "topic note" topic &&
+	git notes add -m "unmodified note" unmodified &&
+	test_when_finished git notes remove topic unmodified &&
+	git range-diff --no-color master..topic master..unmodified \
+		>actual &&
+	sed s/Z/\ /g >expect <<-EOF &&
+	1:  $(test_oid t1) = 1:  $(test_oid u1) s/5/A/
+	2:  $(test_oid t2) = 2:  $(test_oid u2) s/4/A/
+	3:  $(test_oid t3) = 3:  $(test_oid u3) s/11/B/
+	4:  $(test_oid t4) ! 4:  $(test_oid u4) s/12/B/
+	    @@ Commit message
+	    Z
+	    Z
+	    Z ## Notes ##
+	    -    topic note
+	    +    unmodified note
+	    Z
+	    Z ## file ##
+	    Z@@ file: A
+	EOF
+	test_cmp expect actual
+'
+
+test_expect_success 'range-diff with --no-notes' '
+	git notes add -m "topic note" topic &&
+	git notes add -m "unmodified note" unmodified &&
+	test_when_finished git notes remove topic unmodified &&
+	git range-diff --no-color --no-notes master..topic master..unmodified \
+		>actual &&
+	cat >expect <<-EOF &&
+	1:  $(test_oid t1) = 1:  $(test_oid u1) s/5/A/
+	2:  $(test_oid t2) = 2:  $(test_oid u2) s/4/A/
+	3:  $(test_oid t3) = 3:  $(test_oid u3) s/11/B/
+	4:  $(test_oid t4) = 4:  $(test_oid u4) s/12/B/
+	EOF
+	test_cmp expect actual
+'
+
+test_expect_success 'range-diff with multiple --notes' '
+	git notes --ref=note1 add -m "topic note1" topic &&
+	git notes --ref=note1 add -m "unmodified note1" unmodified &&
+	test_when_finished git notes --ref=note1 remove topic unmodified &&
+	git notes --ref=note2 add -m "topic note2" topic &&
+	git notes --ref=note2 add -m "unmodified note2" unmodified &&
+	test_when_finished git notes --ref=note2 remove topic unmodified &&
+	git range-diff --no-color --notes=note1 --notes=note2 master..topic master..unmodified \
+		>actual &&
+	sed s/Z/\ /g >expect <<-EOF &&
+	1:  $(test_oid t1) = 1:  $(test_oid u1) s/5/A/
+	2:  $(test_oid t2) = 2:  $(test_oid u2) s/4/A/
+	3:  $(test_oid t3) = 3:  $(test_oid u3) s/11/B/
+	4:  $(test_oid t4) ! 4:  $(test_oid u4) s/12/B/
+	    @@ Commit message
+	    Z
+	    Z
+	    Z ## Notes (note1) ##
+	    -    topic note1
+	    +    unmodified note1
+	    Z
+	    Z
+	    Z ## Notes (note2) ##
+	    -    topic note2
+	    +    unmodified note2
+	    Z
+	    Z ## file ##
+	    Z@@ file: A
+	EOF
+	test_cmp expect actual
+'
+
+test_expect_success 'format-patch --range-diff does not compare notes by default' '
+	git notes add -m "topic note" topic &&
+	git notes add -m "unmodified note" unmodified &&
+	test_when_finished git notes remove topic unmodified &&
+	git format-patch --cover-letter --range-diff=$prev \
+		master..unmodified >actual &&
+	test_when_finished "rm 000?-*" &&
+	test_line_count = 5 actual &&
+	test_i18ngrep "^Range-diff:$" 0000-* &&
+	grep "= 1: .* s/5/A" 0000-* &&
+	grep "= 2: .* s/4/A" 0000-* &&
+	grep "= 3: .* s/11/B" 0000-* &&
+	grep "= 4: .* s/12/B" 0000-* &&
+	! grep "Notes" 0000-* &&
+	! grep "note" 0000-*
+'
+
+test_expect_success 'format-patch --range-diff with --no-notes' '
+	git notes add -m "topic note" topic &&
+	git notes add -m "unmodified note" unmodified &&
+	test_when_finished git notes remove topic unmodified &&
+	git format-patch --no-notes --cover-letter --range-diff=$prev \
+		master..unmodified >actual &&
+	test_when_finished "rm 000?-*" &&
+	test_line_count = 5 actual &&
+	test_i18ngrep "^Range-diff:$" 0000-* &&
+	grep "= 1: .* s/5/A" 0000-* &&
+	grep "= 2: .* s/4/A" 0000-* &&
+	grep "= 3: .* s/11/B" 0000-* &&
+	grep "= 4: .* s/12/B" 0000-* &&
+	! grep "Notes" 0000-* &&
+	! grep "note" 0000-*
+'
+
+test_expect_success 'format-patch --range-diff with --notes' '
+	git notes add -m "topic note" topic &&
+	git notes add -m "unmodified note" unmodified &&
+	test_when_finished git notes remove topic unmodified &&
+	git format-patch --notes --cover-letter --range-diff=$prev \
+		master..unmodified >actual &&
+	test_when_finished "rm 000?-*" &&
+	test_line_count = 5 actual &&
+	test_i18ngrep "^Range-diff:$" 0000-* &&
+	grep "= 1: .* s/5/A" 0000-* &&
+	grep "= 2: .* s/4/A" 0000-* &&
+	grep "= 3: .* s/11/B" 0000-* &&
+	grep "! 4: .* s/12/B" 0000-* &&
+	sed s/Z/\ /g >expect <<-EOF &&
+	    @@ Commit message
+	    Z
+	    Z
+	    Z ## Notes ##
+	    -    topic note
+	    +    unmodified note
+	    Z
+	    Z ## file ##
+	    Z@@ file: A
+	EOF
+	sed "/@@ Commit message/,/@@ file: A/!d" 0000-* >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'format-patch --range-diff with format.notes config' '
+	git notes add -m "topic note" topic &&
+	git notes add -m "unmodified note" unmodified &&
+	test_when_finished git notes remove topic unmodified &&
+	test_config format.notes true &&
+	git format-patch --cover-letter --range-diff=$prev \
+		master..unmodified >actual &&
+	test_when_finished "rm 000?-*" &&
+	test_line_count = 5 actual &&
+	test_i18ngrep "^Range-diff:$" 0000-* &&
+	grep "= 1: .* s/5/A" 0000-* &&
+	grep "= 2: .* s/4/A" 0000-* &&
+	grep "= 3: .* s/11/B" 0000-* &&
+	grep "! 4: .* s/12/B" 0000-* &&
+	sed s/Z/\ /g >expect <<-EOF &&
+	    @@ Commit message
+	    Z
+	    Z
+	    Z ## Notes ##
+	    -    topic note
+	    +    unmodified note
+	    Z
+	    Z ## file ##
+	    Z@@ file: A
+	EOF
+	sed "/@@ Commit message/,/@@ file: A/!d" 0000-* >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'format-patch --range-diff with multiple notes' '
+	git notes --ref=note1 add -m "topic note1" topic &&
+	git notes --ref=note1 add -m "unmodified note1" unmodified &&
+	test_when_finished git notes --ref=note1 remove topic unmodified &&
+	git notes --ref=note2 add -m "topic note2" topic &&
+	git notes --ref=note2 add -m "unmodified note2" unmodified &&
+	test_when_finished git notes --ref=note2 remove topic unmodified &&
+	git format-patch --notes=note1 --notes=note2 --cover-letter --range-diff=$prev \
+		master..unmodified >actual &&
+	test_when_finished "rm 000?-*" &&
+	test_line_count = 5 actual &&
+	test_i18ngrep "^Range-diff:$" 0000-* &&
+	grep "= 1: .* s/5/A" 0000-* &&
+	grep "= 2: .* s/4/A" 0000-* &&
+	grep "= 3: .* s/11/B" 0000-* &&
+	grep "! 4: .* s/12/B" 0000-* &&
+	sed s/Z/\ /g >expect <<-EOF &&
+	    @@ Commit message
+	    Z
+	    Z
+	    Z ## Notes (note1) ##
+	    -    topic note1
+	    +    unmodified note1
+	    Z
+	    Z
+	    Z ## Notes (note2) ##
+	    -    topic note2
+	    +    unmodified note2
+	    Z
+	    Z ## file ##
+	    Z@@ file: A
+	EOF
+	sed "/@@ Commit message/,/@@ file: A/!d" 0000-* >actual &&
+	test_cmp expect actual
+'
+
 test_done
diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh
index 9ea5fa4..f41b2af 100755
--- a/t/t3210-pack-refs.sh
+++ b/t/t3210-pack-refs.sh
@@ -240,7 +240,7 @@
 
 test_expect_success SYMLINKS 'pack symlinked packed-refs' '
 	# First make sure that symlinking works when reading:
-	git update-ref refs/heads/loosy refs/heads/master &&
+	git update-ref refs/heads/lossy refs/heads/master &&
 	git for-each-ref >all-refs-before &&
 	mv .git/packed-refs .git/my-deviant-packed-refs &&
 	ln -s my-deviant-packed-refs .git/packed-refs &&
diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh
index d66a5f6..8f43303 100755
--- a/t/t3301-notes.sh
+++ b/t/t3301-notes.sh
@@ -54,7 +54,9 @@
 	test_path_is_missing .git/NOTES_EDITMSG &&
 	git ls-tree -r refs/notes/commits >actual &&
 	test_line_count = 1 actual &&
-	test "b4" = "$(git notes show)" &&
+	echo b4 >expect &&
+	git notes show >actual &&
+	test_cmp expect actual &&
 	git show HEAD^ &&
 	test_must_fail git notes show HEAD^
 '
@@ -79,14 +81,21 @@
 	test_path_is_missing .git/NOTES_EDITMSG &&
 	git ls-tree -r refs/notes/commits >actual &&
 	test_line_count = 1 actual &&
-	test "b3" = "$(git notes show)" &&
+	echo b3 >expect &&
+	git notes show >actual &&
+	test_cmp expect actual &&
 	git show HEAD^ &&
 	test_must_fail git notes show HEAD^
 '
 
 test_expect_success 'show notes from treeish' '
-	test "b3" = "$(git notes --ref commits^{tree} show)" &&
-	test "b4" = "$(git notes --ref commits@{1} show)"
+	echo b3 >expect &&
+	git notes --ref commits^{tree} show >actual &&
+	test_cmp expect actual &&
+
+	echo b4 >expect &&
+	git notes --ref commits@{1} show >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'cannot edit notes from non-ref' '
@@ -99,7 +108,9 @@
 	test_path_is_missing .git/NOTES_EDITMSG &&
 	git ls-tree -r refs/notes/commits >actual &&
 	test_line_count = 1 actual &&
-	test "b3" = "$(git notes show)" &&
+	echo b3 >expect &&
+	git notes show >actual &&
+	test_cmp expect actual &&
 	git show HEAD^ &&
 	test_must_fail git notes show HEAD^
 '
@@ -109,7 +120,9 @@
 	test_path_is_missing .git/NOTES_EDITMSG &&
 	git ls-tree -r refs/notes/commits >actual &&
 	test_line_count = 1 actual &&
-	test "b1" = "$(git notes show)" &&
+	echo b1 >expect &&
+	git notes show >actual &&
+	test_cmp expect actual &&
 	git show HEAD^ &&
 	test_must_fail git notes show HEAD^
 '
@@ -119,7 +132,9 @@
 	test_path_is_missing .git/NOTES_EDITMSG &&
 	git ls-tree -r refs/notes/commits >actual &&
 	test_line_count = 1 actual &&
-	test "b2" = "$(git notes show)" &&
+	echo b2 >expect &&
+	git notes show >actual &&
+	test_cmp expect actual &&
 	git show HEAD^ &&
 	test_must_fail git notes show HEAD^
 '
@@ -129,7 +144,9 @@
 	test_path_is_missing .git/NOTES_EDITMSG &&
 	git ls-tree -r refs/notes/commits >actual &&
 	test_line_count = 1 actual &&
-	test "b1" = "$(git notes show)" &&
+	echo b1 >expect &&
+	git notes show >actual &&
+	test_cmp expect actual &&
 	git show HEAD^ &&
 	test_must_fail git notes show HEAD^
 '
@@ -146,7 +163,8 @@
 		Notes:
 		${indent}b1
 	EOF
-	! (git cat-file commit HEAD | grep b1) &&
+	git cat-file commit HEAD >commits &&
+	! grep b1 commits &&
 	git log -1 >actual &&
 	test_cmp expect actual
 '
@@ -472,9 +490,11 @@
 test_expect_success 'list notes with "git notes list"' '
 	commit_2=$(git rev-parse 2nd) &&
 	commit_3=$(git rev-parse 3rd) &&
+	note_2=$(git rev-parse refs/notes/commits:$commit_2) &&
+	note_3=$(git rev-parse refs/notes/commits:$commit_3) &&
 	sort -t" " -k2 >expect <<-EOF &&
-		$(git rev-parse refs/notes/commits:$commit_2) $commit_2
-		$(git rev-parse refs/notes/commits:$commit_3) $commit_3
+		$note_2 $commit_2
+		$note_3 $commit_3
 	EOF
 	git notes list >actual &&
 	test_cmp expect actual
@@ -486,9 +506,7 @@
 '
 
 test_expect_success 'list specific note with "git notes list <object>"' '
-	cat >expect <<-EOF &&
-		$(git rev-parse refs/notes/commits:$commit_3)
-	EOF
+	git rev-parse refs/notes/commits:$commit_3 >expect &&
 	git notes list HEAD^^ >actual &&
 	test_cmp expect actual
 '
@@ -512,10 +530,11 @@
 
 test_expect_success '"git notes list" does not expand to "git notes list HEAD"' '
 	commit_5=$(git rev-parse 5th) &&
+	note_5=$(git rev-parse refs/notes/commits:$commit_5) &&
 	sort -t" " -k2 >expect_list <<-EOF &&
-		$(git rev-parse refs/notes/commits:$commit_2) $commit_2
-		$(git rev-parse refs/notes/commits:$commit_3) $commit_3
-		$(git rev-parse refs/notes/commits:$commit_5) $commit_5
+		$note_2 $commit_2
+		$note_3 $commit_3
+		$note_5 $commit_5
 	EOF
 	git notes list >actual &&
 	test_cmp expect_list actual
@@ -721,7 +740,8 @@
 	git notes show HEAD: >actual &&
 	test_cmp expect actual &&
 	echo "Note on a blob" >expect &&
-	filename=$(git ls-tree --name-only HEAD | head -n1) &&
+	git ls-tree --name-only HEAD >files &&
+	filename=$(head -n1 files) &&
 	git notes add -m "Note on a blob" HEAD:$filename &&
 	git notes show HEAD:$filename >actual &&
 	test_cmp expect actual &&
@@ -745,10 +765,13 @@
 		Notes:
 		${indent}order test
 	EOF
-	git notes add -C $(git notes list HEAD^) &&
+	note=$(git notes list HEAD^) &&
+	git notes add -C $note &&
 	git log -1 >actual &&
 	test_cmp expect actual &&
-	test "$(git notes list HEAD)" = "$(git notes list HEAD^)"
+	git notes list HEAD^ >expect &&
+	git notes list HEAD >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'create note from non-existing note with "git notes add -C" fails' '
@@ -777,11 +800,12 @@
 		Notes:
 		${indent}This is a blob object
 	EOF
-	blob=$(echo "This is a blob object" | git hash-object -w --stdin) &&
-	git notes add -C $blob &&
+	echo "This is a blob object" | git hash-object -w --stdin >blob &&
+	git notes add -C $(cat blob) &&
 	git log -1 >actual &&
 	test_cmp expect actual &&
-	test "$(git notes list HEAD)" = "$blob"
+	git notes list HEAD >actual &&
+	test_cmp blob actual
 '
 
 test_expect_success 'create note from other note with "git notes add -c"' '
@@ -797,7 +821,8 @@
 		Notes:
 		${indent}yet another note
 	EOF
-	MSG="yet another note" git notes add -c $(git notes list HEAD^^) &&
+	note=$(git notes list HEAD^^) &&
+	MSG="yet another note" git notes add -c $note &&
 	git log -1 >actual &&
 	test_cmp expect actual
 '
@@ -822,7 +847,8 @@
 		${indent}
 		${indent}yet another note
 	EOF
-	git notes append -C $(git notes list HEAD^) HEAD^ &&
+	note=$(git notes list HEAD^) &&
+	git notes append -C $note HEAD^ &&
 	git log -1 HEAD^ >actual &&
 	test_cmp expect actual
 '
@@ -839,7 +865,8 @@
 		Notes:
 		${indent}other note
 	EOF
-	MSG="other note" git notes append -c $(git notes list HEAD^) &&
+	note=$(git notes list HEAD^) &&
+	MSG="other note" git notes append -c $note &&
 	git log -1 >actual &&
 	test_cmp expect actual
 '
@@ -858,7 +885,8 @@
 		${indent}
 		${indent}yet another note
 	EOF
-	MSG="yet another note" git notes append -c $(git notes list HEAD) &&
+	note=$(git notes list HEAD) &&
+	MSG="yet another note" git notes append -c $note &&
 	git log -1 >actual &&
 	test_cmp expect actual
 '
@@ -878,7 +906,9 @@
 	git notes copy 8th 4th &&
 	git log 3rd..4th >actual &&
 	test_cmp expect actual &&
-	test "$(git note list 4th)" = "$(git note list 8th)"
+	git notes list 4th >expect &&
+	git notes list 8th >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'copy note with "git notes copy" with default' '
@@ -899,14 +929,30 @@
 	git notes copy HEAD^ &&
 	git log -1 >actual &&
 	test_cmp expect actual &&
-	test "$(git notes list HEAD)" = "$(git notes list HEAD^)"
+	git notes list HEAD^ >expect &&
+	git notes list HEAD >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'prevent overwrite with "git notes copy"' '
 	test_must_fail git notes copy HEAD~2 HEAD &&
+	cat >expect <<-EOF &&
+		commit $commit
+		Author: A U Thor <author@example.com>
+		Date:   Thu Apr 7 15:23:13 2005 -0700
+
+		${indent}11th
+
+		Notes:
+		${indent}other note
+		${indent}
+		${indent}yet another note
+	EOF
 	git log -1 >actual &&
 	test_cmp expect actual &&
-	test "$(git notes list HEAD)" = "$(git notes list HEAD^)"
+	git notes list HEAD^ >expect &&
+	git notes list HEAD >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'allow overwrite with "git notes copy -f"' '
@@ -924,7 +970,9 @@
 	git notes copy -f HEAD~3 HEAD &&
 	git log -1 >actual &&
 	test_cmp expect actual &&
-	test "$(git notes list HEAD)" = "$(git notes list HEAD~3)"
+	git notes list HEAD~3 >expect &&
+	git notes list HEAD >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'allow overwrite with "git notes copy -f" with default' '
@@ -944,7 +992,9 @@
 	git notes copy -f HEAD~2 &&
 	git log -1 >actual &&
 	test_cmp expect actual &&
-	test "$(git notes list HEAD)" = "$(git notes list HEAD~2)"
+	git notes list HEAD~2 >expect &&
+	git notes list HEAD >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'cannot copy note from object without notes' '
@@ -979,13 +1029,21 @@
 		${indent}
 		${indent}yet another note
 	EOF
-	(echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^) &&
-	echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |
-	git notes copy --stdin &&
+	from=$(git rev-parse HEAD~3) &&
+	to=$(git rev-parse HEAD^) &&
+	echo "$from" "$to" >copy &&
+	from=$(git rev-parse HEAD~2) &&
+	to=$(git rev-parse HEAD) &&
+	echo "$from" "$to" >>copy &&
+	git notes copy --stdin <copy &&
 	git log -2 >actual &&
 	test_cmp expect actual &&
-	test "$(git notes list HEAD)" = "$(git notes list HEAD~2)" &&
-	test "$(git notes list HEAD^)" = "$(git notes list HEAD~3)"
+	git notes list HEAD~2 >expect &&
+	git notes list HEAD >actual &&
+	test_cmp expect actual &&
+	git notes list HEAD~3 >expect &&
+	git notes list HEAD^ >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'git notes copy --for-rewrite (unconfigured)' '
@@ -1006,9 +1064,13 @@
 
 		${indent}14th
 	EOF
-	(echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^) &&
-	echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |
-	git notes copy --for-rewrite=foo &&
+	from=$(git rev-parse HEAD~3) &&
+	to=$(git rev-parse HEAD^) &&
+	echo "$from" "$to" >copy &&
+	from=$(git rev-parse HEAD~2) &&
+	to=$(git rev-parse HEAD) &&
+	echo "$from" "$to" >>copy &&
+	git notes copy --for-rewrite=foo <copy &&
 	git log -2 >actual &&
 	test_cmp expect actual
 '
@@ -1041,17 +1103,23 @@
 	EOF
 	test_config notes.rewriteMode overwrite &&
 	test_config notes.rewriteRef "refs/notes/*" &&
-	(echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^) &&
-	echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |
-	git notes copy --for-rewrite=foo &&
+	from=$(git rev-parse HEAD~3) &&
+	to=$(git rev-parse HEAD^) &&
+	echo "$from" "$to" >copy &&
+	from=$(git rev-parse HEAD~2) &&
+	to=$(git rev-parse HEAD) &&
+	echo "$from" "$to" >>copy &&
+	git notes copy --for-rewrite=foo <copy &&
 	git log -2 >actual &&
 	test_cmp expect actual
 '
 
 test_expect_success 'git notes copy --for-rewrite (disabled)' '
 	test_config notes.rewrite.bar false &&
-	echo $(git rev-parse HEAD~3) $(git rev-parse HEAD) |
-	git notes copy --for-rewrite=bar &&
+	from=$(git rev-parse HEAD~3) &&
+	to=$(git rev-parse HEAD) &&
+	echo "$from" "$to" >copy &&
+	git notes copy --for-rewrite=bar <copy &&
 	git log -2 >actual &&
 	test_cmp expect actual
 '
@@ -1071,8 +1139,10 @@
 	git notes add -f -m"a fresh note" HEAD^ &&
 	test_config notes.rewriteMode overwrite &&
 	test_config notes.rewriteRef "refs/notes/*" &&
-	echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
-	git notes copy --for-rewrite=foo &&
+	from=$(git rev-parse HEAD^) &&
+	to=$(git rev-parse HEAD) &&
+	echo "$from" "$to" >copy &&
+	git notes copy --for-rewrite=foo <copy &&
 	git log -1 >actual &&
 	test_cmp expect actual
 '
@@ -1080,8 +1150,10 @@
 test_expect_success 'git notes copy --for-rewrite (ignore)' '
 	test_config notes.rewriteMode ignore &&
 	test_config notes.rewriteRef "refs/notes/*" &&
-	echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
-	git notes copy --for-rewrite=foo &&
+	from=$(git rev-parse HEAD^) &&
+	to=$(git rev-parse HEAD) &&
+	echo "$from" "$to" >copy &&
+	git notes copy --for-rewrite=foo <copy &&
 	git log -1 >actual &&
 	test_cmp expect actual
 '
@@ -1103,8 +1175,10 @@
 	git notes add -f -m"another fresh note" HEAD^ &&
 	test_config notes.rewriteMode concatenate &&
 	test_config notes.rewriteRef "refs/notes/*" &&
-	echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
-	git notes copy --for-rewrite=foo &&
+	from=$(git rev-parse HEAD^) &&
+	to=$(git rev-parse HEAD) &&
+	echo "$from" "$to" >copy &&
+	git notes copy --for-rewrite=foo <copy &&
 	git log -1 >actual &&
 	test_cmp expect actual
 '
@@ -1131,9 +1205,13 @@
 	git notes add -f -m"append 2" HEAD^^ &&
 	test_config notes.rewriteMode concatenate &&
 	test_config notes.rewriteRef "refs/notes/*" &&
-	(echo $(git rev-parse HEAD^) $(git rev-parse HEAD) &&
-	echo $(git rev-parse HEAD^^) $(git rev-parse HEAD)) |
-	git notes copy --for-rewrite=foo &&
+	from=$(git rev-parse HEAD^) &&
+	to=$(git rev-parse HEAD) &&
+	echo "$from" "$to" >copy &&
+	from=$(git rev-parse HEAD^^) &&
+	to=$(git rev-parse HEAD) &&
+	echo "$from" "$to" >>copy &&
+	git notes copy --for-rewrite=foo <copy &&
 	git log -1 >actual &&
 	test_cmp expect actual
 '
@@ -1142,8 +1220,10 @@
 	git notes remove HEAD^ &&
 	test_config notes.rewriteMode concatenate &&
 	test_config notes.rewriteRef "refs/notes/*" &&
-	echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
-	git notes copy --for-rewrite=foo &&
+	from=$(git rev-parse HEAD^) &&
+	to=$(git rev-parse HEAD) &&
+	echo "$from" "$to" >copy &&
+	git notes copy --for-rewrite=foo <copy &&
 	git log -1 >actual &&
 	test_cmp expect actual
 '
@@ -1163,8 +1243,10 @@
 	test_config notes.rewriteMode concatenate &&
 	test_config notes.rewriteRef "refs/notes/*" &&
 	git notes add -f -m"replacement note 1" HEAD^ &&
-	echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
-	GIT_NOTES_REWRITE_MODE=overwrite git notes copy --for-rewrite=foo &&
+	from=$(git rev-parse HEAD^) &&
+	to=$(git rev-parse HEAD) &&
+	echo "$from" "$to" >copy &&
+	GIT_NOTES_REWRITE_MODE=overwrite git notes copy --for-rewrite=foo <copy &&
 	git log -1 >actual &&
 	test_cmp expect actual
 '
@@ -1184,9 +1266,11 @@
 	git notes add -f -m"replacement note 2" HEAD^ &&
 	test_config notes.rewriteMode overwrite &&
 	test_unconfig notes.rewriteRef &&
-	echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
+	from=$(git rev-parse HEAD^) &&
+	to=$(git rev-parse HEAD) &&
+	echo "$from" "$to" >copy &&
 	GIT_NOTES_REWRITE_REF=refs/notes/commits:refs/notes/other \
-		git notes copy --for-rewrite=foo &&
+		git notes copy --for-rewrite=foo <copy &&
 	git log -1 >actual &&
 	test_cmp expect actual
 '
@@ -1195,9 +1279,11 @@
 	git notes add -f -m"replacement note 3" HEAD^ &&
 	test_config notes.rewriteMode overwrite &&
 	test_config notes.rewriteRef refs/notes/other &&
-	echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
+	from=$(git rev-parse HEAD^) &&
+	to=$(git rev-parse HEAD) &&
+	echo "$from" "$to" >copy &&
 	GIT_NOTES_REWRITE_REF=refs/notes/commits \
-		git notes copy --for-rewrite=foo &&
+		git notes copy --for-rewrite=foo <copy &&
 	git log -1 >actual &&
 	grep "replacement note 3" actual
 '
@@ -1212,26 +1298,36 @@
 test_expect_success 'git notes get-ref expands refs/heads/master to refs/notes/refs/heads/master' '
 	test_unconfig core.notesRef &&
 	sane_unset GIT_NOTES_REF &&
-	test "$(git notes --ref=refs/heads/master get-ref)" = "refs/notes/refs/heads/master"
+	echo refs/notes/refs/heads/master >expect &&
+	git notes --ref=refs/heads/master get-ref >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'git notes get-ref (no overrides)' '
 	test_unconfig core.notesRef &&
 	sane_unset GIT_NOTES_REF &&
-	test "$(git notes get-ref)" = "refs/notes/commits"
+	echo refs/notes/commits >expect &&
+	git notes get-ref >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'git notes get-ref (core.notesRef)' '
 	test_config core.notesRef refs/notes/foo &&
-	test "$(git notes get-ref)" = "refs/notes/foo"
+	echo refs/notes/foo >expect &&
+	git notes get-ref >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'git notes get-ref (GIT_NOTES_REF)' '
-	test "$(GIT_NOTES_REF=refs/notes/bar git notes get-ref)" = "refs/notes/bar"
+	echo refs/notes/bar >expect &&
+	GIT_NOTES_REF=refs/notes/bar git notes get-ref >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'git notes get-ref (--ref)' '
-	test "$(GIT_NOTES_REF=refs/notes/bar git notes --ref=baz get-ref)" = "refs/notes/baz"
+	echo refs/notes/baz >expect &&
+	GIT_NOTES_REF=refs/notes/bar git notes --ref=baz get-ref >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'setup testing of empty notes' '
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index ab18ac5..221b35f 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -64,7 +64,7 @@
 	pre="$(git rev-parse --verify HEAD)" &&
 	git rebase master &&
 	test_cmp_rev "$pre" ORIG_HEAD &&
-	! test_cmp_rev "$pre" HEAD
+	test_cmp_rev ! "$pre" HEAD
 '
 
 test_expect_success 'rebase, with <onto> and <upstream> specified as :/quuxery' '
@@ -159,6 +159,12 @@
 	test_must_fail git rebase
 '
 
+test_expect_success 'rebase works with format.useAutoBase' '
+	test_config format.useAutoBase true &&
+	git checkout topic &&
+	git rebase master
+'
+
 test_expect_success 'default to common base in @{upstream}s reflog if no upstream arg' '
 	git checkout -b default-base master &&
 	git checkout -b default topic &&
diff --git a/t/t3403-rebase-skip.sh b/t/t3403-rebase-skip.sh
index 1f5122b..ee8a8db 100755
--- a/t/t3403-rebase-skip.sh
+++ b/t/t3403-rebase-skip.sh
@@ -7,6 +7,8 @@
 
 . ./test-lib.sh
 
+. "$TEST_DIRECTORY"/lib-rebase.sh
+
 # we assume the default git am -3 --skip strategy is tested independently
 # and always works :)
 
@@ -20,6 +22,13 @@
 	git commit -a -m "hello world" &&
 	echo goodbye >> hello &&
 	git commit -a -m "goodbye" &&
+	git tag goodbye &&
+
+	git checkout --detach &&
+	git checkout HEAD^ . &&
+	test_tick &&
+	git commit -m reverted-goodbye &&
+	git tag reverted-goodbye &&
 
 	git checkout -f skip-reference &&
 	echo moo > hello &&
@@ -76,4 +85,27 @@
 
 test_debug 'gitk --all & sleep 1'
 
+test_expect_success 'fixup that empties commit fails' '
+	test_when_finished "git rebase --abort" &&
+	(
+		set_fake_editor &&
+		test_must_fail env FAKE_LINES="1 fixup 2" git rebase -i \
+			goodbye^ reverted-goodbye
+	)
+'
+
+test_expect_success 'squash that empties commit fails' '
+	test_when_finished "git rebase --abort" &&
+	(
+		set_fake_editor &&
+		test_must_fail env FAKE_LINES="1 squash 2" git rebase -i \
+			goodbye^ reverted-goodbye
+	)
+'
+
+# Must be the last test in this file
+test_expect_success '$EDITOR and friends are unchanged' '
+	test_editor_unchanged
+'
+
 test_done
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index bf0dc75..ae6e55c 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1265,11 +1265,11 @@
 	test_when_finished "reset_rebase && git checkout master" &&
 	git checkout collide &&
 	(
-	unset test_tick &&
-	test_tick &&
-	set_fake_editor &&
-	FAKE_COMMIT_MESSAGE="collide2 ac4f2ee" \
-	FAKE_LINES="reword 1 2" git rebase -i HEAD~2
+		unset test_tick &&
+		test_tick &&
+		set_fake_editor &&
+		FAKE_COMMIT_MESSAGE="collide2 ac4f2ee" \
+		FAKE_LINES="reword 1 2" git rebase -i HEAD~2
 	)
 '
 
diff --git a/t/t3421-rebase-topology-linear.sh b/t/t3421-rebase-topology-linear.sh
index b847064..325072b 100755
--- a/t/t3421-rebase-topology-linear.sh
+++ b/t/t3421-rebase-topology-linear.sh
@@ -61,7 +61,7 @@
 	test_expect_$result "rebase $* -f rewrites even if upstream is an ancestor" "
 		reset_rebase &&
 		git rebase $* -f b e &&
-		! test_cmp_rev e HEAD &&
+		test_cmp_rev ! e HEAD &&
 		test_cmp_rev b HEAD~2 &&
 		test_linear_range 'd e' b..
 	"
@@ -78,7 +78,7 @@
 	test_expect_$result "rebase $* -f rewrites even if remote upstream is an ancestor" "
 		reset_rebase &&
 		git rebase $* -f branch-b branch-e &&
-		! test_cmp_rev branch-e origin/branch-e &&
+		test_cmp_rev ! branch-e origin/branch-e &&
 		test_cmp_rev branch-b HEAD~2 &&
 		test_linear_range 'd e' branch-b..
 	"
@@ -368,7 +368,7 @@
 	test_expect_$result "rebase $* -f --root on linear history causes re-write" "
 		reset_rebase &&
 		git rebase $* -f --root c &&
-		! test_cmp_rev a HEAD~2 &&
+		test_cmp_rev ! a HEAD~2 &&
 		test_linear_range 'a b c' HEAD
 	"
 }
diff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh
index 50e7960..c823406 100755
--- a/t/t3422-rebase-incompatible-options.sh
+++ b/t/t3422-rebase-incompatible-options.sh
@@ -61,8 +61,6 @@
 }
 
 test_rebase_am_only --whitespace=fix
-test_rebase_am_only --ignore-whitespace
-test_rebase_am_only --committer-date-is-author-date
 test_rebase_am_only -C4
 
 test_expect_success REBASE_P '--preserve-merges incompatible with --signoff' '
diff --git a/t/t3429-rebase-edit-todo.sh b/t/t3429-rebase-edit-todo.sh
index aaeac6e..7024d49 100755
--- a/t/t3429-rebase-edit-todo.sh
+++ b/t/t3429-rebase-edit-todo.sh
@@ -52,4 +52,34 @@
 	test_cmp expected actual
 '
 
+test_expect_success 're-reading todo doesnt interfere with revert --edit' '
+	git reset --hard third &&
+
+	git revert --edit third second &&
+
+	cat >expect <<-\EOF &&
+	Revert "second"
+	Revert "third"
+	third
+	second
+	first
+	EOF
+	git log --format="%s" >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 're-reading todo doesnt interfere with cherry-pick --edit' '
+	git reset --hard first &&
+
+	git cherry-pick --edit second third &&
+
+	cat >expect <<-\EOF &&
+	third
+	second
+	first
+	EOF
+	git log --format="%s" >actual &&
+	test_cmp expect actual
+'
+
 test_done
diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh
index 9efcf48..e72ca34 100755
--- a/t/t3430-rebase-merges.sh
+++ b/t/t3430-rebase-merges.sh
@@ -346,7 +346,7 @@
 	git merge --allow-unrelated-histories khnum &&
 	test_tick &&
 	git rebase -f -r HEAD^ &&
-	! test_cmp_rev HEAD^2 khnum &&
+	test_cmp_rev ! HEAD^2 khnum &&
 	test_cmp_graph HEAD^.. <<-\EOF &&
 	*   Merge branch '\''khnum'\'' into asherah
 	|\
@@ -408,7 +408,7 @@
 	| | * three
 	| * | two
 	| |/
-	* | one
+	* / one
 	|/
 	o before-octopus
 	EOF
@@ -468,4 +468,31 @@
 	test_cmp expect G.t
 '
 
+test_expect_success '--rebase-merges with commit that can generate bad characters for filename' '
+	git checkout -b colon-in-label E &&
+	git merge -m "colon: this should work" G &&
+	git rebase --rebase-merges --force-rebase E
+'
+
+test_expect_success '--rebase-merges with message matched with onto label' '
+	git checkout -b onto-label E &&
+	git merge -m onto G &&
+	git rebase --rebase-merges --force-rebase E &&
+	test_cmp_graph <<-\EOF
+	*   onto
+	|\
+	| * G
+	| * F
+	* |   E
+	|\ \
+	| * | B
+	* | | D
+	| |/
+	|/|
+	* | C
+	|/
+	* A
+	EOF
+'
+
 test_done
diff --git a/t/t3432-rebase-fast-forward.sh b/t/t3432-rebase-fast-forward.sh
index 034ffc7..92f95b5 100755
--- a/t/t3432-rebase-fast-forward.sh
+++ b/t/t3432-rebase-fast-forward.sh
@@ -64,7 +64,7 @@
 			test_cmp_rev \$oldhead \$newhead
 		elif test $cmp = diff
 		then
-			! test_cmp_rev \$oldhead \$newhead
+			test_cmp_rev ! \$oldhead \$newhead
 		fi
 	"
 }
diff --git a/t/t3433-rebase-options-compatibility.sh b/t/t3433-rebase-options-compatibility.sh
new file mode 100755
index 0000000..5166f15
--- /dev/null
+++ b/t/t3433-rebase-options-compatibility.sh
@@ -0,0 +1,131 @@
+#!/bin/sh
+#
+# Copyright (c) 2019 Rohit Ashiwal
+#
+
+test_description='tests to ensure compatibility between am and interactive backends'
+
+. ./test-lib.sh
+
+GIT_AUTHOR_DATE="1999-04-02T08:03:20+05:30"
+export GIT_AUTHOR_DATE
+
+# This is a special case in which both am and interactive backends
+# provide the same output. It was done intentionally because
+# both the backends fall short of optimal behaviour.
+test_expect_success 'setup' '
+	git checkout -b topic &&
+	q_to_tab >file <<-\EOF &&
+	line 1
+	Qline 2
+	line 3
+	EOF
+	git add file &&
+	git commit -m "add file" &&
+	cat >file <<-\EOF &&
+	line 1
+	new line 2
+	line 3
+	EOF
+	git commit -am "update file" &&
+	git tag side &&
+	test_commit commit1 foo foo1 &&
+	test_commit commit2 foo foo2 &&
+	test_commit commit3 foo foo3 &&
+
+	git checkout --orphan master &&
+	git rm --cached foo &&
+	rm foo &&
+	sed -e "s/^|//" >file <<-\EOF &&
+	|line 1
+	|        line 2
+	|line 3
+	EOF
+	git add file &&
+	git commit -m "add file" &&
+	git tag main
+'
+
+test_expect_success '--ignore-whitespace works with am backend' '
+	cat >expect <<-\EOF &&
+	line 1
+	new line 2
+	line 3
+	EOF
+	test_must_fail git rebase main side &&
+	git rebase --abort &&
+	git rebase --ignore-whitespace main side &&
+	test_cmp expect file
+'
+
+test_expect_success '--ignore-whitespace works with interactive backend' '
+	cat >expect <<-\EOF &&
+	line 1
+	new line 2
+	line 3
+	EOF
+	test_must_fail git rebase --merge main side &&
+	git rebase --abort &&
+	git rebase --merge --ignore-whitespace main side &&
+	test_cmp expect file
+'
+
+test_expect_success '--committer-date-is-author-date works with am backend' '
+	git commit --amend &&
+	git rebase --committer-date-is-author-date HEAD^ &&
+	git show HEAD --pretty="format:%ai" >authortime &&
+	git show HEAD --pretty="format:%ci" >committertime &&
+	test_cmp authortime committertime
+'
+
+test_expect_success '--committer-date-is-author-date works with interactive backend' '
+	git commit --amend &&
+	git rebase -i --committer-date-is-author-date HEAD^ &&
+	git show HEAD --pretty="format:%ai" >authortime &&
+	git show HEAD --pretty="format:%ci" >committertime &&
+	test_cmp authortime committertime
+'
+
+test_expect_success '--committer-date-is-author-date works with rebase -r' '
+	git checkout side &&
+	git merge --no-ff commit3 &&
+	git rebase -r --root --committer-date-is-author-date &&
+	git rev-list HEAD >rev_list &&
+	while read HASH
+	do
+		git show $HASH --pretty="format:%ai" >authortime
+		git show $HASH --pretty="format:%ci" >committertime
+		test_cmp authortime committertime
+	done <rev_list
+'
+
+# Checking for +0000 in author time is enough since default
+# timezone is UTC, but the timezone used while committing
+# sets to +0530.
+test_expect_success '--ignore-date works with am backend' '
+	git commit --amend --date="$GIT_AUTHOR_DATE" &&
+	git rebase --ignore-date HEAD^ &&
+	git show HEAD --pretty="format:%ai" >authortime &&
+	grep "+0000" authortime
+'
+
+test_expect_success '--ignore-date works with interactive backend' '
+	git commit --amend --date="$GIT_AUTHOR_DATE" &&
+	git rebase --ignore-date -i HEAD^ &&
+	git show HEAD --pretty="format:%ai" >authortime &&
+	grep "+0000" authortime
+'
+
+test_expect_success '--ignore-date works with rebase -r' '
+	git checkout side &&
+	git merge --no-ff commit3 &&
+	git rebase -r --root --ignore-date &&
+	git rev-list HEAD >rev_list &&
+	while read HASH
+	do
+		git show $HASH --pretty="format:%ai" >authortime
+		grep "+0000" authortime
+	done <rev_list
+'
+
+test_done
diff --git a/t/t3434-rebase-i18n.sh b/t/t3434-rebase-i18n.sh
new file mode 100755
index 0000000..c7c835c
--- /dev/null
+++ b/t/t3434-rebase-i18n.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+#
+# Copyright (c) 2019 Doan Tran Cong Danh
+#
+
+test_description='rebase with changing encoding
+
+Initial setup:
+
+1 - 2              master
+ \
+  3 - 4            first
+   \
+    5 - 6          second
+'
+
+. ./test-lib.sh
+
+compare_msg () {
+	iconv -f "$2" -t "$3" "$TEST_DIRECTORY/t3434/$1" >expect &&
+	git cat-file commit HEAD >raw &&
+	sed "1,/^$/d" raw >actual &&
+	test_cmp expect actual
+}
+
+test_expect_success setup '
+	test_commit one &&
+	git branch first &&
+	test_commit two &&
+	git switch first &&
+	test_commit three &&
+	git branch second &&
+	test_commit four &&
+	git switch second &&
+	test_commit five &&
+	test_commit six
+'
+
+test_expect_success 'rebase --rebase-merges update encoding eucJP to UTF-8' '
+	git switch -c merge-eucJP-UTF-8 first &&
+	git config i18n.commitencoding eucJP &&
+	git merge -F "$TEST_DIRECTORY/t3434/eucJP.txt" second &&
+	git config i18n.commitencoding UTF-8 &&
+	git rebase --rebase-merges master &&
+	compare_msg eucJP.txt eucJP UTF-8
+'
+
+test_expect_success 'rebase --rebase-merges update encoding eucJP to ISO-2022-JP' '
+	git switch -c merge-eucJP-ISO-2022-JP first &&
+	git config i18n.commitencoding eucJP &&
+	git merge -F "$TEST_DIRECTORY/t3434/eucJP.txt" second &&
+	git config i18n.commitencoding ISO-2022-JP &&
+	git rebase --rebase-merges master &&
+	compare_msg eucJP.txt eucJP ISO-2022-JP
+'
+
+test_rebase_continue_update_encode () {
+	old=$1
+	new=$2
+	msgfile=$3
+	test_expect_success "rebase --continue update from $old to $new" '
+		(git rebase --abort || : abort current git-rebase failure) &&
+		git switch -c conflict-$old-$new one &&
+		echo for-conflict >two.t &&
+		git add two.t &&
+		git config i18n.commitencoding $old &&
+		git commit -F "$TEST_DIRECTORY/t3434/$msgfile" &&
+		git config i18n.commitencoding $new &&
+		test_must_fail git rebase -m master &&
+		test -f .git/rebase-merge/message &&
+		git stripspace <.git/rebase-merge/message >two.t &&
+		git add two.t &&
+		git rebase --continue &&
+		compare_msg $msgfile $old $new &&
+		: git-commit assume invalid utf-8 is latin1 &&
+		test_cmp expect two.t
+	'
+}
+
+test_rebase_continue_update_encode ISO-8859-1 UTF-8 ISO8859-1.txt
+test_rebase_continue_update_encode eucJP UTF-8 eucJP.txt
+test_rebase_continue_update_encode eucJP ISO-2022-JP eucJP.txt
+
+test_done
diff --git a/t/t3434/ISO8859-1.txt b/t/t3434/ISO8859-1.txt
new file mode 100644
index 0000000..7cbef0e
--- /dev/null
+++ b/t/t3434/ISO8859-1.txt
@@ -0,0 +1,3 @@
+ÄËÑÏÖ
+
+Ábçdèfg
diff --git a/t/t3434/eucJP.txt b/t/t3434/eucJP.txt
new file mode 100644
index 0000000..546f2aa
--- /dev/null
+++ b/t/t3434/eucJP.txt
@@ -0,0 +1,4 @@
+¤Ï¤ì¤Ò¤Û¤Õ
+
+¤·¤Æ¤¤¤ë¤Î¤¬¡¢¤¤¤ë¤Î¤Ç¡£
+ßÀÉͤۤì¤×¤ê¤Ý¤ì¤Þ¤Ó¤°¤ê¤í¤Ø¡£
diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh
index d1c68af..7c1da21 100755
--- a/t/t3501-revert-cherry-pick.sh
+++ b/t/t3501-revert-cherry-pick.sh
@@ -106,7 +106,7 @@
 	rm -rf * &&
 	git cherry-pick initial &&
 	git diff --quiet initial &&
-	! test_cmp_rev initial HEAD
+	test_cmp_rev ! initial HEAD
 '
 
 test_expect_success 'cherry-pick "-" to pick from previous branch' '
@@ -150,7 +150,7 @@
 	test_tick &&
 	git commit -m renamed &&
 	echo modified >renamed &&
-	git cherry-pick refs/heads/unrelated >out &&
+	git cherry-pick refs/heads/unrelated &&
 	test $(git rev-parse :0:renamed) = $(git rev-parse HEAD~2:to-rename.t) &&
 	grep -q "^modified$" renamed
 '
diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh
index b457333..23070a7 100755
--- a/t/t3508-cherry-pick-many-commits.sh
+++ b/t/t3508-cherry-pick-many-commits.sh
@@ -5,7 +5,7 @@
 . ./test-lib.sh
 
 check_head_differs_from() {
-	! test_cmp_rev HEAD "$1"
+	test_cmp_rev ! HEAD "$1"
 }
 
 check_head_equals() {
diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
index 8c8cca5..0ea858d 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -113,9 +113,10 @@
 	echo frotz >test-file &&
 	git add test-file &&
 	git commit -m "add file for rm test" &&
-	git rm test-file >rm-output &&
-	test $(grep "^rm " rm-output | wc -l) = 1 &&
-	rm -f test-file rm-output &&
+	git rm test-file >rm-output.raw &&
+	grep "^rm " rm-output.raw >rm-output &&
+	test_line_count = 1 rm-output &&
+	rm -f test-file rm-output.raw rm-output &&
 	git commit -m "remove file from rm test"
 '
 
@@ -250,6 +251,7 @@
 		echo "100644 $hash 0	some-file-$i"
 		i=$(( $i + 1 ))
 	done | git update-index --index-info &&
+	# git command is intentionally placed upstream of pipe to induce SIGPIPE
 	git rm -n "some-file-*" | : &&
 	test_path_is_missing .git/index.lock
 '
@@ -303,7 +305,8 @@
 
 test_expect_success 'rm removes empty submodules from work tree' '
 	mkdir submod &&
-	git update-index --add --cacheinfo 160000 $(git rev-parse HEAD) submod &&
+	hash=$(git rev-parse HEAD) &&
+	git update-index --add --cacheinfo 160000 "$hash" submod &&
 	git config -f .gitmodules submodule.sub.url ./. &&
 	git config -f .gitmodules submodule.sub.path submod &&
 	git submodule init &&
@@ -622,7 +625,8 @@
 	git submodule update &&
 	(
 		cd submod &&
-		git update-index --add --cacheinfo 160000 $(git rev-parse HEAD) subsubmod &&
+		hash=$(git rev-parse HEAD) &&
+		git update-index --add --cacheinfo 160000 "$hash" subsubmod &&
 		git config -f .gitmodules submodule.sub.url ../. &&
 		git config -f .gitmodules submodule.sub.path subsubmod &&
 		git submodule init &&
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index d50e165..12ee321 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -23,6 +23,17 @@
 	test_cmp "$1.filtered" "$2.filtered"
 }
 
+# This function uses a trick to manipulate the interactive add to use color:
+# the `want_color()` function special-cases the situation where a pager was
+# spawned and Git now wants to output colored text: to detect that situation,
+# the environment variable `GIT_PAGER_IN_USE` is set. However, color is
+# suppressed despite that environment variable if the `TERM` variable
+# indicates a dumb terminal, so we set that variable, too.
+
+force_color () {
+	env GIT_PAGER_IN_USE=true TERM=vt100 "$@"
+}
+
 test_expect_success 'setup (initial)' '
 	echo content >file &&
 	git add file &&
@@ -94,7 +105,6 @@
 	grep "unchanged *+3/-0 file" output
 '
 
-
 test_expect_success 'setup expected' '
 	cat >expected <<-\EOF
 	EOF
@@ -263,6 +273,35 @@
 
 # end of tests disabled when filemode is not usable
 
+test_expect_success 'different prompts for mode change/deleted' '
+	git reset --hard &&
+	>file &&
+	>deleted &&
+	git add --chmod=+x file deleted &&
+	echo changed >file &&
+	rm deleted &&
+	test_write_lines n n n |
+	git -c core.filemode=true add -p >actual &&
+	sed -n "s/^\(([0-9/]*) Stage .*?\).*/\1/p" actual >actual.filtered &&
+	cat >expect <<-\EOF &&
+	(1/1) Stage deletion [y,n,q,a,d,?]?
+	(1/2) Stage mode change [y,n,q,a,d,j,J,g,/,?]?
+	(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]?
+	EOF
+	test_cmp expect actual.filtered
+'
+
+test_expect_success 'correct message when there is nothing to do' '
+	git reset --hard &&
+	git add -p 2>err &&
+	test_i18ngrep "No changes" err &&
+	printf "\\0123" >binary &&
+	git add binary &&
+	printf "\\0abc" >binary &&
+	git add -p 2>err &&
+	test_i18ngrep "Only binary files changed" err
+'
+
 test_expect_success 'setup again' '
 	git reset --hard &&
 	test_chmod +x file &&
@@ -374,6 +413,36 @@
 	test_write_lines 10 15 20 21 22 23 24 30 40 50 60 >test
 '
 
+test_expect_success 'goto hunk' '
+	test_when_finished "git reset" &&
+	tr _ " " >expect <<-EOF &&
+	(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? + 1:  -1,2 +1,3          +15
+	_ 2:  -2,4 +3,8          +21
+	go to which hunk? @@ -1,2 +1,3 @@
+	_10
+	+15
+	_20
+	(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?_
+	EOF
+	test_write_lines s y g 1 | git add -p >actual &&
+	tail -n 7 <actual >actual.trimmed &&
+	test_cmp expect actual.trimmed
+'
+
+test_expect_success 'navigate to hunk via regex' '
+	test_when_finished "git reset" &&
+	tr _ " " >expect <<-EOF &&
+	(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? @@ -1,2 +1,3 @@
+	_10
+	+15
+	_20
+	(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?_
+	EOF
+	test_write_lines s y /1,2 | git add -p >actual &&
+	tail -n 5 <actual >actual.trimmed &&
+	test_cmp expect actual.trimmed
+'
+
 test_expect_success 'split hunk "add -p (edit)"' '
 	# Split, say Edit and do nothing.  Then:
 	#
@@ -403,6 +472,40 @@
 	! grep "^+31" actual
 '
 
+test_expect_success 'split hunk with incomplete line at end' '
+	git reset --hard &&
+	printf "missing LF" >>test &&
+	git add test &&
+	test_write_lines before 10 20 30 40 50 60 70 >test &&
+	git grep --cached missing &&
+	test_write_lines s n y q | git add -p &&
+	test_must_fail git grep --cached missing &&
+	git grep before &&
+	test_must_fail git grep --cached before
+'
+
+test_expect_failure 'edit, adding lines to the first hunk' '
+	test_write_lines 10 11 20 30 40 50 51 60 >test &&
+	git reset &&
+	tr _ " " >patch <<-EOF &&
+	@@ -1,5 +1,6 @@
+	_10
+	+11
+	+12
+	_20
+	+21
+	+22
+	_30
+	EOF
+	# test sequence is s(plit), e(dit), n(o)
+	# q n q q is there to make sure we exit at the end.
+	printf "%s\n" s e n   q n q q |
+	EDITOR=./fake_editor.sh git add -p 2>error &&
+	test_must_be_empty error &&
+	git diff --cached >actual &&
+	grep "^+22" actual
+'
+
 test_expect_success 'patch mode ignores unmerged entries' '
 	git reset --hard &&
 	test_commit conflict &&
@@ -429,35 +532,48 @@
 	diff_cmp expected diff
 '
 
-test_expect_success TTY 'diffs can be colorized' '
+test_expect_success 'diffs can be colorized' '
 	git reset --hard &&
 
 	echo content >test &&
-	printf y | test_terminal git add -p >output 2>&1 &&
+	printf y >y &&
+	force_color git add -p >output 2>&1 <y &&
 
 	# We do not want to depend on the exact coloring scheme
 	# git uses for diffs, so just check that we saw some kind of color.
 	grep "$(printf "\\033")" output
 '
 
-test_expect_success TTY 'diffFilter filters diff' '
+test_expect_success 'diffFilter filters diff' '
 	git reset --hard &&
 
 	echo content >test &&
 	test_config interactive.diffFilter "sed s/^/foo:/" &&
-	printf y | test_terminal git add -p >output 2>&1 &&
+	printf y >y &&
+	force_color git add -p >output 2>&1 <y &&
 
 	# avoid depending on the exact coloring or content of the prompts,
 	# and just make sure we saw our diff prefixed
 	grep foo:.*content output
 '
 
-test_expect_success TTY 'detect bogus diffFilter output' '
+test_expect_success 'detect bogus diffFilter output' '
 	git reset --hard &&
 
 	echo content >test &&
 	test_config interactive.diffFilter "echo too-short" &&
-	printf y | test_must_fail test_terminal git add -p
+	printf y >y &&
+	test_must_fail force_color git add -p <y
+'
+
+test_expect_success 'diff.algorithm is passed to `git diff-files`' '
+	git reset --hard &&
+
+	>file &&
+	git add file &&
+	echo changed >file &&
+	test_must_fail git -c diff.algorithm=bogus add -p 2>err &&
+	test_i18ngrep "error: option diff-algorithm accepts " err
 '
 
 test_expect_success 'patch-mode via -i prompts for files' '
@@ -647,4 +763,29 @@
 	test_write_lines a b a b a a b a b a >expect &&
 	test_cmp expect a
 '
+
+test_expect_success 'show help from add--helper' '
+	git reset --hard &&
+	cat >expect <<-EOF &&
+
+	<BOLD>*** Commands ***<RESET>
+	  1: <BOLD;BLUE>s<RESET>tatus	  2: <BOLD;BLUE>u<RESET>pdate	  3: <BOLD;BLUE>r<RESET>evert	  4: <BOLD;BLUE>a<RESET>dd untracked
+	  5: <BOLD;BLUE>p<RESET>atch	  6: <BOLD;BLUE>d<RESET>iff	  7: <BOLD;BLUE>q<RESET>uit	  8: <BOLD;BLUE>h<RESET>elp
+	<BOLD;BLUE>What now<RESET>> <BOLD;RED>status        - show paths with changes<RESET>
+	<BOLD;RED>update        - add working tree state to the staged set of changes<RESET>
+	<BOLD;RED>revert        - revert staged set of changes back to the HEAD version<RESET>
+	<BOLD;RED>patch         - pick hunks and update selectively<RESET>
+	<BOLD;RED>diff          - view diff between HEAD and index<RESET>
+	<BOLD;RED>add untracked - add contents of untracked files to the staged set of changes<RESET>
+	<BOLD>*** Commands ***<RESET>
+	  1: <BOLD;BLUE>s<RESET>tatus	  2: <BOLD;BLUE>u<RESET>pdate	  3: <BOLD;BLUE>r<RESET>evert	  4: <BOLD;BLUE>a<RESET>dd untracked
+	  5: <BOLD;BLUE>p<RESET>atch	  6: <BOLD;BLUE>d<RESET>iff	  7: <BOLD;BLUE>q<RESET>uit	  8: <BOLD;BLUE>h<RESET>elp
+	<BOLD;BLUE>What now<RESET>>$SP
+	Bye.
+	EOF
+	test_write_lines h | force_color git add -i >actual.colored &&
+	test_decode_color <actual.colored >actual &&
+	test_i18ncmp expect actual
+'
+
 test_done
diff --git a/t/t3704-add-pathspec-file.sh b/t/t3704-add-pathspec-file.sh
new file mode 100755
index 0000000..3cfdb66
--- /dev/null
+++ b/t/t3704-add-pathspec-file.sh
@@ -0,0 +1,127 @@
+#!/bin/sh
+
+test_description='add --pathspec-from-file'
+
+. ./test-lib.sh
+
+test_tick
+
+test_expect_success setup '
+	test_commit file0 &&
+	echo A >fileA.t &&
+	echo B >fileB.t &&
+	echo C >fileC.t &&
+	echo D >fileD.t
+'
+
+restore_checkpoint () {
+	git reset
+}
+
+verify_expect () {
+	git status --porcelain --untracked-files=no -- fileA.t fileB.t fileC.t fileD.t >actual &&
+	test_cmp expect actual
+}
+
+test_expect_success '--pathspec-from-file from stdin' '
+	restore_checkpoint &&
+
+	echo fileA.t | git add --pathspec-from-file=- &&
+
+	cat >expect <<-\EOF &&
+	A  fileA.t
+	EOF
+	verify_expect
+'
+
+test_expect_success '--pathspec-from-file from file' '
+	restore_checkpoint &&
+
+	echo fileA.t >list &&
+	git add --pathspec-from-file=list &&
+
+	cat >expect <<-\EOF &&
+	A  fileA.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'NUL delimiters' '
+	restore_checkpoint &&
+
+	printf "fileA.t\0fileB.t\0" | git add --pathspec-from-file=- --pathspec-file-nul &&
+
+	cat >expect <<-\EOF &&
+	A  fileA.t
+	A  fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'LF delimiters' '
+	restore_checkpoint &&
+
+	printf "fileA.t\nfileB.t\n" | git add --pathspec-from-file=- &&
+
+	cat >expect <<-\EOF &&
+	A  fileA.t
+	A  fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'no trailing delimiter' '
+	restore_checkpoint &&
+
+	printf "fileA.t\nfileB.t" | git add --pathspec-from-file=- &&
+
+	cat >expect <<-\EOF &&
+	A  fileA.t
+	A  fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'CRLF delimiters' '
+	restore_checkpoint &&
+
+	printf "fileA.t\r\nfileB.t\r\n" | git add --pathspec-from-file=- &&
+
+	cat >expect <<-\EOF &&
+	A  fileA.t
+	A  fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'quotes' '
+	restore_checkpoint &&
+
+	printf "\"file\\101.t\"" | git add --pathspec-from-file=- &&
+
+	cat >expect <<-\EOF &&
+	A  fileA.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'quotes not compatible with --pathspec-file-nul' '
+	restore_checkpoint &&
+
+	printf "\"file\\101.t\"" >list &&
+	test_must_fail git add --pathspec-from-file=list --pathspec-file-nul
+'
+
+test_expect_success 'only touches what was listed' '
+	restore_checkpoint &&
+
+	printf "fileB.t\nfileC.t\n" | git add --pathspec-from-file=- &&
+
+	cat >expect <<-\EOF &&
+	A  fileB.t
+	A  fileC.t
+	EOF
+	verify_expect
+'
+
+test_done
diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh
index b92ff95..d277a9f 100755
--- a/t/t3900-i18n-commit.sh
+++ b/t/t3900-i18n-commit.sh
@@ -204,4 +204,41 @@
 
 test_commit_autosquash_flags ISO-2022-JP squash
 
+test_commit_autosquash_multi_encoding () {
+	flag=$1
+	old=$2
+	new=$3
+	msg=$4
+	test_expect_success "commit --$flag into $old from $new" '
+		git checkout -b $flag-$old-$new C0 &&
+		git config i18n.commitencoding $old &&
+		echo $old >>F &&
+		git commit -a -F "$TEST_DIRECTORY"/t3900/$msg &&
+		test_tick &&
+		echo intermediate stuff >>G &&
+		git add G &&
+		git commit -a -m "intermediate commit" &&
+		test_tick &&
+		git config i18n.commitencoding $new &&
+		echo $new-$flag >>F &&
+		git commit -a --$flag HEAD^ &&
+		git rebase --autosquash -i HEAD^^^ &&
+		git rev-list HEAD >actual &&
+		test_line_count = 3 actual &&
+		iconv -f $old -t UTF-8 "$TEST_DIRECTORY"/t3900/$msg >expect &&
+		if test $flag = squash; then
+			subject="$(head -1 expect)" &&
+			printf "\nsquash! %s\n" "$subject" >>expect
+		fi &&
+		git cat-file commit HEAD^ >raw &&
+		(sed "1,/^$/d" raw | iconv -f $new -t utf-8) >actual &&
+		test_cmp expect actual
+	'
+}
+
+test_commit_autosquash_multi_encoding fixup UTF-8 ISO-8859-1 1-UTF-8.txt
+test_commit_autosquash_multi_encoding squash ISO-8859-1 UTF-8 ISO8859-1.txt
+test_commit_autosquash_multi_encoding squash eucJP ISO-2022-JP eucJP.txt
+test_commit_autosquash_multi_encoding fixup ISO-2022-JP UTF-8 ISO-2022-JP.txt
+
 test_done
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index a4da72f..ea56e85 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -244,8 +244,11 @@
 	test_must_be_empty output.out
 '
 
-test_expect_success 'pop -q is quiet' '
+test_expect_success 'pop -q works and is quiet' '
 	git stash pop -q >output.out 2>&1 &&
+	echo bar >expect &&
+	git show :file >actual &&
+	test_cmp expect actual &&
 	test_must_be_empty output.out
 '
 
@@ -254,6 +257,8 @@
 	git add file &&
 	git stash save --quiet &&
 	git stash pop -q --index >output.out 2>&1 &&
+	git diff-files file2 >file2.diff &&
+	test_must_be_empty file2.diff &&
 	test foo = "$(git show :file)" &&
 	test_must_be_empty output.out
 '
diff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh
index 29ca76f..f075c7f 100755
--- a/t/t3905-stash-include-untracked.sh
+++ b/t/t3905-stash-include-untracked.sh
@@ -277,8 +277,8 @@
 	test_path_is_file ignored.d/bar
 '
 
-test_expect_success 'stash -u -- <non-existant> shows no changes when there are none' '
-	git stash push -u -- non-existant >actual &&
+test_expect_success 'stash -u -- <non-existent> shows no changes when there are none' '
+	git stash push -u -- non-existent >actual &&
 	echo "No local changes to save" >expect &&
 	test_i18ncmp expect actual
 '
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 69267b1..b653dd7 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -793,6 +793,38 @@
 	! grep "this is note 2" out
 '
 
+test_expect_success 'format-patch with multiple notes refs in config' '
+	test_when_finished "test_unconfig format.notes" &&
+
+	git notes --ref note1 add -m "this is note 1" HEAD &&
+	test_when_finished git notes --ref note1 remove HEAD &&
+	git notes --ref note2 add -m "this is note 2" HEAD &&
+	test_when_finished git notes --ref note2 remove HEAD &&
+
+	git config format.notes note1 &&
+	git format-patch -1 --stdout >out &&
+	grep "this is note 1" out &&
+	! grep "this is note 2" out &&
+	git config format.notes note2 &&
+	git format-patch -1 --stdout >out &&
+	! grep "this is note 1" out &&
+	grep "this is note 2" out &&
+	git config --add format.notes note1 &&
+	git format-patch -1 --stdout >out &&
+	grep "this is note 1" out &&
+	grep "this is note 2" out &&
+
+	git config --replace-all format.notes note1 &&
+	git config --add format.notes false &&
+	git format-patch -1 --stdout >out &&
+	! grep "this is note 1" out &&
+	! grep "this is note 2" out &&
+	git config --add format.notes note2 &&
+	git format-patch -1 --stdout >out &&
+	! grep "this is note 1" out &&
+	grep "this is note 2" out
+'
+
 echo "fatal: --name-only does not make sense" >expect.name-only
 echo "fatal: --name-status does not make sense" >expect.name-status
 echo "fatal: --check does not make sense" >expect.check
@@ -1939,10 +1971,9 @@
 	test_must_fail 	git format-patch --base=auto -1
 '
 
-test_expect_success 'format-patch format.useAutoBaseoption' '
-	test_when_finished "git config --unset format.useAutoBase" &&
+test_expect_success 'format-patch format.useAutoBase option' '
 	git checkout local &&
-	git config format.useAutoBase true &&
+	test_config format.useAutoBase true &&
 	git format-patch --stdout -1 >patch &&
 	grep "^base-commit:" patch >actual &&
 	git rev-parse upstream >commit-id-base &&
@@ -1951,8 +1982,7 @@
 '
 
 test_expect_success 'format-patch --base overrides format.useAutoBase' '
-	test_when_finished "git config --unset format.useAutoBase" &&
-	git config format.useAutoBase true &&
+	test_config format.useAutoBase true &&
 	git format-patch --stdout --base=HEAD~1 -1 >patch &&
 	grep "^base-commit:" patch >actual &&
 	git rev-parse HEAD~1 >commit-id-base &&
@@ -1960,6 +1990,12 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'format-patch --no-base overrides format.useAutoBase' '
+	test_config format.useAutoBase true &&
+	git format-patch --stdout --no-base -1 >patch &&
+	! grep "^base-commit:" patch
+'
+
 test_expect_success 'format-patch --base with --attach' '
 	git format-patch --attach=mimemime --stdout --base=HEAD~ -1 >patch &&
 	sed -n -e "/^base-commit:/s/.*/1/p" -e "/^---*mimemime--$/s/.*/2/p" \
diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
index eadaf57..88d3026 100755
--- a/t/t4015-diff-whitespace.sh
+++ b/t/t4015-diff-whitespace.sh
@@ -16,7 +16,8 @@
 	} while (0);
 	EOF
 	git update-index --add x &&
-	before=$(git rev-parse --short $(git hash-object x)) &&
+	old_hash_x=$(git hash-object x) &&
+	before=$(git rev-parse --short "$old_hash_x") &&
 
 	cat <<-\EOF >x &&
 	do
@@ -25,7 +26,8 @@
 	}
 	while (0);
 	EOF
-	after=$(git rev-parse --short $(git hash-object x)) &&
+	new_hash_x=$(git hash-object x) &&
+	after=$(git rev-parse --short "$new_hash_x") &&
 
 	cat <<-EOF >expect &&
 	diff --git a/x b/x
@@ -63,7 +65,8 @@
 	EOF
 
 	git update-index x &&
-	before=$(git rev-parse --short $(git hash-object x)) &&
+	old_hash_x=$(git hash-object x) &&
+	before=$(git rev-parse --short "$old_hash_x") &&
 
 	tr "_" " " <<-\EOF >x &&
 	_	whitespace at beginning
@@ -73,7 +76,8 @@
 	unchanged line
 	CR at end
 	EOF
-	after=$(git rev-parse --short $(git hash-object x)) &&
+	new_hash_x=$(git hash-object x) &&
+	after=$(git rev-parse --short "$new_hash_x") &&
 
 	tr "Q_" "\015 " <<-EOF >expect &&
 	diff --git a/x b/x
@@ -526,13 +530,15 @@
 test_expect_success 'check mixed spaces and tabs in indent' '
 	# This is indented with SP HT SP.
 	echo " 	 foo();" >x &&
-	git diff --check | grep "space before tab in indent"
+	test_must_fail git diff --check >check &&
+	grep "space before tab in indent" check
 '
 
 test_expect_success 'check mixed tabs and spaces in indent' '
 	# This is indented with HT SP HT.
 	echo "	 	foo();" >x &&
-	git diff --check | grep "space before tab in indent"
+	test_must_fail git diff --check >check &&
+	grep "space before tab in indent" check
 '
 
 test_expect_success 'check with no whitespace errors' '
@@ -753,20 +759,23 @@
 test_expect_success 'line numbers in --check output are correct' '
 	echo "" >x &&
 	echo "foo(); " >>x &&
-	git diff --check | grep "x:2:"
+	test_must_fail git diff --check >check &&
+	grep "x:2:" check
 '
 
 test_expect_success 'checkdiff detects new trailing blank lines (1)' '
 	echo "foo();" >x &&
 	echo "" >>x &&
-	git diff --check | grep "new blank line"
+	test_must_fail git diff --check >check &&
+	grep "new blank line" check
 '
 
 test_expect_success 'checkdiff detects new trailing blank lines (2)' '
-	{ echo a; echo b; echo; echo; } >x &&
+	test_write_lines a b "" "" >x &&
 	git add x &&
-	{ echo a; echo; echo; echo; echo; } >x &&
-	git diff --check | grep "new blank line"
+	test_write_lines a "" "" "" "" >x &&
+	test_must_fail git diff --check >check &&
+	grep "new blank line" check
 '
 
 test_expect_success 'checkdiff allows new blank lines' '
@@ -794,14 +803,16 @@
 	git reset --hard &&
 	for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i"; done >x &&
 	git add x &&
-	before=$(git rev-parse --short $(git hash-object x)) &&
+	hash_x=$(git hash-object x) &&
+	before=$(git rev-parse --short "$hash_x") &&
 	git commit -m "base" &&
 	sed -e "5s/^/ /" x >z &&
 	git rm x &&
 	git add z &&
-	after=$(git rev-parse --short $(git hash-object z)) &&
-	git diff -w -M --cached |
-	sed -e "/^similarity index /s/[0-9][0-9]*/NUM/" >actual &&
+	hash_z=$(git hash-object z) &&
+	after=$(git rev-parse --short "$hash_z") &&
+	git diff -w -M --cached >actual.raw &&
+	sed -e "/^similarity index /s/[0-9][0-9]*/NUM/" actual.raw >actual &&
 	cat <<-EOF >expect &&
 	diff --git a/x b/z
 	similarity index NUM%
@@ -840,7 +851,8 @@
 	git config core.autocrlf true &&
 	test_must_fail git merge master &&
 
-	git diff | sed -e "1,/^@@@/d" >actual &&
+	git diff >actual.raw &&
+	sed -e "1,/^@@@/d" actual.raw >actual &&
 	! grep "^-" actual
 
 '
@@ -864,11 +876,14 @@
 	git config core.whitespace blank-at-eol &&
 	git reset --hard &&
 	echo "test" >x &&
-	before=$(git rev-parse --short $(git hash-object x)) &&
+	old_hash_x=$(git hash-object x) &&
+	before=$(git rev-parse --short "$old_hash_x") &&
 	git commit -m "initial" x &&
 	echo "{NTN}" | tr "NT" "\n\t" >>x &&
-	after=$(git rev-parse --short $(git hash-object x)) &&
-	git diff --color | test_decode_color >current &&
+	new_hash_x=$(git hash-object x) &&
+	after=$(git rev-parse --short "$new_hash_x") &&
+	git diff --color >current.raw &&
+	test_decode_color <current.raw >current &&
 
 	cat >expected <<-EOF &&
 	<BOLD>diff --git a/x b/x<RESET>
@@ -891,17 +906,19 @@
 		echo "0. blank-at-eol " &&
 		echo "1. blank-at-eol "
 	} >x &&
-	before=$(git rev-parse --short $(git hash-object x)) &&
+	old_hash_x=$(git hash-object x) &&
+	before=$(git rev-parse --short "$old_hash_x") &&
 	git commit -a --allow-empty -m preimage &&
 	{
 		echo "0. blank-at-eol " &&
 		echo "1. still-blank-at-eol " &&
 		echo "2. and a new line "
 	} >x &&
-	after=$(git rev-parse --short $(git hash-object x)) &&
+	new_hash_x=$(git hash-object x) &&
+	after=$(git rev-parse --short "$new_hash_x") &&
 
-	git diff --color |
-	test_decode_color >current &&
+	git diff --color >current.raw &&
+	test_decode_color <current.raw >current &&
 
 	cat >expected <<-EOF &&
 	<BOLD>diff --git a/x b/x<RESET>
@@ -925,14 +942,16 @@
 		echo "0. blank-at-eol " &&
 		echo "1. blank-at-eol "
 	} >x &&
-	before=$(git rev-parse --short $(git hash-object x)) &&
+	old_hash_x=$(git hash-object x) &&
+	before=$(git rev-parse --short "$old_hash_x") &&
 	git commit -a --allow-empty -m preimage &&
 	{
 		echo "0. blank-at-eol " &&
 		echo "1. still-blank-at-eol " &&
 		echo "2. and a new line "
 	} >x &&
-	after=$(git rev-parse --short $(git hash-object x)) &&
+	new_hash_x=$(git hash-object x) &&
+	after=$(git rev-parse --short "$new_hash_x") &&
 
 	cat >expect.default-old <<-EOF &&
 	<BOLD>diff --git a/x b/x<RESET>
@@ -974,32 +993,32 @@
 
 test_expect_success 'test --ws-error-highlight option' '
 
-	git diff --color --ws-error-highlight=default,old |
-	test_decode_color >current &&
+	git diff --color --ws-error-highlight=default,old >current.raw &&
+	test_decode_color <current.raw >current &&
 	test_cmp expect.default-old current &&
 
-	git diff --color --ws-error-highlight=all |
-	test_decode_color >current &&
+	git diff --color --ws-error-highlight=all >current.raw &&
+	test_decode_color <current.raw >current &&
 	test_cmp expect.all current &&
 
-	git diff --color --ws-error-highlight=none |
-	test_decode_color >current &&
+	git diff --color --ws-error-highlight=none >current.raw &&
+	test_decode_color <current.raw >current &&
 	test_cmp expect.none current
 
 '
 
 test_expect_success 'test diff.wsErrorHighlight config' '
 
-	git -c diff.wsErrorHighlight=default,old diff --color |
-	test_decode_color >current &&
+	git -c diff.wsErrorHighlight=default,old diff --color >current.raw &&
+	test_decode_color <current.raw >current &&
 	test_cmp expect.default-old current &&
 
-	git -c diff.wsErrorHighlight=all diff --color |
-	test_decode_color >current &&
+	git -c diff.wsErrorHighlight=all diff --color >current.raw &&
+	test_decode_color <current.raw >current &&
 	test_cmp expect.all current &&
 
-	git -c diff.wsErrorHighlight=none diff --color |
-	test_decode_color >current &&
+	git -c diff.wsErrorHighlight=none diff --color >current.raw &&
+	test_decode_color <current.raw >current &&
 	test_cmp expect.none current
 
 '
@@ -1007,18 +1026,18 @@
 test_expect_success 'option overrides diff.wsErrorHighlight' '
 
 	git -c diff.wsErrorHighlight=none \
-		diff --color --ws-error-highlight=default,old |
-	test_decode_color >current &&
+		diff --color --ws-error-highlight=default,old >current.raw &&
+	test_decode_color <current.raw >current &&
 	test_cmp expect.default-old current &&
 
 	git -c diff.wsErrorHighlight=default \
-		diff --color --ws-error-highlight=all |
-	test_decode_color >current &&
+		diff --color --ws-error-highlight=all >current.raw &&
+	test_decode_color <current.raw >current &&
 	test_cmp expect.all current &&
 
 	git -c diff.wsErrorHighlight=all \
-		diff --color --ws-error-highlight=none |
-	test_decode_color >current &&
+		diff --color --ws-error-highlight=none >current.raw &&
+	test_decode_color <current.raw >current &&
 	test_cmp expect.none current
 
 '
@@ -1038,7 +1057,8 @@
 	git mv test.c main.c &&
 	test_config color.diff.oldMoved "normal red" &&
 	test_config color.diff.newMoved "normal green" &&
-	git diff HEAD --color-moved=zebra --color --no-renames | test_decode_color >actual &&
+	git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
+	test_decode_color <actual.raw >actual &&
 	cat >expected <<-EOF &&
 	<BOLD>diff --git a/main.c b/main.c<RESET>
 	<BOLD>new file mode 100644<RESET>
@@ -1141,9 +1161,12 @@
 			bar();
 		}
 	EOF
-	after_main=$(git rev-parse --short $(git hash-object main.c)) &&
-	after_test=$(git rev-parse --short $(git hash-object test.c)) &&
-	git diff HEAD --no-renames --color-moved=zebra --color | test_decode_color >actual &&
+	hash_main=$(git hash-object main.c) &&
+	after_main=$(git rev-parse --short "$hash_main") &&
+	hash_test=$(git hash-object test.c) &&
+	after_test=$(git rev-parse --short "$hash_test") &&
+	git diff HEAD --no-renames --color-moved=zebra --color >actual.raw &&
+	test_decode_color <actual.raw >actual &&
 	cat <<-EOF >expected &&
 	<BOLD>diff --git a/main.c b/main.c<RESET>
 	<BOLD>index $before_main..$after_main 100644<RESET>
@@ -1192,7 +1215,8 @@
 	test_config color.diff.oldMovedAlternative "blue" &&
 	test_config color.diff.newMovedAlternative "yellow" &&
 	# needs previous test as setup
-	git diff HEAD --no-renames --color-moved=plain --color | test_decode_color >actual &&
+	git diff HEAD --no-renames --color-moved=plain --color >actual.raw &&
+	test_decode_color <actual.raw >actual &&
 	cat <<-EOF >expected &&
 	<BOLD>diff --git a/main.c b/main.c<RESET>
 	<BOLD>index $before_main..$after_main 100644<RESET>
@@ -1771,7 +1795,8 @@
 	! grep BRED decoded_actual &&
 
 	# nor did we mess with it another way
-	git diff --submodule=diff --color | test_decode_color >expect &&
+	git diff --submodule=diff --color >expect.raw &&
+	test_decode_color <expect.raw >expect &&
 	test_cmp expect decoded_actual &&
 	rm -rf bananas &&
 	git submodule deinit bananas
@@ -2025,11 +2050,6 @@
 	test_cmp expected actual
 '
 
-# Note that the "6" in the expected hunk header below is funny, since we only
-# show 5 lines (the missing one was blank and thus ignored). This is how
-# --ignore-blank-lines behaves even without --function-context, and this test
-# is just checking the interaction of the two features. Don't take it as an
-# endorsement of that output.
 test_expect_success 'combine --ignore-blank-lines with --function-context' '
 	test_write_lines 1 "" 2 3 4 5 >a &&
 	test_write_lines 1    2 3 4   >b &&
@@ -2039,6 +2059,7 @@
 	cat <<-\EOF >expect &&
 	@@ -1,6 +1,4 @@
 	 1
+	-
 	 2
 	 3
 	 4
@@ -2047,4 +2068,27 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'combine --ignore-blank-lines with --function-context 2' '
+	test_write_lines    a b c "" function 1 2 3 4 5 "" 6 7 8 9 >a &&
+	test_write_lines "" a b c "" function 1 2 3 4 5    6 7 8   >b &&
+	test_must_fail git diff --no-index \
+		--ignore-blank-lines --function-context a b >actual.raw &&
+	sed -n "/@@/,\$p" <actual.raw >actual &&
+	cat <<-\EOF >expect &&
+	@@ -5,11 +6,9 @@ c
+	 function
+	 1
+	 2
+	 3
+	 4
+	 5
+	-
+	 6
+	 7
+	 8
+	-9
+	EOF
+	test_cmp expect actual
+'
+
 test_done
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index 6f5ef00..c0f4839 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -32,6 +32,7 @@
 	csharp
 	css
 	dts
+	elixir
 	fortran
 	fountain
 	golang
diff --git a/t/t4018/elixir-do-not-pick-end b/t/t4018/elixir-do-not-pick-end
new file mode 100644
index 0000000..fae08ba
--- /dev/null
+++ b/t/t4018/elixir-do-not-pick-end
@@ -0,0 +1,5 @@
+defmodule RIGHT do
+end
+#
+#
+# ChangeMe; do not pick up 'end' line
diff --git a/t/t4018/elixir-ex-unit-test b/t/t4018/elixir-ex-unit-test
new file mode 100644
index 0000000..0560a2b
--- /dev/null
+++ b/t/t4018/elixir-ex-unit-test
@@ -0,0 +1,6 @@
+defmodule Test do
+  test "RIGHT" do
+    assert true == true
+    assert ChangeMe
+  end
+end
diff --git a/t/t4018/elixir-function b/t/t4018/elixir-function
new file mode 100644
index 0000000..d452f49
--- /dev/null
+++ b/t/t4018/elixir-function
@@ -0,0 +1,5 @@
+def function(RIGHT, arg) do
+  # comment
+  # comment
+  ChangeMe
+end
diff --git a/t/t4018/elixir-macro b/t/t4018/elixir-macro
new file mode 100644
index 0000000..4f925e9
--- /dev/null
+++ b/t/t4018/elixir-macro
@@ -0,0 +1,5 @@
+defmacro foo(RIGHT) do
+  # Code
+  # Code
+  ChangeMe
+end
diff --git a/t/t4018/elixir-module b/t/t4018/elixir-module
new file mode 100644
index 0000000..91a4e7a
--- /dev/null
+++ b/t/t4018/elixir-module
@@ -0,0 +1,9 @@
+defmodule RIGHT do
+  @moduledoc """
+  Foo bar
+  """
+
+  def ChangeMe(a) where is_map(a) do
+    a
+  end
+end
diff --git a/t/t4018/elixir-module-func b/t/t4018/elixir-module-func
new file mode 100644
index 0000000..c9910d0
--- /dev/null
+++ b/t/t4018/elixir-module-func
@@ -0,0 +1,8 @@
+defmodule Foo do
+  def fun(RIGHT) do
+     # Code
+     # Code
+     # Code
+     ChangeMe
+  end
+end
diff --git a/t/t4018/elixir-nested-module b/t/t4018/elixir-nested-module
new file mode 100644
index 0000000..771ebc5
--- /dev/null
+++ b/t/t4018/elixir-nested-module
@@ -0,0 +1,9 @@
+defmodule MyApp.RIGHT do
+  @moduledoc """
+  Foo bar
+  """
+
+  def ChangeMe(a) where is_map(a) do
+    a
+  end
+end
diff --git a/t/t4018/elixir-private-function b/t/t4018/elixir-private-function
new file mode 100644
index 0000000..1aabe33
--- /dev/null
+++ b/t/t4018/elixir-private-function
@@ -0,0 +1,5 @@
+defp function(RIGHT, arg) do
+  # comment
+  # comment
+  ChangeMe
+end
diff --git a/t/t4018/elixir-protocol b/t/t4018/elixir-protocol
new file mode 100644
index 0000000..7d91736
--- /dev/null
+++ b/t/t4018/elixir-protocol
@@ -0,0 +1,6 @@
+defprotocol RIGHT do
+  @doc """
+  Calculates the size (and not the length!) of a data structure
+  """
+  def size(data, ChangeMe)
+end
diff --git a/t/t4018/elixir-protocol-implementation b/t/t4018/elixir-protocol-implementation
new file mode 100644
index 0000000..f9234bb
--- /dev/null
+++ b/t/t4018/elixir-protocol-implementation
@@ -0,0 +1,5 @@
+defimpl RIGHT do
+  # Docs
+  # Docs
+  def foo(ChangeMe), do: :ok
+end
diff --git a/t/t4018/python-async-def b/t/t4018/python-async-def
new file mode 100644
index 0000000..87640e0
--- /dev/null
+++ b/t/t4018/python-async-def
@@ -0,0 +1,4 @@
+async def RIGHT(pi: int = 3.14):
+    while True:
+        break
+    return ChangeMe()
diff --git a/t/t4018/python-class b/t/t4018/python-class
new file mode 100644
index 0000000..ba9e741
--- /dev/null
+++ b/t/t4018/python-class
@@ -0,0 +1,4 @@
+class RIGHT(int, str):
+    # comment
+    # another comment
+    # ChangeMe
diff --git a/t/t4018/python-def b/t/t4018/python-def
new file mode 100644
index 0000000..e50b31b
--- /dev/null
+++ b/t/t4018/python-def
@@ -0,0 +1,4 @@
+def RIGHT(pi: int = 3.14):
+    while True:
+        break
+    return ChangeMe()
diff --git a/t/t4018/python-indented-async-def b/t/t4018/python-indented-async-def
new file mode 100644
index 0000000..f5d0325
--- /dev/null
+++ b/t/t4018/python-indented-async-def
@@ -0,0 +1,7 @@
+class Foo:
+    async def RIGHT(self, x: int):
+        return [
+            1,
+            2,
+            ChangeMe,
+        ]
diff --git a/t/t4018/python-indented-class b/t/t4018/python-indented-class
new file mode 100644
index 0000000..19b4f35
--- /dev/null
+++ b/t/t4018/python-indented-class
@@ -0,0 +1,5 @@
+if TYPE_CHECKING:
+    class RIGHT:
+        # comment
+        # another comment
+        # ChangeMe
diff --git a/t/t4018/python-indented-def b/t/t4018/python-indented-def
new file mode 100644
index 0000000..208fbad
--- /dev/null
+++ b/t/t4018/python-indented-def
@@ -0,0 +1,7 @@
+class Foo:
+    def RIGHT(self, x: int):
+        return [
+            1,
+            2,
+            ChangeMe,
+        ]
diff --git a/t/t4038-diff-combined.sh b/t/t4038-diff-combined.sh
index b5a5689..9468083 100755
--- a/t/t4038-diff-combined.sh
+++ b/t/t4038-diff-combined.sh
@@ -354,7 +354,7 @@
 '
 
 # Test for a bug reported at
-# https://public-inbox.org/git/20130515143508.GO25742@login.drsnuggles.stderr.nl/
+# https://lore.kernel.org/git/20130515143508.GO25742@login.drsnuggles.stderr.nl/
 # where a delete lines were missing from combined diff output when they
 # occurred exactly before the context lines of a later change.
 test_expect_success 'combine diff missing delete bug' '
diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh
index 619bf97..f852136 100755
--- a/t/t4041-diff-submodule-option.sh
+++ b/t/t4041-diff-submodule-option.sh
@@ -284,7 +284,7 @@
 	test_must_be_empty actual
 '
 
-test_expect_success 'submodule contains untracked and modifed content' '
+test_expect_success 'submodule contains untracked and modified content' '
 	echo new > sm1/foo6 &&
 	git diff-index -p --submodule=log HEAD >actual &&
 	cat >expected <<-EOF &&
@@ -294,7 +294,7 @@
 	test_cmp expected actual
 '
 
-test_expect_success 'submodule contains untracked and modifed content (untracked ignored)' '
+test_expect_success 'submodule contains untracked and modified content (untracked ignored)' '
 	echo new > sm1/foo6 &&
 	git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual &&
 	cat >expected <<-EOF &&
@@ -303,19 +303,19 @@
 	test_cmp expected actual
 '
 
-test_expect_success 'submodule contains untracked and modifed content (dirty ignored)' '
+test_expect_success 'submodule contains untracked and modified content (dirty ignored)' '
 	echo new > sm1/foo6 &&
 	git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual &&
 	test_must_be_empty actual
 '
 
-test_expect_success 'submodule contains untracked and modifed content (all ignored)' '
+test_expect_success 'submodule contains untracked and modified content (all ignored)' '
 	echo new > sm1/foo6 &&
 	git diff-index -p --ignore-submodules --submodule=log HEAD >actual &&
 	test_must_be_empty actual
 '
 
-test_expect_success 'submodule contains modifed content' '
+test_expect_success 'submodule contains modified content' '
 	rm -f sm1/new-file &&
 	git diff-index -p --submodule=log HEAD >actual &&
 	cat >expected <<-EOF &&
@@ -369,7 +369,7 @@
 	test_must_be_empty actual
 '
 
-test_expect_success 'modified submodule contains untracked and modifed content' '
+test_expect_success 'modified submodule contains untracked and modified content' '
 	echo modification >> sm1/foo6 &&
 	git diff-index -p --submodule=log HEAD >actual &&
 	cat >expected <<-EOF &&
@@ -381,7 +381,7 @@
 	test_cmp expected actual
 '
 
-test_expect_success 'modified submodule contains untracked and modifed content (untracked ignored)' '
+test_expect_success 'modified submodule contains untracked and modified content (untracked ignored)' '
 	echo modification >> sm1/foo6 &&
 	git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual &&
 	cat >expected <<-EOF &&
@@ -392,7 +392,7 @@
 	test_cmp expected actual
 '
 
-test_expect_success 'modified submodule contains untracked and modifed content (dirty ignored)' '
+test_expect_success 'modified submodule contains untracked and modified content (dirty ignored)' '
 	echo modification >> sm1/foo6 &&
 	git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual &&
 	cat >expected <<-EOF &&
@@ -402,13 +402,13 @@
 	test_cmp expected actual
 '
 
-test_expect_success 'modified submodule contains untracked and modifed content (all ignored)' '
+test_expect_success 'modified submodule contains untracked and modified content (all ignored)' '
 	echo modification >> sm1/foo6 &&
 	git diff-index -p --ignore-submodules --submodule=log HEAD >actual &&
 	test_must_be_empty actual
 '
 
-test_expect_success 'modified submodule contains modifed content' '
+test_expect_success 'modified submodule contains modified content' '
 	rm -f sm1/new-file &&
 	git diff-index -p --submodule=log HEAD >actual &&
 	cat >expected <<-EOF &&
diff --git a/t/t4057-diff-combined-paths.sh b/t/t4057-diff-combined-paths.sh
index dff36b7..4f4b541 100755
--- a/t/t4057-diff-combined-paths.sh
+++ b/t/t4057-diff-combined-paths.sh
@@ -33,7 +33,7 @@
 '
 
 
-test_expect_success 'only one trully conflicting path' '
+test_expect_success 'only one truly conflicting path' '
 	git checkout side &&
 	for i in $(test_seq 2 9)
 	do
diff --git a/t/t4100/t-apply-1.patch b/t/t4100/t-apply-1.patch
index 90ab54f..43394f8 100644
--- a/t/t4100/t-apply-1.patch
+++ b/t/t4100/t-apply-1.patch
@@ -75,8 +75,8 @@
 +link:git-ssh-pull.html[git-ssh-pull]::
  	Pulls from a remote repository over ssh connection
  
- Interogators:
-@@ -156,8 +156,8 @@ Interogators:
+ Interrogators:
+@@ -156,8 +156,8 @@ Interrogators:
  link:git-diff-helper.html[git-diff-helper]::
  	Generates patch format output for git-diff-*
  
diff --git a/t/t4100/t-apply-3.patch b/t/t4100/t-apply-3.patch
index 90cdbaa..cac172e 100644
--- a/t/t4100/t-apply-3.patch
+++ b/t/t4100/t-apply-3.patch
@@ -211,7 +211,7 @@
 -
 -		/* If this is an exact directory match, we may have
 -		 * directory files following this path. Match on them.
--		 * Otherwise, we're at a pach subcomponent, and we need
+-		 * Otherwise, we're at a patch subcomponent, and we need
 -		 * to try to match again.
 -		 */
 -		if (mtype == 0)
diff --git a/t/t4100/t-apply-5.patch b/t/t4100/t-apply-5.patch
index 5f6ddc1..57ec79d 100644
--- a/t/t4100/t-apply-5.patch
+++ b/t/t4100/t-apply-5.patch
@@ -185,8 +185,8 @@
 +link:git-ssh-pull.html[git-ssh-pull]::
  	Pulls from a remote repository over ssh connection
  
- Interogators:
-@@ -156,8 +156,8 @@ Interogators:
+ Interrogators:
+@@ -156,8 +156,8 @@ Interrogators:
  link:git-diff-helper.html[git-diff-helper]::
  	Generates patch format output for git-diff-*
  
diff --git a/t/t4100/t-apply-7.patch b/t/t4100/t-apply-7.patch
index 07c6589..fa24305 100644
--- a/t/t4100/t-apply-7.patch
+++ b/t/t4100/t-apply-7.patch
@@ -335,7 +335,7 @@
  
 -		/* If this is an exact directory match, we may have
 -		 * directory files following this path. Match on them.
--		 * Otherwise, we're at a pach subcomponent, and we need
+-		 * Otherwise, we're at a patch subcomponent, and we need
 -		 * to try to match again.
 +	if (e->directory) {
 +		/* If this is a directory, we have the following cases:
diff --git a/t/t4138-apply-ws-expansion.sh b/t/t4138-apply-ws-expansion.sh
index 3b636a6..b19faeb 100755
--- a/t/t4138-apply-ws-expansion.sh
+++ b/t/t4138-apply-ws-expansion.sh
@@ -17,8 +17,8 @@
 	printf "\t%s\n" 1 2 3 >after &&
 	printf "%64s\n" a b c >>after &&
 	printf "\t%s\n" 4 5 6 >>after &&
-	git diff --no-index before after |
-		sed -e "s/before/test-1/" -e "s/after/test-1/" >patch1.patch &&
+	test_expect_code 1 git diff --no-index before after >patch1.patch.raw &&
+	sed -e "s/before/test-1/" -e "s/after/test-1/" patch1.patch.raw >patch1.patch &&
 	printf "%64s\n" 1 2 3 4 5 6 >test-1 &&
 	printf "%64s\n" 1 2 3 a b c 4 5 6 >expect-1 &&
 
@@ -33,8 +33,8 @@
 		x=$(( $x + 1 ))
 	done &&
 	printf "\t%s\n" d e f >>after &&
-	git diff --no-index before after |
-		sed -e "s/before/test-2/" -e "s/after/test-2/" >patch2.patch &&
+	test_expect_code 1 git diff --no-index before after >patch2.patch.raw &&
+	sed -e "s/before/test-2/" -e "s/after/test-2/" patch2.patch.raw >patch2.patch &&
 	printf "%64s\n" a b c d e f >test-2 &&
 	printf "%64s\n" a b c >expect-2 &&
 	x=1 &&
@@ -56,8 +56,8 @@
 		x=$(( $x + 1 ))
 	done &&
 	printf "\t%s\n" d e f >>after &&
-	git diff --no-index before after |
-	sed -e "s/before/test-3/" -e "s/after/test-3/" >patch3.patch &&
+	test_expect_code 1 git diff --no-index before after >patch3.patch.raw &&
+	sed -e "s/before/test-3/" -e "s/after/test-3/" patch3.patch.raw >patch3.patch &&
 	printf "%64s\n" a b c d e f >test-3 &&
 	printf "%64s\n" a b c >expect-3 &&
 	x=0 &&
@@ -84,8 +84,8 @@
 		printf "\t%02d\n" $x >>after
 		x=$(( $x + 1 ))
 	done &&
-	git diff --no-index before after |
-	sed -e "s/before/test-4/" -e "s/after/test-4/" >patch4.patch &&
+	test_expect_code 1 git diff --no-index before after >patch4.patch.raw &&
+	sed -e "s/before/test-4/" -e "s/after/test-4/" patch4.patch.raw >patch4.patch &&
 	>test-4 &&
 	x=0 &&
 	while test $x -lt 50
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index e803ba4..2c94894 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -667,7 +667,7 @@
 * | | fifth
 * | | fourth
 |/ /
-* | third
+* / third
 |/
 * second
 * initial
@@ -1570,6 +1570,14 @@
 	git commit -S -m signed_commit
 '
 
+test_expect_success GPG 'setup signed branch with subkey' '
+	test_when_finished "git reset --hard && git checkout master" &&
+	git checkout -b signed-subkey master &&
+	echo foo >foo &&
+	git add foo &&
+	git commit -SB7227189 -m signed_commit
+'
+
 test_expect_success GPGSM 'setup signed branch x509' '
 	test_when_finished "git reset --hard && git checkout master" &&
 	git checkout -b signed-x509 master &&
@@ -1580,6 +1588,18 @@
 	git commit -S -m signed_commit
 '
 
+test_expect_success GPGSM 'log x509 fingerprint' '
+	echo "F8BF62E0693D0694816377099909C779FA23FD65 | " >expect &&
+	git log -n1 --format="%GF | %GP" signed-x509 >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success GPGSM 'log OpenPGP fingerprint' '
+	echo "D4BE22311AD3131E5EDA29A461092E85B7227189" > expect &&
+	git log -n1 --format="%GP" signed-subkey >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success GPG 'log --graph --show-signature' '
 	git log --graph --show-signature -n1 signed >actual &&
 	grep "^| gpg: Signature made" actual &&
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index f42a69f..204c149 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -134,6 +134,36 @@
 	test_cmp expected actual
 '
 
+for p in short medium full fuller email raw
+do
+	test_expect_success "NUL termination with --reflog --pretty=$p" '
+		revs="$(git rev-list --reflog)" &&
+		for r in $revs
+		do
+			git show -s "$r" --pretty="$p" &&
+			printf "\0" || return 1
+		done >expect &&
+		{
+			git log -z --reflog --pretty="$p" &&
+			printf "\0"
+		} >actual &&
+		test_cmp expect actual
+	'
+done
+
+test_expect_success 'NUL termination with --reflog --pretty=oneline' '
+	revs="$(git rev-list --reflog)" &&
+	for r in $revs
+	do
+		git show -s --pretty=oneline "$r" >raw &&
+		cat raw | lf_to_nul || exit 1
+	done >expect &&
+	# the trailing NUL is already produced so we do not need to
+	# output another one
+	git log -z --pretty=oneline --reflog >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'setup more commits' '
 	test_commit "message one" one one message-one &&
 	test_commit "message two" two two message-two &&
@@ -503,6 +533,12 @@
 	test_cmp expected actual
 '
 
+test_expect_success 'short date' '
+	git log --format=%ad%n%cd --date=short >expected &&
+	git log --format=%as%n%cs >actual &&
+	test_cmp expected actual
+'
+
 # get new digests (with no abbreviations)
 test_expect_success 'set up log decoration tests' '
 	head1=$(git rev-parse --verify HEAD~0) &&
@@ -640,7 +676,7 @@
 	test_cmp expect actual
 '
 
-test_expect_success '%(trailers:key=nonexistant) becomes empty' '
+test_expect_success '%(trailers:key=nonexistent) becomes empty' '
 	git log --no-walk --pretty="x%(trailers:key=Nacked-by)x" >actual &&
 	echo "xx" >expect &&
 	test_cmp expect actual
@@ -788,4 +824,47 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'log --pretty=reference' '
+	git log --pretty="tformat:%h (%s, %as)" >expect &&
+	git log --pretty=reference >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'log --pretty=reference with log.date is overridden by short date' '
+	git log --pretty="tformat:%h (%s, %as)" >expect &&
+	test_config log.date rfc &&
+	git log --pretty=reference >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'log --pretty=reference with explicit date overrides short date' '
+	git log --date=rfc --pretty="tformat:%h (%s, %ad)" >expect &&
+	git log --date=rfc --pretty=reference >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'log --pretty=reference is never unabbreviated' '
+	git log --pretty="tformat:%h (%s, %as)" >expect &&
+	git log --no-abbrev-commit --pretty=reference >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'log --pretty=reference is never decorated' '
+	git log --pretty="tformat:%h (%s, %as)" >expect &&
+	git log --decorate=short --pretty=reference >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'log --pretty=reference does not output reflog info' '
+	git log --walk-reflogs --pretty="tformat:%h (%s, %as)" >expect &&
+	git log --walk-reflogs --pretty=reference >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'log --pretty=reference is colored appropriately' '
+	git log --color=always --pretty="tformat:%C(auto)%h (%s, %as)" >expect &&
+	git log --color=always --pretty=reference >actual &&
+	test_cmp expect actual
+'
+
 test_done
diff --git a/t/t4210-log-i18n.sh b/t/t4210-log-i18n.sh
index 6e61f57..c379208 100755
--- a/t/t4210-log-i18n.sh
+++ b/t/t4210-log-i18n.sh
@@ -70,7 +70,7 @@
 	then
 	    force_regex=.*
 	fi
-	test_expect_success !MINGW,GETTEXT_LOCALE,$prereq "-c grep.patternType=$engine log --grep does not find non-reencoded values (latin1 + locale)" "
+	test_expect_success !MINGW,!REGEX_ILLSEQ,GETTEXT_LOCALE,$prereq "-c grep.patternType=$engine log --grep does not find non-reencoded values (latin1 + locale)" "
 		cat >expect <<-\EOF &&
 		latin1
 		utf8
@@ -84,7 +84,7 @@
 		test_must_be_empty actual
 	"
 
-	test_expect_success !MINGW,GETTEXT_LOCALE,$prereq "-c grep.patternType=$engine log --grep does not die on invalid UTF-8 value (latin1 + locale + invalid needle)" "
+	test_expect_success !MINGW,!REGEX_ILLSEQ,GETTEXT_LOCALE,$prereq "-c grep.patternType=$engine log --grep does not die on invalid UTF-8 value (latin1 + locale + invalid needle)" "
 		LC_ALL=\"$is_IS_locale\" git -c grep.patternType=$engine log --encoding=ISO-8859-1 --format=%s --grep=\"$force_regex$invalid_e\" >actual &&
 		test_must_be_empty actual
 	"
diff --git a/t/t4213-log-tabexpand.sh b/t/t4213-log-tabexpand.sh
index 7f90f58..53a4af3 100755
--- a/t/t4213-log-tabexpand.sh
+++ b/t/t4213-log-tabexpand.sh
@@ -36,7 +36,7 @@
 	esac
 
 	# Prefix the output with the command line arguments, and
-	# replace SP with a dot both in the expecte and actual output
+	# replace SP with a dot both in the expected and actual output
 	# so that test_cmp would show the difference together with the
 	# breakage in a way easier to consume by the debugging user.
 	{
diff --git a/t/t4214-log-graph-octopus.sh b/t/t4214-log-graph-octopus.sh
index 3ae8e51..40d27db 100755
--- a/t/t4214-log-graph-octopus.sh
+++ b/t/t4214-log-graph-octopus.sh
@@ -26,15 +26,14 @@
 test_expect_success 'log --graph with tricky octopus merge, no color' '
 	cat >expect.uncolored <<-\EOF &&
 	* left
-	| *---.   octopus-merge
-	| |\ \ \
-	|/ / / /
+	| *-.   octopus-merge
+	|/|\ \
 	| | | * 4
 	| | * | 3
 	| | |/
-	| * | 2
+	| * / 2
 	| |/
-	* | 1
+	* / 1
 	|/
 	* initial
 	EOF
@@ -47,15 +46,14 @@
 	test_config log.graphColors red,green,yellow,blue,magenta,cyan &&
 	cat >expect.colors <<-\EOF &&
 	* left
-	<RED>|<RESET> *<BLUE>-<RESET><BLUE>-<RESET><MAGENTA>-<RESET><MAGENTA>.<RESET>   octopus-merge
-	<RED>|<RESET> <RED>|<RESET><YELLOW>\<RESET> <BLUE>\<RESET> <MAGENTA>\<RESET>
-	<RED>|<RESET><RED>/<RESET> <YELLOW>/<RESET> <BLUE>/<RESET> <MAGENTA>/<RESET>
+	<RED>|<RESET> *<MAGENTA>-<RESET><MAGENTA>.<RESET>   octopus-merge
+	<RED>|<RESET><RED>/<RESET><YELLOW>|<RESET><BLUE>\<RESET> <MAGENTA>\<RESET>
 	<RED>|<RESET> <YELLOW>|<RESET> <BLUE>|<RESET> * 4
 	<RED>|<RESET> <YELLOW>|<RESET> * <MAGENTA>|<RESET> 3
 	<RED>|<RESET> <YELLOW>|<RESET> <MAGENTA>|<RESET><MAGENTA>/<RESET>
-	<RED>|<RESET> * <MAGENTA>|<RESET> 2
+	<RED>|<RESET> * <MAGENTA>/<RESET> 2
 	<RED>|<RESET> <MAGENTA>|<RESET><MAGENTA>/<RESET>
-	* <MAGENTA>|<RESET> 1
+	* <MAGENTA>/<RESET> 1
 	<MAGENTA>|<RESET><MAGENTA>/<RESET>
 	* initial
 	EOF
@@ -74,9 +72,9 @@
 	| | | * 4
 	| | * | 3
 	| | |/
-	| * | 2
+	| * / 2
 	| |/
-	* | 1
+	* / 1
 	|/
 	* initial
 	EOF
@@ -92,9 +90,9 @@
 	<RED>|<RESET> <GREEN>|<RESET> <YELLOW>|<RESET> * 4
 	<RED>|<RESET> <GREEN>|<RESET> * <BLUE>|<RESET> 3
 	<RED>|<RESET> <GREEN>|<RESET> <BLUE>|<RESET><BLUE>/<RESET>
-	<RED>|<RESET> * <BLUE>|<RESET> 2
+	<RED>|<RESET> * <BLUE>/<RESET> 2
 	<RED>|<RESET> <BLUE>|<RESET><BLUE>/<RESET>
-	* <BLUE>|<RESET> 1
+	* <BLUE>/<RESET> 1
 	<BLUE>|<RESET><BLUE>/<RESET>
 	* initial
 	EOF
@@ -112,9 +110,9 @@
 	| | | * 4
 	| | * | 3
 	| | |/
-	| * | 2
+	| * / 2
 	| |/
-	* | 1
+	* / 1
 	|/
 	* initial
 	EOF
@@ -123,7 +121,7 @@
 	test_cmp expect.uncolored actual
 '
 
-test_expect_failure 'log --graph with normal octopus and child merge with colors' '
+test_expect_success 'log --graph with normal octopus and child merge with colors' '
 	cat >expect.colors <<-\EOF &&
 	* after-merge
 	*<BLUE>-<RESET><BLUE>-<RESET><MAGENTA>-<RESET><MAGENTA>.<RESET>   octopus-merge
@@ -131,9 +129,9 @@
 	<GREEN>|<RESET> <YELLOW>|<RESET> <BLUE>|<RESET> * 4
 	<GREEN>|<RESET> <YELLOW>|<RESET> * <MAGENTA>|<RESET> 3
 	<GREEN>|<RESET> <YELLOW>|<RESET> <MAGENTA>|<RESET><MAGENTA>/<RESET>
-	<GREEN>|<RESET> * <MAGENTA>|<RESET> 2
+	<GREEN>|<RESET> * <MAGENTA>/<RESET> 2
 	<GREEN>|<RESET> <MAGENTA>|<RESET><MAGENTA>/<RESET>
-	* <MAGENTA>|<RESET> 1
+	* <MAGENTA>/<RESET> 1
 	<MAGENTA>|<RESET><MAGENTA>/<RESET>
 	* initial
 	EOF
@@ -147,15 +145,14 @@
 	cat >expect.uncolored <<-\EOF &&
 	* left
 	| * after-merge
-	| *---.   octopus-merge
-	| |\ \ \
-	|/ / / /
+	| *-.   octopus-merge
+	|/|\ \
 	| | | * 4
 	| | * | 3
 	| | |/
-	| * | 2
+	| * / 2
 	| |/
-	* | 1
+	* / 1
 	|/
 	* initial
 	EOF
@@ -164,20 +161,19 @@
 	test_cmp expect.uncolored actual
 '
 
-test_expect_failure 'log --graph with tricky octopus merge and its child with colors' '
+test_expect_success 'log --graph with tricky octopus merge and its child with colors' '
 	test_config log.graphColors red,green,yellow,blue,magenta,cyan &&
 	cat >expect.colors <<-\EOF &&
 	* left
 	<RED>|<RESET> * after-merge
-	<RED>|<RESET> *<MAGENTA>-<RESET><MAGENTA>-<RESET><CYAN>-<RESET><CYAN>.<RESET>   octopus-merge
-	<RED>|<RESET> <RED>|<RESET><BLUE>\<RESET> <MAGENTA>\<RESET> <CYAN>\<RESET>
-	<RED>|<RESET><RED>/<RESET> <BLUE>/<RESET> <MAGENTA>/<RESET> <CYAN>/<RESET>
+	<RED>|<RESET> *<CYAN>-<RESET><CYAN>.<RESET>   octopus-merge
+	<RED>|<RESET><RED>/<RESET><BLUE>|<RESET><MAGENTA>\<RESET> <CYAN>\<RESET>
 	<RED>|<RESET> <BLUE>|<RESET> <MAGENTA>|<RESET> * 4
 	<RED>|<RESET> <BLUE>|<RESET> * <CYAN>|<RESET> 3
 	<RED>|<RESET> <BLUE>|<RESET> <CYAN>|<RESET><CYAN>/<RESET>
-	<RED>|<RESET> * <CYAN>|<RESET> 2
+	<RED>|<RESET> * <CYAN>/<RESET> 2
 	<RED>|<RESET> <CYAN>|<RESET><CYAN>/<RESET>
-	* <CYAN>|<RESET> 1
+	* <CYAN>/<RESET> 1
 	<CYAN>|<RESET><CYAN>/<RESET>
 	* initial
 	EOF
@@ -209,7 +205,7 @@
 	test_cmp expect.uncolored actual
 '
 
-test_expect_failure 'log --graph with crossover in octopus merge with colors' '
+test_expect_success 'log --graph with crossover in octopus merge with colors' '
 	test_config log.graphColors red,green,yellow,blue,magenta,cyan &&
 	cat >expect.colors <<-\EOF &&
 	* after-4
@@ -257,7 +253,7 @@
 	test_cmp expect.uncolored actual
 '
 
-test_expect_failure 'log --graph with crossover in octopus merge and its child with colors' '
+test_expect_success 'log --graph with crossover in octopus merge and its child with colors' '
 	test_config log.graphColors red,green,yellow,blue,magenta,cyan &&
 	cat >expect.colors <<-\EOF &&
 	* after-4
@@ -353,7 +349,7 @@
 	test_cmp expect.uncolored actual
 '
 
-test_expect_failure 'log --graph with unrelated commit and octopus child with colors' '
+test_expect_success 'log --graph with unrelated commit and octopus child with colors' '
 	test_config log.graphColors red,green,yellow,blue,magenta,cyan &&
 	cat >expect.colors <<-\EOF &&
 	* after-initial
diff --git a/t/t4215-log-skewed-merges.sh b/t/t4215-log-skewed-merges.sh
new file mode 100755
index 0000000..18709a7
--- /dev/null
+++ b/t/t4215-log-skewed-merges.sh
@@ -0,0 +1,243 @@
+#!/bin/sh
+
+test_description='git log --graph of skewed merges'
+
+. ./test-lib.sh
+
+check_graph () {
+	cat >expect &&
+	git log --graph --pretty=tformat:%s "$@" >actual.raw &&
+	sed "s/ *$//" actual.raw >actual &&
+	test_cmp expect actual
+}
+
+test_expect_success 'log --graph with merge fusing with its left and right neighbors' '
+	git checkout --orphan _p &&
+	test_commit A &&
+	test_commit B &&
+	git checkout -b _q @^ && test_commit C &&
+	git checkout -b _r @^ && test_commit D &&
+	git checkout _p && git merge --no-ff _q _r -m E &&
+	git checkout _r && test_commit F &&
+	git checkout _p && git merge --no-ff _r -m G &&
+	git checkout @^^ && git merge --no-ff _p -m H &&
+
+	check_graph <<-\EOF
+	*   H
+	|\
+	| *   G
+	| |\
+	| | * F
+	| * | E
+	|/|\|
+	| | * D
+	| * | C
+	| |/
+	* / B
+	|/
+	* A
+	EOF
+'
+
+test_expect_success 'log --graph with left-skewed merge' '
+	git checkout --orphan 0_p && test_commit 0_A &&
+	git checkout -b 0_q 0_p && test_commit 0_B &&
+	git checkout -b 0_r 0_p &&
+	test_commit 0_C &&
+	test_commit 0_D &&
+	git checkout -b 0_s 0_p && test_commit 0_E &&
+	git checkout -b 0_t 0_p && git merge --no-ff 0_r^ 0_s -m 0_F &&
+	git checkout 0_p && git merge --no-ff 0_s -m 0_G &&
+	git checkout @^ && git merge --no-ff 0_q 0_r 0_t 0_p -m 0_H &&
+
+	check_graph <<-\EOF
+	*-----.   0_H
+	|\ \ \ \
+	| | | | * 0_G
+	| |_|_|/|
+	|/| | | |
+	| | | * | 0_F
+	| |_|/|\|
+	|/| | | |
+	| | | | * 0_E
+	| |_|_|/
+	|/| | |
+	| | * | 0_D
+	| | |/
+	| | * 0_C
+	| |/
+	|/|
+	| * 0_B
+	|/
+	* 0_A
+	EOF
+'
+
+test_expect_success 'log --graph with nested left-skewed merge' '
+	git checkout --orphan 1_p &&
+	test_commit 1_A &&
+	test_commit 1_B &&
+	test_commit 1_C &&
+	git checkout -b 1_q @^ && test_commit 1_D &&
+	git checkout 1_p && git merge --no-ff 1_q -m 1_E &&
+	git checkout -b 1_r @~3 && test_commit 1_F &&
+	git checkout 1_p && git merge --no-ff 1_r -m 1_G &&
+	git checkout @^^ && git merge --no-ff 1_p -m 1_H &&
+
+	check_graph <<-\EOF
+	*   1_H
+	|\
+	| *   1_G
+	| |\
+	| | * 1_F
+	| * | 1_E
+	|/| |
+	| * | 1_D
+	* | | 1_C
+	|/ /
+	* / 1_B
+	|/
+	* 1_A
+	EOF
+'
+
+test_expect_success 'log --graph with nested left-skewed merge following normal merge' '
+	git checkout --orphan 2_p &&
+	test_commit 2_A &&
+	test_commit 2_B &&
+	test_commit 2_C &&
+	git checkout -b 2_q @^^ &&
+	test_commit 2_D &&
+	test_commit 2_E &&
+	git checkout -b 2_r @^ && test_commit 2_F &&
+	git checkout 2_q &&
+	git merge --no-ff 2_r -m 2_G &&
+	git merge --no-ff 2_p^ -m 2_H &&
+	git checkout -b 2_s @^^ && git merge --no-ff 2_q -m 2_J &&
+	git checkout 2_p && git merge --no-ff 2_s -m 2_K &&
+
+	check_graph <<-\EOF
+	*   2_K
+	|\
+	| *   2_J
+	| |\
+	| | *   2_H
+	| | |\
+	| | * | 2_G
+	| |/| |
+	| | * | 2_F
+	| * | | 2_E
+	| |/ /
+	| * | 2_D
+	* | | 2_C
+	| |/
+	|/|
+	* | 2_B
+	|/
+	* 2_A
+	EOF
+'
+
+test_expect_success 'log --graph with nested right-skewed merge following left-skewed merge' '
+	git checkout --orphan 3_p &&
+	test_commit 3_A &&
+	git checkout -b 3_q &&
+	test_commit 3_B &&
+	test_commit 3_C &&
+	git checkout -b 3_r @^ &&
+	test_commit 3_D &&
+	git checkout 3_q && git merge --no-ff 3_r -m 3_E &&
+	git checkout 3_p && git merge --no-ff 3_q -m 3_F &&
+	git checkout 3_r && test_commit 3_G &&
+	git checkout 3_p && git merge --no-ff 3_r -m 3_H &&
+	git checkout @^^ && git merge --no-ff 3_p -m 3_J &&
+
+	check_graph <<-\EOF
+	*   3_J
+	|\
+	| *   3_H
+	| |\
+	| | * 3_G
+	| * | 3_F
+	|/| |
+	| * | 3_E
+	| |\|
+	| | * 3_D
+	| * | 3_C
+	| |/
+	| * 3_B
+	|/
+	* 3_A
+	EOF
+'
+
+test_expect_success 'log --graph with right-skewed merge following a left-skewed one' '
+	git checkout --orphan 4_p &&
+	test_commit 4_A &&
+	test_commit 4_B &&
+	test_commit 4_C &&
+	git checkout -b 4_q @^^ && test_commit 4_D &&
+	git checkout -b 4_r 4_p^ && git merge --no-ff 4_q -m 4_E &&
+	git checkout -b 4_s 4_p^^ &&
+	git merge --no-ff 4_r -m 4_F &&
+	git merge --no-ff 4_p -m 4_G &&
+	git checkout @^^ && git merge --no-ff 4_s -m 4_H &&
+
+	check_graph --date-order <<-\EOF
+	*   4_H
+	|\
+	| *   4_G
+	| |\
+	| * | 4_F
+	|/| |
+	| * |   4_E
+	| |\ \
+	| | * | 4_D
+	| |/ /
+	|/| |
+	| | * 4_C
+	| |/
+	| * 4_B
+	|/
+	* 4_A
+	EOF
+'
+
+test_expect_success 'log --graph with octopus merge with column joining its penultimate parent' '
+	git checkout --orphan 5_p &&
+	test_commit 5_A &&
+	git branch 5_q &&
+	git branch 5_r &&
+	test_commit 5_B &&
+	git checkout 5_q && test_commit 5_C &&
+	git checkout 5_r && test_commit 5_D &&
+	git checkout 5_p &&
+	git merge --no-ff 5_q 5_r -m 5_E &&
+	git checkout 5_q && test_commit 5_F &&
+	git checkout -b 5_s 5_p^ &&
+	git merge --no-ff 5_p 5_q -m 5_G &&
+	git checkout 5_r &&
+	git merge --no-ff 5_s -m 5_H &&
+
+	check_graph <<-\EOF
+	*   5_H
+	|\
+	| *-.   5_G
+	| |\ \
+	| | | * 5_F
+	| | * |   5_E
+	| |/|\ \
+	| |_|/ /
+	|/| | /
+	| | |/
+	* | | 5_D
+	| | * 5_C
+	| |/
+	|/|
+	| * 5_B
+	|/
+	* 5_A
+	EOF
+'
+
+test_done
diff --git a/t/t4256-am-format-flowed.sh b/t/t4256-am-format-flowed.sh
index 6340310..2369c4e 100755
--- a/t/t4256-am-format-flowed.sh
+++ b/t/t4256-am-format-flowed.sh
@@ -11,7 +11,7 @@
 '
 
 test_expect_success 'am with format=flowed' '
-	git am <"$TEST_DIRECTORY/t4256/1/patch" >stdout 2>stderr &&
+	git am <"$TEST_DIRECTORY/t4256/1/patch" 2>stderr &&
 	test_i18ngrep "warning: Patch sent with format=flowed" stderr &&
 	test_cmp "$TEST_DIRECTORY/t4256/1/mailinfo.c" mailinfo.c
 '
diff --git a/t/t5150-request-pull.sh b/t/t5150-request-pull.sh
index 852dcd9..1ad4ecc 100755
--- a/t/t5150-request-pull.sh
+++ b/t/t5150-request-pull.sh
@@ -4,6 +4,12 @@
 
 . ./test-lib.sh
 
+if ! test_have_prereq PERL
+then
+	skip_all='skipping request-pull tests, perl not available'
+	test_done
+fi
+
 test_expect_success 'setup' '
 
 	git init --bare upstream.git &&
diff --git a/t/t5314-pack-cycle-detection.sh b/t/t5314-pack-cycle-detection.sh
index e525466..0aec861 100755
--- a/t/t5314-pack-cycle-detection.sh
+++ b/t/t5314-pack-cycle-detection.sh
@@ -53,7 +53,7 @@
 
 
 
-# Create a pack containing the the tree $1 and blob $1:file, with
+# Create a pack containing the tree $1 and blob $1:file, with
 # the latter stored as a delta against $2:file.
 #
 # We convince pack-objects to make the delta in the direction of our choosing
diff --git a/t/t5317-pack-objects-filter-objects.sh b/t/t5317-pack-objects-filter-objects.sh
index 2d2f5d0..dc04465 100755
--- a/t/t5317-pack-objects-filter-objects.sh
+++ b/t/t5317-pack-objects-filter-objects.sh
@@ -45,12 +45,7 @@
 	git -C r1 index-pack ../filter.pack &&
 
 	git -C r1 verify-pack -v ../filter.pack >verify_result &&
-	grep blob verify_result |
-	awk -f print_1.awk |
-	sort >observed &&
-
-	nr=$(wc -l <observed) &&
-	test 0 -eq $nr
+	! grep blob verify_result
 '
 
 test_expect_success 'verify normal and blob:none packfiles have same commits/trees' '
@@ -72,7 +67,8 @@
 	echo foo >r5/foo &&
 	git -C r5 add foo &&
 	git -C r5 commit -m "foo" &&
-	del=$(git -C r5 rev-parse HEAD^{tree} | sed "s|..|&/|") &&
+	git -C r5 rev-parse HEAD^{tree} >tree &&
+	del=$(sed "s|..|&/|" tree) &&
 	rm r5/.git/objects/$del &&
 	test_must_fail git -C r5 pack-objects --revs --stdout 2>bad_tree <<-EOF &&
 	HEAD
@@ -148,12 +144,7 @@
 	git -C r2 index-pack ../filter.pack &&
 
 	git -C r2 verify-pack -v ../filter.pack >verify_result &&
-	grep blob verify_result |
-	awk -f print_1.awk |
-	sort >observed &&
-
-	nr=$(wc -l <observed) &&
-	test 0 -eq $nr
+	! grep blob verify_result
 '
 
 test_expect_success 'verify blob:limit=1000' '
@@ -163,12 +154,7 @@
 	git -C r2 index-pack ../filter.pack &&
 
 	git -C r2 verify-pack -v ../filter.pack >verify_result &&
-	grep blob verify_result |
-	awk -f print_1.awk |
-	sort >observed &&
-
-	nr=$(wc -l <observed) &&
-	test 0 -eq $nr
+	! grep blob verify_result
 '
 
 test_expect_success 'verify blob:limit=1001' '
@@ -230,10 +216,9 @@
 	awk -f print_2.awk ls_files_result |
 	sort >expected &&
 
-	git -C r2 pack-objects --revs --stdout --filter=blob:limit=1k >filter.pack <<-EOF &&
-	HEAD
-	$(git -C r2 rev-parse HEAD:large.10000)
-	EOF
+	echo HEAD >objects &&
+	git -C r2 rev-parse HEAD:large.10000 >>objects &&
+	git -C r2 pack-objects --revs --stdout --filter=blob:limit=1k <objects >filter.pack &&
 	git -C r2 index-pack ../filter.pack &&
 
 	git -C r2 verify-pack -v ../filter.pack >verify_result &&
@@ -377,7 +362,8 @@
 	awk -f print_2.awk ls_files_result |
 	sort >expected &&
 
-	oid=$(git -C r4 ls-files -s pattern | awk -f print_2.awk) &&
+	git -C r4 ls-files -s pattern >staged &&
+	oid=$(awk -f print_2.awk staged) &&
 	git -C r4 pack-objects --revs --stdout --filter=sparse:oid=$oid >filter.pack <<-EOF &&
 	HEAD
 	EOF
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index d42b3ef..3f03de6 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -85,7 +85,7 @@
 	num_commits: $1
 	chunks: oid_fanout oid_lookup commit_metadata$OPTIONAL
 	EOF
-	git commit-graph read >output &&
+	test-tool read-graph >output &&
 	test_cmp expect output
 }
 
@@ -132,7 +132,7 @@
 
 test_expect_success 'commit-graph write force progress on for stderr' '
 	cd "$TRASH_DIRECTORY/full" &&
-	git commit-graph write --progress 2>err &&
+	GIT_PROGRESS_DELAY=0 git commit-graph write --progress 2>err &&
 	test_file_not_empty err
 '
 
@@ -150,7 +150,7 @@
 
 test_expect_success 'commit-graph verify force progress on for stderr' '
 	cd "$TRASH_DIRECTORY/full" &&
-	git commit-graph verify --progress 2>err &&
+	GIT_PROGRESS_DELAY=0 git commit-graph verify --progress 2>err &&
 	test_file_not_empty err
 '
 
@@ -660,7 +660,7 @@
 		git commit-tree -p "$broken" -m "good" "$tree" >good &&
 		test_must_fail git commit-graph write --stdin-commits \
 			<good 2>test_err &&
-		test_i18ngrep "unable to get tree for" test_err
+		test_i18ngrep "unable to parse commit" test_err
 	)
 '
 
diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh
index 115aabd..c248234 100755
--- a/t/t5324-split-commit-graph.sh
+++ b/t/t5324-split-commit-graph.sh
@@ -25,7 +25,7 @@
 	num_commits: $1
 	chunks: oid_fanout oid_lookup commit_metadata
 	EOF
-	git commit-graph read >output &&
+	test-tool read-graph >output &&
 	test_cmp expect output
 }
 
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index 43e1d8d..d7b9f90 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -267,7 +267,7 @@
 '
 
 test_lazy_prereq GIT_DAEMON '
-	git env--helper --type=bool --default=true --exit-code GIT_TEST_GIT_DAEMON
+	test_bool_env GIT_TEST_GIT_DAEMON true
 '
 
 # This test spawns a daemon, so run it only if the user would be OK with
diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh
index cf4cc32..602d996 100755
--- a/t/t5520-pull.sh
+++ b/t/t5520-pull.sh
@@ -5,7 +5,7 @@
 . ./test-lib.sh
 
 modify () {
-	sed -e "$1" <"$2" >"$2.x" &&
+	sed -e "$1" "$2" >"$2.x" &&
 	mv "$2.x" "$2"
 }
 
@@ -15,8 +15,10 @@
 	git add new_file &&
 	git pull "$@" . copy &&
 	test_cmp_rev HEAD^ copy &&
-	test "$(cat new_file)" = dirty &&
-	test "$(cat file)" = "modified again"
+	echo dirty >expect &&
+	test_cmp expect new_file &&
+	echo "modified again" >expect &&
+	test_cmp expect file
 }
 
 test_pull_autostash_fail () {
@@ -39,8 +41,8 @@
 		cd cloned &&
 		git pull ..
 	) &&
-	test -f file &&
-	test -f cloned/file &&
+	test_path_is_file file &&
+	test_path_is_file cloned/file &&
 	test_cmp file cloned/file
 '
 
@@ -50,8 +52,8 @@
 		cd cloned-uho &&
 		git pull .. master:master
 	) &&
-	test -f file &&
-	test -f cloned-uho/file &&
+	test_path_is_file file &&
+	test_path_is_file cloned-uho/file &&
 	test_cmp file cloned-uho/file
 '
 
@@ -99,7 +101,7 @@
 	(
 		cd cloned-octopus &&
 		test_must_fail git pull .. master master &&
-		! test -f file
+		test_path_is_missing file
 	)
 '
 
@@ -110,9 +112,11 @@
 	echo updated >file &&
 	git commit -a -m updated &&
 	git checkout copy &&
-	test "$(cat file)" = file &&
+	echo file >expect &&
+	test_cmp expect file &&
 	git pull &&
-	test "$(cat file)" = updated &&
+	echo updated >expect &&
+	test_cmp expect file &&
 	git reflog -1 >reflog.actual &&
 	sed "s/^[0-9a-f][0-9a-f]*/OBJID/" reflog.actual >reflog.fuzzy &&
 	echo "OBJID HEAD@{0}: pull: Fast-forward" >reflog.expected &&
@@ -125,9 +129,11 @@
 	git commit -a -m modified &&
 	git checkout copy &&
 	git reset --hard HEAD^ &&
-	test "$(cat file)" = file &&
+	echo file >expect &&
+	test_cmp expect file &&
 	git pull . second &&
-	test "$(cat file)" = modified &&
+	echo modified >expect &&
+	test_cmp expect file &&
 	git reflog -1 >reflog.actual &&
 	sed "s/^[0-9a-f][0-9a-f]*/OBJID/" reflog.actual >reflog.fuzzy &&
 	echo "OBJID HEAD@{0}: pull . second: Fast-forward" >reflog.expected &&
@@ -137,10 +143,11 @@
 test_expect_success 'fail if wildcard spec does not match any refs' '
 	git checkout -b test copy^ &&
 	test_when_finished "git checkout -f copy && git branch -D test" &&
-	test "$(cat file)" = file &&
+	echo file >expect &&
+	test_cmp expect file &&
 	test_must_fail git pull . "refs/nonexisting1/*:refs/nonexisting2/*" 2>err &&
 	test_i18ngrep "no candidates for merging" err &&
-	test "$(cat file)" = file
+	test_cmp expect file
 '
 
 test_expect_success 'fail if no branches specified with non-default remote' '
@@ -148,11 +155,12 @@
 	test_when_finished "git remote remove test_remote" &&
 	git checkout -b test copy^ &&
 	test_when_finished "git checkout -f copy && git branch -D test" &&
-	test "$(cat file)" = file &&
+	echo file >expect &&
+	test_cmp expect file &&
 	test_config branch.test.remote origin &&
 	test_must_fail git pull test_remote 2>err &&
 	test_i18ngrep "specify a branch on the command line" err &&
-	test "$(cat file)" = file
+	test_cmp expect file
 '
 
 test_expect_success 'fail if not on a branch' '
@@ -160,10 +168,11 @@
 	test_when_finished "git remote remove origin" &&
 	git checkout HEAD^ &&
 	test_when_finished "git checkout -f copy" &&
-	test "$(cat file)" = file &&
+	echo file >expect &&
+	test_cmp expect file &&
 	test_must_fail git pull 2>err &&
 	test_i18ngrep "not currently on a branch" err &&
-	test "$(cat file)" = file
+	test_cmp expect file
 '
 
 test_expect_success 'fail if no configuration for current branch' '
@@ -172,10 +181,11 @@
 	git checkout -b test copy^ &&
 	test_when_finished "git checkout -f copy && git branch -D test" &&
 	test_config branch.test.remote test_remote &&
-	test "$(cat file)" = file &&
+	echo file >expect &&
+	test_cmp expect file &&
 	test_must_fail git pull 2>err &&
 	test_i18ngrep "no tracking information" err &&
-	test "$(cat file)" = file
+	test_cmp expect file
 '
 
 test_expect_success 'pull --all: fail if no configuration for current branch' '
@@ -184,10 +194,11 @@
 	git checkout -b test copy^ &&
 	test_when_finished "git checkout -f copy && git branch -D test" &&
 	test_config branch.test.remote test_remote &&
-	test "$(cat file)" = file &&
+	echo file >expect &&
+	test_cmp expect file &&
 	test_must_fail git pull --all 2>err &&
 	test_i18ngrep "There is no tracking information" err &&
-	test "$(cat file)" = file
+	test_cmp expect file
 '
 
 test_expect_success 'fail if upstream branch does not exist' '
@@ -195,26 +206,31 @@
 	test_when_finished "git checkout -f copy && git branch -D test" &&
 	test_config branch.test.remote . &&
 	test_config branch.test.merge refs/heads/nonexisting &&
-	test "$(cat file)" = file &&
+	echo file >expect &&
+	test_cmp expect file &&
 	test_must_fail git pull 2>err &&
 	test_i18ngrep "no such ref was fetched" err &&
-	test "$(cat file)" = file
+	test_cmp expect file
 '
 
 test_expect_success 'fail if the index has unresolved entries' '
 	git checkout -b third second^ &&
 	test_when_finished "git checkout -f copy && git branch -D third" &&
-	test "$(cat file)" = file &&
+	echo file >expect &&
+	test_cmp expect file &&
 	test_commit modified2 file &&
-	test -z "$(git ls-files -u)" &&
+	git ls-files -u >unmerged &&
+	test_must_be_empty unmerged &&
 	test_must_fail git pull . second &&
-	test -n "$(git ls-files -u)" &&
+	git ls-files -u >unmerged &&
+	test_file_not_empty unmerged &&
 	cp file expected &&
 	test_must_fail git pull . second 2>err &&
 	test_i18ngrep "Pulling is not possible because you have unmerged files." err &&
 	test_cmp expected file &&
 	git add file &&
-	test -z "$(git ls-files -u)" &&
+	git ls-files -u >unmerged &&
+	test_must_be_empty unmerged &&
 	test_must_fail git pull . second 2>err &&
 	test_i18ngrep "You have not concluded your merge" err &&
 	test_cmp expected file
@@ -223,36 +239,42 @@
 test_expect_success 'fast-forwards working tree if branch head is updated' '
 	git checkout -b third second^ &&
 	test_when_finished "git checkout -f copy && git branch -D third" &&
-	test "$(cat file)" = file &&
+	echo file >expect &&
+	test_cmp expect file &&
 	git pull . second:third 2>err &&
 	test_i18ngrep "fetch updated the current branch head" err &&
-	test "$(cat file)" = modified &&
-	test "$(git rev-parse third)" = "$(git rev-parse second)"
+	echo modified >expect &&
+	test_cmp expect file &&
+	test_cmp_rev third second
 '
 
 test_expect_success 'fast-forward fails with conflicting work tree' '
 	git checkout -b third second^ &&
 	test_when_finished "git checkout -f copy && git branch -D third" &&
-	test "$(cat file)" = file &&
+	echo file >expect &&
+	test_cmp expect file &&
 	echo conflict >file &&
 	test_must_fail git pull . second:third 2>err &&
 	test_i18ngrep "Cannot fast-forward your working tree" err &&
-	test "$(cat file)" = conflict &&
-	test "$(git rev-parse third)" = "$(git rev-parse second)"
+	echo conflict >expect &&
+	test_cmp expect file &&
+	test_cmp_rev third second
 '
 
 test_expect_success '--rebase' '
 	git branch to-rebase &&
-	echo modified again > file &&
+	echo modified again >file &&
 	git commit -m file file &&
 	git checkout to-rebase &&
-	echo new > file2 &&
+	echo new >file2 &&
 	git add file2 &&
 	git commit -m "new file" &&
 	git tag before-rebase &&
 	git pull --rebase . copy &&
-	test "$(git rev-parse HEAD^)" = "$(git rev-parse copy)" &&
-	test new = "$(git show HEAD:file2)"
+	test_cmp_rev HEAD^ copy &&
+	echo new >expect &&
+	git show HEAD:file2 >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success '--rebase fast forward' '
@@ -263,7 +285,7 @@
 
 	git checkout to-rebase &&
 	git pull --rebase . ff &&
-	test "$(git rev-parse HEAD)" = "$(git rev-parse ff)" &&
+	test_cmp_rev HEAD ff &&
 
 	# The above only validates the result.  Did we actually bypass rebase?
 	git reflog -1 >reflog.actual &&
@@ -287,7 +309,7 @@
 	git checkout behind &&
 	echo dirty >file &&
 	git pull --rebase --autostash . to-rebase-ff &&
-	test "$(git rev-parse HEAD)" = "$(git rev-parse to-rebase-ff)"
+	test_cmp_rev HEAD to-rebase-ff
 '
 
 test_expect_success '--rebase with conflicts shows advice' '
@@ -325,9 +347,11 @@
 test_expect_success '--rebase fails with multiple branches' '
 	git reset --hard before-rebase &&
 	test_must_fail git pull --rebase . copy master 2>err &&
-	test "$(git rev-parse HEAD)" = "$(git rev-parse before-rebase)" &&
+	test_cmp_rev HEAD before-rebase &&
 	test_i18ngrep "Cannot rebase onto multiple branches" err &&
-	test modified = "$(git show HEAD:file)"
+	echo modified >expect &&
+	git show HEAD:file >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'pull --rebase succeeds with dirty working directory and rebase.autostash set' '
@@ -377,8 +401,10 @@
 	git reset --hard before-rebase &&
 	test_config pull.rebase true &&
 	git pull . copy &&
-	test "$(git rev-parse HEAD^)" = "$(git rev-parse copy)" &&
-	test new = "$(git show HEAD:file2)"
+	test_cmp_rev HEAD^ copy &&
+	echo new >expect &&
+	git show HEAD:file2 >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'pull --autostash & pull.rebase=true' '
@@ -395,8 +421,10 @@
 	git reset --hard before-rebase &&
 	test_config branch.to-rebase.rebase true &&
 	git pull . copy &&
-	test "$(git rev-parse HEAD^)" = "$(git rev-parse copy)" &&
-	test new = "$(git show HEAD:file2)"
+	test_cmp_rev HEAD^ copy &&
+	echo new >expect &&
+	git show HEAD:file2 >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'branch.to-rebase.rebase should override pull.rebase' '
@@ -404,23 +432,29 @@
 	test_config pull.rebase true &&
 	test_config branch.to-rebase.rebase false &&
 	git pull . copy &&
-	test "$(git rev-parse HEAD^)" != "$(git rev-parse copy)" &&
-	test new = "$(git show HEAD:file2)"
+	test_cmp_rev ! HEAD^ copy &&
+	echo new >expect &&
+	git show HEAD:file2 >actual &&
+	test_cmp expect actual
 '
 
-test_expect_success "pull --rebase warns on --verify-signatures" '
+test_expect_success 'pull --rebase warns on --verify-signatures' '
 	git reset --hard before-rebase &&
 	git pull --rebase --verify-signatures . copy 2>err &&
-	test "$(git rev-parse HEAD^)" = "$(git rev-parse copy)" &&
-	test new = "$(git show HEAD:file2)" &&
+	test_cmp_rev HEAD^ copy &&
+	echo new >expect &&
+	git show HEAD:file2 >actual &&
+	test_cmp expect actual &&
 	test_i18ngrep "ignoring --verify-signatures for rebase" err
 '
 
-test_expect_success "pull --rebase does not warn on --no-verify-signatures" '
+test_expect_success 'pull --rebase does not warn on --no-verify-signatures' '
 	git reset --hard before-rebase &&
 	git pull --rebase --no-verify-signatures . copy 2>err &&
-	test "$(git rev-parse HEAD^)" = "$(git rev-parse copy)" &&
-	test new = "$(git show HEAD:file2)" &&
+	test_cmp_rev HEAD^ copy &&
+	echo new >expect &&
+	git show HEAD:file2 >actual &&
+	test_cmp expect actual &&
 	test_i18ngrep ! "verify-signatures" err
 '
 
@@ -440,25 +474,31 @@
 	git reset --hard before-preserve-rebase &&
 	test_config pull.rebase false &&
 	git pull . copy &&
-	test "$(git rev-parse HEAD^1)" = "$(git rev-parse before-preserve-rebase)" &&
-	test "$(git rev-parse HEAD^2)" = "$(git rev-parse copy)" &&
-	test file3 = "$(git show HEAD:file3.t)"
+	test_cmp_rev HEAD^1 before-preserve-rebase &&
+	test_cmp_rev HEAD^2 copy &&
+	echo file3 >expect &&
+	git show HEAD:file3.t >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'pull.rebase=true flattens keep-merge' '
 	git reset --hard before-preserve-rebase &&
 	test_config pull.rebase true &&
 	git pull . copy &&
-	test "$(git rev-parse HEAD^^)" = "$(git rev-parse copy)" &&
-	test file3 = "$(git show HEAD:file3.t)"
+	test_cmp_rev HEAD^^ copy &&
+	echo file3 >expect &&
+	git show HEAD:file3.t >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'pull.rebase=1 is treated as true and flattens keep-merge' '
 	git reset --hard before-preserve-rebase &&
 	test_config pull.rebase 1 &&
 	git pull . copy &&
-	test "$(git rev-parse HEAD^^)" = "$(git rev-parse copy)" &&
-	test file3 = "$(git show HEAD:file3.t)"
+	test_cmp_rev HEAD^^ copy &&
+	echo file3 >expect &&
+	git show HEAD:file3.t >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success REBASE_P \
@@ -466,8 +506,8 @@
 	git reset --hard before-preserve-rebase &&
 	test_config pull.rebase preserve &&
 	git pull . copy &&
-	test "$(git rev-parse HEAD^^)" = "$(git rev-parse copy)" &&
-	test "$(git rev-parse HEAD^2)" = "$(git rev-parse keep-merge)"
+	test_cmp_rev HEAD^^ copy &&
+	test_cmp_rev HEAD^2 keep-merge
 '
 
 test_expect_success 'pull.rebase=interactive' '
@@ -478,7 +518,8 @@
 	test_set_editor "$TRASH_DIRECTORY/fake-editor" &&
 	test_when_finished "test_might_fail git rebase --abort" &&
 	test_must_fail git pull --rebase=interactive . copy &&
-	test "I was here" = "$(cat fake.out)"
+	echo "I was here" >expect &&
+	test_cmp expect fake.out
 '
 
 test_expect_success 'pull --rebase=i' '
@@ -489,30 +530,35 @@
 	test_set_editor "$TRASH_DIRECTORY/fake-editor" &&
 	test_when_finished "test_might_fail git rebase --abort" &&
 	test_must_fail git pull --rebase=i . copy &&
-	test "I was here, too" = "$(cat fake.out)"
+	echo "I was here, too" >expect &&
+	test_cmp expect fake.out
 '
 
 test_expect_success 'pull.rebase=invalid fails' '
 	git reset --hard before-preserve-rebase &&
 	test_config pull.rebase invalid &&
-	! git pull . copy
+	test_must_fail git pull . copy
 '
 
 test_expect_success '--rebase=false create a new merge commit' '
 	git reset --hard before-preserve-rebase &&
 	test_config pull.rebase true &&
 	git pull --rebase=false . copy &&
-	test "$(git rev-parse HEAD^1)" = "$(git rev-parse before-preserve-rebase)" &&
-	test "$(git rev-parse HEAD^2)" = "$(git rev-parse copy)" &&
-	test file3 = "$(git show HEAD:file3.t)"
+	test_cmp_rev HEAD^1 before-preserve-rebase &&
+	test_cmp_rev HEAD^2 copy &&
+	echo file3 >expect &&
+	git show HEAD:file3.t >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success '--rebase=true rebases and flattens keep-merge' '
 	git reset --hard before-preserve-rebase &&
 	test_config pull.rebase preserve &&
 	git pull --rebase=true . copy &&
-	test "$(git rev-parse HEAD^^)" = "$(git rev-parse copy)" &&
-	test file3 = "$(git show HEAD:file3.t)"
+	test_cmp_rev HEAD^^ copy &&
+	echo file3 >expect &&
+	git show HEAD:file3.t >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success REBASE_P \
@@ -520,58 +566,62 @@
 	git reset --hard before-preserve-rebase &&
 	test_config pull.rebase true &&
 	git pull --rebase=preserve . copy &&
-	test "$(git rev-parse HEAD^^)" = "$(git rev-parse copy)" &&
-	test "$(git rev-parse HEAD^2)" = "$(git rev-parse keep-merge)"
+	test_cmp_rev HEAD^^ copy &&
+	test_cmp_rev HEAD^2 keep-merge
 '
 
 test_expect_success '--rebase=invalid fails' '
 	git reset --hard before-preserve-rebase &&
-	! git pull --rebase=invalid . copy
+	test_must_fail git pull --rebase=invalid . copy
 '
 
 test_expect_success '--rebase overrides pull.rebase=preserve and flattens keep-merge' '
 	git reset --hard before-preserve-rebase &&
 	test_config pull.rebase preserve &&
 	git pull --rebase . copy &&
-	test "$(git rev-parse HEAD^^)" = "$(git rev-parse copy)" &&
-	test file3 = "$(git show HEAD:file3.t)"
+	test_cmp_rev HEAD^^ copy &&
+	echo file3 >expect &&
+	git show HEAD:file3.t >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success '--rebase with rebased upstream' '
-
 	git remote add -f me . &&
 	git checkout copy &&
 	git tag copy-orig &&
 	git reset --hard HEAD^ &&
-	echo conflicting modification > file &&
+	echo conflicting modification >file &&
 	git commit -m conflict file &&
 	git checkout to-rebase &&
-	echo file > file2 &&
+	echo file >file2 &&
 	git commit -m to-rebase file2 &&
 	git tag to-rebase-orig &&
 	git pull --rebase me copy &&
-	test "conflicting modification" = "$(cat file)" &&
-	test file = "$(cat file2)"
-
+	echo "conflicting modification" >expect &&
+	test_cmp expect file &&
+	echo file >expect &&
+	test_cmp expect file2
 '
 
 test_expect_success '--rebase -f with rebased upstream' '
 	test_when_finished "test_might_fail git rebase --abort" &&
 	git reset --hard to-rebase-orig &&
 	git pull --rebase -f me copy &&
-	test "conflicting modification" = "$(cat file)" &&
-	test file = "$(cat file2)"
+	echo "conflicting modification" >expect &&
+	test_cmp expect file &&
+	echo file >expect &&
+	test_cmp expect file2
 '
 
 test_expect_success '--rebase with rebased default upstream' '
-
 	git update-ref refs/remotes/me/copy copy-orig &&
 	git checkout --track -b to-rebase2 me/copy &&
 	git reset --hard to-rebase-orig &&
 	git pull --rebase &&
-	test "conflicting modification" = "$(cat file)" &&
-	test file = "$(cat file2)"
-
+	echo "conflicting modification" >expect &&
+	test_cmp expect file &&
+	echo file >expect &&
+	test_cmp expect file2
 '
 
 test_expect_success 'rebased upstream + fetch + pull --rebase' '
@@ -582,13 +632,14 @@
 	git reset --hard to-rebase-orig &&
 	git fetch &&
 	git pull --rebase &&
-	test "conflicting modification" = "$(cat file)" &&
-	test file = "$(cat file2)"
+	echo "conflicting modification" >expect &&
+	test_cmp expect file &&
+	echo file >expect &&
+	test_cmp expect file2
 
 '
 
 test_expect_success 'pull --rebase dies early with dirty working directory' '
-
 	git checkout to-rebase &&
 	git update-ref refs/remotes/me/copy copy^ &&
 	COPY="$(git rev-parse --verify me/copy)" &&
@@ -596,23 +647,23 @@
 	test_config branch.to-rebase.remote me &&
 	test_config branch.to-rebase.merge refs/heads/copy &&
 	test_config branch.to-rebase.rebase true &&
-	echo dirty >> file &&
+	echo dirty >>file &&
 	git add file &&
 	test_must_fail git pull &&
-	test "$COPY" = "$(git rev-parse --verify me/copy)" &&
+	test_cmp_rev "$COPY" me/copy &&
 	git checkout HEAD -- file &&
 	git pull &&
-	test "$COPY" != "$(git rev-parse --verify me/copy)"
-
+	test_cmp_rev ! "$COPY" me/copy
 '
 
 test_expect_success 'pull --rebase works on branch yet to be born' '
 	git rev-parse master >expect &&
 	mkdir empty_repo &&
-	(cd empty_repo &&
-	 git init &&
-	 git pull --rebase .. master &&
-	 git rev-parse HEAD >../actual
+	(
+		cd empty_repo &&
+		git init &&
+		git pull --rebase .. master &&
+		git rev-parse HEAD >../actual
 	) &&
 	test_cmp expect actual
 '
@@ -624,10 +675,14 @@
 		cd empty_repo2 &&
 		echo staged-file >staged-file &&
 		git add staged-file &&
-		test "$(git ls-files)" = staged-file &&
+		echo staged-file >expect &&
+		git ls-files >actual &&
+		test_cmp expect actual &&
 		test_must_fail git pull --rebase .. master 2>err &&
-		test "$(git ls-files)" = staged-file &&
-		test "$(git show :staged-file)" = staged-file &&
+		git ls-files >actual &&
+		test_cmp expect actual &&
+		git show :staged-file >actual &&
+		test_cmp expect actual &&
 		test_i18ngrep "unborn branch with changes added to the index" err
 	)
 '
@@ -638,7 +693,8 @@
 	(
 		cd corrupt &&
 		test_commit one &&
-		obj=$(git rev-parse --verify HEAD | sed "s#^..#&/#") &&
+		git rev-parse --verify HEAD >head &&
+		obj=$(sed "s#^..#&/#" head) &&
 		rm -f .git/objects/$obj &&
 		test_must_fail git pull --rebase
 	)
@@ -646,66 +702,77 @@
 
 test_expect_success 'setup for detecting upstreamed changes' '
 	mkdir src &&
-	(cd src &&
-	 git init &&
-	 printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" > stuff &&
-	 git add stuff &&
-	 git commit -m "Initial revision"
+	(
+		cd src &&
+		git init &&
+		printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" > stuff &&
+		git add stuff &&
+		git commit -m "Initial revision"
 	) &&
 	git clone src dst &&
-	(cd src &&
-	 modify s/5/43/ stuff &&
-	 git commit -a -m "5->43" &&
-	 modify s/6/42/ stuff &&
-	 git commit -a -m "Make it bigger"
+	(
+		cd src &&
+		modify s/5/43/ stuff &&
+		git commit -a -m "5->43" &&
+		modify s/6/42/ stuff &&
+		git commit -a -m "Make it bigger"
 	) &&
-	(cd dst &&
-	 modify s/5/43/ stuff &&
-	 git commit -a -m "Independent discovery of 5->43"
+	(
+		cd dst &&
+		modify s/5/43/ stuff &&
+		git commit -a -m "Independent discovery of 5->43"
 	)
 '
 
 test_expect_success 'git pull --rebase detects upstreamed changes' '
-	(cd dst &&
-	 git pull --rebase &&
-	 test -z "$(git ls-files -u)"
+	(
+		cd dst &&
+		git pull --rebase &&
+		git ls-files -u >untracked &&
+		test_must_be_empty untracked
 	)
 '
 
 test_expect_success 'setup for avoiding reapplying old patches' '
-	(cd dst &&
-	 test_might_fail git rebase --abort &&
-	 git reset --hard origin/master
+	(
+		cd dst &&
+		test_might_fail git rebase --abort &&
+		git reset --hard origin/master
 	) &&
 	git clone --bare src src-replace.git &&
 	rm -rf src &&
 	mv src-replace.git src &&
-	(cd dst &&
-	 modify s/2/22/ stuff &&
-	 git commit -a -m "Change 2" &&
-	 modify s/3/33/ stuff &&
-	 git commit -a -m "Change 3" &&
-	 modify s/4/44/ stuff &&
-	 git commit -a -m "Change 4" &&
-	 git push &&
+	(
+		cd dst &&
+		modify s/2/22/ stuff &&
+		git commit -a -m "Change 2" &&
+		modify s/3/33/ stuff &&
+		git commit -a -m "Change 3" &&
+		modify s/4/44/ stuff &&
+		git commit -a -m "Change 4" &&
+		git push &&
 
-	 modify s/44/55/ stuff &&
-	 git commit --amend -a -m "Modified Change 4"
+		modify s/44/55/ stuff &&
+		git commit --amend -a -m "Modified Change 4"
 	)
 '
 
 test_expect_success 'git pull --rebase does not reapply old patches' '
-	(cd dst &&
-	 test_must_fail git pull --rebase &&
-	 test 1 = $(find .git/rebase-apply -name "000*" | wc -l)
+	(
+		cd dst &&
+		test_must_fail git pull --rebase &&
+		find .git/rebase-apply -name "000*" >patches &&
+		test_line_count = 1 patches
 	)
 '
 
 test_expect_success 'git pull --rebase against local branch' '
 	git checkout -b copy2 to-rebase-orig &&
 	git pull --rebase . to-rebase &&
-	test "conflicting modification" = "$(cat file)" &&
-	test file = "$(cat file2)"
+	echo "conflicting modification" >expect &&
+	test_cmp expect file &&
+	echo file >expect &&
+	test_cmp expect file2
 '
 
 test_done
diff --git a/t/t5528-push-default.sh b/t/t5528-push-default.sh
index 4430956..4d1e0c3 100755
--- a/t/t5528-push-default.sh
+++ b/t/t5528-push-default.sh
@@ -163,7 +163,7 @@
 # update parent1's foo (which is our upstream)
 test_pushdefault_workflow success upstream foo
 
-# upsream is foo which is not the name of the current branch
+# upstream is foo which is not the name of the current branch
 test_pushdefault_workflow failure simple master
 
 # master and foo are updated
diff --git a/t/t5535-fetch-push-symref.sh b/t/t5535-fetch-push-symref.sh
index 8ed58d2..e8f6d23 100755
--- a/t/t5535-fetch-push-symref.sh
+++ b/t/t5535-fetch-push-symref.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='avoiding conflicting update thru symref aliasing'
+test_description='avoiding conflicting update through symref aliasing'
 
 . ./test-lib.sh
 
diff --git a/t/t5545-push-options.sh b/t/t5545-push-options.sh
index 04b34c4..38e6f73 100755
--- a/t/t5545-push-options.sh
+++ b/t/t5545-push-options.sh
@@ -115,7 +115,7 @@
 
 	git -C parent submodule add ../upstream workbench &&
 	git -C parent/workbench remote add up ../../upstream &&
-	git -C parent commit -m "add submoule" &&
+	git -C parent commit -m "add submodule" &&
 
 	test_commit -C parent/workbench two &&
 	git -C parent add workbench &&
diff --git a/t/t5580-clone-push-unc.sh b/t/t5580-clone-push-unc.sh
index b3c8a92..01b52c1 100755
--- a/t/t5580-clone-push-unc.sh
+++ b/t/t5580-clone-push-unc.sh
@@ -58,7 +58,7 @@
 
 test_expect_success MINGW 'remote nick cannot contain backslashes' '
 	BACKSLASHED="$(winpwd | tr / \\\\)" &&
-	git ls-remote "$BACKSLASHED" >out 2>err &&
+	git ls-remote "$BACKSLASHED" 2>err &&
 	test_i18ngrep ! "unable to access" err
 '
 
diff --git a/t/t5608-clone-2gb.sh b/t/t5608-clone-2gb.sh
index 2c6bc07..eee0842 100755
--- a/t/t5608-clone-2gb.sh
+++ b/t/t5608-clone-2gb.sh
@@ -3,7 +3,7 @@
 test_description='Test cloning a repository larger than 2 gigabyte'
 . ./test-lib.sh
 
-if test -z "$GIT_TEST_CLONE_2GB"
+if ! test_bool_env GIT_TEST_CLONE_2GB false
 then
 	say 'Skipping expensive 2GB clone test; enable it with GIT_TEST_CLONE_2GB=t'
 else
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index eaa33a8..fea56cd 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -304,6 +304,76 @@
 	test_i18ngrep "unable to parse sparse filter data in" err
 '
 
+setup_triangle () {
+	rm -rf big-blob.txt server client promisor-remote &&
+
+	printf "line %d\n" $(test_seq 1 100) >big-blob.txt &&
+
+	# Create a server with 2 commits: a commit with a big blob and a child
+	# commit with an incremental change. Also, create a partial clone
+	# client that only contains the first commit.
+	git init server &&
+	git -C server config --local uploadpack.allowfilter 1 &&
+	cp big-blob.txt server &&
+	git -C server add big-blob.txt &&
+	git -C server commit -m "initial" &&
+	git clone --bare --filter=tree:0 "file://$(pwd)/server" client &&
+	echo another line >>server/big-blob.txt &&
+	git -C server commit -am "append line to big blob" &&
+
+	# Create a promisor remote that only contains the blob from the first
+	# commit, and set it as the promisor remote of client. Thus, whenever
+	# the client lazy fetches, the lazy fetch will succeed only if it is
+	# for this blob.
+	git init promisor-remote &&
+	test_commit -C promisor-remote one && # so that ref advertisement is not empty
+	git -C promisor-remote config --local uploadpack.allowanysha1inwant 1 &&
+	git -C promisor-remote hash-object -w --stdin <big-blob.txt &&
+	git -C client remote set-url origin "file://$(pwd)/promisor-remote"
+}
+
+# NEEDSWORK: The tests beginning with "fetch lazy-fetches" below only
+# test that "fetch" avoid fetching trees and blobs, but not commits or
+# tags. Revisit this if Git is ever taught to support partial clones
+# with commits and/or tags filtered out.
+
+test_expect_success 'fetch lazy-fetches only to resolve deltas' '
+	setup_triangle &&
+
+	# Exercise to make sure it works. Git will not fetch anything from the
+	# promisor remote other than for the big blob (because it needs to
+	# resolve the delta).
+	GIT_TRACE_PACKET="$(pwd)/trace" git -C client \
+		fetch "file://$(pwd)/server" master &&
+
+	# Verify the assumption that the client needed to fetch the delta base
+	# to resolve the delta.
+	git hash-object big-blob.txt >hash &&
+	grep "want $(cat hash)" trace
+'
+
+test_expect_success 'fetch lazy-fetches only to resolve deltas, protocol v2' '
+	setup_triangle &&
+
+	git -C server config --local protocol.version 2 &&
+	git -C client config --local protocol.version 2 &&
+	git -C promisor-remote config --local protocol.version 2 &&
+
+	# Exercise to make sure it works. Git will not fetch anything from the
+	# promisor remote other than for the big blob (because it needs to
+	# resolve the delta).
+	GIT_TRACE_PACKET="$(pwd)/trace" git -C client \
+		fetch "file://$(pwd)/server" master &&
+
+	# Verify that protocol version 2 was used.
+	grep "fetch< version 2" trace &&
+
+	# Verify the assumption that the client needed to fetch the delta base
+	# to resolve the delta.
+	git hash-object big-blob.txt >hash &&
+	grep "want $(cat hash)" trace
+'
+
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
 
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index ae9175c..e73067d 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -32,7 +32,7 @@
 	test_cmp expect actual
 '
 
-test_expect_success 'ref advertisment is filtered with ls-remote using protocol v2' '
+test_expect_success 'ref advertisement is filtered with ls-remote using protocol v2' '
 	test_when_finished "rm -f log" &&
 
 	GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \
@@ -154,7 +154,7 @@
 	test_cmp expect actual
 '
 
-test_expect_success 'ref advertisment is filtered with ls-remote using protocol v2' '
+test_expect_success 'ref advertisement is filtered with ls-remote using protocol v2' '
 	test_when_finished "rm -f log" &&
 
 	GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \
@@ -225,7 +225,7 @@
 	grep "fetch< version 2" log
 '
 
-test_expect_success 'ref advertisment is filtered during fetch using protocol v2' '
+test_expect_success 'ref advertisement is filtered during fetch using protocol v2' '
 	test_when_finished "rm -f log" &&
 
 	test_commit -C file_parent three &&
@@ -682,9 +682,9 @@
 	git -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" log -1 --format=%s client_branch >expect &&
 	test_cmp expect actual &&
 
-	# Client didnt request to use protocol v2
+	# Client did not request to use protocol v2
 	! grep "Git-Protocol: version=2" log &&
-	# Server didnt respond using protocol v2
+	# Server did not respond using protocol v2
 	! grep "git< version 2" log
 '
 
diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index 3a2c143..1424fab 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -18,14 +18,16 @@
 		p
 		}' <out | test-tool pkt-line unpack-sideband >o.pack &&
 	git index-pack o.pack &&
-	git verify-pack -v o.idx | grep commit | cut -c-40 | sort >actual_commits
+	git verify-pack -v o.idx >objs &&
+	grep commit objs | cut -c-40 | sort >actual_commits
 }
 
 check_output () {
 	get_actual_refs &&
 	test_cmp expected_refs actual_refs &&
 	get_actual_commits &&
-	test_cmp expected_commits actual_commits
+	sort expected_commits >sorted_commits &&
+	test_cmp sorted_commits actual_commits
 }
 
 # c(o/foo) d(o/bar)
@@ -75,17 +77,19 @@
 '
 
 test_expect_success 'basic want-ref' '
+	oid=$(git rev-parse f) &&
 	cat >expected_refs <<-EOF &&
-	$(git rev-parse f) refs/heads/master
+	$oid refs/heads/master
 	EOF
-	git rev-parse f | sort >expected_commits &&
+	git rev-parse f >expected_commits &&
 
+	oid=$(git rev-parse a) &&
 	test-tool pkt-line pack >in <<-EOF &&
 	command=fetch
 	0001
 	no-progress
 	want-ref refs/heads/master
-	have $(git rev-parse a)
+	have $oid
 	done
 	0000
 	EOF
@@ -95,19 +99,22 @@
 '
 
 test_expect_success 'multiple want-ref lines' '
+	oid_c=$(git rev-parse c) &&
+	oid_d=$(git rev-parse d) &&
 	cat >expected_refs <<-EOF &&
-	$(git rev-parse c) refs/heads/o/foo
-	$(git rev-parse d) refs/heads/o/bar
+	$oid_c refs/heads/o/foo
+	$oid_d refs/heads/o/bar
 	EOF
-	git rev-parse c d | sort >expected_commits &&
+	git rev-parse c d >expected_commits &&
 
+	oid=$(git rev-parse b) &&
 	test-tool pkt-line pack >in <<-EOF &&
 	command=fetch
 	0001
 	no-progress
 	want-ref refs/heads/o/foo
 	want-ref refs/heads/o/bar
-	have $(git rev-parse b)
+	have $oid
 	done
 	0000
 	EOF
@@ -117,10 +124,11 @@
 '
 
 test_expect_success 'mix want and want-ref' '
+	oid=$(git rev-parse f) &&
 	cat >expected_refs <<-EOF &&
-	$(git rev-parse f) refs/heads/master
+	$oid refs/heads/master
 	EOF
-	git rev-parse e f | sort >expected_commits &&
+	git rev-parse e f >expected_commits &&
 
 	test-tool pkt-line pack >in <<-EOF &&
 	command=fetch
@@ -138,17 +146,19 @@
 '
 
 test_expect_success 'want-ref with ref we already have commit for' '
+	oid=$(git rev-parse c) &&
 	cat >expected_refs <<-EOF &&
-	$(git rev-parse c) refs/heads/o/foo
+	$oid refs/heads/o/foo
 	EOF
 	>expected_commits &&
 
+	oid=$(git rev-parse c) &&
 	test-tool pkt-line pack >in <<-EOF &&
 	command=fetch
 	0001
 	no-progress
 	want-ref refs/heads/o/foo
-	have $(git rev-parse c)
+	have $oid
 	done
 	0000
 	EOF
@@ -211,13 +221,14 @@
 
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
+	oid=$(git -C "$REPO" rev-parse d) &&
 	GIT_TRACE_PACKET="$(pwd)/log" git -C local fetch origin \
-		$(git -C "$REPO" rev-parse d):refs/heads/actual &&
+		"$oid":refs/heads/actual &&
 
 	git -C "$REPO" rev-parse "d" >expected &&
 	git -C local rev-parse refs/heads/actual >actual &&
 	test_cmp expected actual &&
-	grep "want $(git -C "$REPO" rev-parse d)" log
+	grep "want $oid" log
 '
 
 test_expect_success 'fetching multiple refs' '
@@ -239,13 +250,14 @@
 
 	rm -rf local &&
 	cp -r "$LOCAL_PRISTINE" local &&
+	oid=$(git -C "$REPO" rev-parse b) &&
 	GIT_TRACE_PACKET="$(pwd)/log" git -C local fetch origin \
-		master $(git -C "$REPO" rev-parse b):refs/heads/actual &&
+		master "$oid":refs/heads/actual &&
 
 	git -C "$REPO" rev-parse "master" "b" >expected &&
 	git -C local rev-parse refs/remotes/origin/master refs/heads/actual >actual &&
 	test_cmp expected actual &&
-	grep "want $(git -C "$REPO" rev-parse b)" log &&
+	grep "want $oid" log &&
 	grep "want-ref refs/heads/master" log
 '
 
@@ -312,10 +324,9 @@
 	# repository appears to change during negotiation, for example, when
 	# different servers in a load-balancing arrangement serve (stateless)
 	# RPCs during a single negotiation.
-	printf "s/%s/%s/" \
-	       $(git -C "$REPO" rev-parse $1 | tr -d "\n") \
-	       $(git -C "$REPO" rev-parse $2 | tr -d "\n") \
-	       >"$HTTPD_ROOT_PATH/one-time-sed"
+	oid1=$(git -C "$REPO" rev-parse $1) &&
+	oid2=$(git -C "$REPO" rev-parse $2) &&
+	echo "s/$oid1/$oid2/" >"$HTTPD_ROOT_PATH/one-time-sed"
 }
 
 test_expect_success 'server is initially ahead - no ref in want' '
diff --git a/t/t6016-rev-list-graph-simplify-history.sh b/t/t6016-rev-list-graph-simplify-history.sh
index f7181d1..f5e6e92 100755
--- a/t/t6016-rev-list-graph-simplify-history.sh
+++ b/t/t6016-rev-list-graph-simplify-history.sh
@@ -67,11 +67,10 @@
 	echo "| * $C4" >> expected &&
 	echo "| * $C3" >> expected &&
 	echo "* | $A5" >> expected &&
-	echo "| |     " >> expected &&
-	echo "|  \\    " >> expected &&
-	echo "*-. \\   $A4" >> expected &&
-	echo "|\\ \\ \\  " >> expected &&
-	echo "| | |/  " >> expected &&
+	echo "| |   " >> expected &&
+	echo "|  \\  " >> expected &&
+	echo "*-. | $A4" >> expected &&
+	echo "|\\ \\| " >> expected &&
 	echo "| | * $C2" >> expected &&
 	echo "| | * $C1" >> expected &&
 	echo "| * | $B2" >> expected &&
@@ -97,11 +96,10 @@
 	echo "| * $C4" >> expected &&
 	echo "| * $C3" >> expected &&
 	echo "* | $A5" >> expected &&
-	echo "| |     " >> expected &&
-	echo "|  \\    " >> expected &&
-	echo "*-. \\   $A4" >> expected &&
-	echo "|\\ \\ \\  " >> expected &&
-	echo "| | |/  " >> expected &&
+	echo "| |   " >> expected &&
+	echo "|  \\  " >> expected &&
+	echo "*-. | $A4" >> expected &&
+	echo "|\\ \\| " >> expected &&
 	echo "| | * $C2" >> expected &&
 	echo "| | * $C1" >> expected &&
 	echo "| * | $B2" >> expected &&
@@ -131,9 +129,8 @@
 	echo "| * $C4" >> expected &&
 	echo "| * $C3" >> expected &&
 	echo "* | $A5" >> expected &&
-	echo "* |   $A4" >> expected &&
-	echo "|\\ \\  " >> expected &&
-	echo "| |/  " >> expected &&
+	echo "* | $A4" >> expected &&
+	echo "|\\| " >> expected &&
 	echo "| * $C2" >> expected &&
 	echo "| * $C1" >> expected &&
 	echo "* | $A3" >> expected &&
@@ -151,9 +148,8 @@
 	echo "|\\  " >> expected &&
 	echo "| * $C4" >> expected &&
 	echo "* | $A5" >> expected &&
-	echo "* |   $A4" >> expected &&
-	echo "|\\ \\  " >> expected &&
-	echo "| |/  " >> expected &&
+	echo "* | $A4" >> expected &&
+	echo "|\\| " >> expected &&
 	echo "* | $A3" >> expected &&
 	echo "|/  " >> expected &&
 	echo "* $A2" >> expected &&
@@ -255,7 +251,7 @@
 	echo "* | | | $A3" >> expected &&
 	echo "o | | | $A2" >> expected &&
 	echo "|/ / /  " >> expected &&
-	echo "o | | $A1" >> expected &&
+	echo "o / / $A1" >> expected &&
 	echo " / /  " >> expected &&
 	echo "| o $C3" >> expected &&
 	echo "|/  " >> expected &&
diff --git a/t/t6019-rev-list-ancestry-path.sh b/t/t6019-rev-list-ancestry-path.sh
index beadaf6..353f843 100755
--- a/t/t6019-rev-list-ancestry-path.sh
+++ b/t/t6019-rev-list-ancestry-path.sh
@@ -143,14 +143,14 @@
 test_expect_success 'criss-cross: rev-list --ancestry-path cb..bc' '
 	(cd criss-cross &&
 	 git rev-list --ancestry-path xcb..xbc > actual &&
-	 test -z "$(cat actual)")
+	 test_must_be_empty actual)
 '
 
 # no commits in repository descend from cb
 test_expect_success 'criss-cross: rev-list --ancestry-path --all ^cb' '
 	(cd criss-cross &&
 	 git rev-list --ancestry-path --all ^xcb > actual &&
-	 test -z "$(cat actual)")
+	 test_must_be_empty actual)
 '
 
 test_done
diff --git a/t/t6021-merge-criss-cross.sh b/t/t6021-merge-criss-cross.sh
index 213deec..d254e02 100755
--- a/t/t6021-merge-criss-cross.sh
+++ b/t/t6021-merge-criss-cross.sh
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Fredrik Kuivinen
 #
 
-# See http://marc.info/?l=git&m=111463358500362&w=2 for a
+# See https://lore.kernel.org/git/Pine.LNX.4.44.0504271254120.4678-100000@wax.eds.org/ for a
 # nice description of what this is about.
 
 
diff --git a/t/t6024-recursive-merge.sh b/t/t6024-recursive-merge.sh
index 27c7de9..0c9e3c2 100755
--- a/t/t6024-recursive-merge.sh
+++ b/t/t6024-recursive-merge.sh
@@ -14,85 +14,90 @@
 GIT_COMMITTER_DATE="2006-12-12 23:28:00 +0100"
 export GIT_COMMITTER_DATE
 
-test_expect_success "setup tests" '
-echo 1 > a1 &&
-git add a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:00" git commit -m 1 a1 &&
+test_expect_success 'setup tests' '
+	echo 1 >a1 &&
+	git add a1 &&
+	GIT_AUTHOR_DATE="2006-12-12 23:00:00" git commit -m 1 a1 &&
 
-git checkout -b A master &&
-echo A > a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:01" git commit -m A a1 &&
+	git checkout -b A master &&
+	echo A >a1 &&
+	GIT_AUTHOR_DATE="2006-12-12 23:00:01" git commit -m A a1 &&
 
-git checkout -b B master &&
-echo B > a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:02" git commit -m B a1 &&
+	git checkout -b B master &&
+	echo B >a1 &&
+	GIT_AUTHOR_DATE="2006-12-12 23:00:02" git commit -m B a1 &&
 
-git checkout -b D A &&
-git rev-parse B > .git/MERGE_HEAD &&
-echo D > a1 &&
-git update-index a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:03" git commit -m D &&
+	git checkout -b D A &&
+	git rev-parse B >.git/MERGE_HEAD &&
+	echo D >a1 &&
+	git update-index a1 &&
+	GIT_AUTHOR_DATE="2006-12-12 23:00:03" git commit -m D &&
 
-git symbolic-ref HEAD refs/heads/other &&
-echo 2 > a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:04" git commit -m 2 a1 &&
+	git symbolic-ref HEAD refs/heads/other &&
+	echo 2 >a1 &&
+	GIT_AUTHOR_DATE="2006-12-12 23:00:04" git commit -m 2 a1 &&
 
-git checkout -b C &&
-echo C > a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:05" git commit -m C a1 &&
+	git checkout -b C &&
+	echo C >a1 &&
+	GIT_AUTHOR_DATE="2006-12-12 23:00:05" git commit -m C a1 &&
 
-git checkout -b E C &&
-git rev-parse B > .git/MERGE_HEAD &&
-echo E > a1 &&
-git update-index a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:06" git commit -m E &&
+	git checkout -b E C &&
+	git rev-parse B >.git/MERGE_HEAD &&
+	echo E >a1 &&
+	git update-index a1 &&
+	GIT_AUTHOR_DATE="2006-12-12 23:00:06" git commit -m E &&
 
-git checkout -b G E &&
-git rev-parse A > .git/MERGE_HEAD &&
-echo G > a1 &&
-git update-index a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:07" git commit -m G &&
+	git checkout -b G E &&
+	git rev-parse A >.git/MERGE_HEAD &&
+	echo G >a1 &&
+	git update-index a1 &&
+	GIT_AUTHOR_DATE="2006-12-12 23:00:07" git commit -m G &&
 
-git checkout -b F D &&
-git rev-parse C > .git/MERGE_HEAD &&
-echo F > a1 &&
-git update-index a1 &&
-GIT_AUTHOR_DATE="2006-12-12 23:00:08" git commit -m F
+	git checkout -b F D &&
+	git rev-parse C >.git/MERGE_HEAD &&
+	echo F >a1 &&
+	git update-index a1 &&
+	GIT_AUTHOR_DATE="2006-12-12 23:00:08" git commit -m F
 '
 
 test_expect_success 'combined merge conflicts' '
 	test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git merge -m final G
 '
 
-cat > expect << EOF
-<<<<<<< HEAD
-F
-=======
-G
->>>>>>> G
-EOF
+test_expect_success 'result contains a conflict' '
+	cat >expect <<-\EOF &&
+	<<<<<<< HEAD
+	F
+	=======
+	G
+	>>>>>>> G
+	EOF
 
-test_expect_success "result contains a conflict" "test_cmp expect a1"
+	test_cmp expect a1
+'
 
-git ls-files --stage > out
-cat > expect << EOF
-100644 ec3fe2a791706733f2d8fa7ad45d9a9672031f5e 1	a1
-100644 cf84443e49e1b366fac938711ddf4be2d4d1d9e9 2	a1
-100644 fd7923529855d0b274795ae3349c5e0438333979 3	a1
-EOF
+test_expect_success 'virtual trees were processed' '
+	git ls-files --stage >out &&
 
-test_expect_success "virtual trees were processed" "test_cmp expect out"
+	cat >expect <<-\EOF &&
+	100644 ec3fe2a791706733f2d8fa7ad45d9a9672031f5e 1	a1
+	100644 cf84443e49e1b366fac938711ddf4be2d4d1d9e9 2	a1
+	100644 fd7923529855d0b274795ae3349c5e0438333979 3	a1
+	EOF
+
+	test_cmp expect out
+'
 
 test_expect_success 'refuse to merge binary files' '
 	git reset --hard &&
-	printf "\0" > binary-file &&
+	printf "\0" >binary-file &&
 	git add binary-file &&
 	git commit -m binary &&
 	git checkout G &&
-	printf "\0\0" > binary-file &&
+	printf "\0\0" >binary-file &&
 	git add binary-file &&
 	git commit -m binary2 &&
-	test_must_fail git merge F > merge.out 2> merge.err &&
+	test_must_fail git merge F >merge.out 2>merge.err &&
 	grep "Cannot merge binary files: binary-file (HEAD vs. F)" merge.err
 '
 
@@ -116,7 +121,6 @@
 	test 1 = $(git ls-files --unmerged | wc -l) &&
 	test_must_fail git rev-parse --verify :2:a2 &&
 	git rev-parse --verify :3:a2
-
 '
 
 test_done
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index bdc42e9..821a0c8 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -482,7 +482,7 @@
 	git bisect good > my_bisect_log2.txt &&
 	test -f ".git/BISECT_ANCESTORS_OK" &&
 	test "$HASH6" = $(git rev-parse --verify HEAD) &&
-	git bisect bad > my_bisect_log3.txt &&
+	git bisect bad &&
 	git bisect good "$A_HASH" > my_bisect_log4.txt &&
 	test_i18ngrep "merge base must be tested" my_bisect_log4.txt &&
 	test_must_fail test -f ".git/BISECT_ANCESTORS_OK"
diff --git a/t/t6036-recursive-corner-cases.sh b/t/t6036-recursive-corner-cases.sh
index 7fddcc8..7d73afd 100755
--- a/t/t6036-recursive-corner-cases.sh
+++ b/t/t6036-recursive-corner-cases.sh
@@ -1532,7 +1532,7 @@
 		mv -f b_R1 b &&
 		mv -f a_R1 a &&
 		git add b a &&
-		test_tick && git commit -m "verson R1 of files" &&
+		test_tick && git commit -m "version R1 of files" &&
 		git tag R1 &&
 
 		# Create first merge on left side
@@ -1696,7 +1696,7 @@
 		git checkout R &&
 		echo right >>content &&
 		git add content &&
-		test_tick && git commit -m "verson R1 of content" &&
+		test_tick && git commit -m "version R1 of content" &&
 		git tag R1 &&
 
 		# Create L2
diff --git a/t/t6043-merge-rename-directories.sh b/t/t6043-merge-rename-directories.sh
index bd2f97b..83792c5 100755
--- a/t/t6043-merge-rename-directories.sh
+++ b/t/t6043-merge-rename-directories.sh
@@ -754,7 +754,7 @@
 #
 # What if we were to attempt to do directory rename detection when someone
 # "mostly" moved a directory but still left some files around, or,
-# equivalently, fully renamed a directory in one commmit and then recreated
+# equivalently, fully renamed a directory in one commit and then recreated
 # that directory in a later commit adding some new files and then tried to
 # merge?
 #
@@ -953,7 +953,7 @@
 #   Commit B: z/{b,c,d_1,e}, y/d_3
 #   Expected: y/{b,c,e}, CONFLICT(add/add: y/d_2 vs. y/d_3)
 #   NOTE: If z/d_1 in commit B were to be involved in dir rename detection, as
-#         we normaly would since z/ is being renamed to y/, then this would be
+#         we normally would since z/ is being renamed to y/, then this would be
 #         a rename/delete (z/d_1 -> y/d_1 vs. deleted) AND an add/add/add
 #         conflict of y/d_1 vs. y/d_2 vs. y/d_3.  Add/add/add is not
 #         representable in the index, so the existence of y/d_3 needs to
@@ -2116,7 +2116,7 @@
 #
 #   Note: It could easily be argued that the correct resolution here is
 #         y/{b,c,e}, CONFLICT(rename/delete: z/d -> y/d vs deleted)
-#         and that the modifed version of d should be present in y/ after
+#         and that the modified version of d should be present in y/ after
 #         the merge, just marked as conflicted.  Indeed, I previously did
 #         argue that.  But applying directory renames to the side of
 #         history where a file is merely modified results in spurious
diff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh
index 28611c9..52cde09 100755
--- a/t/t6102-rev-list-unexpected-objects.sh
+++ b/t/t6102-rev-list-unexpected-objects.sh
@@ -52,7 +52,7 @@
 '
 
 test_expect_success 'traverse unexpected non-commit parent (seen)' '
-	test_must_fail git rev-list --objects $commit $broken_commit \
+	test_must_fail git rev-list --objects $blob $broken_commit \
 		>output 2>&1 &&
 	test_i18ngrep "not a commit" output
 '
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 45047d0..09c50f3 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -1,28 +1,27 @@
 #!/bin/sh
 
-test_description='test describe
+test_description='test describe'
 
-                       B
-        .--------------o----o----o----x
-       /                   /    /
- o----o----o----o----o----.    /
-       \        A    c        /
-        .------------o---o---o
-                   D,R   e
-'
+#  o---o-----o----o----o-------o----x
+#       \   D,R   e           /
+#        \---o-------------o-'
+#         \  B            /
+#          `-o----o----o-'
+#                 A    c
+#
+# First parent of a merge commit is on the same line, second parent below.
+
 . ./test-lib.sh
 
 check_describe () {
 	expect="$1"
 	shift
-	R=$(git describe "$@" 2>err.actual)
-	S=$?
-	cat err.actual >&3
-	test_expect_success "describe $*" '
-	test $S = 0 &&
+	describe_opts="$@"
+	test_expect_success "describe $describe_opts" '
+	R=$(git describe $describe_opts 2>err.actual) &&
 	case "$R" in
 	$expect)	echo happy ;;
-	*)	echo "Oops - $R is not $expect";
+	*)	echo "Oops - $R is not $expect" &&
 		false ;;
 	esac
 	'
@@ -382,7 +381,7 @@
 	test_i18ngrep "fatal: test-blob-1 is neither a commit nor blob" actual
 '
 
-test_expect_failure ULIMIT_STACK_SIZE 'name-rev works in a deep repo' '
+test_expect_success ULIMIT_STACK_SIZE 'name-rev works in a deep repo' '
 	i=1 &&
 	while test $i -lt 8000
 	do
@@ -439,4 +438,45 @@
 	test_cmp expect actual
 '
 
+# A--------------master
+#  \            /
+#   \----------M2
+#    \        /
+#     \---M1-C
+#      \ /
+#       B
+test_expect_success 'name-rev covers all conditions while looking at parents' '
+	git init repo &&
+	(
+		cd repo &&
+
+		echo A >file &&
+		git add file &&
+		git commit -m A &&
+		A=$(git rev-parse HEAD) &&
+
+		git checkout --detach &&
+		echo B >file &&
+		git commit -m B file &&
+		B=$(git rev-parse HEAD) &&
+
+		git checkout $A &&
+		git merge --no-ff $B &&  # M1
+
+		echo C >file &&
+		git commit -m C file &&
+
+		git checkout $A &&
+		git merge --no-ff HEAD@{1} && # M2
+
+		git checkout master &&
+		git merge --no-ff HEAD@{1} &&
+
+		echo "$B master^2^2~1^2" >expect &&
+		git name-rev $B >actual &&
+
+		test_cmp expect actual
+	)
+'
+
 test_done
diff --git a/t/t6130-pathspec-noglob.sh b/t/t6130-pathspec-noglob.sh
index 3776023..ba7902c 100755
--- a/t/t6130-pathspec-noglob.sh
+++ b/t/t6130-pathspec-noglob.sh
@@ -10,6 +10,7 @@
 	# the name "f*" in the worktree, because it is not allowed
 	# on Windows (the tests below do not depend on the presence
 	# of the file in the worktree)
+	git config core.protectNTFS false &&
 	git update-index --add --cacheinfo 100644 "$(git rev-parse HEAD:foo)" "f*" &&
 	test_tick &&
 	git commit -m star &&
diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh
index c0f04dc..0a69a67 100755
--- a/t/t6500-gc.sh
+++ b/t/t6500-gc.sh
@@ -103,14 +103,14 @@
 '
 
 test_expect_success 'gc --no-quiet' '
-	git -c gc.writeCommitGraph=true gc --no-quiet >stdout 2>stderr &&
+	GIT_PROGRESS_DELAY=0 git -c gc.writeCommitGraph=true gc --no-quiet >stdout 2>stderr &&
 	test_must_be_empty stdout &&
-	test_line_count = 1 stderr &&
 	test_i18ngrep "Computing commit graph generation numbers" stderr
 '
 
 test_expect_success TTY 'with TTY: gc --no-quiet' '
-	test_terminal git -c gc.writeCommitGraph=true gc --no-quiet >stdout 2>stderr &&
+	test_terminal env GIT_PROGRESS_DELAY=0 \
+		git -c gc.writeCommitGraph=true gc --no-quiet >stdout 2>stderr &&
 	test_must_be_empty stdout &&
 	test_i18ngrep "Enumerating objects" stderr &&
 	test_i18ngrep "Computing commit graph generation numbers" stderr
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 80eb13d..6db92bd 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -227,10 +227,10 @@
 test_expect_success \
 	'trying to delete two tags, existing and not, should fail in the 2nd' '
 	tag_exists mytag &&
-	! tag_exists myhead &&
-	test_must_fail git tag -d mytag anothertag &&
+	! tag_exists nonexistingtag &&
+	test_must_fail git tag -d mytag nonexistingtag &&
 	! tag_exists mytag &&
-	! tag_exists myhead
+	! tag_exists nonexistingtag
 '
 
 test_expect_success 'trying to delete an already deleted tag should fail' \
@@ -517,7 +517,6 @@
 test_expect_success \
 	'trying to create tags giving both -m or -F options should fail' '
 	echo "message file 1" >msgfile1 &&
-	echo "message file 2" >msgfile2 &&
 	! tag_exists msgtag &&
 	test_must_fail git tag -m "message 1" -F msgfile1 msgtag &&
 	! tag_exists msgtag &&
@@ -1420,7 +1419,7 @@
 get_tag_header reuse $commit commit $time >expect
 echo "An annotation to be reused" >> expect
 test_expect_success \
-	'overwriting an annoted tag should use its previous body' '
+	'overwriting an annotated tag should use its previous body' '
 	git tag -a -m "An annotation to be reused" reuse &&
 	GIT_EDITOR=true git tag -f -a reuse &&
 	get_tag_msg reuse >actual &&
diff --git a/t/t7030-verify-tag.sh b/t/t7030-verify-tag.sh
index 041e319..8f077be 100755
--- a/t/t7030-verify-tag.sh
+++ b/t/t7030-verify-tag.sh
@@ -44,8 +44,8 @@
 test_expect_success GPGSM 'create signed tags x509 ' '
 	test_config gpg.format x509 &&
 	test_config user.signingkey $GIT_COMMITTER_EMAIL &&
-	echo 9 >file && test_tick && git commit -a -m "nineth gpgsm-signed" &&
-	git tag -s -m nineth nineth-signed-x509
+	echo 9 >file && test_tick && git commit -a -m "ninth gpgsm-signed" &&
+	git tag -s -m ninth ninth-signed-x509
 '
 
 test_expect_success GPG 'verify and show signatures' '
@@ -80,10 +80,10 @@
 '
 
 test_expect_success GPGSM 'verify and show signatures x509' '
-	git verify-tag nineth-signed-x509 2>actual &&
+	git verify-tag ninth-signed-x509 2>actual &&
 	grep "Good signature from" actual &&
 	! grep "BAD signature from" actual &&
-	echo nineth-signed-x509 OK
+	echo ninth-signed-x509 OK
 '
 
 test_expect_success GPG 'detect fudged signature' '
@@ -127,10 +127,10 @@
 '
 
 test_expect_success GPGSM 'verify signatures with --raw x509' '
-	git verify-tag --raw nineth-signed-x509 2>actual &&
+	git verify-tag --raw ninth-signed-x509 2>actual &&
 	grep "GOODSIG" actual &&
 	! grep "BADSIG" actual &&
-	echo nineth-signed-x509 OK
+	echo ninth-signed-x509 OK
 '
 
 test_expect_success GPG 'verify multiple tags' '
@@ -147,7 +147,7 @@
 '
 
 test_expect_success GPGSM 'verify multiple tags x509' '
-	tags="seventh-signed nineth-signed-x509" &&
+	tags="seventh-signed ninth-signed-x509" &&
 	for i in $tags
 	do
 		git verify-tag -v --raw $i || return 1
diff --git a/t/t7061-wtstatus-ignore.sh b/t/t7061-wtstatus-ignore.sh
index 0c394cf..e4cf548 100755
--- a/t/t7061-wtstatus-ignore.sh
+++ b/t/t7061-wtstatus-ignore.sh
@@ -43,11 +43,16 @@
 	test_cmp expected actual
 '
 cat >expected <<\EOF
-?? untracked/uncommitted
+?? untracked/
 !! untracked/ignored
 EOF
 
-test_expect_success 'status prefixed untracked directory with --ignored' '
+test_expect_success 'status of untracked directory with --ignored works with or without prefix' '
+	git status --porcelain --ignored >tmp &&
+	grep untracked/ tmp >actual &&
+	rm tmp &&
+	test_cmp expected actual &&
+
 	git status --porcelain --ignored untracked/ >actual &&
 	test_cmp expected actual
 '
diff --git a/t/t7105-reset-patch.sh b/t/t7105-reset-patch.sh
index bd10a96..fc2a6cf 100755
--- a/t/t7105-reset-patch.sh
+++ b/t/t7105-reset-patch.sh
@@ -38,6 +38,27 @@
 	test_i18ngrep "Apply" output
 '
 
+test_expect_success PERL 'git reset -p HEAD^^{tree}' '
+	test_write_lines n y | git reset -p HEAD^^{tree} >output &&
+	verify_state dir/foo work parent &&
+	verify_saved_state bar &&
+	test_i18ngrep "Apply" output
+'
+
+test_expect_success PERL 'git reset -p HEAD^:dir/foo (blob fails)' '
+	set_and_save_state dir/foo work work &&
+	test_must_fail git reset -p HEAD^:dir/foo &&
+	verify_saved_state dir/foo &&
+	verify_saved_state bar
+'
+
+test_expect_success PERL 'git reset -p aaaaaaaa (unknown fails)' '
+	set_and_save_state dir/foo work work &&
+	test_must_fail git reset -p aaaaaaaa &&
+	verify_saved_state dir/foo &&
+	verify_saved_state bar
+'
+
 # The idea in the rest is that bar sorts first, so we always say 'y'
 # first and if the path limiter fails it'll apply to bar instead of
 # dir/foo.  There's always an extra 'n' to reject edits to dir/foo in
diff --git a/t/t7107-reset-pathspec-file.sh b/t/t7107-reset-pathspec-file.sh
new file mode 100755
index 0000000..6b1a731
--- /dev/null
+++ b/t/t7107-reset-pathspec-file.sh
@@ -0,0 +1,155 @@
+#!/bin/sh
+
+test_description='reset --pathspec-from-file'
+
+. ./test-lib.sh
+
+test_tick
+
+test_expect_success setup '
+	echo A >fileA.t &&
+	echo B >fileB.t &&
+	echo C >fileC.t &&
+	echo D >fileD.t &&
+	git add . &&
+	git commit --include . -m "Commit" &&
+	git tag checkpoint
+'
+
+restore_checkpoint () {
+	git reset --hard checkpoint
+}
+
+verify_expect () {
+	git status --porcelain -- fileA.t fileB.t fileC.t fileD.t >actual &&
+	test_cmp expect actual
+}
+
+test_expect_success '--pathspec-from-file from stdin' '
+	restore_checkpoint &&
+
+	git rm fileA.t &&
+	echo fileA.t | git reset --pathspec-from-file=- &&
+
+	cat >expect <<-\EOF &&
+	 D fileA.t
+	EOF
+	verify_expect
+'
+
+test_expect_success '--pathspec-from-file from file' '
+	restore_checkpoint &&
+
+	git rm fileA.t &&
+	echo fileA.t >list &&
+	git reset --pathspec-from-file=list &&
+
+	cat >expect <<-\EOF &&
+	 D fileA.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'NUL delimiters' '
+	restore_checkpoint &&
+
+	git rm fileA.t fileB.t &&
+	printf "fileA.t\0fileB.t\0" | git reset --pathspec-from-file=- --pathspec-file-nul &&
+
+	cat >expect <<-\EOF &&
+	 D fileA.t
+	 D fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'LF delimiters' '
+	restore_checkpoint &&
+
+	git rm fileA.t fileB.t &&
+	printf "fileA.t\nfileB.t\n" | git reset --pathspec-from-file=- &&
+
+	cat >expect <<-\EOF &&
+	 D fileA.t
+	 D fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'no trailing delimiter' '
+	restore_checkpoint &&
+
+	git rm fileA.t fileB.t &&
+	printf "fileA.t\nfileB.t" | git reset --pathspec-from-file=- &&
+
+	cat >expect <<-\EOF &&
+	 D fileA.t
+	 D fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'CRLF delimiters' '
+	restore_checkpoint &&
+
+	git rm fileA.t fileB.t &&
+	printf "fileA.t\r\nfileB.t\r\n" | git reset --pathspec-from-file=- &&
+
+	cat >expect <<-\EOF &&
+	 D fileA.t
+	 D fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'quotes' '
+	restore_checkpoint &&
+
+	git rm fileA.t &&
+	printf "\"file\\101.t\"" | git reset --pathspec-from-file=- &&
+
+	cat >expect <<-\EOF &&
+	 D fileA.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'quotes not compatible with --pathspec-file-nul' '
+	restore_checkpoint &&
+
+	git rm fileA.t &&
+	printf "\"file\\101.t\"" >list &&
+	# Note: "git reset" has not yet learned to fail on wrong pathspecs
+	git reset --pathspec-from-file=list --pathspec-file-nul &&
+
+	cat >expect <<-\EOF &&
+	 D fileA.t
+	EOF
+	test_must_fail verify_expect
+'
+
+test_expect_success '--pathspec-from-file is not compatible with --soft or --hard' '
+	restore_checkpoint &&
+
+	git rm fileA.t &&
+	echo fileA.t >list &&
+	test_must_fail git reset --soft --pathspec-from-file=list &&
+	test_must_fail git reset --hard --pathspec-from-file=list
+'
+
+test_expect_success 'only touches what was listed' '
+	restore_checkpoint &&
+
+	git rm fileA.t fileB.t fileC.t fileD.t &&
+	printf "fileB.t\nfileC.t\n" | git reset --pathspec-from-file=- &&
+
+	cat >expect <<-\EOF &&
+	D  fileA.t
+	 D fileB.t
+	 D fileC.t
+	D  fileD.t
+	EOF
+	verify_expect
+'
+
+test_done
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 691b5fc..7f75bb1 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -356,6 +356,28 @@
 	test_line_count = 1 lines
 '
 
+test_expect_success 'status from subdirectory should have the same SHA1' '
+	test_when_finished "rmdir addtest/subdir" &&
+	(
+		cd addtest &&
+		mkdir subdir &&
+		git submodule status >output &&
+		awk "{print \$1}" <output >expect &&
+		cd subdir &&
+		git submodule status >../output &&
+		awk "{print \$1}" <../output >../actual &&
+		test_cmp ../expect ../actual &&
+		git -C ../submod checkout HEAD^ &&
+		git submodule status >../output &&
+		awk "{print \$1}" <../output >../actual2 &&
+		cd .. &&
+		git submodule status >output &&
+		awk "{print \$1}" <output >expect2 &&
+		test_cmp expect2 actual2 &&
+		! test_cmp actual actual2
+	)
+'
+
 test_expect_success 'setup - fetch commit name from submodule' '
 	rev1=$(cd .subrepo && git rev-parse HEAD) &&
 	printf "rev1: %s\n" "$rev1" &&
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index df34c99..7478f7a 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -406,12 +406,26 @@
 	)
 '
 
-test_expect_success 'submodule update - command in .gitmodules is ignored' '
+test_expect_success 'submodule update - command in .gitmodules is rejected' '
 	test_when_finished "git -C super reset --hard HEAD^" &&
 	git -C super config -f .gitmodules submodule.submodule.update "!false" &&
 	git -C super commit -a -m "add command to .gitmodules file" &&
 	git -C super/submodule reset --hard $submodulesha1^ &&
-	git -C super submodule update submodule
+	test_must_fail git -C super submodule update submodule
+'
+
+test_expect_success 'fsck detects command in .gitmodules' '
+	git init command-in-gitmodules &&
+	(
+		cd command-in-gitmodules &&
+		git submodule add ../submodule submodule &&
+		test_commit adding-submodule &&
+
+		git config -f .gitmodules submodule.submodule.update "!false" &&
+		git add .gitmodules &&
+		test_commit configuring-update &&
+		test_must_fail git fsck
+	)
 '
 
 cat << EOF >expect
@@ -480,6 +494,9 @@
 '
 
 test_expect_success 'submodule init does not copy command into .git/config' '
+	test_when_finished "git -C super update-index --force-remove submodule1" &&
+	test_when_finished git config -f super/.gitmodules \
+		--remove-section submodule.submodule1 &&
 	(cd super &&
 	 git ls-files -s submodule >out &&
 	 H=$(cut -d" " -f2 out) &&
@@ -488,10 +505,9 @@
 	 git config -f .gitmodules submodule.submodule1.path submodule1 &&
 	 git config -f .gitmodules submodule.submodule1.url ../submodule &&
 	 git config -f .gitmodules submodule.submodule1.update !false &&
-	 git submodule init submodule1 &&
-	 echo "none" >expect &&
-	 git config submodule.submodule1.update >actual &&
-	 test_cmp expect actual
+	 test_must_fail git submodule init submodule1 &&
+	 test_expect_code 1 git config submodule.submodule1.update >actual &&
+	 test_must_be_empty actual
 	)
 '
 
diff --git a/t/t7415-submodule-names.sh b/t/t7415-submodule-names.sh
index 49a37ef..7ae0dc8 100755
--- a/t/t7415-submodule-names.sh
+++ b/t/t7415-submodule-names.sh
@@ -191,4 +191,61 @@
 	)
 '
 
+test_expect_success MINGW 'prevent git~1 squatting on Windows' '
+	git init squatting &&
+	(
+		cd squatting &&
+		mkdir a &&
+		touch a/..git &&
+		git add a/..git &&
+		test_tick &&
+		git commit -m initial &&
+
+		modules="$(test_write_lines \
+			"[submodule \"b.\"]" "url = ." "path = c" \
+			"[submodule \"b\"]" "url = ." "path = d\\\\a" |
+			git hash-object -w --stdin)" &&
+		rev="$(git rev-parse --verify HEAD)" &&
+		hash="$(echo x | git hash-object -w --stdin)" &&
+		test_must_fail git update-index --add \
+			--cacheinfo 160000,$rev,d\\a 2>err &&
+		test_i18ngrep backslash err &&
+		git -c core.protectNTFS=false update-index --add \
+			--cacheinfo 100644,$modules,.gitmodules \
+			--cacheinfo 160000,$rev,c \
+			--cacheinfo 160000,$rev,d\\a \
+			--cacheinfo 100644,$hash,d./a/x \
+			--cacheinfo 100644,$hash,d./a/..git &&
+		test_tick &&
+		git -c core.protectNTFS=false commit -m "module"
+	) &&
+	test_must_fail git -c core.protectNTFS=false \
+		clone --recurse-submodules squatting squatting-clone 2>err &&
+	test_i18ngrep -e "directory not empty" -e "not an empty directory" err &&
+	! grep gitdir squatting-clone/d/a/git~2
+'
+
+test_expect_success 'git dirs of sibling submodules must not be nested' '
+	git init nested &&
+	test_commit -C nested nested &&
+	(
+		cd nested &&
+		cat >.gitmodules <<-EOF &&
+		[submodule "hippo"]
+			url = .
+			path = thing1
+		[submodule "hippo/hooks"]
+			url = .
+			path = thing2
+		EOF
+		git clone . thing1 &&
+		git clone . thing2 &&
+		git add .gitmodules thing1 thing2 &&
+		test_tick &&
+		git commit -m nested
+	) &&
+	test_must_fail git clone --recurse-submodules nested clone 2>err &&
+	test_i18ngrep "is inside git dir" err
+'
+
 test_done
diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh
index 1cd2c1c..5ba041f 100755
--- a/t/t7416-submodule-dash-url.sh
+++ b/t/t7416-submodule-dash-url.sh
@@ -46,4 +46,18 @@
 	grep gitmodulesUrl err
 '
 
+test_expect_success 'trailing backslash is handled correctly' '
+	git init testmodule &&
+	test_commit -C testmodule c &&
+	git submodule add ./testmodule &&
+	: ensure that the name ends in a double backslash &&
+	sed -e "s|\\(submodule \"testmodule\\)\"|\\1\\\\\\\\\"|" \
+		-e "s|url = .*|url = \" --should-not-be-an-option\"|" \
+		<.gitmodules >.new &&
+	mv .new .gitmodules &&
+	git commit -am "Add testmodule" &&
+	test_must_fail git clone --verbose --recurse-submodules . dolly 2>err &&
+	test_i18ngrep ! "unknown option" err
+'
+
 test_done
diff --git a/t/t7417-submodule-path-url.sh b/t/t7417-submodule-path-url.sh
index 756af8c..f7e7e94 100755
--- a/t/t7417-submodule-path-url.sh
+++ b/t/t7417-submodule-path-url.sh
@@ -25,4 +25,21 @@
 	grep gitmodulesPath err
 '
 
+test_expect_success MINGW 'submodule paths disallows trailing spaces' '
+	git init super &&
+	test_must_fail git -C super submodule add ../upstream "sub " &&
+
+	: add "sub", then rename "sub" to "sub ", the hard way &&
+	git -C super submodule add ../upstream sub &&
+	tree=$(git -C super write-tree) &&
+	git -C super ls-tree $tree >tree &&
+	sed "s/sub/sub /" <tree >tree.new &&
+	tree=$(git -C super mktree <tree.new) &&
+	commit=$(echo with space | git -C super commit-tree $tree) &&
+	git -C super update-ref refs/heads/master $commit &&
+
+	test_must_fail git clone --recurse-submodules super dst 2>err &&
+	test_i18ngrep "sub " err
+'
+
 test_done
diff --git a/t/t7420-submodule-set-url.sh b/t/t7420-submodule-set-url.sh
new file mode 100755
index 0000000..ef0cb6e
--- /dev/null
+++ b/t/t7420-submodule-set-url.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+#
+# Copyright (c) 2019 Denton Liu
+#
+
+test_description='Test submodules set-url subcommand
+
+This test verifies that the set-url subcommand of git-submodule is working
+as expected.
+'
+
+TEST_NO_CREATE_REPO=1
+. ./test-lib.sh
+
+test_expect_success 'submodule config cache setup' '
+	mkdir submodule &&
+	(
+		cd submodule &&
+		git init &&
+		echo a >file &&
+		git add file &&
+		git commit -ma
+	) &&
+	mkdir super &&
+	(
+		cd super &&
+		git init &&
+		git submodule add ../submodule &&
+		git commit -m "add submodule"
+	)
+'
+
+test_expect_success 'test submodule set-url' '
+	# add a commit and move the submodule (change the url)
+	(
+		cd submodule &&
+		echo b >>file &&
+		git add file &&
+		git commit -mb
+	) &&
+	mv submodule newsubmodule &&
+
+	git -C newsubmodule show >expect &&
+	(
+		cd super &&
+		test_must_fail git submodule update --remote &&
+		git submodule set-url submodule ../newsubmodule &&
+		grep -F "url = ../newsubmodule" .gitmodules &&
+		git submodule update --remote
+	) &&
+	git -C super/submodule show >actual &&
+	test_cmp expect actual
+'
+
+test_done
diff --git a/t/t7501-commit-basic-functionality.sh b/t/t7501-commit-basic-functionality.sh
index f1349af..110b4bf 100755
--- a/t/t7501-commit-basic-functionality.sh
+++ b/t/t7501-commit-basic-functionality.sh
@@ -150,7 +150,7 @@
 test_expect_success 'amend commit' '
 	cat >editor <<-\EOF &&
 	#!/bin/sh
-	sed -e "s/a file/an amend commit/g" < "$1" > "$1-"
+	sed -e "s/a file/an amend commit/g" <"$1" >"$1-"
 	mv "$1-" "$1"
 	EOF
 	chmod 755 editor &&
@@ -263,7 +263,7 @@
 test_expect_success 'editing message from other commit' '
 	cat >editor <<-\EOF &&
 	#!/bin/sh
-	sed -e "s/amend/older/g"  < "$1" > "$1-"
+	sed -e "s/amend/older/g"  <"$1" >"$1-"
 	mv "$1-" "$1"
 	EOF
 	chmod 755 editor &&
@@ -285,9 +285,8 @@
 '
 
 test_expect_success PERL 'interactive add' '
-	echo 7 |
-	git commit --interactive |
-	grep "What now"
+	echo 7 | test_must_fail git commit --interactive >out &&
+	grep "What now" out
 '
 
 test_expect_success PERL "commit --interactive doesn't change index if editor aborts" '
@@ -362,12 +361,12 @@
 	oldtick=$GIT_AUTHOR_DATE &&
 	test_tick &&
 	git reset --hard &&
-	git cat-file -p HEAD |
+	git cat-file -p HEAD >commit &&
 	sed -e "s/author.*/author $author $oldtick/" \
-		-e "s/^\(committer.*> \).*$/\1$GIT_COMMITTER_DATE/" > \
-		expected &&
+		-e "s/^\(committer.*> \).*$/\1$GIT_COMMITTER_DATE/" \
+		commit >expected &&
 	git commit --amend --author="$author" &&
-	git cat-file -p HEAD > current &&
+	git cat-file -p HEAD >current &&
 	test_cmp expected current
 
 '
@@ -377,12 +376,12 @@
 	test_tick &&
 	newtick=$GIT_AUTHOR_DATE &&
 	git reset --hard &&
-	git cat-file -p HEAD |
+	git cat-file -p HEAD >commit &&
 	sed -e "s/author.*/author $author $newtick/" \
-		-e "s/^\(committer.*> \).*$/\1$GIT_COMMITTER_DATE/" > \
-		expected &&
+		-e "s/^\(committer.*> \).*$/\1$GIT_COMMITTER_DATE/" \
+		commit >expected &&
 	git commit --amend --date="$newtick" &&
-	git cat-file -p HEAD > current &&
+	git cat-file -p HEAD >current &&
 	test_cmp expected current
 
 '
@@ -409,12 +408,13 @@
 	echo 1 >positive &&
 	git add positive &&
 	git commit -s -m "thank you" &&
-	git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
+	git cat-file commit HEAD >commit &&
+	sed -e "1,/^\$/d" commit >actual &&
 	(
 		echo thank you &&
 		echo &&
-		git var GIT_COMMITTER_IDENT |
-		sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /"
+		git var GIT_COMMITTER_IDENT >ident &&
+		sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /" ident
 	) >expected &&
 	test_cmp expected actual
 
@@ -428,13 +428,14 @@
 	git commit -s -m "thank you
 
 $existing" &&
-	git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
+	git cat-file commit HEAD >commit &&
+	sed -e "1,/^\$/d" commit >actual &&
 	(
 		echo thank you &&
 		echo &&
 		echo $existing &&
-		git var GIT_COMMITTER_IDENT |
-		sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /"
+		git var GIT_COMMITTER_IDENT >ident &&
+		sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /" ident
 	) >expected &&
 	test_cmp expected actual
 
@@ -448,13 +449,14 @@
 	git commit -s -m "welcome
 
 $alt" &&
-	git cat-file commit HEAD | sed -e "1,/^\$/d" > actual &&
+	git cat-file commit HEAD >commit &&
+	sed -e "1,/^\$/d" commit >actual &&
 	(
 		echo welcome &&
 		echo &&
 		echo $alt &&
-		git var GIT_COMMITTER_IDENT |
-		sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /"
+		git var GIT_COMMITTER_IDENT >ident &&
+		sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /" ident
 	) >expected &&
 	test_cmp expected actual
 '
@@ -468,15 +470,16 @@
 
 We have now
 $alt" &&
-	git cat-file commit HEAD | sed -e "1,/^\$/d" > actual &&
+	git cat-file commit HEAD >commit &&
+	sed -e "1,/^\$/d" commit >actual &&
 	(
 		echo welcome &&
 		echo &&
 		echo We have now &&
 		echo $alt &&
 		echo &&
-		git var GIT_COMMITTER_IDENT |
-		sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /"
+		git var GIT_COMMITTER_IDENT >ident &&
+		sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /" ident
 	) >expected &&
 	test_cmp expected actual
 '
@@ -489,7 +492,8 @@
 
 non-trailer line
 Myfooter: x" &&
-	git cat-file commit HEAD | sed -e "1,/^\$/d" > actual &&
+	git cat-file commit HEAD >commit &&
+	sed -e "1,/^\$/d" commit >actual &&
 	(
 		echo subject &&
 		echo &&
@@ -506,7 +510,8 @@
 
 non-trailer line
 Myfooter: x" &&
-	git cat-file commit HEAD | sed -e "1,/^\$/d" > actual &&
+	git cat-file commit HEAD >commit &&
+	sed -e "1,/^\$/d" commit >actual &&
 	(
 		echo subject &&
 		echo &&
@@ -538,7 +543,8 @@
 	>negative &&
 	git add negative &&
 	git commit -m "one" -m "two" -m "three" &&
-	git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
+	git cat-file commit HEAD >commit &&
+	sed -e "1,/^\$/d" commit >actual &&
 	(
 		echo one &&
 		echo &&
@@ -555,23 +561,25 @@
 	oldtick=$GIT_AUTHOR_DATE &&
 	test_tick &&
 	git reset --hard &&
-	git cat-file -p HEAD |
+	git cat-file -p HEAD >commit &&
 	sed -e "s/author.*/author $author $oldtick/" \
-		-e "s/^\(committer.*> \).*$/\1$GIT_COMMITTER_DATE/" > \
-		expected &&
+		-e "s/^\(committer.*> \).*$/\1$GIT_COMMITTER_DATE/" \
+		commit >expected &&
 	git commit --amend --author="$author" &&
-	git cat-file -p HEAD > current &&
+	git cat-file -p HEAD >current &&
 	test_cmp expected current
 
 '
 
 test_expect_success 'git commit <file> with dirty index' '
-	echo tacocat > elif &&
-	echo tehlulz > chz &&
+	echo tacocat >elif &&
+	echo tehlulz >chz &&
 	git add chz &&
 	git commit elif -m "tacocat is a palindrome" &&
-	git show --stat | grep elif &&
-	git diff --cached | grep chz
+	git show --stat >stat &&
+	grep elif stat &&
+	git diff --cached >diff &&
+	grep chz diff
 '
 
 test_expect_success 'same tree (single parent)' '
@@ -584,7 +592,8 @@
 test_expect_success 'same tree (single parent) --allow-empty' '
 
 	git commit --allow-empty -m "forced empty" &&
-	git cat-file commit HEAD | grep forced
+	git cat-file commit HEAD >commit &&
+	grep forced commit
 
 '
 
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index 4e676cd..482ce35 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1571,7 +1571,7 @@
 	test_cmp expected_without_stash actual
 '
 
-test_expect_success 'no additionnal info if no stash entries' '
+test_expect_success 'no additional info if no stash entries' '
 	git stash clear &&
 	git -c status.showStash=true status >actual &&
 	test_cmp expected_without_stash actual
diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh
index f19202b..6602790 100755
--- a/t/t7513-interpret-trailers.sh
+++ b/t/t7513-interpret-trailers.sh
@@ -1234,7 +1234,7 @@
 	test_cmp expected actual
 '
 
-test_expect_success 'with command using commiter information' '
+test_expect_success 'with command using committer information' '
 	git config trailer.sign.ifExists "addIfDifferent" &&
 	git config trailer.sign.command "echo \"\$GIT_COMMITTER_NAME <\$GIT_COMMITTER_EMAIL>\"" &&
 	cat complex_message_body >expected &&
diff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh
index 997d5fb..cf0fda2 100755
--- a/t/t7519-status-fsmonitor.sh
+++ b/t/t7519-status-fsmonitor.sh
@@ -106,6 +106,8 @@
 
 # test that "update-index --fsmonitor-valid" sets the fsmonitor valid bit
 test_expect_success 'update-index --fsmonitor-valid" sets the fsmonitor valid bit' '
+	write_script .git/hooks/fsmonitor-test<<-\EOF &&
+	EOF
 	git update-index --fsmonitor &&
 	git update-index --fsmonitor-valid dir1/modified &&
 	git update-index --fsmonitor-valid dir2/modified &&
@@ -164,6 +166,8 @@
 
 # test that newly added files are marked valid
 test_expect_success 'newly added files are marked valid' '
+	write_script .git/hooks/fsmonitor-test<<-\EOF &&
+	EOF
 	git add new &&
 	git add dir1/new &&
 	git add dir2/new &&
@@ -218,11 +222,12 @@
 # Ensure commands that call refresh_index() to move the index back in time
 # properly invalidate the fsmonitor cache
 test_expect_success 'refresh_index() invalidates fsmonitor cache' '
-	write_script .git/hooks/fsmonitor-test<<-\EOF &&
-	EOF
 	clean_repo &&
 	dirty_repo &&
+	write_integration_script &&
 	git add . &&
+	write_script .git/hooks/fsmonitor-test<<-\EOF &&
+	EOF
 	git commit -m "to reset" &&
 	git reset HEAD~1 &&
 	git status >actual &&
@@ -294,7 +299,7 @@
 	done
 done
 
-# test that splitting the index dosn't interfere
+# test that splitting the index doesn't interfere
 test_expect_success 'splitting the index results in the same state' '
 	write_integration_script &&
 	dirty_repo &&
diff --git a/t/t7519/fsmonitor-watchman b/t/t7519/fsmonitor-watchman
index 5514edc..d8e7a1e 100755
--- a/t/t7519/fsmonitor-watchman
+++ b/t/t7519/fsmonitor-watchman
@@ -23,7 +23,8 @@
 
 if ($version == 1) {
 	# convert nanoseconds to seconds
-	$time = int $time / 1000000000;
+	# subtract one second to make sure watchman will return all changes
+	$time = int ($time / 1000000000) - 1;
 } else {
 	die "Unsupported query-fsmonitor hook version '$version'.\n" .
 	    "Falling back to scanning...\n";
@@ -54,18 +55,12 @@
 	#
 	# To accomplish this, we're using the "since" generator to use the
 	# recency index to select candidate nodes and "fields" to limit the
-	# output to file names only. Then we're using the "expression" term to
-	# further constrain the results.
-	#
-	# The category of transient files that we want to ignore will have a
-	# creation clock (cclock) newer than $time_t value and will also not
-	# currently exist.
+	# output to file names only.
 
 	my $query = <<"	END";
 		["query", "$git_work_tree", {
 			"since": $time,
-			"fields": ["name"],
-			"expression": ["not", ["allof", ["since", $time, "cclock"], ["not", "exists"]]]
+			"fields": ["name"]
 		}]
 	END
 	
diff --git a/t/t7526-commit-pathspec-file.sh b/t/t7526-commit-pathspec-file.sh
new file mode 100755
index 0000000..4b58901
--- /dev/null
+++ b/t/t7526-commit-pathspec-file.sh
@@ -0,0 +1,136 @@
+#!/bin/sh
+
+test_description='commit --pathspec-from-file'
+
+. ./test-lib.sh
+
+test_tick
+
+test_expect_success setup '
+	test_commit file0 &&
+	git tag checkpoint &&
+
+	echo A >fileA.t &&
+	echo B >fileB.t &&
+	echo C >fileC.t &&
+	echo D >fileD.t &&
+	git add fileA.t fileB.t fileC.t fileD.t
+'
+
+restore_checkpoint () {
+	git reset --soft checkpoint
+}
+
+verify_expect () {
+	git diff-tree --no-commit-id --name-status -r HEAD >actual &&
+	test_cmp expect actual
+}
+
+test_expect_success '--pathspec-from-file from stdin' '
+	restore_checkpoint &&
+
+	echo fileA.t | git commit --pathspec-from-file=- -m "Commit" &&
+
+	cat >expect <<-\EOF &&
+	A	fileA.t
+	EOF
+	verify_expect
+'
+
+test_expect_success '--pathspec-from-file from file' '
+	restore_checkpoint &&
+
+	echo fileA.t >list &&
+	git commit --pathspec-from-file=list -m "Commit" &&
+
+	cat >expect <<-\EOF &&
+	A	fileA.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'NUL delimiters' '
+	restore_checkpoint &&
+
+	printf "fileA.t\0fileB.t\0" | git commit --pathspec-from-file=- --pathspec-file-nul -m "Commit" &&
+
+	cat >expect <<-\EOF &&
+	A	fileA.t
+	A	fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'LF delimiters' '
+	restore_checkpoint &&
+
+	printf "fileA.t\nfileB.t\n" | git commit --pathspec-from-file=- -m "Commit" &&
+
+	cat >expect <<-\EOF &&
+	A	fileA.t
+	A	fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'no trailing delimiter' '
+	restore_checkpoint &&
+
+	printf "fileA.t\nfileB.t" | git commit --pathspec-from-file=- -m "Commit" &&
+
+	cat >expect <<-\EOF &&
+	A	fileA.t
+	A	fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'CRLF delimiters' '
+	restore_checkpoint &&
+
+	printf "fileA.t\r\nfileB.t\r\n" | git commit --pathspec-from-file=- -m "Commit" &&
+
+	cat >expect <<-\EOF &&
+	A	fileA.t
+	A	fileB.t
+	EOF
+	verify_expect
+'
+
+test_expect_success 'quotes' '
+	restore_checkpoint &&
+
+	printf "\"file\\101.t\"" | git commit --pathspec-from-file=- -m "Commit" &&
+
+	cat >expect <<-\EOF &&
+	A	fileA.t
+	EOF
+	verify_expect expect
+'
+
+test_expect_success 'quotes not compatible with --pathspec-file-nul' '
+	restore_checkpoint &&
+
+	printf "\"file\\101.t\"" >list &&
+	test_must_fail git commit --pathspec-from-file=list --pathspec-file-nul -m "Commit"
+'
+
+test_expect_success 'only touches what was listed' '
+	restore_checkpoint &&
+
+	printf "fileB.t\nfileC.t\n" | git commit --pathspec-from-file=- -m "Commit" &&
+
+	cat >expect <<-\EOF &&
+	A	fileB.t
+	A	fileC.t
+	EOF
+	verify_expect
+'
+
+test_expect_success '--pathspec-from-file and --all cannot be used together' '
+	restore_checkpoint &&
+	test_must_fail git commit --pathspec-from-file=- --all -m "Commit" 2>err &&
+	test_i18ngrep "[-]-pathspec-from-file with -a does not make sense" err
+'
+
+test_done
diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh
index 4e855bc2..25b235c 100755
--- a/t/t7700-repack.sh
+++ b/t/t7700-repack.sh
@@ -4,129 +4,104 @@
 
 . ./test-lib.sh
 
-commit_and_pack() {
-	test_commit "$@" >/dev/null &&
-	SHA1=$(git pack-objects --all --unpacked --incremental .git/objects/pack/pack </dev/null) &&
-	echo pack-${SHA1}.pack
+commit_and_pack () {
+	test_commit "$@" 1>&2 &&
+	incrpackid=$(git pack-objects --all --unpacked --incremental .git/objects/pack/pack </dev/null) &&
+	echo pack-${incrpackid}.pack
+}
+
+test_no_missing_in_packs () {
+	myidx=$(ls -1 .git/objects/pack/*.idx) &&
+	test_path_is_file "$myidx" &&
+	git verify-pack -v alt_objects/pack/*.idx >orig.raw &&
+	sed -n -e "s/^\($OID_REGEX\).*/\1/p" orig.raw | sort >orig &&
+	git verify-pack -v $myidx >dest.raw &&
+	cut -d" " -f1 dest.raw | sort >dest &&
+	comm -23 orig dest >missing &&
+	test_must_be_empty missing
+}
+
+# we expect $packid and $oid to be defined
+test_has_duplicate_object () {
+	want_duplicate_object="$1"
+	found_duplicate_object=false
+	for p in .git/objects/pack/*.idx
+	do
+		idx=$(basename $p)
+		test "pack-$packid.idx" = "$idx" && continue
+		git verify-pack -v $p >packlist || return $?
+		if grep "^$oid" packlist
+		then
+			found_duplicate_object=true
+			echo "DUPLICATE OBJECT FOUND"
+			break
+		fi
+	done &&
+	test "$want_duplicate_object" = "$found_duplicate_object"
 }
 
 test_expect_success 'objects in packs marked .keep are not repacked' '
-	echo content1 > file1 &&
-	echo content2 > file2 &&
+	echo content1 >file1 &&
+	echo content2 >file2 &&
 	git add . &&
 	test_tick &&
 	git commit -m initial_commit &&
 	# Create two packs
 	# The first pack will contain all of the objects except one
-	git rev-list --objects --all | grep -v file2 |
-		git pack-objects pack > /dev/null &&
+	git rev-list --objects --all >objs &&
+	grep -v file2 objs | git pack-objects pack &&
 	# The second pack will contain the excluded object
-	packsha1=$(git rev-list --objects --all | grep file2 |
-		git pack-objects pack) &&
-	>pack-$packsha1.keep &&
-	objsha1=$(git verify-pack -v pack-$packsha1.idx | head -n 1 |
-		sed -e "s/^\([0-9a-f]\{40\}\).*/\1/") &&
+	packid=$(grep file2 objs | git pack-objects pack) &&
+	>pack-$packid.keep &&
+	git verify-pack -v pack-$packid.idx >packlist &&
+	oid=$(head -n 1 packlist | sed -e "s/^\($OID_REGEX\).*/\1/") &&
 	mv pack-* .git/objects/pack/ &&
 	git repack -A -d -l &&
 	git prune-packed &&
-	for p in .git/objects/pack/*.idx; do
-		idx=$(basename $p)
-		test "pack-$packsha1.idx" = "$idx" && continue
-		if git verify-pack -v $p | egrep "^$objsha1"; then
-			found_duplicate_object=1
-			echo "DUPLICATE OBJECT FOUND"
-			break
-		fi
-	done &&
-	test -z "$found_duplicate_object"
+	test_has_duplicate_object false
 '
 
 test_expect_success 'writing bitmaps via command-line can duplicate .keep objects' '
-	# build on $objsha1, $packsha1, and .keep state from previous
+	# build on $oid, $packid, and .keep state from previous
 	git repack -Adbl &&
-	test_when_finished "found_duplicate_object=" &&
-	for p in .git/objects/pack/*.idx; do
-		idx=$(basename $p)
-		test "pack-$packsha1.idx" = "$idx" && continue
-		if git verify-pack -v $p | egrep "^$objsha1"; then
-			found_duplicate_object=1
-			echo "DUPLICATE OBJECT FOUND"
-			break
-		fi
-	done &&
-	test "$found_duplicate_object" = 1
+	test_has_duplicate_object true
 '
 
 test_expect_success 'writing bitmaps via config can duplicate .keep objects' '
-	# build on $objsha1, $packsha1, and .keep state from previous
+	# build on $oid, $packid, and .keep state from previous
 	git -c repack.writebitmaps=true repack -Adl &&
-	test_when_finished "found_duplicate_object=" &&
-	for p in .git/objects/pack/*.idx; do
-		idx=$(basename $p)
-		test "pack-$packsha1.idx" = "$idx" && continue
-		if git verify-pack -v $p | egrep "^$objsha1"; then
-			found_duplicate_object=1
-			echo "DUPLICATE OBJECT FOUND"
-			break
-		fi
-	done &&
-	test "$found_duplicate_object" = 1
+	test_has_duplicate_object true
 '
 
 test_expect_success 'loose objects in alternate ODB are not repacked' '
 	mkdir alt_objects &&
-	echo $(pwd)/alt_objects > .git/objects/info/alternates &&
-	echo content3 > file3 &&
-	objsha1=$(GIT_OBJECT_DIRECTORY=alt_objects git hash-object -w file3) &&
+	echo $(pwd)/alt_objects >.git/objects/info/alternates &&
+	echo content3 >file3 &&
+	oid=$(GIT_OBJECT_DIRECTORY=alt_objects git hash-object -w file3) &&
 	git add file3 &&
 	test_tick &&
 	git commit -m commit_file3 &&
 	git repack -a -d -l &&
 	git prune-packed &&
-	for p in .git/objects/pack/*.idx; do
-		if git verify-pack -v $p | egrep "^$objsha1"; then
-			found_duplicate_object=1
-			echo "DUPLICATE OBJECT FOUND"
-			break
-		fi
-	done &&
-	test -z "$found_duplicate_object"
+	test_has_duplicate_object false
 '
 
 test_expect_success 'packed obs in alt ODB are repacked even when local repo is packless' '
 	mkdir alt_objects/pack &&
 	mv .git/objects/pack/* alt_objects/pack &&
 	git repack -a &&
-	myidx=$(ls -1 .git/objects/pack/*.idx) &&
-	test -f "$myidx" &&
-	for p in alt_objects/pack/*.idx; do
-		git verify-pack -v $p | sed -n -e "/^[0-9a-f]\{40\}/p"
-	done | while read sha1 rest; do
-		if ! ( git verify-pack -v $myidx | grep "^$sha1" ); then
-			echo "Missing object in local pack: $sha1"
-			return 1
-		fi
-	done
+	test_no_missing_in_packs
 '
 
 test_expect_success 'packed obs in alt ODB are repacked when local repo has packs' '
 	rm -f .git/objects/pack/* &&
-	echo new_content >> file1 &&
+	echo new_content >>file1 &&
 	git add file1 &&
 	test_tick &&
 	git commit -m more_content &&
 	git repack &&
 	git repack -a -d &&
-	myidx=$(ls -1 .git/objects/pack/*.idx) &&
-	test -f "$myidx" &&
-	for p in alt_objects/pack/*.idx; do
-		git verify-pack -v $p | sed -n -e "/^[0-9a-f]\{40\}/p"
-	done | while read sha1 rest; do
-		if ! ( git verify-pack -v $myidx | grep "^$sha1" ); then
-			echo "Missing object in local pack: $sha1"
-			return 1
-		fi
-	done
+	test_no_missing_in_packs
 '
 
 test_expect_success 'packed obs in alternate ODB kept pack are repacked' '
@@ -134,7 +109,7 @@
 	for p in alt_objects/pack/*.pack
 	do
 		base_name=$(basename $p .pack) &&
-		if test -f alt_objects/pack/$base_name.keep
+		if test_path_is_file alt_objects/pack/$base_name.keep
 		then
 			rm alt_objects/pack/$base_name.keep
 		else
@@ -142,22 +117,13 @@
 		fi
 	done &&
 	git repack -a -d &&
-	myidx=$(ls -1 .git/objects/pack/*.idx) &&
-	test -f "$myidx" &&
-	for p in alt_objects/pack/*.idx; do
-		git verify-pack -v $p | sed -n -e "/^[0-9a-f]\{40\}/p"
-	done | while read sha1 rest; do
-		if ! ( git verify-pack -v $myidx | grep "^$sha1" ); then
-			echo "Missing object in local pack: $sha1"
-			return 1
-		fi
-	done
+	test_no_missing_in_packs
 '
 
 test_expect_success 'packed unreachable obs in alternate ODB are not loosened' '
 	rm -f alt_objects/pack/*.keep &&
 	mv .git/objects/pack/* alt_objects/pack/ &&
-	csha1=$(git rev-parse HEAD^{commit}) &&
+	coid=$(git rev-parse HEAD^{commit}) &&
 	git reset --hard HEAD^ &&
 	test_tick &&
 	git reflog expire --expire=$test_tick --expire-unreachable=$test_tick --all &&
@@ -167,15 +133,15 @@
 	    --unpack-unreachable </dev/null pack &&
 	rm -f .git/objects/pack/* &&
 	mv pack-* .git/objects/pack/ &&
-	test 0 = $(git verify-pack -v -- .git/objects/pack/*.idx |
-		egrep "^$csha1 " | sort | uniq | wc -l) &&
-	echo > .git/objects/info/alternates &&
-	test_must_fail git show $csha1
+	git verify-pack -v -- .git/objects/pack/*.idx >packlist &&
+	! grep "^$coid " packlist &&
+	echo >.git/objects/info/alternates &&
+	test_must_fail git show $coid
 '
 
 test_expect_success 'local packed unreachable obs that exist in alternate ODB are not loosened' '
-	echo $(pwd)/alt_objects > .git/objects/info/alternates &&
-	echo "$csha1" | git pack-objects --non-empty --all --reflog pack &&
+	echo $(pwd)/alt_objects >.git/objects/info/alternates &&
+	echo "$coid" | git pack-objects --non-empty --all --reflog pack &&
 	rm -f .git/objects/pack/* &&
 	mv pack-* .git/objects/pack/ &&
 	# The pack-objects call on the next line is equivalent to
@@ -184,10 +150,10 @@
 	    --unpack-unreachable </dev/null pack &&
 	rm -f .git/objects/pack/* &&
 	mv pack-* .git/objects/pack/ &&
-	test 0 = $(git verify-pack -v -- .git/objects/pack/*.idx |
-		egrep "^$csha1 " | sort | uniq | wc -l) &&
-	echo > .git/objects/info/alternates &&
-	test_must_fail git show $csha1
+	git verify-pack -v -- .git/objects/pack/*.idx >packlist &&
+	! grep "^$coid " &&
+	echo >.git/objects/info/alternates &&
+	test_must_fail git show $coid
 '
 
 test_expect_success 'objects made unreachable by grafts only are kept' '
@@ -196,7 +162,7 @@
 	H0=$(git rev-parse HEAD) &&
 	H1=$(git rev-parse HEAD^) &&
 	H2=$(git rev-parse HEAD^^) &&
-	echo "$H0 $H2" > .git/info/grafts &&
+	echo "$H0 $H2" >.git/info/grafts &&
 	git reflog expire --expire=$test_tick --expire-unreachable=$test_tick --all &&
 	git repack -a -d &&
 	git cat-file -t $H1
@@ -235,7 +201,7 @@
 
 test_expect_success 'bitmaps can be disabled on bare repos' '
 	git -c repack.writeBitmaps=false -C bare.git repack -ad &&
-	bitmap=$(ls bare.git/objects/pack/*.bitmap 2>/dev/null || :) &&
+	bitmap=$(ls bare.git/objects/pack/*.bitmap || :) &&
 	test -z "$bitmap"
 '
 
diff --git a/t/t7811-grep-open.sh b/t/t7811-grep-open.sh
index d1ebfd8..a98785d 100755
--- a/t/t7811-grep-open.sh
+++ b/t/t7811-grep-open.sh
@@ -113,7 +113,6 @@
 	subdir/grep.c
 	unrelated
 	EOF
-	>empty &&
 
 	echo "enum grep_pat_token" >unrelated &&
 	test_when_finished "git checkout HEAD unrelated" &&
diff --git a/t/t7812-grep-icase-non-ascii.sh b/t/t7812-grep-icase-non-ascii.sh
index 531eb59..03dba66 100755
--- a/t/t7812-grep-icase-non-ascii.sh
+++ b/t/t7812-grep-icase-non-ascii.sh
@@ -70,15 +70,18 @@
 test_expect_success GETTEXT_LOCALE,LIBPCRE2 'PCRE v2: grep non-ASCII from invalid UTF-8 data' '
 	git grep -h "æ" invalid-0x80 >actual &&
 	test_cmp expected actual &&
-	git grep -h "(*NO_JIT)æ" invalid-0x80 &&
+	git grep -h "(*NO_JIT)æ" invalid-0x80 >actual &&
 	test_cmp expected actual
 '
 
 test_expect_success GETTEXT_LOCALE,LIBPCRE2 'PCRE v2: grep non-ASCII from invalid UTF-8 data with -i' '
 	test_might_fail git grep -hi "Æ" invalid-0x80 >actual &&
-	test_cmp expected actual &&
-	test_must_fail git grep -hi "(*NO_JIT)Æ" invalid-0x80 &&
-	test_cmp expected actual
+	if test -s actual
+	then
+	    test_cmp expected actual
+	fi &&
+	test_must_fail git grep -hi "(*NO_JIT)Æ" invalid-0x80 >actual &&
+	! test_cmp expected actual
 '
 
 test_done
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 997f90b..a834afa 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -1260,7 +1260,7 @@
 	grep "To: default@example.com" stdout
 '
 
-test_expect_success $PREREQ 'sendemail.identity: bool identity variable existance overrides' '
+test_expect_success $PREREQ 'sendemail.identity: bool identity variable existence overrides' '
 	git -c sendemail.identity=cloud \
 		-c sendemail.xmailer=true \
 		-c sendemail.cloud.xmailer=false \
@@ -2066,7 +2066,7 @@
 	TO1=$(echo "QTo 1 <to1@example.com>" | q_to_tab) &&
 	TO2=$(echo "QZto2" | qz_to_tab_space) &&
 	CC1=$(echo "cc1" | append_cr) &&
-	BCC1=$(echo "Q bcc1@example.com Q" | q_to_nul) &&
+	BCC1=$(echo " bcc1@example.com Q" | q_to_nul) &&
 	git send-email \
 	--dry-run \
 	--from="	Example <from@example.com>" \
diff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh
index 0b20b07..c90fdc5 100755
--- a/t/t9010-svn-fe.sh
+++ b/t/t9010-svn-fe.sh
@@ -53,8 +53,6 @@
 	printf "%s\n" "$text"
 }
 
->empty
-
 test_expect_success 'empty dump' '
 	reinit_git &&
 	echo "SVN-fs-dump-format-version: 2" >input &&
@@ -208,7 +206,7 @@
 	test_cmp expect.date actual.date &&
 	test_cmp expect.files actual.files &&
 	git checkout HEAD empty-file &&
-	test_cmp empty file
+	test_must_be_empty file
 '
 
 test_expect_success 'directory with files' '
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index e707fb8..ae9950a 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -2143,12 +2143,27 @@
 	test_must_fail git fast-import <input
 '
 
+test_expect_success 'R: import-marks features forbidden by default' '
+	>git.marks &&
+	echo "feature import-marks=git.marks" >input &&
+	test_must_fail git fast-import <input &&
+	echo "feature import-marks-if-exists=git.marks" >input &&
+	test_must_fail git fast-import <input
+'
+
 test_expect_success 'R: only one import-marks feature allowed per stream' '
+	>git.marks &&
+	>git2.marks &&
 	cat >input <<-EOF &&
 	feature import-marks=git.marks
 	feature import-marks=git2.marks
 	EOF
 
+	test_must_fail git fast-import --allow-unsafe-features <input
+'
+
+test_expect_success 'R: export-marks feature forbidden by default' '
+	echo "feature export-marks=git.marks" >input &&
 	test_must_fail git fast-import <input
 '
 
@@ -2162,19 +2177,29 @@
 
 	EOF
 
-	cat input | git fast-import &&
+	git fast-import --allow-unsafe-features <input &&
 	grep :1 git.marks
 '
 
 test_expect_success 'R: export-marks options can be overridden by commandline options' '
-	cat input | git fast-import --export-marks=other.marks &&
-	grep :1 other.marks
+	cat >input <<-\EOF &&
+	feature export-marks=feature-sub/git.marks
+	blob
+	mark :1
+	data 3
+	hi
+
+	EOF
+	git fast-import --allow-unsafe-features \
+			--export-marks=cmdline-sub/other.marks <input &&
+	grep :1 cmdline-sub/other.marks &&
+	test_path_is_missing feature-sub
 '
 
 test_expect_success 'R: catch typo in marks file name' '
 	test_must_fail git fast-import --import-marks=nonexistent.marks </dev/null &&
 	echo "feature import-marks=nonexistent.marks" |
-	test_must_fail git fast-import
+	test_must_fail git fast-import --allow-unsafe-features
 '
 
 test_expect_success 'R: import and output marks can be the same file' '
@@ -2229,7 +2254,8 @@
 test_expect_success 'R: feature import-marks-if-exists' '
 	rm -f io.marks &&
 
-	git fast-import --export-marks=io.marks <<-\EOF &&
+	git fast-import --export-marks=io.marks \
+			--allow-unsafe-features <<-\EOF &&
 	feature import-marks-if-exists=not_io.marks
 	EOF
 	test_must_be_empty io.marks &&
@@ -2240,7 +2266,8 @@
 	echo ":1 $blob" >expect &&
 	echo ":2 $blob" >>expect &&
 
-	git fast-import --export-marks=io.marks <<-\EOF &&
+	git fast-import --export-marks=io.marks \
+			--allow-unsafe-features <<-\EOF &&
 	feature import-marks-if-exists=io.marks
 	blob
 	mark :2
@@ -2253,7 +2280,8 @@
 	echo ":3 $blob" >>expect &&
 
 	git fast-import --import-marks=io.marks \
-			--export-marks=io.marks <<-\EOF &&
+			--export-marks=io.marks \
+			--allow-unsafe-features <<-\EOF &&
 	feature import-marks-if-exists=not_io.marks
 	blob
 	mark :3
@@ -2264,7 +2292,8 @@
 	test_cmp expect io.marks &&
 
 	git fast-import --import-marks-if-exists=not_io.marks \
-			--export-marks=io.marks <<-\EOF &&
+			--export-marks=io.marks \
+			--allow-unsafe-features <<-\EOF &&
 	feature import-marks-if-exists=io.marks
 	EOF
 	test_must_be_empty io.marks
@@ -2276,7 +2305,7 @@
 	feature export-marks=marks.new
 	EOF
 
-	cat input | git fast-import &&
+	git fast-import --allow-unsafe-features <input &&
 	test_cmp marks.out marks.new
 '
 
@@ -2286,7 +2315,7 @@
 	feature export-marks=marks.new
 	EOF
 
-	cat input | git fast-import --import-marks=marks.out &&
+	git fast-import --import-marks=marks.out --allow-unsafe-features <input &&
 	test_cmp marks.out marks.new
 '
 
@@ -2299,7 +2328,8 @@
 
 	head -n2 marks.out > one.marks &&
 	tail -n +3 marks.out > two.marks &&
-	git fast-import --import-marks=one.marks --import-marks=two.marks <input &&
+	git fast-import --import-marks=one.marks --import-marks=two.marks \
+		--allow-unsafe-features <input &&
 	test_cmp marks.out combined.marks
 '
 
@@ -2312,7 +2342,7 @@
 
 	mkdir -p .git/info/fast-import/ &&
 	cp marks.new .git/info/fast-import/relative.in &&
-	git fast-import <input &&
+	git fast-import --allow-unsafe-features <input &&
 	test_cmp marks.new .git/info/fast-import/relative.out
 '
 
@@ -2324,7 +2354,7 @@
 	feature export-marks=non-relative.out
 	EOF
 
-	git fast-import <input &&
+	git fast-import --allow-unsafe-features <input &&
 	test_cmp marks.new non-relative.out
 '
 
@@ -2477,9 +2507,6 @@
 	echo $expect_id blob $expect_len >expect.response &&
 
 	rm -f blobs &&
-	cat >frontend <<-\FRONTEND_END &&
-	#!/bin/sh
-	FRONTEND_END
 
 	mkfifo blobs &&
 	(
@@ -2594,7 +2621,7 @@
 
 	EOF
 
-	cat input | git fast-import 2> output &&
+	git fast-import 2>output <input &&
 	test_must_be_empty output
 '
 
@@ -3164,13 +3191,22 @@
 	exec 9<>V.output
 	rm V.output
 
-	git fast-import $options <&8 >&9 &
-	echo $! >V.pid
+	(
+		git fast-import $options <&8 >&9 &
+		echo $! >&9
+		wait $!
+		echo >&2 "background fast-import terminated too early with exit code $?"
+		# Un-block the read loop in the main shell process.
+		echo >&9 UNEXPECTED
+	) &
+	sh_pid=$!
+	read fi_pid <&9
 	# We don't mind if fast-import has already died by the time the test
 	# ends.
 	test_when_finished "
 		exec 8>&-; exec 9>&-;
-		kill $(cat V.pid) && wait $(cat V.pid)
+		kill $sh_pid && wait $sh_pid
+		kill $fi_pid && wait $fi_pid
 		true"
 
 	# Start in the background to ensure we adhere strictly to (blocking)
@@ -3190,6 +3226,9 @@
 		then
 			error=0
 			break
+		elif test "$output" = "UNEXPECTED"
+		then
+			break
 		fi
 		# otherwise ignore cruft
 		echo >&2 "cruft: $output"
@@ -3202,7 +3241,7 @@
 }
 
 background_import_still_running () {
-	if ! kill -0 "$(cat V.pid)"
+	if ! kill -0 "$fi_pid"
 	then
 		echo >&2 "background fast-import terminated too early"
 		false
diff --git a/t/t9301-fast-import-notes.sh b/t/t9301-fast-import-notes.sh
index dadc70b..ca223dc 100755
--- a/t/t9301-fast-import-notes.sh
+++ b/t/t9301-fast-import-notes.sh
@@ -275,7 +275,7 @@
     third note for first commit
 EXPECT_END
 
-test_expect_success 'add concatentation notes with M command' '
+test_expect_success 'add concatenation notes with M command' '
 
 	git fast-import <input &&
 	GIT_NOTES_REF=refs/notes/test git log | grep "^    " > actual &&
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 2e4e214..690c90f 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -541,7 +541,7 @@
 
 # NEEDSWORK: not just check return status, but validate the output
 # Note that these tests DO NOTHING other than print a warning that
-# they are ommitting the one tag we asked them to export (because the
+# they are omitting the one tag we asked them to export (because the
 # tags resolve to a tree).  They exist just to make sure we do not
 # abort but instead just warn.
 test_expect_success 'tree_tag-obj'    'git fast-export tree_tag-obj'
@@ -600,9 +600,10 @@
 
 test_expect_success 'fast-export quotes pathnames' '
 	git init crazy-paths &&
+	test_config -C crazy-paths core.protectNTFS false &&
 	(cd crazy-paths &&
 	 blob=$(echo foo | git hash-object -w --stdin) &&
-	 git update-index --add \
+	 git -c core.protectNTFS=false update-index --add \
 		--cacheinfo 100644 $blob "$(printf "path with\\nnewline")" \
 		--cacheinfo 100644 $blob "path with \"quote\"" \
 		--cacheinfo 100644 $blob "path with \\backslash" \
diff --git a/t/t9502-gitweb-standalone-parse-output.sh b/t/t9502-gitweb-standalone-parse-output.sh
index 0796a43..e38cbc9 100755
--- a/t/t9502-gitweb-standalone-parse-output.sh
+++ b/t/t9502-gitweb-standalone-parse-output.sh
@@ -188,8 +188,8 @@
 '
 
 xss() {
-	echo >&2 "Checking $1..." &&
-	gitweb_run "$1" &&
+	echo >&2 "Checking $*..." &&
+	gitweb_run "$@" &&
 	if grep "$TAG" gitweb.body; then
 		echo >&2 "xss: $TAG should have been quoted in output"
 		return 1
@@ -200,7 +200,8 @@
 test_expect_success 'xss checks' '
 	TAG="<magic-xss-tag>" &&
 	xss "a=rss&p=$TAG" &&
-	xss "a=rss&p=foo.git&f=$TAG"
+	xss "a=rss&p=foo.git&f=$TAG" &&
+	xss "" "$TAG+"
 '
 
 test_done
diff --git a/t/t9809-git-p4-client-view.sh b/t/t9809-git-p4-client-view.sh
index 3cff1fc..9c9710d 100755
--- a/t/t9809-git-p4-client-view.sh
+++ b/t/t9809-git-p4-client-view.sh
@@ -407,7 +407,7 @@
 '
 
 #
-# What happens when two files of the same name are overlayed together?
+# What happens when two files of the same name are overlaid together?
 # The last-listed file should take preference.
 #
 # //depot
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index e90ac56..93877ba 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -378,7 +378,7 @@
 '
 
 
-test_expect_success '__gitdir - returns error when cant find repo' '
+test_expect_success '__gitdir - returns error when cannot find repo' '
 	(
 		__git_dir="non-existing" &&
 		test_must_fail __gitdir >"$actual"
@@ -945,7 +945,7 @@
 	rm -f .git/FETCH_HEAD
 '
 
-test_expect_success '__git_refs - dont filter refs unless told so' '
+test_expect_success '__git_refs - do not filter refs unless told so' '
 	cat >expected <<-EOF &&
 	HEAD
 	master
@@ -1257,7 +1257,7 @@
 		# In the following tests calling this function we only
 		# care about how __git_complete_index_file() deals with
 		# unusual characters in path names.  By requesting only
-		# untracked files we dont have to bother adding any
+		# untracked files we do not have to bother adding any
 		# paths to the index in those tests.
 		__git_complete_index_file --others &&
 		print_comp
@@ -1438,6 +1438,8 @@
 	--no-guess Z
 	--no-... Z
 	--overlay Z
+	--pathspec-file-nul Z
+	--pathspec-from-file=Z
 	EOF
 '
 
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index b299ecc..284c52d 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -308,7 +308,7 @@
 	total=$1
 
 	add_from=
-	if git -C "$indir" rev-parse --verify "$ref"
+	if git -C "$indir" rev-parse --quiet --verify "$ref"
 	then
 		add_from=t
 	fi
@@ -1012,19 +1012,30 @@
 	fi
 }
 
-# Tests that its two parameters refer to the same revision
+# Tests that its two parameters refer to the same revision, or if '!' is
+# provided first, that its other two parameters refer to different
+# revisions.
 test_cmp_rev () {
+	local op='=' wrong_result=different
+
+	if test $# -ge 1 && test "x$1" = 'x!'
+	then
+	    op='!='
+	    wrong_result='the same'
+	    shift
+	fi
 	if test $# != 2
 	then
 		error "bug in the test script: test_cmp_rev requires two revisions, but got $#"
 	else
 		local r1 r2
 		r1=$(git rev-parse --verify "$1") &&
-		r2=$(git rev-parse --verify "$2") &&
-		if test "$r1" != "$r2"
+		r2=$(git rev-parse --verify "$2") || return 1
+
+		if ! test "$r1" "$op" "$r2"
 		then
 			cat >&4 <<-EOF
-			error: two revisions point to different objects:
+			error: two revisions point to $wrong_result objects:
 			  '$1': $r1
 			  '$2': $r2
 			EOF
@@ -1175,6 +1186,34 @@
 	command "$PERL_PATH" "$@" 2>&7
 } 7>&2 2>&4
 
+# Given the name of an environment variable with a bool value, normalize
+# its value to a 0 (true) or 1 (false or empty string) return code.
+#
+#   test_bool_env GIT_TEST_HTTPD <default-value>
+#
+# Return with code corresponding to the given default value if the variable
+# is unset.
+# Abort the test script if either the value of the variable or the default
+# are not valid bool values.
+
+test_bool_env () {
+	if test $# != 2
+	then
+		BUG "test_bool_env requires two parameters (variable name and default value)"
+	fi
+
+	git env--helper --type=bool --default="$2" --exit-code "$1"
+	ret=$?
+	case $ret in
+	0|1)	# unset or valid bool value
+		;;
+	*)	# invalid bool value or something unexpected
+		error >&7 "test_bool_env requires bool values both for \$$1 and for the default fallback"
+		;;
+	esac
+	return $ret
+}
+
 # Exit the test suite, either by skipping all remaining tests or by
 # exiting with an error. If our prerequisite variable $1 falls back
 # on a default assume we were opportunistically trying to set up some
@@ -1183,7 +1222,7 @@
 # The error/skip message should be given by $2.
 #
 test_skip_or_die () {
-	if ! git env--helper --type=bool --default=false --exit-code $1
+	if ! test_bool_env "$1" false
 	then
 		skip_all=$2
 		test_done
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 46c4440..44df51b 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1004,6 +1004,12 @@
 		to_skip=t
 		skipped_reason="GIT_SKIP_TESTS"
 	fi
+	if test -z "$to_skip" && test -n "$run_list" &&
+	   ! match_test_selector_list '--run' $test_count "$run_list"
+	then
+		to_skip=t
+		skipped_reason="--run"
+	fi
 	if test -z "$to_skip" && test -n "$test_prereq" &&
 	   ! test_have_prereq "$test_prereq"
 	then
@@ -1016,12 +1022,6 @@
 		fi
 		skipped_reason="missing $missing_prereq${of_prereq}"
 	fi
-	if test -z "$to_skip" && test -n "$run_list" &&
-		! match_test_selector_list '--run' $test_count "$run_list"
-	then
-		to_skip=t
-		skipped_reason="--run"
-	fi
 
 	case "$to_skip" in
 	t)
@@ -1406,23 +1406,23 @@
 # The GIT_TEST_FAIL_PREREQS code hooks into test_set_prereq(), and
 # thus needs to be set up really early, and set an internal variable
 # for convenience so the hot test_set_prereq() codepath doesn't need
-# to call "git env--helper". Only do that work if needed by seeing if
-# GIT_TEST_FAIL_PREREQS is set at all.
+# to call "git env--helper" (via test_bool_env). Only do that work
+# if needed by seeing if GIT_TEST_FAIL_PREREQS is set at all.
 GIT_TEST_FAIL_PREREQS_INTERNAL=
 if test -n "$GIT_TEST_FAIL_PREREQS"
 then
-	if git env--helper --type=bool --default=0 --exit-code GIT_TEST_FAIL_PREREQS
+	if test_bool_env GIT_TEST_FAIL_PREREQS false
 	then
 		GIT_TEST_FAIL_PREREQS_INTERNAL=true
 		test_set_prereq FAIL_PREREQS
 	fi
 else
 	test_lazy_prereq FAIL_PREREQS '
-		git env--helper --type=bool --default=0 --exit-code GIT_TEST_FAIL_PREREQS
+		test_bool_env GIT_TEST_FAIL_PREREQS false
 	'
 fi
 
-# Fix some commands on Windows
+# Fix some commands on Windows, and other OS-specific things
 uname_s=$(uname -s)
 case $uname_s in
 *MINGW*)
@@ -1453,6 +1453,12 @@
 	test_set_prereq SED_STRIPS_CR
 	test_set_prereq GREP_STRIPS_CR
 	;;
+FreeBSD)
+	test_set_prereq REGEX_ILLSEQ
+	test_set_prereq POSIXPERM
+	test_set_prereq BSLASHPSPEC
+	test_set_prereq EXECKEEPSPID
+	;;
 *)
 	test_set_prereq POSIXPERM
 	test_set_prereq BSLASHPSPEC
@@ -1477,7 +1483,7 @@
 fi
 
 test_lazy_prereq C_LOCALE_OUTPUT '
-	! git env--helper --type=bool --default=0 --exit-code GIT_TEST_GETTEXT_POISON
+	! test_bool_env GIT_TEST_GETTEXT_POISON false
 '
 
 if test -z "$GIT_TEST_CHECK_CACHE_TREE"
diff --git a/tag.c b/tag.c
index bfa0e31..71b5444 100644
--- a/tag.c
+++ b/tag.c
@@ -141,7 +141,16 @@
 
 	if (item->object.parsed)
 		return 0;
-	item->object.parsed = 1;
+
+	if (item->tag) {
+		/*
+		 * Presumably left over from a previous failed parse;
+		 * clear it out in preparation for re-parsing (we'll probably
+		 * hit the same error, which lets us tell our current caller
+		 * about the problem).
+		 */
+		FREE_AND_NULL(item->tag);
+	}
 
 	if (size < the_hash_algo->hexsz + 24)
 		return -1;
@@ -167,10 +176,15 @@
 	} else if (!strcmp(type, tag_type)) {
 		item->tagged = (struct object *)lookup_tag(r, &oid);
 	} else {
-		error("Unknown type %s", type);
-		item->tagged = NULL;
+		return error("unknown tag type '%s' in %s",
+			     type, oid_to_hex(&item->object.oid));
 	}
 
+	if (!item->tagged)
+		return error("bad tag pointer to %s in %s",
+			     oid_to_hex(&oid),
+			     oid_to_hex(&item->object.oid));
+
 	if (bufptr + 4 < tail && starts_with(bufptr, "tag "))
 		; 		/* good */
 	else
@@ -187,6 +201,7 @@
 	else
 		item->date = 0;
 
+	item->object.parsed = 1;
 	return 0;
 }
 
diff --git a/tar.h b/tar.h
index 3467705..6b258c4 100644
--- a/tar.h
+++ b/tar.h
@@ -1,3 +1,6 @@
+#ifndef TAR_H
+#define TAR_H
+
 #define TYPEFLAG_AUTO		'\0'
 #define TYPEFLAG_REG		'0'
 #define TYPEFLAG_LNK		'2'
@@ -23,3 +26,5 @@
 	char devminor[8];	/* 337 */
 	char prefix[155];	/* 345 */
 };
+
+#endif /* TAR_H */
diff --git a/templates/hooks--fsmonitor-watchman.sample b/templates/hooks--fsmonitor-watchman.sample
index e673bb3..ef94fa2 100755
--- a/templates/hooks--fsmonitor-watchman.sample
+++ b/templates/hooks--fsmonitor-watchman.sample
@@ -22,7 +22,8 @@
 
 if ($version == 1) {
 	# convert nanoseconds to seconds
-	$time = int $time / 1000000000;
+	# subtract one second to make sure watchman will return all changes
+	$time = int ($time / 1000000000) - 1;
 } else {
 	die "Unsupported query-fsmonitor hook version '$version'.\n" .
 	    "Falling back to scanning...\n";
@@ -53,18 +54,12 @@
 	#
 	# To accomplish this, we're using the "since" generator to use the
 	# recency index to select candidate nodes and "fields" to limit the
-	# output to file names only. Then we're using the "expression" term to
-	# further constrain the results.
-	#
-	# The category of transient files that we want to ignore will have a
-	# creation clock (cclock) newer than $time_t value and will also not
-	# currently exist.
+	# output to file names only.
 
 	my $query = <<"	END";
 		["query", "$git_work_tree", {
 			"since": $time,
-			"fields": ["name"],
-			"expression": ["not", ["allof", ["since", $time, "cclock"], ["not", "exists"]]]
+			"fields": ["name"]
 		}]
 	END
 
diff --git a/trace.h b/trace.h
index 9fa3e7a..9826618 100644
--- a/trace.h
+++ b/trace.h
@@ -4,6 +4,82 @@
 #include "git-compat-util.h"
 #include "strbuf.h"
 
+/**
+ * The trace API can be used to print debug messages to stderr or a file. Trace
+ * code is inactive unless explicitly enabled by setting `GIT_TRACE*` environment
+ * variables.
+ *
+ * The trace implementation automatically adds `timestamp file:line ... \n` to
+ * all trace messages. E.g.:
+ *
+ * ------------
+ * 23:59:59.123456 git.c:312               trace: built-in: git 'foo'
+ * 00:00:00.000001 builtin/foo.c:99        foo: some message
+ * ------------
+ *
+ * Bugs & Caveats
+ * --------------
+ *
+ * GIT_TRACE_* environment variables can be used to tell Git to show
+ * trace output to its standard error stream. Git can often spawn a pager
+ * internally to run its subcommand and send its standard output and
+ * standard error to it.
+ *
+ * Because GIT_TRACE_PERFORMANCE trace is generated only at the very end
+ * of the program with atexit(), which happens after the pager exits, it
+ * would not work well if you send its log to the standard error output
+ * and let Git spawn the pager at the same time.
+ *
+ * As a work around, you can for example use '--no-pager', or set
+ * GIT_TRACE_PERFORMANCE to another file descriptor which is redirected
+ * to stderr, or set GIT_TRACE_PERFORMANCE to a file specified by its
+ * absolute path.
+ *
+ * For example instead of the following command which by default may not
+ * print any performance information:
+ *
+ * ------------
+ * GIT_TRACE_PERFORMANCE=2 git log -1
+ * ------------
+ *
+ * you may want to use:
+ *
+ * ------------
+ * GIT_TRACE_PERFORMANCE=2 git --no-pager log -1
+ * ------------
+ *
+ * or:
+ *
+ * ------------
+ * GIT_TRACE_PERFORMANCE=3 3>&2 git log -1
+ * ------------
+ *
+ * or:
+ *
+ * ------------
+ * GIT_TRACE_PERFORMANCE=/path/to/log/file git log -1
+ * ------------
+ *
+ */
+
+/**
+ * Defines a trace key (or category). The default (for API functions that
+ * don't take a key) is `GIT_TRACE`.
+ *
+ * E.g. to define a trace key controlled by environment variable `GIT_TRACE_FOO`:
+ *
+ * ------------
+ * static struct trace_key trace_foo = TRACE_KEY_INIT(FOO);
+ *
+ * static void trace_print_foo(const char *message)
+ * {
+ * 	trace_printf_key(&trace_foo, "%s", message);
+ * }
+ * ------------
+ *
+ * Note: don't use `const` as the trace implementation stores internal state in
+ * the `trace_key` structure.
+ */
 struct trace_key {
 	const char * const key;
 	int fd;
@@ -18,31 +94,84 @@
 extern struct trace_key trace_setup_key;
 
 void trace_repo_setup(const char *prefix);
+
+/**
+ * Checks whether the trace key is enabled. Used to prevent expensive
+ * string formatting before calling one of the printing APIs.
+ */
 int trace_want(struct trace_key *key);
+
+/**
+ * Disables tracing for the specified key, even if the environment variable
+ * was set.
+ */
 void trace_disable(struct trace_key *key);
+
+/**
+ * Returns nanoseconds since the epoch (01/01/1970), typically used
+ * for performance measurements.
+ * Currently there are high precision timer implementations for Linux (using
+ * `clock_gettime(CLOCK_MONOTONIC)`) and Windows (`QueryPerformanceCounter`).
+ * Other platforms use `gettimeofday` as time source.
+ */
 uint64_t getnanotime(void);
+
 void trace_command_performance(const char **argv);
 void trace_verbatim(struct trace_key *key, const void *buf, unsigned len);
 uint64_t trace_performance_enter(void);
 
 #ifndef HAVE_VARIADIC_MACROS
 
+/**
+ * Prints a formatted message, similar to printf.
+ */
 __attribute__((format (printf, 1, 2)))
 void trace_printf(const char *format, ...);
 
 __attribute__((format (printf, 2, 3)))
 void trace_printf_key(struct trace_key *key, const char *format, ...);
 
+/**
+ * Prints a formatted message, followed by a quoted list of arguments.
+ */
 __attribute__((format (printf, 2, 3)))
 void trace_argv_printf(const char **argv, const char *format, ...);
 
+/**
+ * Prints the strbuf, without additional formatting (i.e. doesn't
+ * choke on `%` or even `\0`).
+ */
 void trace_strbuf(struct trace_key *key, const struct strbuf *data);
 
-/* Prints elapsed time (in nanoseconds) if GIT_TRACE_PERFORMANCE is enabled. */
+/**
+ * Prints elapsed time (in nanoseconds) if GIT_TRACE_PERFORMANCE is enabled.
+ *
+ * Example:
+ * ------------
+ * uint64_t t = 0;
+ * for (;;) {
+ * 	// ignore
+ * t -= getnanotime();
+ * // code section to measure
+ * t += getnanotime();
+ * // ignore
+ * }
+ * trace_performance(t, "frotz");
+ * ------------
+ */
 __attribute__((format (printf, 2, 3)))
 void trace_performance(uint64_t nanos, const char *format, ...);
 
-/* Prints elapsed time since 'start' if GIT_TRACE_PERFORMANCE is enabled. */
+/**
+ * Prints elapsed time since 'start' if GIT_TRACE_PERFORMANCE is enabled.
+ *
+ * Example:
+ * ------------
+ * uint64_t start = getnanotime();
+ * // code section to measure
+ * trace_performance_since(start, "foobar");
+ * ------------
+ */
 __attribute__((format (printf, 2, 3)))
 void trace_performance_since(uint64_t start, const char *format, ...);
 
diff --git a/trace2.h b/trace2.h
index 050bf3c..e5e81c0 100644
--- a/trace2.h
+++ b/trace2.h
@@ -1,6 +1,40 @@
 #ifndef TRACE2_H
 #define TRACE2_H
 
+/**
+ * The Trace2 API can be used to print debug, performance, and telemetry
+ * information to stderr or a file.  The Trace2 feature is inactive unless
+ * explicitly enabled by enabling one or more Trace2 Targets.
+ *
+ * The Trace2 API is intended to replace the existing (Trace1)
+ * printf-style tracing provided by the existing `GIT_TRACE` and
+ * `GIT_TRACE_PERFORMANCE` facilities.  During initial implementation,
+ * Trace2 and Trace1 may operate in parallel.
+ *
+ * The Trace2 API defines a set of high-level messages with known fields,
+ * such as (`start`: `argv`) and (`exit`: {`exit-code`, `elapsed-time`}).
+ *
+ * Trace2 instrumentation throughout the Git code base sends Trace2
+ * messages to the enabled Trace2 Targets.  Targets transform these
+ * messages content into purpose-specific formats and write events to
+ * their data streams.  In this manner, the Trace2 API can drive
+ * many different types of analysis.
+ *
+ * Targets are defined using a VTable allowing easy extension to other
+ * formats in the future.  This might be used to define a binary format,
+ * for example.
+ *
+ * Trace2 is controlled using `trace2.*` config values in the system and
+ * global config files and `GIT_TRACE2*` environment variables.  Trace2 does
+ * not read from repo local or worktree config files or respect `-c`
+ * command line config settings.
+ *
+ * For more info about: trace2 targets, conventions for public functions and
+ * macros, trace2 target formats and examples on trace2 API usage refer to
+ * Documentation/technical/api-trace2.txt
+ *
+ */
+
 struct child_process;
 struct repository;
 struct json_writer;
@@ -39,7 +73,12 @@
 /*
  * Initialize TRACE2 tracing facility if any of the builtin TRACE2
  * targets are enabled in the system config or the environment.
- * Emits a 'version' event.
+ * This includes setting up the Trace2 thread local storage (TLS).
+ * Emits a 'version' message containing the version of git
+ * and the Trace2 protocol.
+ *
+ * This function should be called from `main()` as early as possible in
+ * the life of the process after essential process initialization.
  *
  * Cleanup/Termination is handled automatically by a registered
  * atexit() routine.
@@ -49,7 +88,7 @@
 #define trace2_initialize() trace2_initialize_fl(__FILE__, __LINE__)
 
 /*
- * Return true if trace2 is enabled.
+ * Return 1 if trace2 is enabled (at least one target is active).
  */
 int trace2_is_enabled(void);
 
@@ -114,7 +153,8 @@
 #define trace2_cmd_mode(sv) trace2_cmd_mode_fl(__FILE__, __LINE__, (sv))
 
 /*
- * Emit an 'alias' expansion event.
+ * Emits an "alias" message containing the alias used and the argument
+ * expansion.
  */
 void trace2_cmd_alias_fl(const char *file, int line, const char *alias,
 			 const char **argv);
@@ -123,7 +163,7 @@
 	trace2_cmd_alias_fl(__FILE__, __LINE__, (alias), (argv))
 
 /*
- * Emit one or more 'def_param' events for "interesting" configuration
+ * Emit one or more 'def_param' events for "important" configuration
  * settings.
  *
  * Use the TR2_SYSENV_CFG_PARAM setting to register a comma-separated
@@ -144,7 +184,7 @@
 
 /*
  * Emit a "def_param" event for the given config key/value pair IF
- * we consider the key to be "interesting".
+ * we consider the key to be "important".
  *
  * Use this for new/updated config settings created/updated after
  * trace2_cmd_list_config() is called.
@@ -155,20 +195,34 @@
 #define trace2_cmd_set_config(k, v) \
 	trace2_cmd_set_config_fl(__FILE__, __LINE__, (k), (v))
 
-/*
- * Emit a 'child_start' event prior to spawning a child process.
+/**
+ * Emits a "child_start" message containing the "child-id",
+ * "child-argv", and "child-classification".
  *
  * Before calling optionally set "cmd->trace2_child_class" to a string
  * describing the type of the child process.  For example, "editor" or
  * "pager".
+ *
+ * This function assigns a unique "child-id" to `cmd->trace2_child_id`.
+ * This field is used later during the "child_exit" message to associate
+ * it with the "child_start" message.
+ *
+ * This function should be called before spawning the child process.
  */
 void trace2_child_start_fl(const char *file, int line,
 			   struct child_process *cmd);
 
 #define trace2_child_start(cmd) trace2_child_start_fl(__FILE__, __LINE__, (cmd))
 
-/*
- * Emit a 'child_exit' event after the child process completes.
+/**
+ * Emits a "child_exit" message containing the "child-id",
+ * the child's elapsed time and exit-code.
+ *
+ * The reported elapsed time includes the process creation overhead and
+ * time spend waiting for it to exit, so it may be slightly longer than
+ * the time reported by the child itself.
+ *
+ * This function should be called after reaping the child process.
  */
 void trace2_child_exit_fl(const char *file, int line, struct child_process *cmd,
 			  int child_exit_code);
@@ -176,21 +230,22 @@
 #define trace2_child_exit(cmd, code) \
 	trace2_child_exit_fl(__FILE__, __LINE__, (cmd), (code))
 
-/*
+/**
  * Emit an 'exec' event prior to calling one of exec(), execv(),
  * execvp(), and etc.  On Unix-derived systems, this will be the
  * last event emitted for the current process, unless the exec
  * fails.  On Windows, exec() behaves like 'child_start' and a
  * waitpid(), so additional events may be emitted.
  *
- * Returns the "exec_id".
+ * Returns a unique "exec-id".  This value is used later
+ * if the exec() fails and a "exec-result" message is necessary.
  */
 int trace2_exec_fl(const char *file, int line, const char *exe,
 		   const char **argv);
 
 #define trace2_exec(exe, argv) trace2_exec_fl(__FILE__, __LINE__, (exe), (argv))
 
-/*
+/**
  * Emit an 'exec_result' when possible.  On Unix-derived systems,
  * this should be called after exec() returns (which only happens
  * when there is an error starting the new process).  On Windows,
@@ -226,11 +281,12 @@
 #define trace2_thread_exit() trace2_thread_exit_fl(__FILE__, __LINE__)
 
 /*
- * Emit a 'param' event.
+ * Emits a "def_param" message containing a key/value pair.
  *
- * Write a "<param> = <value>" pair describing some aspect of the
- * run such as an important configuration setting or command line
- * option that significantly changes command behavior.
+ * This message is intended to report some global aspect of the current
+ * command, such as a configuration setting or command line switch that
+ * significantly affects program performance or behavior, such as
+ * `core.abbrev`, `status.showUntrackedFiles`, or `--no-ahead-behind`.
  */
 void trace2_def_param_fl(const char *file, int line, const char *param,
 			 const char *value);
@@ -243,18 +299,35 @@
  * a trace2-repo-id to be used in subsequent activity events.
  *
  * Emits a 'worktree' event for this repo instance.
+ *
+ * Region and data messages may refer to this repo-id.
+ *
+ * The main/top-level repository will have repo-id value 1 (aka "r1").
+ *
+ * The repo-id field is in anticipation of future in-proc submodule
+ * repositories.
  */
 void trace2_def_repo_fl(const char *file, int line, struct repository *repo);
 
 #define trace2_def_repo(repo) trace2_def_repo_fl(__FILE__, __LINE__, repo)
 
-/*
+/**
  * Emit a 'region_enter' event for <category>.<label> with optional
  * repo-id and printf message.
  *
- * Enter a new nesting level on the current thread and remember the
- * current time.  This controls the indenting of all subsequent events
- * on this thread.
+ * This function pushes a new region nesting stack level on the current
+ * thread and starts a clock for the new stack frame.
+ *
+ * The `category` field is an arbitrary category name used to classify
+ * regions by feature area, such as "status" or "index".  At this time
+ * it is only just printed along with the rest of the message.  It may
+ * be used in the future to filter messages.
+ *
+ * The `label` field is an arbitrary label used to describe the activity
+ * being started, such as "read_recursive" or "do_read_index".
+ *
+ * The `repo` field, if set, will be used to get the "repo-id", so that
+ * recursive oerations can be attributed to the correct repository.
  */
 void trace2_region_enter_fl(const char *file, int line, const char *category,
 			    const char *label, const struct repository *repo, ...);
@@ -289,12 +362,17 @@
 /* clang-format on */
 #endif
 
-/*
+/**
  * Emit a 'region_leave' event for <category>.<label> with optional
  * repo-id and printf message.
  *
  * Leave current nesting level and report the elapsed time spent
  * in this nesting level.
+ *
+ * The `category`, `label`, and `repo` fields are the same as
+ * trace2_region_enter_fl. The `category` and `label` do not
+ * need to match the corresponding "region_enter" message,
+ * but it makes the data stream easier to understand.
  */
 void trace2_region_leave_fl(const char *file, int line, const char *category,
 			    const char *label, const struct repository *repo, ...);
@@ -329,10 +407,12 @@
 /* clang-format on */
 #endif
 
-/*
+/**
  * Emit a key-value pair 'data' event of the form <category>.<key> = <value>.
  * This event implicitly contains information about thread, nesting region,
  * and optional repo-id.
+ * This could be used to print the number of files in a directory during
+ * a multi-threaded recursive tree walk.
  *
  * On event-based TRACE2 targets, this generates a 'data' event suitable
  * for post-processing.  On printf-based TRACE2 targets, this is converted
diff --git a/trace2/tr2_sid.c b/trace2/tr2_sid.c
index 6948fd4..dc6e75e 100644
--- a/trace2/tr2_sid.c
+++ b/trace2/tr2_sid.c
@@ -19,7 +19,7 @@
  *    "H<first_8_chars_of_sha1_of_hostname>"
  *    "Localhost" when no hostname.
  *
- * where <process> is a 9 character string containing the least signifcant
+ * where <process> is a 9 character string containing the least significant
  * 32 bits in the process-id.
  *    "P<pid>"
  * (This is an abribrary choice.  On most systems pid_t is a 32 bit value,
diff --git a/trace2/tr2_tgt_perf.c b/trace2/tr2_tgt_perf.c
index ffac802..a8018f1 100644
--- a/trace2/tr2_tgt_perf.c
+++ b/trace2/tr2_tgt_perf.c
@@ -26,12 +26,9 @@
 #define TR2FMT_PERF_REPO_WIDTH (3)
 #define TR2FMT_PERF_CATEGORY_WIDTH (12)
 
-#define TR2_DOTS_BUFFER_SIZE (100)
 #define TR2_INDENT (2)
 #define TR2_INDENT_LENGTH(ctx) (((ctx)->nr_open_regions - 1) * TR2_INDENT)
 
-static struct strbuf dots = STRBUF_INIT;
-
 static int fn_init(void)
 {
 	int want = tr2_dst_trace_want(&tr2dst_perf);
@@ -41,8 +38,6 @@
 	if (!want)
 		return want;
 
-	strbuf_addchars(&dots, '.', TR2_DOTS_BUFFER_SIZE);
-
 	brief = tr2_sysenv_get(TR2_SYSENV_PERF_BRIEF);
 	if (brief && *brief &&
 	    ((want_brief = git_parse_maybe_bool(brief)) != -1))
@@ -54,8 +49,6 @@
 static void fn_term(void)
 {
 	tr2_dst_trace_disable(&tr2dst_perf);
-
-	strbuf_release(&dots);
 }
 
 /*
@@ -138,14 +131,8 @@
 	strbuf_addf(buf, "%-*.*s | ", TR2FMT_PERF_CATEGORY_WIDTH,
 		    TR2FMT_PERF_CATEGORY_WIDTH, (category ? category : ""));
 
-	if (ctx->nr_open_regions > 0) {
-		int len_indent = TR2_INDENT_LENGTH(ctx);
-		while (len_indent > dots.len) {
-			strbuf_addbuf(buf, &dots);
-			len_indent -= dots.len;
-		}
-		strbuf_addf(buf, "%.*s", len_indent, dots.buf);
-	}
+	if (ctx->nr_open_regions > 0)
+		strbuf_addchars(buf, '.', TR2_INDENT_LENGTH(ctx));
 }
 
 static void perf_io_write_fl(const char *file, int line, const char *event_name,
diff --git a/transport-helper.c b/transport-helper.c
index a9d6902..413d9d8 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -435,6 +435,7 @@
 	child_process_init(fastimport);
 	fastimport->in = xdup(helper->out);
 	argv_array_push(&fastimport->args, "fast-import");
+	argv_array_push(&fastimport->args, "--allow-unsafe-features");
 	argv_array_push(&fastimport->args, debug ? "--stats" : "--quiet");
 
 	if (data->bidi_import) {
diff --git a/tree-walk.c b/tree-walk.c
index bea819d..d5a8e09 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -1124,7 +1124,7 @@
 		 * later on.
 		 * max_depth is ignored but we may consider support it
 		 * in future, see
-		 * https://public-inbox.org/git/7vmxo5l2g4.fsf@alter.siamese.dyndns.org/
+		 * https://lore.kernel.org/git/7vmxo5l2g4.fsf@alter.siamese.dyndns.org/
 		 */
 		if (ps->recursive && S_ISDIR(entry->mode))
 			return entry_interesting;
diff --git a/tree-walk.h b/tree-walk.h
index abe2caf..826396c 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -3,6 +3,13 @@
 
 #include "cache.h"
 
+/**
+ * The tree walking API is used to traverse and inspect trees.
+ */
+
+/**
+ * An entry in a tree. Each entry has a sha1 identifier, pathname, and mode.
+ */
 struct name_entry {
 	struct object_id oid;
 	const char *path;
@@ -10,12 +17,29 @@
 	unsigned int mode;
 };
 
+/**
+ * A semi-opaque data structure used to maintain the current state of the walk.
+ */
 struct tree_desc {
+	/*
+	 * pointer into the memory representation of the tree. It always
+	 * points at the current entry being visited.
+	 */
 	const void *buffer;
+
+	/* points to the current entry being visited. */
 	struct name_entry entry;
+
+	/* counts the number of bytes left in the `buffer`. */
 	unsigned int size;
 };
 
+/**
+ * Decode the entry currently being visited (the one pointed to by
+ * `tree_desc's` `entry` member) and return the sha1 of the entry. The
+ * `pathp` and `modep` arguments are set to the entry's pathname and mode
+ * respectively.
+ */
 static inline const struct object_id *tree_entry_extract(struct tree_desc *desc, const char **pathp, unsigned short *modep)
 {
 	*pathp = desc->entry.path;
@@ -23,6 +47,11 @@
 	return &desc->entry.oid;
 }
 
+/**
+ * Calculate the length of a tree entry's pathname. This utilizes the
+ * memory structure of a tree entry to avoid the overhead of using a
+ * generic strlen().
+ */
 static inline int tree_entry_len(const struct name_entry *ne)
 {
 	return ne->pathlen;
@@ -33,52 +62,141 @@
  * corrupt tree entry rather than dying,
  */
 
+/**
+ * Walk to the next entry in a tree. This is commonly used in conjunction
+ * with `tree_entry_extract` to inspect the current entry.
+ */
 void update_tree_entry(struct tree_desc *);
+
 int update_tree_entry_gently(struct tree_desc *);
+
+/**
+ * Initialize a `tree_desc` and decode its first entry. The buffer and
+ * size parameters are assumed to be the same as the buffer and size
+ * members of `struct tree`.
+ */
 void init_tree_desc(struct tree_desc *desc, const void *buf, unsigned long size);
+
 int init_tree_desc_gently(struct tree_desc *desc, const void *buf, unsigned long size);
 
 /*
- * Helper function that does both tree_entry_extract() and update_tree_entry()
- * and returns true for success
+ * Visit the next entry in a tree. Returns 1 when there are more entries
+ * left to visit and 0 when all entries have been visited. This is
+ * commonly used in the test of a while loop.
  */
 int tree_entry(struct tree_desc *, struct name_entry *);
+
 int tree_entry_gently(struct tree_desc *, struct name_entry *);
 
+/**
+ * Initialize a `tree_desc` and decode its first entry given the
+ * object ID of a tree. Returns the `buffer` member if the latter
+ * is a valid tree identifier and NULL otherwise.
+ */
 void *fill_tree_descriptor(struct repository *r,
 			   struct tree_desc *desc,
 			   const struct object_id *oid);
 
 struct traverse_info;
 typedef int (*traverse_callback_t)(int n, unsigned long mask, unsigned long dirmask, struct name_entry *entry, struct traverse_info *);
+
+/**
+ * Traverse `n` number of trees in parallel. The `fn` callback member of
+ * `traverse_info` is called once for each tree entry.
+ */
 int traverse_trees(struct index_state *istate, int n, struct tree_desc *t, struct traverse_info *info);
 
 enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r, struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned short *mode);
 
+/**
+ * A structure used to maintain the state of a traversal.
+ */
 struct traverse_info {
 	const char *traverse_path;
+
+	/*
+	 * points to the traverse_info which was used to descend into the
+	 * current tree. If this is the top-level tree `prev` will point to
+	 * a dummy traverse_info.
+	 */
 	struct traverse_info *prev;
+
+	/* is the entry for the current tree (if the tree is a subtree). */
 	const char *name;
+
 	size_t namelen;
 	unsigned mode;
 
+	/* is the length of the full path for the current tree. */
 	size_t pathlen;
+
 	struct pathspec *pathspec;
 
+	/* can be used by callbacks to maintain directory-file conflicts. */
 	unsigned long df_conflicts;
+
+	/* a callback called for each entry in the tree.
+	 *
+	 * The arguments passed to the traverse callback are as follows:
+	 *
+	 * - `n` counts the number of trees being traversed.
+	 *
+	 * - `mask` has its nth bit set if something exists in the nth entry.
+	 *
+	 * - `dirmask` has its nth bit set if the nth tree's entry is a directory.
+	 *
+	 * - `entry` is an array of size `n` where the nth entry is from the nth tree.
+	 *
+	 * - `info` maintains the state of the traversal.
+	 *
+	 * Returning a negative value will terminate the traversal. Otherwise the
+	 * return value is treated as an update mask. If the nth bit is set the nth tree
+	 * will be updated and if the bit is not set the nth tree entry will be the
+	 * same in the next callback invocation.
+	 */
 	traverse_callback_t fn;
+
+	/* can be anything the `fn` callback would want to use. */
 	void *data;
+
+	/* tells whether to stop at the first error or not. */
 	int show_all_errors;
 };
 
+/**
+ * Find an entry in a tree given a pathname and the sha1 of a tree to
+ * search. Returns 0 if the entry is found and -1 otherwise. The third
+ * and fourth parameters are set to the entry's sha1 and mode respectively.
+ */
 int get_tree_entry(struct repository *, const struct object_id *, const char *, struct object_id *, unsigned short *);
+
+/**
+ * Generate the full pathname of a tree entry based from the root of the
+ * traversal. For example, if the traversal has recursed into another
+ * tree named "bar" the pathname of an entry "baz" in the "bar"
+ * tree would be "bar/baz".
+ */
 char *make_traverse_path(char *path, size_t pathlen, const struct traverse_info *info,
 			 const char *name, size_t namelen);
+
+/**
+ * Convenience wrapper to `make_traverse_path` into a strbuf.
+ */
 void strbuf_make_traverse_path(struct strbuf *out,
 			       const struct traverse_info *info,
 			       const char *name, size_t namelen);
+
+/**
+ * Initialize a `traverse_info` given the pathname of the tree to start
+ * traversing from.
+ */
 void setup_traverse_info(struct traverse_info *info, const char *base);
 
+/**
+ * Calculate the length of a pathname returned by `make_traverse_path`.
+ * This utilizes the memory structure of a tree entry to avoid the
+ * overhead of using a generic strlen().
+ */
 static inline size_t traverse_path_len(const struct traverse_info *info,
 				       size_t namelen)
 {
diff --git a/unpack-trees.c b/unpack-trees.c
index 3789a22..2399b68 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -275,9 +275,9 @@
 }
 
 /*
- * Preform the loading of the repository's gitmodules file.  This function is
+ * Perform the loading of the repository's gitmodules file.  This function is
  * used by 'check_update()' to perform loading of the gitmodules file in two
- * differnt situations:
+ * different situations:
  * (1) before removing entries from the working tree if the gitmodules file has
  *     been marked for removal.  This situation is specified by 'state' == NULL.
  * (2) before checking out entries to the working tree if the gitmodules file
@@ -1544,6 +1544,9 @@
 	o->merge_size = len;
 	mark_all_ce_unused(o->src_index);
 
+	if (o->src_index->fsmonitor_last_update)
+		o->result.fsmonitor_last_update = o->src_index->fsmonitor_last_update;
+
 	/*
 	 * Sparse checkout loop #1: set NEW_SKIP_WORKTREE on existing entries
 	 */
@@ -2104,7 +2107,8 @@
 		invalidate_ce_path(old, o);
 	}
 
-	do_add_entry(o, merge, update, CE_STAGEMASK);
+	if (do_add_entry(o, merge, update, CE_STAGEMASK) < 0)
+		return -1;
 	return 1;
 }
 
@@ -2428,7 +2432,8 @@
 
 	if (old && same(old, a)) {
 		int update = 0;
-		if (o->reset && o->update && !ce_uptodate(old) && !ce_skip_worktree(old)) {
+		if (o->reset && o->update && !ce_uptodate(old) && !ce_skip_worktree(old) &&
+			!(old->ce_flags & CE_FSMONITOR_VALID)) {
 			struct stat st;
 			if (lstat(old->name, &st) ||
 			    ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE))
diff --git a/url.c b/url.c
index e34e5e7..e04bd60 100644
--- a/url.c
+++ b/url.c
@@ -5,7 +5,7 @@
 {
 	/*
 	 * The set of valid URL schemes, as per STD66 (RFC3986) is
-	 * '[A-Za-z][A-Za-z0-9+.-]*'. But use sightly looser check
+	 * '[A-Za-z][A-Za-z0-9+.-]*'. But use slightly looser check
 	 * of '[A-Za-z0-9][A-Za-z0-9+.-]*' because earlier version
 	 * of check used '[A-Za-z0-9]+' so not to break any remote
 	 * helpers.
diff --git a/usage.c b/usage.c
index 2fdb200..58fb5ff 100644
--- a/usage.c
+++ b/usage.c
@@ -9,14 +9,26 @@
 void vreportf(const char *prefix, const char *err, va_list params)
 {
 	char msg[4096];
-	char *p;
+	char *p, *pend = msg + sizeof(msg);
+	size_t prefix_len = strlen(prefix);
 
-	vsnprintf(msg, sizeof(msg), err, params);
-	for (p = msg; *p; p++) {
+	if (sizeof(msg) <= prefix_len) {
+		fprintf(stderr, "BUG!!! too long a prefix '%s'\n", prefix);
+		abort();
+	}
+	memcpy(msg, prefix, prefix_len);
+	p = msg + prefix_len;
+	if (vsnprintf(p, pend - p, err, params) < 0)
+		*p = '\0'; /* vsnprintf() failed, clip at prefix */
+
+	for (; p != pend - 1 && *p; p++) {
 		if (iscntrl(*p) && *p != '\t' && *p != '\n')
 			*p = '?';
 	}
-	fprintf(stderr, "%s%s\n", prefix, msg);
+
+	*(p++) = '\n'; /* we no longer need a NUL */
+	fflush(stderr);
+	write_in_full(2, msg, p - msg);
 }
 
 static NORETURN void usage_builtin(const char *err, va_list params)
diff --git a/userdiff.c b/userdiff.c
index e187d35..efbe05e 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -32,6 +32,19 @@
 	 /* Property names and math operators */
 	 "[a-zA-Z0-9,._+?#-]+"
 	 "|[-+*/%&^|!~]|>>|<<|&&|\\|\\|"),
+PATTERNS("elixir",
+	 "^[ \t]*((def(macro|module|impl|protocol|p)?|test)[ \t].*)$",
+	 /* -- */
+	 /* Atoms, names, and module attributes */
+	 "[@:]?[a-zA-Z0-9@_?!]+"
+	 /* Numbers with specific base */
+	 "|[-+]?0[xob][0-9a-fA-F]+"
+	 /* Numbers */
+	 "|[-+]?[0-9][0-9_.]*([eE][-+]?[0-9_]+)?"
+	 /* Operators and atoms that represent them */
+	 "|:?(\\+\\+|--|\\.\\.|~~~|<>|\\^\\^\\^|<?\\|>|<<<?|>?>>|<<?~|~>?>|<~>|<=|>=|===?|!==?|=~|&&&?|\\|\\|\\|?|=>|<-|\\\\\\\\|->)"
+	 /* Not real operators, but should be grouped */
+	 "|:?%[A-Za-z0-9_.]\\{\\}?"),
 IPATTERN("fortran",
 	 "!^([C*]|[ \t]*!)\n"
 	 "!^[ \t]*MODULE[ \t]+PROCEDURE[ \t]\n"
@@ -133,7 +146,7 @@
 	 "[a-zA-Z_][a-zA-Z0-9_]*"
 	 "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+"
 	 "|[-+*/<>%&^|=!.]=|--|\\+\\+|<<=?|>>=?|===|&&|\\|\\||::|->"),
-PATTERNS("python", "^[ \t]*((class|def)[ \t].*)$",
+PATTERNS("python", "^[ \t]*((class|(async[ \t]+)?def)[ \t].*)$",
 	 /* -- */
 	 "[a-zA-Z_][a-zA-Z0-9_]*"
 	 "|[-+0-9.e]+[jJlL]?|0[xX]?[0-9a-fA-F]+[lL]?"
diff --git a/utf8.c b/utf8.c
index 5c8f151..5b39361 100644
--- a/utf8.c
+++ b/utf8.c
@@ -411,11 +411,10 @@
  */
 static int same_utf_encoding(const char *src, const char *dst)
 {
-	if (istarts_with(src, "utf") && istarts_with(dst, "utf")) {
-		/* src[3] or dst[3] might be '\0' */
-		int i = (src[3] == '-' ? 4 : 3);
-		int j = (dst[3] == '-' ? 4 : 3);
-		return !strcasecmp(src+i, dst+j);
+	if (skip_iprefix(src, "utf", &src) && skip_iprefix(dst, "utf", &dst)) {
+		skip_prefix(src, "-", &src);
+		skip_prefix(dst, "-", &dst);
+		return !strcasecmp(src, dst);
 	}
 	return 0;
 }
diff --git a/xdiff-interface.h b/xdiff-interface.h
index ede4246..93df269 100644
--- a/xdiff-interface.h
+++ b/xdiff-interface.h
@@ -44,7 +44,7 @@
  * Compare the strings l1 with l2 which are of size s1 and s2 respectively.
  * Returns 1 if the strings are deemed equal, 0 otherwise.
  * The `flags` given as XDF_WHITESPACE_FLAGS determine how white spaces
- * are treated for the comparision.
+ * are treated for the comparison.
  */
 int xdiff_compare_lines(const char *l1, long s1,
 			const char *l2, long s2, long flags);
diff --git a/xdiff/xemit.c b/xdiff/xemit.c
index 30713ae..9d7d6c5 100644
--- a/xdiff/xemit.c
+++ b/xdiff/xemit.c
@@ -172,10 +172,12 @@
 	struct func_line func_line = { 0 };
 
 	for (xch = xscr; xch; xch = xche->next) {
+		xdchange_t *xchp = xch;
 		xche = xdl_get_hunk(&xch, xecfg);
 		if (!xch)
 			break;
 
+pre_context_calculation:
 		s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0);
 		s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0);
 
@@ -212,6 +214,21 @@
 			if (fs1 < s1) {
 				s2 = XDL_MAX(s2 - (s1 - fs1), 0);
 				s1 = fs1;
+
+				/*
+				 * Did we extend context upwards into an
+				 * ignored change?
+				 */
+				while (xchp != xch &&
+				       xchp->i1 + xchp->chg1 <= s1 &&
+				       xchp->i2 + xchp->chg2 <= s2)
+					xchp = xchp->next;
+
+				/* If so, show it after all. */
+				if (xchp != xch) {
+					xch = xchp;
+					goto pre_context_calculation;
+				}
 			}
 		}