summary refs log tree commit
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Documentation/CodingGuidelines4
-rw-r--r--Documentation/Makefile1
-rw-r--r--Documentation/MyFirstContribution.txt53
-rw-r--r--Documentation/MyFirstObjectWalk.txt906
-rw-r--r--Documentation/RelNotes/1.5.0.txt4
-rw-r--r--Documentation/RelNotes/1.6.5.4.txt2
-rw-r--r--Documentation/RelNotes/1.7.0.2.txt2
-rw-r--r--Documentation/RelNotes/1.7.10.4.txt2
-rw-r--r--Documentation/RelNotes/1.7.12.3.txt2
-rw-r--r--Documentation/RelNotes/1.7.5.3.txt2
-rw-r--r--Documentation/RelNotes/1.8.0.txt2
-rw-r--r--Documentation/RelNotes/1.8.4.1.txt2
-rw-r--r--Documentation/RelNotes/2.1.3.txt2
-rw-r--r--Documentation/RelNotes/2.10.0.txt2
-rw-r--r--Documentation/RelNotes/2.10.2.txt2
-rw-r--r--Documentation/RelNotes/2.11.1.txt2
-rw-r--r--Documentation/RelNotes/2.12.0.txt2
-rw-r--r--Documentation/RelNotes/2.13.0.txt2
-rw-r--r--Documentation/RelNotes/2.13.3.txt4
-rw-r--r--Documentation/RelNotes/2.14.0.txt4
-rw-r--r--Documentation/RelNotes/2.16.0.txt2
-rw-r--r--Documentation/RelNotes/2.16.3.txt2
-rw-r--r--Documentation/RelNotes/2.17.0.txt2
-rw-r--r--Documentation/RelNotes/2.18.0.txt2
-rw-r--r--Documentation/RelNotes/2.19.0.txt2
-rw-r--r--Documentation/RelNotes/2.20.0.txt2
-rw-r--r--Documentation/RelNotes/2.24.0.txt99
-rw-r--r--Documentation/RelNotes/2.25.0.txt68
-rw-r--r--Documentation/RelNotes/2.3.3.txt2
-rw-r--r--Documentation/RelNotes/2.3.7.txt2
-rw-r--r--Documentation/RelNotes/2.4.3.txt2
-rw-r--r--Documentation/RelNotes/2.7.0.txt2
-rw-r--r--Documentation/RelNotes/2.8.0.txt2
-rw-r--r--Documentation/RelNotes/2.9.3.txt2
-rw-r--r--Documentation/config.txt2
-rw-r--r--Documentation/config/core.txt10
-rw-r--r--Documentation/config/format.txt8
-rw-r--r--Documentation/config/pack.txt4
-rw-r--r--Documentation/config/tag.txt2
-rw-r--r--Documentation/fetch-options.txt4
-rw-r--r--Documentation/git-am.txt2
-rw-r--r--Documentation/git-bisect-lk2009.txt2
-rw-r--r--Documentation/git-bisect.txt2
-rw-r--r--Documentation/git-bundle.txt35
-rw-r--r--Documentation/git-check-attr.txt2
-rw-r--r--Documentation/git-check-ignore.txt2
-rw-r--r--Documentation/git-clone.txt8
-rw-r--r--Documentation/git-commit-graph.txt12
-rw-r--r--Documentation/git-cvsserver.txt2
-rw-r--r--Documentation/git-diff.txt2
-rw-r--r--Documentation/git-fast-export.txt2
-rw-r--r--Documentation/git-filter-branch.txt4
-rw-r--r--Documentation/git-format-patch.txt25
-rw-r--r--Documentation/git-multi-pack-index.txt6
-rw-r--r--Documentation/git-notes.txt6
-rw-r--r--Documentation/git-range-diff.txt2
-rw-r--r--Documentation/git-read-tree.txt2
-rw-r--r--Documentation/git-rebase.txt4
-rw-r--r--Documentation/git-rev-parse.txt7
-rw-r--r--Documentation/git-shortlog.txt3
-rw-r--r--Documentation/git-sparse-checkout.txt153
-rw-r--r--Documentation/git-stash.txt5
-rw-r--r--Documentation/git-tag.txt2
-rw-r--r--Documentation/git-update-index.txt8
-rw-r--r--Documentation/git.txt4
-rw-r--r--Documentation/gitattributes.txt8
-rw-r--r--Documentation/gitmodules.txt2
-rw-r--r--Documentation/gitremote-helpers.txt5
-rw-r--r--Documentation/gitrepository-layout.txt10
-rw-r--r--Documentation/gitsubmodules.txt2
-rw-r--r--Documentation/howto/separating-topic-branches.txt2
-rw-r--r--Documentation/manpage-bold-literal.xsl3
-rw-r--r--Documentation/merge-options.txt2
-rw-r--r--Documentation/merge-strategies.txt2
-rw-r--r--Documentation/pretty-formats.txt6
-rw-r--r--Documentation/rev-list-options.txt11
-rw-r--r--Documentation/technical/api-config.txt319
-rw-r--r--Documentation/technical/api-grep.txt8
-rw-r--r--Documentation/technical/api-object-access.txt15
-rw-r--r--Documentation/technical/api-quote.txt10
-rw-r--r--Documentation/technical/api-submodule-config.txt2
-rw-r--r--Documentation/technical/api-trace2.txt14
-rw-r--r--Documentation/technical/api-xdiff-interface.txt7
-rw-r--r--Documentation/technical/commit-graph.txt12
-rw-r--r--Documentation/technical/hash-function-transition.txt4
-rw-r--r--Documentation/technical/index-format.txt4
-rw-r--r--Documentation/technical/pack-protocol.txt2
-rw-r--r--Documentation/technical/partial-clone.txt2
-rw-r--r--Documentation/technical/protocol-v2.txt2
-rw-r--r--Documentation/technical/rerere.txt2
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--INSTALL6
-rw-r--r--Makefile5
l---------RelNotes2
-rw-r--r--apply.c6
-rw-r--r--azure-pipelines.yml4
-rw-r--r--builtin.h1
-rw-r--r--builtin/blame.c32
-rw-r--r--builtin/bundle.c217
-rw-r--r--builtin/clone.c38
-rw-r--r--builtin/commit-graph.c69
-rw-r--r--builtin/commit.c22
-rw-r--r--builtin/fetch.c19
-rw-r--r--builtin/fsck.c126
-rw-r--r--builtin/gc.c4
-rw-r--r--builtin/grep.c1
-rw-r--r--builtin/log.c141
-rw-r--r--builtin/multi-pack-index.c18
-rw-r--r--builtin/notes.c2
-rw-r--r--builtin/pack-objects.c21
-rw-r--r--builtin/read-tree.c3
-rw-r--r--builtin/rebase.c7
-rw-r--r--builtin/repack.c9
-rw-r--r--builtin/rev-parse.c11
-rw-r--r--builtin/sparse-checkout.c488
-rw-r--r--builtin/stash.c14
-rw-r--r--builtin/update-index.c6
-rw-r--r--builtin/worktree.c2
-rw-r--r--bundle.c9
-rw-r--r--bundle.h3
-rw-r--r--cache.h14
-rwxr-xr-xci/install-dependencies.sh6
-rw-r--r--column.c13
-rw-r--r--command-list.txt2
-rw-r--r--commit-graph.c18
-rw-r--r--commit-reach.c1
-rw-r--r--commit.c57
-rw-r--r--commit.h2
-rw-r--r--compat/mingw.c4
-rw-r--r--compat/mingw.h2
-rw-r--r--compat/nedmalloc/malloc.c.h6
-rw-r--r--compat/obstack.h2
-rw-r--r--compat/regex/regcomp.c2
-rw-r--r--compat/regex/regex.h2
-rw-r--r--compat/regex/regex_internal.c2
-rw-r--r--compat/regex/regexec.c4
-rw-r--r--compat/vcbuild/find_vs_env.bat2
-rw-r--r--compat/win32/pthread.h2
-rw-r--r--config.c5
-rw-r--r--config.h335
-rw-r--r--configure.ac51
-rw-r--r--connected.c3
-rw-r--r--contrib/coccinelle/commit.cocci2
-rw-r--r--contrib/coccinelle/object_id.cocci32
-rw-r--r--contrib/completion/git-completion.bash9
-rw-r--r--contrib/completion/git-completion.zsh5
-rw-r--r--contrib/diff-highlight/DiffHighlight.pm2
-rwxr-xr-xcontrib/hooks/multimail/git_multimail.py8
-rwxr-xr-xcontrib/hooks/multimail/post-receive.example2
-rwxr-xr-xcontrib/hooks/post-receive-email2
-rwxr-xr-xcontrib/hooks/update-paranoid2
-rw-r--r--contrib/mw-to-git/.perlcriticrc2
-rwxr-xr-xcontrib/mw-to-git/git-remote-mediawiki.perl2
-rw-r--r--contrib/mw-to-git/t/install-wiki/db_install.php2
-rwxr-xr-xcontrib/mw-to-git/t/t9360-mw-to-git-clone.sh2
-rwxr-xr-xcontrib/mw-to-git/t/test-gitmw-lib.sh2
-rwxr-xr-xcontrib/svn-fe/svnrdump_sim.py2
-rw-r--r--convert.c24
-rw-r--r--daemon.c4
-rw-r--r--diff.c4
-rw-r--r--dir.c209
-rw-r--r--dir.h36
-rw-r--r--environment.c1
-rw-r--r--ewah/bitmap.c2
-rw-r--r--fetch-pack.c96
-rw-r--r--fsck.c386
-rw-r--r--fsck.h39
-rw-r--r--fsmonitor.c31
-rw-r--r--git-compat-util.h2
-rwxr-xr-xgit-cvsimport.perl2
-rw-r--r--git-gui/README.md174
-rwxr-xr-xgit-gui/git-gui.sh15
-rw-r--r--git-gui/lib/diff.tcl33
-rw-r--r--git-gui/po/ja.po9
-rwxr-xr-xgit-legacy-stash.sh5
-rwxr-xr-xgit-send-email.perl2
-rw-r--r--git.c1
-rwxr-xr-xgitweb/gitweb.perl49
-rw-r--r--gitweb/static/js/blame_incremental.js2
-rw-r--r--graph.c646
-rw-r--r--grep.c47
-rw-r--r--grep.h2
-rw-r--r--hashmap.c2
-rw-r--r--hashmap.h8
-rw-r--r--help.c2
-rw-r--r--hex.c10
-rw-r--r--http-push.c8
-rw-r--r--http.c18
-rw-r--r--merge-recursive.c104
-rw-r--r--midx.c71
-rw-r--r--midx.h10
-rw-r--r--name-hash.c4
-rw-r--r--object.h3
-rw-r--r--pack-bitmap.h2
-rw-r--r--pack-objects.c5
-rw-r--r--pack-objects.h19
-rw-r--r--parse-options-cb.c3
-rw-r--r--parse-options.c2
-rw-r--r--path.c128
-rw-r--r--perl/Git.pm2
-rw-r--r--po/bg.po4987
-rw-r--r--po/ca.po60
-rw-r--r--po/de.po5044
-rw-r--r--po/es.po5220
-rw-r--r--po/fr.po4994
-rw-r--r--po/git.pot4924
-rw-r--r--po/it.po5034
-rw-r--r--po/sv.po5240
-rw-r--r--po/vi.po5040
-rw-r--r--po/zh_CN.po4978
-rw-r--r--pretty.c9
-rw-r--r--promisor-remote.c3
-rw-r--r--range-diff.h2
-rw-r--r--read-cache.c2
-rw-r--r--refs/refs-internal.h2
-rw-r--r--remote-curl.c35
-rw-r--r--repo-settings.c2
-rw-r--r--repository.c4
-rw-r--r--repository.h2
-rw-r--r--rerere.c2
-rw-r--r--send-pack.c8
-rw-r--r--sequencer.c51
-rw-r--r--sequencer.h3
-rw-r--r--server-info.c2
-rw-r--r--sha1dc/sha1.c2
-rw-r--r--sha1dc_git.c2
-rw-r--r--string-list.h2
-rw-r--r--t/gitweb-lib.sh7
-rw-r--r--t/helper/test-progress.c2
-rw-r--r--t/helper/test-read-graph.c53
-rw-r--r--t/helper/test-tool.c1
-rw-r--r--t/helper/test-tool.h1
-rw-r--r--t/lib-rebase.sh28
-rw-r--r--t/oid-info/hash-info9
-rwxr-xr-xt/perf/bisect_regression2
-rwxr-xr-xt/perf/p5303-many-packs.sh1
-rwxr-xr-xt/t0000-basic.sh2
-rwxr-xr-xt/t0027-auto-crlf.sh2
-rwxr-xr-xt/t0028-working-tree-encoding.sh4
-rwxr-xr-xt/t0060-path-utils.sh4
-rwxr-xr-xt/t0500-progress-display.sh4
-rwxr-xr-xt/t1050-large.sh6
-rwxr-xr-xt/t1091-sparse-checkout-builtin.sh293
-rwxr-xr-xt/t1305-config-include.sh2
-rwxr-xr-xt/t1308-config-set.sh8
-rwxr-xr-xt/t1400-update-ref.sh18
-rwxr-xr-xt/t1450-fsck.sh2
-rwxr-xr-xt/t1500-rev-parse.sh15
-rwxr-xr-xt/t1512-rev-parse-disambiguation.sh2
-rwxr-xr-xt/t1600-index.sh4
-rwxr-xr-xt/t2400-worktree-add.sh24
-rwxr-xr-xt/t3060-ls-files-with-tree.sh4
-rwxr-xr-xt/t3210-pack-refs.sh2
-rwxr-xr-xt/t3301-notes.sh46
-rwxr-xr-xt/t3404-rebase-interactive.sh596
-rwxr-xr-xt/t3429-rebase-edit-todo.sh2
-rwxr-xr-xt/t3430-rebase-merges.sh2
-rwxr-xr-xt/t3434-rebase-i18n.sh84
-rw-r--r--t/t3434/ISO8859-1.txt3
-rw-r--r--t/t3434/eucJP.txt4
-rwxr-xr-xt/t3900-i18n-commit.sh37
-rwxr-xr-xt/t3903-stash.sh18
-rwxr-xr-xt/t3905-stash-include-untracked.sh4
-rwxr-xr-xt/t3906-stash-submodule.sh42
-rwxr-xr-xt/t4010-diff-pathspec.sh20
-rwxr-xr-xt/t4011-diff-symlink.sh40
-rwxr-xr-xt/t4014-format-patch.sh198
-rwxr-xr-xt/t4015-diff-whitespace.sh89
-rwxr-xr-xt/t4018-diff-funcname.sh1
-rw-r--r--t/t4018/dts-nodes-boolean-prop9
-rw-r--r--t/t4018/dts-nodes-multiline-prop13
-rw-r--r--t/t4018/dts-root2
-rw-r--r--t/t4018/dts-root-comment8
-rw-r--r--t/t4018/elixir-do-not-pick-end5
-rw-r--r--t/t4018/elixir-ex-unit-test6
-rw-r--r--t/t4018/elixir-function5
-rw-r--r--t/t4018/elixir-macro5
-rw-r--r--t/t4018/elixir-module9
-rw-r--r--t/t4018/elixir-module-func8
-rw-r--r--t/t4018/elixir-nested-module9
-rw-r--r--t/t4018/elixir-private-function5
-rw-r--r--t/t4018/elixir-protocol6
-rw-r--r--t/t4018/elixir-protocol-implementation5
-rwxr-xr-xt/t4027-diff-submodule.sh16
-rwxr-xr-xt/t4034-diff-words.sh93
-rwxr-xr-xt/t4038-diff-combined.sh19
-rwxr-xr-xt/t4039-diff-assume-unchanged.sh3
-rwxr-xr-xt/t4041-diff-submodule-option.sh20
-rwxr-xr-xt/t4044-diff-index-unique-abbrev.sh46
-rwxr-xr-xt/t4045-diff-relative.sh2
-rwxr-xr-xt/t4048-diff-combined-binary.sh58
-rwxr-xr-xt/t4057-diff-combined-paths.sh2
-rw-r--r--t/t4100/t-apply-1.patch4
-rw-r--r--t/t4100/t-apply-3.patch2
-rw-r--r--t/t4100/t-apply-5.patch4
-rw-r--r--t/t4100/t-apply-7.patch2
-rwxr-xr-xt/t4108-apply-threeway.sh55
-rwxr-xr-xt/t4202-log.sh2
-rwxr-xr-xt/t4203-mailmap.sh122
-rwxr-xr-xt/t4205-log-pretty-formats.sh2
-rwxr-xr-xt/t4213-log-tabexpand.sh2
-rwxr-xr-xt/t4214-log-graph-octopus.sh62
-rwxr-xr-xt/t4215-log-skewed-merges.sh243
-rwxr-xr-xt/t5318-commit-graph.sh10
-rwxr-xr-xt/t5319-multi-pack-index.sh69
-rwxr-xr-xt/t5324-split-commit-graph.sh2
-rwxr-xr-xt/t5510-fetch.sh16
-rwxr-xr-xt/t5528-push-default.sh2
-rwxr-xr-xt/t5535-fetch-push-symref.sh2
-rwxr-xr-xt/t5541-http-push-smart.sh40
-rwxr-xr-xt/t5545-push-options.sh2
-rwxr-xr-xt/t5616-partial-clone.sh78
-rwxr-xr-xt/t5702-protocol-v2.sh10
-rwxr-xr-xt/t6006-rev-list-format.sh28
-rwxr-xr-xt/t6016-rev-list-graph-simplify-history.sh30
-rwxr-xr-xt/t6024-recursive-merge.sh130
-rwxr-xr-xt/t6036-recursive-corner-cases.sh4
-rwxr-xr-xt/t6042-merge-rename-corner-cases.sh111
-rwxr-xr-xt/t6043-merge-rename-directories.sh574
-rwxr-xr-xt/t6046-merge-skip-unneeded-updates.sh135
-rwxr-xr-xt/t6102-rev-list-unexpected-objects.sh2
-rwxr-xr-xt/t6500-gc.sh14
-rwxr-xr-xt/t7004-tag.sh8
-rwxr-xr-xt/t7012-skip-worktree-writing.sh15
-rwxr-xr-xt/t7030-verify-tag.sh14
-rwxr-xr-xt/t7419-submodule-set-branch.sh6
-rwxr-xr-xt/t7508-status.sh2
-rwxr-xr-xt/t7513-interpret-trailers.sh2
-rwxr-xr-xt/t7519-status-fsmonitor.sh21
-rwxr-xr-xt/t7519/fsmonitor-env24
-rwxr-xr-xt/t7519/fsmonitor-watchman13
-rwxr-xr-xt/t9001-send-email.sh2
-rwxr-xr-xt/t9301-fast-import-notes.sh2
-rwxr-xr-xt/t9350-fast-export.sh2
-rwxr-xr-xt/t9502-gitweb-standalone-parse-output.sh7
-rwxr-xr-xt/t9809-git-p4-client-view.sh2
-rwxr-xr-xt/t9902-completion.sh11
-rw-r--r--t/test-lib.sh20
-rw-r--r--tag.c21
-rwxr-xr-xtemplates/hooks--fsmonitor-watchman.sample13
-rw-r--r--trace2/tr2_sid.c2
-rw-r--r--trace2/tr2_tgt_perf.c17
-rw-r--r--transport-helper.c4
-rw-r--r--transport.h3
-rw-r--r--unpack-trees.c114
-rw-r--r--unpack-trees.h3
-rw-r--r--url.c2
-rw-r--r--usage.c20
-rw-r--r--userdiff.c15
-rw-r--r--utf8.c15
-rw-r--r--xdiff-interface.h2
352 files changed, 30891 insertions, 25047 deletions
diff --git a/.gitignore b/.gitignore
index 89b3b79c1a..aebe7c0908 100644
--- a/.gitignore
+++ b/.gitignore
@@ -158,6 +158,7 @@
 /git-show-branch
 /git-show-index
 /git-show-ref
+/git-sparse-checkout
 /git-stage
 /git-stash
 /git-status
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index f45db5b727..ed4e443a3c 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -75,7 +75,7 @@ For shell scripts specifically (not exhaustive):
 
  - 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 @@ For C programs:
    . 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/Makefile b/Documentation/Makefile
index 06d85ad958..8fe829cc1b 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -77,6 +77,7 @@ API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technica
 SP_ARTICLES += $(API_DOCS)
 
 TECH_DOCS += MyFirstContribution
+TECH_DOCS += MyFirstObjectWalk
 TECH_DOCS += SubmittingPatches
 TECH_DOCS += technical/hash-function-transition
 TECH_DOCS += technical/http-protocol
diff --git a/Documentation/MyFirstContribution.txt b/Documentation/MyFirstContribution.txt
index 5e9b808f5f..b55837e646 100644
--- a/Documentation/MyFirstContribution.txt
+++ b/Documentation/MyFirstContribution.txt
@@ -38,6 +38,26 @@ $ git clone https://github.com/git/git git
 $ 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 @@ NOTE: When you are developing the Git project, it's preferred that you use the
 `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 @@ you want to pass as a parameter something which would usually be interpreted as
 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 @@ will automatically run your PRs through the CI even without the permission given
 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:
 
diff --git a/Documentation/MyFirstObjectWalk.txt b/Documentation/MyFirstObjectWalk.txt
new file mode 100644
index 0000000000..4d24daeb9f
--- /dev/null
+++ b/Documentation/MyFirstObjectWalk.txt
@@ -0,0 +1,906 @@
+= My First Object Walk
+
+== What's an Object Walk?
+
+The object walk is a key concept in Git - this is the process that underpins
+operations like object transfer and fsck. Beginning from a given commit, the
+list of objects is found by walking parent relationships between commits (commit
+X based on commit W) and containment relationships between objects (tree Y is
+contained within commit X, and blob Z is located within tree Y, giving our
+working tree for commit X something like `y/z.txt`).
+
+A related concept is the revision walk, which is focused on commit objects and
+their parent relationships and does not delve into other object types. The
+revision walk is used for operations like `git log`.
+
+=== Related Reading
+
+- `Documentation/user-manual.txt` under "Hacking Git" contains some coverage of
+  the revision walker in its various incarnations.
+- `Documentation/technical/api-revision-walking.txt`
+- 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.
+
+== Setting Up
+
+Create a new branch from `master`.
+
+----
+git checkout -b revwalk origin/master
+----
+
+We'll put our fiddling into a new command. For fun, let's name it `git walken`.
+Open up a new file `builtin/walken.c` and set up the command handler:
+
+----
+/*
+ * "git walken"
+ *
+ * Part of the "My First Object Walk" tutorial.
+ */
+
+#include "builtin.h"
+
+int cmd_walken(int argc, const char **argv, const char *prefix)
+{
+        trace_printf(_("cmd_walken incoming...\n"));
+        return 0;
+}
+----
+
+NOTE: `trace_printf()` differs from `printf()` in that it can be turned on or
+off at runtime. For the purposes of this tutorial, we will write `walken` as
+though it is intended for use as a "plumbing" command: that is, a command which
+is used primarily in scripts, rather than interactively by humans (a "porcelain"
+command). So we will send our debug output to `trace_printf()` instead. When
+running, enable trace output by setting the environment variable `GIT_TRACE`.
+
+Add usage text and `-h` handling, like all subcommands should consistently do
+(our test suite will notice and complain if you fail to do so).
+
+----
+int cmd_walken(int argc, const char **argv, const char *prefix)
+{
+        const char * const walken_usage[] = {
+                N_("git walken"),
+                NULL,
+        }
+        struct option options[] = {
+                OPT_END()
+        };
+
+        argc = parse_options(argc, argv, prefix, options, walken_usage, 0);
+
+        ...
+}
+----
+
+Also add the relevant line in `builtin.h` near `cmd_whatchanged()`:
+
+----
+int cmd_walken(int argc, const char **argv, const char *prefix);
+----
+
+Include the command in `git.c` in `commands[]` near the entry for `whatchanged`,
+maintaining alphabetical ordering:
+
+----
+{ "walken", cmd_walken, RUN_SETUP },
+----
+
+Add it to the `Makefile` near the line for `builtin/worktree.o`:
+
+----
+BUILTIN_OBJS += builtin/walken.o
+----
+
+Build and test out your command, without forgetting to ensure the `DEVELOPER`
+flag is set, and with `GIT_TRACE` enabled so the debug output can be seen:
+
+----
+$ echo DEVELOPER=1 >>config.mak
+$ make
+$ GIT_TRACE=1 ./bin-wrappers/git walken
+----
+
+NOTE: For a more exhaustive overview of the new command process, take a look at
+`Documentation/MyFirstContribution.txt`.
+
+NOTE: A reference implementation can be found at
+https://github.com/nasamuffin/git/tree/revwalk.
+
+=== `struct rev_cmdline_info`
+
+The definition of `struct rev_cmdline_info` can be found in `revision.h`.
+
+This struct is contained within the `rev_info` struct and is used to reflect
+parameters provided by the user over the CLI.
+
+`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.
+
+Per entry, we find:
+
+`item` is the object provided upon which to base the object walk. Items in Git
+can be blobs, trees, commits, or tags. (See `Documentation/gittutorial-2.txt`.)
+
+`name` is the object ID (OID) of the object - a hex string you may be familiar
+with from using Git to organize your source in the past. Check the tutorial
+mentioned above towards the top for a discussion of where the OID can come
+from.
+
+`whence` indicates some information about what to do with the parents of the
+specified object. We'll explore this flag more later on; take a look at
+`Documentation/revisions.txt` to get an idea of what could set the `whence`
+value.
+
+`flags` are used to hint the beginning of the revision walk and are the first
+block under the `#include`s in `revision.h`. The most likely ones to be set in
+the `rev_cmdline_info` are `UNINTERESTING` and `BOTTOM`, but these same flags
+can be used during the walk, as well.
+
+=== `struct rev_info`
+
+This one is quite a bit longer, and many fields are only used during the walk
+by `revision.c` - not configuration options. Most of the configurable flags in
+`struct rev_info` have a mirror in `Documentation/rev-list-options.txt`. It's a
+good idea to take some time and read through that document.
+
+== Basic Commit Walk
+
+First, let's see if we can replicate the output of `git log --oneline`. We'll
+refer back to the implementation frequently to discover norms when performing
+an object walk of our own.
+
+To do so, we'll first find all the commits, in order, which preceded the current
+commit. We'll extract the name and subject of the commit from each.
+
+Ideally, we will also be able to find out which ones are currently at the tip of
+various branches.
+
+=== Setting Up
+
+Preparing for your object walk has some distinct stages.
+
+1. Perform default setup for this mode, and others which may be invoked.
+2. Check configuration files for relevant settings.
+3. Set up the `rev_info` struct.
+4. Tweak the initialized `rev_info` to suit the current walk.
+5. Prepare the `rev_info` for the walk.
+6. Iterate over the objects, processing each one.
+
+==== Default Setups
+
+Before examining configuration files which may modify command behavior, set up
+default state for switches or options your command may have. If your command
+utilizes other Git components, ask them to set up their default states as well.
+For instance, `git log` takes advantage of `grep` and `diff` functionality, so
+its `init_log_defaults()` sets its own state (`decoration_style`) and asks
+`grep` and `diff` to initialize themselves by calling each of their
+initialization functions.
+
+For our first example within `git walken`, we don't intend to use any other
+components within Git, and we don't have any configuration to do.  However, we
+may want to add some later, so for now, we can add an empty placeholder. Create
+a new function in `builtin/walken.c`:
+
+----
+static void init_walken_defaults(void)
+{
+        /*
+         * We don't actually need the same components `git log` does; leave this
+         * empty for now.
+         */
+}
+----
+
+Make sure to add a line invoking it inside of `cmd_walken()`.
+
+----
+int cmd_walken(int argc, const char **argv, const char *prefix)
+{
+        init_walken_defaults();
+}
+----
+
+==== Configuring From `.gitconfig`
+
+Next, we should have a look at any relevant configuration settings (i.e.,
+settings readable and settable from `git config`). This is done by providing a
+callback to `git_config()`; within that callback, you can also invoke methods
+from other components you may need that need to intercept these options. Your
+callback will be invoked once per each configuration value which Git knows about
+(global, local, worktree, etc.).
+
+Similarly to the default values, we don't have anything to do here yet
+ourselves; however, we should call `git_default_config()` if we aren't calling
+any other existing config callbacks.
+
+Add a new function to `builtin/walken.c`:
+
+----
+static int git_walken_config(const char *var, const char *value, void *cb)
+{
+        /*
+         * For now, we don't have any custom configuration, so fall back to
+         * the default config.
+         */
+        return git_default_config(var, value, cb);
+}
+----
+
+Make sure to invoke `git_config()` with it in your `cmd_walken()`:
+
+----
+int cmd_walken(int argc, const char **argv, const char *prefix)
+{
+        ...
+
+        git_config(git_walken_config, NULL);
+
+        ...
+}
+----
+
+==== Setting Up `rev_info`
+
+Now that we've gathered external configuration and options, it's time to
+initialize the `rev_info` object which we will use to perform the walk. This is
+typically done by calling `repo_init_revisions()` with the repository you intend
+to target, as well as the `prefix` argument of `cmd_walken` and your `rev_info`
+struct.
+
+Add the `struct rev_info` and the `repo_init_revisions()` call:
+----
+int cmd_walken(int argc, const char **argv, const char *prefix)
+{
+        /* This can go wherever you like in your declarations.*/
+        struct rev_info rev;
+        ...
+
+        /* This should go after the git_config() call. */
+        repo_init_revisions(the_repository, &rev, prefix);
+
+        ...
+}
+----
+
+==== Tweaking `rev_info` For the Walk
+
+We're getting close, but we're still not quite ready to go. Now that `rev` is
+initialized, we can modify it to fit our needs. This is usually done within a
+helper for clarity, so let's add one:
+
+----
+static void final_rev_info_setup(struct rev_info *rev)
+{
+        /*
+         * We want to mimic the appearance of `git log --oneline`, so let's
+         * force oneline format.
+         */
+        get_commit_format("oneline", rev);
+
+        /* Start our object walk at HEAD. */
+        add_head_to_pending(rev);
+}
+----
+
+[NOTE]
+====
+Instead of using the shorthand `add_head_to_pending()`, you could do
+something like this:
+----
+        struct setup_revision_opt opt;
+
+        memset(&opt, 0, sizeof(opt));
+        opt.def = "HEAD";
+        opt.revarg_opt = REVARG_COMMITTISH;
+        setup_revisions(argc, argv, rev, &opt);
+----
+Using a `setup_revision_opt` gives you finer control over your walk's starting
+point.
+====
+
+Then let's invoke `final_rev_info_setup()` after the call to
+`repo_init_revisions()`:
+
+----
+int cmd_walken(int argc, const char **argv, const char *prefix)
+{
+        ...
+
+        final_rev_info_setup(&rev);
+
+        ...
+}
+----
+
+Later, we may wish to add more arguments to `final_rev_info_setup()`. But for
+now, this is all we need.
+
+==== Preparing `rev_info` For the Walk
+
+Now that `rev` is all initialized and configured, we've got one more setup step
+before we get rolling. We can do this in a helper, which will both prepare the
+`rev_info` for the walk, and perform the walk itself. Let's start the helper
+with the call to `prepare_revision_walk()`, which can return an error without
+dying on its own:
+
+----
+static void walken_commit_walk(struct rev_info *rev)
+{
+        if (prepare_revision_walk(rev))
+                die(_("revision walk setup failed"));
+}
+----
+
+NOTE: `die()` prints to `stderr` and exits the program. Since it will print to
+`stderr` it's likely to be seen by a human, so we will localize it.
+
+==== Performing the Walk!
+
+Finally! We are ready to begin the walk itself. Now we can see that `rev_info`
+can also be used as an iterator; we move to the next item in the walk by using
+`get_revision()` repeatedly. Add the listed variable declarations at the top and
+the walk loop below the `prepare_revision_walk()` call within your
+`walken_commit_walk()`:
+
+----
+static void walken_commit_walk(struct rev_info *rev)
+{
+        struct commit *commit;
+        struct strbuf prettybuf = STRBUF_INIT;
+
+        ...
+
+        while ((commit = get_revision(rev))) {
+                if (!commit)
+                        continue;
+
+                strbuf_reset(&prettybuf);
+                pp_commit_easy(CMIT_FMT_ONELINE, commit, &prettybuf);
+                puts(prettybuf.buf);
+        }
+        strbuf_release(&prettybuf);
+}
+----
+
+NOTE: `puts()` prints a `char*` to `stdout`. Since this is the part of the
+command we expect to be machine-parsed, we're sending it directly to stdout.
+
+Give it a shot.
+
+----
+$ make
+$ ./bin-wrappers/git walken
+----
+
+You should see all of the subject lines of all the commits in
+your tree's history, in order, ending with the initial commit, "Initial revision
+of "git", the information manager from hell". Congratulations! You've written
+your first revision walk. You can play with printing some additional fields
+from each commit if you're curious; have a look at the functions available in
+`commit.h`.
+
+=== Adding a Filter
+
+Next, let's try to filter the commits we see based on their author. This is
+equivalent to running `git log --author=<pattern>`. We can add a filter by
+modifying `rev_info.grep_filter`, which is a `struct grep_opt`.
+
+First some setup. Add `init_grep_defaults()` to `init_walken_defaults()` and add
+`grep_config()` to `git_walken_config()`:
+
+----
+static void init_walken_defaults(void)
+{
+        init_grep_defaults(the_repository);
+}
+
+...
+
+static int git_walken_config(const char *var, const char *value, void *cb)
+{
+        grep_config(var, value, cb);
+        return git_default_config(var, value, cb);
+}
+----
+
+Next, we can modify the `grep_filter`. This is done with convenience functions
+found in `grep.h`. For fun, we're filtering to only commits from folks using a
+`gmail.com` email address - a not-very-precise guess at who may be working on
+Git as a hobby. Since we're checking the author, which is a specific line in the
+header, we'll use the `append_header_grep_pattern()` helper. We can use
+the `enum grep_header_field` to indicate which part of the commit header we want
+to search.
+
+In `final_rev_info_setup()`, add your filter line:
+
+----
+static void final_rev_info_setup(int argc, const char **argv,
+                const char *prefix, struct rev_info *rev)
+{
+        ...
+
+        append_header_grep_pattern(&rev->grep_filter, GREP_HEADER_AUTHOR,
+                "gmail");
+        compile_grep_patterns(&rev->grep_filter);
+
+        ...
+}
+----
+
+`append_header_grep_pattern()` adds your new "gmail" pattern to `rev_info`, but
+it won't work unless we compile it with `compile_grep_patterns()`.
+
+NOTE: If you are using `setup_revisions()` (for example, if you are passing a
+`setup_revision_opt` instead of using `add_head_to_pending()`), you don't need
+to call `compile_grep_patterns()` because `setup_revisions()` calls it for you.
+
+NOTE: We could add the same filter via the `append_grep_pattern()` helper if we
+wanted to, but `append_header_grep_pattern()` adds the `enum grep_context` and
+`enum grep_pat_token` for us.
+
+=== Changing the Order
+
+There are a few ways that we can change the order of the commits during a
+revision walk. Firstly, we can use the `enum rev_sort_order` to choose from some
+typical orderings.
+
+`topo_order` is the same as `git log --topo-order`: we avoid showing a parent
+before all of its children have been shown, and we avoid mixing commits which
+are in different lines of history. (`git help log`'s section on `--topo-order`
+has a very nice diagram to illustrate this.)
+
+Let's see what happens when we run with `REV_SORT_BY_COMMIT_DATE` as opposed to
+`REV_SORT_BY_AUTHOR_DATE`. Add the following:
+
+----
+static void final_rev_info_setup(int argc, const char **argv,
+                const char *prefix, struct rev_info *rev)
+{
+        ...
+
+        rev->topo_order = 1;
+        rev->sort_order = REV_SORT_BY_COMMIT_DATE;
+
+        ...
+}
+----
+
+Let's output this into a file so we can easily diff it with the walk sorted by
+author date.
+
+----
+$ make
+$ ./bin-wrappers/git walken > commit-date.txt
+----
+
+Then, let's sort by author date and run it again.
+
+----
+static void final_rev_info_setup(int argc, const char **argv,
+                const char *prefix, struct rev_info *rev)
+{
+        ...
+
+        rev->topo_order = 1;
+        rev->sort_order = REV_SORT_BY_AUTHOR_DATE;
+
+        ...
+}
+----
+
+----
+$ make
+$ ./bin-wrappers/git walken > author-date.txt
+----
+
+Finally, compare the two. This is a little less helpful without object names or
+dates, but hopefully we get the idea.
+
+----
+$ diff -u commit-date.txt author-date.txt
+----
+
+This display indicates that commits can be reordered after they're written, for
+example with `git rebase`.
+
+Let's try one more reordering of commits. `rev_info` exposes a `reverse` flag.
+Set that flag somewhere inside of `final_rev_info_setup()`:
+
+----
+static void final_rev_info_setup(int argc, const char **argv, const char *prefix,
+                struct rev_info *rev)
+{
+        ...
+
+        rev->reverse = 1;
+
+        ...
+}
+----
+
+Run your walk again and note the difference in order. (If you remove the grep
+pattern, you should see the last commit this call gives you as your current
+HEAD.)
+
+== Basic Object Walk
+
+So far we've been walking only commits. But Git has more types of objects than
+that! Let's see if we can walk _all_ objects, and find out some information
+about each one.
+
+We can base our work on an example. `git pack-objects` prepares all kinds of
+objects for packing into a bitmap or packfile. The work we are interested in
+resides in `builtins/pack-objects.c:get_object_list()`; examination of that
+function shows that the all-object walk is being performed by
+`traverse_commit_list()` or `traverse_commit_list_filtered()`. Those two
+functions reside in `list-objects.c`; examining the source shows that, despite
+the name, these functions traverse all kinds of objects. Let's have a look at
+the arguments to `traverse_commit_list_filtered()`, which are a superset of the
+arguments to the unfiltered version.
+
+- `struct list_objects_filter_options *filter_options`: This is a struct which
+  stores a filter-spec as outlined in `Documentation/rev-list-options.txt`.
+- `struct rev_info *revs`: This is the `rev_info` used for the walk.
+- `show_commit_fn show_commit`: A callback which will be used to handle each
+  individual commit object.
+- `show_object_fn show_object`: A callback which will be used to handle each
+  non-commit object (so each blob, tree, or tag).
+- `void *show_data`: A context buffer which is passed in turn to `show_commit`
+  and `show_object`.
+- `struct oidset *omitted`: A linked-list of object IDs which the provided
+  filter caused to be omitted.
+
+It looks like this `traverse_commit_list_filtered()` uses callbacks we provide
+instead of needing us to call it repeatedly ourselves. Cool! Let's add the
+callbacks first.
+
+For the sake of this tutorial, we'll simply keep track of how many of each kind
+of object we find. At file scope in `builtin/walken.c` add the following
+tracking variables:
+
+----
+static int commit_count;
+static int tag_count;
+static int blob_count;
+static int tree_count;
+----
+
+Commits are handled by a different callback than other objects; let's do that
+one first:
+
+----
+static void walken_show_commit(struct commit *cmt, void *buf)
+{
+        commit_count++;
+}
+----
+
+The `cmt` argument is fairly self-explanatory. But it's worth mentioning that
+the `buf` argument is actually the context buffer that we can provide to the
+traversal calls - `show_data`, which we mentioned a moment ago.
+
+Since we have the `struct commit` object, we can look at all the same parts that
+we looked at in our earlier commit-only walk. For the sake of this tutorial,
+though, we'll just increment the commit counter and move on.
+
+The callback for non-commits is a little different, as we'll need to check
+which kind of object we're dealing with:
+
+----
+static void walken_show_object(struct object *obj, const char *str, void *buf)
+{
+        switch (obj->type) {
+        case OBJ_TREE:
+                tree_count++;
+                break;
+        case OBJ_BLOB:
+                blob_count++;
+                break;
+        case OBJ_TAG:
+                tag_count++;
+                break;
+        case OBJ_COMMIT:
+                BUG("unexpected commit object in walken_show_object\n");
+        default:
+                BUG("unexpected object type %s in walken_show_object\n",
+                        type_name(obj->type));
+        }
+}
+----
+
+Again, `obj` is fairly self-explanatory, and we can guess that `buf` is the same
+context pointer that `walken_show_commit()` receives: the `show_data` argument
+to `traverse_commit_list()` and `traverse_commit_list_filtered()`. Finally,
+`str` contains the name of the object, which ends up being something like
+`foo.txt` (blob), `bar/baz` (tree), or `v1.2.3` (tag).
+
+To help assure us that we aren't double-counting commits, we'll include some
+complaining if a commit object is routed through our non-commit callback; we'll
+also complain if we see an invalid object type. Since those two cases should be
+unreachable, and would only change in the event of a semantic change to the Git
+codebase, we complain by using `BUG()` - which is a signal to a developer that
+the change they made caused unintended consequences, and the rest of the
+codebase needs to be updated to understand that change. `BUG()` is not intended
+to be seen by the public, so it is not localized.
+
+Our main object walk implementation is substantially different from our commit
+walk implementation, so let's make a new function to perform the object walk. We
+can perform setup which is applicable to all objects here, too, to keep separate
+from setup which is applicable to commit-only walks.
+
+We'll start by enabling all types of objects in the `struct rev_info`.  We'll
+also turn on `tree_blobs_in_commit_order`, which means that we will walk a
+commit's tree and everything it points to immediately after we find each commit,
+as opposed to waiting for the end and walking through all trees after the commit
+history has been discovered. With the appropriate settings configured, we are
+ready to call `prepare_revision_walk()`.
+
+----
+static void walken_object_walk(struct rev_info *rev)
+{
+        rev->tree_objects = 1;
+        rev->blob_objects = 1;
+        rev->tag_objects = 1;
+        rev->tree_blobs_in_commit_order = 1;
+
+        if (prepare_revision_walk(rev))
+                die(_("revision walk setup failed"));
+
+        commit_count = 0;
+        tag_count = 0;
+        blob_count = 0;
+        tree_count = 0;
+----
+
+Let's start by calling just the unfiltered walk and reporting our counts.
+Complete your implementation of `walken_object_walk()`:
+
+----
+        traverse_commit_list(rev, walken_show_commit, walken_show_object, NULL);
+
+        printf("commits %d\nblobs %d\ntags %d\ntrees %d\n", commit_count,
+                blob_count, tag_count, tree_count);
+}
+----
+
+NOTE: This output is intended to be machine-parsed. Therefore, we are not
+sending it to `trace_printf()`, and we are not localizing it - we need scripts
+to be able to count on the formatting to be exactly the way it is shown here.
+If we were intending this output to be read by humans, we would need to localize
+it with `_()`.
+
+Finally, we'll ask `cmd_walken()` to use the object walk instead. Discussing
+command line options is out of scope for this tutorial, so we'll just hardcode
+a branch we can change at compile time. Where you call `final_rev_info_setup()`
+and `walken_commit_walk()`, instead branch like so:
+
+----
+        if (1) {
+                add_head_to_pending(&rev);
+                walken_object_walk(&rev);
+        } else {
+                final_rev_info_setup(argc, argv, prefix, &rev);
+                walken_commit_walk(&rev);
+        }
+----
+
+NOTE: For simplicity, we've avoided all the filters and sorts we applied in
+`final_rev_info_setup()` and simply added `HEAD` to our pending queue. If you
+want, you can certainly use the filters we added before by moving
+`final_rev_info_setup()` out of the conditional and removing the call to
+`add_head_to_pending()`.
+
+Now we can try to run our command! It should take noticeably longer than the
+commit walk, but an examination of the output will give you an idea why. Your
+output should look similar to this example, but with different counts:
+
+----
+Object walk completed. Found 55733 commits, 100274 blobs, 0 tags, and 104210 trees.
+----
+
+This makes sense. We have more trees than commits because the Git project has
+lots of subdirectories which can change, plus at least one tree per commit. We
+have no tags because we started on a commit (`HEAD`) and while tags can point to
+commits, commits can't point to tags.
+
+NOTE: You will have different counts when you run this yourself! The number of
+objects grows along with the Git project.
+
+=== Adding a Filter
+
+There are a handful of filters that we can apply to the object walk laid out in
+`Documentation/rev-list-options.txt`. These filters are typically useful for
+operations such as creating packfiles or performing a partial clone. They are
+defined in `list-objects-filter-options.h`. For the purposes of this tutorial we
+will use the "tree:1" filter, which causes the walk to omit all trees and blobs
+which are not directly referenced by commits reachable from the commit in
+`pending` when the walk begins. (`pending` is the list of objects which need to
+be traversed during a walk; you can imagine a breadth-first tree traversal to
+help understand. In our case, that means we omit trees and blobs not directly
+referenced by `HEAD` or `HEAD`'s history, because we begin the walk with only
+`HEAD` in the `pending` list.)
+
+First, we'll need to `#include "list-objects-filter-options.h`" and set up the
+`struct list_objects_filter_options` at the top of the function.
+
+----
+static void walken_object_walk(struct rev_info *rev)
+{
+        struct list_objects_filter_options filter_options = {};
+
+        ...
+----
+
+For now, we are not going to track the omitted objects, so we'll replace those
+parameters with `NULL`. For the sake of simplicity, we'll add a simple
+build-time branch to use our filter or not. Replace the line calling
+`traverse_commit_list()` with the following, which will remind us which kind of
+walk we've just performed:
+
+----
+        if (0) {
+                /* Unfiltered: */
+                trace_printf(_("Unfiltered object walk.\n"));
+                traverse_commit_list(rev, walken_show_commit,
+                                walken_show_object, NULL);
+        } else {
+                trace_printf(
+                        _("Filtered object walk with filterspec 'tree:1'.\n"));
+                parse_list_objects_filter(&filter_options, "tree:1");
+
+                traverse_commit_list_filtered(&filter_options, rev,
+                        walken_show_commit, walken_show_object, NULL, NULL);
+        }
+----
+
+`struct list_objects_filter_options` is usually built directly from a command
+line argument, so the module provides an easy way to build one from a string.
+Even though we aren't taking user input right now, we can still build one with
+a hardcoded string using `parse_list_objects_filter()`.
+
+With the filter spec "tree:1", we are expecting to see _only_ the root tree for
+each commit; therefore, the tree object count should be less than or equal to
+the number of commits. (For an example of why that's true: `git commit --revert`
+points to the same tree object as its grandparent.)
+
+=== Counting Omitted Objects
+
+We also have the capability to enumerate all objects which were omitted by a
+filter, like with `git log --filter=<spec> --filter-print-omitted`. Asking
+`traverse_commit_list_filtered()` to populate the `omitted` list means that our
+object walk does not perform any better than an unfiltered object walk; all
+reachable objects are walked in order to populate the list.
+
+First, add the `struct oidset` and related items we will use to iterate it:
+
+----
+static void walken_object_walk(
+        ...
+
+        struct oidset omitted;
+        struct oidset_iter oit;
+        struct object_id *oid = NULL;
+        int omitted_count = 0;
+        oidset_init(&omitted, 0);
+
+        ...
+----
+
+Modify the call to `traverse_commit_list_filtered()` to include your `omitted`
+object:
+
+----
+        ...
+
+                traverse_commit_list_filtered(&filter_options, rev,
+                        walken_show_commit, walken_show_object, NULL, &omitted);
+
+        ...
+----
+
+Then, after your traversal, the `oidset` traversal is pretty straightforward.
+Count all the objects within and modify the print statement:
+
+----
+        /* Count the omitted objects. */
+        oidset_iter_init(&omitted, &oit);
+
+        while ((oid = oidset_iter_next(&oit)))
+                omitted_count++;
+
+        printf("commits %d\nblobs %d\ntags %d\ntrees%d\nomitted %d\n",
+                commit_count, blob_count, tag_count, tree_count, omitted_count);
+----
+
+By running your walk with and without the filter, you should find that the total
+object count in each case is identical. You can also time each invocation of
+the `walken` subcommand, with and without `omitted` being passed in, to confirm
+to yourself the runtime impact of tracking all omitted objects.
+
+=== Changing the Order
+
+Finally, let's demonstrate that you can also reorder walks of all objects, not
+just walks of commits. First, we'll make our handlers chattier - modify
+`walken_show_commit()` and `walken_show_object()` to print the object as they
+go:
+
+----
+static void walken_show_commit(struct commit *cmt, void *buf)
+{
+        trace_printf("commit: %s\n", oid_to_hex(&cmt->object.oid));
+        commit_count++;
+}
+
+static void walken_show_object(struct object *obj, const char *str, void *buf)
+{
+        trace_printf("%s: %s\n", type_name(obj->type), oid_to_hex(&obj->oid));
+
+        ...
+}
+----
+
+NOTE: Since we will be examining this output directly as humans, we'll use
+`trace_printf()` here. Additionally, since this change introduces a significant
+number of printed lines, using `trace_printf()` will allow us to easily silence
+those lines without having to recompile.
+
+(Leave the counter increment logic in place.)
+
+With only that change, run again (but save yourself some scrollback):
+
+----
+$ GIT_TRACE=1 ./bin-wrappers/git walken | head -n 10
+----
+
+Take a look at the top commit with `git show` and the object ID you printed; it
+should be the same as the output of `git show HEAD`.
+
+Next, let's change a setting on our `struct rev_info` within
+`walken_object_walk()`. Find where you're changing the other settings on `rev`,
+such as `rev->tree_objects` and `rev->tree_blobs_in_commit_order`, and add the
+`reverse` setting at the bottom:
+
+----
+        ...
+
+        rev->tree_objects = 1;
+        rev->blob_objects = 1;
+        rev->tag_objects = 1;
+        rev->tree_blobs_in_commit_order = 1;
+        rev->reverse = 1;
+
+        ...
+----
+
+Now, run again, but this time, let's grab the last handful of objects instead
+of the first handful:
+
+----
+$ make
+$ GIT_TRACE=1 ./bin-wrappers git walken | tail -n 10
+----
+
+The last commit object given should have the same OID as the one we saw at the
+top before, and running `git show <oid>` with that OID should give you again
+the same results as `git show HEAD`. Furthermore, if you run and examine the
+first ten lines again (with `head` instead of `tail` like we did before applying
+the `reverse` setting), you should see that now the first commit printed is the
+initial commit, `e83c5163`.
+
+== Wrapping Up
+
+Let's review. In this tutorial, we:
+
+- Built a commit walk from the ground up
+- Enabled a grep filter for that commit walk
+- Changed the sort order of that filtered commit walk
+- Built an object walk (tags, commits, trees, and blobs) from the ground up
+- Learned how to add a filter-spec to an object walk
+- Changed the display order of the filtered object walk
diff --git a/Documentation/RelNotes/1.5.0.txt b/Documentation/RelNotes/1.5.0.txt
index daf4bdb0d7..d6d42f3183 100644
--- a/Documentation/RelNotes/1.5.0.txt
+++ b/Documentation/RelNotes/1.5.0.txt
@@ -251,7 +251,7 @@ Updates in v1.5.0 since v1.4.4 series
    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 @@ Updates in v1.5.0 since v1.4.4 series
  - 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.5.4.txt b/Documentation/RelNotes/1.6.5.4.txt
index d3a2a3e712..344333de66 100644
--- a/Documentation/RelNotes/1.6.5.4.txt
+++ b/Documentation/RelNotes/1.6.5.4.txt
@@ -10,7 +10,7 @@ Fixes since v1.6.5.3
 
  * "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.7.0.2.txt b/Documentation/RelNotes/1.7.0.2.txt
index fcb46ca6a4..73ed2b5278 100644
--- a/Documentation/RelNotes/1.7.0.2.txt
+++ b/Documentation/RelNotes/1.7.0.2.txt
@@ -34,7 +34,7 @@ Fixes since v1.7.0.1
  * "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 326670df6e..57597f2bf3 100644
--- a/Documentation/RelNotes/1.7.10.4.txt
+++ b/Documentation/RelNotes/1.7.10.4.txt
@@ -7,7 +7,7 @@ Fixes since v1.7.10.3
  * 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 ecda427a35..4b822976b8 100644
--- a/Documentation/RelNotes/1.7.12.3.txt
+++ b/Documentation/RelNotes/1.7.12.3.txt
@@ -25,7 +25,7 @@ Fixes since v1.7.12.2
    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 9c03353af2..1d24edcf2f 100644
--- a/Documentation/RelNotes/1.7.5.3.txt
+++ b/Documentation/RelNotes/1.7.5.3.txt
@@ -22,7 +22,7 @@ Fixes since v1.7.5.2
  * "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 43883c14f0..63d6e4afa4 100644
--- a/Documentation/RelNotes/1.8.0.txt
+++ b/Documentation/RelNotes/1.8.0.txt
@@ -233,7 +233,7 @@ to them for details).
    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 96090ef599..c257beb114 100644
--- a/Documentation/RelNotes/1.8.4.1.txt
+++ b/Documentation/RelNotes/1.8.4.1.txt
@@ -15,7 +15,7 @@ Fixes since v1.8.4
    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/2.1.3.txt b/Documentation/RelNotes/2.1.3.txt
index acc9ebb886..0dfb17c4fc 100644
--- a/Documentation/RelNotes/2.1.3.txt
+++ b/Documentation/RelNotes/2.1.3.txt
@@ -13,7 +13,7 @@ Git v2.1.3 Release Notes
    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 f4da28ab66..3792b7d03d 100644
--- a/Documentation/RelNotes/2.10.0.txt
+++ b/Documentation/RelNotes/2.10.0.txt
@@ -478,7 +478,7 @@ notes for details).
  * 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 c4d4397023..abbd331508 100644
--- a/Documentation/RelNotes/2.10.2.txt
+++ b/Documentation/RelNotes/2.10.2.txt
@@ -86,7 +86,7 @@ Fixes since v2.10.1
    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 9cd14c8197..7d35cf186d 100644
--- a/Documentation/RelNotes/2.11.1.txt
+++ b/Documentation/RelNotes/2.11.1.txt
@@ -104,7 +104,7 @@ Fixes since v2.11
    "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 ef8b97da9b..d2f6a83614 100644
--- a/Documentation/RelNotes/2.12.0.txt
+++ b/Documentation/RelNotes/2.12.0.txt
@@ -315,7 +315,7 @@ notes for details).
    "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 aa99d4b3ce..2a47b4cb0c 100644
--- a/Documentation/RelNotes/2.13.0.txt
+++ b/Documentation/RelNotes/2.13.0.txt
@@ -177,7 +177,7 @@ UI, Workflows & Features
    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 5d76ad5310..384e4de265 100644
--- a/Documentation/RelNotes/2.13.3.txt
+++ b/Documentation/RelNotes/2.13.3.txt
@@ -25,7 +25,7 @@ Fixes since v2.13.2
  * 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 @@ Fixes since v2.13.2
  * 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 4246c68ff5..2711a2529d 100644
--- a/Documentation/RelNotes/2.14.0.txt
+++ b/Documentation/RelNotes/2.14.0.txt
@@ -141,7 +141,7 @@ Performance, Internal Implementation, Development Support etc.
  * 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 @@ notes for details).
  * 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.16.0.txt b/Documentation/RelNotes/2.16.0.txt
index 0c81c5915f..b474781ed8 100644
--- a/Documentation/RelNotes/2.16.0.txt
+++ b/Documentation/RelNotes/2.16.0.txt
@@ -407,7 +407,7 @@ Fixes since v2.15
    (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 64a0bcb0d2..f0121a8f2d 100644
--- a/Documentation/RelNotes/2.16.3.txt
+++ b/Documentation/RelNotes/2.16.3.txt
@@ -24,7 +24,7 @@ Fixes since v2.16.2
 
  * 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.17.0.txt b/Documentation/RelNotes/2.17.0.txt
index c2cf891f71..8b17c26033 100644
--- a/Documentation/RelNotes/2.17.0.txt
+++ b/Documentation/RelNotes/2.17.0.txt
@@ -216,7 +216,7 @@ Fixes since v2.16
 
  * 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.18.0.txt b/Documentation/RelNotes/2.18.0.txt
index 3ea280cf68..6c8a0e97c1 100644
--- a/Documentation/RelNotes/2.18.0.txt
+++ b/Documentation/RelNotes/2.18.0.txt
@@ -179,7 +179,7 @@ Performance, Internal Implementation, Development Support etc.
    (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.19.0.txt b/Documentation/RelNotes/2.19.0.txt
index a06ccf6e2a..891c79b9cb 100644
--- a/Documentation/RelNotes/2.19.0.txt
+++ b/Documentation/RelNotes/2.19.0.txt
@@ -106,7 +106,7 @@ Performance, Internal Implementation, Development Support etc.
  * 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.20.0.txt b/Documentation/RelNotes/2.20.0.txt
index e71fe3dee1..3dd7e6e1fc 100644
--- a/Documentation/RelNotes/2.20.0.txt
+++ b/Documentation/RelNotes/2.20.0.txt
@@ -119,7 +119,7 @@ UI, Workflows & Features
    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.24.0.txt b/Documentation/RelNotes/2.24.0.txt
index 08a3973383..bde154124c 100644
--- a/Documentation/RelNotes/2.24.0.txt
+++ b/Documentation/RelNotes/2.24.0.txt
@@ -6,10 +6,9 @@ Updates since v2.23
 
 Backward compatibility note
 
- * Although it is not officially deprecated, "filter-branch" is
-   showing its age and alternatives are available.  From this release,
-   we started to discourage its uses and hint people about
-   filter-repo.
+ * "filter-branch" is showing its age and alternatives are available.
+   From this release, we started to discourage its use and hint
+   people about filter-repo.
 
 UI, Workflows & Features
 
@@ -68,6 +67,16 @@ UI, Workflows & Features
  * A configuration variable tells "git fetch" to write the commit
    graph after finishing.
 
+ * "git add -i" has been taught to show the total number of hunks and
+   the hunks that has been processed so far when showing prompts.
+
+ * "git fetch --jobs=<n>" allowed <n> parallel jobs when fetching
+   submodules, but this did not apply to "git fetch --multiple" that
+   fetches from multiple remote repositories.  It now does.
+
+ * The installation instruction for zsh completion script (in
+   contrib/) has been a bit improved.
+
 
 Performance, Internal Implementation, Development Support etc.
 
@@ -123,6 +132,20 @@ Performance, Internal Implementation, Development Support etc.
 
  * Update the way build artifacts in t/helper/ directory are ignored.
 
+ * Preparation for SHA-256 upgrade continues.
+
+ * "git log --graph" for an octopus merge is sometimes colored
+   incorrectly, which is demonstrated and documented but not yet
+   fixed.
+
+ * The trace2 output, when sending them to files in a designated
+   directory, can populate the directory with too many files; a
+   mechanism is introduced to set the maximum number of files and
+   discard further logs when the maximum is reached.
+
+ * We have adopted a Code-of-conduct document.
+   (merge 3f9ef874a7 jk/coc later to maint).
+
 
 Fixes since v2.23
 -----------------
@@ -268,6 +291,58 @@ Fixes since v2.23
    has been fixed.
    (merge b181676ce9 rs/convert-fix-utf-without-dash later to maint).
 
+ * The author names taken from SVN repositories may have extra leading
+   or trailing whitespaces, which are now munged away.
+   (merge 4ddd4bddb1 tk/git-svn-trim-author-name later to maint).
+
+ * "git rebase -i" showed a wrong HEAD while "reword" open the editor.
+   (merge b0a3186140 pw/rebase-i-show-HEAD-to-reword later to maint).
+
+ * A few simplification and bugfixes to PCRE interface.
+   (merge c581e4a749 ab/pcre-jit-fixes later to maint).
+
+ * PCRE fixes.
+   (merge ff61681b46 cb/pcre1-cleanup later to maint).
+
+ * "git range-diff" segfaulted when diff.noprefix configuration was
+   used, as it blindly expected the patch it internally generates to
+   have the standard a/ and b/ prefixes.  The command now forces the
+   internal patch to be built without any prefix, not to be affected
+   by any end-user configuration.
+   (merge 937b76ed49 js/range-diff-noprefix later to maint).
+
+ * "git stash apply" in a subdirectory of a secondary worktree failed
+   to access the worktree correctly, which has been corrected.
+   (merge dfd557c978 js/stash-apply-in-secondary-worktree later to maint).
+
+ * The merge-recursive machinery is one of the most complex parts of
+   the system that accumulated cruft over time.  This large series
+   cleans up the implementation quite a bit.
+   (merge b657047719 en/merge-recursive-cleanup later to maint).
+
+ * Pretty-printed command line formatter (used in e.g. reporting the
+   command being run by the tracing API) had a bug that lost an
+   argument that is an empty string, which has been corrected.
+   (merge ce2d7ed2fd gs/sq-quote-buf-pretty later to maint).
+
+ * "git range-diff" failed to handle mode-only change, which has been
+   corrected.
+   (merge 2b6a9b13ca tg/range-diff-output-update later to maint).
+
+ * Dev support update.
+   (merge 4f3c1dc5d6 dl/allow-running-cocci-verbosely later to maint).
+
+ * "git format-patch -o <outdir>" did an equivalent of "mkdir <outdir>"
+   not "mkdir -p <outdir>", which was corrected.
+
+ * "git stash save" lost local changes to submodules, which has been
+   corrected.
+   (merge 556895d0c8 jj/stash-reset-only-toplevel later to maint).
+
+ * The atomic push over smart HTTP transport did not work, which has
+   been corrected.
+   (merge 6f1194246a bc/smart-http-atomic-push later to maint).
+
  * Other code cleanup, docfix, build fix, etc.
    (merge d1387d3895 en/fast-import-merge-doc later to maint).
    (merge 1c24a54ea4 bm/repository-layout-typofix later to maint).
@@ -305,3 +380,19 @@ Fixes since v2.23
    (merge 71f4960b91 js/mingw-spawn-with-spaces-in-path later to maint).
    (merge 53d687bf5f ah/cleanups later to maint).
    (merge f537485fa5 rs/test-remove-useless-debugging-cat later to maint).
+   (merge 11a3d3aadd dl/rev-list-doc-cleanup later to maint).
+   (merge d928a8388a am/t0028-utf16-tests later to maint).
+   (merge b05b40930e dl/t0000-skip-test-test later to maint).
+   (merge 03d3b1297c js/xdiffi-comment-updates later to maint).
+   (merge 57d8f4b4c7 js/doc-stash-save later to maint).
+   (merge 8c1cfd58e3 ta/t1308-typofix later to maint).
+   (merge fa364ad790 bb/utf8-wcwidth-cleanup later to maint).
+   (merge 68b69211b2 bb/compat-util-comment-fix later to maint).
+   (merge 5cc6a4be11 rs/http-push-simplify later to maint).
+   (merge a81e42d235 rs/column-use-utf8-strnwidth later to maint).
+   (merge 062a309d36 rs/remote-curl-use-argv-array later to maint).
+   (merge 3b3c79f6c9 nr/diff-highlight-indent-fix later to maint).
+   (merge 3444ec2eb2 wb/fsmonitor-bitmap-fix later to maint).
+   (merge 10da030ab7 cb/pcre2-chartables-leakfix later to maint).
+   (merge 60e6569a12 js/mingw-needs-hiding-fix later to maint).
+   (merge 52bd3e4657 rl/gitweb-blame-prev-fix later to maint).
diff --git a/Documentation/RelNotes/2.25.0.txt b/Documentation/RelNotes/2.25.0.txt
new file mode 100644
index 0000000000..b61b69f20b
--- /dev/null
+++ b/Documentation/RelNotes/2.25.0.txt
@@ -0,0 +1,68 @@
+Git 2.25 Release Notes
+======================
+
+Updates since v2.24
+-------------------
+
+Backward compatibility notes
+
+
+UI, Workflows & Features
+
+ * A tutorial on object enumeration has been added.
+
+ * The branch description ("git branch --edit-description") has been
+   used to fill the body of the cover letters by the format-patch
+   command; this has been enhanced so that the subject can also be
+   filled.
+
+ * "git rebase --preserve-merges" has been marked as deprecated; this
+   release stops advertising it in the "git rebase -h" output.
+
+ * The code to generate multi-pack index learned to show (or not to
+   show) progress indicators.
+
+ * "git apply --3way" learned to honor merge.conflictStyle
+   configuration variable, like merges would.
+
+ * The custom format for "git log --format=<format>" learned the l/L
+   placeholder that is similar to e/E that fills in the e-mail
+   address, but only the local part on the left side of '@'.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Debugging support for lazy cloning has been a bit improved.
+
+ * Move the definition of a set of bitmask constants from 0ctal
+   literal to (1U<<count) notation.
+
+ * Test updates to prepare for SHA-2 transition continues.
+
+
+Fixes since v2.24
+-----------------
+
+ * "rebase -i" ceased to run post-commit hook by mistake in an earlier
+   update, which has been corrected.
+
+ * "git notes copy $original" ought to copy the notes attached to the
+   original object to HEAD, but a mistaken tightening to command line
+   parameter validation made earlier disabled that feature by mistake.
+
+ * When all files from some subdirectory were renamed to the root
+   directory, the directory rename heuristics would fail to detect that
+   as a rename/merge of the subdirectory to the root directory, which has
+   been corrected.
+
+ * Code clean-up and a bugfix in the logic used to tell worktree local
+   and repository global refs apart.
+   (merge f45f88b2e4 sg/dir-trie-fixes later to maint).
+
+ * "git stash save" in a working tree that is sparsely checked out
+   mistakenly removed paths that are outside the area of interest.
+   (merge 4a58c3d7f7 js/update-index-ignore-removal-for-skip-worktree 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).
diff --git a/Documentation/RelNotes/2.3.3.txt b/Documentation/RelNotes/2.3.3.txt
index 5ef12644c2..850dc68ede 100644
--- a/Documentation/RelNotes/2.3.3.txt
+++ b/Documentation/RelNotes/2.3.3.txt
@@ -12,7 +12,7 @@ Fixes since v2.3.2
  * 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 fc95812cb3..5769184081 100644
--- a/Documentation/RelNotes/2.3.7.txt
+++ b/Documentation/RelNotes/2.3.7.txt
@@ -4,7 +4,7 @@ Git v2.3.7 Release Notes
 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 914d2c1860..422e930aa2 100644
--- a/Documentation/RelNotes/2.4.3.txt
+++ b/Documentation/RelNotes/2.4.3.txt
@@ -66,7 +66,7 @@ Fixes since v2.4.3
  * 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.7.0.txt b/Documentation/RelNotes/2.7.0.txt
index 563dadc57e..e3cbf3a73c 100644
--- a/Documentation/RelNotes/2.7.0.txt
+++ b/Documentation/RelNotes/2.7.0.txt
@@ -40,7 +40,7 @@ UI, Workflows & Features
 
  * "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.8.0.txt b/Documentation/RelNotes/2.8.0.txt
index 5fbe1b86ee..27320b6a9f 100644
--- a/Documentation/RelNotes/2.8.0.txt
+++ b/Documentation/RelNotes/2.8.0.txt
@@ -189,7 +189,7 @@ Performance, Internal Implementation, Development Support etc.
  * 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.9.3.txt b/Documentation/RelNotes/2.9.3.txt
index 695b86f612..305e08062b 100644
--- a/Documentation/RelNotes/2.9.3.txt
+++ b/Documentation/RelNotes/2.9.3.txt
@@ -36,7 +36,7 @@ Fixes since v2.9.2
  * 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/config.txt b/Documentation/config.txt
index f50f1b4128..83e7bba872 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -142,7 +142,7 @@ refer to linkgit:gitignore[5] for details. For convenience:
 
 `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/core.txt b/Documentation/config/core.txt
index 852d2ba37a..bdbbee58b9 100644
--- a/Documentation/config/core.txt
+++ b/Documentation/config/core.txt
@@ -593,8 +593,14 @@ core.multiPackIndex::
         multi-pack-index design document].
 
 core.sparseCheckout::
-        Enable "sparse checkout" feature. See section "Sparse checkout" in
-        linkgit:git-read-tree[1] for more information.
+        Enable "sparse checkout" feature. See linkgit:git-sparse-checkout[1]
+        for more information.
+
+core.sparseCheckoutCone::
+        Enables the "cone mode" of the sparse checkout feature. When the
+        sparse-checkout file contains a limited set of patterns, then this
+        mode provides significant performance advantages. See
+        linkgit:git-sparse-checkout[1] for more information.
 
 core.abbrev::
         Set the length object names are abbreviated to.  If
diff --git a/Documentation/config/format.txt b/Documentation/config/format.txt
index cb629fa769..513fcd88d5 100644
--- a/Documentation/config/format.txt
+++ b/Documentation/config/format.txt
@@ -36,6 +36,12 @@ format.subjectPrefix::
         The default for format-patch is to output files with the '[PATCH]'
         subject prefix. Use this variable to change that prefix.
 
+format.coverFromDescription::
+        The default mode for format-patch to determine which parts of
+        the cover letter will be populated using the branch's
+        description. See the `--cover-from-description` option in
+        linkgit:git-format-patch[1].
+
 format.signature::
         The default for format-patch is to output a signature containing
         the Git version number. Use this variable to change that default.
@@ -81,7 +87,7 @@ format.coverLetter::
 
 format.outputDirectory::
         Set a custom directory to store the resulting files instead of the
-        current working directory.
+        current working directory. All directory components will be created.
 
 format.useAutoBase::
         A boolean value which lets you enable the `--base=auto` option of
diff --git a/Documentation/config/pack.txt b/Documentation/config/pack.txt
index 1d66f0c992..58323a351f 100644
--- a/Documentation/config/pack.txt
+++ b/Documentation/config/pack.txt
@@ -27,6 +27,10 @@ Note that changing the compression level will not automatically recompress
 all existing objects. You can force recompression by passing the -F option
 to linkgit:git-repack[1].
 
+pack.allowPackReuse::
+        When true, which is the default, Git will try to reuse parts
+        of existing packfiles when preparing new packfiles.
+
 pack.island::
         An extended regular expression configuring a set of delta
         islands. See "DELTA ISLANDS" in linkgit:git-pack-objects[1]
diff --git a/Documentation/config/tag.txt b/Documentation/config/tag.txt
index ef5adb3f42..6d9110d84c 100644
--- a/Documentation/config/tag.txt
+++ b/Documentation/config/tag.txt
@@ -13,7 +13,7 @@ tag.gpgSign::
         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/fetch-options.txt b/Documentation/fetch-options.txt
index 43b9ff3bce..a2f78624a2 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -92,6 +92,10 @@ ifndef::git-pull[]
         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-am.txt b/Documentation/git-am.txt
index fc3b993c33..fc5750b3b8 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -177,7 +177,7 @@ default.   You can use `--no-utf8` to override this.
         untouched.
 
 --show-current-patch::
-        Show the patch being applied when "git am" is stopped because
+        Show the entire e-mail message "git am" has stopped at, because
         of conflicts.
 
 DISCUSSION
diff --git a/Documentation/git-bisect-lk2009.txt b/Documentation/git-bisect-lk2009.txt
index e99925184d..2957bc5e0a 100644
--- a/Documentation/git-bisect-lk2009.txt
+++ b/Documentation/git-bisect-lk2009.txt
@@ -158,7 +158,7 @@ Test suites are very nice. But when they are used alone, they are
 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
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt
index 4b45d837a7..7586c5a843 100644
--- a/Documentation/git-bisect.txt
+++ b/Documentation/git-bisect.txt
@@ -413,7 +413,7 @@ $ cat ~/test.sh
 
 # 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 7d6c9dcd17..ccada80a4a 100644
--- a/Documentation/git-bundle.txt
+++ b/Documentation/git-bundle.txt
@@ -9,8 +9,8 @@ git-bundle - Move objects and refs by archive
 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>...]
 
@@ -33,9 +33,11 @@ destination repository.
 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.
+        '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 +77,33 @@ unbundle <file>::
         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
 ---------------------
 
diff --git a/Documentation/git-check-attr.txt b/Documentation/git-check-attr.txt
index 3c0578217b..84f41a8e82 100644
--- a/Documentation/git-check-attr.txt
+++ b/Documentation/git-check-attr.txt
@@ -32,7 +32,7 @@ OPTIONS
         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 8b42cb3fb2..8b2d49c79e 100644
--- a/Documentation/git-check-ignore.txt
+++ b/Documentation/git-check-ignore.txt
@@ -39,7 +39,7 @@ OPTIONS
         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-clone.txt b/Documentation/git-clone.txt
index 34011c2940..0fe91d2f04 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -15,7 +15,7 @@ SYNOPSIS
           [--dissociate] [--separate-git-dir <git dir>]
           [--depth <depth>] [--[no-]single-branch] [--no-tags]
           [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
-          [--[no-]remote-submodules] [--jobs <n>] [--] <repository>
+          [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--] <repository>
           [<directory>]
 
 DESCRIPTION
@@ -156,6 +156,12 @@ objects from the source repository into a pack in the cloned repository.
         used, neither remote-tracking branches nor the related
         configuration variables are created.
 
+--sparse::
+        Initialize the sparse-checkout file so the working
+        directory starts with only the files in the root
+        of the repository. The sparse-checkout file can be
+        modified to grow the working directory as needed.
+
 --mirror::
         Set up a mirror of the source repository.  This implies `--bare`.
         Compared to `--bare`, `--mirror` not only maps local branches of the
diff --git a/Documentation/git-commit-graph.txt b/Documentation/git-commit-graph.txt
index 8c708a7a16..bcd85c1976 100644
--- a/Documentation/git-commit-graph.txt
+++ b/Documentation/git-commit-graph.txt
@@ -9,7 +9,6 @@ git-commit-graph - Write and verify Git commit-graph files
 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 @@ Finally, if `--expire-time=<datetime>` is not specified, let `datetime`
 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 show-ref -s | git commit-graph write --stdin-commits
 $ 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-cvsserver.txt b/Documentation/git-cvsserver.txt
index 79e22b1f3a..1b1c71ad9d 100644
--- a/Documentation/git-cvsserver.txt
+++ b/Documentation/git-cvsserver.txt
@@ -294,7 +294,7 @@ In `dbDriver` and `dbUser` you can use the following variables:
         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 72179d993c..37781cf175 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -36,7 +36,7 @@ two blob objects, or changes between two files on disk.
         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 37634bffd1..e8950de3ba 100644
--- a/Documentation/git-fast-export.txt
+++ b/Documentation/git-fast-export.txt
@@ -142,7 +142,7 @@ by keeping the marks the same across runs.
         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-filter-branch.txt b/Documentation/git-filter-branch.txt
index 5876598852..3686a67d3e 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -534,7 +534,7 @@ repo-filter' also provides
 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]]
@@ -649,7 +649,7 @@ create hoards of confusing empty commits
 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
+* 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
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 0ac56f4b70..00bdf9b125 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -19,6 +19,7 @@ SYNOPSIS
                    [--start-number <n>] [--numbered-files]
                    [--in-reply-to=<message id>] [--suffix=.<sfx>]
                    [--ignore-if-in-upstream]
+                   [--cover-from-description=<mode>]
                    [--rfc] [--subject-prefix=<subject prefix>]
                    [(--reroll-count|-v) <n>]
                    [--to=<email>] [--cc=<email>]
@@ -66,7 +67,8 @@ they are created in the current working directory. The default path
 can be set with the `format.outputDirectory` configuration option.
 The `-o` option takes precedence over `format.outputDirectory`.
 To store patches in the current working directory even when
-`format.outputDirectory` points elsewhere, use `-o .`.
+`format.outputDirectory` points elsewhere, use `-o .`. All directory
+components will be created.
 
 By default, the subject of a single patch is "[PATCH] " followed by
 the concatenation of lines from the commit message up to the first blank
@@ -171,6 +173,26 @@ will want to ensure that threading is disabled for `git send-email`.
         patches being generated, and any patch that matches is
         ignored.
 
+--cover-from-description=<mode>::
+        Controls which parts of the cover letter will be automatically
+        populated using the branch's description.
++
+If `<mode>` is `message` or `default`, the cover letter subject will be
+populated with placeholder text. The body of the cover letter will be
+populated with the branch's description. This is the default mode when
+no configuration nor command line option is specified.
++
+If `<mode>` is `subject`, the first paragraph of the branch description will
+populate the cover letter subject. The remainder of the description will
+populate the body of the cover letter.
++
+If `<mode>` is `auto`, if the first paragraph of the branch description
+is greater than 100 bytes, then the mode will be `message`, otherwise
+`subject` will be used.
++
+If `<mode>` is `none`, both the cover letter subject and body will be
+populated with placeholder text.
+
 --subject-prefix=<subject prefix>::
         Instead of the standard '[PATCH]' prefix in the subject
         line, instead use '[<subject prefix>]'. This
@@ -347,6 +369,7 @@ with configuration variables.
         signOff = true
         outputDirectory = <directory>
         coverLetter = auto
+        coverFromDescription = auto
 ------------
 
 
diff --git a/Documentation/git-multi-pack-index.txt b/Documentation/git-multi-pack-index.txt
index 233b2b7862..642d9ac5b7 100644
--- a/Documentation/git-multi-pack-index.txt
+++ b/Documentation/git-multi-pack-index.txt
@@ -9,7 +9,7 @@ git-multi-pack-index - Write and verify multi-pack-indexes
 SYNOPSIS
 --------
 [verse]
-'git multi-pack-index' [--object-dir=<dir>] <subcommand>
+'git multi-pack-index' [--object-dir=<dir>] [--[no-]progress] <subcommand>
 
 DESCRIPTION
 -----------
@@ -23,6 +23,10 @@ OPTIONS
         `<dir>/packs/multi-pack-index` for the current MIDX file, and
         `<dir>/packs` for the pack-files to index.
 
+--[no-]progress::
+        Turn progress on/off explicitly. If neither is specified, progress is
+        shown if standard error is connected to a terminal.
+
 The following subcommands are available:
 
 write::
diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt
index f56a5a9197..ced2e8280e 100644
--- a/Documentation/git-notes.txt
+++ b/Documentation/git-notes.txt
@@ -10,7 +10,7 @@ SYNOPSIS
 [verse]
 'git notes' [list [<object>]]
 'git notes' add [-f] [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
-'git notes' copy [-f] ( --stdin | <from-object> <to-object> )
+'git notes' copy [-f] ( --stdin | <from-object> [<to-object>] )
 'git notes' append [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
 'git notes' edit [--allow-empty] [<object>]
 'git notes' show [<object>]
@@ -68,8 +68,8 @@ add::
         subcommand).
 
 copy::
-        Copy the notes for the first object onto the second object.
-        Abort if the second object already has notes, or if the first
+        Copy the notes for the first object onto the second object (defaults to
+        HEAD). Abort if the second object already has notes, or if the first
         object has none (use -f to overwrite existing notes to the
         second object). This subcommand is equivalent to:
         `git notes add [-f] -C $(git notes list <from-object>) <to-object>`
diff --git a/Documentation/git-range-diff.txt b/Documentation/git-range-diff.txt
index 8a6ea2c6c5..006feb7ec1 100644
--- a/Documentation/git-range-diff.txt
+++ b/Documentation/git-range-diff.txt
@@ -242,7 +242,7 @@ corresponding.
 
 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-read-tree.txt b/Documentation/git-read-tree.txt
index d271842608..da33f84f33 100644
--- a/Documentation/git-read-tree.txt
+++ b/Documentation/git-read-tree.txt
@@ -436,7 +436,7 @@ support.
 SEE ALSO
 --------
 linkgit:git-write-tree[1]; linkgit:git-ls-files[1];
-linkgit:gitignore[5]
+linkgit:gitignore[5]; linkgit:git-sparse-checkout[1];
 
 GIT
 ---
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 639a4179d1..0c4f038dd6 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -443,8 +443,8 @@ the `rebase-cousins` mode is turned on, such commits are instead rebased
 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
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index e72d332b83..9985477efe 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -274,6 +274,13 @@ print a message to stderr and exit with nonzero status.
         Show the path to the shared index file in split index mode, or
         empty if not in split-index mode.
 
+--show-object-format[=(storage|input|output)]::
+        Show the object format (hash algorithm) used for the repository
+        for storage inside the `.git` directory, input, or output. For
+        input, multiple algorithms may be printed, space-separated.
+        If not specified, the default is "storage".
+
+
 Other Options
 ~~~~~~~~~~~~~
 
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt
index bc80905a8a..a72ea7f7ba 100644
--- a/Documentation/git-shortlog.txt
+++ b/Documentation/git-shortlog.txt
@@ -76,6 +76,9 @@ them.
 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-sparse-checkout.txt b/Documentation/git-sparse-checkout.txt
new file mode 100644
index 0000000000..3931e4f2ad
--- /dev/null
+++ b/Documentation/git-sparse-checkout.txt
@@ -0,0 +1,153 @@
+git-sparse-checkout(1)
+======================
+
+NAME
+----
+git-sparse-checkout - Initialize and modify the sparse-checkout
+configuration, which reduces the checkout to a set of directories
+given by a list of prefixes.
+
+
+SYNOPSIS
+--------
+[verse]
+'git sparse-checkout <subcommand> [options]'
+
+
+DESCRIPTION
+-----------
+
+Initialize and modify the sparse-checkout configuration, which reduces
+the checkout to a set of directories given by a list of prefixes.
+
+THIS COMMAND IS EXPERIMENTAL. ITS BEHAVIOR, AND THE BEHAVIOR OF OTHER
+COMMANDS IN THE PRESENCE OF SPARSE-CHECKOUTS, WILL LIKELY CHANGE IN
+THE FUTURE.
+
+
+COMMANDS
+--------
+'list'::
+        Provide a list of the contents in the sparse-checkout file.
+
+'init'::
+        Enable the `core.sparseCheckout` setting. If the
+        sparse-checkout file does not exist, then populate it with
+        patterns that match every file in the root directory and
+        no other directories, then will remove all directories tracked
+        by Git. Add patterns to the sparse-checkout file to
+        repopulate the working directory.
++
+To avoid interfering with other worktrees, it first enables the
+`extensions.worktreeConfig` setting and makes sure to set the
+`core.sparseCheckout` setting in the worktree-specific config file.
+
+'set'::
+        Write a set of patterns to the sparse-checkout file, as given as
+        a list of arguments following the 'set' subcommand. Update the
+        working directory to match the new patterns. Enable the
+        core.sparseCheckout config setting if it is not already enabled.
+
+'disable'::
+        Remove the sparse-checkout file, set `core.sparseCheckout` to
+        `false`, and restore the working directory to include all files.
+
+SPARSE CHECKOUT
+---------------
+
+"Sparse checkout" allows populating the working directory sparsely.
+It uses the skip-worktree bit (see linkgit:git-update-index[1]) to tell
+Git whether a file in the working directory is worth looking at. If
+the skip-worktree bit is set, then the file is ignored in the working
+directory. Git will not populate the contents of those files, which
+makes a sparse checkout helpful when working in a repository with many
+files, but only a few are important to the current user.
+
+The `$GIT_DIR/info/sparse-checkout` file is used to define the
+skip-worktree reference bitmap. When Git updates the working
+directory, it updates the skip-worktree bits in the index based
+on this file. The files matching the patterns in the file will
+appear in the working directory, and the rest will not.
+
+To enable the sparse-checkout feature, run `git sparse-checkout init` to
+initialize a simple sparse-checkout file and enable the `core.sparseCheckout`
+config setting. Then, run `git sparse-checkout set` to modify the patterns in
+the sparse-checkout file.
+
+To repopulate the working directory with all files, use the
+`git sparse-checkout disable` command.
+
+## FULL PATTERN SET
+
+By default, the sparse-checkout file uses the same syntax as `.gitignore`
+files.
+
+While `$GIT_DIR/info/sparse-checkout` is usually used to specify what
+files are included, you can also specify what files are _not_ included,
+using negative patterns. For example, to remove the file `unwanted`:
+
+----------------
+/*
+!unwanted
+----------------
+
+
+## CONE PATTERN SET
+
+The full pattern set allows for arbitrary pattern matches and complicated
+inclusion/exclusion rules. These can result in O(N*M) pattern matches when
+updating the index, where N is the number of patterns and M is the number
+of paths in the index. To combat this performance issue, a more restricted
+pattern set is allowed when `core.spareCheckoutCone` is enabled.
+
+The accepted patterns in the cone pattern set are:
+
+1. *Recursive:* All paths inside a directory are included.
+
+2. *Parent:* All files immediately inside a directory are included.
+
+In addition to the above two patterns, we also expect that all files in the
+root directory are included. If a recursive pattern is added, then all
+leading directories are added as parent patterns.
+
+By default, when running `git sparse-checkout init`, the root directory is
+added as a parent pattern. At this point, the sparse-checkout file contains
+the following patterns:
+
+```
+/*
+!/*/
+```
+
+This says "include everything in root, but nothing two levels below root."
+If we then add the folder `A/B/C` as a recursive pattern, the folders `A` and
+`A/B` are added as parent patterns. The resulting sparse-checkout file is
+now
+
+```
+/*
+!/*/
+/A/
+!/A/*/
+/A/B/
+!/A/B/*/
+/A/B/C/
+```
+
+Here, order matters, so the negative patterns are overridden by the positive
+patterns that appear lower in the file.
+
+If `core.sparseCheckoutCone=true`, then Git will parse the sparse-checkout file
+expecting patterns of these types. Git will warn if the patterns do not match.
+If the patterns do match the expected format, then Git will use faster hash-
+based algorithms to compute inclusion in the sparse-checkout.
+
+SEE ALSO
+--------
+
+linkgit:git-read-tree[1]
+linkgit:gitignore[5]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index 8fbe12c66c..53e1a1205d 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -87,8 +87,9 @@ The `--patch` option implies `--keep-index`.  You can use
 save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::
 
         This option is deprecated in favour of 'git stash push'.  It
-        differs from "stash push" in that it cannot take pathspecs,
-        and any non-option arguments form the message.
+        differs from "stash push" in that it cannot take pathspecs.
+        Instead, all non-option arguments are concatenated to form the stash
+        message.
 
 list [<options>]::
 
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 2e5599a67f..f6d9791780 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -65,7 +65,7 @@ OPTIONS
 --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 1c4d146a41..c7a6271daf 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -16,6 +16,7 @@ SYNOPSIS
              [--chmod=(+|-)x]
              [--[no-]assume-unchanged]
              [--[no-]skip-worktree]
+             [--[no-]ignore-skip-worktree-entries]
              [--[no-]fsmonitor-valid]
              [--ignore-submodules]
              [--[no-]split-index]
@@ -113,6 +114,11 @@ you will need to handle the situation manually.
         set and unset the "skip-worktree" bit for the paths. See
         section "Skip-worktree bit" below for more information.
 
+
+--[no-]ignore-skip-worktree-entries::
+        Do not remove skip-worktree (AKA "index-only") entries even when
+        the `--remove` option was specified.
+
 --[no-]fsmonitor-valid::
         When one of these flags is specified, the object name recorded
         for the paths are not updated. Instead, these options
@@ -426,7 +432,7 @@ specified by the splitIndex.sharedIndexExpire config variable (see
 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 9b82564d1a..1b678e22db 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -271,8 +271,8 @@ In general, the interrogate commands do not touch the files in
 the working tree.
 
 
-Synching repositories
-~~~~~~~~~~~~~~~~~~~~~
+Syncing repositories
+~~~~~~~~~~~~~~~~~~~~
 
 include::cmds-synchingrepositories.txt[]
 
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index c5a528c667..508fe713c4 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -293,10 +293,10 @@ web front ends do not visualize the contents of these files by default.
 
 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 @@ command. This is achieved by using the long-running process protocol
 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 @@ patterns are available:
 
 - `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/gitmodules.txt b/Documentation/gitmodules.txt
index f2a65ba0ca..953c3876f0 100644
--- a/Documentation/gitmodules.txt
+++ b/Documentation/gitmodules.txt
@@ -81,7 +81,7 @@ submodule.<name>.ignore::
             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.
 
diff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt
index a5c3c04371..f48a031dc3 100644
--- a/Documentation/gitremote-helpers.txt
+++ b/Documentation/gitremote-helpers.txt
@@ -509,6 +509,11 @@ set by Git if the remote helper has the 'option' capability.
         Indicate that only the objects wanted need to be fetched, not
         their dependents.
 
+'option atomic' {'true'|'false'}::
+        When pushing, request the remote server to update refs in a single atomic
+        transaction.  If successful, all refs will be updated, or none will.  If the
+        remote side does not support this capability, the push will fail.
+
 SEE ALSO
 --------
 linkgit:git-remote[1]
diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt
index d6388f10bb..1a2ef4c150 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -96,9 +96,9 @@ refs::
         directory.  The 'git prune' command knows to preserve
         objects reachable from refs found in this directory and
         its subdirectories.
-        This directory is ignored (except refs/bisect and
-        refs/worktree) if $GIT_COMMON_DIR is set and
-        "$GIT_COMMON_DIR/refs" will be used instead.
+        This directory is ignored (except refs/bisect,
+        refs/rewritten and refs/worktree) if $GIT_COMMON_DIR is
+        set and "$GIT_COMMON_DIR/refs" will be used instead.
 
 refs/heads/`name`::
         records tip-of-the-tree commit objects of branch `name`
@@ -240,8 +240,8 @@ remotes::
 logs::
         Records of changes made to refs are stored in this directory.
         See linkgit:git-update-ref[1] for more information. This
-        directory is ignored if $GIT_COMMON_DIR is set and
-        "$GIT_COMMON_DIR/logs" will be used instead.
+        directory is ignored (except logs/HEAD) if $GIT_COMMON_DIR is
+        set and "$GIT_COMMON_DIR/logs" will be used instead.
 
 logs/refs/heads/`name`::
         Records all changes made to the branch tip named `name`.
diff --git a/Documentation/gitsubmodules.txt b/Documentation/gitsubmodules.txt
index 0a890205b8..c476f891b5 100644
--- a/Documentation/gitsubmodules.txt
+++ b/Documentation/gitsubmodules.txt
@@ -3,7 +3,7 @@ gitsubmodules(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 bd1027433b..81be0d6115 100644
--- a/Documentation/howto/separating-topic-branches.txt
+++ b/Documentation/howto/separating-topic-branches.txt
@@ -81,7 +81,7 @@ After I am done, I'd try a pretend-merge between "topicA" and
               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/manpage-bold-literal.xsl b/Documentation/manpage-bold-literal.xsl
index 608eb5df62..94d6c1b545 100644
--- a/Documentation/manpage-bold-literal.xsl
+++ b/Documentation/manpage-bold-literal.xsl
@@ -1,12 +1,13 @@
 <!-- manpage-bold-literal.xsl:
      special formatting for manpages rendered from asciidoc+docbook -->
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:d="http://docbook.org/ns/docbook"
                 version="1.0">
 
 <!-- render literal text as bold (instead of plain or monospace);
      this makes literal text easier to distinguish in manpages
      viewed on a tty -->
-<xsl:template match="literal">
+<xsl:template match="literal|d:literal">
         <xsl:value-of select="$git.docbook.backslash"/>
         <xsl:text>fB</xsl:text>
         <xsl:apply-templates/>
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 59b8ff1e51..40dc4f5e8c 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -34,7 +34,7 @@ set to `no` at the beginning of them.
 
 --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 aa66cbe41e..2912de706b 100644
--- a/Documentation/merge-strategies.txt
+++ b/Documentation/merge-strategies.txt
@@ -32,7 +32,7 @@ The 'recursive' strategy can take the following options:
 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 b87e2e83e6..31c6e8d2b8 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -163,6 +163,9 @@ The placeholders are:
 '%ae':: author email
 '%aE':: author email (respecting .mailmap, see linkgit:git-shortlog[1]
         or linkgit:git-blame[1])
+'%al':: author email local-part (the part before the '@' sign)
+'%aL':: author local-part (see '%al') respecting .mailmap, see
+        linkgit:git-shortlog[1] or linkgit:git-blame[1])
 '%ad':: author date (format respects --date= option)
 '%aD':: author date, RFC2822 style
 '%ar':: author date, relative
@@ -175,6 +178,9 @@ The placeholders are:
 '%ce':: committer email
 '%cE':: committer email (respecting .mailmap, see
         linkgit:git-shortlog[1] or linkgit:git-blame[1])
+'%cl':: author email local-part (the part before the '@' sign)
+'%cL':: author local-part (see '%cl') respecting .mailmap, see
+        linkgit:git-shortlog[1] or linkgit:git-blame[1])
 '%cd':: committer date (format respects --date= option)
 '%cD':: committer date, RFC2822 style
 '%cr':: committer date, relative
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 90ff9e2bea..e37df921b5 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -579,6 +579,7 @@ above) if (1) they are referenced by tags, or (2) they change the
 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 +635,9 @@ This option can be used along with `--bisect-vars`, in this case,
 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 +679,9 @@ together.
         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 +821,9 @@ endif::git-rev-list[]
 
 --do-walk::
         Overrides a previous `--no-walk`.
+endif::git-shortlog[]
 
+ifndef::git-shortlog[]
 Commit Formatting
 ~~~~~~~~~~~~~~~~~
 
@@ -973,7 +979,9 @@ ifdef::git-rev-list[]
         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 +1024,4 @@ options may be given. See linkgit:git-diff-files[1] for more options.
 -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-config.txt b/Documentation/technical/api-config.txt
deleted file mode 100644
index 7d20716c32..0000000000
--- 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-grep.txt b/Documentation/technical/api-grep.txt
deleted file mode 100644
index a69cc8964d..0000000000
--- a/Documentation/technical/api-grep.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-grep API
-========
-
-Talk about <grep.h>, things like:
-
-* grep_buffer()
-
-(JC)
diff --git a/Documentation/technical/api-object-access.txt b/Documentation/technical/api-object-access.txt
deleted file mode 100644
index 5b29622d00..0000000000
--- a/Documentation/technical/api-object-access.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-object access API
-=================
-
-Talk about <sha1-file.c> and <object.h> family, things like
-
-* read_sha1_file()
-* read_object_with_reference()
-* has_sha1_file()
-* write_sha1_file()
-* pretend_object_file()
-* lookup_{object,commit,tag,blob,tree}
-* parse_{object,commit,tag,blob,tree}
-* Use of object flags
-
-(JC, Shawn, Daniel, Dscho, Linus)
diff --git a/Documentation/technical/api-quote.txt b/Documentation/technical/api-quote.txt
deleted file mode 100644
index e8a1bce94e..0000000000
--- a/Documentation/technical/api-quote.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-quote API
-=========
-
-Talk about <quote.h>, things like
-
-* sq_quote and unquote
-* c_style quote and unquote
-* quoting for foreign languages
-
-(JC)
diff --git a/Documentation/technical/api-submodule-config.txt b/Documentation/technical/api-submodule-config.txt
index fb06089393..c409559b86 100644
--- a/Documentation/technical/api-submodule-config.txt
+++ b/Documentation/technical/api-submodule-config.txt
@@ -58,7 +58,7 @@ Functions
 
 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
+So in the normal case, when HEAD:.gitmodules is parsed first and then overlaid
 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).
diff --git a/Documentation/technical/api-trace2.txt b/Documentation/technical/api-trace2.txt
index a045dbe422..17490b528c 100644
--- a/Documentation/technical/api-trace2.txt
+++ b/Documentation/technical/api-trace2.txt
@@ -178,7 +178,7 @@ describe the simplified forms.
 
 == 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.
 
@@ -377,7 +377,7 @@ of `pthread_create()`.
         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
+(so that the correct TLS data is used and cleaned up).  It should
 not be called by the caller of `pthread_join()`.
 
 === Region and Data Messages
@@ -406,7 +406,7 @@ 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.
+recursive operations can be attributed to the correct repository.
 
 `void trace2_region_leave(const char *category, const char *label, const struct repository *repo)`::
 
@@ -421,7 +421,7 @@ 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
+The `category` and `label` do not need to match the corresponding
 "region_enter" message, but it makes the data stream easier to
 understand.
 
@@ -816,7 +816,7 @@ with "?".
 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 +1176,7 @@ d0 | main                     | atexit       |     |  0.028809 |           |
 +
 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 +1371,7 @@ d0 | main                     | atexit       |     |  0.030027 |           |
 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-xdiff-interface.txt b/Documentation/technical/api-xdiff-interface.txt
deleted file mode 100644
index 6296ecad1d..0000000000
--- a/Documentation/technical/api-xdiff-interface.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-xdiff interface API
-===================
-
-Talk about our calling convention to xdiff library, including
-xdiff_emit_consume_fn.
-
-(Dscho, JC)
diff --git a/Documentation/technical/commit-graph.txt b/Documentation/technical/commit-graph.txt
index 729fbcb32f..1507117dc2 100644
--- a/Documentation/technical/commit-graph.txt
+++ b/Documentation/technical/commit-graph.txt
@@ -22,11 +22,11 @@ as "commit-graph" either in the .git/objects/info directory or in the info
 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 @@ have generation number represented by the macro GENERATION_NUMBER_ZERO = 0.
 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
diff --git a/Documentation/technical/hash-function-transition.txt b/Documentation/technical/hash-function-transition.txt
index 2ae8fa470a..8a4596bec1 100644
--- a/Documentation/technical/hash-function-transition.txt
+++ b/Documentation/technical/hash-function-transition.txt
@@ -531,7 +531,7 @@ Until Git protocol gains SHA-256 support, using SHA-256 based storage
 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 @@ git --output-format=sha1 log abac87a^{sha1}..f787cac^{sha256}
 
 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
diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt
index 7c4d67aa6a..faa25c5c52 100644
--- a/Documentation/technical/index-format.txt
+++ b/Documentation/technical/index-format.txt
@@ -318,7 +318,7 @@ The remaining data of each directory block is grouped by type:
 == 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 @@ The remaining data of each directory block is grouped by type:
 
   - 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/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index c73e72de0e..d5ce4eea8a 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -644,7 +644,7 @@ update was successful, or 'ng [refname] [error]' if the update was not.
   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 210373e258..a6034d5610 100644
--- a/Documentation/technical/partial-clone.txt
+++ b/Documentation/technical/partial-clone.txt
@@ -32,7 +32,7 @@ if/when needed.
 
 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.
diff --git a/Documentation/technical/protocol-v2.txt b/Documentation/technical/protocol-v2.txt
index 40f91f6b1e..7e3766cafb 100644
--- a/Documentation/technical/protocol-v2.txt
+++ b/Documentation/technical/protocol-v2.txt
@@ -252,7 +252,7 @@ A `fetch` request can take the following arguments:
     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/rerere.txt b/Documentation/technical/rerere.txt
index aa22d7ace8..af5f9fc24f 100644
--- a/Documentation/technical/rerere.txt
+++ b/Documentation/technical/rerere.txt
@@ -117,7 +117,7 @@ early A became C or B, a late X became Y or Z".  We can see there are
 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/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 98f88a28d3..22e8d83d98 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.23.GIT
+DEF_VER=v2.24.GIT
 
 LF='
 '
diff --git a/INSTALL b/INSTALL
index c39006e8e7..22c364f34f 100644
--- a/INSTALL
+++ b/INSTALL
@@ -109,15 +109,15 @@ Issues of note:
 
  - 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 de60c8e7aa..2795ece4c2 100644
--- a/Makefile
+++ b/Makefile
@@ -727,6 +727,7 @@ TEST_BUILTINS_OBJS += test-prio-queue.o
 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
@@ -1125,6 +1126,7 @@ BUILTIN_OBJS += builtin/shortlog.o
 BUILTIN_OBJS += builtin/show-branch.o
 BUILTIN_OBJS += builtin/show-index.o
 BUILTIN_OBJS += builtin/show-ref.o
+BUILTIN_OBJS += builtin/sparse-checkout.o
 BUILTIN_OBJS += builtin/stash.o
 BUILTIN_OBJS += builtin/stripspace.o
 BUILTIN_OBJS += builtin/submodule--helper.o
@@ -1885,6 +1887,7 @@ ifndef V
         QUIET_SP       = @echo '   ' SP $<;
         QUIET_HDR      = @echo '   ' HDR $(<:hcc=h);
         QUIET_RC       = @echo '   ' RC $@;
+        QUIET_SPATCH   = @echo '   ' SPATCH $<;
         QUIET_SUBDIR0  = +@subdir=
         QUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \
                          $(MAKE) $(PRINT_DIR) -C $$subdir
@@ -2813,7 +2816,7 @@ FOUND_C_SOURCES = $(filter %.c,$(shell $(FIND_SOURCE_FILES)))
 COCCI_SOURCES = $(filter-out $(THIRD_PARTY_SOURCES),$(FOUND_C_SOURCES))
 
 %.cocci.patch: %.cocci $(COCCI_SOURCES)
-        @echo '    ' SPATCH $<; \
+        $(QUIET_SPATCH) \
         if test $(SPATCH_BATCH_SIZE) = 0; then \
                 limit=; \
         else \
diff --git a/RelNotes b/RelNotes
index fc657e7d2f..091dd024b3 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.24.0.txt \ No newline at end of file
+Documentation/RelNotes/2.25.0.txt \ No newline at end of file
diff --git a/apply.c b/apply.c
index f8a046a6a5..d57ac0d052 100644
--- a/apply.c
+++ b/apply.c
@@ -32,7 +32,7 @@ static void git_apply_config(void)
 {
         git_config_get_string_const("apply.whitespace", &apply_default_whitespace);
         git_config_get_string_const("apply.ignorewhitespace", &apply_default_ignorewhitespace);
-        git_config(git_default_config, NULL);
+        git_config(git_xmerge_config, NULL);
 }
 
 static int parse_whitespace_option(struct apply_state *state, const char *option)
@@ -4183,8 +4183,8 @@ static void show_rename_copy(struct patch *p)
                 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/azure-pipelines.yml b/azure-pipelines.yml
index 9f099b9529..af2a5ea484 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -157,7 +157,7 @@ jobs:
     displayName: 'Download git-sdk-64-minimal'
   - powershell: |
       & git-sdk-64-minimal\usr\bin\bash.exe -lc @"
-        make vcxproj
+        make NDEBUG=1 DEVELOPER=1 vcxproj
       "@
       if (!$?) { exit(1) }
     displayName: Generate Visual Studio Solution
@@ -255,7 +255,7 @@ jobs:
 
         cd t &&
         PATH=\"`$PWD/helper:`$PATH\" &&
-        test-tool.exe run-command testsuite -V -x --write-junit-xml \
+        test-tool.exe run-command testsuite --jobs=10 -V -x --write-junit-xml \
                 `$(test-tool.exe path-utils slice-tests \
                         `$SYSTEM_JOBPOSITIONINPHASE `$SYSTEM_TOTALJOBSINPHASE t[0-9]*.sh)
       "@
diff --git a/builtin.h b/builtin.h
index 5cf5df69f7..2b25a80cde 100644
--- a/builtin.h
+++ b/builtin.h
@@ -225,6 +225,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix);
 int cmd_show(int argc, const char **argv, const char *prefix);
 int cmd_show_branch(int argc, const char **argv, const char *prefix);
 int cmd_show_index(int argc, const char **argv, const char *prefix);
+int cmd_sparse_checkout(int argc, const char **argv, const char *prefix);
 int cmd_status(int argc, const char **argv, const char *prefix);
 int cmd_stash(int argc, const char **argv, const char *prefix);
 int cmd_stripspace(int argc, const char **argv, const char *prefix);
diff --git a/builtin/blame.c b/builtin/blame.c
index e946ba6cd9..bf1cecdf3f 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -319,18 +319,18 @@ static const char *format_time(timestamp_t time, const char *tz_str,
         return time_buf.buf;
 }
 
-#define OUTPUT_ANNOTATE_COMPAT        001
-#define OUTPUT_LONG_OBJECT_NAME        002
-#define OUTPUT_RAW_TIMESTAMP        004
-#define OUTPUT_PORCELAIN        010
-#define OUTPUT_SHOW_NAME        020
-#define OUTPUT_SHOW_NUMBER        040
-#define OUTPUT_SHOW_SCORE        0100
-#define OUTPUT_NO_AUTHOR        0200
-#define OUTPUT_SHOW_EMAIL        0400
-#define OUTPUT_LINE_PORCELAIN        01000
-#define OUTPUT_COLOR_LINE        02000
-#define OUTPUT_SHOW_AGE_WITH_COLOR        04000
+#define OUTPUT_ANNOTATE_COMPAT      (1U<<0)
+#define OUTPUT_LONG_OBJECT_NAME     (1U<<1)
+#define OUTPUT_RAW_TIMESTAMP        (1U<<2)
+#define OUTPUT_PORCELAIN            (1U<<3)
+#define OUTPUT_SHOW_NAME            (1U<<4)
+#define OUTPUT_SHOW_NUMBER          (1U<<5)
+#define OUTPUT_SHOW_SCORE           (1U<<6)
+#define OUTPUT_NO_AUTHOR            (1U<<7)
+#define OUTPUT_SHOW_EMAIL           (1U<<8)
+#define OUTPUT_LINE_PORCELAIN       (1U<<9)
+#define OUTPUT_COLOR_LINE           (1U<<10)
+#define OUTPUT_SHOW_AGE_WITH_COLOR  (1U<<11)
 
 static void emit_porcelain_details(struct blame_origin *suspect, int repeat)
 {
@@ -861,14 +861,6 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                 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/bundle.c b/builtin/bundle.c
index 1ea4bfdfc1..f049d27a14 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
+};
 
-int cmd_bundle(int argc, const char **argv, const char *prefix)
-{
+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;
-        const char *cmd, *bundle_file;
         int bundle_fd = -1;
+        int quiet = 0;
 
-        if (argc < 3)
-                usage(builtin_bundle_usage);
+        struct option options[] = {
+                OPT_BOOL('q', "quiet", &quiet,
+                            N_("do not show bundle details")),
+                OPT_END()
+        };
+        const char* bundle_file;
 
-        cmd = argv[1];
-        bundle_file = prefix_filename(prefix, argv[2]);
-        argc -= 2;
-        argv += 2;
+        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 (strcmp(cmd, "create") && (bundle_fd =
-                                read_bundle_header(bundle_file, &header)) < 0)
+        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;
+}
 
-        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;
-        }
-        if (!strcmp(cmd, "list-heads")) {
-                close(bundle_fd);
-                return !!list_bundle_refs(&header, argc, argv);
+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 option options[] = {
+                OPT__VERBOSE(&verbose, N_("be verbose; must be placed before a subcommand")),
+                OPT_END()
+        };
+        int result;
+
+        argc = parse_options(argc, argv, prefix, options, builtin_bundle_usage,
+                PARSE_OPT_STOP_AT_NON_OPTION);
+
+        packet_trace_identity("bundle");
+
+        if (argc < 2)
+                usage_with_options(builtin_bundle_usage, options);
+
+        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, "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/clone.c b/builtin/clone.c
index c46ee29f0a..cc9cd5d3a9 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -59,6 +59,7 @@ static const char *real_git_dir;
 static char *option_upload_pack = "git-upload-pack";
 static int option_verbosity;
 static int option_progress = -1;
+static int option_sparse_checkout;
 static enum transport_family family;
 static struct string_list option_config = STRING_LIST_INIT_NODUP;
 static struct string_list option_required_reference = STRING_LIST_INIT_NODUP;
@@ -146,6 +147,8 @@ static struct option builtin_clone_options[] = {
         OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
         OPT_BOOL(0, "remote-submodules", &option_remote_submodules,
                     N_("any cloned submodules will use their remote-tracking branch")),
+        OPT_BOOL(0, "sparse", &option_sparse_checkout,
+                    N_("initialize sparse-checkout file to include only files at root")),
         OPT_END()
 };
 
@@ -733,6 +736,27 @@ static void update_head(const struct ref *our, const struct ref *remote,
         }
 }
 
+static int git_sparse_checkout_init(const char *repo)
+{
+        struct argv_array argv = ARGV_ARRAY_INIT;
+        int result = 0;
+        argv_array_pushl(&argv, "-C", repo, "sparse-checkout", "init", NULL);
+
+        /*
+         * We must apply the setting in the current process
+         * for the later checkout to use the sparse-checkout file.
+         */
+        core_apply_sparse_checkout = 1;
+
+        if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
+                error(_("failed to initialize sparse-checkout"));
+                result = 1;
+        }
+
+        argv_array_clear(&argv);
+        return result;
+}
+
 static int checkout(int submodule_progress)
 {
         struct object_id oid;
@@ -899,7 +923,7 @@ static void dissociate_from_references(void)
         free(alternates);
 }
 
-static int dir_exists(const char *path)
+static int path_exists(const char *path)
 {
         struct stat sb;
         return !stat(path, &sb);
@@ -927,8 +951,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
         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);
@@ -981,7 +1003,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                 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);
@@ -992,7 +1014,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                 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);
         }
 
@@ -1020,7 +1042,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
         }
 
         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 {
@@ -1106,6 +1128,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
         if (option_required_reference.nr || option_optional_reference.nr)
                 setup_reference();
 
+        if (option_sparse_checkout && git_sparse_checkout_init(repo))
+                return 1;
+
         remote = remote_get(option_origin);
 
         strbuf_addf(&default_refspec, "+%s*:%s*", src_ref_prefix,
@@ -1265,7 +1290,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
         }
 
         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 addc8d4cc0..e0c6fc4bbf 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -8,8 +8,6 @@
 #include "object-store.h"
 
 static char const * const builtin_commit_graph_usage[] = {
-        N_("git commit-graph [--object-dir <objdir>]"),
-        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
@@ -20,11 +18,6 @@ static const char * const builtin_commit_graph_verify_usage[] = {
         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
@@ -94,66 +87,6 @@ static int graph_verify(int argc, const char **argv)
         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;
 
@@ -269,8 +202,6 @@ int cmd_commit_graph(int argc, const char **argv, const char *prefix)
         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 e588bc6ad3..294dc574cd 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1463,28 +1463,6 @@ static int git_commit_config(const char *k, const char *v, void *cb)
         return git_status_config(k, v, s);
 }
 
-int run_commit_hook(int editor_is_used, const char *index_file, const char *name, ...)
-{
-        struct argv_array hook_env = ARGV_ARRAY_INIT;
-        va_list args;
-        int ret;
-
-        argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", index_file);
-
-        /*
-         * Let the hook know that no editor will be launched.
-         */
-        if (!editor_is_used)
-                argv_array_push(&hook_env, "GIT_EDITOR=:");
-
-        va_start(args, name);
-        ret = run_hook_ve(hook_env.argv,name, args);
-        va_end(args);
-        argv_array_clear(&hook_env);
-
-        return ret;
-}
-
 int cmd_commit(int argc, const char **argv, const char *prefix)
 {
         const char *argv_gc_auto[] = {"gc", "--auto", NULL};
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 0c345b5dfe..46ce7c2710 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -77,6 +77,7 @@ static struct refspec refmap = REFSPEC_INIT_FETCH;
 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 @@ static struct option builtin_fetch_options[] = {
                  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()
 };
 
@@ -1074,7 +1077,8 @@ static int check_exist_and_connected(struct ref *ref_map)
          * 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 +1404,7 @@ static int do_fetch(struct transport *transport,
 
                 /*
                  * 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 +1415,7 @@ static int do_fetch(struct transport *transport,
                 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 +1603,8 @@ static int fetch_multiple(struct string_list *list, int max_children)
                         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) {
@@ -1755,8 +1760,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 
         packet_trace_identity("fetch");
 
-        fetch_if_missing = 0;
-
         /* Record the command line for the reflog */
         strbuf_addstr(&default_rla, "fetch");
         for (i = 1; i < argc; i++)
@@ -1865,7 +1868,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
         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/fsck.c b/builtin/fsck.c
index 18403a94fa..8d13794b14 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -50,40 +50,20 @@ static int name_objects;
 #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 @@ static int objerror(struct object *obj, const char *err)
         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 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
         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 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
                 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 @@ static void check_reachable_object(struct object *obj)
                         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 @@ static void check_unreachable_object(struct object *obj)
          * 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 @@ static void check_unreachable_object(struct object *obj)
          */
         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 @@ static void check_unreachable_object(struct object *obj)
                                 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_unreachable_object(struct object *obj)
 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 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
 
         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 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
 
                 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 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
 
                 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 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
         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 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid,
         }
         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 @@ static int fsck_cache_tree(struct cache_tree *it)
                         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 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
         }
 
         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 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                         }
 
                         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 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                                 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 fadb45489f..3f76bf4aa7 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -458,7 +458,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
 /*
  * 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 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
                 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/grep.c b/builtin/grep.c
index 69ac053acc..50ce8d9461 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1147,5 +1147,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                 run_pager(&opt, prefix);
         clear_pathspec(&pathspec);
         free_grep_patterns(&opt);
+        grep_destroy();
         return !hit;
 }
diff --git a/builtin/log.c b/builtin/log.c
index c4b35fdaf9..a26f223ab4 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -37,6 +37,7 @@
 #include "range-diff.h"
 
 #define MAIL_DEFAULT_WRAP 72
+#define COVER_FROM_AUTO_MAX_SUBJECT_LEN 100
 
 /* Set a default date-time format for git log ("log.date" config variable) */
 static const char *default_date_mode = NULL;
@@ -765,23 +766,51 @@ static void add_header(const char *value)
         item->string[len] = '\0';
 }
 
-#define THREAD_SHALLOW 1
-#define THREAD_DEEP 2
-static int thread;
+enum cover_setting {
+        COVER_UNSET,
+        COVER_OFF,
+        COVER_ON,
+        COVER_AUTO
+};
+
+enum thread_level {
+        THREAD_UNSET,
+        THREAD_SHALLOW,
+        THREAD_DEEP
+};
+
+enum cover_from_description {
+        COVER_FROM_NONE,
+        COVER_FROM_MESSAGE,
+        COVER_FROM_SUBJECT,
+        COVER_FROM_AUTO
+};
+
+static enum thread_level thread;
 static int do_signoff;
 static int base_auto;
 static char *from;
 static const char *signature = git_version_string;
 static const char *signature_file;
-static int config_cover_letter;
+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;
 
-enum {
-        COVER_UNSET,
-        COVER_OFF,
-        COVER_ON,
-        COVER_AUTO
-};
+static enum cover_from_description parse_cover_from_description(const char *arg)
+{
+        if (!arg || !strcmp(arg, "default"))
+                return COVER_FROM_MESSAGE;
+        else if (!strcmp(arg, "none"))
+                return COVER_FROM_NONE;
+        else if (!strcmp(arg, "message"))
+                return COVER_FROM_MESSAGE;
+        else if (!strcmp(arg, "subject"))
+                return COVER_FROM_SUBJECT;
+        else if (!strcmp(arg, "auto"))
+                return COVER_FROM_AUTO;
+        else
+                die(_("%s: invalid cover from description mode"), arg);
+}
 
 static int git_format_config(const char *var, const char *value, void *cb)
 {
@@ -836,7 +865,7 @@ static int git_format_config(const char *var, const char *value, void *cb)
                         thread = THREAD_SHALLOW;
                         return 0;
                 }
-                thread = git_config_bool(var, value) && THREAD_SHALLOW;
+                thread = git_config_bool(var, value) ? THREAD_SHALLOW : THREAD_UNSET;
                 return 0;
         }
         if (!strcmp(var, "format.signoff")) {
@@ -888,6 +917,10 @@ static int git_format_config(const char *var, const char *value, void *cb)
                 }
                 return 0;
         }
+        if (!strcmp(var, "format.coverfromdescription")) {
+                cover_from_description_mode = parse_cover_from_description(value);
+                return 0;
+        }
 
         return git_log_config(var, value, cb);
 }
@@ -994,20 +1027,6 @@ static void print_signature(FILE *file)
         putc('\n', file);
 }
 
-static void add_branch_description(struct strbuf *buf, const char *branch_name)
-{
-        struct strbuf desc = STRBUF_INIT;
-        if (!branch_name || !*branch_name)
-                return;
-        read_branch_desc(&desc, branch_name);
-        if (desc.len) {
-                strbuf_addch(buf, '\n');
-                strbuf_addbuf(buf, &desc);
-                strbuf_addch(buf, '\n');
-        }
-        strbuf_release(&desc);
-}
-
 static char *find_branch_name(struct rev_info *rev)
 {
         int i, positive = -1;
@@ -1054,6 +1073,44 @@ static void show_diffstat(struct rev_info *rev,
         fprintf(rev->diffopt.file, "\n");
 }
 
+static void prepare_cover_text(struct pretty_print_context *pp,
+                               const char *branch_name,
+                               struct strbuf *sb,
+                               const char *encoding,
+                               int need_8bit_cte)
+{
+        const char *subject = "*** SUBJECT HERE ***";
+        const char *body = "*** BLURB HERE ***";
+        struct strbuf description_sb = STRBUF_INIT;
+        struct strbuf subject_sb = STRBUF_INIT;
+
+        if (cover_from_description_mode == COVER_FROM_NONE)
+                goto do_pp;
+
+        if (branch_name && *branch_name)
+                read_branch_desc(&description_sb, branch_name);
+        if (!description_sb.len)
+                goto do_pp;
+
+        if (cover_from_description_mode == COVER_FROM_SUBJECT ||
+                        cover_from_description_mode == COVER_FROM_AUTO)
+                body = format_subject(&subject_sb, description_sb.buf, " ");
+
+        if (cover_from_description_mode == COVER_FROM_MESSAGE ||
+                        (cover_from_description_mode == COVER_FROM_AUTO &&
+                         subject_sb.len > COVER_FROM_AUTO_MAX_SUBJECT_LEN))
+                body = description_sb.buf;
+        else
+                subject = subject_sb.buf;
+
+do_pp:
+        pp_title_line(pp, &subject, sb, encoding, need_8bit_cte);
+        pp_remainder(pp, &body, sb, 0);
+
+        strbuf_release(&description_sb);
+        strbuf_release(&subject_sb);
+}
+
 static void make_cover_letter(struct rev_info *rev, int use_stdout,
                               struct commit *origin,
                               int nr, struct commit **list,
@@ -1061,8 +1118,6 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
                               int quiet)
 {
         const char *committer;
-        const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n";
-        const char *msg;
         struct shortlog log;
         struct strbuf sb = STRBUF_INIT;
         int i;
@@ -1092,15 +1147,12 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
         if (!branch_name)
                 branch_name = find_branch_name(rev);
 
-        msg = body;
         pp.fmt = CMIT_FMT_EMAIL;
         pp.date_mode.type = DATE_RFC2822;
         pp.rev = rev;
         pp.print_email_subject = 1;
         pp_user_info(&pp, NULL, &sb, committer, encoding);
-        pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte);
-        pp_remainder(&pp, &msg, &sb, 0);
-        add_branch_description(&sb, branch_name);
+        prepare_cover_text(&pp, branch_name, &sb, encoding, need_8bit_cte);
         fprintf(rev->diffopt.file, "%s\n", sb.buf);
 
         strbuf_release(&sb);
@@ -1249,9 +1301,9 @@ static int output_directory_callback(const struct option *opt, const char *arg,
 
 static int thread_callback(const struct option *opt, const char *arg, int unset)
 {
-        int *thread = (int *)opt->value;
+        enum thread_level *thread = (enum thread_level *)opt->value;
         if (unset)
-                *thread = 0;
+                *thread = THREAD_UNSET;
         else if (!arg || !strcmp(arg, "shallow"))
                 *thread = THREAD_SHALLOW;
         else if (!strcmp(arg, "deep"))
@@ -1542,6 +1594,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
         int use_patch_format = 0;
         int quiet = 0;
         int reroll_count = -1;
+        char *cover_from_description_arg = NULL;
         char *branch_name = NULL;
         char *base_commit = NULL;
         struct base_tree_info bases;
@@ -1578,6 +1631,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                 { OPTION_CALLBACK, 0, "rfc", &rev, NULL,
                             N_("Use [RFC PATCH] instead of [PATCH]"),
                             PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback },
+                OPT_STRING(0, "cover-from-description", &cover_from_description_arg,
+                            N_("cover-from-description-mode"),
+                            N_("generate parts of a cover letter based on a branch's description")),
                 { OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"),
                             N_("Use [<prefix>] instead of [PATCH]"),
                             PARSE_OPT_NONEG, subject_prefix_callback },
@@ -1669,6 +1725,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                              PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
                              PARSE_OPT_KEEP_DASHDASH);
 
+        if (cover_from_description_arg)
+                cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
+
         if (0 < reroll_count) {
                 struct strbuf sprefix = STRBUF_INIT;
                 strbuf_addf(&sprefix, "%s v%d",
@@ -1766,10 +1825,26 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                 setup_pager();
 
         if (output_directory) {
+                int saved;
                 if (rev.diffopt.use_color != GIT_COLOR_ALWAYS)
                         rev.diffopt.use_color = GIT_COLOR_NEVER;
                 if (use_stdout)
                         die(_("standard output, or directory, which one?"));
+                /*
+                 * We consider <outdir> as 'outside of gitdir', therefore avoid
+                 * applying adjust_shared_perm in s-c-l-d.
+                 */
+                saved = get_shared_repository();
+                set_shared_repository(0);
+                switch (safe_create_leading_directories_const(output_directory)) {
+                case SCLD_OK:
+                case SCLD_EXISTS:
+                        break;
+                default:
+                        die(_("could not create leading directories "
+                              "of '%s'"), output_directory);
+                }
+                set_shared_repository(saved);
                 if (mkdir(output_directory, 0777) < 0 && errno != EEXIST)
                         die_errno(_("could not create directory '%s'"),
                                   output_directory);
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index b1ea1a6aa1..5bf88cd2a8 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -6,21 +6,25 @@
 #include "trace2.h"
 
 static char const * const builtin_multi_pack_index_usage[] = {
-        N_("git multi-pack-index [--object-dir=<dir>] (write|verify|expire|repack --batch-size=<size>)"),
+        N_("git multi-pack-index [<options>] (write|verify|expire|repack --batch-size=<size>)"),
         NULL
 };
 
 static struct opts_multi_pack_index {
         const char *object_dir;
         unsigned long batch_size;
+        int progress;
 } opts;
 
 int cmd_multi_pack_index(int argc, const char **argv,
                          const char *prefix)
 {
+        unsigned flags = 0;
+
         static struct option builtin_multi_pack_index_options[] = {
                 OPT_FILENAME(0, "object-dir", &opts.object_dir,
                   N_("object directory containing set of packfile and pack-index pairs")),
+                OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
                 OPT_MAGNITUDE(0, "batch-size", &opts.batch_size,
                   N_("during repack, collect pack-files of smaller size into a batch that is larger than this size")),
                 OPT_END(),
@@ -28,12 +32,15 @@ int cmd_multi_pack_index(int argc, const char **argv,
 
         git_config(git_default_config, NULL);
 
+        opts.progress = isatty(2);
         argc = parse_options(argc, argv, prefix,
                              builtin_multi_pack_index_options,
                              builtin_multi_pack_index_usage, 0);
 
         if (!opts.object_dir)
                 opts.object_dir = get_object_directory();
+        if (opts.progress)
+                flags |= MIDX_PROGRESS;
 
         if (argc == 0)
                 usage_with_options(builtin_multi_pack_index_usage,
@@ -47,16 +54,17 @@ int cmd_multi_pack_index(int argc, const char **argv,
         trace2_cmd_mode(argv[0]);
 
         if (!strcmp(argv[0], "repack"))
-                return midx_repack(the_repository, opts.object_dir, (size_t)opts.batch_size);
+                return midx_repack(the_repository, opts.object_dir,
+                        (size_t)opts.batch_size, flags);
         if (opts.batch_size)
                 die(_("--batch-size option is only for 'repack' subcommand"));
 
         if (!strcmp(argv[0], "write"))
-                return write_midx_file(opts.object_dir);
+                return write_midx_file(opts.object_dir, flags);
         if (!strcmp(argv[0], "verify"))
-                return verify_midx_file(the_repository, opts.object_dir);
+                return verify_midx_file(the_repository, opts.object_dir, flags);
         if (!strcmp(argv[0], "expire"))
-                return expire_midx_packs(the_repository, opts.object_dir);
+                return expire_midx_packs(the_repository, opts.object_dir, flags);
 
         die(_("unrecognized subcommand: %s"), argv[0]);
 }
diff --git a/builtin/notes.c b/builtin/notes.c
index 02e97f55c5..95456f3165 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -513,7 +513,7 @@ static int copy(int argc, const char **argv, const char *prefix)
                 }
         }
 
-        if (argc < 2) {
+        if (argc < 1) {
                 error(_("too few parameters"));
                 usage_with_options(git_notes_copy_usage, options);
         }
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 1929470221..e231c7f5ca 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -164,7 +164,7 @@ static void *get_delta(struct object_entry *entry)
         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.
          */
@@ -894,18 +894,6 @@ static void write_reused_pack_one(size_t pos, struct hashfile *out,
 
                         ofs_len = sizeof(ofs_header) - i;
 
-                        if (0) {
-                                off_t expected_size = cur - offset;
-
-                                if (len + ofs_len < expected_size) {
-                                        unsigned max_pad = (len >= 4) ? 9 : 5;
-                                        header[len - 1] |= 0x80;
-                                        while (len < max_pad && len + ofs_len < expected_size)
-                                                header[len++] = 0x80;
-                                        header[len - 1] &= 0x7F;
-                                }
-                        }
-
                         hashwrite(out, header, len);
                         hashwrite(out, ofs_header + sizeof(ofs_header) - ofs_len, ofs_len);
                         copy_pack_data(out, reuse_packfile, w_curs, cur, next - cur);
@@ -1323,7 +1311,6 @@ static int add_object_entry(const struct object_id *oid, enum object_type type,
         create_object_entry(oid, type, pack_name_hash(name),
                             exclude, name && no_try_delta(name),
                             found_pack, found_offset);
-
         return 1;
 }
 
@@ -3178,7 +3165,8 @@ static void loosen_unused_packed_objects(void)
  */
 static int pack_options_allow_reuse(void)
 {
-        return pack_to_stdout &&
+        return allow_pack_reuse &&
+               pack_to_stdout &&
                !ignore_packed_keep_on_disk &&
                !ignore_packed_keep_in_core &&
                (!local || !have_non_local_packs) &&
@@ -3190,8 +3178,7 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
         if (!(bitmap_git = prepare_bitmap_walk(revs)))
                 return -1;
 
-        if (allow_pack_reuse &&
-            pack_options_allow_reuse() &&
+        if (pack_options_allow_reuse() &&
             !reuse_partial_packfile_from_bitmap(
                         bitmap_git,
                         &reuse_packfile,
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index ca5e655d2f..d7eeaa26ec 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -162,6 +162,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
         opts.head_idx = -1;
         opts.src_index = &the_index;
         opts.dst_index = &the_index;
+        opts.verbose_update = isatty(2);
 
         git_config(git_read_tree_config, NULL);
 
@@ -185,7 +186,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
 
         if (opts.reset || opts.merge || opts.prefix) {
                 if (read_cache_unmerged() && (opts.prefix || opts.merge))
-                        die("You need to resolve your current index first");
+                        die(_("You need to resolve your current index first"));
                 stage = opts.merge = 1;
         }
         resolve_undo_clear();
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 4a20582e72..e755087b0f 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -1471,9 +1471,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                         N_("let the user edit the list of commits to rebase"),
                         PARSE_OPT_NOARG | PARSE_OPT_NONEG,
                         parse_opt_interactive },
-                OPT_SET_INT('p', "preserve-merges", &options.type,
-                            N_("(DEPRECATED) try to recreate merges instead of "
-                               "ignoring them"), REBASE_PRESERVE_MERGES),
+                OPT_SET_INT_F('p', "preserve-merges", &options.type,
+                              N_("(DEPRECATED) try to recreate merges instead of "
+                                 "ignoring them"),
+                              REBASE_PRESERVE_MERGES, PARSE_OPT_HIDDEN),
                 OPT_RERERE_AUTOUPDATE(&options.allow_rerere_autoupdate),
                 OPT_BOOL('k', "keep-empty", &options.keep_empty,
                          N_("preserve empty commits during rebase")),
diff --git a/builtin/repack.c b/builtin/repack.c
index 094c2f8ea4..0781763b06 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -233,6 +233,13 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
                 /*
                  * pack-objects creates the .pack and .idx files, but not the
                  * .promisor file. Create the .promisor file, which is empty.
+                 *
+                 * NEEDSWORK: fetch-pack sometimes generates non-empty
+                 * .promisor files containing the ref names and associated
+                 * hashes at the point of generation of the corresponding
+                 * packfile, but this would not preserve their contents. Maybe
+                 * concatenate the contents of all .promisor files instead of
+                 * just creating a new empty file.
                  */
                 promisor_name = mkpathdup("%s-%s.promisor", packtmp,
                                           line.buf);
@@ -562,7 +569,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
         remove_temporary_files();
 
         if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0))
-                write_midx_file(get_object_directory());
+                write_midx_file(get_object_directory(), 0);
 
         string_list_clear(&names, 0);
         string_list_clear(&rollback, 0);
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 308c67e4fc..85ce2095bf 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -919,6 +919,17 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                                 show_datestring("--min-age=", arg);
                                 continue;
                         }
+                        if (opt_with_value(arg, "--show-object-format", &arg)) {
+                                const char *val = arg ? arg : "storage";
+
+                                if (strcmp(val, "storage") &&
+                                    strcmp(val, "input") &&
+                                    strcmp(val, "output"))
+                                        die("unknown mode for --show-object-format: %s",
+                                            arg);
+                                puts(the_hash_algo->name);
+                                continue;
+                        }
                         if (show_flag(arg) && verify)
                                 die_no_single_rev(quiet);
                         continue;
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
new file mode 100644
index 0000000000..76f65d8edd
--- /dev/null
+++ b/builtin/sparse-checkout.c
@@ -0,0 +1,488 @@
+#include "builtin.h"
+#include "config.h"
+#include "dir.h"
+#include "parse-options.h"
+#include "pathspec.h"
+#include "repository.h"
+#include "run-command.h"
+#include "strbuf.h"
+#include "string-list.h"
+#include "cache.h"
+#include "cache-tree.h"
+#include "lockfile.h"
+#include "resolve-undo.h"
+#include "unpack-trees.h"
+
+static char const * const builtin_sparse_checkout_usage[] = {
+        N_("git sparse-checkout (init|list|set|disable) <options>"),
+        NULL
+};
+
+static char *get_sparse_checkout_filename(void)
+{
+        return git_pathdup("info/sparse-checkout");
+}
+
+static void write_patterns_to_file(FILE *fp, struct pattern_list *pl)
+{
+        int i;
+
+        for (i = 0; i < pl->nr; i++) {
+                struct path_pattern *p = pl->patterns[i];
+
+                if (p->flags & PATTERN_FLAG_NEGATIVE)
+                        fprintf(fp, "!");
+
+                fprintf(fp, "%s", p->pattern);
+
+                if (p->flags & PATTERN_FLAG_MUSTBEDIR)
+                        fprintf(fp, "/");
+
+                fprintf(fp, "\n");
+        }
+}
+
+static int sparse_checkout_list(int argc, const char **argv)
+{
+        struct pattern_list pl;
+        char *sparse_filename;
+        int res;
+
+        memset(&pl, 0, sizeof(pl));
+
+        sparse_filename = get_sparse_checkout_filename();
+        res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL);
+        free(sparse_filename);
+
+        if (res < 0) {
+                warning(_("this worktree is not sparse (sparse-checkout file may not exist)"));
+                return 0;
+        }
+
+        write_patterns_to_file(stdout, &pl);
+        clear_pattern_list(&pl);
+
+        return 0;
+}
+
+static int update_working_directory(struct pattern_list *pl)
+{
+        int result = 0;
+        struct unpack_trees_options o;
+        struct lock_file lock_file = LOCK_INIT;
+        struct object_id oid;
+        struct tree *tree;
+        struct tree_desc t;
+        struct repository *r = the_repository;
+
+        if (repo_read_index_unmerged(r))
+                die(_("You need to resolve your current index first"));
+
+        if (get_oid("HEAD", &oid))
+                return 0;
+
+        tree = parse_tree_indirect(&oid);
+        parse_tree(tree);
+        init_tree_desc(&t, tree->buffer, tree->size);
+
+        memset(&o, 0, sizeof(o));
+        o.verbose_update = isatty(2);
+        o.merge = 1;
+        o.update = 1;
+        o.fn = oneway_merge;
+        o.head_idx = -1;
+        o.src_index = r->index;
+        o.dst_index = r->index;
+        o.skip_sparse_checkout = 0;
+        o.pl = pl;
+        o.keep_pattern_list = !!pl;
+
+        resolve_undo_clear_index(r->index);
+        setup_work_tree();
+
+        cache_tree_free(&r->index->cache_tree);
+
+        repo_hold_locked_index(r, &lock_file, LOCK_DIE_ON_ERROR);
+
+        core_apply_sparse_checkout = 1;
+        result = unpack_trees(1, &t, &o);
+
+        if (!result) {
+                prime_cache_tree(r, r->index, tree);
+                write_locked_index(r->index, &lock_file, COMMIT_LOCK);
+        } else
+                rollback_lock_file(&lock_file);
+
+        return result;
+}
+
+enum sparse_checkout_mode {
+        MODE_NO_PATTERNS = 0,
+        MODE_ALL_PATTERNS = 1,
+        MODE_CONE_PATTERNS = 2,
+};
+
+static int sc_set_config(enum sparse_checkout_mode mode)
+{
+        struct argv_array argv = ARGV_ARRAY_INIT;
+        struct argv_array cone_argv = ARGV_ARRAY_INIT;
+
+        if (git_config_set_gently("extensions.worktreeConfig", "true")) {
+                error(_("failed to set extensions.worktreeConfig setting"));
+                return 1;
+        }
+
+        argv_array_pushl(&argv, "config", "--worktree", "core.sparseCheckout", NULL);
+
+        if (mode)
+                argv_array_pushl(&argv, "true", NULL);
+        else
+                argv_array_pushl(&argv, "false", NULL);
+
+        if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
+                error(_("failed to enable core.sparseCheckout"));
+                return 1;
+        }
+
+        argv_array_pushl(&cone_argv, "config", "--worktree",
+                         "core.sparseCheckoutCone", NULL);
+
+        if (mode == MODE_CONE_PATTERNS)
+                argv_array_push(&cone_argv, "true");
+        else
+                argv_array_push(&cone_argv, "false");
+
+        if (run_command_v_opt(cone_argv.argv, RUN_GIT_CMD)) {
+                error(_("failed to enable core.sparseCheckoutCone"));
+                return 1;
+        }
+
+        return 0;
+}
+
+static char const * const builtin_sparse_checkout_init_usage[] = {
+        N_("git sparse-checkout init [--cone]"),
+        NULL
+};
+
+static struct sparse_checkout_init_opts {
+        int cone_mode;
+} init_opts;
+
+static int sparse_checkout_init(int argc, const char **argv)
+{
+        struct pattern_list pl;
+        char *sparse_filename;
+        FILE *fp;
+        int res;
+        struct object_id oid;
+        int mode;
+
+        static struct option builtin_sparse_checkout_init_options[] = {
+                OPT_BOOL(0, "cone", &init_opts.cone_mode,
+                         N_("initialize the sparse-checkout in cone mode")),
+                OPT_END(),
+        };
+
+        argc = parse_options(argc, argv, NULL,
+                             builtin_sparse_checkout_init_options,
+                             builtin_sparse_checkout_init_usage, 0);
+
+        if (init_opts.cone_mode) {
+                mode = MODE_CONE_PATTERNS;
+                core_sparse_checkout_cone = 1;
+        } else
+                mode = MODE_ALL_PATTERNS;
+
+        if (sc_set_config(mode))
+                return 1;
+
+        memset(&pl, 0, sizeof(pl));
+
+        sparse_filename = get_sparse_checkout_filename();
+        res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL);
+
+        /* If we already have a sparse-checkout file, use it. */
+        if (res >= 0) {
+                free(sparse_filename);
+                goto reset_dir;
+        }
+
+        /* initial mode: all blobs at root */
+        fp = xfopen(sparse_filename, "w");
+        free(sparse_filename);
+        fprintf(fp, "/*\n!/*/\n");
+        fclose(fp);
+
+        if (get_oid("HEAD", &oid)) {
+                /* assume we are in a fresh repo */
+                return 0;
+        }
+
+reset_dir:
+        core_apply_sparse_checkout = 1;
+        return update_working_directory(NULL);
+}
+
+static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *path)
+{
+        struct pattern_entry *e = xmalloc(sizeof(*e));
+        e->patternlen = path->len;
+        e->pattern = strbuf_detach(path, NULL);
+        hashmap_entry_init(&e->ent, memhash(e->pattern, e->patternlen));
+
+        hashmap_add(&pl->recursive_hashmap, &e->ent);
+
+        while (e->patternlen) {
+                char *slash = strrchr(e->pattern, '/');
+                char *oldpattern = e->pattern;
+                size_t newlen;
+
+                if (slash == e->pattern)
+                        break;
+
+                newlen = slash - e->pattern;
+                e = xmalloc(sizeof(struct pattern_entry));
+                e->patternlen = newlen;
+                e->pattern = xstrndup(oldpattern, newlen);
+                hashmap_entry_init(&e->ent, memhash(e->pattern, e->patternlen));
+
+                if (!hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL))
+                        hashmap_add(&pl->parent_hashmap, &e->ent);
+        }
+}
+
+static void write_cone_to_file(FILE *fp, struct pattern_list *pl)
+{
+        int i;
+        struct pattern_entry *pe;
+        struct hashmap_iter iter;
+        struct string_list sl = STRING_LIST_INIT_DUP;
+        struct strbuf parent_pattern = STRBUF_INIT;
+
+        hashmap_for_each_entry(&pl->parent_hashmap, &iter, pe, ent) {
+                if (hashmap_get_entry(&pl->recursive_hashmap, pe, ent, NULL))
+                        continue;
+
+                if (!hashmap_contains_parent(&pl->recursive_hashmap,
+                                             pe->pattern,
+                                             &parent_pattern))
+                        string_list_insert(&sl, pe->pattern);
+        }
+
+        string_list_sort(&sl);
+        string_list_remove_duplicates(&sl, 0);
+
+        fprintf(fp, "/*\n!/*/\n");
+
+        for (i = 0; i < sl.nr; i++) {
+                char *pattern = sl.items[i].string;
+
+                if (strlen(pattern))
+                        fprintf(fp, "%s/\n!%s/*/\n", pattern, pattern);
+        }
+
+        string_list_clear(&sl, 0);
+
+        hashmap_for_each_entry(&pl->recursive_hashmap, &iter, pe, ent) {
+                if (!hashmap_contains_parent(&pl->recursive_hashmap,
+                                             pe->pattern,
+                                             &parent_pattern))
+                        string_list_insert(&sl, pe->pattern);
+        }
+
+        strbuf_release(&parent_pattern);
+
+        string_list_sort(&sl);
+        string_list_remove_duplicates(&sl, 0);
+
+        for (i = 0; i < sl.nr; i++) {
+                char *pattern = sl.items[i].string;
+                fprintf(fp, "%s/\n", pattern);
+        }
+}
+
+static int write_patterns_and_update(struct pattern_list *pl)
+{
+        char *sparse_filename;
+        FILE *fp;
+        int fd;
+        struct lock_file lk = LOCK_INIT;
+        int result;
+
+        result = update_working_directory(pl);
+
+        sparse_filename = get_sparse_checkout_filename();
+        fd = hold_lock_file_for_update(&lk, sparse_filename,
+                                      LOCK_DIE_ON_ERROR);
+
+        result = update_working_directory(pl);
+        if (result) {
+                rollback_lock_file(&lk);
+                free(sparse_filename);
+                clear_pattern_list(pl);
+                update_working_directory(NULL);
+                return result;
+        }
+
+        fp = xfdopen(fd, "w");
+
+        if (core_sparse_checkout_cone)
+                write_cone_to_file(fp, pl);
+        else
+                write_patterns_to_file(fp, pl);
+
+        fflush(fp);
+        commit_lock_file(&lk);
+
+        free(sparse_filename);
+        clear_pattern_list(pl);
+
+        return 0;
+}
+
+static void strbuf_to_cone_pattern(struct strbuf *line, struct pattern_list *pl)
+{
+        strbuf_trim(line);
+
+        strbuf_trim_trailing_dir_sep(line);
+
+        if (!line->len)
+                return;
+
+        if (line->buf[0] != '/')
+                strbuf_insert(line, 0, "/", 1);
+
+        insert_recursive_pattern(pl, line);
+}
+
+static char const * const builtin_sparse_checkout_set_usage[] = {
+        N_("git sparse-checkout set [--stdin|<patterns>]"),
+        NULL
+};
+
+static struct sparse_checkout_set_opts {
+        int use_stdin;
+} set_opts;
+
+static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
+{
+        static const char *empty_base = "";
+        int i;
+        struct pattern_list pl;
+        int result;
+        int set_config = 0;
+
+        static struct option builtin_sparse_checkout_set_options[] = {
+                OPT_BOOL(0, "stdin", &set_opts.use_stdin,
+                         N_("read patterns from standard in")),
+                OPT_END(),
+        };
+
+        memset(&pl, 0, sizeof(pl));
+
+        argc = parse_options(argc, argv, prefix,
+                             builtin_sparse_checkout_set_options,
+                             builtin_sparse_checkout_set_usage,
+                             PARSE_OPT_KEEP_UNKNOWN);
+
+        if (core_sparse_checkout_cone) {
+                struct strbuf line = STRBUF_INIT;
+                hashmap_init(&pl.recursive_hashmap, pl_hashmap_cmp, NULL, 0);
+                hashmap_init(&pl.parent_hashmap, pl_hashmap_cmp, NULL, 0);
+                pl.use_cone_patterns = 1;
+
+                if (set_opts.use_stdin) {
+                        while (!strbuf_getline(&line, stdin))
+                                strbuf_to_cone_pattern(&line, &pl);
+                } else {
+                        for (i = 0; i < argc; i++) {
+                                strbuf_setlen(&line, 0);
+                                strbuf_addstr(&line, argv[i]);
+                                strbuf_to_cone_pattern(&line, &pl);
+                        }
+                }
+        } else {
+                if (set_opts.use_stdin) {
+                        struct strbuf line = STRBUF_INIT;
+
+                        while (!strbuf_getline(&line, stdin)) {
+                                size_t len;
+                                char *buf = strbuf_detach(&line, &len);
+                                add_pattern(buf, empty_base, 0, &pl, 0);
+                        }
+                } else {
+                        for (i = 0; i < argc; i++)
+                                add_pattern(argv[i], empty_base, 0, &pl, 0);
+                }
+        }
+
+        if (!core_apply_sparse_checkout) {
+                sc_set_config(MODE_ALL_PATTERNS);
+                core_apply_sparse_checkout = 1;
+                set_config = 1;
+        }
+
+        result = write_patterns_and_update(&pl);
+
+        if (result && set_config)
+                sc_set_config(MODE_NO_PATTERNS);
+
+        clear_pattern_list(&pl);
+        return result;
+}
+
+static int sparse_checkout_disable(int argc, const char **argv)
+{
+        char *sparse_filename;
+        FILE *fp;
+
+        if (sc_set_config(MODE_ALL_PATTERNS))
+                die(_("failed to change config"));
+
+        sparse_filename = get_sparse_checkout_filename();
+        fp = xfopen(sparse_filename, "w");
+        fprintf(fp, "/*\n");
+        fclose(fp);
+
+        core_apply_sparse_checkout = 1;
+        if (update_working_directory(NULL))
+                die(_("error while refreshing working directory"));
+
+        unlink(sparse_filename);
+        free(sparse_filename);
+
+        return sc_set_config(MODE_NO_PATTERNS);
+}
+
+int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
+{
+        static struct option builtin_sparse_checkout_options[] = {
+                OPT_END(),
+        };
+
+        if (argc == 2 && !strcmp(argv[1], "-h"))
+                usage_with_options(builtin_sparse_checkout_usage,
+                                   builtin_sparse_checkout_options);
+
+        argc = parse_options(argc, argv, prefix,
+                             builtin_sparse_checkout_options,
+                             builtin_sparse_checkout_usage,
+                             PARSE_OPT_STOP_AT_NON_OPTION);
+
+        git_config(git_default_config, NULL);
+
+        if (argc > 0) {
+                if (!strcmp(argv[0], "list"))
+                        return sparse_checkout_list(argc, argv);
+                if (!strcmp(argv[0], "init"))
+                        return sparse_checkout_init(argc, argv);
+                if (!strcmp(argv[0], "set"))
+                        return sparse_checkout_set(argc, argv, prefix);
+                if (!strcmp(argv[0], "disable"))
+                        return sparse_checkout_disable(argc, argv);
+        }
+
+        usage_with_options(builtin_sparse_checkout_usage,
+                           builtin_sparse_checkout_options);
+}
diff --git a/builtin/stash.c b/builtin/stash.c
index bb4f6d8d76..4ad3adf4ba 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -483,13 +483,12 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
                 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;
 
                 /*
@@ -1088,8 +1087,9 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
         }
 
         cp_upd_index.git_cmd = 1;
-        argv_array_pushl(&cp_upd_index.args, "update-index", "-z", "--add",
-                         "--remove", "--stdin", NULL);
+        argv_array_pushl(&cp_upd_index.args, "update-index",
+                         "--ignore-skip-worktree-entries",
+                         "-z", "--add", "--remove", "--stdin", NULL);
         argv_array_pushf(&cp_upd_index.env_array, "GIT_INDEX_FILE=%s",
                          stash_index_path.buf);
 
@@ -1392,7 +1392,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
                         struct child_process cp = CHILD_PROCESS_INIT;
                         cp.git_cmd = 1;
                         argv_array_pushl(&cp.args, "reset", "--hard", "-q",
-                                         NULL);
+                                         "--no-recurse-submodules", NULL);
                         if (run_command(&cp)) {
                                 ret = -1;
                                 goto done;
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 49302d98c5..d527b8f106 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -35,6 +35,7 @@ static int verbose;
 static int mark_valid_only;
 static int mark_skip_worktree_only;
 static int mark_fsmonitor_only;
+static int ignore_skip_worktree_entries;
 #define MARK_FLAG 1
 #define UNMARK_FLAG 2
 static struct strbuf mtime_dir = STRBUF_INIT;
@@ -381,7 +382,8 @@ static int process_path(const char *path, struct stat *st, int stat_errno)
                  * so updating it does not make sense.
                  * On the other hand, removing it from index should work
                  */
-                if (allow_remove && remove_file_from_cache(path))
+                if (!ignore_skip_worktree_entries && allow_remove &&
+                    remove_file_from_cache(path))
                         return error("%s: cannot remove from the index", path);
                 return 0;
         }
@@ -1014,6 +1016,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
                 {OPTION_SET_INT, 0, "no-skip-worktree", &mark_skip_worktree_only, NULL,
                         N_("clear skip-worktree bit"),
                         PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
+                OPT_BOOL(0, "ignore-skip-worktree-entries", &ignore_skip_worktree_entries,
+                         N_("do not touch index-only entries")),
                 OPT_SET_INT(0, "info-only", &info_only,
                         N_("add to index only; do not add content to object database"), 1),
                 OPT_SET_INT(0, "force-remove", &force_remove,
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 4de44f579a..d6bc5263f1 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -376,7 +376,7 @@ static int add_worktree(const char *path, const char *refname,
         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 a85ed3f7bc..99439e07a1 100644
--- a/bundle.c
+++ b/bundle.c
@@ -249,15 +249,16 @@ out:
 
 
 /* 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 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs)
 }
 
 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 @@ int create_bundle(struct repository *r, const char *path,
                 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 37c37d7f65..ceab0c7475 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 @@ struct bundle_header {
 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 04cabaac11..aaeb0cd718 100644
--- a/cache.h
+++ b/cache.h
@@ -304,6 +304,7 @@ static inline unsigned int canon_mode(unsigned int mode)
 
 struct split_index;
 struct untracked_cache;
+struct progress;
 
 struct index_state {
         struct cache_entry **cache;
@@ -326,6 +327,7 @@ struct index_state {
         uint64_t fsmonitor_last_update;
         struct ewah_bitmap *fsmonitor_dirty;
         struct mem_pool *ce_mem_pool;
+        struct progress *progress;
 };
 
 /* Name hashing */
@@ -918,12 +920,14 @@ extern char *git_replace_ref_base;
 
 extern int fsync_object_files;
 extern int core_preload_index;
-extern int core_apply_sparse_checkout;
 extern int precomposed_unicode;
 extern int protect_hfs;
 extern int protect_ntfs;
 extern const char *core_fsmonitor;
 
+int core_apply_sparse_checkout;
+int core_sparse_checkout_cone;
+
 /*
  * Include broken refs in all ref iterations, which will
  * generally choke dangerous operations rather than letting
@@ -1451,7 +1455,8 @@ int get_oid_hex(const char *hex, struct object_id *sha1);
 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.
@@ -1459,13 +1464,12 @@ int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
  * 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 85a9d6b15c..4e64a19112 100755
--- a/ci/install-dependencies.sh
+++ b/ci/install-dependencies.sh
@@ -40,9 +40,15 @@ osx-clang|osx-gcc)
         test -z "$BREW_INSTALL_PACKAGES" ||
         brew install $BREW_INSTALL_PACKAGES
         brew link --force gettext
+        brew cask install perforce || {
+                # Update the definitions and try again
+                git -C "$(brew --repository)"/Library/Taps/homebrew/homebrew-cask pull &&
+                brew cask install perforce
+        } ||
         brew install caskroom/cask/perforce
         case "$jobname" in
         osx-gcc)
+                brew link gcc ||
                 brew link gcc@8
                 ;;
         esac
diff --git a/column.c b/column.c
index 7a17c14b82..4a38eed322 100644
--- a/column.c
+++ b/column.c
@@ -23,18 +23,7 @@ struct column_data {
 /* return length of 's' in letters, ANSI escapes stripped */
 static int item_length(const char *s)
 {
-        int len, i = 0;
-        struct strbuf str = STRBUF_INIT;
-
-        strbuf_addstr(&str, s);
-        while ((s = strstr(str.buf + i, "\033[")) != NULL) {
-                int len = strspn(s + 2, "0123456789;");
-                i = s - str.buf;
-                strbuf_remove(&str, i, len + 3); /* \033[<len><func char> */
-        }
-        len = utf8_strwidth(str.buf);
-        strbuf_release(&str);
-        return len;
+        return utf8_strnwidth(s, -1, 1);
 }
 
 /*
diff --git a/command-list.txt b/command-list.txt
index a9ac72bef4..2087894655 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -166,6 +166,7 @@ git-show-index                          plumbinginterrogators
 git-show-ref                            plumbinginterrogators
 git-sh-i18n                             purehelpers
 git-sh-setup                            purehelpers
+git-sparse-checkout                     mainporcelain           worktree
 git-stash                               mainporcelain
 git-stage                                                               complete
 git-status                              mainporcelain           info
@@ -203,6 +204,7 @@ gitmodules                              guide
 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 fc4a43b8d6..e771394aff 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -41,6 +41,9 @@
 #define GRAPH_MIN_SIZE (GRAPH_HEADER_SIZE + 4 * GRAPH_CHUNKLOOKUP_WIDTH \
                         + GRAPH_FANOUT_SIZE + the_hash_algo->rawsz)
 
+/* Remember to update object flag allocation in object.h */
+#define REACHABLE       (1u<<15)
+
 char *get_commit_graph_filename(const char *obj_dir)
 {
         char *filename = xstrfmt("%s/info/commit-graph", obj_dir);
@@ -461,7 +464,7 @@ static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
 /*
  * 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)
@@ -855,9 +858,6 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
                         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;
@@ -1030,11 +1030,11 @@ static void add_missing_parents(struct write_commit_graph_context *ctx, struct c
 {
         struct commit_list *parent;
         for (parent = commit->parents; parent; parent = parent->next) {
-                if (!(parent->item->object.flags & UNINTERESTING)) {
+                if (!(parent->item->object.flags & REACHABLE)) {
                         ALLOC_GROW(ctx->oids.list, ctx->oids.nr + 1, ctx->oids.alloc);
                         oidcpy(&ctx->oids.list[ctx->oids.nr], &(parent->item->object.oid));
                         ctx->oids.nr++;
-                        parent->item->object.flags |= UNINTERESTING;
+                        parent->item->object.flags |= REACHABLE;
                 }
         }
 }
@@ -1052,7 +1052,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)
                 display_progress(ctx->progress, i + 1);
                 commit = lookup_commit(ctx->r, &ctx->oids.list[i]);
                 if (commit)
-                        commit->object.flags |= UNINTERESTING;
+                        commit->object.flags |= REACHABLE;
         }
         stop_progress(&ctx->progress);
 
@@ -1089,7 +1089,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)
                 commit = lookup_commit(ctx->r, &ctx->oids.list[i]);
 
                 if (commit)
-                        commit->object.flags &= ~UNINTERESTING;
+                        commit->object.flags &= ~REACHABLE;
         }
         stop_progress(&ctx->progress);
 }
@@ -1100,7 +1100,7 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
         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-reach.c b/commit-reach.c
index 3ea174788a..4ca7e706a1 100644
--- a/commit-reach.c
+++ b/commit-reach.c
@@ -10,7 +10,6 @@
 #include "commit-reach.h"
 
 /* Remember to update object flag allocation in object.h */
-#define REACHABLE       (1u<<15)
 #define PARENT1                (1u<<16)
 #define PARENT2                (1u<<17)
 #define STALE                (1u<<18)
diff --git a/commit.c b/commit.c
index 40890ae7ce..434ec030d6 100644
--- a/commit.c
+++ b/commit.c
@@ -19,6 +19,7 @@
 #include "advice.h"
 #include "refs.h"
 #include "commit-reach.h"
+#include "run-command.h"
 
 static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
 
@@ -401,10 +402,22 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
         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')
@@ -412,7 +425,12 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
         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;
 
@@ -432,8 +450,11 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
                 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;
@@ -442,7 +463,9 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
                         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;
                 }
         }
@@ -451,6 +474,7 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
         if (check_graph)
                 load_commit_graph_info(r, item);
 
+        item->object.parsed = 1;
         return 0;
 }
 
@@ -1581,3 +1605,26 @@ size_t ignore_non_trailer(const char *buf, size_t len)
         }
         return boc ? len - boc : len - cutoff;
 }
+
+int run_commit_hook(int editor_is_used, const char *index_file,
+                    const char *name, ...)
+{
+        struct argv_array hook_env = ARGV_ARRAY_INIT;
+        va_list args;
+        int ret;
+
+        argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", index_file);
+
+        /*
+         * Let the hook know that no editor will be launched.
+         */
+        if (!editor_is_used)
+                argv_array_push(&hook_env, "GIT_EDITOR=:");
+
+        va_start(args, name);
+        ret = run_hook_ve(hook_env.argv,name, args);
+        va_end(args);
+        argv_array_clear(&hook_env);
+
+        return ret;
+}
diff --git a/commit.h b/commit.h
index f5295ca7f3..221cdaa34b 100644
--- a/commit.h
+++ b/commit.h
@@ -132,7 +132,7 @@ const void *repo_get_commit_buffer(struct repository *r,
 #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 6b765d936c..2f4654c968 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -363,6 +363,8 @@ static inline int needs_hiding(const char *path)
                         /* ignore trailing slashes */
                         if (*path)
                                 basename = path;
+                        else
+                                break;
                 }
 
         if (hide_dotfiles == HIDE_DOTFILES_TRUE)
@@ -1564,7 +1566,7 @@ static int try_shell_exec(const char *cmd, char *const *argv)
                 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) {
diff --git a/compat/mingw.h b/compat/mingw.h
index 9ad204c57c..1a46334399 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -558,7 +558,7 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen);
 
 /*
  * 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 9134349590..814845d4b3 100644
--- a/compat/nedmalloc/malloc.c.h
+++ b/compat/nedmalloc/malloc.c.h
@@ -1564,7 +1564,7 @@ static FORCEINLINE void* win32direct_mmap(size_t size) {
   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 @@ static FORCEINLINE int win32munmap(void* ptr, size_t size) {
     #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 @@ typedef struct malloc_segment* msegmentptr;
 
   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 ae36ed6a66..01e7c81840 100644
--- a/compat/obstack.h
+++ b/compat/obstack.h
@@ -79,7 +79,7 @@ change its address during its lifetime.
 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 c0d838834a..d1bc09e49b 100644
--- a/compat/regex/regcomp.c
+++ b/compat/regex/regcomp.c
@@ -3462,7 +3462,7 @@ build_equiv_class (bitset_t sbcset, const unsigned char *name)
         /* 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 4d81358a83..08a2609663 100644
--- a/compat/regex/regex.h
+++ b/compat/regex/regex.h
@@ -322,7 +322,7 @@ typedef enum
   /* 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 59bf151336..ec51cf3446 100644
--- a/compat/regex/regex_internal.c
+++ b/compat/regex/regex_internal.c
@@ -1616,7 +1616,7 @@ free_state (re_dfastate_t *state)
   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 1b5d89fd5e..49358ae475 100644
--- a/compat/regex/regexec.c
+++ b/compat/regex/regexec.c
@@ -2420,7 +2420,7 @@ find_recover_state (reg_errcode_t *err, re_match_context_t *mctx)
 /* 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 @@ build_trtable (const re_dfa_t *dfa, re_dfastate_t *state)
   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 40194dd230..b35d264c0e 100644
--- a/compat/vcbuild/find_vs_env.bat
+++ b/compat/vcbuild/find_vs_env.bat
@@ -18,7 +18,7 @@ REM and MAKE, we must blend these two different worlds.  This script
 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/pthread.h b/compat/win32/pthread.h
index f1cfe73de9..737983d00b 100644
--- a/compat/win32/pthread.h
+++ b/compat/win32/pthread.h
@@ -51,7 +51,7 @@ typedef struct {
 } pthread_t;
 
 int pthread_create(pthread_t *thread, const void *unused,
-                          void *(*start_routine)(void*), void *arg);
+                   void *(*start_routine)(void*), void *arg);
 
 /*
  * To avoid the need of copying a struct, we use small macro wrapper to pass
diff --git a/config.c b/config.c
index e7052b3977..d75f88ca0c 100644
--- a/config.c
+++ b/config.c
@@ -1364,6 +1364,11 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
                 return 0;
         }
 
+        if (!strcmp(var, "core.sparsecheckoutcone")) {
+                core_sparse_checkout_cone = git_config_bool(var, value);
+                return 0;
+        }
+
         if (!strcmp(var, "core.precomposeunicode")) {
                 precomposed_unicode = git_config_bool(var, value);
                 return 0;
diff --git a/config.h b/config.h
index f0ed464004..91fd4c5e96 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 @@ struct config_options {
         } 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 @@ void git_config_push_parameter(const char *text);
 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 @@ enum config_scope current_config_scope(void);
 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 @@ int parse_config_key(const char *var,
                      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 config_set {
         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_maybe_bool(struct repository *repo,
 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 @@ struct key_value_info {
         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/configure.ac b/configure.ac
index a43b476402..66aedb9288 100644
--- a/configure.ac
+++ b/configure.ac
@@ -85,7 +85,7 @@ AC_DEFUN([GIT_PARSE_WITH],
 
 # 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_MSG_CHECKING([for old iconv()])
 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/connected.c b/connected.c
index 36c4e5dedb..c337f5f7f4 100644
--- a/connected.c
+++ b/connected.c
@@ -62,7 +62,8 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
                  * 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 d03453341e..778e4704f6 100644
--- a/contrib/coccinelle/commit.cocci
+++ b/contrib/coccinelle/commit.cocci
@@ -20,7 +20,7 @@ expression s;
 + 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 3e536a9834..ddf4f22bd7 100644
--- a/contrib/coccinelle/object_id.cocci
+++ b/contrib/coccinelle/object_id.cocci
@@ -13,38 +13,6 @@ struct object_id *OIDPTR;
 @@
 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 00fbe6c03d..67705da641 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -550,7 +550,7 @@ __git_index_files ()
                                                  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 @@ __git_index_files ()
                         }
                 }
                 # 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)
@@ -2043,6 +2043,10 @@ _git_rebase ()
                 __gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
                 return
                 ;;
+        --onto=*)
+                __git_complete_refs --cur="${cur##--onto=}"
+                return
+                ;;
         --*)
                 __gitcomp_builtin rebase "" \
                         "$__git_rebase_interactive_inprogress_options"
@@ -2843,6 +2847,7 @@ _git_svn ()
                         --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/completion/git-completion.zsh b/contrib/completion/git-completion.zsh
index 886bf95d1f..eef4eff53d 100644
--- a/contrib/completion/git-completion.zsh
+++ b/contrib/completion/git-completion.zsh
@@ -11,8 +11,9 @@
 #
 #  zstyle ':completion:*:*:git:*' script ~/.git-completion.zsh
 #
-# The recommended way to install this script is to copy to '~/.zsh/_git', and
-# then add the following to your ~/.zshrc file:
+# The recommended way to install this script is to make a copy of it in
+# ~/.zsh/ directory as ~/.zsh/git-completion.zsh and then add the following
+# to your ~/.zshrc file:
 #
 #  fpath=(~/.zsh $fpath)
 
diff --git a/contrib/diff-highlight/DiffHighlight.pm b/contrib/diff-highlight/DiffHighlight.pm
index 7440aa1c46..e2589922a6 100644
--- a/contrib/diff-highlight/DiffHighlight.pm
+++ b/contrib/diff-highlight/DiffHighlight.pm
@@ -72,7 +72,7 @@ sub handle_line {
               (?:$COLOR?\|$COLOR?[ ])* # zero or more trailing "|"
                                  [ ]*  # trailing whitespace for merges
             /x) {
-                my $graph_prefix = $&;
+                my $graph_prefix = $&;
 
                 # We must flush before setting graph indent, since the
                 # new commit may be indented differently from what we
diff --git a/contrib/hooks/multimail/git_multimail.py b/contrib/hooks/multimail/git_multimail.py
index 8823399e75..f563be82fc 100755
--- a/contrib/hooks/multimail/git_multimail.py
+++ b/contrib/hooks/multimail/git_multimail.py
@@ -95,7 +95,7 @@ if PYTHON3:
     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 @@ class SMTPMailer(Mailer):
                 # 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 @@ class SMTPMailer(Mailer):
                         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 @@ class ProjectdescEnvironmentMixin(Environment):
         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 b9bb11834e..0f98c5a23d 100755
--- a/contrib/hooks/multimail/post-receive.example
+++ b/contrib/hooks/multimail/post-receive.example
@@ -56,7 +56,7 @@ config = git_multimail.Config('multimailhook')
 
 # 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 8747b84334..ff565eb3d8 100755
--- a/contrib/hooks/post-receive-email
+++ b/contrib/hooks/post-receive-email
@@ -329,7 +329,7 @@ generate_update_branch_email()
         #
         #  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 d18b317b2f..0092d67b8a 100755
--- a/contrib/hooks/update-paranoid
+++ b/contrib/hooks/update-paranoid
@@ -49,7 +49,7 @@ opcode.
 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 158958d363..b7333267ad 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 af9cbc9d0f..d8ff2e69c4 100755
--- a/contrib/mw-to-git/git-remote-mediawiki.perl
+++ b/contrib/mw-to-git/git-remote-mediawiki.perl
@@ -79,7 +79,7 @@ chomp($export_media);
 $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 0f3f4e018a..b033849800 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 @@ $url = 'http://localhost:'.$port.'/wiki/mw-config/index.php';
 $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 cfbfe7ddf6..9106833578 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 one specific page cloned ' '
 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 6546294f15..3948a00282 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 @@ start_lighttpd () {
         "$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 50c6a4f89d..8a3cee6175 100755
--- a/contrib/svn-fe/svnrdump_sim.py
+++ b/contrib/svn-fe/svnrdump_sim.py
@@ -54,7 +54,7 @@ if __name__ == "__main__":
         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 25ac525d5f..797e0bd0b1 100644
--- a/convert.c
+++ b/convert.c
@@ -270,8 +270,12 @@ static int will_convert_lf_to_crlf(struct text_stat *stats,
 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 @@ static int validate_encoding(const char *path, const char *enc,
                          */
                         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 @@ static int validate_encoding(const char *path, const char *enc,
                                 "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 @@ static int encode_to_git(const char *path, const char *src, size_t src_len,
         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/daemon.c b/daemon.c
index 9d2e0d20ef..fd669ed3b4 100644
--- a/daemon.c
+++ b/daemon.c
@@ -598,7 +598,7 @@ static void canonicalize_client(struct strbuf *out, const char *in)
  * 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 @@ static void parse_extra_args(struct hostinfo *hi, struct argv_array *env,
                  * 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/diff.c b/diff.c
index afe4400a60..087213466e 100644
--- a/diff.c
+++ b/diff.c
@@ -2551,7 +2551,7 @@ static int scale_linear(int it, int width, int max_change)
         /*
          * 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);
@@ -3196,7 +3196,7 @@ static int is_conflict_marker(const char *line, int marker_size, unsigned long l
         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;
diff --git a/dir.c b/dir.c
index 61f559f980..0ce591ef68 100644
--- a/dir.c
+++ b/dir.c
@@ -611,6 +611,150 @@ void parse_path_pattern(const char **pattern,
         *patternlen = len;
 }
 
+int pl_hashmap_cmp(const void *unused_cmp_data,
+                   const struct hashmap_entry *a,
+                   const struct hashmap_entry *b,
+                   const void *key)
+{
+        const struct pattern_entry *ee1 =
+                        container_of(a, struct pattern_entry, ent);
+        const struct pattern_entry *ee2 =
+                        container_of(b, struct pattern_entry, ent);
+
+        size_t min_len = ee1->patternlen <= ee2->patternlen
+                         ? ee1->patternlen
+                         : ee2->patternlen;
+
+        return strncmp(ee1->pattern, ee2->pattern, min_len);
+}
+
+static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern *given)
+{
+        struct pattern_entry *translated;
+        char *truncated;
+        char *data = NULL;
+
+        if (!pl->use_cone_patterns)
+                return;
+
+        if (given->flags & PATTERN_FLAG_NEGATIVE &&
+            given->flags & PATTERN_FLAG_MUSTBEDIR &&
+            !strcmp(given->pattern, "/*")) {
+                pl->full_cone = 0;
+                return;
+        }
+
+        if (!given->flags && !strcmp(given->pattern, "/*")) {
+                pl->full_cone = 1;
+                return;
+        }
+
+        if (given->patternlen > 2 &&
+            !strcmp(given->pattern + given->patternlen - 2, "/*")) {
+                if (!(given->flags & PATTERN_FLAG_NEGATIVE)) {
+                        /* Not a cone pattern. */
+                        pl->use_cone_patterns = 0;
+                        warning(_("unrecognized pattern: '%s'"), given->pattern);
+                        goto clear_hashmaps;
+                }
+
+                truncated = xstrdup(given->pattern);
+                truncated[given->patternlen - 2] = 0;
+
+                translated = xmalloc(sizeof(struct pattern_entry));
+                translated->pattern = truncated;
+                translated->patternlen = given->patternlen - 2;
+                hashmap_entry_init(&translated->ent,
+                                   memhash(translated->pattern, translated->patternlen));
+
+                if (!hashmap_get_entry(&pl->recursive_hashmap,
+                                       translated, ent, NULL)) {
+                        /* We did not see the "parent" included */
+                        warning(_("unrecognized negative pattern: '%s'"),
+                                given->pattern);
+                        free(truncated);
+                        free(translated);
+                        goto clear_hashmaps;
+                }
+
+                hashmap_add(&pl->parent_hashmap, &translated->ent);
+                hashmap_remove(&pl->recursive_hashmap, &translated->ent, &data);
+                free(data);
+                return;
+        }
+
+        if (given->flags & PATTERN_FLAG_NEGATIVE) {
+                warning(_("unrecognized negative pattern: '%s'"),
+                        given->pattern);
+                goto clear_hashmaps;
+        }
+
+        translated = xmalloc(sizeof(struct pattern_entry));
+
+        translated->pattern = xstrdup(given->pattern);
+        translated->patternlen = given->patternlen;
+        hashmap_entry_init(&translated->ent,
+                           memhash(translated->pattern, translated->patternlen));
+
+        hashmap_add(&pl->recursive_hashmap, &translated->ent);
+
+        if (hashmap_get_entry(&pl->parent_hashmap, translated, ent, NULL)) {
+                /* we already included this at the parent level */
+                warning(_("your sparse-checkout file may have issues: pattern '%s' is repeated"),
+                        given->pattern);
+                hashmap_remove(&pl->parent_hashmap, &translated->ent, &data);
+                free(data);
+                free(translated);
+        }
+
+        return;
+
+clear_hashmaps:
+        warning(_("disabling cone pattern matching"));
+        hashmap_free_entries(&pl->parent_hashmap, struct pattern_entry, ent);
+        hashmap_free_entries(&pl->recursive_hashmap, struct pattern_entry, ent);
+        pl->use_cone_patterns = 0;
+}
+
+static int hashmap_contains_path(struct hashmap *map,
+                                 struct strbuf *pattern)
+{
+        struct pattern_entry p;
+
+        /* Check straight mapping */
+        p.pattern = pattern->buf;
+        p.patternlen = pattern->len;
+        hashmap_entry_init(&p.ent, memhash(p.pattern, p.patternlen));
+        return !!hashmap_get_entry(map, &p, ent, NULL);
+}
+
+int hashmap_contains_parent(struct hashmap *map,
+                            const char *path,
+                            struct strbuf *buffer)
+{
+        char *slash_pos;
+
+        strbuf_setlen(buffer, 0);
+
+        if (path[0] != '/')
+                strbuf_addch(buffer, '/');
+
+        strbuf_addstr(buffer, path);
+
+        slash_pos = strrchr(buffer->buf, '/');
+
+        while (slash_pos > buffer->buf) {
+                strbuf_setlen(buffer, slash_pos - buffer->buf);
+
+                if (hashmap_contains_path(map, buffer))
+                        return 1;
+
+                slash_pos = strrchr(buffer->buf, '/');
+        }
+
+        return 0;
+}
+
 void add_pattern(const char *string, const char *base,
                  int baselen, struct pattern_list *pl, int srcpos)
 {
@@ -635,6 +779,8 @@ void add_pattern(const char *string, const char *base,
         ALLOC_GROW(pl->patterns, pl->nr + 1, pl->alloc);
         pl->patterns[pl->nr++] = pattern;
         pattern->pl = pl;
+
+        add_pattern_to_hashsets(pl, pattern);
 }
 
 static int read_skip_worktree_file_from_index(const struct index_state *istate,
@@ -860,6 +1006,9 @@ static int add_patterns_from_buffer(char *buf, size_t size,
         int i, lineno = 1;
         char *entry;
 
+        hashmap_init(&pl->recursive_hashmap, pl_hashmap_cmp, NULL, 0);
+        hashmap_init(&pl->parent_hashmap, pl_hashmap_cmp, NULL, 0);
+
         pl->filebuf = buf;
 
         if (skip_utf8_bom(&buf, size))
@@ -1096,16 +1245,58 @@ enum pattern_match_result path_matches_pattern_list(
                                 struct index_state *istate)
 {
         struct path_pattern *pattern;
-        pattern = last_matching_pattern_from_list(pathname, pathlen, basename,
-                                                  dtype, pl, istate);
-        if (pattern) {
-                if (pattern->flags & PATTERN_FLAG_NEGATIVE)
-                        return NOT_MATCHED;
-                else
-                        return MATCHED;
+        struct strbuf parent_pathname = STRBUF_INIT;
+        int result = NOT_MATCHED;
+        const char *slash_pos;
+
+        if (!pl->use_cone_patterns) {
+                pattern = last_matching_pattern_from_list(pathname, pathlen, basename,
+                                                        dtype, pl, istate);
+                if (pattern) {
+                        if (pattern->flags & PATTERN_FLAG_NEGATIVE)
+                                return NOT_MATCHED;
+                        else
+                                return MATCHED;
+                }
+
+                return UNDECIDED;
+        }
+
+        if (pl->full_cone)
+                return MATCHED;
+
+        strbuf_addch(&parent_pathname, '/');
+        strbuf_add(&parent_pathname, pathname, pathlen);
+
+        if (hashmap_contains_path(&pl->recursive_hashmap,
+                                  &parent_pathname)) {
+                result = MATCHED_RECURSIVE;
+                goto done;
+        }
+
+        slash_pos = strrchr(parent_pathname.buf, '/');
+
+        if (slash_pos == parent_pathname.buf) {
+                /* include every file in root */
+                result = MATCHED;
+                goto done;
         }
 
-        return UNDECIDED;
+        strbuf_setlen(&parent_pathname, slash_pos - parent_pathname.buf);
+
+        if (hashmap_contains_path(&pl->parent_hashmap, &parent_pathname)) {
+                result = MATCHED;
+                goto done;
+        }
+
+        if (hashmap_contains_parent(&pl->recursive_hashmap,
+                                    pathname,
+                                    &parent_pathname))
+                result = MATCHED_RECURSIVE;
+
+done:
+        strbuf_release(&parent_pathname);
+        return result;
 }
 
 static struct path_pattern *last_matching_pattern_from_lists(
@@ -2489,7 +2680,7 @@ static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up)
                                  * 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 2fbdef014f..77a43dbf89 100644
--- a/dir.h
+++ b/dir.h
@@ -4,6 +4,7 @@
 /* See Documentation/technical/api-directory-listing.txt */
 
 #include "cache.h"
+#include "hashmap.h"
 #include "strbuf.h"
 
 struct dir_entry {
@@ -37,6 +38,13 @@ struct path_pattern {
         int srcpos;
 };
 
+/* used for hashmaps for cone patterns */
+struct pattern_entry {
+        struct hashmap_entry ent;
+        char *pattern;
+        size_t patternlen;
+};
+
 /*
  * Each excludes file will be parsed into a fresh exclude_list which
  * is appended to the relevant exclude_list_group (either EXC_DIRS or
@@ -55,6 +63,26 @@ struct pattern_list {
         const char *src;
 
         struct path_pattern **patterns;
+
+        /*
+         * While scanning the excludes, we attempt to match the patterns
+         * with a more restricted set that allows us to use hashsets for
+         * matching logic, which is faster than the linear lookup in the
+         * excludes array above. If non-zero, that check succeeded.
+         */
+        unsigned use_cone_patterns;
+        unsigned full_cone;
+
+        /*
+         * Stores paths where everything starting with those paths
+         * is included.
+         */
+        struct hashmap recursive_hashmap;
+
+        /*
+         * Used to check single-level parents of blobs.
+         */
+        struct hashmap parent_hashmap;
 };
 
 /*
@@ -236,6 +264,7 @@ enum pattern_match_result {
         UNDECIDED = -1,
         NOT_MATCHED = 0,
         MATCHED = 1,
+        MATCHED_RECURSIVE = 2,
 };
 
 /*
@@ -271,6 +300,13 @@ int is_excluded(struct dir_struct *dir,
                 struct index_state *istate,
                 const char *name, int *dtype);
 
+int pl_hashmap_cmp(const void *unused_cmp_data,
+                   const struct hashmap_entry *a,
+                   const struct hashmap_entry *b,
+                   const void *key);
+int hashmap_contains_parent(struct hashmap *map,
+                            const char *path,
+                            struct strbuf *buffer);
 struct pattern_list *add_pattern_list(struct dir_struct *dir,
                                       int group_type, const char *src);
 int add_patterns_from_file_to_list(const char *fname, const char *base, int baselen,
diff --git a/environment.c b/environment.c
index efa072680a..2a1a866659 100644
--- a/environment.c
+++ b/environment.c
@@ -67,6 +67,7 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
 char *notes_ref_name;
 int grafts_replace_parents = 1;
 int core_apply_sparse_checkout;
+int core_sparse_checkout_cone;
 int merge_log_config = -1;
 int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
 unsigned long pack_size_limit_cfg;
diff --git a/ewah/bitmap.c b/ewah/bitmap.c
index eac05485f1..b5fed9621f 100644
--- a/ewah/bitmap.c
+++ b/ewah/bitmap.c
@@ -41,7 +41,7 @@ void bitmap_set(struct bitmap *self, size_t pos)
 
         if (block >= self->word_alloc) {
                 size_t old_size = self->word_alloc;
-                self->word_alloc = (block + 1) * 2;
+                self->word_alloc = block ? block * 2 : 1;
                 REALLOC_ARRAY(self->words, self->word_alloc);
                 memset(self->words + old_size, 0x0,
                         (self->word_alloc - old_size) * sizeof(eword_t));
diff --git a/fetch-pack.c b/fetch-pack.c
index 0130b44112..ba92587023 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -673,7 +673,8 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
                 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)
@@ -756,8 +757,33 @@ static int sideband_demux(int in, int out, void *data)
         return ret;
 }
 
+static void write_promisor_file(const char *keep_name,
+                                struct ref **sought, int nr_sought)
+{
+        struct strbuf promisor_name = STRBUF_INIT;
+        int suffix_stripped;
+        FILE *output;
+        int i;
+
+        strbuf_addstr(&promisor_name, keep_name);
+        suffix_stripped = strbuf_strip_suffix(&promisor_name, ".keep");
+        if (!suffix_stripped)
+                BUG("name of pack lockfile should end with .keep (was '%s')",
+                    keep_name);
+        strbuf_addstr(&promisor_name, ".promisor");
+
+        output = xfopen(promisor_name.buf, "w");
+        for (i = 0; i < nr_sought; i++)
+                fprintf(output, "%s %s\n", oid_to_hex(&sought[i]->old_oid),
+                        sought[i]->name);
+        fclose(output);
+
+        strbuf_release(&promisor_name);
+}
+
 static int get_pack(struct fetch_pack_args *args,
-                    int xd[2], char **pack_lockfile)
+                    int xd[2], char **pack_lockfile,
+                    struct ref **sought, int nr_sought)
 {
         struct async demux;
         int do_keep = args->keep_pack;
@@ -819,7 +845,13 @@ static int get_pack(struct fetch_pack_args *args,
                 }
                 if (args->check_self_contained_and_connected)
                         argv_array_push(&cmd.args, "--check-self-contained-and-connected");
-                if (args->from_promisor)
+                /*
+                 * If we're obtaining the filename of a lockfile, we'll use
+                 * that filename to write a .promisor file with more
+                 * information below. If not, we need index-pack to do it for
+                 * us.
+                 */
+                if (!(do_keep && pack_lockfile) && args->from_promisor)
                         argv_array_push(&cmd.args, "--promisor");
         }
         else {
@@ -873,6 +905,14 @@ static int get_pack(struct fetch_pack_args *args,
                 die(_("%s failed"), cmd_name);
         if (use_sideband && finish_async(&demux))
                 die(_("error in sideband demultiplexer"));
+
+        /*
+         * Now that index-pack has succeeded, write the promisor file using the
+         * obtained .keep filename if necessary
+         */
+        if (do_keep && pack_lockfile && args->from_promisor)
+                write_promisor_file(*pack_lockfile, sought, nr_sought);
+
         return 0;
 }
 
@@ -895,8 +935,15 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
         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);
@@ -983,7 +1030,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
                 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]);
@@ -992,7 +1039,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
         } 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.
@@ -1008,11 +1055,12 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
                 alternate_shallow_file = setup_temporary_shallow(si->shallow);
         else
                 alternate_shallow_file = NULL;
-        if (get_pack(args, fd, pack_lockfile))
+        if (get_pack(args, fd, pack_lockfile, sought, nr_sought))
                 die(_("git fetch-pack: fetch failed."));
 
  all_done:
-        negotiator.release(&negotiator);
+        if (negotiator)
+                negotiator->release(negotiator);
         return ref;
 }
 
@@ -1230,7 +1278,8 @@ static int process_acks(struct fetch_negotiator *negotiator,
                                 struct commit *commit;
                                 oidset_insert(common, &oid);
                                 commit = lookup_commit(the_repository, &oid);
-                                negotiator->ack(negotiator, commit);
+                                if (negotiator)
+                                        negotiator->ack(negotiator, commit);
                         }
                         continue;
                 }
@@ -1382,8 +1431,16 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
         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);
@@ -1407,15 +1464,15 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
 
                         /* 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);
@@ -1429,7 +1486,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
                                                     "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))
@@ -1439,7 +1496,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
                         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;
@@ -1464,7 +1521,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
 
                         /* get the pack */
                         process_section_header(&reader, "packfile", 0);
-                        if (get_pack(args, fd, pack_lockfile))
+                        if (get_pack(args, fd, pack_lockfile, sought, nr_sought))
                                 die(_("git fetch-pack: fetch failed."));
 
                         state = FETCH_DONE;
@@ -1474,7 +1531,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
                 }
         }
 
-        negotiator.release(&negotiator);
+        if (negotiator)
+                negotiator->release(negotiator);
         oidset_clear(&common);
         return ref;
 }
diff --git a/fsck.c b/fsck.c
index cdb7d8db03..ac4ba4c8e8 100644
--- a/fsck.c
+++ b/fsck.c
@@ -43,21 +43,17 @@ static struct oidset gitmodules_done = OIDSET_INIT;
         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) \
@@ -281,14 +277,16 @@ static void append_msg_id(struct strbuf *sb, const char *msg_id)
         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 +295,7 @@ static int report(struct fsck_options *options, struct object *object,
         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 +307,71 @@ static int report(struct fsck_options *options, struct object *object,
 
         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)
+                options->object_names = kh_init_oid_map();
+}
+
+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 lookup_decoration(options->object_names, obj);
+        return kh_value(options->object_names, pos);
 }
 
-static void put_object_name(struct fsck_options *options, struct object *obj,
-        const char *fmt, ...)
+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;
-
-        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);
+        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);
+
+        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 +384,7 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
         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 +397,21 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
                 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 +432,10 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
         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 +463,17 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
 
         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 +487,12 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
 
 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 +514,8 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options)
         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 +566,9 @@ static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, con
         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 +585,8 @@ static int fsck_tree(struct tree *item, struct fsck_options *options)
         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;
         }
 
@@ -587,13 +612,14 @@ static int fsck_tree(struct tree *item, struct fsck_options *options)
                         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 (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 +664,31 @@ static int fsck_tree(struct tree *item, struct fsck_options *options)
         }
 
         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 +696,7 @@ static int verify_headers(const void *data, unsigned long size,
         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 +714,13 @@ static int verify_headers(const void *data, unsigned long size,
         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 +730,28 @@ static int fsck_ident(const char **ident, struct object *obj, struct fsck_option
                 (*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 +759,60 @@ static int fsck_ident(const char **ident, struct object *obj, struct fsck_option
             !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 +820,60 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,
         return 0;
 }
 
-static int fsck_commit(struct commit *commit, const char *data,
-        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)
+static int fsck_tag(const struct object_id *oid, const char *buffer,
+                    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 +881,20 @@ static int fsck_tag_buffer(struct tag *tag, const char *data,
 
         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,19 +912,22 @@ static int fsck_gitmodules_fn(const char *var, const char *value, void *vdata)
 
         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);
@@ -970,17 +936,17 @@ static int fsck_gitmodules_fn(const char *var, const char *value, void *vdata)
         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 +955,18 @@ static int fsck_blob(struct blob *blob, const char *buf,
                  * 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 +977,33 @@ int fsck_object(struct object *obj, void *data, unsigned long size,
         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 +1015,6 @@ int fsck_finish(struct fsck_options *options)
 
         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 +1022,22 @@ int fsck_finish(struct fsck_options *options)
                 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 b95595ae5f..69cf715e79 100644
--- a/fsck.h
+++ b/fsck.h
@@ -27,10 +27,12 @@ typedef int (*fsck_walk_func)(struct object *obj, int type, void *data, struct f
 
 /* 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 @@ struct fsck_options {
         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 @@ struct fsck_options {
  *    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_object(struct object *obj, void *data, unsigned long size,
  */
 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 231e83a94d..0477500b39 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -14,8 +14,13 @@ struct trace_key trace_fsmonitor = TRACE_KEY_INIT(FSMONITOR);
 static void fsmonitor_ewah_callback(size_t pos, void *is)
 {
         struct index_state *istate = (struct index_state *)is;
-        struct cache_entry *ce = istate->cache[pos];
+        struct cache_entry *ce;
 
+        if (pos >= istate->cache_nr)
+                BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" >= %u)",
+                    (uintmax_t)pos, istate->cache_nr);
+
+        ce = istate->cache[pos];
         ce->ce_flags &= ~CE_FSMONITOR_VALID;
 }
 
@@ -50,17 +55,25 @@ int read_fsmonitor_extension(struct index_state *istate, const void *data,
         }
         istate->fsmonitor_dirty = fsmonitor_dirty;
 
+        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);
+
         trace_printf_key(&trace_fsmonitor, "read fsmonitor extension successful");
         return 0;
 }
 
 void fill_fsmonitor_bitmap(struct index_state *istate)
 {
-        unsigned int i;
+        unsigned int i, skipped = 0;
         istate->fsmonitor_dirty = ewah_new();
-        for (i = 0; i < istate->cache_nr; i++)
-                if (!(istate->cache[i]->ce_flags & CE_FSMONITOR_VALID))
-                        ewah_set(istate->fsmonitor_dirty, i);
+        for (i = 0; i < istate->cache_nr; i++) {
+                if (istate->cache[i]->ce_flags & CE_REMOVE)
+                        skipped++;
+                else if (!(istate->cache[i]->ce_flags & CE_FSMONITOR_VALID))
+                        ewah_set(istate->fsmonitor_dirty, i - skipped);
+        }
 }
 
 void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)
@@ -71,6 +84,11 @@ void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)
         uint32_t ewah_size = 0;
         int fixup = 0;
 
+        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);
+
         put_be32(&hdr_version, INDEX_EXTENSION_VERSION);
         strbuf_add(sb, &hdr_version, sizeof(uint32_t));
 
@@ -236,6 +254,9 @@ void tweak_fsmonitor(struct index_state *istate)
                         }
 
                         /* Mark all previously saved entries as dirty */
+                        if (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);
                         ewah_each_bit(istate->fsmonitor_dirty, fsmonitor_ewah_callback, istate);
 
                         /* Now mark the untracked cache for fsmonitor usage */
diff --git a/git-compat-util.h b/git-compat-util.h
index 8b8b29a867..607dca7534 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -77,7 +77,7 @@
 #endif
 /*
  * ARRAY_SIZE - get the number of elements in a visible array
- *  <at> x: the array whose size you want.
+ * @x: the array whose size you want.
  *
  * This does not work on pointers, or arrays declared as [], or
  * function parameters.  With correct compiler support, such usage
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index b31613cb8a..1057f389d3 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -600,7 +600,7 @@ my $cvs = CVSconn->new($opt_d, $cvs_tree);
 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-gui/README.md b/git-gui/README.md
new file mode 100644
index 0000000000..5ce2122fbc
--- /dev/null
+++ b/git-gui/README.md
@@ -0,0 +1,174 @@
+# Git GUI - A graphical user interface for Git
+
+Git GUI allows you to use the [Git source control management
+tools](https://git-scm.com/) via a GUI. This includes staging, committing,
+adding, pushing, etc. It can also be used as a blame viewer, a tree browser,
+and a citool (make exactly one commit before exiting and returning to shell).
+More details about Git GUI can be found in its manual page by either running
+`man git-gui`, or by visiting the [online manual
+page](https://git-scm.com/docs/git-gui).
+
+Git GUI was initially written by Shawn O. Pearce, and is distributed with the
+standard Git installation.
+
+# Building and installing
+
+You need to have the following dependencies installed before you begin:
+
+- Git
+- Tcl
+- Tk
+- wish
+- Gitk (needed for browsing history)
+- msgfmt
+
+Most of Git GUI is written in Tcl, so there is no compilation involved. Still,
+some things do need to be done (mostly some substitutions), so you do need to
+"build" it.
+
+You can build Git GUI using:
+
+```
+make
+```
+
+And then install it using:
+
+```
+make install
+```
+
+You probably need to have root/admin permissions to install.
+
+# Contributing
+
+The project is currently maintained by Pratyush Yadav over at
+https://github.com/prati0100/git-gui. Even though the project is hosted at
+GitHub, the development does not happen over GitHub Issues and Pull Requests.
+Instead, an email based workflow is used. The Git mailing list
+[git@vger.kernel.org](mailto:git@vger.kernel.org) is where the patches are
+discussed and reviewed.
+
+More information about the Git mailing list and instructions to subscribe can
+be found [here](https://git.wiki.kernel.org/index.php/GitCommunity).
+
+## Sending your changes
+
+Since the development happens over email, you need to send in your commits in
+text format. Commits can be converted to emails via the two tools provided by
+Git: `git-send-email` and `git-format-patch`.
+
+You can use `git-format-patch` to generate patches in mbox format from your
+commits that can then be sent via email. Let's say you are working on a branch
+called 'foo' that was created on top of 'master'. You can run:
+
+```
+git format-patch -o output_dir master..foo
+```
+
+to convert all the extra commits in 'foo' into a set of patches saved in the
+folder `output_dir`.
+
+If you are sending multiple patches, it is recommended to include a cover
+letter. A cover letter is an email explaining in brief what the series is
+supposed to do. A cover letter template can be generated by passing
+`--cover-letter` to `git-format-patch`.
+
+After you send your patches, you might get a review suggesting some changes.
+Make those changes, and re-send your patch(es) in reply to the first patch of
+your initial version. Also please mention the version of the patch. This can be
+done by passing `-v X` to `git-format-patch`, where 'X' is the version number
+of the patch(es).
+
+### Using git-send-email
+
+You can use `git-send-email` to send patches generated via `git-format-patch`.
+While you can directly send patches via `git-send-email`, it is recommended
+that you first use `git-format-patch` to generate the emails, audit them, and
+then send them via `git-send-email`.
+
+A pretty good guide to configuring and using `git-send-email` can be found
+[here](https://www.freedesktop.org/wiki/Software/PulseAudio/HowToUseGitSendEmail/)
+
+### Using your email client
+
+If your email client supports sending mbox format emails, you can use
+`git-format-patch` to get an mbox file for each commit, and then send them. If
+there is more than one patch in the series, then all patches after the first
+patch (or the cover letter) need to be sent as replies to the first.
+`git-send-email` does this by default.
+
+### Using GitGitGadget
+
+Since some people prefer a GitHub pull request based workflow, they can use
+[GitGitGadget](https://gitgitgadget.github.io/) to send in patches. The tool
+was originally written for sending patches to the Git project, but it now also
+supports sending patches for git-gui.
+
+Instructions for using GitGitGadget to send git-gui patches, courtesy of
+Johannes Schindelin:
+
+If you don't already have a fork of the [git/git](https://github.com/git/git)
+repo, you need to make one. Then clone your fork:
+
+```
+git clone https://github.com/<your-username>/git
+```
+
+Then add GitGitGadget as a remote:
+
+```
+git remote add gitgitgadget https://github.com/gitgitgadget/git
+```
+
+Then fetch the git-gui branch:
+
+```
+git fetch gitgitgadget git-gui/master
+```
+
+Then create a new branch based on git-gui/master:
+
+```
+git checkout -b <your-branch-name> git-gui/master
+```
+
+Make whatever commits you need to, push them to your fork, and then head over
+to https://github.com/gitgitgadget/git/pulls and open a Pull Request targeting
+git-gui/master.
+
+GitGitGadget will welcome you with a (hopefully) helpful message.
+
+## Signing off
+
+You need to sign off your commits before sending them to the list. You can do
+that by passing the `-s` option to `git-commit`. You can also use the "Sign
+Off" option in Git GUI.
+
+A sign-off is a simple 'Signed-off-by: A U Thor \<author@example.com\>' line at
+the end of the commit message, after your explanation of the commit.
+
+A sign-off means that you are legally allowed to send the code, and it serves
+as a certificate of origin. More information can be found at
+[developercertificate.org](https://developercertificate.org/).
+
+## Responding to review comments
+
+It is quite likely your patches will get review comments. Those comments are
+sent on the Git mailing list as replies to your patch, and you will usually be
+Cc'ed in those replies.
+
+You are expected to respond by either explaining your code further to convince
+the reviewer what you are doing is correct, or acknowledge the comments and
+re-send the patches with those comments addressed.
+
+Some tips for those not familiar with communication on a mailing list:
+
+- Use only plain text emails. No HTML at all.
+- Wrap lines at around 75 characters.
+- Do not send attachments. If you do need to send some files, consider using a
+  hosting service, and paste the link in your email.
+- Do not [top post](http://www.idallen.com/topposting.html).
+- Always "reply all". Keep all correspondents and the list in Cc. If you reply
+  directly to a reviewer, and not Cc the list, other people would not be able
+  to chime in.
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index fd476b6999..0d21f5688b 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -2736,10 +2736,18 @@ if {![is_bare]} {
 }
 
 if {[is_Windows]} {
+        # Use /git-bash.exe if available
+        set normalized [file normalize $::argv0]
+        regsub "/mingw../libexec/git-core/git-gui$" \
+                $normalized "/git-bash.exe" cmdLine
+        if {$cmdLine != $normalized && [file exists $cmdLine]} {
+                set cmdLine [list "Git Bash" $cmdLine &]
+        } else {
+                set cmdLine [list "Git Bash" bash --login -l &]
+        }
         .mbar.repository add command \
                 -label [mc "Git Bash"] \
-                -command {eval exec [auto_execok start] \
-                                          [list "Git Bash" bash --login -l &]}
+                -command {eval exec [auto_execok start] $cmdLine}
 }
 
 if {[is_Windows] || ![is_bare]} {
@@ -3581,6 +3589,9 @@ $ui_diff tag conf d_s- \
 $ui_diff tag conf d< \
         -foreground orange \
         -font font_diffbold
+$ui_diff tag conf d| \
+        -foreground orange \
+        -font font_diffbold
 $ui_diff tag conf d= \
         -foreground orange \
         -font font_diffbold
diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl
index 958a0fa219..871ad488c2 100644
--- a/git-gui/lib/diff.tcl
+++ b/git-gui/lib/diff.tcl
@@ -270,19 +270,6 @@ proc show_other_diff {path w m cont_info} {
         }
 }
 
-proc get_conflict_marker_size {path} {
-        set size 7
-        catch {
-                set fd_rc [eval [list git_read check-attr "conflict-marker-size" -- $path]]
-                set ret [gets $fd_rc line]
-                close $fd_rc
-                if {$ret > 0} {
-                        regexp {.*: conflict-marker-size: (\d+)$} $line line size
-                }
-        }
-        return $size
-}
-
 proc start_show_diff {cont_info {add_opts {}}} {
         global file_states file_lists
         global is_3way_diff is_submodule_diff diff_active repo_config
@@ -298,7 +285,7 @@ proc start_show_diff {cont_info {add_opts {}}} {
         set is_submodule_diff 0
         set diff_active 1
         set current_diff_header {}
-        set conflict_size [get_conflict_marker_size $path]
+        set conflict_size [gitattr $path conflict-marker-size 7]
 
         set cmd [list]
         if {$w eq $ui_index} {
@@ -360,6 +347,10 @@ proc start_show_diff {cont_info {add_opts {}}} {
         }
 
         set ::current_diff_inheader 1
+        # Detect pre-image lines of the diff3 conflict-style. They are just
+        # '++' lines which is not bijective. Thus, we need to maintain a state
+        # across lines.
+        set ::conflict_in_pre_image 0
         fconfigure $fd \
                 -blocking 0 \
                 -encoding [get_path_encoding $path] \
@@ -462,11 +453,23 @@ proc read_diff {fd conflict_size cont_info} {
                         {--} {set tags d_--}
                         {++} {
                                 set regexp [string map [list %conflict_size $conflict_size]\
-                                                                {^\+\+([<>=]){%conflict_size}(?: |$)}]
+                                                                {^\+\+([<>=|]){%conflict_size}(?: |$)}]
                                 if {[regexp $regexp $line _g op]} {
                                         set is_conflict_diff 1
                                         set line [string replace $line 0 1 {  }]
                                         set tags d$op
+
+                                        # The ||| conflict-marker marks the start of the pre-image.
+                                        # All those lines are also prefixed with '++'. Thus we need
+                                        # to maintain this state.
+                                        set ::conflict_in_pre_image [expr {$op eq {|}}]
+                                } elseif {$::conflict_in_pre_image} {
+                                        # This is a pre-image line. It is the one which both sides
+                                        # are based on. As it has also the '++' line start, it is
+                                        # normally shown as 'added'. Invert this to '--' to make
+                                        # it a 'removed' line.
+                                        set line [string replace $line 0 1 {--}]
+                                        set tags d_--
                                 } else {
                                         set tags d_++
                                 }
diff --git a/git-gui/po/ja.po b/git-gui/po/ja.po
index 208651c1af..2f61153ab9 100644
--- a/git-gui/po/ja.po
+++ b/git-gui/po/ja.po
@@ -4,14 +4,15 @@
 #
 # しらいし ななこ <nanako3@bluebottle.com>, 2007.
 # Satoshi Yasushima <s.yasushima@gmail.com>, 2016.
+# KIDANI Akito <a.kid.1985@gmail.com>, 2019.
 #
 msgid ""
 msgstr ""
 "Project-Id-Version: git-gui\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2016-05-27 17:52+0900\n"
-"PO-Revision-Date: 2016-06-22 12:50+0900\n"
-"Last-Translator: Satoshi Yasushima <s.yasushima@gmail.com>\n"
+"PO-Revision-Date: 2019-10-13 23:20+0900\n"
+"Last-Translator: KIDANI Akito <a.kid.1985@gmail.com>\n"
 "Language-Team: Japanese\n"
 "Language: ja\n"
 "MIME-Version: 1.0\n"
@@ -661,7 +662,7 @@ msgstr ""
 #: lib/merge.tcl:108
 #, tcl-format
 msgid "%s of %s"
-msgstr "%s の %s ブランチ"
+msgstr "%2$s の %1$s ブランチ"
 
 #: lib/merge.tcl:122
 #, tcl-format
@@ -956,7 +957,7 @@ msgstr "エラー: コマンドが失敗しました"
 #: lib/checkout_op.tcl:85
 #, tcl-format
 msgid "Fetching %s from %s"
-msgstr "%s から %s をフェッチしています"
+msgstr "%2$s から %1$s をフェッチしています"
 
 #: lib/checkout_op.tcl:133
 #, tcl-format
diff --git a/git-legacy-stash.sh b/git-legacy-stash.sh
index f60e9b3e87..53fa574301 100755
--- a/git-legacy-stash.sh
+++ b/git-legacy-stash.sh
@@ -193,7 +193,8 @@ create_stash () {
                         GIT_INDEX_FILE="$TMPindex" &&
                         export GIT_INDEX_FILE &&
                         git diff-index --name-only -z HEAD -- "$@" >"$TMP-stagenames" &&
-                        git update-index -z --add --remove --stdin <"$TMP-stagenames" &&
+                        git update-index --ignore-skip-worktree-entries \
+                                -z --add --remove --stdin <"$TMP-stagenames" &&
                         git write-tree &&
                         rm -f "$TMPindex"
                 ) ) ||
@@ -370,7 +371,7 @@ push_stash () {
                         git diff-index -p --cached --binary HEAD -- "$@" |
                         git apply --index -R
                 else
-                        git reset --hard -q
+                        git reset --hard -q --no-recurse-submodules
                 fi
 
                 if test "$keep_index" = "t" && test -n "$i_tree"
diff --git a/git-send-email.perl b/git-send-email.perl
index 5f92c89c1c..dc95656f75 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1228,7 +1228,7 @@ sub process_address_list {
 # 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.c b/git.c
index ce6ab0ece2..7be7ad34bd 100644
--- a/git.c
+++ b/git.c
@@ -572,6 +572,7 @@ static struct cmd_struct commands[] = {
         { "show-branch", cmd_show_branch, RUN_SETUP },
         { "show-index", cmd_show_index },
         { "show-ref", cmd_show_ref, RUN_SETUP },
+        { "sparse-checkout", cmd_sparse_checkout, RUN_SETUP | NEED_WORK_TREE },
         { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
         /*
          * NEEDSWORK: Until the builtin stash is thoroughly robust and no
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 7fef19fe59..0f857d790b 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1657,15 +1657,15 @@ sub quot_cec {
         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 @@ sub print_feed_meta {
 
                         $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 @@ sub print_feed_meta {
                               "/>\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 @@ sub print_feed_meta {
         } 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 @@ sub git_footer_html {
         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 @@ sub git_blob {
                         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 @@ sub git_feed {
         } 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 @@ XML
                       $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 @@ XML
                               "<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 @@ XML
                         }
                         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 @@ XML
                 }
 
                 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/gitweb/static/js/blame_incremental.js b/gitweb/static/js/blame_incremental.js
index db6eb50584..e100d8206b 100644
--- a/gitweb/static/js/blame_incremental.js
+++ b/gitweb/static/js/blame_incremental.js
@@ -484,7 +484,7 @@ function processBlameLines(lines) {
                         case 'previous':
                                 curCommit.nprevious++;
                                 // store only first 'previous' header
-                                if (!'previous' in curCommit) {
+                                if (!('previous' in curCommit)) {
                                         var parts = data.split(' ', 2);
                                         curCommit.previous    = parts[0];
                                         curCommit.file_parent = unquote(parts[1]);
diff --git a/graph.c b/graph.c
index f53135485f..e3fd0ea5f8 100644
--- a/graph.c
+++ b/graph.c
@@ -112,14 +112,42 @@ static const char *column_get_color_code(unsigned short color)
         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 +203,63 @@ struct git_graph {
          */
         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 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:
+         *
+         *                | | |                        | |  \
+         *                | * |                        | *-. \
+         *         &#