Merge branch 'jt/interpret-branch-name-fallback'

"git status" has trouble showing where it came from by interpreting
reflog entries that recordcertain events, e.g. "checkout @{u}", and
gives a hard/fatal error.  Even though it inherently is impossible
to give a correct answer because the reflog entries lose some
information (e.g. "@{u}" does not record what branch the user was
on hence which branch 'the upstream' needs to be computed, and even
if the record were available, the relationship between branches may
have changed), at least hide the error to allow "status" show its
output.

* jt/interpret-branch-name-fallback:
  wt-status: tolerate dangling marks
  refs: move dwim_ref() to header file
  sha1-name: replace unsigned int with option struct
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 84a5dcf..fcfd138 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -7,34 +7,33 @@
 
 jobs:
   ci-config:
-      runs-on: ubuntu-latest
-      outputs:
-        enabled: ${{ steps.check-ref.outputs.enabled }}
-      steps:
-        - name: try to clone ci-config branch
-          continue-on-error: true
-          run: |
-            git -c protocol.version=2 clone \
-              --no-tags \
-              --single-branch \
-              -b ci-config \
-              --depth 1 \
-              --no-checkout \
-              --filter=blob:none \
-              https://github.com/${{ github.repository }} \
-              config-repo &&
-              cd config-repo &&
-              git checkout HEAD -- ci/config
-        - id: check-ref
-          name: check whether CI is enabled for ref
-          run: |
-            enabled=yes
-            if test -x config-repo/ci/config/allow-ref &&
-               ! config-repo/ci/config/allow-ref '${{ github.ref }}'
-            then
-              enabled=no
-            fi
-            echo "::set-output name=enabled::$enabled"
+    runs-on: ubuntu-latest
+    outputs:
+      enabled: ${{ steps.check-ref.outputs.enabled }}
+    steps:
+      - name: try to clone ci-config branch
+        run: |
+          git -c protocol.version=2 clone \
+            --no-tags \
+            --single-branch \
+            -b ci-config \
+            --depth 1 \
+            --no-checkout \
+            --filter=blob:none \
+            https://github.com/${{ github.repository }} \
+            config-repo &&
+          cd config-repo &&
+          git checkout HEAD -- ci/config || : ignore
+      - id: check-ref
+        name: check whether CI is enabled for ref
+        run: |
+          enabled=yes
+          if test -x config-repo/ci/config/allow-ref &&
+             ! config-repo/ci/config/allow-ref '${{ github.ref }}'
+          then
+            enabled=no
+          fi
+          echo "::set-output name=enabled::$enabled"
 
   windows-build:
     needs: ci-config
@@ -145,13 +144,6 @@
         ## Unzip and remove the artifact
         unzip artifacts.zip
         rm artifacts.zip
-    - name: generate Visual Studio solution
-      shell: powershell
-      run: |
-        & .\git-sdk-64-minimal\usr\bin\bash.exe -lc @"
-          make NDEBUG=1 DEVELOPER=1 vcxproj
-        "@
-        if (!$?) { exit(1) }
     - name: download vcpkg artifacts
       shell: powershell
       run: |
@@ -163,6 +155,17 @@
         Remove-Item compat.zip
     - name: add msbuild to PATH
       uses: microsoft/setup-msbuild@v1.0.0
+    - name: copy dlls to root
+      shell: powershell
+      run: |
+        & compat\vcbuild\vcpkg_copy_dlls.bat release
+        if (!$?) { exit(1) }
+    - name: generate Visual Studio solution
+      shell: bash
+      run: |
+        cmake `pwd`/contrib/buildsystems/ -DCMAKE_PREFIX_PATH=`pwd`/compat/vcbuild/vcpkg/installed/x64-windows \
+        -DIconv_LIBRARY=`pwd`/compat/vcbuild/vcpkg/installed/x64-windows/lib/libiconv.lib -DIconv_INCLUDE_DIR=`pwd`/compat/vcbuild/vcpkg/installed/x64-windows/include \
+        -DMSGFMT_EXE=`pwd`/git-sdk-64-minimal/mingw64/bin/msgfmt.exe -DPERL_TESTS=OFF -DPYTHON_TESTS=OFF -DCURL_NO_CURL_CMAKE=ON
     - name: MSBuild
       run: msbuild git.sln -property:Configuration=Release -property:Platform=x64 -maxCpuCount:4 -property:PlatformToolset=v142
     - name: bundle artifact tar
@@ -171,8 +174,6 @@
         MSVC: 1
         VCPKG_ROOT: ${{github.workspace}}\compat\vcbuild\vcpkg
       run: |
-        & compat\vcbuild\vcpkg_copy_dlls.bat release
-        if (!$?) { exit(1) }
         & git-sdk-64-minimal\usr\bin\bash.exe -lc @"
           mkdir -p artifacts &&
           eval \"`$(make -n artifacts-tar INCLUDE_DLLS_IN_ARTIFACTS=YesPlease ARTIFACTS_DIRECTORY=artifacts 2>&1 | grep ^tar)\"
@@ -203,7 +204,7 @@
     - name: extract build artifacts
       shell: bash
       run: tar xf artifacts.tar.gz
-    - name: test (parallel)
+    - name: test
       shell: powershell
       env:
         MSYSTEM: MINGW64
@@ -214,12 +215,19 @@
           # Let Git ignore the SDK and the test-cache
           printf '%s\n' /git-sdk-64-minimal/ /test-cache/ >>.git/info/exclude
 
-          cd t &&
-          PATH=\"`$PWD/helper:`$PATH\" &&
-          test-tool.exe run-command testsuite --jobs=10 -V -x --write-junit-xml \
-                  `$(test-tool.exe path-utils slice-tests \
-                          ${{matrix.nr}} 10 t[0-9]*.sh)
+          ci/run-test-slice.sh ${{matrix.nr}} 10
         "@
+    - name: ci/print-test-failures.sh
+      if: failure()
+      shell: powershell
+      run: |
+        & .\git-sdk-64-minimal\usr\bin\bash.exe -lc ci/print-test-failures.sh
+    - name: Upload failed tests' directories
+      if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+      uses: actions/upload-artifact@v1
+      with:
+        name: failed-tests-windows
+        path: ${{env.FAILED_TEST_ARTIFACTS}}
   regular:
     needs: ci-config
     if: needs.ci-config.outputs.enabled == 'yes'
diff --git a/.gitignore b/.gitignore
index ee509a2..9673e79 100644
--- a/.gitignore
+++ b/.gitignore
@@ -134,7 +134,6 @@
 /git-remote-fd
 /git-remote-ext
 /git-remote-testpy
-/git-remote-testsvn
 /git-repack
 /git-replace
 /git-request-pull
diff --git a/Documentation/Makefile b/Documentation/Makefile
index ecd0b34..80d1908 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -17,6 +17,7 @@
 MAN1_TXT += gitk.txt
 MAN1_TXT += gitweb.txt
 
+# man5 / man7 guides (note: new guides should also be added to command-list.txt)
 MAN5_TXT += gitattributes.txt
 MAN5_TXT += githooks.txt
 MAN5_TXT += gitignore.txt
@@ -294,6 +295,7 @@
 	cmds-plumbingmanipulators.txt \
 	cmds-synchingrepositories.txt \
 	cmds-synchelpers.txt \
+	cmds-guide.txt \
 	cmds-purehelpers.txt \
 	cmds-foreignscminterface.txt
 
@@ -301,7 +303,7 @@
 
 cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
 	$(QUIET_GEN)$(RM) $@ && \
-	$(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \
+	$(PERL_PATH) ./cmd-list.perl ../command-list.txt $(cmds_txt) $(QUIET_STDERR) && \
 	date >$@
 
 mergetools_txt = mergetools-diff.txt mergetools-merge.txt
diff --git a/Documentation/MyFirstContribution.txt b/Documentation/MyFirstContribution.txt
index d85c9b5..4f85a08 100644
--- a/Documentation/MyFirstContribution.txt
+++ b/Documentation/MyFirstContribution.txt
@@ -319,14 +319,14 @@
 ...
 
 	git_config(git_default_config, NULL);
-	if (git_config_get_string_const("user.name", &cfg_name) > 0)
+	if (git_config_get_string_tmp("user.name", &cfg_name) > 0)
 		printf(_("No name is found in config\n"));
 	else
 		printf(_("Your name: %s\n"), cfg_name);
 ----
 
 `git_config()` will grab the configuration from config files known to Git and
-apply standard precedence rules. `git_config_get_string_const()` will look up
+apply standard precedence rules. `git_config_get_string_tmp()` will look up
 a specific key ("user.name") and give you the value. There are a number of
 single-key lookup functions like this one; you can see them all (and more info
 about how to use `git_config()`) in `Documentation/technical/api-config.txt`.
diff --git a/Documentation/RelNotes/2.29.0.txt b/Documentation/RelNotes/2.29.0.txt
new file mode 100644
index 0000000..a640fbc
--- /dev/null
+++ b/Documentation/RelNotes/2.29.0.txt
@@ -0,0 +1,313 @@
+Git 2.29 Release Notes
+======================
+
+Updates since v2.28
+-------------------
+
+UI, Workflows & Features
+
+ * "git help log" has been enhanced by sharing more material from the
+   documentation for the underlying "git rev-list" command.
+
+ * "git for-each-ref --format=<>" learned %(contents:size).
+
+ * "git merge" learned to selectively omit " into <branch>" at the end
+   of the title of default merge message with merge.suppressDest
+   configuration.
+
+ * The component to respond to "git fetch" request is made more
+   configurable to selectively allow or reject object filtering
+   specification used for partial cloning.
+
+ * Stop when "sendmail.*" configuration variables are defined, which
+   could be a mistaken attempt to define "sendemail.*" variables.
+
+ * The existing backends for "git mergetool" based on variants of vim
+   have been refactored and then support for "nvim" has been added.
+
+ * "git bisect" learns the "--first-parent" option to find the first
+   breakage along the first-parent chain.
+
+ * "git log --first-parent -p" showed patches only for single-parent
+   commits on the first-parent chain; the "--first-parent" option has
+   been made to imply "-m".  Use "--no-diff-merges" to restore the
+   previous behaviour to omit patches for merge commits.
+
+ * The commit labels used to explain each side of conflicted hunks
+   placed by the sequencer machinery have been made more readable by
+   humans.
+
+ * The "--batch-size" option of "git multi-pack-index repack" command
+   is now used to specify that very small packfiles are collected into
+   one until the total size roughly exceeds it.
+
+ * The recent addition of SHA-256 support is marked as experimental in
+   the documentation.
+
+ * "git fetch" learned --no-write-fetch-head option to avoid writing
+   the FETCH_HEAD file.
+
+ * Command line completion (in contrib/) usually omits redundant,
+   deprecated and/or dangerous options from its output; it learned to
+   optionally include all of them.
+
+ * The output from the "diff" family of the commands had abbreviated
+   object names of blobs involved in the patch, but its length was not
+   affected by the --abbrev option.  Now it is.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The changed-path Bloom filter is improved using ideas from an
+   independent implementation.
+
+ * Updates to the changed-paths bloom filter.
+
+ * The test framework has been updated so that most tests will run
+   with predictable (artificial) timestamps.
+
+ * Preliminary clean-up of the refs API in preparation for adding a
+   new refs backend "reftable".
+
+ * Dev support to limit the use of test_must_fail to only git commands.
+
+ * While packing many objects in a repository with a promissor remote,
+   lazily fetching missing objects from the promissor remote one by
+   one may be inefficient---the code now attempts to fetch all the
+   missing objects in batch (obviously this won't work for a lazy
+   clone that lazily fetches tree objects as you cannot even enumerate
+   what blobs are missing until you learn which trees are missing).
+
+ * The pretend-object mechanism checks if the given object already
+   exists in the object store before deciding to keep the data
+   in-core, but the check would have triggered lazy fetching of such
+   an object from a promissor remote.
+
+ * The argv_array API is useful for not just managing argv but any
+   "vector" (NULL-terminated array) of strings, and has seen adoption
+   to a certain degree.  It has been renamed to "strvec" to reduce the
+   barrier to adoption.
+
+ * The final leg of SHA-256 transition plus doc updates.  Note that
+   there is no inter-operability between SHA-1 and SHA-256
+   repositories yet.
+
+ * CMake support to build with MSVC for Windows bypassing the Makefile.
+
+ * A new helper function has_object() has been introduced to make it
+   easier to mark object existence checks that do and don't want to
+   trigger lazy fetches, and a few such checks are converted using it.
+
+ * A no-op replacement function implemented as a C preprocessor macro
+   does not perform as good a job as one implemented as a "static
+   inline" function in catching errors in parameters; replace the
+   former with the latter in <git-compat-util.h> header.
+
+ * Test framework update.
+   (merge d572f52a64 es/test-cmp-typocatcher later to maint).
+
+ * Updates to "git merge" tests, in preparation for a new merge
+   strategy backend.
+
+ * midx and commit-graph files now use the byte defined in their file
+   format specification for identifying the hash function used for
+   object names.
+
+ * The FETCH_HEAD is now always read from the filesystem regardless of
+   the ref backend in use, as its format is much richer than the
+   normal refs, and written directly by "git fetch" as a plain file..
+
+ * A handful of places in in-tree code still relied on being able to
+   execute the git subcommands, especially built-ins, in "git-foo"
+   form, which have been corrected.
+
+ * An unused binary has been discarded, and and a bunch of commands
+   have been turned into into built-in.
+
+ * A handful of places in in-tree code still relied on being able to
+   execute the git subcommands, especially built-ins, in "git-foo"
+   form, which have been corrected.
+
+
+Fixes since v2.28
+-----------------
+
+ * "git clone --separate-git-dir=$elsewhere" used to stomp on the
+   contents of the existing directory $elsewhere, which has been
+   taught to fail when $elsewhere is not an empty directory.
+   (merge dfaa209a79 bw/fail-cloning-into-non-empty later to maint).
+
+ * With the base fix to 2.27 regresion, any new extensions in a v0
+   repository would still be silently honored, which is not quite
+   right.  Instead, complain and die loudly.
+   (merge ec91ffca04 jk/reject-newer-extensions-in-v0 later to maint).
+
+ * Fetching from a lazily cloned repository resulted at the server
+   side in attempts to lazy fetch objects that the client side has,
+   many of which will not be available from the third-party anyway.
+   (merge 77aa0941ce jt/avoid-lazy-fetching-upon-have-check later to maint).
+
+ * Fix to an ancient bug caused by an over-eager attempt for
+   optimization.
+   (merge a98f7fb366 rs/add-index-entry-optim-fix later to maint).
+
+ * Pushing a ref whose name contains non-ASCII character with the
+   "--force-with-lease" option did not work over smart HTTP protocol,
+   which has been corrected.
+   (merge cd85b447bf bc/push-cas-cquoted-refname later to maint).
+
+ * "git mv src dst", when src is an unmerged path, errored out
+   correctly but with an incorrect error message to claim that src is
+   not tracked, which has been clarified.
+   (merge 9b906af657 ct/mv-unmerged-path-error later to maint).
+
+ * Fix to a regression introduced during 2.27 cycle.
+   (merge cada7308ad en/fill-directory-exponential later to maint).
+
+ * Command line completion (in contrib/) update.
+   (merge 688b87c81b mp/complete-show-color-moved later to maint).
+
+ * All "mergy" operations that internally use the merge-recursive
+   machinery should honor the merge.renormalize configuration, but
+   many of them didn't.
+
+ * Doc cleanup around "worktree".
+   (merge dc9c144be5 es/worktree-doc-cleanups later to maint).
+
+ * The "git blame --first-parent" option was not documented, but now
+   it is.
+   (merge 11bc12ae1e rp/blame-first-parent-doc later to maint).
+
+ * The logic to find the ref transaction hook script attempted to
+   cache the path to the found hook without realizing that it needed
+   to keep a copied value, as the API it used returned a transitory
+   buffer space.  This has been corrected.
+   (merge 09b2aa30c9 ps/ref-transaction-hook later to maint).
+
+ * Recent versions of "git diff-files" shows a diff between the index
+   and the working tree for "intent-to-add" paths as a "new file"
+   patch; "git apply --cached" should be able to take "git diff-files"
+   and should act as an equivalent to "git add" for the path, but the
+   command failed to do so for such a path.
+   (merge 4c025c667e rp/apply-cached-with-i-t-a later to maint).
+
+ * "git diff [<tree-ish>] $path" for a $path that is marked with i-t-a
+   bit was not showing the mode bits from the working tree.
+   (merge cb0dd22b82 rp/ita-diff-modefix later to maint).
+
+ * Ring buffer with size 4 used for bin-hex translation resulted in a
+   wrong object name in the sequencer's todo output, which has been
+   corrected.
+   (merge 5da69c0dac ak/sequencer-fix-find-uniq-abbrev later to maint).
+
+ * When given more than one target line ranges, "git blame -La,b
+   -Lc,d" was over-eager to coalesce groups of original lines and
+   showed incorrect results, which has been corrected.
+   (merge c2ebaa27d6 jk/blame-coalesce-fix later to maint).
+
+ * The regexp to identify the function boundary for FORTRAN programs
+   has been updated.
+   (merge 75c3b6b2e8 pb/userdiff-fortran-update later to maint).
+
+ * A few end-user facing messages have been updated to be
+   hash-algorithm agnostic.
+   (merge 4279000d3e jc/object-names-are-not-sha-1 later to maint).
+
+ * "unlink" emulation on MinGW has been optimized.
+   (merge 680e0b4524 jh/mingw-unlink later to maint).
+
+ * The purpose of "git init --separate-git-dir" is to initialize a
+   new project with the repository separate from the working tree,
+   or, in the case of an existing project, to move the repository
+   (the .git/ directory) out of the working tree. It does not make
+   sense to use --separate-git-dir with a bare repository for which
+   there is no working tree, so disallow its use with bare
+   repositories.
+   (merge ccf236a23a es/init-no-separate-git-dir-in-bare later to maint).
+
+ * "ls-files -o" mishandled the top-level directory of another git
+   working tree that hangs in the current git working tree.
+   (merge ab282aa548 en/dir-nonbare-embedded later to maint).
+
+ * Fix some incorrect UNLEAK() annotations.
+   (merge 3e19816dc0 jk/unleak-fixes later to maint).
+
+ * Use more buffered I/O where we used to call many small write(2)s.
+   (merge a698d67b08 rs/more-buffered-io later to maint).
+
+ * The patch-id computation did not ignore the "incomplete last line"
+   marker like whitespaces.
+   (merge 82a62015a7 rs/patch-id-with-incomplete-line later to maint).
+
+ * Updates into a lazy/partial clone with a submodule did not work
+   well with transfer.fsckobjects set.
+
+ * The parser for "git for-each-ref --format=..." was too loose when
+   parsing the "%(trailers...)" atom, and forgot that "trailers" and
+   "trailers:<modifiers>" are the only two allowed forms, which has
+   been corrected.
+   (merge 2c22e102f8 hv/ref-filter-trailers-atom-parsing-fix later to maint).
+
+ * Long ago, we decided to use 3 threads by default when running the
+   index-pack task in parallel, which has been adjusted a bit upwards.
+   (merge fbff95b67f jk/index-pack-w-more-threads later to maint).
+
+ * "git restore/checkout --no-overlay" with wildcarded pathspec
+   mistakenly removed matching paths in subdirectories, which has been
+   corrected.
+   (merge bfda204ade rs/checkout-no-overlay-pathspec-fix later to maint).
+
+ * The description of --cached/--index options in "git apply --help"
+   has been updated.
+   (merge d064702be3 rp/apply-cached-doc later to maint).
+
+ * Feeding "$ZERO_OID" to "git log --ignore-missing --stdin", and
+   running "git log --ignore-missing $ZERO_OID" fell back to start
+   digging from HEAD; it has been corrected to become a no-op, like
+   "git log --tags=no-tag-matches-this-pattern" does.
+   (merge 04a0e98515 jk/rev-input-given-fix later to maint).
+
+ * Various callers of run_command API has been modernized.
+   (merge afbdba391e jc/run-command-use-embedded-args later to maint).
+
+ * List of options offered and accepted by "git add -i/-p" were
+   inconsistent, which have been corrected.
+   (merge ce910287e7 pw/add-p-allowed-options-fix later to maint).
+
+ * Various callers of run_command API has been modernized.
+   (merge afbdba391e jc/run-command-use-embedded-args later to maint).
+
+ * "git diff --stat -w" showed 0-line changes for paths whose changes
+   were only whitespaces, which was not intuitive.  We now omit such
+   paths from the stat output.
+   (merge 1cf3d5db9b mr/diff-hide-stat-wo-textual-change later to maint).
+
+ * It was possible for xrealloc() to send a non-NULL pointer that has
+   been freed, which has been fixed.
+   (merge 6479ea4a8a jk/xrealloc-avoid-use-after-free later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 84544f2ea3 sk/typofixes later to maint).
+   (merge b17f411ab5 ar/help-guides-doc later to maint).
+   (merge 98c6871fad rs/grep-simpler-parse-object-or-die-call later to maint).
+   (merge 861c4ce141 en/typofixes later to maint).
+   (merge 60e47f6773 sg/ci-git-path-fix-with-pyenv later to maint).
+   (merge e2bfa50ac3 jb/doc-packfile-name later to maint).
+   (merge 918d8ff780 es/worktree-cleanup later to maint).
+   (merge dc156bc31f ma/t1450-quotefix later to maint).
+   (merge 56e743426b en/merge-recursive-comment-fixes later to maint).
+   (merge 7d23ff818f rs/bisect-oid-to-hex-fix later to maint).
+   (merge de20baf2c9 ny/notes-doc-sample-update later to maint).
+   (merge f649aaaf82 so/rev-parser-errormessage-fix later to maint).
+   (merge 6103d58b7f bc/sha-256-cvs-svn-updates later to maint).
+   (merge ac900fddb7 ma/stop-progress-null-fix later to maint).
+   (merge e767963ab6 rs/upload-pack-sigchain-fix later to maint).
+   (merge a831908599 rs/preserve-merges-unused-code-removal later to maint).
+   (merge 6dfefe70a9 jb/commit-graph-doc-fix later to maint).
+   (merge 847b37271e pb/set-url-docfix later to maint).
+   (merge 748f733d54 mt/checkout-entry-dead-code-removal later to maint).
+   (merge ce820cbd58 dl/subtree-docs later to maint).
+   (merge 55fe225dde jk/leakfix later to maint).
+   (merge ee22a29215 so/pretty-abbrev-doc later to maint).
+   (merge 3100fd5588 jc/post-checkout-doc later to maint).
+   (merge 17bae89476 pb/doc-external-diff-env later to maint).
diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt
index 5d122db..88750af 100644
--- a/Documentation/blame-options.txt
+++ b/Documentation/blame-options.txt
@@ -36,6 +36,12 @@
 	START.  `git blame --reverse START` is taken as `git blame
 	--reverse START..HEAD` for convenience.
 
+--first-parent::
+	Follow only the first parent commit upon seeing a merge
+	commit. This option can be used to determine when a line
+	was introduced to a particular integration branch, rather
+	than when it was introduced to the history overall.
+
 -p::
 --porcelain::
 	Show in a format designed for machine consumption.
diff --git a/Documentation/cmd-list.perl b/Documentation/cmd-list.perl
index 5aa73cf..af5da45 100755
--- a/Documentation/cmd-list.perl
+++ b/Documentation/cmd-list.perl
@@ -6,9 +6,14 @@
 	my ($out, $nameattr) = @_;
 	my ($name, $attr) = @$nameattr;
 	my ($state, $description);
+	my $mansection;
 	$state = 0;
 	open I, '<', "$name.txt" or die "No such file $name.txt";
 	while (<I>) {
+		if (/^git[a-z0-9-]*\(([0-9])\)$/) {
+			$mansection = $1;
+			next;
+		}
 		if (/^NAME$/) {
 			$state = 1;
 			next;
@@ -27,7 +32,7 @@
 		die "No description found in $name.txt";
 	}
 	if (my ($verify_name, $text) = ($description =~ /^($name) - (.*)/)) {
-		print $out "linkgit:$name\[1\]::\n\t";
+		print $out "linkgit:$name\[$mansection\]::\n\t";
 		if ($attr =~ / deprecated /) {
 			print $out "(deprecated) ";
 		}
@@ -38,12 +43,15 @@
 	}
 }
 
-while (<>) {
+my ($input, @categories) = @ARGV;
+
+open IN, "<$input";
+while (<IN>) {
 	last if /^### command list/;
 }
 
 my %cmds = ();
-for (sort <>) {
+for (sort <IN>) {
 	next if /^#/;
 
 	chomp;
@@ -51,17 +59,10 @@
 	$attr = '' unless defined $attr;
 	push @{$cmds{$cat}}, [$name, " $attr "];
 }
+close IN;
 
-for my $cat (qw(ancillaryinterrogators
-		ancillarymanipulators
-		mainporcelain
-		plumbinginterrogators
-		plumbingmanipulators
-		synchingrepositories
-		foreignscminterface
-		purehelpers
-		synchelpers)) {
-	my $out = "cmds-$cat.txt";
+for my $out (@categories) {
+	my ($cat) = $out =~ /^cmds-(.*)\.txt$/;
 	open O, '>', "$out+" or die "Cannot open output file $out+";
 	for (@{$cmds{$cat}}) {
 		format_one(\*O, $_);
diff --git a/Documentation/config.txt b/Documentation/config.txt
index ef0768b..3042d80 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -348,6 +348,8 @@
 
 include::config/difftool.txt[]
 
+include::config/extensions.txt[]
+
 include::config/fastimport.txt[]
 
 include::config/feature.txt[]
diff --git a/Documentation/config/extensions.txt b/Documentation/config/extensions.txt
new file mode 100644
index 0000000..4e23d73
--- /dev/null
+++ b/Documentation/config/extensions.txt
@@ -0,0 +1,8 @@
+extensions.objectFormat::
+	Specify the hash algorithm to use.  The acceptable values are `sha1` and
+	`sha256`.  If not specified, `sha1` is assumed.  It is an error to specify
+	this key unless `core.repositoryFormatVersion` is 1.
++
+Note that this setting should only be set by linkgit:git-init[1] or
+linkgit:git-clone[1].  Trying to change it after initialization will not
+work and will produce hard-to-diagnose issues.
diff --git a/Documentation/config/fetch.txt b/Documentation/config/fetch.txt
index b203940..6af6f5e 100644
--- a/Documentation/config/fetch.txt
+++ b/Documentation/config/fetch.txt
@@ -60,7 +60,10 @@
 	sent when negotiating the contents of the packfile to be sent by the
 	server. Set to "skipping" to use an algorithm that skips commits in an
 	effort to converge faster, but may result in a larger-than-necessary
-	packfile; The default is "default" which instructs Git to use the default algorithm
+	packfile; or set to "noop" to not send any information at all, which
+	will almost certainly result in a larger-than-necessary packfile, but
+	will skip the negotiation step.
+	The default is "default" which instructs Git to use the default algorithm
 	that never skips commits (unless the server has acknowledged it or one
 	of its descendants). If `feature.experimental` is enabled, then this
 	setting defaults to "skipping".
diff --git a/Documentation/config/fmt-merge-msg.txt b/Documentation/config/fmt-merge-msg.txt
index c73cfa9..a8e8f74 100644
--- a/Documentation/config/fmt-merge-msg.txt
+++ b/Documentation/config/fmt-merge-msg.txt
@@ -8,3 +8,15 @@
 	most the specified number of one-line descriptions from the
 	actual commits that are being merged.  Defaults to false, and
 	true is a synonym for 20.
+
+merge.suppressDest::
+	By adding a glob that matches the names of integration
+	branches to this multi-valued configuration variable, the
+	default merge message computed for merges into these
+	integration branches will omit " into <branch name>" from
+	its title.
++
+An element with an empty value can be used to clear the list
+of globs accumulated from previous configuration entries.
+When there is no `merge.suppressDest` variable defined, the
+default value of `master` is used for backward compatibility.
diff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt
index 0006faf..cbc5af4 100644
--- a/Documentation/config/sendemail.txt
+++ b/Documentation/config/sendemail.txt
@@ -61,3 +61,8 @@
 sendemail.smtpReloginDelay::
 	Seconds wait before reconnecting to smtp server.
 	See also the `--relogin-delay` option of linkgit:git-send-email[1].
+
+sendemail.forbidSendmailVariables::
+	To avoid common misconfiguration mistakes, linkgit:git-send-email[1]
+	will abort with a warning if any configuration options for "sendmail"
+	exist. Set this variable to bypass the check.
diff --git a/Documentation/config/uploadpack.txt b/Documentation/config/uploadpack.txt
index ed1c835..ee7b3ac 100644
--- a/Documentation/config/uploadpack.txt
+++ b/Documentation/config/uploadpack.txt
@@ -57,6 +57,24 @@
 	If this option is set, `upload-pack` will support partial
 	clone and partial fetch object filtering.
 
+uploadpackfilter.allow::
+	Provides a default value for unspecified object filters (see: the
+	below configuration variable).
+	Defaults to `true`.
+
+uploadpackfilter.<filter>.allow::
+	Explicitly allow or ban the object filter corresponding to
+	`<filter>`, where `<filter>` may be one of: `blob:none`,
+	`blob:limit`, `tree`, `sparse:oid`, or `combine`. If using
+	combined filters, both `combine` and all of the nested filter
+	kinds must be allowed. Defaults to `uploadpackfilter.allow`.
+
+uploadpackfilter.tree.maxDepth::
+	Only allow `--filter=tree=<n>` when `n` is no more than the value of
+	`uploadpackfilter.tree.maxDepth`. If set, this also implies
+	`uploadpackfilter.tree.allow=true`, unless this configuration
+	variable had already been set. Has no effect if unset.
+
 uploadpack.allowRefInWant::
 	If this option is set, `upload-pack` will support the `ref-in-want`
 	feature of the protocol version 2 `fetch` command.  This feature
diff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt
index e8ed647..b10ff4c 100644
--- a/Documentation/diff-generate-patch.txt
+++ b/Documentation/diff-generate-patch.txt
@@ -10,7 +10,8 @@
 linkgit:git-diff-files[1]
 with the `-p` option produces patch text.
 You can customize the creation of patch text via the
-`GIT_EXTERNAL_DIFF` and the `GIT_DIFF_OPTS` environment variables.
+`GIT_EXTERNAL_DIFF` and the `GIT_DIFF_OPTS` environment variables
+(see linkgit:git[1]).
 
 What the -p option produces is slightly different from the traditional
 diff format:
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 7987d72..573fb9b 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -73,6 +73,11 @@
 	Synonym for `-p --raw`.
 endif::git-format-patch[]
 
+ifdef::git-log[]
+-t::
+	Show the tree objects in the diff output.
+endif::git-log[]
+
 --indent-heuristic::
 	Enable the heuristic that shifts diff hunk boundaries to make patches
 	easier to read. This is the default.
@@ -441,10 +446,11 @@
 --abbrev[=<n>]::
 	Instead of showing the full 40-byte hexadecimal object
 	name in diff-raw format output and diff-tree header
-	lines, show only a partial prefix.  This is
-	independent of the `--full-index` option above, which controls
-	the diff-patch output format.  Non default number of
-	digits can be specified with `--abbrev=<n>`.
+	lines, show only a partial prefix.
+	In diff-patch output format, `--full-index` takes higher
+	precedence, i.e. if `--full-index` is specified, full blob
+	names will be shown regardless of `--abbrev`.
+	Non default number of digits can be specified with `--abbrev=<n>`.
 
 -B[<n>][/<m>]::
 --break-rewrites[=[<n>][/<m>]]::
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 6e2a160..e8104c0 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -64,6 +64,15 @@
 --dry-run::
 	Show what would be done, without making any changes.
 
+ifndef::git-pull[]
+--[no-]write-fetch-head::
+	Write the list of remote refs fetched in the `FETCH_HEAD`
+	file directly under `$GIT_DIR`.  This is the default.
+	Passing `--no-write-fetch-head` from the command line tells
+	Git not to write the file.  Under `--dry-run` option, the
+	file is never written.
+endif::git-pull[]
+
 -f::
 --force::
 	When 'git fetch' is used with `<src>:<dst>` refspec it may
@@ -186,7 +195,7 @@
 endif::git-pull[]
 
 --set-upstream::
-	If the remote is fetched successfully, pull and add upstream
+	If the remote is fetched successfully, add upstream
 	(tracking) reference, used by argument-less
 	linkgit:git-pull[1] and other commands. For more information,
 	see `branch.<name>.merge` and `branch.<name>.remote` in
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt
index b9aa390..91d9a86 100644
--- a/Documentation/git-apply.txt
+++ b/Documentation/git-apply.txt
@@ -61,18 +61,18 @@
 	file and detects errors.  Turns off "apply".
 
 --index::
-	When `--check` is in effect, or when applying the patch
-	(which is the default when none of the options that
-	disables it is in effect), make sure the patch is
-	applicable to what the current index file records.  If
-	the file to be patched in the working tree is not
-	up to date, it is flagged as an error.  This flag also
-	causes the index file to be updated.
+	Apply the patch to both the index and the working tree (or
+	merely check that it would apply cleanly to both if `--check` is
+	in effect). Note that `--index` expects index entries and
+	working tree copies for relevant paths to be identical (their
+	contents and metadata such as file mode must match), and will
+	raise an error if they are not, even if the patch would apply
+	cleanly to both the index and the working tree in isolation.
 
 --cached::
-	Apply a patch without touching the working tree. Instead take the
-	cached data, apply the patch, and store the result in the index
-	without using the working tree. This implies `--index`.
+	Apply the patch to just the index, without touching the working
+	tree. If `--check` is in effect, merely check that it would
+	apply cleanly to the index entry.
 
 --intent-to-add::
 	When applying the patch only to the working tree, mark new
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt
index 7586c5a..fbb39fb 100644
--- a/Documentation/git-bisect.txt
+++ b/Documentation/git-bisect.txt
@@ -16,8 +16,8 @@
 The command takes various subcommands, and different options depending
 on the subcommand:
 
- git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
-		  [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]
+ git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
+		  [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]
  git bisect (bad|new|<term-new>) [<rev>]
  git bisect (good|old|<term-old>) [<rev>...]
  git bisect terms [--term-good | --term-bad]
@@ -365,6 +365,17 @@
 +
 If the repository is bare, `--no-checkout` is assumed.
 
+--first-parent::
++
+Follow only the first parent commit upon seeing a merge commit.
++
+In detecting regressions introduced through the merging of a branch, the merge
+commit will be identified as introduction of the bug and its ancestors will be
+ignored.
++
+This option is particularly useful in avoiding false positives when a merged
+branch contained broken or non-buildable commits, but the merge itself was OK.
+
 EXAMPLES
 --------
 
diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt
index d34b096..53804ca 100644
--- a/Documentation/git-bundle.txt
+++ b/Documentation/git-bundle.txt
@@ -9,7 +9,8 @@
 SYNOPSIS
 --------
 [verse]
-'git bundle' create [-q | --quiet | --progress | --all-progress] [--all-progress-implied] <file> <git-rev-list-args>
+'git bundle' create [-q | --quiet | --progress | --all-progress] [--all-progress-implied]
+		    [--version=<version>] <file> <git-rev-list-args>
 'git bundle' verify [-q | --quiet] <file>
 'git bundle' list-heads <file> [<refname>...]
 'git bundle' unbundle <file> [<refname>...]
@@ -102,6 +103,12 @@
 	is activated.  Unlike --all-progress this flag doesn't actually
 	force any progress display by itself.
 
+--version=<version>::
+	Specify the bundle version.  Version 2 is the older format and can only be
+	used with SHA-1 repositories; the newer version 3 contains capabilities that
+	permit extensions. The default is the oldest supported format, based on the
+	hash algorithm in use.
+
 -q::
 --quiet::
 	This flag makes the command not to report its progress
diff --git a/Documentation/git-commit-graph.txt b/Documentation/git-commit-graph.txt
index 8ca1764..17405c7 100644
--- a/Documentation/git-commit-graph.txt
+++ b/Documentation/git-commit-graph.txt
@@ -62,7 +62,10 @@
 With the `--changed-paths` option, compute and write information about the
 paths changed between a commit and its first parent. This operation can
 take a while on large repositories. It provides significant performance gains
-for getting history of a directory or a file with `git log -- <path>`.
+for getting history of a directory or a file with `git log -- <path>`. If
+this option is given, future commit-graph writes will automatically assume
+that this option was intended. Use `--no-changed-paths` to stop storing this
+data.
 +
 With the `--split[=<strategy>]` option, write the commit-graph as a
 chain of multiple commit-graph files stored in
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index 45b6d8e..9067c20 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -48,6 +48,10 @@
 
 include::pull-fetch-param.txt[]
 
+--stdin::
+	Read refspecs, one per line, from stdin in addition to those provided
+	as arguments. The "tag <name>" format is not supported.
+
 include::urls-remotes.txt[]
 
 
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 6dcd39f..616ce46 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -222,6 +222,8 @@
 In addition to the above, for commit and tag objects, the header
 field names (`tree`, `parent`, `object`, `type`, and `tag`) can
 be used to specify the value in the header field.
+Fields `tree` and `parent` can also be used with modifier `:short` and
+`:short=<length>` just like `objectname`.
 
 For commit and tag objects, the special `creatordate` and `creator`
 fields will correspond to the appropriate date or name-email-date tuple
@@ -230,14 +232,35 @@
 
 Fields that have name-email-date tuple as its value (`author`,
 `committer`, and `tagger`) can be suffixed with `name`, `email`,
-and `date` to extract the named component.
+and `date` to extract the named component.  For email fields (`authoremail`,
+`committeremail` and `taggeremail`), `:trim` can be appended to get the email
+without angle brackets, and `:localpart` to get the part before the `@` symbol
+out of the trimmed email.
 
-The complete message in a commit and tag object is `contents`.
-Its first line is `contents:subject`, where subject is the concatenation
-of all lines of the commit message up to the first blank line.  The next
-line is `contents:body`, where body is all of the lines after the first
-blank line.  The optional GPG signature is `contents:signature`.  The
-first `N` lines of the message is obtained using `contents:lines=N`.
+The message in a commit or a tag object is `contents`, from which
+`contents:<part>` can be used to extract various parts out of:
+
+contents:size::
+	The size in bytes of the commit or tag message.
+
+contents:subject::
+	The first paragraph of the message, which typically is a
+	single line, is taken as the "subject" of the commit or the
+	tag message.
+	Instead of `contents:subject`, field `subject` can also be used to
+	obtain same results. `:sanitize` can be appended to `subject` for
+	subject line suitable for filename.
+
+contents:body::
+	The remainder of the commit or the tag message that follows
+	the "subject".
+
+contents:signature::
+	The optional GPG signature of the tag.
+
+contents:lines=N::
+	The first `N` lines of the message.
+
 Additionally, the trailers as interpreted by linkgit:git-interpret-trailers[1]
 are obtained as `trailers` (or by using the historical alias
 `contents:trailers`).  Non-trailer lines from the trailer block can be omitted
diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt
index f71db0d..44fe886 100644
--- a/Documentation/git-help.txt
+++ b/Documentation/git-help.txt
@@ -8,7 +8,7 @@
 SYNOPSIS
 --------
 [verse]
-'git help' [-a|--all [--[no-]verbose]] [-g|--guide]
+'git help' [-a|--all [--[no-]verbose]] [-g|--guides]
 	   [-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE]
 
 DESCRIPTION
@@ -21,8 +21,8 @@
 If the option `--all` or `-a` is given, all available commands are
 printed on the standard output.
 
-If the option `--guide` or `-g` is given, a list of the useful
-Git guides is also printed on the standard output.
+If the option `--guides` or `-g` is given, a list of the
+Git concept guides is also printed on the standard output.
 
 If a command, or a guide, is given, a manual page for that command or
 guide is brought up. The 'man' program is used by default for this
@@ -58,7 +58,7 @@
 
 -g::
 --guides::
-	Prints a list of useful guides on the standard output. This
+	Prints a list of the Git concept guides on the standard output. This
 	option overrides any given command or guide name.
 
 -i::
diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt
index 65b53fc..63cf498 100644
--- a/Documentation/git-imap-send.txt
+++ b/Documentation/git-imap-send.txt
@@ -51,17 +51,13 @@
 CONFIGURATION
 -------------
 
-To use the tool, imap.folder and either imap.tunnel or imap.host must be set
+To use the tool, `imap.folder` and either `imap.tunnel` or `imap.host` must be set
 to appropriate values.
 
-Variables
-~~~~~~~~~
-
 include::config/imap.txt[]
 
-Examples
-~~~~~~~~
-
+EXAMPLES
+--------
 Using tunnel mode:
 
 ..........................
@@ -89,14 +85,18 @@
     user = bob
     pass = p4ssw0rd
     port = 123
-    sslverify = false
+    ; sslVerify = false
 .........................
 
 
-EXAMPLES
---------
-To submit patches using GMail's IMAP interface, first, edit your ~/.gitconfig
-to specify your account settings:
+[NOTE]
+You may want to use `sslVerify=false`
+while troubleshooting, if you suspect that the reason you are
+having trouble connecting is because the certificate you use at
+the private server `example.com` you are trying to set up (or
+have set up) may not be verified correctly.
+
+Using Gmail's IMAP interface:
 
 ---------
 [imap]
@@ -104,17 +104,21 @@
 	host = imaps://imap.gmail.com
 	user = user@gmail.com
 	port = 993
-	sslverify = false
 ---------
 
-You might need to instead use: folder = "[Google Mail]/Drafts" if you get an error
+[NOTE]
+You might need to instead use: `folder = "[Google Mail]/Drafts"` if you get an error
 that the "Folder doesn't exist".
 
+[NOTE]
+If your Gmail account is set to another language than English, the name of the "Drafts"
+folder will be localized.
+
 Once the commits are ready to be sent, run the following command:
 
   $ git format-patch --cover-letter -M --stdout origin/master | git imap-send
 
-Just make sure to disable line wrapping in the email client (GMail's web
+Just make sure to disable line wrapping in the email client (Gmail's web
 interface will wrap lines no matter what, so you need to use a real
 IMAP client).
 
diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.txt
index 9316d9a..af0c262 100644
--- a/Documentation/git-index-pack.txt
+++ b/Documentation/git-index-pack.txt
@@ -100,12 +100,14 @@
 	value is set or outside a repository.
 +
 This option cannot be used with --stdin.
++
+include::object-format-disclaimer.txt[]
 
 NOTES
 -----
 
-Once the index has been created, the list of object names is sorted
-and the SHA-1 hash of that list is printed to stdout. If --stdin was
+Once the index has been created, the hash that goes into the name of
+the pack/idx file is printed to stdout. If --stdin was
 also used then this is prefixed by either "pack\t", or "keep\t" if a
 new .keep file was successfully created. This is useful to remove a
 .keep file used as a lock to prevent the race with 'git repack'
diff --git a/Documentation/git-init.txt b/Documentation/git-init.txt
index ddfe265..f35f70f 100644
--- a/Documentation/git-init.txt
+++ b/Documentation/git-init.txt
@@ -53,6 +53,8 @@
 
 Specify the given object format (hash algorithm) for the repository.  The valid
 values are 'sha1' and (if enabled) 'sha256'.  'sha1' is the default.
++
+include::object-format-disclaimer.txt[]
 
 --template=<template_directory>::
 
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 20e6d21..2b8ac5f 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -15,9 +15,12 @@
 -----------
 Shows the commit logs.
 
-The command takes options applicable to the `git rev-list`
+:git-log: 1
+include::rev-list-description.txt[]
+
+The command takes options applicable to the linkgit:git-rev-list[1]
 command to control what is shown and how, and options applicable to
-the `git diff-*` commands to control how the changes
+the linkgit:git-diff[1] command to control how the changes
 each commit introduces are shown.
 
 
@@ -111,8 +114,51 @@
 
 include::pretty-formats.txt[]
 
-COMMON DIFF OPTIONS
--------------------
+DIFF FORMATTING
+---------------
+
+By default, `git log` does not generate any diff output. The options
+below can be used to show the changes made by each commit.
+
+Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
+will never show a diff, even if a diff format like `--patch` is
+selected, nor will they match search options like `-S`. The exception is
+when `--first-parent` is in use, in which merges are treated like normal
+single-parent commits (this can be overridden by providing a
+combined-diff option or with `--no-diff-merges`).
+
+-c::
+	With this option, diff output for a merge commit
+	shows the differences from each of the parents to the merge result
+	simultaneously instead of showing pairwise diff between a parent
+	and the result one at a time. Furthermore, it lists only files
+	which were modified from all parents.
+
+--cc::
+	This flag implies the `-c` option and further compresses the
+	patch output by omitting uninteresting hunks whose contents in
+	the parents have only two variants and the merge result picks
+	one of them without modification.
+
+--combined-all-paths::
+	This flag causes combined diffs (used for merge commits) to
+	list the name of the file from all parents.  It thus only has
+	effect when -c or --cc are specified, and is likely only
+	useful if filename changes are detected (i.e. when either
+	rename or copy detection have been requested).
+
+-m::
+	This flag makes the merge commits show the full diff like
+	regular commits; for each merge parent, a separate log entry
+	and diff is generated. An exception is that only diff against
+	the first parent is shown when `--first-parent` option is given;
+	in that case, the output represents the changes the merge
+	brought _into_ the then-current branch.
+
+--diff-merges=off::
+--no-diff-merges::
+	Disable output of diffs for merge commits (default). Useful to
+	override `-m`, `-c`, or `--cc`.
 
 :git-log: 1
 include::diff-options.txt[]
diff --git a/Documentation/git-multi-pack-index.txt b/Documentation/git-multi-pack-index.txt
index 0c66194..eb0caa0 100644
--- a/Documentation/git-multi-pack-index.txt
+++ b/Documentation/git-multi-pack-index.txt
@@ -51,11 +51,12 @@
 	multi-pack-index, then divide by the total number of objects in
 	the pack and multiply by the pack size. We select packs with
 	expected size below the batch size until the set of packs have
-	total expected size at least the batch size. If the total size
-	does not reach the batch size, then do nothing. If a new pack-
-	file is created, rewrite the multi-pack-index to reference the
-	new pack-file. A later run of 'git multi-pack-index expire' will
-	delete the pack-files that were part of this batch.
+	total expected size at least the batch size, or all pack-files
+	are considered. If only one pack-file is selected, then do
+	nothing. If a new pack-file is created, rewrite the
+	multi-pack-index to reference the new pack-file. A later run of
+	'git multi-pack-index expire' will delete the pack-files that
+	were part of this batch.
 +
 If `repack.packKeptObjects` is `false`, then any pack-files with an
 associated `.keep` file will not be selected for the batch to repack.
diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt
index ced2e82..0a42006 100644
--- a/Documentation/git-notes.txt
+++ b/Documentation/git-notes.txt
@@ -223,7 +223,7 @@
 contains "files" whose paths are the object names for the objects
 they describe, with some directory separators included for performance
 reasons footnote:[Permitted pathnames have the form
-'ab'`/`'cd'`/`'ef'`/`'...'`/`'abcdef...': a sequence of directory
+'bf'`/`'fe'`/`'30'`/`'...'`/`'680d5a...': a sequence of directory
 names of two hexadecimal digits each followed by a filename with the
 rest of the object ID.].
 
diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt
index eaa2f2a..54d715e 100644
--- a/Documentation/git-pack-objects.txt
+++ b/Documentation/git-pack-objects.txt
@@ -270,15 +270,18 @@
 	This option specifies how missing objects are handled.
 +
 The form '--missing=error' requests that pack-objects stop with an error if
-a missing object is encountered.  This is the default action.
+a missing object is encountered.  If the repository is a partial clone, an
+attempt to fetch missing objects will be made before declaring them missing.
+This is the default action.
 +
 The form '--missing=allow-any' will allow object traversal to continue
-if a missing object is encountered.  Missing objects will silently be
-omitted from the results.
+if a missing object is encountered.  No fetch of a missing object will occur.
+Missing objects will silently be omitted from the results.
 +
 The form '--missing=allow-promisor' is like 'allow-any', but will only
 allow object traversal to continue for EXPECTED promisor missing objects.
-Unexpected missing object will raise an error.
+No fetch of a missing object will occur.  An unexpected missing object will
+raise an error.
 
 --exclude-promisor-objects::
 	Omit objects that are known to be in the promisor remote.  (This
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 374d248..38e1548 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -204,6 +204,7 @@
 -------------
 
 include::config/rebase.txt[]
+include::config/sequencer.txt[]
 
 OPTIONS
 -------
@@ -459,17 +460,38 @@
 See also INCOMPATIBLE OPTIONS below.
 
 --ignore-whitespace::
+	Ignore whitespace differences when trying to reconcile
+differences. Currently, each backend implements an approximation of
+this behavior:
++
+apply backend: When applying a patch, ignore changes in whitespace in
+context lines. Unfortunately, this means that if the "old" lines being
+replaced by the patch differ only in whitespace from the existing
+file, you will get a merge conflict instead of a successful patch
+application.
++
+merge backend: Treat lines with only whitespace changes as unchanged
+when merging. Unfortunately, this means that any patch hunks that were
+intended to modify whitespace and nothing else will be dropped, even
+if the other side had no changes that conflicted.
+
 --whitespace=<option>::
-	These flags are passed to the 'git apply' program
+	This flag is passed to the 'git apply' program
 	(see linkgit:git-apply[1]) that applies the patch.
 	Implies --apply.
 +
 See also INCOMPATIBLE OPTIONS below.
 
 --committer-date-is-author-date::
+	Instead of using the current time as the committer date, use
+	the author date of the commit being rebased as the committer
+	date. This option implies `--force-rebase`.
+
 --ignore-date::
-	These flags are passed to 'git am' to easily change the dates
-	of the rebased commits (see linkgit:git-am[1]).
+--reset-author-date::
+	Instead of using the author date of the original commit, use
+	the current time as the	author date of the rebased commit.  This
+	option implies `--force-rebase`.
 +
 See also INCOMPATIBLE OPTIONS below.
 
@@ -607,9 +629,6 @@
 The following options:
 
  * --apply
- * --committer-date-is-author-date
- * --ignore-date
- * --ignore-whitespace
  * --whitespace
  * -C
 
@@ -636,6 +655,9 @@
  * --preserve-merges and --signoff
  * --preserve-merges and --rebase-merges
  * --preserve-merges and --empty=
+ * --preserve-merges and --ignore-whitespace
+ * --preserve-merges and --committer-date-is-author-date
+ * --preserve-merges and --ignore-date
  * --keep-base and --onto
  * --keep-base and --root
  * --fork-point and --root
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index 025c911..5da6623 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -14,44 +14,8 @@
 DESCRIPTION
 -----------
 
-List commits that are reachable by following the `parent` links from the
-given commit(s), but exclude commits that are reachable from the one(s)
-given with a '{caret}' in front of them.  The output is given in reverse
-chronological order by default.
-
-You can think of this as a set operation.  Commits given on the command
-line form a set of commits that are reachable from any of them, and then
-commits reachable from any of the ones given with '{caret}' in front are
-subtracted from that set.  The remaining commits are what comes out in the
-command's output.  Various other options and paths parameters can be used
-to further limit the result.
-
-Thus, the following command:
-
------------------------------------------------------------------------
-	$ git rev-list foo bar ^baz
------------------------------------------------------------------------
-
-means "list all the commits which are reachable from 'foo' or 'bar', but
-not from 'baz'".
-
-A special notation "'<commit1>'..'<commit2>'" can be used as a
-short-hand for "{caret}'<commit1>' '<commit2>'". For example, either of
-the following may be used interchangeably:
-
------------------------------------------------------------------------
-	$ git rev-list origin..HEAD
-	$ git rev-list HEAD ^origin
------------------------------------------------------------------------
-
-Another special notation is "'<commit1>'...'<commit2>'" which is useful
-for merges.  The resulting set of commits is the symmetric difference
-between the two operands.  The following two commands are equivalent:
-
------------------------------------------------------------------------
-	$ git rev-list A B --not $(git merge-base --all A B)
-	$ git rev-list A...B
------------------------------------------------------------------------
+:git-rev-list: 1
+include::rev-list-description.txt[]
 
 'rev-list' is a very essential Git command, since it
 provides the ability to build and traverse commit ancestry graphs. For
diff --git a/Documentation/git-show-index.txt b/Documentation/git-show-index.txt
index 39b1d8e..e49318a 100644
--- a/Documentation/git-show-index.txt
+++ b/Documentation/git-show-index.txt
@@ -44,6 +44,8 @@
 	valid values are 'sha1' and (if enabled) 'sha256'.  The default is the
 	algorithm for the current repository (set by `extensions.objectFormat`), or
 	'sha1' if no value is set or outside a repository..
++
+include::object-format-disclaimer.txt[]
 
 GIT
 ---
diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt
index 3e737c2..d401234 100644
--- a/Documentation/git-update-ref.txt
+++ b/Documentation/git-update-ref.txt
@@ -148,12 +148,13 @@
 
 LOGGING UPDATES
 ---------------
-If config parameter "core.logAllRefUpdates" is true and the ref is one under
-"refs/heads/", "refs/remotes/", "refs/notes/", or the symbolic ref HEAD; or
-the file "$GIT_DIR/logs/<ref>" exists then `git update-ref` will append
-a line to the log file "$GIT_DIR/logs/<ref>" (dereferencing all
-symbolic refs before creating the log name) describing the change
-in ref value.  Log lines are formatted as:
+If config parameter "core.logAllRefUpdates" is true and the ref is one
+under "refs/heads/", "refs/remotes/", "refs/notes/", or a pseudoref
+like HEAD or ORIG_HEAD; or the file "$GIT_DIR/logs/<ref>" exists then
+`git update-ref` will append a line to the log file
+"$GIT_DIR/logs/<ref>" (dereferencing all symbolic refs before creating
+the log name) describing the change in ref value.  Log lines are
+formatted as:
 
     oldsha1 SP newsha1 SP committer LF
 
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 4796c3c..f70cda4 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -15,6 +15,7 @@
 'git worktree move' <worktree> <new-path>
 'git worktree prune' [-n] [-v] [--expire <expire>]
 'git worktree remove' [-f] <worktree>
+'git worktree repair' [<path>...]
 'git worktree unlock' <worktree>
 
 DESCRIPTION
@@ -25,8 +26,9 @@
 A git repository can support multiple working trees, allowing you to check
 out more than one branch at a time.  With `git worktree add` a new working
 tree is associated with the repository.  This new working tree is called a
-"linked working tree" as opposed to the "main working tree" prepared by "git
-init" or "git clone".  A repository has one main working tree (if it's not a
+"linked working tree" as opposed to the "main working tree" prepared by
+linkgit:git-init[1] or linkgit:git-clone[1].
+A repository has one main working tree (if it's not a
 bare repository) and zero or more linked working trees. When you are done
 with a linked working tree, remove it with `git worktree remove`.
 
@@ -48,10 +50,10 @@
 
 Create `<path>` and checkout `<commit-ish>` into it. The new working directory
 is linked to the current repository, sharing everything except working
-directory specific files such as HEAD, index, etc. `-` may also be
-specified as `<commit-ish>`; it is synonymous with `@{-1}`.
+directory specific files such as `HEAD`, `index`, etc. As a convenience,
+`<commit-ish>` may be a bare "`-`", which is synonymous with `@{-1}`.
 +
-If <commit-ish> is a branch name (call it `<branch>`) and is not found,
+If `<commit-ish>` is a branch name (call it `<branch>`) and is not found,
 and neither `-b` nor `-B` nor `--detach` are used, but there does
 exist a tracking branch in exactly one remote (call it `<remote>`)
 with a matching name, treat as equivalent to:
@@ -66,24 +68,24 @@
 unique across all remotes. Set it to
 e.g. `checkout.defaultRemote=origin` to always checkout remote
 branches from there if `<branch>` is ambiguous but exists on the
-'origin' remote. See also `checkout.defaultRemote` in
+`origin` remote. See also `checkout.defaultRemote` in
 linkgit:git-config[1].
 +
 If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
-then, as a convenience, the new worktree is associated with a branch
+then, as a convenience, the new working tree is associated with a branch
 (call it `<branch>`) named after `$(basename <path>)`.  If `<branch>`
-doesn't exist, a new branch based on HEAD is automatically created as
+doesn't exist, a new branch based on `HEAD` is automatically created as
 if `-b <branch>` was given.  If `<branch>` does exist, it will be
-checked out in the new worktree, if it's not checked out anywhere
-else, otherwise the command will refuse to create the worktree (unless
+checked out in the new working tree, if it's not checked out anywhere
+else, otherwise the command will refuse to create the working tree (unless
 `--force` is used).
 
 list::
 
-List details of each worktree.  The main worktree is listed first, followed by
-each of the linked worktrees.  The output details include if the worktree is
-bare, the revision currently checked out, and the branch currently checked out
-(or 'detached HEAD' if none).
+List details of each working tree.  The main working tree is listed first,
+followed by each of the linked working trees.  The output details include
+whether the working tree is bare, the revision currently checked out, and the
+branch currently checked out (or "detached HEAD" if none).
 
 lock::
 
@@ -96,11 +98,14 @@
 move::
 
 Move a working tree to a new location. Note that the main working tree
-or linked working trees containing submodules cannot be moved.
+or linked working trees containing submodules cannot be moved with this
+command. (The `git worktree repair` command, however, can reestablish
+the connection with linked working trees if you move the main working
+tree manually.)
 
 prune::
 
-Prune working tree information in $GIT_DIR/worktrees.
+Prune working tree information in `$GIT_DIR/worktrees`.
 
 remove::
 
@@ -109,6 +114,23 @@
 trees or ones with submodules can be removed with `--force`. The main
 working tree cannot be removed.
 
+repair [<path>...]::
+
+Repair working tree administrative files, if possible, if they have
+become corrupted or outdated due to external factors.
++
+For instance, if the main working tree (or bare repository) is moved,
+linked working trees will be unable to locate it. Running `repair` in
+the main working tree will reestablish the connection from linked
+working trees back to the main working tree.
++
+Similarly, if a linked working tree is moved without using `git worktree
+move`, the main working tree (or bare repository) will be unable to
+locate it. Running `repair` within the recently-moved working tree will
+reestablish the connection. If multiple linked working trees are moved,
+running `repair` from any working tree with each tree's new `<path>` as
+an argument, will reestablish the connection to all the specified paths.
+
 unlock::
 
 Unlock a working tree, allowing it to be pruned, moved or deleted.
@@ -128,7 +150,7 @@
 `move` refuses to move a locked working tree unless `--force` is specified
 twice. If the destination is already assigned to some other working tree but is
 missing (for instance, if `<new-path>` was deleted manually), then `--force`
-allows the move to proceed; use --force twice if the destination is locked.
+allows the move to proceed; use `--force` twice if the destination is locked.
 +
 `remove` refuses to remove an unclean working tree unless `--force` is used.
 To remove a locked working tree, specify `--force` twice.
@@ -137,13 +159,13 @@
 -B <new-branch>::
 	With `add`, create a new branch named `<new-branch>` starting at
 	`<commit-ish>`, and check out `<new-branch>` into the new working tree.
-	If `<commit-ish>` is omitted, it defaults to HEAD.
+	If `<commit-ish>` is omitted, it defaults to `HEAD`.
 	By default, `-b` refuses to create a new branch if it already
 	exists. `-B` overrides this safeguard, resetting `<new-branch>` to
 	`<commit-ish>`.
 
 --detach::
-	With `add`, detach HEAD in the new working tree. See "DETACHED HEAD"
+	With `add`, detach `HEAD` in the new working tree. See "DETACHED HEAD"
 	in linkgit:git-checkout[1].
 
 --[no-]checkout::
@@ -154,7 +176,7 @@
 
 --[no-]guess-remote::
 	With `worktree add <path>`, without `<commit-ish>`, instead
-	of creating a new branch from HEAD, if there exists a tracking
+	of creating a new branch from `HEAD`, if there exists a tracking
 	branch in exactly one remote matching the basename of `<path>`,
 	base the new branch on the remote-tracking branch, and mark
 	the remote-tracking branch as "upstream" from the new branch.
@@ -166,12 +188,12 @@
 	When creating a new branch, if `<commit-ish>` is a branch,
 	mark it as "upstream" from the new branch.  This is the
 	default if `<commit-ish>` is a remote-tracking branch.  See
-	"--track" in linkgit:git-branch[1] for details.
+	`--track` in linkgit:git-branch[1] for details.
 
 --lock::
 	Keep the working tree locked after creation. This is the
 	equivalent of `git worktree lock` after `git worktree add`,
-	but without race condition.
+	but without a race condition.
 
 -n::
 --dry-run::
@@ -185,14 +207,14 @@
 
 -q::
 --quiet::
-	With 'add', suppress feedback messages.
+	With `add`, suppress feedback messages.
 
 -v::
 --verbose::
 	With `prune`, report all removals.
 
 --expire <time>::
-	With `prune`, only expire unused working trees older than <time>.
+	With `prune`, only expire unused working trees older than `<time>`.
 
 --reason <string>::
 	With `lock`, an explanation why the working tree is locked.
@@ -202,48 +224,48 @@
 	absolute.
 +
 If the last path components in the working tree's path is unique among
-working trees, it can be used to identify worktrees. For example if
-you only have two working trees, at "/abc/def/ghi" and "/abc/def/ggg",
-then "ghi" or "def/ghi" is enough to point to the former working tree.
+working trees, it can be used to identify a working tree. For example if
+you only have two working trees, at `/abc/def/ghi` and `/abc/def/ggg`,
+then `ghi` or `def/ghi` is enough to point to the former working tree.
 
 REFS
 ----
 In multiple working trees, some refs may be shared between all working
-trees, some refs are local. One example is HEAD is different for all
-working trees. This section is about the sharing rules and how to access
+trees and some refs are local. One example is `HEAD` which is different for each
+working tree. This section is about the sharing rules and how to access
 refs of one working tree from another.
 
 In general, all pseudo refs are per working tree and all refs starting
-with "refs/" are shared. Pseudo refs are ones like HEAD which are
-directly under GIT_DIR instead of inside GIT_DIR/refs. There is one
-exception to this: refs inside refs/bisect and refs/worktree is not
+with `refs/` are shared. Pseudo refs are ones like `HEAD` which are
+directly under `$GIT_DIR` instead of inside `$GIT_DIR/refs`. There are
+exceptions, however: refs inside `refs/bisect` and `refs/worktree` are not
 shared.
 
 Refs that are per working tree can still be accessed from another
-working tree via two special paths, main-worktree and worktrees. The
-former gives access to per-worktree refs of the main working tree,
+working tree via two special paths, `main-worktree` and `worktrees`. The
+former gives access to per-working tree refs of the main working tree,
 while the latter to all linked working trees.
 
-For example, main-worktree/HEAD or main-worktree/refs/bisect/good
-resolve to the same value as the main working tree's HEAD and
-refs/bisect/good respectively. Similarly, worktrees/foo/HEAD or
-worktrees/bar/refs/bisect/bad are the same as
-GIT_COMMON_DIR/worktrees/foo/HEAD and
-GIT_COMMON_DIR/worktrees/bar/refs/bisect/bad.
+For example, `main-worktree/HEAD` or `main-worktree/refs/bisect/good`
+resolve to the same value as the main working tree's `HEAD` and
+`refs/bisect/good` respectively. Similarly, `worktrees/foo/HEAD` or
+`worktrees/bar/refs/bisect/bad` are the same as
+`$GIT_COMMON_DIR/worktrees/foo/HEAD` and
+`$GIT_COMMON_DIR/worktrees/bar/refs/bisect/bad`.
 
-To access refs, it's best not to look inside GIT_DIR directly. Instead
+To access refs, it's best not to look inside `$GIT_DIR` directly. Instead
 use commands such as linkgit:git-rev-parse[1] or linkgit:git-update-ref[1]
 which will handle refs correctly.
 
 CONFIGURATION FILE
 ------------------
-By default, the repository "config" file is shared across all working
+By default, the repository `config` file is shared across all working
 trees. If the config variables `core.bare` or `core.worktree` are
 already present in the config file, they will be applied to the main
 working trees only.
 
 In order to have configuration specific to working trees, you can turn
-on "worktreeConfig" extension, e.g.:
+on the `worktreeConfig` extension, e.g.:
 
 ------------
 $ git config extensions.worktreeConfig true
@@ -255,7 +277,7 @@
 versions will refuse to access repositories with this extension.
 
 Note that in this file, the exception for `core.bare` and `core.worktree`
-is gone. If you have them in $GIT_DIR/config before, you must move
+is gone. If they exist in `$GIT_DIR/config`, you must move
 them to the `config.worktree` of the main working tree. You may also
 take this opportunity to review and move other configuration that you
 do not want to share to all working trees:
@@ -268,7 +290,7 @@
 DETAILS
 -------
 Each linked working tree has a private sub-directory in the repository's
-$GIT_DIR/worktrees directory.  The private sub-directory's name is usually
+`$GIT_DIR/worktrees` directory.  The private sub-directory's name is usually
 the base name of the linked working tree's path, possibly appended with a
 number to make it unique.  For example, when `$GIT_DIR=/path/main/.git` the
 command `git worktree add /path/other/test-next next` creates the linked
@@ -276,51 +298,52 @@
 `$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1`
 if `test-next` is already taken).
 
-Within a linked working tree, $GIT_DIR is set to point to this private
+Within a linked working tree, `$GIT_DIR` is set to point to this private
 directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and
-$GIT_COMMON_DIR is set to point back to the main working tree's $GIT_DIR
+`$GIT_COMMON_DIR` is set to point back to the main working tree's `$GIT_DIR`
 (e.g. `/path/main/.git`). These settings are made in a `.git` file located at
 the top directory of the linked working tree.
 
 Path resolution via `git rev-parse --git-path` uses either
-$GIT_DIR or $GIT_COMMON_DIR depending on the path. For example, in the
+`$GIT_DIR` or `$GIT_COMMON_DIR` depending on the path. For example, in the
 linked working tree `git rev-parse --git-path HEAD` returns
 `/path/main/.git/worktrees/test-next/HEAD` (not
 `/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git
 rev-parse --git-path refs/heads/master` uses
-$GIT_COMMON_DIR and returns `/path/main/.git/refs/heads/master`,
-since refs are shared across all working trees, except refs/bisect and
-refs/worktree.
+`$GIT_COMMON_DIR` and returns `/path/main/.git/refs/heads/master`,
+since refs are shared across all working trees, except `refs/bisect` and
+`refs/worktree`.
 
 See linkgit:gitrepository-layout[5] for more information. The rule of
 thumb is do not make any assumption about whether a path belongs to
-$GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
-inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
+`$GIT_DIR` or `$GIT_COMMON_DIR` when you need to directly access something
+inside `$GIT_DIR`. Use `git rev-parse --git-path` to get the final path.
 
-If you manually move a linked working tree, you need to update the 'gitdir' file
+If you manually move a linked working tree, you need to update the `gitdir` file
 in the entry's directory. For example, if a linked working tree is moved
 to `/newpath/test-next` and its `.git` file points to
 `/path/main/.git/worktrees/test-next`, then update
 `/path/main/.git/worktrees/test-next/gitdir` to reference `/newpath/test-next`
-instead.
+instead. Better yet, run `git worktree repair` to reestablish the connection
+automatically.
 
-To prevent a $GIT_DIR/worktrees entry from being pruned (which
+To prevent a `$GIT_DIR/worktrees` entry from being pruned (which
 can be useful in some situations, such as when the
 entry's working tree is stored on a portable device), use the
 `git worktree lock` command, which adds a file named
-'locked' to the entry's directory. The file contains the reason in
+`locked` to the entry's directory. The file contains the reason in
 plain text. For example, if a linked working tree's `.git` file points
 to `/path/main/.git/worktrees/test-next` then a file named
 `/path/main/.git/worktrees/test-next/locked` will prevent the
 `test-next` entry from being pruned.  See
 linkgit:gitrepository-layout[5] for details.
 
-When extensions.worktreeConfig is enabled, the config file
+When `extensions.worktreeConfig` is enabled, the config file
 `.git/worktrees/<id>/config.worktree` is read after `.git/config` is.
 
 LIST OUTPUT FORMAT
 ------------------
-The worktree list command has two output formats.  The default format shows the
+The `worktree list` command has two output formats. The default format shows the
 details on a single line with columns.  For example:
 
 ------------
@@ -333,10 +356,10 @@
 Porcelain Format
 ~~~~~~~~~~~~~~~~
 The porcelain format has a line per attribute.  Attributes are listed with a
-label and value separated by a single space.  Boolean attributes (like 'bare'
-and 'detached') are listed as a label only, and are only present if and only
-if the value is true.  The first attribute of a worktree is always `worktree`,
-an empty line indicates the end of the record.  For example:
+label and value separated by a single space.  Boolean attributes (like `bare`
+and `detached`) are listed as a label only, and are present only
+if the value is true.  The first attribute of a working tree is always
+`worktree`, an empty line indicates the end of the record.  For example:
 
 ------------
 $ git worktree list --porcelain
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 3e50065..2f72b10 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -304,6 +304,13 @@
 
 include::cmds-purehelpers.txt[]
 
+Guides
+------
+
+The following documentation pages are guides about Git concepts.
+
+include::cmds-guide.txt[]
+
 
 Configuration Mechanism
 -----------------------
@@ -497,7 +504,8 @@
 	If this variable is set, the default hash algorithm for new
 	repositories will be set to this value. This value is currently
 	ignored when cloning; the setting of the remote repository
-	is used instead. The default is "sha1".
+	is used instead. The default is "sha1". THIS VARIABLE IS
+	EXPERIMENTAL! See `--object-format` in linkgit:git-init[1].
 
 Git Commits
 ~~~~~~~~~~~
@@ -543,8 +551,9 @@
 
 `GIT_EXTERNAL_DIFF`::
 	When the environment variable `GIT_EXTERNAL_DIFF` is set, the
-	program named by it is called, instead of the diff invocation
-	described above.  For a path that is added, removed, or modified,
+	program named by it is called to generate diffs, and Git
+	does not use its builtin diff machinery.
+	For a path that is added, removed, or modified,
 	`GIT_EXTERNAL_DIFF` is called with 7 parameters:
 
 	path old-file old-hex old-mode new-file new-hex new-mode
@@ -597,6 +606,12 @@
 	an editor is to be launched. See also linkgit:git-var[1]
 	and the `core.editor` option in linkgit:git-config[1].
 
+`GIT_SEQUENCE_EDITOR`::
+	This environment variable overrides the configured Git editor
+	when editing the todo list of an interactive rebase. See also
+	linkit::git-rebase[1] and the `sequence.editor` option in
+	linkit::git-config[1].
+
 `GIT_SSH`::
 `GIT_SSH_COMMAND`::
 	If either of these environment variables is set then 'git fetch'
diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt
index 9e481ae..758bf39 100644
--- a/Documentation/gitcredentials.txt
+++ b/Documentation/gitcredentials.txt
@@ -3,7 +3,7 @@
 
 NAME
 ----
-gitcredentials - providing usernames and passwords to Git
+gitcredentials - Providing usernames and passwords to Git
 
 SYNOPSIS
 --------
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index 31b601e..cf95d6d 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -193,7 +193,9 @@
 the ref of the new HEAD (which may or may not have changed), and a flag
 indicating whether the checkout was a branch checkout (changing branches,
 flag=1) or a file checkout (retrieving a file from the index, flag=0).
-This hook cannot affect the outcome of `git switch` or `git checkout`.
+This hook cannot affect the outcome of `git switch` or `git checkout`,
+other than that the hook's exit status becomes the exit status of
+these two commands.
 
 It is also run after linkgit:git-clone[1], unless the `--no-checkout` (`-n`) option is
 used. The first parameter given to the hook is the null-ref, the second the
diff --git a/Documentation/object-format-disclaimer.txt b/Documentation/object-format-disclaimer.txt
new file mode 100644
index 0000000..4cb106f
--- /dev/null
+++ b/Documentation/object-format-disclaimer.txt
@@ -0,0 +1,6 @@
+THIS OPTION IS EXPERIMENTAL! SHA-256 support is experimental and still
+in an early stage.  A SHA-256 repository will in general not be able to
+share work with "regular" SHA-1 repositories.  It should be assumed
+that, e.g., Git internal file formats in relation to SHA-256
+repositories may change in backwards-incompatible ways.  Only use
+`--object-format=sha256` for testing purposes.
diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt
index 7a6da6d..17c5aac 100644
--- a/Documentation/pretty-options.txt
+++ b/Documentation/pretty-options.txt
@@ -25,8 +25,8 @@
 
 --no-abbrev-commit::
 	Show the full 40-byte hexadecimal commit object name. This negates
-	`--abbrev-commit` and those options which imply it such as
-	"--oneline". It also overrides the `log.abbrevCommit` variable.
+	`--abbrev-commit`, either explicit or implied by other options such
+	as "--oneline". It also overrides the `log.abbrevCommit` variable.
 
 --oneline::
 	This is a shorthand for "--pretty=oneline --abbrev-commit"
diff --git a/Documentation/rev-list-description.txt b/Documentation/rev-list-description.txt
new file mode 100644
index 0000000..a9efa7f
--- /dev/null
+++ b/Documentation/rev-list-description.txt
@@ -0,0 +1,61 @@
+List commits that are reachable by following the `parent` links from the
+given commit(s), but exclude commits that are reachable from the one(s)
+given with a '{caret}' in front of them.  The output is given in reverse
+chronological order by default.
+
+You can think of this as a set operation. Commits reachable from any of
+the commits given on the command line form a set, and then commits reachable
+from any of the ones given with '{caret}' in front are subtracted from that
+set.  The remaining commits are what comes out in the command's output.
+Various other options and paths parameters can be used to further limit the
+result.
+
+Thus, the following command:
+
+ifdef::git-rev-list[]
+-----------------------------------------------------------------------
+$ git rev-list foo bar ^baz
+-----------------------------------------------------------------------
+endif::git-rev-list[]
+ifdef::git-log[]
+-----------------------------------------------------------------------
+$ git log foo bar ^baz
+-----------------------------------------------------------------------
+endif::git-log[]
+
+means "list all the commits which are reachable from 'foo' or 'bar', but
+not from 'baz'".
+
+A special notation "'<commit1>'..'<commit2>'" can be used as a
+short-hand for "^'<commit1>' '<commit2>'". For example, either of
+the following may be used interchangeably:
+
+ifdef::git-rev-list[]
+-----------------------------------------------------------------------
+$ git rev-list origin..HEAD
+$ git rev-list HEAD ^origin
+-----------------------------------------------------------------------
+endif::git-rev-list[]
+ifdef::git-log[]
+-----------------------------------------------------------------------
+$ git log origin..HEAD
+$ git log HEAD ^origin
+-----------------------------------------------------------------------
+endif::git-log[]
+
+Another special notation is "'<commit1>'...'<commit2>'" which is useful
+for merges.  The resulting set of commits is the symmetric difference
+between the two operands.  The following two commands are equivalent:
+
+ifdef::git-rev-list[]
+-----------------------------------------------------------------------
+$ git rev-list A B --not $(git merge-base --all A B)
+$ git rev-list A...B
+-----------------------------------------------------------------------
+endif::git-rev-list[]
+ifdef::git-log[]
+-----------------------------------------------------------------------
+$ git log A B --not $(git merge-base --all A B)
+$ git log A...B
+-----------------------------------------------------------------------
+endif::git-log[]
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index b01b2b6..0023790 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -128,8 +128,7 @@
 	because merges into a topic branch tend to be only about
 	adjusting to updated upstream from time to time, and
 	this option allows you to ignore the individual commits
-	brought in to your history by such a merge. Cannot be
-	combined with --bisect.
+	brought in to your history by such a merge.
 
 --not::
 	Reverses the meaning of the '{caret}' prefix (or lack thereof)
@@ -207,7 +206,7 @@
 	Pretend as if the bad bisection ref `refs/bisect/bad`
 	was listed and as if it was followed by `--not` and the good
 	bisection refs `refs/bisect/good-*` on the command
-	line. Cannot be combined with --first-parent.
+	line.
 endif::git-rev-list[]
 
 --stdin::
@@ -743,7 +742,7 @@
 would be of roughly the same length.  Finding the change which
 introduces a regression is thus reduced to a binary search: repeatedly
 generate and test new 'midpoint's until the commit chain is of length
-one. Cannot be combined with --first-parent.
+one.
 
 --bisect-vars::
 	This calculates the same as `--bisect`, except that refs in
@@ -1117,48 +1116,3 @@
 	by a tab.
 endif::git-rev-list[]
 endif::git-shortlog[]
-
-ifndef::git-shortlog[]
-ifndef::git-rev-list[]
-Diff Formatting
-~~~~~~~~~~~~~~~
-
-Listed below are options that control the formatting of diff output.
-Some of them are specific to linkgit:git-rev-list[1], however other diff
-options may be given. See linkgit:git-diff-files[1] for more options.
-
--c::
-	With this option, diff output for a merge commit
-	shows the differences from each of the parents to the merge result
-	simultaneously instead of showing pairwise diff between a parent
-	and the result one at a time. Furthermore, it lists only files
-	which were modified from all parents.
-
---cc::
-	This flag implies the `-c` option and further compresses the
-	patch output by omitting uninteresting hunks whose contents in
-	the parents have only two variants and the merge result picks
-	one of them without modification.
-
---combined-all-paths::
-	This flag causes combined diffs (used for merge commits) to
-	list the name of the file from all parents.  It thus only has
-	effect when -c or --cc are specified, and is likely only
-	useful if filename changes are detected (i.e. when either
-	rename or copy detection have been requested).
-
--m::
-	This flag makes the merge commits show the full diff like
-	regular commits; for each merge parent, a separate log entry
-	and diff is generated. An exception is that only diff against
-	the first parent is shown when `--first-parent` option is given;
-	in that case, the output represents the changes the merge
-	brought _into_ the then-current branch.
-
--r::
-	Show recursive diffs.
-
--t::
-	Show the tree objects in the diff output. This implies `-r`.
-endif::git-rev-list[]
-endif::git-shortlog[]
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index 1ad9506..d9169c0 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -254,6 +254,9 @@
 previous section, means the set of commits `reachable` from the given
 commit.
 
+Specifying several revisions means the set of commits reachable from
+any of the given commits.
+
 A commit's reachable set is the commit itself and the commits in
 its ancestry chain.
 
diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index 2e2e7c1..5a60bbf 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -232,9 +232,9 @@
 	will be overwritten, so this should only be used for options where
 	the last one specified on the command line wins.
 
-`OPT_PASSTHRU_ARGV(short, long, &argv_array_var, arg_str, description, flags)`::
+`OPT_PASSTHRU_ARGV(short, long, &strvec_var, arg_str, description, flags)`::
 	Introduce an option where all instances of it on the command-line will
-	be reconstructed into an argv_array. This is useful when you need to
+	be reconstructed into a strvec. This is useful when you need to
 	pass the command-line option, which can be specified multiple times,
 	to another command.
 
diff --git a/Documentation/technical/bundle-format.txt b/Documentation/technical/bundle-format.txt
index 0e82815..bac558d 100644
--- a/Documentation/technical/bundle-format.txt
+++ b/Documentation/technical/bundle-format.txt
@@ -7,6 +7,8 @@
 We will use ABNF notation to define the Git bundle format. See
 protocol-common.txt for the details.
 
+A v2 bundle looks like this:
+
 ----
 bundle    = signature *prerequisite *reference LF pack
 signature = "# v2 git bundle" LF
@@ -18,9 +20,28 @@
 pack         = ... ; packfile
 ----
 
+A v3 bundle looks like this:
+
+----
+bundle    = signature *capability *prerequisite *reference LF pack
+signature = "# v3 git bundle" LF
+
+capability   = "@" key ["=" value] LF
+prerequisite = "-" obj-id SP comment LF
+comment      = *CHAR
+reference    = obj-id SP refname LF
+key          = 1*(ALPHA / DIGIT / "-")
+value        = *(%01-09 / %0b-FF)
+
+pack         = ... ; packfile
+----
+
 == Semantics
 
-A Git bundle consists of three parts.
+A Git bundle consists of several parts.
+
+* "Capabilities", which are only in the v3 format, indicate functionality that
+	the bundle requires to be read properly.
 
 * "Prerequisites" lists the objects that are NOT included in the bundle and the
   reader of the bundle MUST already have, in order to use the data in the
@@ -46,3 +67,10 @@
 Note that the prerequisites does not represent a shallow-clone boundary. The
 semantics of the prerequisites and the shallow-clone boundaries are different,
 and the Git bundle v2 format cannot represent a shallow clone repository.
+
+== Capabilities
+
+Because there is no opportunity for negotiation, unknown capabilities cause 'git
+bundle' to abort.  The only known capability is `object-format`, which specifies
+the hash algorithm in use, and can take the same values as the
+`extensions.objectFormat` configuration value.
diff --git a/Documentation/technical/commit-graph-format.txt b/Documentation/technical/commit-graph-format.txt
index 1beef17..6ddbceb 100644
--- a/Documentation/technical/commit-graph-format.txt
+++ b/Documentation/technical/commit-graph-format.txt
@@ -32,7 +32,7 @@
 of the body. The header includes certain values, such as number of chunks
 and hash type.
 
-All 4-byte numbers are in network order.
+All multi-byte numbers are in network byte order.
 
 HEADER:
 
@@ -42,8 +42,13 @@
   1-byte version number:
       Currently, the only valid version is 1.
 
-  1-byte Hash Version (1 = SHA-1)
-      We infer the hash length (H) from this value.
+  1-byte Hash Version
+      We infer the hash length (H) from this value:
+	1 => SHA-1
+	2 => SHA-256
+      If the hash type does not match the repository's hash algorithm, the
+      commit-graph file should be ignored with a warning presented to the
+      user.
 
   1-byte number (C) of "chunks"
 
diff --git a/Documentation/technical/commit-graph.txt b/Documentation/technical/commit-graph.txt
index 808fa30..f14a765 100644
--- a/Documentation/technical/commit-graph.txt
+++ b/Documentation/technical/commit-graph.txt
@@ -210,12 +210,12 @@
 			    +---------------------+
 			    |                     |
  +-----------------------+  +---------------------+
- |  graph-{hash2} |->|                     |
+ |  graph-{hash2}        |->|                     |
  +-----------------------+  +---------------------+
 	  |                 |                     |
  +-----------------------+  +---------------------+
  |                       |  |                     |
- |  graph-{hash1} |->|                     |
+ |  graph-{hash1}        |->|                     |
  |                       |  |                     |
  +-----------------------+  +---------------------+
 	  |                  tmp_graphXXX
@@ -223,7 +223,7 @@
  |                       |
  |                       |
  |                       |
- |  graph-{hash0} |
+ |  graph-{hash0}        |
  |                       |
  |                       |
  |                       |
diff --git a/Documentation/technical/hash-function-transition.txt b/Documentation/technical/hash-function-transition.txt
index 5b2db3b..6fd20eb 100644
--- a/Documentation/technical/hash-function-transition.txt
+++ b/Documentation/technical/hash-function-transition.txt
@@ -650,7 +650,6 @@
 
 The first user-visible change is the introduction of the objectFormat
 extension (without compatObjectFormat). This requires:
-- implementing the loose-object-idx
 - teaching fsck about this mode of operation
 - using the hash function API (vtable) when computing object names
 - signing objects and verifying signatures
@@ -658,6 +657,7 @@
   repository
 
 Next comes introduction of compatObjectFormat:
+- implementing the loose-object-idx
 - translating object names between object formats
 - translating object content between object formats
 - generating and verifying signatures in the compat format
diff --git a/Documentation/technical/http-protocol.txt b/Documentation/technical/http-protocol.txt
index 51a79e6..96d89ea 100644
--- a/Documentation/technical/http-protocol.txt
+++ b/Documentation/technical/http-protocol.txt
@@ -401,8 +401,9 @@
 The stream is terminated by a pkt-line flush (`0000`).
 
 A single "want" or "have" command MUST have one hex formatted
-SHA-1 as its value.  Multiple SHA-1s MUST be sent by sending
-multiple commands.
+object name as its value.  Multiple object names MUST be sent by sending
+multiple commands. Object names MUST be given using the object format
+negotiated through the `object-format` capability (default SHA-1).
 
 The `have` list is created by popping the first 32 commits
 from `c_pending`.  Less can be supplied if `c_pending` empties.
diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt
index faa25c5..f9a3644 100644
--- a/Documentation/technical/index-format.txt
+++ b/Documentation/technical/index-format.txt
@@ -3,8 +3,11 @@
 
 == The Git index file has the following format
 
-  All binary numbers are in network byte order. Version 2 is described
-  here unless stated otherwise.
+  All binary numbers are in network byte order.
+  In a repository using the traditional SHA-1, checksums and object IDs
+  (object names) mentioned below are all computed using SHA-1.  Similarly,
+  in SHA-256 repositories, these values are computed using SHA-256.
+  Version 2 is described here unless stated otherwise.
 
    - A 12-byte header consisting of
 
@@ -32,8 +35,7 @@
 
      Extension data
 
-   - 160-bit SHA-1 over the content of the index file before this
-     checksum.
+   - Hash checksum over the content of the index file before this checksum.
 
 == Index entry
 
@@ -80,7 +82,7 @@
   32-bit file size
     This is the on-disk size from stat(2), truncated to 32-bit.
 
-  160-bit SHA-1 for the represented object
+  Object name for the represented object
 
   A 16-bit 'flags' field split into (high to low bits)
 
@@ -160,8 +162,8 @@
 
   - A newline (ASCII 10); and
 
-  - 160-bit object name for the object that would result from writing
-    this span of index as a tree.
+  - Object name for the object that would result from writing this span
+    of index as a tree.
 
   An entry can be in an invalidated state and is represented by having
   a negative number in the entry_count field. In this case, there is no
@@ -198,7 +200,7 @@
     stage 1 to 3 (a missing stage is represented by "0" in this field);
     and
 
-  - At most three 160-bit object names of the entry in stages from 1 to 3
+  - At most three object names of the entry in stages from 1 to 3
     (nothing is written for a missing stage).
 
 === Split index
@@ -211,8 +213,8 @@
 
   The extension consists of:
 
-  - 160-bit SHA-1 of the shared index file. The shared index file path
-    is $GIT_DIR/sharedindex.<SHA-1>. If all 160 bits are zero, the
+  - Hash of the shared index file. The shared index file path
+    is $GIT_DIR/sharedindex.<hash>. If all bits are zero, the
     index does not require a shared index file.
 
   - An ewah-encoded delete bitmap, each bit represents an entry in the
@@ -253,10 +255,10 @@
 
   - 32-bit dir_flags (see struct dir_struct)
 
-  - 160-bit SHA-1 of $GIT_DIR/info/exclude. Null SHA-1 means the file
+  - Hash of $GIT_DIR/info/exclude. A null hash means the file
     does not exist.
 
-  - 160-bit SHA-1 of core.excludesfile. Null SHA-1 means the file does
+  - Hash of core.excludesfile. A null hash means the file does
     not exist.
 
   - NUL-terminated string of per-dir exclude file name. This usually
@@ -285,13 +287,13 @@
   - An ewah bitmap, the n-th bit records "check-only" bit of
     read_directory_recursive() for the n-th directory.
 
-  - An ewah bitmap, the n-th bit indicates whether SHA-1 and stat data
+  - An ewah bitmap, the n-th bit indicates whether hash and stat data
     is valid for the n-th directory and exists in the next data.
 
   - An array of stat data. The n-th data corresponds with the n-th
     "one" bit in the previous ewah bitmap.
 
-  - An array of SHA-1. The n-th SHA-1 corresponds with the n-th "one" bit
+  - An array of hashes. The n-th hash corresponds with the n-th "one" bit
     in the previous ewah bitmap.
 
   - One NUL.
@@ -330,12 +332,12 @@
 
   - 32-bit offset to the end of the index entries
 
-  - 160-bit SHA-1 over the extension types and their sizes (but not
+  - Hash over the extension types and their sizes (but not
 	their contents).  E.g. if we have "TREE" extension that is N-bytes
 	long, "REUC" extension that is M-bytes long, followed by "EOIE",
 	then the hash would be:
 
-	SHA-1("TREE" + <binary representation of N> +
+	Hash("TREE" + <binary representation of N> +
 		"REUC" + <binary representation of M>)
 
 == Index Entry Offset Table
diff --git a/Documentation/technical/pack-format.txt b/Documentation/technical/pack-format.txt
index d3a142c..f96b2e6 100644
--- a/Documentation/technical/pack-format.txt
+++ b/Documentation/technical/pack-format.txt
@@ -1,6 +1,12 @@
 Git pack format
 ===============
 
+== Checksums and object IDs
+
+In a repository using the traditional SHA-1, pack checksums, index checksums,
+and object IDs (object names) mentioned below are all computed using SHA-1.
+Similarly, in SHA-256 repositories, these values are computed using SHA-256.
+
 == pack-*.pack files have the following format:
 
    - A header appears at the beginning and consists of the following:
@@ -26,7 +32,7 @@
 
      (deltified representation)
      n-byte type and length (3-bit type, (n-1)*7+4-bit length)
-     20-byte base object name if OBJ_REF_DELTA or a negative relative
+     base object name if OBJ_REF_DELTA or a negative relative
 	 offset from the delta object's position in the pack if this
 	 is an OBJ_OFS_DELTA object
      compressed delta data
@@ -34,7 +40,7 @@
      Observation: length of each object is encoded in a variable
      length format and is not constrained to 32-bit or anything.
 
-  - The trailer records 20-byte SHA-1 checksum of all of the above.
+  - The trailer records a pack checksum of all of the above.
 
 === Object types
 
@@ -58,8 +64,8 @@
 
 Both ofs-delta and ref-delta store the "delta" to be applied to
 another object (called 'base object') to reconstruct the object. The
-difference between them is, ref-delta directly encodes 20-byte base
-object name. If the base object is in the same pack, ofs-delta encodes
+difference between them is, ref-delta directly encodes base object
+name. If the base object is in the same pack, ofs-delta encodes
 the offset of the base object in the pack instead.
 
 The base object could also be deltified if it's in the same pack.
@@ -143,14 +149,14 @@
     object is stored in the packfile as the offset from the
     beginning.
 
-    20-byte object name.
+    one object name of the appropriate size.
 
   - The file is concluded with a trailer:
 
-    A copy of the 20-byte SHA-1 checksum at the end of
-    corresponding packfile.
+    A copy of the pack checksum at the end of the corresponding
+    packfile.
 
-    20-byte SHA-1-checksum of all of the above.
+    Index checksum of all of the above.
 
 Pack Idx file:
 
@@ -198,7 +204,7 @@
         If it is not DELTA, then deflated bytes (the size above
 		is the size before compression).
 	If it is REF_DELTA, then
-	  20-byte base object name SHA-1 (the size above is the
+	  base object name (the size above is the
 		size of the delta data that follows).
           delta data, deflated.
 	If it is OFS_DELTA, then
@@ -227,9 +233,9 @@
 
   - A 256-entry fan-out table just like v1.
 
-  - A table of sorted 20-byte SHA-1 object names.  These are
-    packed together without offset values to reduce the cache
-    footprint of the binary search for a specific object name.
+  - A table of sorted object names.  These are packed together
+    without offset values to reduce the cache footprint of the
+    binary search for a specific object name.
 
   - A table of 4-byte CRC32 values of the packed object data.
     This is new in v2 so compressed data can be copied directly
@@ -248,10 +254,10 @@
 
   - The same trailer as a v1 pack file:
 
-    A copy of the 20-byte SHA-1 checksum at the end of
+    A copy of the pack checksum at the end of
     corresponding packfile.
 
-    20-byte SHA-1-checksum of all of the above.
+    Index checksum of all of the above.
 
 == multi-pack-index (MIDX) files have the following format:
 
@@ -273,7 +279,12 @@
 	    Git only writes or recognizes version 1.
 
 	1-byte Object Id Version
-	    Git only writes or recognizes version 1 (SHA1).
+	    We infer the length of object IDs (OIDs) from this value:
+		1 => SHA-1
+		2 => SHA-256
+	    If the hash type does not match the repository's hash algorithm,
+	    the multi-pack-index file should be ignored with a warning
+	    presented to the user.
 
 	1-byte number of "chunks"
 
@@ -329,4 +340,4 @@
 
 TRAILER:
 
-	20-byte SHA1-checksum of the above contents.
+	Index checksum of the above contents.
diff --git a/Documentation/technical/partial-clone.txt b/Documentation/technical/partial-clone.txt
index b9e17e7..0780d30 100644
--- a/Documentation/technical/partial-clone.txt
+++ b/Documentation/technical/partial-clone.txt
@@ -171,20 +171,13 @@
 Fetching Missing Objects
 ------------------------
 
-- Fetching of objects is done using the existing transport mechanism using
-  transport_fetch_refs(), setting a new transport option
-  TRANS_OPT_NO_DEPENDENTS to indicate that only the objects themselves are
-  desired, not any object that they refer to.
-+
-Because some transports invoke fetch_pack() in the same process, fetch_pack()
-has been updated to not use any object flags when the corresponding argument
-(no_dependents) is set.
+- Fetching of objects is done by invoking a "git fetch" subprocess.
 
 - The local repository sends a request with the hashes of all requested
-  objects as "want" lines, and does not perform any packfile negotiation.
+  objects, and does not perform any packfile negotiation.
   It then receives a packfile.
 
-- Because we are reusing the existing fetch-pack mechanism, fetching
+- Because we are reusing the existing fetch mechanism, fetching
   currently fetches all objects referred to by the requested objects, even
   though they are not necessary.
 
diff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt
index 36ccd14..124d716 100644
--- a/Documentation/technical/protocol-capabilities.txt
+++ b/Documentation/technical/protocol-capabilities.txt
@@ -324,15 +324,19 @@
 ----------------------
 
 If the upload-pack server advertises this capability, fetch-pack may
-send "want" lines with SHA-1s that exist at the server but are not
-advertised by upload-pack.
+send "want" lines with object names that exist at the server but are not
+advertised by upload-pack. For historical reasons, the name of this
+capability contains "sha1". Object names are always given using the
+object format negotiated through the 'object-format' capability.
 
 allow-reachable-sha1-in-want
 ----------------------------
 
 If the upload-pack server advertises this capability, fetch-pack may
-send "want" lines with SHA-1s that exist at the server but are not
-advertised by upload-pack.
+send "want" lines with object names that exist at the server but are not
+advertised by upload-pack. For historical reasons, the name of this
+capability contains "sha1". Object names are always given using the
+object format negotiated through the 'object-format' capability.
 
 push-cert=<nonce>
 -----------------
diff --git a/Documentation/technical/shallow.txt b/Documentation/technical/shallow.txt
index 01dedfe..f3738ba 100644
--- a/Documentation/technical/shallow.txt
+++ b/Documentation/technical/shallow.txt
@@ -13,7 +13,7 @@
 stops after showing them; "git fsck" does not complain saying
 the commits listed on their "parent" lines do not exist).
 
-Each line contains exactly one SHA-1. When read, a commit_graft
+Each line contains exactly one object name. When read, a commit_graft
 will be constructed, which has nr_parent < 0 to make it easier
 to discern from user provided grafts.
 
diff --git a/Makefile b/Makefile
index 372139f..86e5411 100644
--- a/Makefile
+++ b/Makefile
@@ -569,7 +569,6 @@
 COMPAT_CFLAGS =
 COMPAT_OBJS =
 XDIFF_OBJS =
-VCSSVN_OBJS =
 GENERATED_H =
 EXTRA_CPPFLAGS =
 FUZZ_OBJS =
@@ -671,13 +670,9 @@
 # ... and all the rest that could be moved out of bindir to gitexecdir
 PROGRAMS += $(EXTRA_PROGRAMS)
 
-PROGRAM_OBJS += bugreport.o
-PROGRAM_OBJS += credential-store.o
 PROGRAM_OBJS += daemon.o
-PROGRAM_OBJS += fast-import.o
 PROGRAM_OBJS += http-backend.o
 PROGRAM_OBJS += imap-send.o
-PROGRAM_OBJS += remote-testsvn.o
 PROGRAM_OBJS += sh-i18n--envsubst.o
 PROGRAM_OBJS += shell.o
 
@@ -749,8 +744,6 @@
 # Do not add more tests here unless they have extra dependencies. Add
 # them in TEST_BUILTINS_OBJS above.
 TEST_PROGRAMS_NEED_X += test-fake-ssh
-TEST_PROGRAMS_NEED_X += test-line-buffer
-TEST_PROGRAMS_NEED_X += test-svn-fe
 TEST_PROGRAMS_NEED_X += test-tool
 
 TEST_PROGRAMS = $(patsubst %,t/helper/%$X,$(TEST_PROGRAMS_NEED_X))
@@ -806,7 +799,6 @@
 
 LIB_FILE = libgit.a
 XDIFF_LIB = xdiff/lib.a
-VCSSVN_LIB = vcs-svn/lib.a
 
 GENERATED_H += config-list.h
 GENERATED_H += command-list.h
@@ -828,7 +820,6 @@
 LIB_OBJS += archive-tar.o
 LIB_OBJS += archive-zip.o
 LIB_OBJS += archive.o
-LIB_OBJS += argv-array.o
 LIB_OBJS += attr.o
 LIB_OBJS += base85.o
 LIB_OBJS += bisect.o
@@ -917,6 +908,7 @@
 LIB_OBJS += midx.o
 LIB_OBJS += name-hash.o
 LIB_OBJS += negotiator/default.o
+LIB_OBJS += negotiator/noop.o
 LIB_OBJS += negotiator/skipping.o
 LIB_OBJS += notes-cache.o
 LIB_OBJS += notes-merge.o
@@ -986,6 +978,7 @@
 LIB_OBJS += split-index.o
 LIB_OBJS += stable-qsort.o
 LIB_OBJS += strbuf.o
+LIB_OBJS += strvec.o
 LIB_OBJS += streaming.o
 LIB_OBJS += string-list.o
 LIB_OBJS += sub-process.o
@@ -1042,6 +1035,7 @@
 BUILTIN_OBJS += builtin/bisect--helper.o
 BUILTIN_OBJS += builtin/blame.o
 BUILTIN_OBJS += builtin/branch.o
+BUILTIN_OBJS += builtin/bugreport.o
 BUILTIN_OBJS += builtin/bundle.o
 BUILTIN_OBJS += builtin/cat-file.o
 BUILTIN_OBJS += builtin/check-attr.o
@@ -1052,6 +1046,9 @@
 BUILTIN_OBJS += builtin/checkout.o
 BUILTIN_OBJS += builtin/clean.o
 BUILTIN_OBJS += builtin/clone.o
+BUILTIN_OBJS += builtin/credential-cache.o
+BUILTIN_OBJS += builtin/credential-cache--daemon.o
+BUILTIN_OBJS += builtin/credential-store.o
 BUILTIN_OBJS += builtin/column.o
 BUILTIN_OBJS += builtin/commit-graph.o
 BUILTIN_OBJS += builtin/commit-tree.o
@@ -1067,6 +1064,7 @@
 BUILTIN_OBJS += builtin/difftool.o
 BUILTIN_OBJS += builtin/env--helper.o
 BUILTIN_OBJS += builtin/fast-export.o
+BUILTIN_OBJS += builtin/fast-import.o
 BUILTIN_OBJS += builtin/fetch-pack.o
 BUILTIN_OBJS += builtin/fetch.o
 BUILTIN_OBJS += builtin/fmt-merge-msg.o
@@ -1634,11 +1632,8 @@
 endif
 ifdef NO_UNIX_SOCKETS
 	BASIC_CFLAGS += -DNO_UNIX_SOCKETS
-	EXCLUDED_PROGRAMS += git-credential-cache git-credential-cache--daemon
 else
 	LIB_OBJS += unix-socket.o
-	PROGRAM_OBJS += credential-cache.o
-	PROGRAM_OBJS += credential-cache--daemon.o
 endif
 
 ifdef NO_ICONV
@@ -2346,16 +2341,9 @@
 XDIFF_OBJS += xdiff/xprepare.o
 XDIFF_OBJS += xdiff/xutils.o
 
-VCSSVN_OBJS += vcs-svn/fast_export.o
-VCSSVN_OBJS += vcs-svn/line_buffer.o
-VCSSVN_OBJS += vcs-svn/sliding_window.o
-VCSSVN_OBJS += vcs-svn/svndiff.o
-VCSSVN_OBJS += vcs-svn/svndump.o
-
 TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
 OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
 	$(XDIFF_OBJS) \
-	$(VCSSVN_OBJS) \
 	$(FUZZ_OBJS) \
 	common-main.o \
 	git.o
@@ -2459,10 +2447,6 @@
 git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
-git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)
-	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
-		$(LIBS)
-
 git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(IMAP_SEND_LDFLAGS) $(LIBS)
@@ -2474,10 +2458,6 @@
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS)
 
-git-remote-testsvn$X: remote-testsvn.o GIT-LDFLAGS $(GITLIBS) $(VCSSVN_LIB)
-	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) \
-	$(VCSSVN_LIB)
-
 $(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY)
 	$(QUIET_LNCP)$(RM) $@ && \
 	ln $< $@ 2>/dev/null || \
@@ -2494,9 +2474,6 @@
 $(XDIFF_LIB): $(XDIFF_OBJS)
 	$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
 
-$(VCSSVN_LIB): $(VCSSVN_OBJS)
-	$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
-
 export DEFAULT_EDITOR DEFAULT_PAGER
 
 Documentation/GIT-EXCLUDED-PROGRAMS: FORCE
@@ -2771,10 +2748,6 @@
 
 .PHONY: test perf
 
-t/helper/test-line-buffer$X: $(VCSSVN_LIB)
-
-t/helper/test-svn-fe$X: $(VCSSVN_LIB)
-
 .PRECIOUS: $(TEST_OBJS)
 
 t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
@@ -2901,18 +2874,13 @@
 	# because it is just a copy/hardlink of git.exe, rather than a unique binary.
 	$(INSTALL) git.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
 	$(INSTALL) git-shell.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
-	$(INSTALL) git-upload-pack.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
-	$(INSTALL) git-credential-store.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 	$(INSTALL) git-daemon.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
-	$(INSTALL) git-fast-import.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 	$(INSTALL) git-http-backend.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 	$(INSTALL) git-http-fetch.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 	$(INSTALL) git-http-push.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 	$(INSTALL) git-imap-send.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 	$(INSTALL) git-remote-http.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
-	$(INSTALL) git-remote-testsvn.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 	$(INSTALL) git-sh-i18n--envsubst.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
-	$(INSTALL) git-show-index.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 ifndef DEBUG
 	$(INSTALL) $(vcpkg_rel_bin)/*.dll '$(DESTDIR_SQ)$(bindir_SQ)'
 	$(INSTALL) $(vcpkg_rel_bin)/*.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
@@ -3112,7 +3080,7 @@
 clean: profile-clean coverage-clean cocciclean
 	$(RM) *.res
 	$(RM) $(OBJECTS)
-	$(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB)
+	$(RM) $(LIB_FILE) $(XDIFF_LIB)
 	$(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
 	$(RM) $(TEST_PROGRAMS)
 	$(RM) $(FUZZ_PROGRAMS)
diff --git a/RelNotes b/RelNotes
index a7b4f6d..9143650 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.28.0.txt
\ No newline at end of file
+Documentation/RelNotes/2.29.0.txt
\ No newline at end of file
diff --git a/add-interactive.c b/add-interactive.c
index 29cd2fe..555c4ab 100644
--- a/add-interactive.c
+++ b/add-interactive.c
@@ -935,18 +935,18 @@
 	opts->prompt = N_("Patch update");
 	count = list_and_choose(s, files, opts);
 	if (count > 0) {
-		struct argv_array args = ARGV_ARRAY_INIT;
+		struct strvec args = STRVEC_INIT;
 		struct pathspec ps_selected = { 0 };
 
 		for (i = 0; i < files->items.nr; i++)
 			if (files->selected[i])
-				argv_array_push(&args,
-						files->items.items[i].string);
+				strvec_push(&args,
+					    files->items.items[i].string);
 		parse_pathspec(&ps_selected,
 			       PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
-			       PATHSPEC_LITERAL_PATH, "", args.argv);
+			       PATHSPEC_LITERAL_PATH, "", args.v);
 		res = run_add_p(s->r, ADD_P_ADD, NULL, &ps_selected);
-		argv_array_clear(&args);
+		strvec_clear(&args);
 		clear_pathspec(&ps_selected);
 	}
 
@@ -976,18 +976,18 @@
 	count = list_and_choose(s, files, opts);
 	opts->flags = 0;
 	if (count > 0) {
-		struct argv_array args = ARGV_ARRAY_INIT;
+		struct strvec args = STRVEC_INIT;
 
-		argv_array_pushl(&args, "git", "diff", "-p", "--cached",
-				 oid_to_hex(!is_initial ? &oid :
-					    s->r->hash_algo->empty_tree),
-				 "--", NULL);
+		strvec_pushl(&args, "git", "diff", "-p", "--cached",
+			     oid_to_hex(!is_initial ? &oid :
+					s->r->hash_algo->empty_tree),
+			     "--", NULL);
 		for (i = 0; i < files->items.nr; i++)
 			if (files->selected[i])
-				argv_array_push(&args,
-						files->items.items[i].string);
-		res = run_command_v_opt(args.argv, 0);
-		argv_array_clear(&args);
+				strvec_push(&args,
+					    files->items.items[i].string);
+		res = run_command_v_opt(args.v, 0);
+		strvec_clear(&args);
 	}
 
 	putchar('\n');
diff --git a/add-patch.c b/add-patch.c
index f899389..457b8c5 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -2,7 +2,7 @@
 #include "add-interactive.h"
 #include "strbuf.h"
 #include "run-command.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "pathspec.h"
 #include "color.h"
 #include "diff.h"
@@ -286,12 +286,12 @@
 
 	va_start(ap, cp);
 	while ((arg = va_arg(ap, const char *)))
-		argv_array_push(&cp->args, arg);
+		strvec_push(&cp->args, arg);
 	va_end(ap);
 
 	cp->git_cmd = 1;
-	argv_array_pushf(&cp->env_array,
-			 INDEX_ENVIRONMENT "=%s", s->s.r->index_file);
+	strvec_pushf(&cp->env_array,
+		     INDEX_ENVIRONMENT "=%s", s->s.r->index_file);
 }
 
 static int parse_range(const char **p,
@@ -370,7 +370,7 @@
 
 static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
 {
-	struct argv_array args = ARGV_ARRAY_INIT;
+	struct strvec args = STRVEC_INIT;
 	const char *diff_algorithm = s->s.interactive_diff_algorithm;
 	struct strbuf *plain = &s->plain, *colored = NULL;
 	struct child_process cp = CHILD_PROCESS_INIT;
@@ -380,32 +380,32 @@
 	struct hunk *hunk = NULL;
 	int res;
 
-	argv_array_pushv(&args, s->mode->diff_cmd);
+	strvec_pushv(&args, s->mode->diff_cmd);
 	if (diff_algorithm)
-		argv_array_pushf(&args, "--diff-algorithm=%s", diff_algorithm);
+		strvec_pushf(&args, "--diff-algorithm=%s", diff_algorithm);
 	if (s->revision) {
 		struct object_id oid;
-		argv_array_push(&args,
-				/* could be on an unborn branch */
-				!strcmp("HEAD", s->revision) &&
-				get_oid("HEAD", &oid) ?
-				empty_tree_oid_hex() : s->revision);
+		strvec_push(&args,
+			    /* could be on an unborn branch */
+			    !strcmp("HEAD", s->revision) &&
+			    get_oid("HEAD", &oid) ?
+			    empty_tree_oid_hex() : s->revision);
 	}
-	color_arg_index = args.argc;
+	color_arg_index = args.nr;
 	/* Use `--no-color` explicitly, just in case `diff.color = always`. */
-	argv_array_pushl(&args, "--no-color", "-p", "--", NULL);
+	strvec_pushl(&args, "--no-color", "-p", "--", NULL);
 	for (i = 0; i < ps->nr; i++)
-		argv_array_push(&args, ps->items[i].original);
+		strvec_push(&args, ps->items[i].original);
 
 	setup_child_process(s, &cp, NULL);
-	cp.argv = args.argv;
+	cp.argv = args.v;
 	res = capture_command(&cp, plain, 0);
 	if (res) {
-		argv_array_clear(&args);
+		strvec_clear(&args);
 		return error(_("could not parse diff"));
 	}
 	if (!plain->len) {
-		argv_array_clear(&args);
+		strvec_clear(&args);
 		return 0;
 	}
 	strbuf_complete_line(plain);
@@ -415,11 +415,11 @@
 		const char *diff_filter = s->s.interactive_diff_filter;
 
 		setup_child_process(s, &colored_cp, NULL);
-		xsnprintf((char *)args.argv[color_arg_index], 8, "--color");
-		colored_cp.argv = args.argv;
+		xsnprintf((char *)args.v[color_arg_index], 8, "--color");
+		colored_cp.argv = args.v;
 		colored = &s->colored;
 		res = capture_command(&colored_cp, colored, 0);
-		argv_array_clear(&args);
+		strvec_clear(&args);
 		if (res)
 			return error(_("could not parse colored diff"));
 
@@ -444,7 +444,7 @@
 		colored_p = colored->buf;
 		colored_pend = colored_p + colored->len;
 	}
-	argv_array_clear(&args);
+	strvec_clear(&args);
 
 	/* parse files and hunks */
 	p = plain->buf;
@@ -457,11 +457,9 @@
 			eol = pend;
 
 		if (starts_with(p, "diff ")) {
-			s->file_diff_nr++;
-			ALLOC_GROW(s->file_diff, s->file_diff_nr,
+			ALLOC_GROW_BY(s->file_diff, s->file_diff_nr, 1,
 				   file_diff_alloc);
 			file_diff = s->file_diff + s->file_diff_nr - 1;
-			memset(file_diff, 0, sizeof(*file_diff));
 			hunk = &file_diff->head;
 			hunk->start = p - plain->buf;
 			if (colored_p)
@@ -483,11 +481,9 @@
 				 */
 				hunk->splittable_into++;
 
-			file_diff->hunk_nr++;
-			ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr,
+			ALLOC_GROW_BY(file_diff->hunk, file_diff->hunk_nr, 1,
 				   file_diff->hunk_alloc);
 			hunk = file_diff->hunk + file_diff->hunk_nr - 1;
-			memset(hunk, 0, sizeof(*hunk));
 
 			hunk->start = p - plain->buf;
 			if (colored)
@@ -511,7 +507,7 @@
 			if (file_diff->mode_change)
 				BUG("double mode change?\n\n%.*s",
 				    (int)(eol - plain->buf), plain->buf);
-			if (file_diff->hunk_nr++)
+			if (file_diff->hunk_nr)
 				BUG("mode change in the middle?\n\n%.*s",
 				    (int)(eol - plain->buf), plain->buf);
 
@@ -520,9 +516,8 @@
 			 * is _part of_ the header "hunk".
 			 */
 			file_diff->mode_change = 1;
-			ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr,
+			ALLOC_GROW_BY(file_diff->hunk, file_diff->hunk_nr, 1,
 				   file_diff->hunk_alloc);
-			memset(file_diff->hunk, 0, sizeof(struct hunk));
 			file_diff->hunk->start = p - plain->buf;
 			if (colored_p)
 				file_diff->hunk->colored_start =
@@ -1158,7 +1153,7 @@
 
 	setup_child_process(s, &cp,
 			    "apply", "--check", NULL);
-	argv_array_pushv(&cp.args, s->mode->apply_check_args);
+	strvec_pushv(&cp.args, s->mode->apply_check_args);
 	if (pipe_command(&cp, s->buf.buf, s->buf.len, NULL, 0, NULL, 0))
 		return error(_("'git apply --cached' failed"));
 
@@ -1203,7 +1198,7 @@
 	for (;;) {
 		int res = edit_hunk_manually(s, hunk);
 		if (res == 0) {
-			/* abandonded */
+			/* abandoned */
 			*hunk = backup;
 			return -1;
 		}
@@ -1357,6 +1352,15 @@
 	struct child_process cp = CHILD_PROCESS_INIT;
 	int colored = !!s->colored.len, quit = 0;
 	enum prompt_mode_type prompt_mode_type;
+	enum {
+		ALLOW_GOTO_PREVIOUS_HUNK = 1 << 0,
+		ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK = 1 << 1,
+		ALLOW_GOTO_NEXT_HUNK = 1 << 2,
+		ALLOW_GOTO_NEXT_UNDECIDED_HUNK = 1 << 3,
+		ALLOW_SEARCH_AND_GOTO = 1 << 4,
+		ALLOW_SPLIT = 1 << 5,
+		ALLOW_EDIT = 1 << 6
+	} permitted = 0;
 
 	if (!file_diff->hunk_nr)
 		return 0;
@@ -1393,22 +1397,35 @@
 		fputs(s->buf.buf, stdout);
 
 		strbuf_reset(&s->buf);
-		if (undecided_previous >= 0)
+		if (undecided_previous >= 0) {
+			permitted |= ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK;
 			strbuf_addstr(&s->buf, ",k");
-		if (hunk_index)
+		}
+		if (hunk_index) {
+			permitted |= ALLOW_GOTO_PREVIOUS_HUNK;
 			strbuf_addstr(&s->buf, ",K");
-		if (undecided_next >= 0)
+		}
+		if (undecided_next >= 0) {
+			permitted |= ALLOW_GOTO_NEXT_UNDECIDED_HUNK;
 			strbuf_addstr(&s->buf, ",j");
-		if (hunk_index + 1 < file_diff->hunk_nr)
+		}
+		if (hunk_index + 1 < file_diff->hunk_nr) {
+			permitted |= ALLOW_GOTO_NEXT_HUNK;
 			strbuf_addstr(&s->buf, ",J");
-		if (file_diff->hunk_nr > 1)
+		}
+		if (file_diff->hunk_nr > 1) {
+			permitted |= ALLOW_SEARCH_AND_GOTO;
 			strbuf_addstr(&s->buf, ",g,/");
-		if (hunk->splittable_into > 1)
+		}
+		if (hunk->splittable_into > 1) {
+			permitted |= ALLOW_SPLIT;
 			strbuf_addstr(&s->buf, ",s");
+		}
 		if (hunk_index + 1 > file_diff->mode_change &&
-		    !file_diff->deleted)
+		    !file_diff->deleted) {
+			permitted |= ALLOW_EDIT;
 			strbuf_addstr(&s->buf, ",e");
-
+		}
 		if (file_diff->deleted)
 			prompt_mode_type = PROMPT_DELETION;
 		else if (file_diff->added)
@@ -1457,22 +1474,22 @@
 				break;
 			}
 		} else if (s->answer.buf[0] == 'K') {
-			if (hunk_index)
+			if (permitted & ALLOW_GOTO_PREVIOUS_HUNK)
 				hunk_index--;
 			else
 				err(s, _("No previous hunk"));
 		} else if (s->answer.buf[0] == 'J') {
-			if (hunk_index + 1 < file_diff->hunk_nr)
+			if (permitted & ALLOW_GOTO_NEXT_HUNK)
 				hunk_index++;
 			else
 				err(s, _("No next hunk"));
 		} else if (s->answer.buf[0] == 'k') {
-			if (undecided_previous >= 0)
+			if (permitted & ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK)
 				hunk_index = undecided_previous;
 			else
 				err(s, _("No previous hunk"));
 		} else if (s->answer.buf[0] == 'j') {
-			if (undecided_next >= 0)
+			if (permitted & ALLOW_GOTO_NEXT_UNDECIDED_HUNK)
 				hunk_index = undecided_next;
 			else
 				err(s, _("No next hunk"));
@@ -1480,7 +1497,7 @@
 			char *pend;
 			unsigned long response;
 
-			if (file_diff->hunk_nr < 2) {
+			if (!(permitted & ALLOW_SEARCH_AND_GOTO)) {
 				err(s, _("No other hunks to goto"));
 				continue;
 			}
@@ -1517,7 +1534,7 @@
 			regex_t regex;
 			int ret;
 
-			if (file_diff->hunk_nr < 2) {
+			if (!(permitted & ALLOW_SEARCH_AND_GOTO)) {
 				err(s, _("No other hunks to search"));
 				continue;
 			}
@@ -1562,7 +1579,7 @@
 			hunk_index = i;
 		} else if (s->answer.buf[0] == 's') {
 			size_t splittable_into = hunk->splittable_into;
-			if (splittable_into < 2)
+			if (!(permitted & ALLOW_SPLIT))
 				err(s, _("Sorry, cannot split this hunk"));
 			else if (!split_hunk(s, file_diff,
 					     hunk - file_diff->hunk))
@@ -1570,7 +1587,7 @@
 						 _("Split into %d hunks."),
 						 (int)splittable_into);
 		} else if (s->answer.buf[0] == 'e') {
-			if (hunk_index + 1 == file_diff->mode_change)
+			if (!(permitted & ALLOW_EDIT))
 				err(s, _("Sorry, cannot edit this hunk"));
 			else if (edit_hunk_loop(s, file_diff, hunk) >= 0) {
 				hunk->use = USE_HUNK;
@@ -1619,7 +1636,7 @@
 					   s->mode->is_reverse);
 		else {
 			setup_child_process(s, &cp, "apply", NULL);
-			argv_array_pushv(&cp.args, s->mode->apply_args);
+			strvec_pushv(&cp.args, s->mode->apply_args);
 			if (pipe_command(&cp, s->buf.buf, s->buf.len,
 					 NULL, 0, NULL, 0))
 				error(_("'git apply' failed"));
diff --git a/apply.c b/apply.c
index 8bff604..76dba93 100644
--- a/apply.c
+++ b/apply.c
@@ -30,8 +30,8 @@
 
 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_get_string("apply.whitespace", &apply_default_whitespace);
+	git_config_get_string("apply.ignorewhitespace", &apply_default_ignorewhitespace);
 	git_config(git_xmerge_config, NULL);
 }
 
@@ -3178,7 +3178,7 @@
 		return 0; /* deletion patch */
 	}
 
-	if (has_object_file(&oid)) {
+	if (has_object(the_repository, &oid, 0)) {
 		/* We already have the postimage */
 		enum object_type type;
 		unsigned long size;
@@ -3740,6 +3740,7 @@
 
 #define EXISTS_IN_INDEX 1
 #define EXISTS_IN_WORKTREE 2
+#define EXISTS_IN_INDEX_AS_ITA 3
 
 static int check_to_create(struct apply_state *state,
 			   const char *new_name,
@@ -3747,10 +3748,23 @@
 {
 	struct stat nst;
 
-	if (state->check_index &&
-	    index_name_pos(state->repo->index, new_name, strlen(new_name)) >= 0 &&
-	    !ok_if_exists)
-		return EXISTS_IN_INDEX;
+	if (state->check_index && (!ok_if_exists || !state->cached)) {
+		int pos;
+
+		pos = index_name_pos(state->repo->index, new_name, strlen(new_name));
+		if (pos >= 0) {
+			struct cache_entry *ce = state->repo->index->cache[pos];
+
+			/* allow ITA, as they do not yet exist in the index */
+			if (!ok_if_exists && !(ce->ce_flags & CE_INTENT_TO_ADD))
+				return EXISTS_IN_INDEX;
+
+			/* ITA entries can never match working tree files */
+			if (!state->cached && (ce->ce_flags & CE_INTENT_TO_ADD))
+				return EXISTS_IN_INDEX_AS_ITA;
+		}
+	}
+
 	if (state->cached)
 		return 0;
 
@@ -3935,6 +3949,9 @@
 		case EXISTS_IN_INDEX:
 			return error(_("%s: already exists in index"), new_name);
 			break;
+		case EXISTS_IN_INDEX_AS_ITA:
+			return error(_("%s: does not match index"), new_name);
+			break;
 		case EXISTS_IN_WORKTREE:
 			return error(_("%s: already exists in working directory"),
 				     new_name);
diff --git a/argv-array.c b/argv-array.c
deleted file mode 100644
index 61ef8c0..0000000
--- a/argv-array.c
+++ /dev/null
@@ -1,109 +0,0 @@
-#include "cache.h"
-#include "argv-array.h"
-#include "strbuf.h"
-
-const char *empty_argv[] = { NULL };
-
-void argv_array_init(struct argv_array *array)
-{
-	array->argv = empty_argv;
-	array->argc = 0;
-	array->alloc = 0;
-}
-
-static void argv_array_push_nodup(struct argv_array *array, const char *value)
-{
-	if (array->argv == empty_argv)
-		array->argv = NULL;
-
-	ALLOC_GROW(array->argv, array->argc + 2, array->alloc);
-	array->argv[array->argc++] = value;
-	array->argv[array->argc] = NULL;
-}
-
-const char *argv_array_push(struct argv_array *array, const char *value)
-{
-	argv_array_push_nodup(array, xstrdup(value));
-	return array->argv[array->argc - 1];
-}
-
-const char *argv_array_pushf(struct argv_array *array, const char *fmt, ...)
-{
-	va_list ap;
-	struct strbuf v = STRBUF_INIT;
-
-	va_start(ap, fmt);
-	strbuf_vaddf(&v, fmt, ap);
-	va_end(ap);
-
-	argv_array_push_nodup(array, strbuf_detach(&v, NULL));
-	return array->argv[array->argc - 1];
-}
-
-void argv_array_pushl(struct argv_array *array, ...)
-{
-	va_list ap;
-	const char *arg;
-
-	va_start(ap, array);
-	while ((arg = va_arg(ap, const char *)))
-		argv_array_push(array, arg);
-	va_end(ap);
-}
-
-void argv_array_pushv(struct argv_array *array, const char **argv)
-{
-	for (; *argv; argv++)
-		argv_array_push(array, *argv);
-}
-
-void argv_array_pop(struct argv_array *array)
-{
-	if (!array->argc)
-		return;
-	free((char *)array->argv[array->argc - 1]);
-	array->argv[array->argc - 1] = NULL;
-	array->argc--;
-}
-
-void argv_array_split(struct argv_array *array, const char *to_split)
-{
-	while (isspace(*to_split))
-		to_split++;
-	for (;;) {
-		const char *p = to_split;
-
-		if (!*p)
-			break;
-
-		while (*p && !isspace(*p))
-			p++;
-		argv_array_push_nodup(array, xstrndup(to_split, p - to_split));
-
-		while (isspace(*p))
-			p++;
-		to_split = p;
-	}
-}
-
-void argv_array_clear(struct argv_array *array)
-{
-	if (array->argv != empty_argv) {
-		int i;
-		for (i = 0; i < array->argc; i++)
-			free((char *)array->argv[i]);
-		free(array->argv);
-	}
-	argv_array_init(array);
-}
-
-const char **argv_array_detach(struct argv_array *array)
-{
-	if (array->argv == empty_argv)
-		return xcalloc(1, sizeof(const char *));
-	else {
-		const char **ret = array->argv;
-		argv_array_init(array);
-		return ret;
-	}
-}
diff --git a/argv-array.h b/argv-array.h
deleted file mode 100644
index a7d3b10..0000000
--- a/argv-array.h
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef ARGV_ARRAY_H
-#define ARGV_ARRAY_H
-
-/**
- * The argv-array API allows one to dynamically build and store
- * NULL-terminated lists.  An argv-array maintains the invariant that the
- * `argv` member always points to a non-NULL array, and that the array is
- * always NULL-terminated at the element pointed to by `argv[argc]`. This
- * makes the result suitable for passing to functions expecting to receive
- * argv from main().
- *
- * The string-list API (documented in string-list.h) is similar, but cannot be
- * used for these purposes; instead of storing a straight string pointer,
- * it contains an item structure with a `util` field that is not compatible
- * with the traditional argv interface.
- *
- * Each `argv_array` manages its own memory. Any strings pushed into the
- * array are duplicated, and all memory is freed by argv_array_clear().
- */
-
-extern const char *empty_argv[];
-
-/**
- * A single array. This should be initialized by assignment from
- * `ARGV_ARRAY_INIT`, or by calling `argv_array_init`. The `argv`
- * member contains the actual array; the `argc` member contains the
- * number of elements in the array, not including the terminating
- * NULL.
- */
-struct argv_array {
-	const char **argv;
-	int argc;
-	int alloc;
-};
-
-#define ARGV_ARRAY_INIT { empty_argv, 0, 0 }
-
-/**
- * Initialize an array. This is no different than assigning from
- * `ARGV_ARRAY_INIT`.
- */
-void argv_array_init(struct argv_array *);
-
-/* Push a copy of a string onto the end of the array. */
-const char *argv_array_push(struct argv_array *, const char *);
-
-/**
- * Format a string and push it onto the end of the array. This is a
- * convenience wrapper combining `strbuf_addf` and `argv_array_push`.
- */
-__attribute__((format (printf,2,3)))
-const char *argv_array_pushf(struct argv_array *, const char *fmt, ...);
-
-/**
- * Push a list of strings onto the end of the array. The arguments
- * should be a list of `const char *` strings, terminated by a NULL
- * argument.
- */
-LAST_ARG_MUST_BE_NULL
-void argv_array_pushl(struct argv_array *, ...);
-
-/* Push a null-terminated array of strings onto the end of the array. */
-void argv_array_pushv(struct argv_array *, const char **);
-
-/**
- * Remove the final element from the array. If there are no
- * elements in the array, do nothing.
- */
-void argv_array_pop(struct argv_array *);
-
-/* Splits by whitespace; does not handle quoted arguments! */
-void argv_array_split(struct argv_array *, const char *);
-
-/**
- * Free all memory associated with the array and return it to the
- * initial, empty state.
- */
-void argv_array_clear(struct argv_array *);
-
-/**
- * Disconnect the `argv` member from the `argv_array` struct and
- * return it. The caller is responsible for freeing the memory used
- * by the array, and by the strings it references. After detaching,
- * the `argv_array` is in a reinitialized state and can be pushed
- * into again.
- */
-const char **argv_array_detach(struct argv_array *);
-
-#endif /* ARGV_ARRAY_H */
diff --git a/bisect.c b/bisect.c
index d5e8304..d42a3a3 100644
--- a/bisect.c
+++ b/bisect.c
@@ -11,10 +11,11 @@
 #include "log-tree.h"
 #include "bisect.h"
 #include "oid-array.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "commit-slab.h"
 #include "commit-reach.h"
 #include "object-store.h"
+#include "dir.h"
 
 static struct oid_array good_revs;
 static struct oid_array skipped_revs;
@@ -88,15 +89,16 @@
 	**commit_weight_at(&commit_weight, elem->item) = weight;
 }
 
-static int count_interesting_parents(struct commit *commit)
+static int count_interesting_parents(struct commit *commit, unsigned bisect_flags)
 {
 	struct commit_list *p;
 	int count;
 
 	for (count = 0, p = commit->parents; p; p = p->next) {
-		if (p->item->object.flags & UNINTERESTING)
-			continue;
-		count++;
+		if (!(p->item->object.flags & UNINTERESTING))
+			count++;
+		if (bisect_flags & FIND_BISECTION_FIRST_PARENT_ONLY)
+			break;
 	}
 	return count;
 }
@@ -135,7 +137,7 @@
 	for (p = list; p; p = p->next) {
 		struct commit_list *pp;
 		struct commit *commit = p->item;
-		unsigned flags = commit->object.flags;
+		unsigned commit_flags = commit->object.flags;
 		enum object_type type;
 		unsigned long size;
 		char *buf = read_object_file(&commit->object.oid, &type,
@@ -144,9 +146,9 @@
 		int subject_len;
 
 		fprintf(stderr, "%c%c%c ",
-			(flags & TREESAME) ? ' ' : 'T',
-			(flags & UNINTERESTING) ? 'U' : ' ',
-			(flags & COUNTED) ? 'C' : ' ');
+			(commit_flags & TREESAME) ? ' ' : 'T',
+			(commit_flags & UNINTERESTING) ? 'U' : ' ',
+			(commit_flags & COUNTED) ? 'C' : ' ');
 		if (*commit_weight_at(&commit_weight, p->item))
 			fprintf(stderr, "%3d", weight(p));
 		else
@@ -171,9 +173,9 @@
 	best = list;
 	for (p = list; p; p = p->next) {
 		int distance;
-		unsigned flags = p->item->object.flags;
+		unsigned commit_flags = p->item->object.flags;
 
-		if (flags & TREESAME)
+		if (commit_flags & TREESAME)
 			continue;
 		distance = weight(p);
 		if (nr - distance < distance)
@@ -212,9 +214,9 @@
 
 	for (p = list, cnt = 0; p; p = p->next) {
 		int distance;
-		unsigned flags = p->item->object.flags;
+		unsigned commit_flags = p->item->object.flags;
 
-		if (flags & TREESAME)
+		if (commit_flags & TREESAME)
 			continue;
 		distance = weight(p);
 		if (nr - distance < distance)
@@ -259,7 +261,7 @@
  */
 static struct commit_list *do_find_bisection(struct commit_list *list,
 					     int nr, int *weights,
-					     int find_all)
+					     unsigned bisect_flags)
 {
 	int n, counted;
 	struct commit_list *p;
@@ -268,12 +270,12 @@
 
 	for (n = 0, p = list; p; p = p->next) {
 		struct commit *commit = p->item;
-		unsigned flags = commit->object.flags;
+		unsigned commit_flags = commit->object.flags;
 
 		*commit_weight_at(&commit_weight, p->item) = &weights[n++];
-		switch (count_interesting_parents(commit)) {
+		switch (count_interesting_parents(commit, bisect_flags)) {
 		case 0:
-			if (!(flags & TREESAME)) {
+			if (!(commit_flags & TREESAME)) {
 				weight_set(p, 1);
 				counted++;
 				show_list("bisection 2 count one",
@@ -314,11 +316,13 @@
 			continue;
 		if (weight(p) != -2)
 			continue;
+		if (bisect_flags & FIND_BISECTION_FIRST_PARENT_ONLY)
+			BUG("shouldn't be calling count-distance in fp mode");
 		weight_set(p, count_distance(p));
 		clear_distance(list);
 
 		/* Does it happen to be at exactly half-way? */
-		if (!find_all && halfway(p, nr))
+		if (!(bisect_flags & FIND_BISECTION_ALL) && halfway(p, nr))
 			return p;
 		counted++;
 	}
@@ -328,11 +332,14 @@
 	while (counted < nr) {
 		for (p = list; p; p = p->next) {
 			struct commit_list *q;
-			unsigned flags = p->item->object.flags;
+			unsigned commit_flags = p->item->object.flags;
 
 			if (0 <= weight(p))
 				continue;
-			for (q = p->item->parents; q; q = q->next) {
+
+			for (q = p->item->parents;
+			     q;
+			     q = bisect_flags & FIND_BISECTION_FIRST_PARENT_ONLY ? NULL : q->next) {
 				if (q->item->object.flags & UNINTERESTING)
 					continue;
 				if (0 <= weight(q))
@@ -346,7 +353,7 @@
 			 * add one for p itself if p is to be counted,
 			 * otherwise inherit it from q directly.
 			 */
-			if (!(flags & TREESAME)) {
+			if (!(commit_flags & TREESAME)) {
 				weight_set(p, weight(q)+1);
 				counted++;
 				show_list("bisection 2 count one",
@@ -356,21 +363,21 @@
 				weight_set(p, weight(q));
 
 			/* Does it happen to be at exactly half-way? */
-			if (!find_all && halfway(p, nr))
+			if (!(bisect_flags & FIND_BISECTION_ALL) && halfway(p, nr))
 				return p;
 		}
 	}
 
 	show_list("bisection 2 counted all", counted, nr, list);
 
-	if (!find_all)
+	if (!(bisect_flags & FIND_BISECTION_ALL))
 		return best_bisection(list, nr);
 	else
 		return best_bisection_sorted(list, nr);
 }
 
 void find_bisection(struct commit_list **commit_list, int *reaches,
-		    int *all, int find_all)
+		    int *all, unsigned bisect_flags)
 {
 	int nr, on_list;
 	struct commit_list *list, *p, *best, *next, *last;
@@ -386,16 +393,16 @@
 	for (nr = on_list = 0, last = NULL, p = *commit_list;
 	     p;
 	     p = next) {
-		unsigned flags = p->item->object.flags;
+		unsigned commit_flags = p->item->object.flags;
 
 		next = p->next;
-		if (flags & UNINTERESTING) {
+		if (commit_flags & UNINTERESTING) {
 			free(p);
 			continue;
 		}
 		p->next = last;
 		last = p;
-		if (!(flags & TREESAME))
+		if (!(commit_flags & TREESAME))
 			nr++;
 		on_list++;
 	}
@@ -406,9 +413,9 @@
 	weights = xcalloc(on_list, sizeof(*weights));
 
 	/* Do the real work of finding bisection commit. */
-	best = do_find_bisection(list, nr, weights, find_all);
+	best = do_find_bisection(list, nr, weights, bisect_flags);
 	if (best) {
-		if (!find_all) {
+		if (!(bisect_flags & FIND_BISECTION_ALL)) {
 			list->item = best->item;
 			free_commit_list(list->next);
 			best = list;
@@ -454,9 +461,10 @@
 static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
 static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
+static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 static GIT_PATH_FUNC(git_path_head_name, "head-name")
 
-static void read_bisect_paths(struct argv_array *array)
+static void read_bisect_paths(struct strvec *array)
 {
 	struct strbuf str = STRBUF_INIT;
 	const char *filename = git_path_bisect_names();
@@ -464,7 +472,7 @@
 
 	while (strbuf_getline_lf(&str, fp) != EOF) {
 		strbuf_trim(&str);
-		if (sq_dequote_to_argv_array(str.buf, array))
+		if (sq_dequote_to_strvec(str.buf, array))
 			die(_("Badly quoted content in file '%s': %s"),
 			    filename, str.buf);
 	}
@@ -632,7 +640,7 @@
 			     const char *bad_format, const char *good_format,
 			     int read_paths)
 {
-	struct argv_array rev_argv = ARGV_ARRAY_INIT;
+	struct strvec rev_argv = STRVEC_INIT;
 	int i;
 
 	repo_init_revisions(r, revs, prefix);
@@ -640,16 +648,16 @@
 	revs->commit_format = CMIT_FMT_UNSPECIFIED;
 
 	/* rev_argv.argv[0] will be ignored by setup_revisions */
-	argv_array_push(&rev_argv, "bisect_rev_setup");
-	argv_array_pushf(&rev_argv, bad_format, oid_to_hex(current_bad_oid));
+	strvec_push(&rev_argv, "bisect_rev_setup");
+	strvec_pushf(&rev_argv, bad_format, oid_to_hex(current_bad_oid));
 	for (i = 0; i < good_revs.nr; i++)
-		argv_array_pushf(&rev_argv, good_format,
-				 oid_to_hex(good_revs.oid + i));
-	argv_array_push(&rev_argv, "--");
+		strvec_pushf(&rev_argv, good_format,
+			     oid_to_hex(good_revs.oid + i));
+	strvec_push(&rev_argv, "--");
 	if (read_paths)
 		read_bisect_paths(&rev_argv);
 
-	setup_revisions(rev_argv.argc, rev_argv.argv, revs, NULL);
+	setup_revisions(rev_argv.nr, rev_argv.v, revs, NULL);
 	/* XXX leak rev_argv, as "revs" may still be pointing to it */
 }
 
@@ -709,7 +717,7 @@
 	char bisect_rev_hex[GIT_MAX_HEXSZ + 1];
 	enum bisect_error res = BISECT_OK;
 
-	memcpy(bisect_rev_hex, oid_to_hex(bisect_rev), the_hash_algo->hexsz + 1);
+	oid_to_hex_r(bisect_rev_hex, bisect_rev);
 	update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
 
 	argv_checkout[2] = bisect_rev_hex;
@@ -983,7 +991,7 @@
  * If no_checkout is non-zero, the bisection process does not
  * checkout the trial commit but instead simply updates BISECT_HEAD.
  */
-enum bisect_error bisect_next_all(struct repository *r, const char *prefix, int no_checkout)
+enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
 {
 	struct rev_info revs;
 	struct commit_list *tried;
@@ -991,21 +999,31 @@
 	enum bisect_error res = BISECT_OK;
 	struct object_id *bisect_rev;
 	char *steps_msg;
+	int no_checkout = ref_exists("BISECT_HEAD");
+	unsigned bisect_flags = 0;
 
 	read_bisect_terms(&term_bad, &term_good);
 	if (read_bisect_refs())
 		die(_("reading bisect refs failed"));
 
+	if (file_exists(git_path_bisect_first_parent()))
+		bisect_flags |= FIND_BISECTION_FIRST_PARENT_ONLY;
+
+	if (skipped_revs.nr)
+		bisect_flags |= FIND_BISECTION_ALL;
+
 	res = check_good_are_ancestors_of_bad(r, prefix, no_checkout);
 	if (res)
 		return res;
 
 	bisect_rev_setup(r, &revs, prefix, "%s", "^%s", 1);
+
+	revs.first_parent_only = !!(bisect_flags & FIND_BISECTION_FIRST_PARENT_ONLY);
 	revs.limited = 1;
 
 	bisect_common(&revs);
 
-	find_bisection(&revs.commits, &reaches, &all, !!skipped_revs.nr);
+	find_bisection(&revs.commits, &reaches, &all, bisect_flags);
 	revs.commits = managed_skipped(revs.commits, &tried);
 
 	if (!revs.commits) {
@@ -1133,6 +1151,7 @@
 	unlink_or_warn(git_path_bisect_names());
 	unlink_or_warn(git_path_bisect_run());
 	unlink_or_warn(git_path_bisect_terms());
+	unlink_or_warn(git_path_bisect_first_parent());
 	/* Cleanup head-name if it got left by an old version of git-bisect */
 	unlink_or_warn(git_path_head_name());
 	/*
diff --git a/bisect.h b/bisect.h
index 8bad8d8..ec24ac2 100644
--- a/bisect.h
+++ b/bisect.h
@@ -12,7 +12,7 @@
  * best commit, as chosen by `find_all`.
  */
 void find_bisection(struct commit_list **list, int *reaches, int *all,
-		    int find_all);
+		    unsigned bisect_flags);
 
 struct commit_list *filter_skipped(struct commit_list *list,
 				   struct commit_list **tried,
@@ -23,6 +23,9 @@
 #define BISECT_SHOW_ALL		(1<<0)
 #define REV_LIST_QUIET		(1<<1)
 
+#define FIND_BISECTION_ALL			(1u<<0)
+#define FIND_BISECTION_FIRST_PARENT_ONLY	(1u<<1)
+
 struct rev_list_info {
 	struct rev_info *revs;
 	int flags;
@@ -58,9 +61,7 @@
 	BISECT_INTERNAL_SUCCESS_MERGE_BASE = -11
 };
 
-enum bisect_error bisect_next_all(struct repository *r,
-		    const char *prefix,
-		    int no_checkout);
+enum bisect_error bisect_next_all(struct repository *r, const char *prefix);
 
 int estimate_bisect_steps(int all);
 
diff --git a/blame.c b/blame.c
index 82fa16d..1be1cd8 100644
--- a/blame.c
+++ b/blame.c
@@ -1184,6 +1184,7 @@
 	for (ent = sb->ent; ent && (next = ent->next); ent = next) {
 		if (ent->suspect == next->suspect &&
 		    ent->s_lno + ent->num_lines == next->s_lno &&
+		    ent->lno + ent->num_lines == next->lno &&
 		    ent->ignored == next->ignored &&
 		    ent->unblamable == next->unblamable) {
 			ent->num_lines += next->num_lines;
diff --git a/bloom.c b/bloom.c
index 6a7f2f2..1a57322 100644
--- a/bloom.c
+++ b/bloom.c
@@ -187,7 +187,7 @@
 	struct diff_options diffopt;
 	int max_changes = 512;
 
-	if (bloom_filters.slab_size == 0)
+	if (!bloom_filters.slab_size)
 		return NULL;
 
 	filter = bloom_filter_slab_at(&bloom_filters, c);
@@ -195,16 +195,14 @@
 	if (!filter->data) {
 		load_commit_graph_info(r, c);
 		if (commit_graph_position(c) != COMMIT_NOT_FROM_GRAPH &&
-			r->objects->commit_graph->chunk_bloom_indexes) {
-			if (load_bloom_filter_from_graph(r->objects->commit_graph, filter, c))
-				return filter;
-			else
-				return NULL;
-		}
+			r->objects->commit_graph->chunk_bloom_indexes)
+			load_bloom_filter_from_graph(r->objects->commit_graph, filter, c);
 	}
 
-	if (filter->data || !compute_if_not_present)
+	if (filter->data)
 		return filter;
+	if (!compute_if_not_present)
+		return NULL;
 
 	repo_diff_setup(r, &diffopt);
 	diffopt.flags.recursive = 1;
diff --git a/builtin.h b/builtin.h
index a5ae15b..ba954e1 100644
--- a/builtin.h
+++ b/builtin.h
@@ -119,6 +119,7 @@
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix);
 int cmd_blame(int argc, const char **argv, const char *prefix);
 int cmd_branch(int argc, const char **argv, const char *prefix);
+int cmd_bugreport(int argc, const char **argv, const char *prefix);
 int cmd_bundle(int argc, const char **argv, const char *prefix);
 int cmd_cat_file(int argc, const char **argv, const char *prefix);
 int cmd_checkout(int argc, const char **argv, const char *prefix);
@@ -138,6 +139,9 @@
 int cmd_config(int argc, const char **argv, const char *prefix);
 int cmd_count_objects(int argc, const char **argv, const char *prefix);
 int cmd_credential(int argc, const char **argv, const char *prefix);
+int cmd_credential_cache(int argc, const char **argv, const char *prefix);
+int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix);
+int cmd_credential_store(int argc, const char **argv, const char *prefix);
 int cmd_describe(int argc, const char **argv, const char *prefix);
 int cmd_diff_files(int argc, const char **argv, const char *prefix);
 int cmd_diff_index(int argc, const char **argv, const char *prefix);
@@ -146,6 +150,7 @@
 int cmd_difftool(int argc, const char **argv, const char *prefix);
 int cmd_env__helper(int argc, const char **argv, const char *prefix);
 int cmd_fast_export(int argc, const char **argv, const char *prefix);
+int cmd_fast_import(int argc, const char **argv, const char *prefix);
 int cmd_fetch(int argc, const char **argv, const char *prefix);
 int cmd_fetch_pack(int argc, const char **argv, const char *prefix);
 int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
diff --git a/builtin/add.c b/builtin/add.c
index 298e011..b36a99e 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -18,7 +18,7 @@
 #include "diffcore.h"
 #include "revision.h"
 #include "bulk-checkin.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "submodule.h"
 #include "add-interactive.h"
 
@@ -188,7 +188,7 @@
 			const struct pathspec *pathspec)
 {
 	int status, i;
-	struct argv_array argv = ARGV_ARRAY_INIT;
+	struct strvec argv = STRVEC_INIT;
 	int use_builtin_add_i =
 		git_env_bool("GIT_TEST_ADD_I_USE_BUILTIN", -1);
 
@@ -218,18 +218,18 @@
 		return !!run_add_p(the_repository, mode, revision, pathspec);
 	}
 
-	argv_array_push(&argv, "add--interactive");
+	strvec_push(&argv, "add--interactive");
 	if (patch_mode)
-		argv_array_push(&argv, patch_mode);
+		strvec_push(&argv, patch_mode);
 	if (revision)
-		argv_array_push(&argv, revision);
-	argv_array_push(&argv, "--");
+		strvec_push(&argv, revision);
+	strvec_push(&argv, "--");
 	for (i = 0; i < pathspec->nr; i++)
 		/* pass original pathspec, to be re-parsed */
-		argv_array_push(&argv, pathspec->items[i].original);
+		strvec_push(&argv, pathspec->items[i].original);
 
-	status = run_command_v_opt(argv.argv, RUN_GIT_CMD);
-	argv_array_clear(&argv);
+	status = run_command_v_opt(argv.v, RUN_GIT_CMD);
+	strvec_clear(&argv);
 	return status;
 }
 
@@ -534,11 +534,11 @@
 	die_in_unpopulated_submodule(&the_index, prefix);
 	die_path_inside_submodule(&the_index, &pathspec);
 
+	dir_init(&dir);
 	if (add_new_files) {
 		int baselen;
 
 		/* Set up the default git porcelain excludes */
-		memset(&dir, 0, sizeof(dir));
 		if (!ignored_too) {
 			dir.flags |= DIR_COLLECT_IGNORED;
 			setup_standard_excludes(&dir);
@@ -611,7 +611,7 @@
 			       COMMIT_LOCK | SKIP_IF_UNCHANGED))
 		die(_("Unable to write new index file"));
 
+	dir_clear(&dir);
 	UNLEAK(pathspec);
-	UNLEAK(dir);
 	return exit_status;
 }
diff --git a/builtin/am.c b/builtin/am.c
index 69e50de..b5c63dd 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -98,6 +98,8 @@
 	char *author_name;
 	char *author_email;
 	char *author_date;
+	char *committer_name;
+	char *committer_email;
 	char *msg;
 	size_t msg_len;
 
@@ -116,7 +118,7 @@
 	int keep; /* enum keep_type */
 	int message_id;
 	int scissors; /* enum scissors_type */
-	struct argv_array git_apply_opts;
+	struct strvec git_apply_opts;
 	const char *resolvemsg;
 	int committer_date_is_author_date;
 	int ignore_date;
@@ -130,6 +132,8 @@
  */
 static void am_state_init(struct am_state *state)
 {
+	const char *committer;
+	struct ident_split id;
 	int gpgsign;
 
 	memset(state, 0, sizeof(*state));
@@ -146,10 +150,18 @@
 
 	state->scissors = SCISSORS_UNSET;
 
-	argv_array_init(&state->git_apply_opts);
+	strvec_init(&state->git_apply_opts);
 
 	if (!git_config_get_bool("commit.gpgsign", &gpgsign))
 		state->sign_commit = gpgsign ? "" : NULL;
+
+	committer = git_committer_info(IDENT_STRICT);
+	if (split_ident_line(&id, committer, strlen(committer)) < 0)
+		die(_("invalid committer: %s"), committer);
+	state->committer_name =
+		xmemdupz(id.name_begin, id.name_end - id.name_begin);
+	state->committer_email =
+		xmemdupz(id.mail_begin, id.mail_end - id.mail_end);
 }
 
 /**
@@ -161,8 +173,10 @@
 	free(state->author_name);
 	free(state->author_email);
 	free(state->author_date);
+	free(state->committer_name);
+	free(state->committer_email);
 	free(state->msg);
-	argv_array_clear(&state->git_apply_opts);
+	strvec_clear(&state->git_apply_opts);
 }
 
 /**
@@ -398,8 +412,8 @@
 		state->scissors = SCISSORS_UNSET;
 
 	read_state_file(&sb, state, "apply-opt", 1);
-	argv_array_clear(&state->git_apply_opts);
-	if (sq_dequote_to_argv_array(sb.buf, &state->git_apply_opts) < 0)
+	strvec_clear(&state->git_apply_opts);
+	if (sq_dequote_to_strvec(sb.buf, &state->git_apply_opts) < 0)
 		die(_("could not parse %s"), am_path(state, "apply-opt"));
 
 	state->rebasing = !!file_exists(am_path(state, "rebasing"));
@@ -452,8 +466,8 @@
 	if (!hook)
 		return 0;
 
-	argv_array_push(&cp.args, hook);
-	argv_array_push(&cp.args, "rebase");
+	strvec_push(&cp.args, hook);
+	strvec_push(&cp.args, "rebase");
 
 	cp.in = xopen(am_path(state, "rewritten"), O_RDONLY);
 	cp.stdout_to_stderr = 1;
@@ -651,16 +665,16 @@
 	int ret;
 
 	cp.git_cmd = 1;
-	argv_array_push(&cp.args, "mailsplit");
-	argv_array_pushf(&cp.args, "-d%d", state->prec);
-	argv_array_pushf(&cp.args, "-o%s", state->dir);
-	argv_array_push(&cp.args, "-b");
+	strvec_push(&cp.args, "mailsplit");
+	strvec_pushf(&cp.args, "-d%d", state->prec);
+	strvec_pushf(&cp.args, "-o%s", state->dir);
+	strvec_push(&cp.args, "-b");
 	if (keep_cr)
-		argv_array_push(&cp.args, "--keep-cr");
+		strvec_push(&cp.args, "--keep-cr");
 	if (mboxrd)
-		argv_array_push(&cp.args, "--mboxrd");
-	argv_array_push(&cp.args, "--");
-	argv_array_pushv(&cp.args, paths);
+		strvec_push(&cp.args, "--mboxrd");
+	strvec_push(&cp.args, "--");
+	strvec_pushv(&cp.args, paths);
 
 	ret = capture_command(&cp, &last, 8);
 	if (ret)
@@ -787,7 +801,7 @@
 	const char *series_dir;
 	char *series_dir_buf;
 	FILE *fp;
-	struct argv_array patches = ARGV_ARRAY_INIT;
+	struct strvec patches = STRVEC_INIT;
 	struct strbuf sb = STRBUF_INIT;
 	int ret;
 
@@ -805,16 +819,16 @@
 		if (*sb.buf == '#')
 			continue; /* skip comment lines */
 
-		argv_array_push(&patches, mkpath("%s/%s", series_dir, sb.buf));
+		strvec_push(&patches, mkpath("%s/%s", series_dir, sb.buf));
 	}
 
 	fclose(fp);
 	strbuf_release(&sb);
 	free(series_dir_buf);
 
-	ret = split_mail_conv(stgit_patch_to_mail, state, patches.argv, keep_cr);
+	ret = split_mail_conv(stgit_patch_to_mail, state, patches.v, keep_cr);
 
-	argv_array_clear(&patches);
+	strvec_clear(&patches);
 	return ret;
 }
 
@@ -1002,7 +1016,7 @@
 	}
 	write_state_text(state, "scissors", str);
 
-	sq_quote_argv(&sb, state->git_apply_opts.argv);
+	sq_quote_argv(&sb, state->git_apply_opts.v);
 	write_state_text(state, "apply-opt", sb.buf);
 
 	if (state->rebasing)
@@ -1390,8 +1404,8 @@
  */
 static int run_apply(const struct am_state *state, const char *index_file)
 {
-	struct argv_array apply_paths = ARGV_ARRAY_INIT;
-	struct argv_array apply_opts = ARGV_ARRAY_INIT;
+	struct strvec apply_paths = STRVEC_INIT;
+	struct strvec apply_opts = STRVEC_INIT;
 	struct apply_state apply_state;
 	int res, opts_left;
 	int force_apply = 0;
@@ -1400,10 +1414,10 @@
 	if (init_apply_state(&apply_state, the_repository, NULL))
 		BUG("init_apply_state() failed");
 
-	argv_array_push(&apply_opts, "apply");
-	argv_array_pushv(&apply_opts, state->git_apply_opts.argv);
+	strvec_push(&apply_opts, "apply");
+	strvec_pushv(&apply_opts, state->git_apply_opts.v);
 
-	opts_left = apply_parse_options(apply_opts.argc, apply_opts.argv,
+	opts_left = apply_parse_options(apply_opts.nr, apply_opts.v,
 					&apply_state, &force_apply, &options,
 					NULL);
 
@@ -1426,12 +1440,12 @@
 	if (check_apply_state(&apply_state, force_apply))
 		BUG("check_apply_state() failed");
 
-	argv_array_push(&apply_paths, am_path(state, "patch"));
+	strvec_push(&apply_paths, am_path(state, "patch"));
 
-	res = apply_all_patches(&apply_state, apply_paths.argc, apply_paths.argv, options);
+	res = apply_all_patches(&apply_state, apply_paths.nr, apply_paths.v, options);
 
-	argv_array_clear(&apply_paths);
-	argv_array_clear(&apply_opts);
+	strvec_clear(&apply_paths);
+	strvec_clear(&apply_opts);
 	clear_apply_state(&apply_state);
 
 	if (res)
@@ -1454,10 +1468,10 @@
 	struct child_process cp = CHILD_PROCESS_INIT;
 
 	cp.git_cmd = 1;
-	argv_array_push(&cp.args, "apply");
-	argv_array_pushv(&cp.args, state->git_apply_opts.argv);
-	argv_array_pushf(&cp.args, "--build-fake-ancestor=%s", index_file);
-	argv_array_push(&cp.args, am_path(state, "patch"));
+	strvec_push(&cp.args, "apply");
+	strvec_pushv(&cp.args, state->git_apply_opts.v);
+	strvec_pushf(&cp.args, "--build-fake-ancestor=%s", index_file);
+	strvec_push(&cp.args, am_path(state, "patch"));
 
 	if (run_command(&cp))
 		return -1;
@@ -1556,7 +1570,7 @@
 	struct object_id tree, parent, commit;
 	const struct object_id *old_oid;
 	struct commit_list *parents = NULL;
-	const char *reflog_msg, *author;
+	const char *reflog_msg, *author, *committer = NULL;
 	struct strbuf sb = STRBUF_INIT;
 
 	if (run_hook_le(NULL, "pre-applypatch", NULL))
@@ -1580,11 +1594,15 @@
 			IDENT_STRICT);
 
 	if (state->committer_date_is_author_date)
-		setenv("GIT_COMMITTER_DATE",
-			state->ignore_date ? "" : state->author_date, 1);
+		committer = fmt_ident(state->committer_name,
+				      state->author_email, WANT_COMMITTER_IDENT,
+				      state->ignore_date ? NULL
+							 : state->author_date,
+				      IDENT_STRICT);
 
-	if (commit_tree(state->msg, state->msg_len, &tree, parents, &commit,
-			author, state->sign_commit))
+	if (commit_tree_extended(state->msg, state->msg_len, &tree, parents,
+				 &commit, author, committer, state->sign_commit,
+				 NULL))
 		die(_("failed to write commit object"));
 
 	reflog_msg = getenv("GIT_REFLOG_ACTION");
@@ -1676,7 +1694,7 @@
 			if (!pager)
 				pager = "cat";
 			prepare_pager_args(&cp, pager);
-			argv_array_push(&cp.args, am_path(state, "patch"));
+			strvec_push(&cp.args, am_path(state, "patch"));
 			run_command(&cp);
 		}
 	}
@@ -2346,7 +2364,7 @@
 		if (state.signoff == SIGNOFF_EXPLICIT)
 			am_append_signoff(&state);
 	} else {
-		struct argv_array paths = ARGV_ARRAY_INIT;
+		struct strvec paths = STRVEC_INIT;
 		int i;
 
 		/*
@@ -2371,17 +2389,17 @@
 
 		for (i = 0; i < argc; i++) {
 			if (is_absolute_path(argv[i]) || !prefix)
-				argv_array_push(&paths, argv[i]);
+				strvec_push(&paths, argv[i]);
 			else
-				argv_array_push(&paths, mkpath("%s/%s", prefix, argv[i]));
+				strvec_push(&paths, mkpath("%s/%s", prefix, argv[i]));
 		}
 
-		if (state.interactive && !paths.argc)
+		if (state.interactive && !paths.nr)
 			die(_("interactive mode requires patches on the command line"));
 
-		am_setup(&state, patch_format, paths.argv, keep_cr);
+		am_setup(&state, patch_format, paths.v, keep_cr);
 
-		argv_array_clear(&paths);
+		strvec_clear(&paths);
 	}
 
 	switch (resume.mode) {
diff --git a/builtin/annotate.c b/builtin/annotate.c
index da413ae..58ff977 100644
--- a/builtin/annotate.c
+++ b/builtin/annotate.c
@@ -5,18 +5,18 @@
  */
 #include "git-compat-util.h"
 #include "builtin.h"
-#include "argv-array.h"
+#include "strvec.h"
 
 int cmd_annotate(int argc, const char **argv, const char *prefix)
 {
-	struct argv_array args = ARGV_ARRAY_INIT;
+	struct strvec args = STRVEC_INIT;
 	int i;
 
-	argv_array_pushl(&args, "annotate", "-c", NULL);
+	strvec_pushl(&args, "annotate", "-c", NULL);
 
 	for (i = 1; i < argc; i++) {
-		argv_array_push(&args, argv[i]);
+		strvec_push(&args, argv[i]);
 	}
 
-	return cmd_blame(args.argc, args.argv, prefix);
+	return cmd_blame(args.nr, args.v, prefix);
 }
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index ec49962..7dcc1b5 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -4,7 +4,7 @@
 #include "bisect.h"
 #include "refs.h"
 #include "dir.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "run-command.h"
 #include "prompt.h"
 #include "quote.h"
@@ -13,13 +13,13 @@
 static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
 static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
 static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
-static GIT_PATH_FUNC(git_path_bisect_head, "BISECT_HEAD")
 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
 static GIT_PATH_FUNC(git_path_head_name, "head-name")
 static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
+static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 
 static const char * const git_bisect_helper_usage[] = {
-	N_("git bisect--helper --next-all [--no-checkout]"),
+	N_("git bisect--helper --next-all"),
 	N_("git bisect--helper --write-terms <bad_term> <good_term>"),
 	N_("git bisect--helper --bisect-clean-state"),
 	N_("git bisect--helper --bisect-reset [<commit>]"),
@@ -27,8 +27,8 @@
 	N_("git bisect--helper --bisect-check-and-set-terms <command> <good_term> <bad_term>"),
 	N_("git bisect--helper --bisect-next-check <good_term> <bad_term> [<term>]"),
 	N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
-	N_("git bisect--helper --bisect-start [--term-{old,good}=<term> --term-{new,bad}=<term>]"
-					     "[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]"),
+	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
+					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
 	NULL
 };
 
@@ -164,19 +164,19 @@
 		strbuf_addstr(&branch, commit);
 	}
 
-	if (!file_exists(git_path_bisect_head())) {
-		struct argv_array argv = ARGV_ARRAY_INIT;
+	if (!ref_exists("BISECT_HEAD")) {
+		struct strvec argv = STRVEC_INIT;
 
-		argv_array_pushl(&argv, "checkout", branch.buf, "--", NULL);
-		if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
+		strvec_pushl(&argv, "checkout", branch.buf, "--", NULL);
+		if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
 			error(_("could not check out original"
 				" HEAD '%s'. Try 'git bisect"
 				" reset <commit>'."), branch.buf);
 			strbuf_release(&branch);
-			argv_array_clear(&argv);
+			strvec_clear(&argv);
 			return -1;
 		}
-		argv_array_clear(&argv);
+		strvec_clear(&argv);
 	}
 
 	strbuf_release(&branch);
@@ -421,9 +421,10 @@
 	return res;
 }
 
-static int bisect_start(struct bisect_terms *terms, int no_checkout,
-			const char **argv, int argc)
+static int bisect_start(struct bisect_terms *terms, const char **argv, int argc)
 {
+	int no_checkout = 0;
+	int first_parent_only = 0;
 	int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
 	int flags, pathspec_pos, res = 0;
 	struct string_list revs = STRING_LIST_INIT_DUP;
@@ -453,6 +454,8 @@
 			break;
 		} else if (!strcmp(arg, "--no-checkout")) {
 			no_checkout = 1;
+		} else if (!strcmp(arg, "--first-parent")) {
+			first_parent_only = 1;
 		} else if (!strcmp(arg, "--term-good") ||
 			 !strcmp(arg, "--term-old")) {
 			i++;
@@ -526,11 +529,11 @@
 		strbuf_read_file(&start_head, git_path_bisect_start(), 0);
 		strbuf_trim(&start_head);
 		if (!no_checkout) {
-			struct argv_array argv = ARGV_ARRAY_INIT;
+			struct strvec argv = STRVEC_INIT;
 
-			argv_array_pushl(&argv, "checkout", start_head.buf,
-					 "--", NULL);
-			if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
+			strvec_pushl(&argv, "checkout", start_head.buf,
+				     "--", NULL);
+			if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
 				res = error(_("checking out '%s' failed."
 						 " Try 'git bisect start "
 						 "<valid-branch>'."),
@@ -577,6 +580,9 @@
 	 */
 	write_file(git_path_bisect_start(), "%s\n", start_head.buf);
 
+	if (first_parent_only)
+		write_file(git_path_bisect_first_parent(), "\n");
+
 	if (no_checkout) {
 		if (get_oid(start_head.buf, &oid) < 0) {
 			res = error(_("invalid ref: '%s'"), start_head.buf);
@@ -632,7 +638,7 @@
 		BISECT_TERMS,
 		BISECT_START
 	} cmdmode = 0;
-	int no_checkout = 0, res = 0, nolog = 0;
+	int res = 0, nolog = 0;
 	struct option options[] = {
 		OPT_CMDMODE(0, "next-all", &cmdmode,
 			 N_("perform 'git bisect next'"), NEXT_ALL),
@@ -654,8 +660,6 @@
 			 N_("print out the bisect terms"), BISECT_TERMS),
 		OPT_CMDMODE(0, "bisect-start", &cmdmode,
 			 N_("start the bisect session"), BISECT_START),
-		OPT_BOOL(0, "no-checkout", &no_checkout,
-			 N_("update BISECT_HEAD instead of checking out the current commit")),
 		OPT_BOOL(0, "no-log", &nolog,
 			 N_("no log for BISECT_WRITE")),
 		OPT_END()
@@ -671,7 +675,7 @@
 
 	switch (cmdmode) {
 	case NEXT_ALL:
-		res = bisect_next_all(the_repository, prefix, no_checkout);
+		res = bisect_next_all(the_repository, prefix);
 		break;
 	case WRITE_TERMS:
 		if (argc != 2)
@@ -713,7 +717,7 @@
 		break;
 	case BISECT_START:
 		set_terms(&terms, "bad", "good");
-		res = bisect_start(&terms, no_checkout, argv, argc);
+		res = bisect_start(&terms, argv, argc);
 		break;
 	default:
 		return error("BUG: unknown subcommand '%d'", cmdmode);
diff --git a/builtin/blame.c b/builtin/blame.c
index 94ef57c..eb513fb 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -842,7 +842,7 @@
 	const char *contents_from = NULL;
 	const struct option options[] = {
 		OPT_BOOL(0, "incremental", &incremental, N_("Show blame entries as we find them, incrementally")),
-		OPT_BOOL('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")),
+		OPT_BOOL('b', NULL, &blank_boundary, N_("Do not show object names of boundary commits (Default: off)")),
 		OPT_BOOL(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")),
 		OPT_BOOL(0, "show-stats", &show_stats, N_("Show work cost statistics")),
 		OPT_BOOL(0, "progress", &show_progress, N_("Force progress reporting")),
diff --git a/bugreport.c b/builtin/bugreport.c
similarity index 94%
rename from bugreport.c
rename to builtin/bugreport.c
index 09579e2..3ad4b9b 100644
--- a/bugreport.c
+++ b/builtin/bugreport.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
 #include "parse-options.h"
 #include "strbuf.h"
 #include "help.h"
@@ -119,7 +119,7 @@
 	strbuf_addf(buf, "\n\n[%s]\n", title);
 }
 
-int cmd_main(int argc, const char **argv)
+int cmd_bugreport(int argc, const char **argv, const char *prefix)
 {
 	struct strbuf buffer = STRBUF_INIT;
 	struct strbuf report_path = STRBUF_INIT;
@@ -127,8 +127,6 @@
 	time_t now = time(NULL);
 	char *option_output = NULL;
 	char *option_suffix = "%Y-%m-%d-%H%M";
-	int nongit_ok = 0;
-	const char *prefix = NULL;
 	const char *user_relative_path = NULL;
 
 	const struct option bugreport_options[] = {
@@ -139,8 +137,6 @@
 		OPT_END()
 	};
 
-	prefix = setup_git_directory_gently(&nongit_ok);
-
 	argc = parse_options(argc, argv, prefix, bugreport_options,
 			     bugreport_usage, 0);
 
@@ -170,15 +166,13 @@
 	get_system_info(&buffer);
 
 	get_header(&buffer, _("Enabled Hooks"));
-	get_populated_hooks(&buffer, nongit_ok);
+	get_populated_hooks(&buffer, !startup_info->have_repository);
 
 	/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
 	report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
 
-	if (report < 0) {
-		UNLEAK(report_path);
+	if (report < 0)
 		die(_("couldn't create a new file at '%s'"), report_path.buf);
-	}
 
 	if (write_in_full(report, buffer.buf, buffer.len) < 0)
 		die_errno(_("unable to write to %s"), report_path.buf);
diff --git a/builtin/bundle.c b/builtin/bundle.c
index f049d27..ea69481 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -1,5 +1,5 @@
 #include "builtin.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "parse-options.h"
 #include "cache.h"
 #include "bundle.h"
@@ -59,7 +59,8 @@
 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 strvec pack_opts;
+	int version = -1;
 
 	struct option options[] = {
 		OPT_SET_INT('q', "quiet", &progress,
@@ -71,6 +72,8 @@
 		OPT_BOOL(0, "all-progress-implied",
 			 &all_progress_implied,
 			 N_("similar to --all-progress when progress meter is shown")),
+		OPT_INTEGER(0, "version", &version,
+			    N_("specify bundle format version")),
 		OPT_END()
 	};
 	const char* bundle_file;
@@ -79,19 +82,19 @@
 			builtin_bundle_create_usage, options, &bundle_file);
 	/* bundle internals use argv[1] as further parameters */
 
-	argv_array_init(&pack_opts);
+	strvec_init(&pack_opts);
 	if (progress == 0)
-		argv_array_push(&pack_opts, "--quiet");
+		strvec_push(&pack_opts, "--quiet");
 	else if (progress == 1)
-		argv_array_push(&pack_opts, "--progress");
+		strvec_push(&pack_opts, "--progress");
 	else if (progress == 2)
-		argv_array_push(&pack_opts, "--all-progress");
+		strvec_push(&pack_opts, "--all-progress");
 	if (progress && all_progress_implied)
-		argv_array_push(&pack_opts, "--all-progress-implied");
+		strvec_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);
+	return !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts, version);
 }
 
 static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c
index ea5d0ae..3c65274 100644
--- a/builtin/check-ignore.c
+++ b/builtin/check-ignore.c
@@ -180,7 +180,7 @@
 	if (!no_index && read_cache() < 0)
 		die(_("index file corrupt"));
 
-	memset(&dir, 0, sizeof(dir));
+	dir_init(&dir);
 	setup_standard_excludes(&dir);
 
 	if (stdin_paths) {
@@ -190,7 +190,7 @@
 		maybe_flush_or_die(stdout, "ignore to stdout");
 	}
 
-	clear_directory(&dir);
+	dir_clear(&dir);
 
 	return !num_ignored;
 }
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 6350df8..0951f8f 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -239,6 +239,8 @@
 	mmbuffer_t result_buf;
 	struct object_id threeway[3];
 	unsigned mode = 0;
+	struct ll_merge_options ll_opts;
+	int renormalize = 0;
 
 	memset(threeway, 0, sizeof(threeway));
 	while (pos < active_nr) {
@@ -259,13 +261,12 @@
 	read_mmblob(&ours, &threeway[1]);
 	read_mmblob(&theirs, &threeway[2]);
 
-	/*
-	 * NEEDSWORK: re-create conflicts from merges with
-	 * merge.renormalize set, too
-	 */
+	memset(&ll_opts, 0, sizeof(ll_opts));
+	git_config_get_bool("merge.renormalize", &renormalize);
+	ll_opts.renormalize = renormalize;
 	status = ll_merge(&result_buf, path, &ancestor, "base",
 			  &ours, "ours", &theirs, "theirs",
-			  state->istate, NULL);
+			  state->istate, &ll_opts);
 	free(ancestor.ptr);
 	free(ours.ptr);
 	free(theirs.ptr);
@@ -771,13 +772,6 @@
 			 */
 
 			add_files_to_cache(NULL, NULL, 0);
-			/*
-			 * NEEDSWORK: carrying over local changes
-			 * when branches have different end-of-line
-			 * normalization (or clean+smudge rules) is
-			 * a pain; plumb in an option to set
-			 * o.renormalize?
-			 */
 			init_merge_options(&o, the_repository);
 			o.verbosity = 0;
 			work = write_in_core_index_as_tree(the_repository);
@@ -1126,8 +1120,10 @@
 	if (!check_refname_format(new_branch_info->path, 0) &&
 	    !read_ref(new_branch_info->path, &branch_rev))
 		oidcpy(rev, &branch_rev);
-	else
+	else {
+		free((char *)new_branch_info->path);
 		new_branch_info->path = NULL; /* not an existing branch */
+	}
 
 	new_branch_info->commit = lookup_commit_reference_gently(the_repository, rev, 1);
 	if (!new_branch_info->commit) {
@@ -1713,6 +1709,8 @@
 		die(_("--pathspec-file-nul requires --pathspec-from-file"));
 	}
 
+	opts->pathspec.recursive = 1;
+
 	if (opts->pathspec.nr) {
 		if (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)
 			die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
diff --git a/builtin/clean.c b/builtin/clean.c
index 5a9c29a..e53ea52 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -667,7 +667,7 @@
 		if (!confirm.len)
 			break;
 
-		memset(&dir, 0, sizeof(dir));
+		dir_init(&dir);
 		pl = add_pattern_list(&dir, EXC_CMDL, "manual exclude");
 		ignore_list = strbuf_split_max(&confirm, ' ', 0);
 
@@ -698,7 +698,7 @@
 		}
 
 		strbuf_list_free(ignore_list);
-		clear_directory(&dir);
+		dir_clear(&dir);
 	}
 
 	strbuf_release(&confirm);
@@ -923,7 +923,7 @@
 	argc = parse_options(argc, argv, prefix, options, builtin_clean_usage,
 			     0);
 
-	memset(&dir, 0, sizeof(dir));
+	dir_init(&dir);
 	if (!interactive && !dry_run && !force) {
 		if (config_set)
 			die(_("clean.requireForce set to true and neither -i, -n, nor -f given; "
@@ -1021,11 +1021,7 @@
 		string_list_append(&del_list, rel);
 	}
 
-	for (i = 0; i < dir.nr; i++)
-		free(dir.entries[i]);
-
-	for (i = 0; i < dir.ignored_nr; i++)
-		free(dir.ignored[i]);
+	dir_clear(&dir);
 
 	if (interactive && del_list.nr > 0)
 		interactive_main_loop();
diff --git a/builtin/clone.c b/builtin/clone.c
index bef7074..b087ee4 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -742,9 +742,9 @@
 
 static int git_sparse_checkout_init(const char *repo)
 {
-	struct argv_array argv = ARGV_ARRAY_INIT;
+	struct strvec argv = STRVEC_INIT;
 	int result = 0;
-	argv_array_pushl(&argv, "-C", repo, "sparse-checkout", "init", NULL);
+	strvec_pushl(&argv, "-C", repo, "sparse-checkout", "init", NULL);
 
 	/*
 	 * We must apply the setting in the current process
@@ -752,12 +752,12 @@
 	 */
 	core_apply_sparse_checkout = 1;
 
-	if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
+	if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
 		error(_("failed to initialize sparse-checkout"));
 		result = 1;
 	}
 
-	argv_array_clear(&argv);
+	strvec_clear(&argv);
 	return result;
 }
 
@@ -819,33 +819,33 @@
 			   oid_to_hex(&oid), "1", NULL);
 
 	if (!err && (option_recurse_submodules.nr > 0)) {
-		struct argv_array args = ARGV_ARRAY_INIT;
-		argv_array_pushl(&args, "submodule", "update", "--require-init", "--recursive", NULL);
+		struct strvec args = STRVEC_INIT;
+		strvec_pushl(&args, "submodule", "update", "--require-init", "--recursive", NULL);
 
 		if (option_shallow_submodules == 1)
-			argv_array_push(&args, "--depth=1");
+			strvec_push(&args, "--depth=1");
 
 		if (max_jobs != -1)
-			argv_array_pushf(&args, "--jobs=%d", max_jobs);
+			strvec_pushf(&args, "--jobs=%d", max_jobs);
 
 		if (submodule_progress)
-			argv_array_push(&args, "--progress");
+			strvec_push(&args, "--progress");
 
 		if (option_verbosity < 0)
-			argv_array_push(&args, "--quiet");
+			strvec_push(&args, "--quiet");
 
 		if (option_remote_submodules) {
-			argv_array_push(&args, "--remote");
-			argv_array_push(&args, "--no-fetch");
+			strvec_push(&args, "--remote");
+			strvec_push(&args, "--no-fetch");
 		}
 
 		if (option_single_branch >= 0)
-			argv_array_push(&args, option_single_branch ?
+			strvec_push(&args, option_single_branch ?
 					       "--single-branch" :
 					       "--no-single-branch");
 
-		err = run_command_v_opt(args.argv, RUN_GIT_CMD);
-		argv_array_clear(&args);
+		err = run_command_v_opt(args.v, RUN_GIT_CMD);
+		strvec_clear(&args);
 	}
 
 	return err;
@@ -946,7 +946,7 @@
 	int is_bundle = 0, is_local;
 	const char *repo_name, *repo, *work_tree, *git_dir;
 	char *path, *dir, *display_repo = NULL;
-	int dest_exists;
+	int dest_exists, real_dest_exists = 0;
 	const struct ref *refs, *remote_head;
 	const struct ref *remote_head_points_at;
 	const struct ref *our_head_points_at;
@@ -961,7 +961,7 @@
 	int err = 0, complete_refs_before_fetch = 1;
 	int submodule_progress;
 
-	struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
+	struct strvec ref_prefixes = STRVEC_INIT;
 
 	packet_trace_identity("clone");
 	argc = parse_options(argc, argv, prefix, builtin_clone_options,
@@ -1021,6 +1021,14 @@
 		die(_("destination path '%s' already exists and is not "
 			"an empty directory."), dir);
 
+	if (real_git_dir) {
+		real_dest_exists = path_exists(real_git_dir);
+		if (real_dest_exists && !is_empty_dir(real_git_dir))
+			die(_("repository path '%s' already exists and is not "
+				"an empty directory."), real_git_dir);
+	}
+
+
 	strbuf_addf(&reflog_msg, "clone: from %s",
 		    display_repo ? display_repo : repo);
 	free(display_repo);
@@ -1057,7 +1065,7 @@
 	}
 
 	if (real_git_dir) {
-		if (path_exists(real_git_dir))
+		if (real_dest_exists)
 			junk_git_dir_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
 		junk_git_dir = real_git_dir;
 	} else {
@@ -1211,12 +1219,12 @@
 		transport->smart_options->check_self_contained_and_connected = 1;
 
 
-	argv_array_push(&ref_prefixes, "HEAD");
+	strvec_push(&ref_prefixes, "HEAD");
 	refspec_ref_prefixes(&remote->fetch, &ref_prefixes);
 	if (option_branch)
 		expand_ref_prefix(&ref_prefixes, option_branch);
 	if (!option_no_tags)
-		argv_array_push(&ref_prefixes, "refs/tags/");
+		strvec_push(&ref_prefixes, "refs/tags/");
 
 	refs = transport_get_remote_refs(transport, &ref_prefixes);
 
@@ -1327,6 +1335,6 @@
 	strbuf_release(&default_refspec);
 	junk_mode = JUNK_LEAVE_ALL;
 
-	argv_array_clear(&ref_prefixes);
+	strvec_clear(&ref_prefixes);
 	return err;
 }
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 16c9f61..523501f 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -201,6 +201,7 @@
 	};
 
 	opts.progress = isatty(2);
+	opts.enable_changed_paths = -1;
 	split_opts.size_multiple = 2;
 	split_opts.max_commits = 0;
 	split_opts.expire_time = 0;
@@ -221,7 +222,9 @@
 		flags |= COMMIT_GRAPH_WRITE_SPLIT;
 	if (opts.progress)
 		flags |= COMMIT_GRAPH_WRITE_PROGRESS;
-	if (opts.enable_changed_paths ||
+	if (!opts.enable_changed_paths)
+		flags |= COMMIT_GRAPH_NO_WRITE_BLOOM_FILTERS;
+	if (opts.enable_changed_paths == 1 ||
 	    git_env_bool(GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS, 0))
 		flags |= COMMIT_GRAPH_WRITE_BLOOM_FILTERS;
 
diff --git a/builtin/commit.c b/builtin/commit.c
index d1b7396..5d91b13 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -847,21 +847,19 @@
 			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
 				!merge_contains_scissors)
 				wt_status_add_cut_line(s->fp);
-			status_printf_ln(s, GIT_COLOR_NORMAL,
-			    whence == FROM_MERGE
-				? _("\n"
-					"It looks like you may be committing a merge.\n"
-					"If this is not correct, please remove the file\n"
-					"	%s\n"
-					"and try again.\n")
-				: _("\n"
-					"It looks like you may be committing a cherry-pick.\n"
-					"If this is not correct, please remove the file\n"
-					"	%s\n"
-					"and try again.\n"),
+			status_printf_ln(
+				s, GIT_COLOR_NORMAL,
 				whence == FROM_MERGE ?
-					git_path_merge_head(the_repository) :
-					git_path_cherry_pick_head(the_repository));
+					      _("\n"
+					  "It looks like you may be committing a merge.\n"
+					  "If this is not correct, please run\n"
+					  "	git update-ref -d MERGE_HEAD\n"
+					  "and try again.\n") :
+					      _("\n"
+					  "It looks like you may be committing a cherry-pick.\n"
+					  "If this is not correct, please run\n"
+					  "	git update-ref -d CHERRY_PICK_HEAD\n"
+					  "and try again.\n"));
 		}
 
 		fprintf(s->fp, "\n");
@@ -1005,15 +1003,15 @@
 		return 0;
 
 	if (use_editor) {
-		struct argv_array env = ARGV_ARRAY_INIT;
+		struct strvec env = STRVEC_INIT;
 
-		argv_array_pushf(&env, "GIT_INDEX_FILE=%s", index_file);
-		if (launch_editor(git_path_commit_editmsg(), NULL, env.argv)) {
+		strvec_pushf(&env, "GIT_INDEX_FILE=%s", index_file);
+		if (launch_editor(git_path_commit_editmsg(), NULL, env.v)) {
 			fprintf(stderr,
 			_("Please supply the message using either -m or -F option.\n"));
 			exit(1);
 		}
-		argv_array_clear(&env);
+		strvec_clear(&env);
 	}
 
 	if (!no_verify &&
@@ -1674,8 +1672,8 @@
 	}
 
 	if (commit_tree_extended(sb.buf, sb.len, &active_cache_tree->oid,
-				 parents, &oid, author_ident.buf, sign_commit,
-				 extra)) {
+				 parents, &oid, author_ident.buf, NULL,
+				 sign_commit, extra)) {
 		rollback_index_files();
 		die(_("failed to write commit object"));
 	}
diff --git a/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
similarity index 90%
rename from credential-cache--daemon.c
rename to builtin/credential-cache--daemon.c
index ec1271f..c61f123 100644
--- a/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -1,9 +1,12 @@
-#include "cache.h"
+#include "builtin.h"
+#include "parse-options.h"
+
+#ifndef NO_UNIX_SOCKETS
+
 #include "config.h"
 #include "tempfile.h"
 #include "credential.h"
 #include "unix-socket.h"
-#include "parse-options.h"
 
 struct credential_cache_entry {
 	struct credential item;
@@ -257,7 +260,7 @@
 	free(path_copy);
 }
 
-int cmd_main(int argc, const char **argv)
+int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
 {
 	struct tempfile *socket_file;
 	const char *socket_path;
@@ -275,7 +278,7 @@
 
 	git_config_get_bool("credentialcache.ignoresighup", &ignore_sighup);
 
-	argc = parse_options(argc, argv, NULL, options, usage, 0);
+	argc = parse_options(argc, argv, prefix, options, usage, 0);
 	socket_path = argv[0];
 
 	if (!socket_path)
@@ -295,3 +298,21 @@
 
 	return 0;
 }
+
+#else
+
+int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
+{
+	const char * const usage[] = {
+		"git credential-cache--daemon [options] <action>",
+		"",
+		"credential-cache--daemon is disabled in this build of Git",
+		NULL
+	};
+	struct option options[] = { OPT_END() };
+
+	argc = parse_options(argc, argv, prefix, options, usage, 0);
+	die(_("credential-cache--daemon unavailable; no unix socket support"));
+}
+
+#endif /* NO_UNIX_SOCKET */
diff --git a/credential-cache.c b/builtin/credential-cache.c
similarity index 80%
rename from credential-cache.c
rename to builtin/credential-cache.c
index 1cccc3a..9b3f709 100644
--- a/credential-cache.c
+++ b/builtin/credential-cache.c
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "builtin.h"
+#include "parse-options.h"
+
+#ifndef NO_UNIX_SOCKETS
+
 #include "credential.h"
 #include "string-list.h"
-#include "parse-options.h"
 #include "unix-socket.h"
 #include "run-command.h"
 
@@ -39,13 +42,13 @@
 static void spawn_daemon(const char *socket)
 {
 	struct child_process daemon = CHILD_PROCESS_INIT;
-	const char *argv[] = { NULL, NULL, NULL };
 	char buf[128];
 	int r;
 
-	argv[0] = "git-credential-cache--daemon";
-	argv[1] = socket;
-	daemon.argv = argv;
+	strvec_pushl(&daemon.args,
+		     "credential-cache--daemon", socket,
+		     NULL);
+	daemon.git_cmd = 1;
 	daemon.no_stdin = 1;
 	daemon.out = -1;
 
@@ -96,7 +99,7 @@
 	return socket;
 }
 
-int cmd_main(int argc, const char **argv)
+int cmd_credential_cache(int argc, const char **argv, const char *prefix)
 {
 	char *socket_path = NULL;
 	int timeout = 900;
@@ -113,7 +116,7 @@
 		OPT_END()
 	};
 
-	argc = parse_options(argc, argv, NULL, options, usage, 0);
+	argc = parse_options(argc, argv, prefix, options, usage, 0);
 	if (!argc)
 		usage_with_options(usage, options);
 	op = argv[0];
@@ -134,3 +137,21 @@
 
 	return 0;
 }
+
+#else
+
+int cmd_credential_cache(int argc, const char **argv, const char *prefix)
+{
+	const char * const usage[] = {
+		"git credential-cache [options] <action>",
+		"",
+		"credential-cache is disabled in this build of Git",
+		NULL
+	};
+	struct option options[] = { OPT_END() };
+
+	argc = parse_options(argc, argv, prefix, options, usage, 0);
+	die(_("credential-cache unavailable; no unix socket support"));
+}
+
+#endif /* NO_UNIX_SOCKETS */
diff --git a/credential-store.c b/builtin/credential-store.c
similarity index 96%
rename from credential-store.c
rename to builtin/credential-store.c
index 294e771..5331ab1 100644
--- a/credential-store.c
+++ b/builtin/credential-store.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
 #include "lockfile.h"
 #include "credential.h"
 #include "string-list.h"
@@ -143,7 +143,7 @@
 			return; /* Found credential */
 }
 
-int cmd_main(int argc, const char **argv)
+int cmd_credential_store(int argc, const char **argv, const char *prefix)
 {
 	const char * const usage[] = {
 		"git credential-store [<options>] <action>",
@@ -161,7 +161,7 @@
 
 	umask(077);
 
-	argc = parse_options(argc, (const char **)argv, NULL, options, usage, 0);
+	argc = parse_options(argc, (const char **)argv, prefix, options, usage, 0);
 	if (argc != 1)
 		usage_with_options(usage, options);
 	op = argv[0];
diff --git a/builtin/describe.c b/builtin/describe.c
index 21d2cb9..7668591 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -12,7 +12,7 @@
 #include "revision.h"
 #include "diff.h"
 #include "hashmap.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "run-command.h"
 #include "object-store.h"
 #include "list-objects.h"
@@ -501,15 +501,15 @@
 static void describe_blob(struct object_id oid, struct strbuf *dst)
 {
 	struct rev_info revs;
-	struct argv_array args = ARGV_ARRAY_INIT;
+	struct strvec args = STRVEC_INIT;
 	struct process_commit_data pcd = { null_oid, oid, dst, &revs};
 
-	argv_array_pushl(&args, "internal: The first arg is not parsed",
-		"--objects", "--in-commit-order", "--reverse", "HEAD",
-		NULL);
+	strvec_pushl(&args, "internal: The first arg is not parsed",
+		     "--objects", "--in-commit-order", "--reverse", "HEAD",
+		     NULL);
 
 	repo_init_revisions(the_repository, &revs, NULL);
-	if (setup_revisions(args.argc, args.argv, &revs, NULL) > 1)
+	if (setup_revisions(args.nr, args.v, &revs, NULL) > 1)
 		BUG("setup_revisions could not handle all args?");
 
 	if (prepare_revision_walk(&revs))
@@ -594,26 +594,26 @@
 
 	if (contains) {
 		struct string_list_item *item;
-		struct argv_array args;
+		struct strvec args;
 
-		argv_array_init(&args);
-		argv_array_pushl(&args, "name-rev",
-				 "--peel-tag", "--name-only", "--no-undefined",
-				 NULL);
+		strvec_init(&args);
+		strvec_pushl(&args, "name-rev",
+			     "--peel-tag", "--name-only", "--no-undefined",
+			     NULL);
 		if (always)
-			argv_array_push(&args, "--always");
+			strvec_push(&args, "--always");
 		if (!all) {
-			argv_array_push(&args, "--tags");
+			strvec_push(&args, "--tags");
 			for_each_string_list_item(item, &patterns)
-				argv_array_pushf(&args, "--refs=refs/tags/%s", item->string);
+				strvec_pushf(&args, "--refs=refs/tags/%s", item->string);
 			for_each_string_list_item(item, &exclude_patterns)
-				argv_array_pushf(&args, "--exclude=refs/tags/%s", item->string);
+				strvec_pushf(&args, "--exclude=refs/tags/%s", item->string);
 		}
 		if (argc)
-			argv_array_pushv(&args, argv);
+			strvec_pushv(&args, argv);
 		else
-			argv_array_push(&args, "HEAD");
-		return cmd_name_rev(args.argc, args.argv, prefix);
+			strvec_push(&args, "HEAD");
+		return cmd_name_rev(args.nr, args.v, prefix);
 	}
 
 	hashmap_init(&names, commit_name_neq, NULL, 0);
@@ -624,7 +624,7 @@
 	if (argc == 0) {
 		if (broken) {
 			struct child_process cp = CHILD_PROCESS_INIT;
-			argv_array_pushv(&cp.args, diff_index_args);
+			strvec_pushv(&cp.args, diff_index_args);
 			cp.git_cmd = 1;
 			cp.no_stdin = 1;
 			cp.no_stdout = 1;
@@ -646,7 +646,7 @@
 		} else if (dirty) {
 			struct lock_file index_lock = LOCK_INIT;
 			struct rev_info revs;
-			struct argv_array args = ARGV_ARRAY_INIT;
+			struct strvec args = STRVEC_INIT;
 			int fd, result;
 
 			setup_work_tree();
@@ -658,8 +658,8 @@
 				repo_update_index_if_able(the_repository, &index_lock);
 
 			repo_init_revisions(the_repository, &revs, prefix);
-			argv_array_pushv(&args, diff_index_args);
-			if (setup_revisions(args.argc, args.argv, &revs, NULL) != 1)
+			strvec_pushv(&args, diff_index_args);
+			if (setup_revisions(args.nr, args.v, &revs, NULL) != 1)
 				BUG("malformed internal diff-index command line");
 			result = run_diff_index(&revs, 0);
 
diff --git a/builtin/difftool.c b/builtin/difftool.c
index c280e68..7ac432b 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -18,7 +18,7 @@
 #include "run-command.h"
 #include "exec-cmd.h"
 #include "parse-options.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "strbuf.h"
 #include "lockfile.h"
 #include "object-store.h"
@@ -210,10 +210,10 @@
 	strbuf_addf(&index_env, "GIT_INDEX_FILE=%s", index_path);
 	env[0] = index_env.buf;
 
-	argv_array_pushl(&update_index.args,
-			 "--git-dir", git_dir, "--work-tree", workdir,
-			 "update-index", "--really-refresh", "-q",
-			 "--unmerged", NULL);
+	strvec_pushl(&update_index.args,
+		     "--git-dir", git_dir, "--work-tree", workdir,
+		     "update-index", "--really-refresh", "-q",
+		     "--unmerged", NULL);
 	update_index.no_stdin = 1;
 	update_index.no_stdout = 1;
 	update_index.no_stderr = 1;
@@ -225,9 +225,9 @@
 	/* Ignore any errors of update-index */
 	run_command(&update_index);
 
-	argv_array_pushl(&diff_files.args,
-			 "--git-dir", git_dir, "--work-tree", workdir,
-			 "diff-files", "--name-only", "-z", NULL);
+	strvec_pushl(&diff_files.args,
+		     "--git-dir", git_dir, "--work-tree", workdir,
+		     "diff-files", "--name-only", "-z", NULL);
 	diff_files.no_stdin = 1;
 	diff_files.git_cmd = 1;
 	diff_files.use_shell = 0;
@@ -393,10 +393,10 @@
 	child.clean_on_exit = 1;
 	child.dir = prefix;
 	child.out = -1;
-	argv_array_pushl(&child.args, "diff", "--raw", "--no-abbrev", "-z",
-			 NULL);
+	strvec_pushl(&child.args, "diff", "--raw", "--no-abbrev", "-z",
+		     NULL);
 	for (i = 0; i < argc; i++)
-		argv_array_push(&child.args, argv[i]);
+		strvec_push(&child.args, argv[i]);
 	if (start_command(&child))
 		die("could not obtain raw diff");
 	fp = xfdopen(child.out, "r");
@@ -667,7 +667,7 @@
 static int run_file_diff(int prompt, const char *prefix,
 			 int argc, const char **argv)
 {
-	struct argv_array args = ARGV_ARRAY_INIT;
+	struct strvec args = STRVEC_INIT;
 	const char *env[] = {
 		"GIT_PAGER=", "GIT_EXTERNAL_DIFF=git-difftool--helper", NULL,
 		NULL
@@ -680,10 +680,10 @@
 		env[2] = "GIT_DIFFTOOL_NO_PROMPT=true";
 
 
-	argv_array_push(&args, "diff");
+	strvec_push(&args, "diff");
 	for (i = 0; i < argc; i++)
-		argv_array_push(&args, argv[i]);
-	ret = run_command_v_opt_cd_env(args.argv, RUN_GIT_CMD, prefix, env);
+		strvec_push(&args, argv[i]);
+	ret = run_command_v_opt_cd_env(args.v, RUN_GIT_CMD, prefix, env);
 	exit(ret);
 }
 
diff --git a/fast-import.c b/builtin/fast-import.c
similarity index 99%
rename from fast-import.c
rename to builtin/fast-import.c
index 0dfa14d..1c85eaf 100644
--- a/fast-import.c
+++ b/builtin/fast-import.c
@@ -526,14 +526,6 @@
 	return r;
 }
 
-static char *pool_strdup(const char *s)
-{
-	size_t len = strlen(s) + 1;
-	char *r = mem_pool_alloc(&fi_mem_pool, len);
-	memcpy(r, s, len);
-	return r;
-}
-
 static void insert_mark(struct mark_set *s, uintmax_t idnum, struct object_entry *oe)
 {
 	while ((idnum >> s->shift) >= 1024) {
@@ -615,7 +607,7 @@
 		die("Branch name doesn't conform to GIT standards: %s", name);
 
 	b = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct branch));
-	b->name = pool_strdup(name);
+	b->name = mem_pool_strdup(&fi_mem_pool, name);
 	b->table_next_branch = branch_table[hc];
 	b->branch_tree.versions[0].mode = S_IFDIR;
 	b->branch_tree.versions[1].mode = S_IFDIR;
@@ -843,9 +835,9 @@
 	unpack.in = p->pack_fd;
 	unpack.git_cmd = 1;
 	unpack.stdout_to_stderr = 1;
-	argv_array_push(&unpack.args, "unpack-objects");
+	strvec_push(&unpack.args, "unpack-objects");
 	if (!show_stats)
-		argv_array_push(&unpack.args, "-q");
+		strvec_push(&unpack.args, "-q");
 
 	return run_command(&unpack);
 }
@@ -2806,7 +2798,7 @@
 
 	t = mem_pool_alloc(&fi_mem_pool, sizeof(struct tag));
 	memset(t, 0, sizeof(struct tag));
-	t->name = pool_strdup(arg);
+	t->name = mem_pool_strdup(&fi_mem_pool, arg);
 	if (last_tag)
 		last_tag->next_tag = t;
 	else
@@ -3519,14 +3511,13 @@
 	build_mark_map(&sub_marks_from, &sub_marks_to);
 }
 
-int cmd_main(int argc, const char **argv)
+int cmd_fast_import(int argc, const char **argv, const char *prefix)
 {
 	unsigned int i;
 
 	if (argc == 2 && !strcmp(argv[1], "-h"))
 		usage(fast_import_usage);
 
-	setup_git_directory();
 	reset_pack_idx_option(&pack_idx_opts);
 	git_pack_config();
 
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index bbb5c96..58b7c1f 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -153,10 +153,6 @@
 			args.from_promisor = 1;
 			continue;
 		}
-		if (!strcmp("--no-dependents", arg)) {
-			args.no_dependents = 1;
-			continue;
-		}
 		if (skip_prefix(arg, ("--" CL_ARG__FILTER "="), &arg)) {
 			parse_list_objects_filter(&args.filter_options, arg);
 			continue;
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 82ac4be..a6d3268 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -19,7 +19,7 @@
 #include "submodule-config.h"
 #include "submodule.h"
 #include "connected.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "utf8.h"
 #include "packfile.h"
 #include "list-objects-filter-options.h"
@@ -56,6 +56,7 @@
 #define PRUNE_TAGS_BY_DEFAULT 0 /* do we prune tags by default? */
 
 static int all, append, dry_run, force, keep, multiple, update_head_ok;
+static int write_fetch_head = 1;
 static int verbosity, deepen_relative, set_upstream;
 static int progress = -1;
 static int enable_auto_gc = 1;
@@ -79,6 +80,7 @@
 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 stdin_refspecs = 0;
 
 static int git_fetch_config(const char *k, const char *v, void *cb)
 {
@@ -162,6 +164,8 @@
 		    PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
 	OPT_BOOL(0, "dry-run", &dry_run,
 		 N_("dry run")),
+	OPT_BOOL(0, "write-fetch-head", &write_fetch_head,
+		 N_("write fetched references to the FETCH_HEAD file")),
 	OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
 	OPT_BOOL('u', "update-head-ok", &update_head_ok,
 		    N_("allow updating of HEAD ref")),
@@ -202,6 +206,8 @@
 		 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_BOOL(0, "stdin", &stdin_refspecs,
+		 N_("accept refspecs from stdin")),
 	OPT_END()
 };
 
@@ -439,6 +445,7 @@
 	struct ref *orefs = NULL, **oref_tail = &orefs;
 
 	struct hashmap existing_refs;
+	int existing_refs_populated = 0;
 
 	if (rs->nr) {
 		struct refspec *fetch_refspec;
@@ -532,15 +539,18 @@
 
 	ref_map = ref_remove_duplicates(ref_map);
 
-	refname_hash_init(&existing_refs);
-	for_each_ref(add_one_refname, &existing_refs);
-
 	for (rm = ref_map; rm; rm = rm->next) {
 		if (rm->peer_ref) {
 			const char *refname = rm->peer_ref->name;
 			struct refname_hash_entry *peer_item;
 			unsigned int hash = strhash(refname);
 
+			if (!existing_refs_populated) {
+				refname_hash_init(&existing_refs);
+				for_each_ref(add_one_refname, &existing_refs);
+				existing_refs_populated = 1;
+			}
+
 			peer_item = hashmap_get_entry_from_hash(&existing_refs,
 						hash, refname,
 						struct refname_hash_entry, ent);
@@ -550,7 +560,8 @@
 			}
 		}
 	}
-	hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);
+	if (existing_refs_populated)
+		hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);
 
 	return ref_map;
 }
@@ -645,7 +656,7 @@
 	struct ref *rm;
 	const char *format = "full";
 
-	git_config_get_string_const("fetch.output", &format);
+	git_config_get_string_tmp("fetch.output", &format);
 	if (!strcasecmp(format, "full"))
 		compact_format = 0;
 	else if (!strcasecmp(format, "compact"))
@@ -893,7 +904,9 @@
 	const char *what, *kind;
 	struct ref *rm;
 	char *url;
-	const char *filename = dry_run ? "/dev/null" : git_path_fetch_head(the_repository);
+	const char *filename = (!write_fetch_head
+				? "/dev/null"
+				: git_path_fetch_head(the_repository));
 	int want_status;
 	int summary_width = transport_summary_width(ref_map);
 
@@ -1010,11 +1023,17 @@
 				rc |= update_local_ref(ref, what, rm, &note,
 						       summary_width);
 				free(ref);
-			} else
+			} else if (write_fetch_head || dry_run) {
+				/*
+				 * Display fetches written to FETCH_HEAD (or
+				 * would be written to FETCH_HEAD, if --dry-run
+				 * is set).
+				 */
 				format_display(&note, '*',
 					       *kind ? kind : "branch", NULL,
 					       *what ? what : "HEAD",
 					       "FETCH_HEAD", summary_width);
+			}
 			if (note.len) {
 				if (verbosity >= 0 && !shown_url) {
 					fprintf(stderr, _("From %.*s\n"),
@@ -1316,7 +1335,7 @@
 	int autotags = (transport->remote->fetch_tags == 1);
 	int retcode = 0;
 	const struct ref *remote_refs;
-	struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
+	struct strvec ref_prefixes = STRVEC_INIT;
 	int must_list_refs = 1;
 
 	if (tags == TAGS_DEFAULT) {
@@ -1327,7 +1346,7 @@
 	}
 
 	/* if not appending, truncate FETCH_HEAD */
-	if (!append && !dry_run) {
+	if (!append && write_fetch_head) {
 		retcode = truncate_fetch_head();
 		if (retcode)
 			goto cleanup;
@@ -1354,8 +1373,8 @@
 
 	if (tags == TAGS_SET || tags == TAGS_DEFAULT) {
 		must_list_refs = 1;
-		if (ref_prefixes.argc)
-			argv_array_push(&ref_prefixes, "refs/tags/");
+		if (ref_prefixes.nr)
+			strvec_push(&ref_prefixes, "refs/tags/");
 	}
 
 	if (must_list_refs) {
@@ -1365,7 +1384,7 @@
 	} else
 		remote_refs = NULL;
 
-	argv_array_clear(&ref_prefixes);
+	strvec_clear(&ref_prefixes);
 
 	ref_map = get_ref_map(transport->remote, remote_refs, rs,
 			      tags, &autotags);
@@ -1503,34 +1522,34 @@
 	return 1;
 }
 
-static void add_options_to_argv(struct argv_array *argv)
+static void add_options_to_argv(struct strvec *argv)
 {
 	if (dry_run)
-		argv_array_push(argv, "--dry-run");
+		strvec_push(argv, "--dry-run");
 	if (prune != -1)
-		argv_array_push(argv, prune ? "--prune" : "--no-prune");
+		strvec_push(argv, prune ? "--prune" : "--no-prune");
 	if (prune_tags != -1)
-		argv_array_push(argv, prune_tags ? "--prune-tags" : "--no-prune-tags");
+		strvec_push(argv, prune_tags ? "--prune-tags" : "--no-prune-tags");
 	if (update_head_ok)
-		argv_array_push(argv, "--update-head-ok");
+		strvec_push(argv, "--update-head-ok");
 	if (force)
-		argv_array_push(argv, "--force");
+		strvec_push(argv, "--force");
 	if (keep)
-		argv_array_push(argv, "--keep");
+		strvec_push(argv, "--keep");
 	if (recurse_submodules == RECURSE_SUBMODULES_ON)
-		argv_array_push(argv, "--recurse-submodules");
+		strvec_push(argv, "--recurse-submodules");
 	else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
-		argv_array_push(argv, "--recurse-submodules=on-demand");
+		strvec_push(argv, "--recurse-submodules=on-demand");
 	if (tags == TAGS_SET)
-		argv_array_push(argv, "--tags");
+		strvec_push(argv, "--tags");
 	else if (tags == TAGS_UNSET)
-		argv_array_push(argv, "--no-tags");
+		strvec_push(argv, "--no-tags");
 	if (verbosity >= 2)
-		argv_array_push(argv, "-v");
+		strvec_push(argv, "-v");
 	if (verbosity >= 1)
-		argv_array_push(argv, "-v");
+		strvec_push(argv, "-v");
 	else if (verbosity < 0)
-		argv_array_push(argv, "-q");
+		strvec_push(argv, "-q");
 
 }
 
@@ -1554,8 +1573,8 @@
 	remote = state->remotes->items[state->next++].string;
 	*task_cb = remote;
 
-	argv_array_pushv(&cp->args, state->argv);
-	argv_array_push(&cp->args, remote);
+	strvec_pushv(&cp->args, state->argv);
+	strvec_push(&cp->args, remote);
 	cp->git_cmd = 1;
 
 	if (verbosity >= 0)
@@ -1592,22 +1611,22 @@
 static int fetch_multiple(struct string_list *list, int max_children)
 {
 	int i, result = 0;
-	struct argv_array argv = ARGV_ARRAY_INIT;
+	struct strvec argv = STRVEC_INIT;
 
-	if (!append && !dry_run) {
+	if (!append && write_fetch_head) {
 		int errcode = truncate_fetch_head();
 		if (errcode)
 			return errcode;
 	}
 
-	argv_array_pushl(&argv, "fetch", "--append", "--no-auto-gc",
-			"--no-write-commit-graph", NULL);
+	strvec_pushl(&argv, "fetch", "--append", "--no-auto-gc",
+		     "--no-write-commit-graph", NULL);
 	add_options_to_argv(&argv);
 
 	if (max_children != 1 && list->nr != 1) {
-		struct parallel_fetch_state state = { argv.argv, list, 0, 0 };
+		struct parallel_fetch_state state = { argv.v, list, 0, 0 };
 
-		argv_array_push(&argv, "--end-of-options");
+		strvec_push(&argv, "--end-of-options");
 		result = run_processes_parallel_tr2(max_children,
 						    &fetch_next_remote,
 						    &fetch_failed_to_start,
@@ -1620,17 +1639,17 @@
 	} else
 		for (i = 0; i < list->nr; i++) {
 			const char *name = list->items[i].string;
-			argv_array_push(&argv, name);
+			strvec_push(&argv, name);
 			if (verbosity >= 0)
 				printf(_("Fetching %s\n"), name);
-			if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
+			if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
 				error(_("Could not fetch %s"), name);
 				result = 1;
 			}
-			argv_array_pop(&argv);
+			strvec_pop(&argv);
 		}
 
-	argv_array_clear(&argv);
+	strvec_clear(&argv);
 	return !!result;
 }
 
@@ -1675,7 +1694,8 @@
 	return;
 }
 
-static int fetch_one(struct remote *remote, int argc, const char **argv, int prune_tags_ok)
+static int fetch_one(struct remote *remote, int argc, const char **argv,
+		     int prune_tags_ok, int use_stdin_refspecs)
 {
 	struct refspec rs = REFSPEC_INIT_FETCH;
 	int i;
@@ -1732,6 +1752,13 @@
 		}
 	}
 
+	if (use_stdin_refspecs) {
+		struct strbuf line = STRBUF_INIT;
+		while (strbuf_getline_lf(&line, stdin) != EOF)
+			refspec_append(&rs, line.buf);
+		strbuf_release(&line);
+	}
+
 	if (server_options.nr)
 		gtransport->server_options = &server_options;
 
@@ -1766,12 +1793,18 @@
 		free(anon);
 	}
 
-	fetch_config_from_gitmodules(&submodule_fetch_jobs_config,
-				     &recurse_submodules);
 	git_config(git_fetch_config, NULL);
 
 	argc = parse_options(argc, argv, prefix,
 			     builtin_fetch_options, builtin_fetch_usage, 0);
+	if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
+		int *sfjc = submodule_fetch_jobs_config == -1
+			    ? &submodule_fetch_jobs_config : NULL;
+		int *rs = recurse_submodules == RECURSE_SUBMODULES_DEFAULT
+			  ? &recurse_submodules : NULL;
+
+		fetch_config_from_gitmodules(sfjc, rs);
+	}
 
 	if (deepen_relative) {
 		if (deepen_relative < 0)
@@ -1795,6 +1828,10 @@
 	if (depth || deepen_since || deepen_not.nr)
 		deepen = 1;
 
+	/* FETCH_HEAD never gets updated in --dry-run mode */
+	if (dry_run)
+		write_fetch_head = 0;
+
 	if (all) {
 		if (argc == 1)
 			die(_("fetch --all does not take a repository argument"));
@@ -1828,7 +1865,7 @@
 	if (remote) {
 		if (filter_options.choice || has_promisor_remote())
 			fetch_one_setup_partial(remote);
-		result = fetch_one(remote, argc, argv, prune_tags_ok);
+		result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs);
 	} else {
 		int max_children = max_jobs;
 
@@ -1836,6 +1873,10 @@
 			die(_("--filter can only be used with the remote "
 			      "configured in extensions.partialclone"));
 
+		if (stdin_refspecs)
+			die(_("--stdin can only be used when fetching "
+			      "from one remote"));
+
 		if (max_children < 0)
 			max_children = fetch_parallel_config;
 
@@ -1844,7 +1885,7 @@
 	}
 
 	if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
-		struct argv_array options = ARGV_ARRAY_INIT;
+		struct strvec options = STRVEC_INIT;
 		int max_children = max_jobs;
 
 		if (max_children < 0)
@@ -1860,7 +1901,7 @@
 						    recurse_submodules_default,
 						    verbosity < 0,
 						    max_children);
-		argv_array_clear(&options);
+		strvec_clear(&options);
 	}
 
 	string_list_clear(&list, 0);
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 37aa07d..fbf26ca 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -168,7 +168,7 @@
 		return 0;
 
 	if (!(obj->flags & HAS_OBJ)) {
-		if (parent && !has_object_file(&obj->oid)) {
+		if (parent && !has_object(the_repository, &obj->oid, 1)) {
 			printf_ln(_("broken link from %7s %s\n"
 				    "              to %7s %s"),
 				  printable_type(&parent->oid, parent->type),
diff --git a/builtin/gc.c b/builtin/gc.c
index 8e0b9cf..aafa094 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -18,7 +18,7 @@
 #include "parse-options.h"
 #include "run-command.h"
 #include "sigchain.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "commit.h"
 #include "commit-graph.h"
 #include "packfile.h"
@@ -50,12 +50,12 @@
 static unsigned long big_pack_threshold;
 static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
 
-static struct argv_array pack_refs_cmd = ARGV_ARRAY_INIT;
-static struct argv_array reflog = ARGV_ARRAY_INIT;
-static struct argv_array repack = ARGV_ARRAY_INIT;
-static struct argv_array prune = ARGV_ARRAY_INIT;
-static struct argv_array prune_worktrees = ARGV_ARRAY_INIT;
-static struct argv_array rerere = ARGV_ARRAY_INIT;
+static struct strvec pack_refs_cmd = STRVEC_INIT;
+static struct strvec reflog = STRVEC_INIT;
+static struct strvec repack = STRVEC_INIT;
+static struct strvec prune = STRVEC_INIT;
+static struct strvec prune_worktrees = STRVEC_INIT;
+static struct strvec rerere = STRVEC_INIT;
 
 static struct tempfile *pidfile;
 static struct lock_file log_lock;
@@ -311,18 +311,18 @@
 
 static int keep_one_pack(struct string_list_item *item, void *data)
 {
-	argv_array_pushf(&repack, "--keep-pack=%s", basename(item->string));
+	strvec_pushf(&repack, "--keep-pack=%s", basename(item->string));
 	return 0;
 }
 
 static void add_repack_all_option(struct string_list *keep_pack)
 {
 	if (prune_expire && !strcmp(prune_expire, "now"))
-		argv_array_push(&repack, "-a");
+		strvec_push(&repack, "-a");
 	else {
-		argv_array_push(&repack, "-A");
+		strvec_push(&repack, "-A");
 		if (prune_expire)
-			argv_array_pushf(&repack, "--unpack-unreachable=%s", prune_expire);
+			strvec_pushf(&repack, "--unpack-unreachable=%s", prune_expire);
 	}
 
 	if (keep_pack)
@@ -331,7 +331,7 @@
 
 static void add_repack_incremental_option(void)
 {
-	argv_array_push(&repack, "--no-write-bitmap-index");
+	strvec_push(&repack, "--no-write-bitmap-index");
 }
 
 static int need_to_gc(void)
@@ -514,11 +514,11 @@
 	if (done++)
 		return;
 
-	if (pack_refs && run_command_v_opt(pack_refs_cmd.argv, RUN_GIT_CMD))
-		die(FAILED_RUN, pack_refs_cmd.argv[0]);
+	if (pack_refs && run_command_v_opt(pack_refs_cmd.v, RUN_GIT_CMD))
+		die(FAILED_RUN, pack_refs_cmd.v[0]);
 
-	if (prune_reflogs && run_command_v_opt(reflog.argv, RUN_GIT_CMD))
-		die(FAILED_RUN, reflog.argv[0]);
+	if (prune_reflogs && run_command_v_opt(reflog.v, RUN_GIT_CMD))
+		die(FAILED_RUN, reflog.v[0]);
 }
 
 int cmd_gc(int argc, const char **argv, const char *prefix)
@@ -552,12 +552,12 @@
 	if (argc == 2 && !strcmp(argv[1], "-h"))
 		usage_with_options(builtin_gc_usage, builtin_gc_options);
 
-	argv_array_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL);
-	argv_array_pushl(&reflog, "reflog", "expire", "--all", NULL);
-	argv_array_pushl(&repack, "repack", "-d", "-l", NULL);
-	argv_array_pushl(&prune, "prune", "--expire", NULL);
-	argv_array_pushl(&prune_worktrees, "worktree", "prune", "--expire", NULL);
-	argv_array_pushl(&rerere, "rerere", "gc", NULL);
+	strvec_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL);
+	strvec_pushl(&reflog, "reflog", "expire", "--all", NULL);
+	strvec_pushl(&repack, "repack", "-d", "-l", NULL);
+	strvec_pushl(&prune, "prune", "--expire", NULL);
+	strvec_pushl(&prune_worktrees, "worktree", "prune", "--expire", NULL);
+	strvec_pushl(&rerere, "rerere", "gc", NULL);
 
 	/* default expiry time, overwritten in gc_config */
 	gc_config();
@@ -576,14 +576,14 @@
 		die(_("failed to parse prune expiry value %s"), prune_expire);
 
 	if (aggressive) {
-		argv_array_push(&repack, "-f");
+		strvec_push(&repack, "-f");
 		if (aggressive_depth > 0)
-			argv_array_pushf(&repack, "--depth=%d", aggressive_depth);
+			strvec_pushf(&repack, "--depth=%d", aggressive_depth);
 		if (aggressive_window > 0)
-			argv_array_pushf(&repack, "--window=%d", aggressive_window);
+			strvec_pushf(&repack, "--window=%d", aggressive_window);
 	}
 	if (quiet)
-		argv_array_push(&repack, "-q");
+		strvec_push(&repack, "-q");
 
 	if (auto_gc) {
 		/*
@@ -653,29 +653,29 @@
 
 	if (!repository_format_precious_objects) {
 		close_object_store(the_repository->objects);
-		if (run_command_v_opt(repack.argv, RUN_GIT_CMD))
-			die(FAILED_RUN, repack.argv[0]);
+		if (run_command_v_opt(repack.v, RUN_GIT_CMD))
+			die(FAILED_RUN, repack.v[0]);
 
 		if (prune_expire) {
-			argv_array_push(&prune, prune_expire);
+			strvec_push(&prune, prune_expire);
 			if (quiet)
-				argv_array_push(&prune, "--no-progress");
+				strvec_push(&prune, "--no-progress");
 			if (has_promisor_remote())
-				argv_array_push(&prune,
-						"--exclude-promisor-objects");
-			if (run_command_v_opt(prune.argv, RUN_GIT_CMD))
-				die(FAILED_RUN, prune.argv[0]);
+				strvec_push(&prune,
+					    "--exclude-promisor-objects");
+			if (run_command_v_opt(prune.v, RUN_GIT_CMD))
+				die(FAILED_RUN, prune.v[0]);
 		}
 	}
 
 	if (prune_worktrees_expire) {
-		argv_array_push(&prune_worktrees, prune_worktrees_expire);
-		if (run_command_v_opt(prune_worktrees.argv, RUN_GIT_CMD))
-			die(FAILED_RUN, prune_worktrees.argv[0]);
+		strvec_push(&prune_worktrees, prune_worktrees_expire);
+		if (run_command_v_opt(prune_worktrees.v, RUN_GIT_CMD))
+			die(FAILED_RUN, prune_worktrees.v[0]);
 	}
 
-	if (run_command_v_opt(rerere.argv, RUN_GIT_CMD))
-		die(FAILED_RUN, rerere.argv[0]);
+	if (run_command_v_opt(rerere.v, RUN_GIT_CMD))
+		die(FAILED_RUN, rerere.v[0]);
 
 	report_garbage = report_pack_garbage;
 	reprepare_packed_git(the_repository);
diff --git a/builtin/grep.c b/builtin/grep.c
index a5056f3..f58979b 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -397,7 +397,7 @@
 	int i, status;
 
 	for (i = 0; i < path_list->nr; i++)
-		argv_array_push(&child.args, path_list->items[i].string);
+		strvec_push(&child.args, path_list->items[i].string);
 	child.dir = prefix;
 	child.use_shell = 1;
 
@@ -466,7 +466,7 @@
 		struct strbuf base = STRBUF_INIT;
 
 		obj_read_lock();
-		object = parse_object_or_die(oid, oid_to_hex(oid));
+		object = parse_object_or_die(oid, NULL);
 		obj_read_unlock();
 		data = read_object_with_reference(&subrepo,
 						  &object->oid, tree_type,
@@ -693,7 +693,7 @@
 	struct dir_struct dir;
 	int i, hit = 0;
 
-	memset(&dir, 0, sizeof(dir));
+	dir_init(&dir);
 	if (!use_index)
 		dir.flags |= DIR_NO_GITLINKS;
 	if (exc_std)
@@ -705,6 +705,7 @@
 		if (hit && opt->status_only)
 			break;
 	}
+	dir_clear(&dir);
 	return hit;
 }
 
diff --git a/builtin/help.c b/builtin/help.c
index 299206e..bb339f0 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -579,7 +579,7 @@
 	}
 
 	if (show_guides)
-		list_common_guides_help();
+		list_guides_help();
 
 	if (show_all || show_guides) {
 		printf("%s\n", _(git_more_info_string));
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index f865666..9721bf1 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1798,9 +1798,22 @@
 
 	if (HAVE_THREADS && !nr_threads) {
 		nr_threads = online_cpus();
-		/* An experiment showed that more threads does not mean faster */
-		if (nr_threads > 3)
-			nr_threads = 3;
+		/*
+		 * Experiments show that going above 20 threads doesn't help,
+		 * no matter how many cores you have. Below that, we tend to
+		 * max at half the number of online_cpus(), presumably because
+		 * half of those are hyperthreads rather than full cores. We'll
+		 * never reduce the level below "3", though, to match a
+		 * historical value that nobody complained about.
+		 */
+		if (nr_threads < 4)
+			; /* too few cores to consider capping */
+		else if (nr_threads < 6)
+			nr_threads = 3; /* historic cap */
+		else if (nr_threads < 40)
+			nr_threads /= 2;
+		else
+			nr_threads = 20; /* hard cap */
 	}
 
 	curr_pack = open_pack_file(pack_name);
diff --git a/builtin/init-db.c b/builtin/init-db.c
index cee6482..cd3e760 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -9,6 +9,7 @@
 #include "builtin.h"
 #include "exec-cmd.h"
 #include "parse-options.h"
+#include "worktree.h"
 
 #ifndef DEFAULT_GIT_TEMPLATE_DIR
 #define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
@@ -183,11 +184,6 @@
 	char repo_version_string[10];
 	int repo_version = GIT_REPO_VERSION;
 
-#ifndef ENABLE_SHA256
-	if (hash_algo != GIT_HASH_SHA1)
-		die(_("The hash algorithm %s is not supported in this build."), hash_algos[hash_algo].name);
-#endif
-
 	if (hash_algo != GIT_HASH_SHA1)
 		repo_version = GIT_REPO_VERSION_READ;
 
@@ -369,6 +365,7 @@
 
 		if (rename(src, git_dir))
 			die_errno(_("unable to move %s to %s"), src, git_dir);
+		repair_worktrees(NULL, NULL);
 	}
 
 	write_file(git_link, "gitdir: %s", git_dir);
@@ -568,6 +565,9 @@
 
 	argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0);
 
+	if (real_git_dir && is_bare_repository_cfg == 1)
+		die(_("--separate-git-dir and --bare are mutually exclusive"));
+
 	if (real_git_dir && !is_absolute_path(real_git_dir))
 		real_git_dir = real_pathdup(real_git_dir, 1);
 
@@ -642,6 +642,30 @@
 	if (!git_dir)
 		git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
 
+	/*
+	 * When --separate-git-dir is used inside a linked worktree, take
+	 * care to ensure that the common .git/ directory is relocated, not
+	 * the worktree-specific .git/worktrees/<id>/ directory.
+	 */
+	if (real_git_dir) {
+		int err;
+		const char *p;
+		struct strbuf sb = STRBUF_INIT;
+
+		p = read_gitfile_gently(git_dir, &err);
+		if (p && get_common_dir(&sb, p)) {
+			struct strbuf mainwt = STRBUF_INIT;
+
+			strbuf_addbuf(&mainwt, &sb);
+			strbuf_strip_suffix(&mainwt, "/.git");
+			if (chdir(mainwt.buf) < 0)
+				die_errno(_("cannot chdir to %s"), mainwt.buf);
+			strbuf_release(&mainwt);
+			git_dir = strbuf_detach(&sb, NULL);
+		}
+		strbuf_release(&sb);
+	}
+
 	if (is_bare_repository_cfg < 0)
 		is_bare_repository_cfg = guess_repository_type(git_dir);
 
@@ -663,6 +687,8 @@
 				   get_git_work_tree());
 	}
 	else {
+		if (real_git_dir)
+			die(_("--separate-git-dir incompatible with bare repository"));
 		if (work_tree)
 			set_git_work_tree(work_tree);
 	}
diff --git a/builtin/log.c b/builtin/log.c
index 76578c4..4ec7f57 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -599,8 +599,8 @@
 static void show_setup_revisions_tweak(struct rev_info *rev,
 				       struct setup_revision_opt *opt)
 {
-	if (rev->ignore_merges) {
-		/* There was no "-m" on the command line */
+	if (rev->ignore_merges < 0) {
+		/* There was no "-m" variant on the command line */
 		rev->ignore_merges = 0;
 		if (!rev->first_parent_only && !rev->combine_merges) {
 			/* No "--first-parent", "-c", or "--cc" */
@@ -732,8 +732,7 @@
 	if (!rev->diffopt.output_format && rev->combine_merges)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 
-	/* Turn -m on when --cc/-c was given */
-	if (rev->combine_merges)
+	if (rev->first_parent_only && rev->ignore_merges < 0)
 		rev->ignore_merges = 0;
 }
 
@@ -1128,18 +1127,18 @@
 
 static int get_notes_refs(struct string_list_item *item, void *arg)
 {
-	argv_array_pushf(arg, "--notes=%s", item->string);
+	strvec_pushf(arg, "--notes=%s", item->string);
 	return 0;
 }
 
-static void get_notes_args(struct argv_array *arg, struct rev_info *rev)
+static void get_notes_args(struct strvec *arg, struct rev_info *rev)
 {
 	if (!rev->show_notes) {
-		argv_array_push(arg, "--no-notes");
+		strvec_push(arg, "--no-notes");
 	} else if (rev->notes_opt.use_default_notes > 0 ||
 		   (rev->notes_opt.use_default_notes == -1 &&
 		    !rev->notes_opt.extra_notes_refs.nr)) {
-		argv_array_push(arg, "--notes");
+		strvec_push(arg, "--notes");
 	} else {
 		for_each_string_list(&rev->notes_opt.extra_notes_refs, get_notes_refs, arg);
 	}
@@ -1217,7 +1216,7 @@
 		 * can be added later if deemed desirable.
 		 */
 		struct diff_options opts;
-		struct argv_array other_arg = ARGV_ARRAY_INIT;
+		struct strvec other_arg = STRVEC_INIT;
 		diff_setup(&opts);
 		opts.file = rev->diffopt.file;
 		opts.use_color = rev->diffopt.use_color;
@@ -1226,7 +1225,7 @@
 		get_notes_args(&other_arg, rev);
 		show_range_diff(rev->rdiff1, rev->rdiff2,
 				rev->creation_factor, 1, &opts, &other_arg);
-		argv_array_clear(&other_arg);
+		strvec_clear(&other_arg);
 	}
 }
 
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 30a4c10..c8eae89 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -584,7 +584,7 @@
 	if (argc == 2 && !strcmp(argv[1], "-h"))
 		usage_with_options(ls_files_usage, builtin_ls_files_options);
 
-	memset(&dir, 0, sizeof(dir));
+	dir_init(&dir);
 	prefix = cmd_prefix;
 	if (prefix)
 		prefix_len = strlen(prefix);
@@ -688,6 +688,6 @@
 		return bad ? 1 : 0;
 	}
 
-	UNLEAK(dir);
+	dir_clear(&dir);
 	return 0;
 }
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 3a4dd12..092917e 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -45,7 +45,7 @@
 	int show_symref_target = 0;
 	const char *uploadpack = NULL;
 	const char **pattern = NULL;
-	struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
+	struct strvec ref_prefixes = STRVEC_INIT;
 	int i;
 	struct string_list server_options = STRING_LIST_INIT_DUP;
 
@@ -83,6 +83,8 @@
 			     PARSE_OPT_STOP_AT_NON_OPTION);
 	dest = argv[0];
 
+	UNLEAK(sorting);
+
 	if (argc > 1) {
 		int i;
 		pattern = xcalloc(argc, sizeof(const char *));
@@ -92,9 +94,9 @@
 	}
 
 	if (flags & REF_TAGS)
-		argv_array_push(&ref_prefixes, "refs/tags/");
+		strvec_push(&ref_prefixes, "refs/tags/");
 	if (flags & REF_HEADS)
-		argv_array_push(&ref_prefixes, "refs/heads/");
+		strvec_push(&ref_prefixes, "refs/heads/");
 
 	remote = remote_get(dest);
 	if (!remote) {
@@ -107,7 +109,6 @@
 
 	if (get_url) {
 		printf("%s\n", *remote->url);
-		UNLEAK(sorting);
 		return 0;
 	}
 
@@ -122,10 +123,8 @@
 		int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
 		repo_set_hash_algo(the_repository, hash_algo);
 	}
-	if (transport_disconnect(transport)) {
-		UNLEAK(sorting);
+	if (transport_disconnect(transport))
 		return 1;
-	}
 
 	if (!dest && !quiet)
 		fprintf(stderr, "From %s\n", *remote->url);
@@ -150,7 +149,6 @@
 		status = 0; /* we found something */
 	}
 
-	UNLEAK(sorting);
 	ref_array_clear(&ref_array);
 	return status;
 }
diff --git a/builtin/merge.c b/builtin/merge.c
index 835b2f4..032a8f5 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -72,7 +72,6 @@
 static size_t xopts_nr, xopts_alloc;
 static const char *branch;
 static char *branch_mergeoptions;
-static int option_renormalize;
 static int verbosity;
 static int allow_rerere_auto;
 static int abort_current_merge;
@@ -621,8 +620,6 @@
 		return git_config_string(&pull_octopus, k, v);
 	else if (!strcmp(k, "commit.cleanup"))
 		return git_config_string(&cleanup_arg, k, v);
-	else if (!strcmp(k, "merge.renormalize"))
-		option_renormalize = git_config_bool(k, v);
 	else if (!strcmp(k, "merge.ff")) {
 		int boolval = git_parse_maybe_bool(v);
 		if (0 <= boolval) {
@@ -721,7 +718,6 @@
 		if (!strcmp(strategy, "subtree"))
 			o.subtree_shift = "";
 
-		o.renormalize = option_renormalize;
 		o.show_rename_progress =
 			show_progress == -1 ? isatty(2) : show_progress;
 
@@ -1352,7 +1348,7 @@
 		else
 			die(_("You have not concluded your merge (MERGE_HEAD exists)."));
 	}
-	if (file_exists(git_path_cherry_pick_head(the_repository))) {
+	if (ref_exists("CHERRY_PICK_HEAD")) {
 		if (advice_resolve_conflict)
 			die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
 			    "Please, commit your changes before you merge."));
diff --git a/builtin/mv.c b/builtin/mv.c
index be15ba7..7dac714 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -132,6 +132,7 @@
 	struct stat st;
 	struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
 	struct lock_file lock_file = LOCK_INIT;
+	struct cache_entry *ce;
 
 	git_config(git_default_config, NULL);
 
@@ -220,9 +221,11 @@
 				}
 				argc += last - first;
 			}
-		} else if (cache_name_pos(src, length) < 0)
+		} else if (!(ce = cache_file_exists(src, length, ignore_case))) {
 			bad = _("not under version control");
-		else if (lstat(dst, &st) == 0 &&
+		} else if (ce_stage(ce)) {
+			bad = _("conflicted");
+		} else if (lstat(dst, &st) == 0 &&
 			 (!ignore_case || strcasecmp(src, dst))) {
 			bad = _("destination exists");
 			if (force) {
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index a9dcd25..725dd04 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -521,7 +521,7 @@
 	int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
 	struct name_ref_data data = { 0, 0, STRING_LIST_INIT_NODUP, STRING_LIST_INIT_NODUP };
 	struct option opts[] = {
-		OPT_BOOL(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")),
+		OPT_BOOL(0, "name-only", &data.name_only, N_("print only ref-based names (no object names)")),
 		OPT_BOOL(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
 		OPT_STRING_LIST(0, "refs", &data.ref_filters, N_("pattern"),
 				   N_("only use refs matching <pattern>")),
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 7016b28..5617c01 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -27,7 +27,7 @@
 #include "delta-islands.h"
 #include "reachable.h"
 #include "oid-array.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "list.h"
 #include "packfile.h"
 #include "object-store.h"
@@ -35,6 +35,7 @@
 #include "midx.h"
 #include "trace2.h"
 #include "shallow.h"
+#include "promisor-remote.h"
 
 #define IN_PACK(obj) oe_in_pack(&to_pack, obj)
 #define SIZE(obj) oe_size(&to_pack, obj)
@@ -1704,9 +1705,30 @@
 	return 0;
 }
 
-static void check_object(struct object_entry *entry)
+static void prefetch_to_pack(uint32_t object_index_start) {
+	struct oid_array to_fetch = OID_ARRAY_INIT;
+	uint32_t i;
+
+	for (i = object_index_start; i < to_pack.nr_objects; i++) {
+		struct object_entry *entry = to_pack.objects + i;
+
+		if (!oid_object_info_extended(the_repository,
+					      &entry->idx.oid,
+					      NULL,
+					      OBJECT_INFO_FOR_PREFETCH))
+			continue;
+		oid_array_append(&to_fetch, &entry->idx.oid);
+	}
+	promisor_remote_get_direct(the_repository,
+				   to_fetch.oid, to_fetch.nr);
+	oid_array_clear(&to_fetch);
+}
+
+static void check_object(struct object_entry *entry, uint32_t object_index)
 {
 	unsigned long canonical_size;
+	enum object_type type;
+	struct object_info oi = {.typep = &type, .sizep = &canonical_size};
 
 	if (IN_PACK(entry)) {
 		struct packed_git *p = IN_PACK(entry);
@@ -1840,8 +1862,18 @@
 		unuse_pack(&w_curs);
 	}
 
-	oe_set_type(entry,
-		    oid_object_info(the_repository, &entry->idx.oid, &canonical_size));
+	if (oid_object_info_extended(the_repository, &entry->idx.oid, &oi,
+				     OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_LOOKUP_REPLACE) < 0) {
+		if (has_promisor_remote()) {
+			prefetch_to_pack(object_index);
+			if (oid_object_info_extended(the_repository, &entry->idx.oid, &oi,
+						     OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_LOOKUP_REPLACE) < 0)
+				type = -1;
+		} else {
+			type = -1;
+		}
+	}
+	oe_set_type(entry, type);
 	if (entry->type_valid) {
 		SET_SIZE(entry, canonical_size);
 	} else {
@@ -2061,7 +2093,7 @@
 
 	for (i = 0; i < to_pack.nr_objects; i++) {
 		struct object_entry *entry = sorted_by_offset[i];
-		check_object(entry);
+		check_object(entry, i);
 		if (entry->type_valid &&
 		    oe_size_greater_than(&to_pack, entry, big_file_threshold))
 			entry->no_try_delta = 1;
@@ -3016,7 +3048,7 @@
 	 * Quietly ignore ALL missing objects.  This avoids problems with
 	 * staging them now and getting an odd error later.
 	 */
-	if (!has_object_file(&obj->oid))
+	if (!has_object(the_repository, &obj->oid, 0))
 		return;
 
 	show_object(obj, name, data);
@@ -3030,7 +3062,7 @@
 	 * Quietly ignore EXPECTED missing objects.  This avoids problems with
 	 * staging them now and getting an odd error later.
 	 */
-	if (!has_object_file(&obj->oid) && is_promisor_object(&obj->oid))
+	if (!has_object(the_repository, &obj->oid, 0) && is_promisor_object(&obj->oid))
 		return;
 
 	show_object(obj, name, data);
@@ -3325,7 +3357,7 @@
 			if (starts_with(line, "--shallow ")) {
 				struct object_id oid;
 				if (get_oid_hex(line + 10, &oid))
-					die("not an SHA-1 '%s'", line + 10);
+					die("not an object name '%s'", line + 10);
 				register_shallow(the_repository, &oid);
 				use_bitmap_index = 0;
 				continue;
@@ -3439,7 +3471,7 @@
 	int use_internal_rev_list = 0;
 	int shallow = 0;
 	int all_progress_implied = 0;
-	struct argv_array rp = ARGV_ARRAY_INIT;
+	struct strvec rp = STRVEC_INIT;
 	int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0;
 	int rev_list_index = 0;
 	struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
@@ -3575,36 +3607,36 @@
 		cache_max_small_delta_size = (1U << OE_Z_DELTA_BITS) - 1;
 	}
 
-	argv_array_push(&rp, "pack-objects");
+	strvec_push(&rp, "pack-objects");
 	if (thin) {
 		use_internal_rev_list = 1;
-		argv_array_push(&rp, shallow
+		strvec_push(&rp, shallow
 				? "--objects-edge-aggressive"
 				: "--objects-edge");
 	} else
-		argv_array_push(&rp, "--objects");
+		strvec_push(&rp, "--objects");
 
 	if (rev_list_all) {
 		use_internal_rev_list = 1;
-		argv_array_push(&rp, "--all");
+		strvec_push(&rp, "--all");
 	}
 	if (rev_list_reflog) {
 		use_internal_rev_list = 1;
-		argv_array_push(&rp, "--reflog");
+		strvec_push(&rp, "--reflog");
 	}
 	if (rev_list_index) {
 		use_internal_rev_list = 1;
-		argv_array_push(&rp, "--indexed-objects");
+		strvec_push(&rp, "--indexed-objects");
 	}
 	if (rev_list_unpacked) {
 		use_internal_rev_list = 1;
-		argv_array_push(&rp, "--unpacked");
+		strvec_push(&rp, "--unpacked");
 	}
 
 	if (exclude_promisor_objects) {
 		use_internal_rev_list = 1;
 		fetch_if_missing = 0;
-		argv_array_push(&rp, "--exclude-promisor-objects");
+		strvec_push(&rp, "--exclude-promisor-objects");
 	}
 	if (unpack_unreachable || keep_unreachable || pack_loose_unreachable)
 		use_internal_rev_list = 1;
@@ -3666,7 +3698,7 @@
 		write_bitmap_index = 0;
 
 	if (use_delta_islands)
-		argv_array_push(&rp, "--topo-order");
+		strvec_push(&rp, "--topo-order");
 
 	if (progress && all_progress_implied)
 		progress = 2;
@@ -3704,8 +3736,8 @@
 	if (!use_internal_rev_list)
 		read_object_list_from_stdin();
 	else {
-		get_object_list(rp.argc, rp.argv);
-		argv_array_clear(&rp);
+		get_object_list(rp.nr, rp.v);
+		strvec_clear(&rp);
 	}
 	cleanup_preferred_base();
 	if (include_tag && nr_result)
diff --git a/builtin/pull.c b/builtin/pull.c
index 8159c5d..015f6de 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -87,8 +87,8 @@
 static int opt_autostash = -1;
 static int config_autostash;
 static int check_trust_level = 1;
-static struct argv_array opt_strategies = ARGV_ARRAY_INIT;
-static struct argv_array opt_strategy_opts = ARGV_ARRAY_INIT;
+static struct strvec opt_strategies = STRVEC_INIT;
+static struct strvec opt_strategy_opts = STRVEC_INIT;
 static char *opt_gpg_sign;
 static int opt_allow_unrelated_histories;
 
@@ -110,7 +110,7 @@
 static char *opt_ipv6;
 static int opt_show_forced_updates = -1;
 static char *set_upstream;
-static struct argv_array opt_fetch = ARGV_ARRAY_INIT;
+static struct strvec opt_fetch = STRVEC_INIT;
 
 static struct option pull_options[] = {
 	/* Shared options */
@@ -251,25 +251,25 @@
 /**
  * Pushes "-q" or "-v" switches into arr to match the opt_verbosity level.
  */
-static void argv_push_verbosity(struct argv_array *arr)
+static void argv_push_verbosity(struct strvec *arr)
 {
 	int verbosity;
 
 	for (verbosity = opt_verbosity; verbosity > 0; verbosity--)
-		argv_array_push(arr, "-v");
+		strvec_push(arr, "-v");
 
 	for (verbosity = opt_verbosity; verbosity < 0; verbosity++)
-		argv_array_push(arr, "-q");
+		strvec_push(arr, "-q");
 }
 
 /**
  * Pushes "-f" switches into arr to match the opt_force level.
  */
-static void argv_push_force(struct argv_array *arr)
+static void argv_push_force(struct strvec *arr)
 {
 	int force = opt_force;
 	while (force-- > 0)
-		argv_array_push(arr, "-f");
+		strvec_push(arr, "-f");
 }
 
 /**
@@ -524,75 +524,75 @@
  */
 static int run_fetch(const char *repo, const char **refspecs)
 {
-	struct argv_array args = ARGV_ARRAY_INIT;
+	struct strvec args = STRVEC_INIT;
 	int ret;
 
-	argv_array_pushl(&args, "fetch", "--update-head-ok", NULL);
+	strvec_pushl(&args, "fetch", "--update-head-ok", NULL);
 
 	/* Shared options */
 	argv_push_verbosity(&args);
 	if (opt_progress)
-		argv_array_push(&args, opt_progress);
+		strvec_push(&args, opt_progress);
 
 	/* Options passed to git-fetch */
 	if (opt_all)
-		argv_array_push(&args, opt_all);
+		strvec_push(&args, opt_all);
 	if (opt_append)
-		argv_array_push(&args, opt_append);
+		strvec_push(&args, opt_append);
 	if (opt_upload_pack)
-		argv_array_push(&args, opt_upload_pack);
+		strvec_push(&args, opt_upload_pack);
 	argv_push_force(&args);
 	if (opt_tags)
-		argv_array_push(&args, opt_tags);
+		strvec_push(&args, opt_tags);
 	if (opt_prune)
-		argv_array_push(&args, opt_prune);
+		strvec_push(&args, opt_prune);
 	if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT)
 		switch (recurse_submodules) {
 		case RECURSE_SUBMODULES_ON:
-			argv_array_push(&args, "--recurse-submodules=on");
+			strvec_push(&args, "--recurse-submodules=on");
 			break;
 		case RECURSE_SUBMODULES_OFF:
-			argv_array_push(&args, "--recurse-submodules=no");
+			strvec_push(&args, "--recurse-submodules=no");
 			break;
 		case RECURSE_SUBMODULES_ON_DEMAND:
-			argv_array_push(&args, "--recurse-submodules=on-demand");
+			strvec_push(&args, "--recurse-submodules=on-demand");
 			break;
 		default:
 			BUG("submodule recursion option not understood");
 		}
 	if (max_children)
-		argv_array_push(&args, max_children);
+		strvec_push(&args, max_children);
 	if (opt_dry_run)
-		argv_array_push(&args, "--dry-run");
+		strvec_push(&args, "--dry-run");
 	if (opt_keep)
-		argv_array_push(&args, opt_keep);
+		strvec_push(&args, opt_keep);
 	if (opt_depth)
-		argv_array_push(&args, opt_depth);
+		strvec_push(&args, opt_depth);
 	if (opt_unshallow)
-		argv_array_push(&args, opt_unshallow);
+		strvec_push(&args, opt_unshallow);
 	if (opt_update_shallow)
-		argv_array_push(&args, opt_update_shallow);
+		strvec_push(&args, opt_update_shallow);
 	if (opt_refmap)
-		argv_array_push(&args, opt_refmap);
+		strvec_push(&args, opt_refmap);
 	if (opt_ipv4)
-		argv_array_push(&args, opt_ipv4);
+		strvec_push(&args, opt_ipv4);
 	if (opt_ipv6)
-		argv_array_push(&args, opt_ipv6);
+		strvec_push(&args, opt_ipv6);
 	if (opt_show_forced_updates > 0)
-		argv_array_push(&args, "--show-forced-updates");
+		strvec_push(&args, "--show-forced-updates");
 	else if (opt_show_forced_updates == 0)
-		argv_array_push(&args, "--no-show-forced-updates");
+		strvec_push(&args, "--no-show-forced-updates");
 	if (set_upstream)
-		argv_array_push(&args, set_upstream);
-	argv_array_pushv(&args, opt_fetch.argv);
+		strvec_push(&args, set_upstream);
+	strvec_pushv(&args, opt_fetch.v);
 
 	if (repo) {
-		argv_array_push(&args, repo);
-		argv_array_pushv(&args, refspecs);
+		strvec_push(&args, repo);
+		strvec_pushv(&args, refspecs);
 	} else if (*refspecs)
 		BUG("refspecs without repo?");
-	ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
-	argv_array_clear(&args);
+	ret = run_command_v_opt(args.v, RUN_GIT_CMD);
+	strvec_clear(&args);
 	return ret;
 }
 
@@ -637,8 +637,8 @@
 
 	cp.git_cmd = 1;
 	cp.no_stdin = 1;
-	argv_array_pushl(&cp.args, "submodule", "update",
-				   "--recursive", "--rebase", NULL);
+	strvec_pushl(&cp.args, "submodule", "update",
+		     "--recursive", "--rebase", NULL);
 	argv_push_verbosity(&cp.args);
 
 	return run_command(&cp);
@@ -650,8 +650,8 @@
 
 	cp.git_cmd = 1;
 	cp.no_stdin = 1;
-	argv_array_pushl(&cp.args, "submodule", "update",
-				   "--recursive", "--checkout", NULL);
+	strvec_pushl(&cp.args, "submodule", "update",
+		     "--recursive", "--checkout", NULL);
 	argv_push_verbosity(&cp.args);
 
 	return run_command(&cp);
@@ -663,48 +663,48 @@
 static int run_merge(void)
 {
 	int ret;
-	struct argv_array args = ARGV_ARRAY_INIT;
+	struct strvec args = STRVEC_INIT;
 
-	argv_array_pushl(&args, "merge", NULL);
+	strvec_pushl(&args, "merge", NULL);
 
 	/* Shared options */
 	argv_push_verbosity(&args);
 	if (opt_progress)
-		argv_array_push(&args, opt_progress);
+		strvec_push(&args, opt_progress);
 
 	/* Options passed to git-merge */
 	if (opt_diffstat)
-		argv_array_push(&args, opt_diffstat);
+		strvec_push(&args, opt_diffstat);
 	if (opt_log)
-		argv_array_push(&args, opt_log);
+		strvec_push(&args, opt_log);
 	if (opt_signoff)
-		argv_array_push(&args, opt_signoff);
+		strvec_push(&args, opt_signoff);
 	if (opt_squash)
-		argv_array_push(&args, opt_squash);
+		strvec_push(&args, opt_squash);
 	if (opt_commit)
-		argv_array_push(&args, opt_commit);
+		strvec_push(&args, opt_commit);
 	if (opt_edit)
-		argv_array_push(&args, opt_edit);
+		strvec_push(&args, opt_edit);
 	if (cleanup_arg)
-		argv_array_pushf(&args, "--cleanup=%s", cleanup_arg);
+		strvec_pushf(&args, "--cleanup=%s", cleanup_arg);
 	if (opt_ff)
-		argv_array_push(&args, opt_ff);
+		strvec_push(&args, opt_ff);
 	if (opt_verify_signatures)
-		argv_array_push(&args, opt_verify_signatures);
-	argv_array_pushv(&args, opt_strategies.argv);
-	argv_array_pushv(&args, opt_strategy_opts.argv);
+		strvec_push(&args, opt_verify_signatures);
+	strvec_pushv(&args, opt_strategies.v);
+	strvec_pushv(&args, opt_strategy_opts.v);
 	if (opt_gpg_sign)
-		argv_array_push(&args, opt_gpg_sign);
+		strvec_push(&args, opt_gpg_sign);
 	if (opt_autostash == 0)
-		argv_array_push(&args, "--no-autostash");
+		strvec_push(&args, "--no-autostash");
 	else if (opt_autostash == 1)
-		argv_array_push(&args, "--autostash");
+		strvec_push(&args, "--autostash");
 	if (opt_allow_unrelated_histories > 0)
-		argv_array_push(&args, "--allow-unrelated-histories");
+		strvec_push(&args, "--allow-unrelated-histories");
 
-	argv_array_push(&args, "FETCH_HEAD");
-	ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
-	argv_array_clear(&args);
+	strvec_push(&args, "FETCH_HEAD");
+	ret = run_command_v_opt(args.v, RUN_GIT_CMD);
+	strvec_clear(&args);
 	return ret;
 }
 
@@ -801,8 +801,8 @@
 	if (!remote_branch)
 		return -1;
 
-	argv_array_pushl(&cp.args, "merge-base", "--fork-point",
-			remote_branch, curr_branch->name, NULL);
+	strvec_pushl(&cp.args, "merge-base", "--fork-point",
+		     remote_branch, curr_branch->name, NULL);
 	cp.no_stdin = 1;
 	cp.no_stderr = 1;
 	cp.git_cmd = 1;
@@ -862,48 +862,48 @@
 {
 	int ret;
 	struct object_id oct_merge_base;
-	struct argv_array args = ARGV_ARRAY_INIT;
+	struct strvec args = STRVEC_INIT;
 
 	if (!get_octopus_merge_base(&oct_merge_base, curr_head, merge_head, fork_point))
 		if (!is_null_oid(fork_point) && oideq(&oct_merge_base, fork_point))
 			fork_point = NULL;
 
-	argv_array_push(&args, "rebase");
+	strvec_push(&args, "rebase");
 
 	/* Shared options */
 	argv_push_verbosity(&args);
 
 	/* Options passed to git-rebase */
 	if (opt_rebase == REBASE_MERGES)
-		argv_array_push(&args, "--rebase-merges");
+		strvec_push(&args, "--rebase-merges");
 	else if (opt_rebase == REBASE_PRESERVE)
-		argv_array_push(&args, "--preserve-merges");
+		strvec_push(&args, "--preserve-merges");
 	else if (opt_rebase == REBASE_INTERACTIVE)
-		argv_array_push(&args, "--interactive");
+		strvec_push(&args, "--interactive");
 	if (opt_diffstat)
-		argv_array_push(&args, opt_diffstat);
-	argv_array_pushv(&args, opt_strategies.argv);
-	argv_array_pushv(&args, opt_strategy_opts.argv);
+		strvec_push(&args, opt_diffstat);
+	strvec_pushv(&args, opt_strategies.v);
+	strvec_pushv(&args, opt_strategy_opts.v);
 	if (opt_gpg_sign)
-		argv_array_push(&args, opt_gpg_sign);
+		strvec_push(&args, opt_gpg_sign);
 	if (opt_autostash == 0)
-		argv_array_push(&args, "--no-autostash");
+		strvec_push(&args, "--no-autostash");
 	else if (opt_autostash == 1)
-		argv_array_push(&args, "--autostash");
+		strvec_push(&args, "--autostash");
 	if (opt_verify_signatures &&
 	    !strcmp(opt_verify_signatures, "--verify-signatures"))
 		warning(_("ignoring --verify-signatures for rebase"));
 
-	argv_array_push(&args, "--onto");
-	argv_array_push(&args, oid_to_hex(merge_head));
+	strvec_push(&args, "--onto");
+	strvec_push(&args, oid_to_hex(merge_head));
 
 	if (fork_point && !is_null_oid(fork_point))
-		argv_array_push(&args, oid_to_hex(fork_point));
+		strvec_push(&args, oid_to_hex(fork_point));
 	else
-		argv_array_push(&args, oid_to_hex(merge_head));
+		strvec_push(&args, oid_to_hex(merge_head));
 
-	ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
-	argv_array_clear(&args);
+	ret = run_command_v_opt(args.v, RUN_GIT_CMD);
+	strvec_clear(&args);
 	return ret;
 }
 
diff --git a/builtin/range-diff.c b/builtin/range-diff.c
index d8a4670..24c4162 100644
--- a/builtin/range-diff.c
+++ b/builtin/range-diff.c
@@ -15,7 +15,7 @@
 {
 	int creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT;
 	struct diff_options diffopt = { NULL };
-	struct argv_array other_arg = ARGV_ARRAY_INIT;
+	struct strvec other_arg = STRVEC_INIT;
 	int simple_color = -1;
 	struct option range_diff_options[] = {
 		OPT_INTEGER(0, "creation-factor", &creation_factor,
@@ -84,7 +84,7 @@
 	res = show_range_diff(range1.buf, range2.buf, creation_factor,
 			      simple_color < 1, &diffopt, &other_arg);
 
-	argv_array_clear(&other_arg);
+	strvec_clear(&other_arg);
 	strbuf_release(&range1);
 	strbuf_release(&range2);
 
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 37ba76a..c4ff203 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -8,7 +8,7 @@
 #include "builtin.h"
 #include "run-command.h"
 #include "exec-cmd.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "dir.h"
 #include "packfile.h"
 #include "refs.h"
@@ -84,7 +84,7 @@
 		REBASE_FORCE = 1<<3,
 		REBASE_INTERACTIVE_EXPLICIT = 1<<4,
 	} flags;
-	struct argv_array git_am_opts;
+	struct strvec git_am_opts;
 	const char *action;
 	int signoff;
 	int allow_rerere_autoupdate;
@@ -92,6 +92,8 @@
 	int autosquash;
 	char *gpg_sign_opt;
 	int autostash;
+	int committer_date_is_author_date;
+	int ignore_date;
 	char *cmd;
 	int allow_empty_message;
 	int rebase_merges, rebase_cousins;
@@ -108,7 +110,7 @@
 		.keep_empty = 1,			\
 		.default_backend = "merge",	  	\
 		.flags = REBASE_NO_QUIET, 		\
-		.git_am_opts = ARGV_ARRAY_INIT,		\
+		.git_am_opts = STRVEC_INIT,		\
 		.git_format_patch_opt = STRBUF_INIT	\
 	}
 
@@ -130,8 +132,12 @@
 	replay.quiet = !(opts->flags & REBASE_NO_QUIET);
 	replay.verbose = opts->flags & REBASE_VERBOSE;
 	replay.reschedule_failed_exec = opts->reschedule_failed_exec;
+	replay.committer_date_is_author_date =
+					opts->committer_date_is_author_date;
+	replay.ignore_date = opts->ignore_date;
 	replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
 	replay.strategy = opts->strategy;
+
 	if (opts->strategy_opts)
 		parse_strategy_opts(&replay, opts->strategy_opts);
 
@@ -323,7 +329,7 @@
 	int ret;
 	const char *head_hash = NULL;
 	char *revisions = NULL, *shortrevisions = NULL;
-	struct argv_array make_script_args = ARGV_ARRAY_INIT;
+	struct strvec make_script_args = STRVEC_INIT;
 	struct todo_list todo_list = TODO_LIST_INIT;
 	struct replay_opts replay = get_replay_opts(opts);
 	struct string_list commands = STRING_LIST_INIT_DUP;
@@ -345,13 +351,13 @@
 		write_file(path_squash_onto(), "%s\n",
 			   oid_to_hex(opts->squash_onto));
 
-	argv_array_pushl(&make_script_args, "", revisions, NULL);
+	strvec_pushl(&make_script_args, "", revisions, NULL);
 	if (opts->restrict_revision)
-		argv_array_pushf(&make_script_args, "^%s",
-				 oid_to_hex(&opts->restrict_revision->object.oid));
+		strvec_pushf(&make_script_args, "^%s",
+			     oid_to_hex(&opts->restrict_revision->object.oid));
 
 	ret = sequencer_make_script(the_repository, &todo_list.buf,
-				    make_script_args.argc, make_script_args.argv,
+				    make_script_args.nr, make_script_args.v,
 				    flags);
 
 	if (ret)
@@ -372,7 +378,7 @@
 	free(revisions);
 	free(shortrevisions);
 	todo_list_release(&todo_list);
-	argv_array_clear(&make_script_args);
+	strvec_clear(&make_script_args);
 
 	return ret;
 }
@@ -420,7 +426,7 @@
 		struct child_process cmd = CHILD_PROCESS_INIT;
 
 		cmd.git_cmd = 1;
-		argv_array_pushl(&cmd.args, "show", "REBASE_HEAD", "--", NULL);
+		strvec_pushl(&cmd.args, "show", "REBASE_HEAD", "--", NULL);
 		ret = run_command(&cmd);
 
 		break;
@@ -811,13 +817,13 @@
 	char *rebased_patches;
 
 	am.git_cmd = 1;
-	argv_array_push(&am.args, "am");
+	strvec_push(&am.args, "am");
 
 	if (opts->action && !strcmp("continue", opts->action)) {
-		argv_array_push(&am.args, "--resolved");
-		argv_array_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
+		strvec_push(&am.args, "--resolved");
+		strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
 		if (opts->gpg_sign_opt)
-			argv_array_push(&am.args, opts->gpg_sign_opt);
+			strvec_push(&am.args, opts->gpg_sign_opt);
 		status = run_command(&am);
 		if (status)
 			return status;
@@ -825,8 +831,8 @@
 		return move_to_original_branch(opts);
 	}
 	if (opts->action && !strcmp("skip", opts->action)) {
-		argv_array_push(&am.args, "--skip");
-		argv_array_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
+		strvec_push(&am.args, "--skip");
+		strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
 		status = run_command(&am);
 		if (status)
 			return status;
@@ -834,7 +840,7 @@
 		return move_to_original_branch(opts);
 	}
 	if (opts->action && !strcmp("show-current-patch", opts->action)) {
-		argv_array_push(&am.args, "--show-current-patch");
+		strvec_push(&am.args, "--show-current-patch");
 		return run_command(&am);
 	}
 
@@ -852,29 +858,29 @@
 		status = error_errno(_("could not open '%s' for writing"),
 				     rebased_patches);
 		free(rebased_patches);
-		argv_array_clear(&am.args);
+		strvec_clear(&am.args);
 		return status;
 	}
 
 	format_patch.git_cmd = 1;
-	argv_array_pushl(&format_patch.args, "format-patch", "-k", "--stdout",
-			 "--full-index", "--cherry-pick", "--right-only",
-			 "--src-prefix=a/", "--dst-prefix=b/", "--no-renames",
-			 "--no-cover-letter", "--pretty=mboxrd", "--topo-order",
-			 "--no-base", NULL);
+	strvec_pushl(&format_patch.args, "format-patch", "-k", "--stdout",
+		     "--full-index", "--cherry-pick", "--right-only",
+		     "--src-prefix=a/", "--dst-prefix=b/", "--no-renames",
+		     "--no-cover-letter", "--pretty=mboxrd", "--topo-order",
+		     "--no-base", NULL);
 	if (opts->git_format_patch_opt.len)
-		argv_array_split(&format_patch.args,
-				 opts->git_format_patch_opt.buf);
-	argv_array_push(&format_patch.args, revisions.buf);
+		strvec_split(&format_patch.args,
+			     opts->git_format_patch_opt.buf);
+	strvec_push(&format_patch.args, revisions.buf);
 	if (opts->restrict_revision)
-		argv_array_pushf(&format_patch.args, "^%s",
-				 oid_to_hex(&opts->restrict_revision->object.oid));
+		strvec_pushf(&format_patch.args, "^%s",
+			     oid_to_hex(&opts->restrict_revision->object.oid));
 
 	status = run_command(&format_patch);
 	if (status) {
 		unlink(rebased_patches);
 		free(rebased_patches);
-		argv_array_clear(&am.args);
+		strvec_clear(&am.args);
 
 		reset_head(the_repository, &opts->orig_head, "checkout",
 			   opts->head_name, 0,
@@ -896,20 +902,20 @@
 		status = error_errno(_("could not open '%s' for reading"),
 				     rebased_patches);
 		free(rebased_patches);
-		argv_array_clear(&am.args);
+		strvec_clear(&am.args);
 		return status;
 	}
 
-	argv_array_pushv(&am.args, opts->git_am_opts.argv);
-	argv_array_push(&am.args, "--rebasing");
-	argv_array_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
-	argv_array_push(&am.args, "--patch-format=mboxrd");
+	strvec_pushv(&am.args, opts->git_am_opts.v);
+	strvec_push(&am.args, "--rebasing");
+	strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
+	strvec_push(&am.args, "--patch-format=mboxrd");
 	if (opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE)
-		argv_array_push(&am.args, "--rerere-autoupdate");
+		strvec_push(&am.args, "--rerere-autoupdate");
 	else if (opts->allow_rerere_autoupdate == RERERE_NOAUTOUPDATE)
-		argv_array_push(&am.args, "--no-rerere-autoupdate");
+		strvec_push(&am.args, "--no-rerere-autoupdate");
 	if (opts->gpg_sign_opt)
-		argv_array_push(&am.args, opts->gpg_sign_opt);
+		strvec_push(&am.args, opts->gpg_sign_opt);
 	status = run_command(&am);
 	unlink(rebased_patches);
 	free(rebased_patches);
@@ -969,7 +975,7 @@
 	add_var(&script_snippet, "revisions", opts->revisions);
 	add_var(&script_snippet, "restrict_revision", opts->restrict_revision ?
 		oid_to_hex(&opts->restrict_revision->object.oid) : NULL);
-	sq_quote_argv_pretty(&buf, opts->git_am_opts.argv);
+	sq_quote_argv_pretty(&buf, opts->git_am_opts.v);
 	add_var(&script_snippet, "git_am_opt", buf.buf);
 	strbuf_release(&buf);
 	add_var(&script_snippet, "verbose",
@@ -1289,6 +1295,7 @@
 	struct strbuf revisions = STRBUF_INIT;
 	struct strbuf buf = STRBUF_INIT;
 	struct object_id merge_base;
+	int ignore_whitespace = 0;
 	enum action action = ACTION_NONE;
 	const char *gpg_sign = NULL;
 	struct string_list exec = STRING_LIST_INIT_NODUP;
@@ -1318,16 +1325,17 @@
 			PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
 		OPT_BOOL(0, "signoff", &options.signoff,
 			 N_("add a Signed-off-by: line to each commit")),
-		OPT_PASSTHRU_ARGV(0, "ignore-whitespace", &options.git_am_opts,
-				  NULL, N_("passed to 'git am'"),
-				  PARSE_OPT_NOARG),
-		OPT_PASSTHRU_ARGV(0, "committer-date-is-author-date",
-				  &options.git_am_opts, NULL,
-				  N_("passed to 'git am'"), PARSE_OPT_NOARG),
-		OPT_PASSTHRU_ARGV(0, "ignore-date", &options.git_am_opts, NULL,
-				  N_("passed to 'git am'"), PARSE_OPT_NOARG),
+		OPT_BOOL(0, "committer-date-is-author-date",
+			 &options.committer_date_is_author_date,
+			 N_("make committer date match author date")),
+		OPT_BOOL(0, "reset-author-date", &options.ignore_date,
+			 N_("ignore author date and use current date")),
+		OPT_HIDDEN_BOOL(0, "ignore-date", &options.ignore_date,
+				N_("synonym of --reset-author-date")),
 		OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),
 				  N_("passed to 'git apply'"), 0),
+		OPT_BOOL(0, "ignore-whitespace", &ignore_whitespace,
+			 N_("ignore changes in whitespace")),
 		OPT_PASSTHRU_ARGV(0, "whitespace", &options.git_am_opts,
 				  N_("action"), N_("passed to 'git apply'"), 0),
 		OPT_BIT('f', "force-rebase", &options.flags,
@@ -1624,12 +1632,12 @@
 	    options.autosquash) {
 		allow_preemptive_ff = 0;
 	}
+	if (options.committer_date_is_author_date || options.ignore_date)
+		options.flags |= REBASE_FORCE;
 
-	for (i = 0; i < options.git_am_opts.argc; i++) {
-		const char *option = options.git_am_opts.argv[i], *p;
-		if (!strcmp(option, "--committer-date-is-author-date") ||
-		    !strcmp(option, "--ignore-date") ||
-		    !strcmp(option, "--whitespace=fix") ||
+	for (i = 0; i < options.git_am_opts.nr; i++) {
+		const char *option = options.git_am_opts.v[i], *p;
+		if (!strcmp(option, "--whitespace=fix") ||
 		    !strcmp(option, "--whitespace=strip"))
 			allow_preemptive_ff = 0;
 		else if (skip_prefix(option, "-C", &p)) {
@@ -1649,7 +1657,7 @@
 			exit(1);
 
 	if (!(options.flags & REBASE_NO_QUIET))
-		argv_array_push(&options.git_am_opts, "-q");
+		strvec_push(&options.git_am_opts, "-q");
 
 	if (options.empty != EMPTY_UNSPECIFIED)
 		imply_merge(&options, "--empty");
@@ -1682,6 +1690,23 @@
 		imply_merge(&options, "--rebase-merges");
 	}
 
+	if (options.type == REBASE_APPLY) {
+		if (ignore_whitespace)
+			strvec_push(&options.git_am_opts,
+				    "--ignore-whitespace");
+		if (options.committer_date_is_author_date)
+			strvec_push(&options.git_am_opts,
+				    "--committer-date-is-author-date");
+		if (options.ignore_date)
+			strvec_push(&options.git_am_opts, "--ignore-date");
+	} else {
+		/* REBASE_MERGE and PRESERVE_MERGES */
+		if (ignore_whitespace) {
+			string_list_append(&strategy_options,
+					   "ignore-space-change");
+		}
+	}
+
 	if (strategy_options.nr) {
 		int i;
 
@@ -1721,10 +1746,10 @@
 	if (isatty(2) && options.flags & REBASE_NO_QUIET)
 		strbuf_addstr(&options.git_format_patch_opt, " --progress");
 
-	if (options.git_am_opts.argc || options.type == REBASE_APPLY) {
+	if (options.git_am_opts.nr || options.type == REBASE_APPLY) {
 		/* all am options except -q are compatible only with --apply */
-		for (i = options.git_am_opts.argc - 1; i >= 0; i--)
-			if (strcmp(options.git_am_opts.argv[i], "-q"))
+		for (i = options.git_am_opts.nr - 1; i >= 0; i--)
+			if (strcmp(options.git_am_opts.v[i], "-q"))
 				break;
 
 		if (i >= 0) {
@@ -1776,7 +1801,7 @@
 		if (options.type == REBASE_PRESERVE_MERGES)
 			die("cannot combine '--signoff' with "
 			    "'--preserve-merges'");
-		argv_array_push(&options.git_am_opts, "--signoff");
+		strvec_push(&options.git_am_opts, "--signoff");
 		options.flags |= REBASE_FORCE;
 	}
 
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index d43663b..439f29d 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -15,7 +15,7 @@
 #include "string-list.h"
 #include "oid-array.h"
 #include "connected.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "version.h"
 #include "tag.h"
 #include "gpg-interface.h"
@@ -667,25 +667,25 @@
 		nonce_status = check_nonce(push_cert.buf, bogs);
 	}
 	if (!is_null_oid(&push_cert_oid)) {
-		argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT=%s",
-				 oid_to_hex(&push_cert_oid));
-		argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT_SIGNER=%s",
-				 sigcheck.signer ? sigcheck.signer : "");
-		argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT_KEY=%s",
-				 sigcheck.key ? sigcheck.key : "");
-		argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT_STATUS=%c",
-				 sigcheck.result);
+		strvec_pushf(&proc->env_array, "GIT_PUSH_CERT=%s",
+			     oid_to_hex(&push_cert_oid));
+		strvec_pushf(&proc->env_array, "GIT_PUSH_CERT_SIGNER=%s",
+			     sigcheck.signer ? sigcheck.signer : "");
+		strvec_pushf(&proc->env_array, "GIT_PUSH_CERT_KEY=%s",
+			     sigcheck.key ? sigcheck.key : "");
+		strvec_pushf(&proc->env_array, "GIT_PUSH_CERT_STATUS=%c",
+			     sigcheck.result);
 		if (push_cert_nonce) {
-			argv_array_pushf(&proc->env_array,
-					 "GIT_PUSH_CERT_NONCE=%s",
-					 push_cert_nonce);
-			argv_array_pushf(&proc->env_array,
-					 "GIT_PUSH_CERT_NONCE_STATUS=%s",
-					 nonce_status);
+			strvec_pushf(&proc->env_array,
+				     "GIT_PUSH_CERT_NONCE=%s",
+				     push_cert_nonce);
+			strvec_pushf(&proc->env_array,
+				     "GIT_PUSH_CERT_NONCE_STATUS=%s",
+				     nonce_status);
 			if (nonce_status == NONCE_SLOP)
-				argv_array_pushf(&proc->env_array,
-						 "GIT_PUSH_CERT_NONCE_SLOP=%ld",
-						 nonce_stamp_slop);
+				strvec_pushf(&proc->env_array,
+					     "GIT_PUSH_CERT_NONCE_SLOP=%ld",
+					     nonce_stamp_slop);
 		}
 	}
 }
@@ -720,16 +720,16 @@
 	if (feed_state->push_options) {
 		int i;
 		for (i = 0; i < feed_state->push_options->nr; i++)
-			argv_array_pushf(&proc.env_array,
-				"GIT_PUSH_OPTION_%d=%s", i,
-				feed_state->push_options->items[i].string);
-		argv_array_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT=%d",
-				 feed_state->push_options->nr);
+			strvec_pushf(&proc.env_array,
+				     "GIT_PUSH_OPTION_%d=%s", i,
+				     feed_state->push_options->items[i].string);
+		strvec_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT=%d",
+			     feed_state->push_options->nr);
 	} else
-		argv_array_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT");
+		strvec_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT");
 
 	if (tmp_objdir)
-		argv_array_pushv(&proc.env_array, tmp_objdir_env(tmp_objdir));
+		strvec_pushv(&proc.env_array, tmp_objdir_env(tmp_objdir));
 
 	if (use_sideband) {
 		memset(&muxer, 0, sizeof(muxer));
@@ -931,7 +931,7 @@
 }
 
 static const char *push_to_deploy(unsigned char *sha1,
-				  struct argv_array *env,
+				  struct strvec *env,
 				  const char *work_tree)
 {
 	const char *update_refresh[] = {
@@ -950,7 +950,7 @@
 	struct child_process child = CHILD_PROCESS_INIT;
 
 	child.argv = update_refresh;
-	child.env = env->argv;
+	child.env = env->v;
 	child.dir = work_tree;
 	child.no_stdin = 1;
 	child.stdout_to_stderr = 1;
@@ -961,7 +961,7 @@
 	/* run_command() does not clean up completely; reinitialize */
 	child_process_init(&child);
 	child.argv = diff_files;
-	child.env = env->argv;
+	child.env = env->v;
 	child.dir = work_tree;
 	child.no_stdin = 1;
 	child.stdout_to_stderr = 1;
@@ -974,7 +974,7 @@
 
 	child_process_init(&child);
 	child.argv = diff_index;
-	child.env = env->argv;
+	child.env = env->v;
 	child.no_stdin = 1;
 	child.no_stdout = 1;
 	child.stdout_to_stderr = 0;
@@ -985,7 +985,7 @@
 	read_tree[3] = hash_to_hex(sha1);
 	child_process_init(&child);
 	child.argv = read_tree;
-	child.env = env->argv;
+	child.env = env->v;
 	child.dir = work_tree;
 	child.no_stdin = 1;
 	child.no_stdout = 1;
@@ -1000,11 +1000,11 @@
 static const char *push_to_checkout_hook = "push-to-checkout";
 
 static const char *push_to_checkout(unsigned char *hash,
-				    struct argv_array *env,
+				    struct strvec *env,
 				    const char *work_tree)
 {
-	argv_array_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree));
-	if (run_hook_le(env->argv, push_to_checkout_hook,
+	strvec_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree));
+	if (run_hook_le(env->v, push_to_checkout_hook,
 			hash_to_hex(hash), NULL))
 		return "push-to-checkout hook declined";
 	else
@@ -1014,7 +1014,7 @@
 static const char *update_worktree(unsigned char *sha1, const struct worktree *worktree)
 {
 	const char *retval, *work_tree, *git_dir = NULL;
-	struct argv_array env = ARGV_ARRAY_INIT;
+	struct strvec env = STRVEC_INIT;
 
 	if (worktree && worktree->path)
 		work_tree = worktree->path;
@@ -1030,14 +1030,14 @@
 	if (!git_dir)
 		git_dir = get_git_dir();
 
-	argv_array_pushf(&env, "GIT_DIR=%s", absolute_path(git_dir));
+	strvec_pushf(&env, "GIT_DIR=%s", absolute_path(git_dir));
 
 	if (!find_hook(push_to_checkout_hook))
 		retval = push_to_deploy(sha1, &env, work_tree);
 	else
 		retval = push_to_checkout(sha1, &env, work_tree);
 
-	argv_array_clear(&env);
+	strvec_clear(&env);
 	return retval;
 }
 
@@ -1205,11 +1205,11 @@
 	for (cmd = commands; cmd; cmd = cmd->next) {
 		if (cmd->error_string || cmd->did_not_exist)
 			continue;
-		if (!proc.args.argc)
-			argv_array_push(&proc.args, hook);
-		argv_array_push(&proc.args, cmd->ref_name);
+		if (!proc.args.nr)
+			strvec_push(&proc.args, hook);
+		strvec_push(&proc.args, cmd->ref_name);
 	}
-	if (!proc.args.argc)
+	if (!proc.args.nr)
 		return;
 
 	proc.no_stdin = 1;
@@ -1715,10 +1715,10 @@
 
 static const char *pack_lockfile;
 
-static void push_header_arg(struct argv_array *args, struct pack_header *hdr)
+static void push_header_arg(struct strvec *args, struct pack_header *hdr)
 {
-	argv_array_pushf(args, "--pack_header=%"PRIu32",%"PRIu32,
-			ntohl(hdr->hdr_version), ntohl(hdr->hdr_entries));
+	strvec_pushf(args, "--pack_header=%"PRIu32",%"PRIu32,
+		     ntohl(hdr->hdr_version), ntohl(hdr->hdr_entries));
 }
 
 static const char *unpack(int err_fd, struct shallow_info *si)
@@ -1742,8 +1742,8 @@
 
 	if (si->nr_ours || si->nr_theirs) {
 		alt_shallow_file = setup_temporary_shallow(si->shallow);
-		argv_array_push(&child.args, "--shallow-file");
-		argv_array_push(&child.args, alt_shallow_file);
+		strvec_push(&child.args, "--shallow-file");
+		strvec_push(&child.args, alt_shallow_file);
 	}
 
 	tmp_objdir = tmp_objdir_create();
@@ -1762,16 +1762,16 @@
 	tmp_objdir_add_as_alternate(tmp_objdir);
 
 	if (ntohl(hdr.hdr_entries) < unpack_limit) {
-		argv_array_push(&child.args, "unpack-objects");
+		strvec_push(&child.args, "unpack-objects");
 		push_header_arg(&child.args, &hdr);
 		if (quiet)
-			argv_array_push(&child.args, "-q");
+			strvec_push(&child.args, "-q");
 		if (fsck_objects)
-			argv_array_pushf(&child.args, "--strict%s",
-				fsck_msg_types.buf);
+			strvec_pushf(&child.args, "--strict%s",
+				     fsck_msg_types.buf);
 		if (max_input_size)
-			argv_array_pushf(&child.args, "--max-input-size=%"PRIuMAX,
-				(uintmax_t)max_input_size);
+			strvec_pushf(&child.args, "--max-input-size=%"PRIuMAX,
+				     (uintmax_t)max_input_size);
 		child.no_stdout = 1;
 		child.err = err_fd;
 		child.git_cmd = 1;
@@ -1781,28 +1781,28 @@
 	} else {
 		char hostname[HOST_NAME_MAX + 1];
 
-		argv_array_pushl(&child.args, "index-pack", "--stdin", NULL);
+		strvec_pushl(&child.args, "index-pack", "--stdin", NULL);
 		push_header_arg(&child.args, &hdr);
 
 		if (xgethostname(hostname, sizeof(hostname)))
 			xsnprintf(hostname, sizeof(hostname), "localhost");
-		argv_array_pushf(&child.args,
-				 "--keep=receive-pack %"PRIuMAX" on %s",
-				 (uintmax_t)getpid(),
-				 hostname);
+		strvec_pushf(&child.args,
+			     "--keep=receive-pack %"PRIuMAX" on %s",
+			     (uintmax_t)getpid(),
+			     hostname);
 
 		if (!quiet && err_fd)
-			argv_array_push(&child.args, "--show-resolving-progress");
+			strvec_push(&child.args, "--show-resolving-progress");
 		if (use_sideband)
-			argv_array_push(&child.args, "--report-end-of-input");
+			strvec_push(&child.args, "--report-end-of-input");
 		if (fsck_objects)
-			argv_array_pushf(&child.args, "--strict%s",
-				fsck_msg_types.buf);
+			strvec_pushf(&child.args, "--strict%s",
+				     fsck_msg_types.buf);
 		if (!reject_thin)
-			argv_array_push(&child.args, "--fix-thin");
+			strvec_push(&child.args, "--fix-thin");
 		if (max_input_size)
-			argv_array_pushf(&child.args, "--max-input-size=%"PRIuMAX,
-				(uintmax_t)max_input_size);
+			strvec_pushf(&child.args, "--max-input-size=%"PRIuMAX,
+				     (uintmax_t)max_input_size);
 		child.out = -1;
 		child.err = err_fd;
 		child.git_cmd = 1;
diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c
index 6a9127a..fd3538d 100644
--- a/builtin/remote-ext.c
+++ b/builtin/remote-ext.c
@@ -117,12 +117,12 @@
 	}
 }
 
-static void parse_argv(struct argv_array *out, const char *arg, const char *service)
+static void parse_argv(struct strvec *out, const char *arg, const char *service)
 {
 	while (*arg) {
 		char *expanded = strip_escapes(arg, service, &arg);
 		if (expanded)
-			argv_array_push(out, expanded);
+			strvec_push(out, expanded);
 		free(expanded);
 	}
 }
diff --git a/builtin/remote.c b/builtin/remote.c
index e837799..542f56e 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -10,7 +10,7 @@
 #include "refs.h"
 #include "refspec.h"
 #include "object-store.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "commit-reach.h"
 
 static const char * const builtin_remote_usage[] = {
@@ -478,6 +478,7 @@
 	struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
 	struct refspec_item refspec;
 
+	memset(&refspec, 0, sizeof(refspec));
 	refspec.force = 0;
 	refspec.pattern = 1;
 	refspec.src = refspec.dst = "refs/heads/*";
@@ -1451,35 +1452,35 @@
 			 N_("prune remotes after fetching")),
 		OPT_END()
 	};
-	struct argv_array fetch_argv = ARGV_ARRAY_INIT;
+	struct strvec fetch_argv = STRVEC_INIT;
 	int default_defined = 0;
 	int retval;
 
 	argc = parse_options(argc, argv, NULL, options, builtin_remote_update_usage,
 			     PARSE_OPT_KEEP_ARGV0);
 
-	argv_array_push(&fetch_argv, "fetch");
+	strvec_push(&fetch_argv, "fetch");
 
 	if (prune != -1)
-		argv_array_push(&fetch_argv, prune ? "--prune" : "--no-prune");
+		strvec_push(&fetch_argv, prune ? "--prune" : "--no-prune");
 	if (verbose)
-		argv_array_push(&fetch_argv, "-v");
-	argv_array_push(&fetch_argv, "--multiple");
+		strvec_push(&fetch_argv, "-v");
+	strvec_push(&fetch_argv, "--multiple");
 	if (argc < 2)
-		argv_array_push(&fetch_argv, "default");
+		strvec_push(&fetch_argv, "default");
 	for (i = 1; i < argc; i++)
-		argv_array_push(&fetch_argv, argv[i]);
+		strvec_push(&fetch_argv, argv[i]);
 
-	if (strcmp(fetch_argv.argv[fetch_argv.argc-1], "default") == 0) {
+	if (strcmp(fetch_argv.v[fetch_argv.nr-1], "default") == 0) {
 		git_config(get_remote_default, &default_defined);
 		if (!default_defined) {
-			argv_array_pop(&fetch_argv);
-			argv_array_push(&fetch_argv, "--all");
+			strvec_pop(&fetch_argv);
+			strvec_push(&fetch_argv, "--all");
 		}
 	}
 
-	retval = run_command_v_opt(fetch_argv.argv, RUN_GIT_CMD);
-	argv_array_clear(&fetch_argv);
+	retval = run_command_v_opt(fetch_argv.v, RUN_GIT_CMD);
+	strvec_clear(&fetch_argv);
 	return retval;
 }
 
diff --git a/builtin/repack.c b/builtin/repack.c
index df28773..01e7767 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -7,7 +7,7 @@
 #include "sigchain.h"
 #include "strbuf.h"
 #include "string-list.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "midx.h"
 #include "packfile.h"
 #include "prune-packed.h"
@@ -133,7 +133,11 @@
 static void remove_redundant_pack(const char *dir_name, const char *base_name)
 {
 	struct strbuf buf = STRBUF_INIT;
-	strbuf_addf(&buf, "%s/%s.pack", dir_name, base_name);
+	struct multi_pack_index *m = get_local_multi_pack_index(the_repository);
+	strbuf_addf(&buf, "%s.pack", base_name);
+	if (m && midx_contains_pack(m, buf.buf))
+		clear_midx_file(the_repository);
+	strbuf_insertf(&buf, 0, "%s/", dir_name);
 	unlink_pack_path(buf.buf, 1);
 	strbuf_release(&buf);
 }
@@ -153,28 +157,28 @@
 static void prepare_pack_objects(struct child_process *cmd,
 				 const struct pack_objects_args *args)
 {
-	argv_array_push(&cmd->args, "pack-objects");
+	strvec_push(&cmd->args, "pack-objects");
 	if (args->window)
-		argv_array_pushf(&cmd->args, "--window=%s", args->window);
+		strvec_pushf(&cmd->args, "--window=%s", args->window);
 	if (args->window_memory)
-		argv_array_pushf(&cmd->args, "--window-memory=%s", args->window_memory);
+		strvec_pushf(&cmd->args, "--window-memory=%s", args->window_memory);
 	if (args->depth)
-		argv_array_pushf(&cmd->args, "--depth=%s", args->depth);
+		strvec_pushf(&cmd->args, "--depth=%s", args->depth);
 	if (args->threads)
-		argv_array_pushf(&cmd->args, "--threads=%s", args->threads);
+		strvec_pushf(&cmd->args, "--threads=%s", args->threads);
 	if (args->max_pack_size)
-		argv_array_pushf(&cmd->args, "--max-pack-size=%s", args->max_pack_size);
+		strvec_pushf(&cmd->args, "--max-pack-size=%s", args->max_pack_size);
 	if (args->no_reuse_delta)
-		argv_array_pushf(&cmd->args, "--no-reuse-delta");
+		strvec_pushf(&cmd->args, "--no-reuse-delta");
 	if (args->no_reuse_object)
-		argv_array_pushf(&cmd->args, "--no-reuse-object");
+		strvec_pushf(&cmd->args, "--no-reuse-object");
 	if (args->local)
-		argv_array_push(&cmd->args,  "--local");
+		strvec_push(&cmd->args,  "--local");
 	if (args->quiet)
-		argv_array_push(&cmd->args,  "--quiet");
+		strvec_push(&cmd->args,  "--quiet");
 	if (delta_base_offset)
-		argv_array_push(&cmd->args,  "--delta-base-offset");
-	argv_array_push(&cmd->args, packtmp);
+		strvec_push(&cmd->args,  "--delta-base-offset");
+	strvec_push(&cmd->args, packtmp);
 	cmd->git_cmd = 1;
 	cmd->out = -1;
 }
@@ -286,7 +290,6 @@
 	int keep_unreachable = 0;
 	struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
 	int no_update_server_info = 0;
-	int midx_cleared = 0;
 	struct pack_objects_args po_args = {NULL};
 
 	struct option builtin_repack_options[] = {
@@ -361,24 +364,24 @@
 
 	prepare_pack_objects(&cmd, &po_args);
 
-	argv_array_push(&cmd.args, "--keep-true-parents");
+	strvec_push(&cmd.args, "--keep-true-parents");
 	if (!pack_kept_objects)
-		argv_array_push(&cmd.args, "--honor-pack-keep");
+		strvec_push(&cmd.args, "--honor-pack-keep");
 	for (i = 0; i < keep_pack_list.nr; i++)
-		argv_array_pushf(&cmd.args, "--keep-pack=%s",
-				 keep_pack_list.items[i].string);
-	argv_array_push(&cmd.args, "--non-empty");
-	argv_array_push(&cmd.args, "--all");
-	argv_array_push(&cmd.args, "--reflog");
-	argv_array_push(&cmd.args, "--indexed-objects");
+		strvec_pushf(&cmd.args, "--keep-pack=%s",
+			     keep_pack_list.items[i].string);
+	strvec_push(&cmd.args, "--non-empty");
+	strvec_push(&cmd.args, "--all");
+	strvec_push(&cmd.args, "--reflog");
+	strvec_push(&cmd.args, "--indexed-objects");
 	if (has_promisor_remote())
-		argv_array_push(&cmd.args, "--exclude-promisor-objects");
+		strvec_push(&cmd.args, "--exclude-promisor-objects");
 	if (write_bitmaps > 0)
-		argv_array_push(&cmd.args, "--write-bitmap-index");
+		strvec_push(&cmd.args, "--write-bitmap-index");
 	else if (write_bitmaps < 0)
-		argv_array_push(&cmd.args, "--write-bitmap-index-quiet");
+		strvec_push(&cmd.args, "--write-bitmap-index-quiet");
 	if (use_delta_islands)
-		argv_array_push(&cmd.args, "--delta-islands");
+		strvec_push(&cmd.args, "--delta-islands");
 
 	if (pack_everything & ALL_INTO_ONE) {
 		get_non_kept_pack_filenames(&existing_packs, &keep_pack_list);
@@ -387,23 +390,23 @@
 
 		if (existing_packs.nr && delete_redundant) {
 			if (unpack_unreachable) {
-				argv_array_pushf(&cmd.args,
-						"--unpack-unreachable=%s",
-						unpack_unreachable);
-				argv_array_push(&cmd.env_array, "GIT_REF_PARANOIA=1");
+				strvec_pushf(&cmd.args,
+					     "--unpack-unreachable=%s",
+					     unpack_unreachable);
+				strvec_push(&cmd.env_array, "GIT_REF_PARANOIA=1");
 			} else if (pack_everything & LOOSEN_UNREACHABLE) {
-				argv_array_push(&cmd.args,
-						"--unpack-unreachable");
+				strvec_push(&cmd.args,
+					    "--unpack-unreachable");
 			} else if (keep_unreachable) {
-				argv_array_push(&cmd.args, "--keep-unreachable");
-				argv_array_push(&cmd.args, "--pack-loose-unreachable");
+				strvec_push(&cmd.args, "--keep-unreachable");
+				strvec_push(&cmd.args, "--pack-loose-unreachable");
 			} else {
-				argv_array_push(&cmd.env_array, "GIT_REF_PARANOIA=1");
+				strvec_push(&cmd.env_array, "GIT_REF_PARANOIA=1");
 			}
 		}
 	} else {
-		argv_array_push(&cmd.args, "--unpacked");
-		argv_array_push(&cmd.args, "--incremental");
+		strvec_push(&cmd.args, "--unpacked");
+		strvec_push(&cmd.args, "--incremental");
 	}
 
 	cmd.no_stdin = 1;
@@ -439,11 +442,6 @@
 		for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
 			char *fname, *fname_old;
 
-			if (!midx_cleared) {
-				clear_midx_file(the_repository);
-				midx_cleared = 1;
-			}
-
 			fname = mkpathdup("%s/pack-%s%s", packdir,
 						item->string, exts[ext].name);
 			if (!file_exists(fname)) {
diff --git a/builtin/replace.c b/builtin/replace.c
index b36d17a..cd48765 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -228,13 +228,13 @@
 	if (fd < 0)
 		return error_errno(_("unable to open %s for writing"), filename);
 
-	argv_array_push(&cmd.args, "--no-replace-objects");
-	argv_array_push(&cmd.args, "cat-file");
+	strvec_push(&cmd.args, "--no-replace-objects");
+	strvec_push(&cmd.args, "cat-file");
 	if (raw)
-		argv_array_push(&cmd.args, type_name(type));
+		strvec_push(&cmd.args, type_name(type));
 	else
-		argv_array_push(&cmd.args, "-p");
-	argv_array_push(&cmd.args, oid_to_hex(oid));
+		strvec_push(&cmd.args, "-p");
+	strvec_push(&cmd.args, oid_to_hex(oid));
 	cmd.git_cmd = 1;
 	cmd.out = fd;
 
@@ -502,7 +502,7 @@
 	const char *graft_file = get_graft_file(the_repository);
 	FILE *fp = fopen_or_warn(graft_file, "r");
 	struct strbuf buf = STRBUF_INIT, err = STRBUF_INIT;
-	struct argv_array args = ARGV_ARRAY_INIT;
+	struct strvec args = STRVEC_INIT;
 
 	if (!fp)
 		return -1;
@@ -512,10 +512,10 @@
 		if (*buf.buf == '#')
 			continue;
 
-		argv_array_split(&args, buf.buf);
-		if (args.argc && create_graft(args.argc, args.argv, force, 1))
+		strvec_split(&args, buf.buf);
+		if (args.nr && create_graft(args.nr, args.v, force, 1))
 			strbuf_addf(&err, "\n\t%s", buf.buf);
-		argv_array_clear(&args);
+		strvec_clear(&args);
 	}
 	fclose(fp);
 
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index f520111..25c6c3b 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -637,8 +637,15 @@
 
 	if (bisect_list) {
 		int reaches, all;
+		unsigned bisect_flags = 0;
 
-		find_bisection(&revs.commits, &reaches, &all, bisect_find_all);
+		if (bisect_find_all)
+			bisect_flags |= FIND_BISECTION_ALL;
+
+		if (revs.first_parent_only)
+			bisect_flags |= FIND_BISECTION_FIRST_PARENT_ONLY;
+
+		find_bisection(&revs.commits, &reaches, &all, bisect_flags);
 
 		if (bisect_show_vars)
 			return show_bisect_vars(&info, reaches, all);
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index a472862..d6d2dab 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -4,7 +4,7 @@
 #include "refs.h"
 #include "builtin.h"
 #include "color.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "parse-options.h"
 #include "dir.h"
 #include "commit-slab.h"
@@ -20,7 +20,7 @@
 
 static int showbranch_use_color = -1;
 
-static struct argv_array default_args = ARGV_ARRAY_INIT;
+static struct strvec default_args = STRVEC_INIT;
 
 /*
  * TODO: convert this use of commit->object.flags to commit-slab
@@ -561,9 +561,9 @@
 		 * default_arg is now passed to parse_options(), so we need to
 		 * mimic the real argv a bit better.
 		 */
-		if (!default_args.argc)
-			argv_array_push(&default_args, "show-branch");
-		argv_array_push(&default_args, value);
+		if (!default_args.nr)
+			strvec_push(&default_args, "show-branch");
+		strvec_push(&default_args, value);
 		return 0;
 	}
 
@@ -684,9 +684,9 @@
 	git_config(git_show_branch_config, NULL);
 
 	/* If nothing is specified, try the default first */
-	if (ac == 1 && default_args.argc) {
-		ac = default_args.argc;
-		av = default_args.argv;
+	if (ac == 1 && default_args.nr) {
+		ac = default_args.nr;
+		av = default_args.v;
 	}
 
 	ac = parse_options(ac, av, prefix, builtin_show_branch_options,
diff --git a/builtin/stash.c b/builtin/stash.c
index 9312cd1..3f811f3 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -7,7 +7,7 @@
 #include "cache-tree.h"
 #include "unpack-trees.h"
 #include "merge-recursive.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "run-command.h"
 #include "dir.h"
 #include "rerere.h"
@@ -277,8 +277,8 @@
 	 * however it should be done together with apply_cached.
 	 */
 	cp.git_cmd = 1;
-	argv_array_pushl(&cp.args, "diff-tree", "--binary", NULL);
-	argv_array_pushf(&cp.args, "%s^2^..%s^2", w_commit_hex, w_commit_hex);
+	strvec_pushl(&cp.args, "diff-tree", "--binary", NULL);
+	strvec_pushf(&cp.args, "%s^2^..%s^2", w_commit_hex, w_commit_hex);
 
 	return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
 }
@@ -293,7 +293,7 @@
 	 * buffer.
 	 */
 	cp.git_cmd = 1;
-	argv_array_pushl(&cp.args, "apply", "--cached", NULL);
+	strvec_pushl(&cp.args, "apply", "--cached", NULL);
 	return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
 }
 
@@ -306,7 +306,7 @@
 	 * API for resetting.
 	 */
 	cp.git_cmd = 1;
-	argv_array_push(&cp.args, "reset");
+	strvec_push(&cp.args, "reset");
 
 	return run_command(&cp);
 }
@@ -335,9 +335,9 @@
 	 * converted together with update_index.
 	 */
 	cp.git_cmd = 1;
-	argv_array_pushl(&cp.args, "diff-index", "--cached", "--name-only",
-			 "--diff-filter=A", NULL);
-	argv_array_push(&cp.args, c_tree_hex);
+	strvec_pushl(&cp.args, "diff-index", "--cached", "--name-only",
+		     "--diff-filter=A", NULL);
+	strvec_push(&cp.args, c_tree_hex);
 	return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
 }
 
@@ -350,7 +350,7 @@
 	 * function exposed in order to remove this forking.
 	 */
 	cp.git_cmd = 1;
-	argv_array_pushl(&cp.args, "update-index", "--add", "--stdin", NULL);
+	strvec_pushl(&cp.args, "update-index", "--add", "--stdin", NULL);
 	return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
 }
 
@@ -365,10 +365,10 @@
 	 * run_command to fork processes that will not interfere.
 	 */
 	cp.git_cmd = 1;
-	argv_array_push(&cp.args, "read-tree");
-	argv_array_push(&cp.args, oid_to_hex(u_tree));
-	argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
-			 stash_index_path.buf);
+	strvec_push(&cp.args, "read-tree");
+	strvec_push(&cp.args, oid_to_hex(u_tree));
+	strvec_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
+		     stash_index_path.buf);
 	if (run_command(&cp)) {
 		remove_path(stash_index_path.buf);
 		return -1;
@@ -376,9 +376,9 @@
 
 	child_process_init(&cp);
 	cp.git_cmd = 1;
-	argv_array_pushl(&cp.args, "checkout-index", "--all", NULL);
-	argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
-			 stash_index_path.buf);
+	strvec_pushl(&cp.args, "checkout-index", "--all", NULL);
+	strvec_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
+		     stash_index_path.buf);
 
 	res = run_command(&cp);
 	remove_path(stash_index_path.buf);
@@ -499,11 +499,11 @@
 		 */
 		cp.git_cmd = 1;
 		cp.dir = prefix;
-		argv_array_pushf(&cp.env_array, GIT_WORK_TREE_ENVIRONMENT"=%s",
-				 absolute_path(get_git_work_tree()));
-		argv_array_pushf(&cp.env_array, GIT_DIR_ENVIRONMENT"=%s",
-				 absolute_path(get_git_dir()));
-		argv_array_push(&cp.args, "status");
+		strvec_pushf(&cp.env_array, GIT_WORK_TREE_ENVIRONMENT"=%s",
+			     absolute_path(get_git_work_tree()));
+		strvec_pushf(&cp.env_array, GIT_DIR_ENVIRONMENT"=%s",
+			     absolute_path(get_git_dir()));
+		strvec_push(&cp.args, "status");
 		run_command(&cp);
 	}
 
@@ -546,9 +546,9 @@
 	 */
 
 	cp_reflog.git_cmd = 1;
-	argv_array_pushl(&cp_reflog.args, "reflog", "delete", "--updateref",
-			 "--rewrite", NULL);
-	argv_array_push(&cp_reflog.args, info->revision.buf);
+	strvec_pushl(&cp_reflog.args, "reflog", "delete", "--updateref",
+		     "--rewrite", NULL);
+	strvec_push(&cp_reflog.args, info->revision.buf);
 	ret = run_command(&cp_reflog);
 	if (!ret) {
 		if (!quiet)
@@ -566,8 +566,8 @@
 	cp.git_cmd = 1;
 	/* Even though --quiet is specified, rev-parse still outputs the hash */
 	cp.no_stdout = 1;
-	argv_array_pushl(&cp.args, "rev-parse", "--verify", "--quiet", NULL);
-	argv_array_pushf(&cp.args, "%s@{0}", ref_stash);
+	strvec_pushl(&cp.args, "rev-parse", "--verify", "--quiet", NULL);
+	strvec_pushf(&cp.args, "%s@{0}", ref_stash);
 	ret = run_command(&cp);
 
 	/* do_clear_stash if we just dropped the last stash entry */
@@ -663,9 +663,9 @@
 		return -1;
 
 	cp.git_cmd = 1;
-	argv_array_pushl(&cp.args, "checkout", "-b", NULL);
-	argv_array_push(&cp.args, branch);
-	argv_array_push(&cp.args, oid_to_hex(&info.b_commit));
+	strvec_pushl(&cp.args, "checkout", "-b", NULL);
+	strvec_push(&cp.args, branch);
+	strvec_push(&cp.args, oid_to_hex(&info.b_commit));
 	ret = run_command(&cp);
 	if (!ret)
 		ret = do_apply_stash(prefix, &info, 1, 0);
@@ -692,11 +692,11 @@
 		return 0;
 
 	cp.git_cmd = 1;
-	argv_array_pushl(&cp.args, "log", "--format=%gd: %gs", "-g",
-			 "--first-parent", "-m", NULL);
-	argv_array_pushv(&cp.args, argv);
-	argv_array_push(&cp.args, ref_stash);
-	argv_array_push(&cp.args, "--");
+	strvec_pushl(&cp.args, "log", "--format=%gd: %gs", "-g",
+		     "--first-parent", "-m", NULL);
+	strvec_pushv(&cp.args, argv);
+	strvec_push(&cp.args, ref_stash);
+	strvec_push(&cp.args, "--");
 	return run_command(&cp);
 }
 
@@ -727,8 +727,8 @@
 	int ret = 0;
 	struct stash_info info;
 	struct rev_info rev;
-	struct argv_array stash_args = ARGV_ARRAY_INIT;
-	struct argv_array revision_args = ARGV_ARRAY_INIT;
+	struct strvec stash_args = STRVEC_INIT;
+	struct strvec revision_args = STRVEC_INIT;
 	struct option options[] = {
 		OPT_END()
 	};
@@ -737,16 +737,16 @@
 	git_config(git_diff_ui_config, NULL);
 	init_revisions(&rev, prefix);
 
-	argv_array_push(&revision_args, argv[0]);
+	strvec_push(&revision_args, argv[0]);
 	for (i = 1; i < argc; i++) {
 		if (argv[i][0] != '-')
-			argv_array_push(&stash_args, argv[i]);
+			strvec_push(&stash_args, argv[i]);
 		else
-			argv_array_push(&revision_args, argv[i]);
+			strvec_push(&revision_args, argv[i]);
 	}
 
-	ret = get_stash_info(&info, stash_args.argc, stash_args.argv);
-	argv_array_clear(&stash_args);
+	ret = get_stash_info(&info, stash_args.nr, stash_args.v);
+	strvec_clear(&stash_args);
 	if (ret)
 		return -1;
 
@@ -754,7 +754,7 @@
 	 * The config settings are applied only if there are not passed
 	 * any options.
 	 */
-	if (revision_args.argc == 1) {
+	if (revision_args.nr == 1) {
 		if (show_stat)
 			rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT;
 
@@ -767,7 +767,7 @@
 		}
 	}
 
-	argc = setup_revisions(revision_args.argc, revision_args.argv, &rev, NULL);
+	argc = setup_revisions(revision_args.nr, revision_args.v, &rev, NULL);
 	if (argc > 1) {
 		free_stash_info(&info);
 		usage_with_options(git_stash_show_usage, options);
@@ -842,12 +842,12 @@
 	return do_store_stash(&obj, stash_msg, quiet);
 }
 
-static void add_pathspecs(struct argv_array *args,
+static void add_pathspecs(struct strvec *args,
 			  const struct pathspec *ps) {
 	int i;
 
 	for (i = 0; i < ps->nr; i++)
-		argv_array_push(args, ps->items[i].original);
+		strvec_push(args, ps->items[i].original);
 }
 
 /*
@@ -864,7 +864,7 @@
 	int found = 0;
 	struct dir_struct dir;
 
-	memset(&dir, 0, sizeof(dir));
+	dir_init(&dir);
 	if (include_untracked != INCLUDE_ALL_FILES)
 		setup_standard_excludes(&dir);
 
@@ -875,12 +875,9 @@
 		strbuf_addstr(untracked_files, ent->name);
 		/* NUL-terminate: will be fed to update-index -z */
 		strbuf_addch(untracked_files, '\0');
-		free(ent);
 	}
 
-	free(dir.entries);
-	free(dir.ignored);
-	clear_directory(&dir);
+	dir_clear(&dir);
 	return found;
 }
 
@@ -960,9 +957,9 @@
 	struct index_state istate = { NULL };
 
 	cp_upd_index.git_cmd = 1;
-	argv_array_pushl(&cp_upd_index.args, "update-index", "-z", "--add",
-			 "--remove", "--stdin", NULL);
-	argv_array_pushf(&cp_upd_index.env_array, "GIT_INDEX_FILE=%s",
+	strvec_pushl(&cp_upd_index.args, "update-index", "-z", "--add",
+		     "--remove", "--stdin", NULL);
+	strvec_pushf(&cp_upd_index.env_array, "GIT_INDEX_FILE=%s",
 			 stash_index_path.buf);
 
 	strbuf_addf(&untracked_msg, "untracked files on %s\n", msg->buf);
@@ -1003,9 +1000,9 @@
 	remove_path(stash_index_path.buf);
 
 	cp_read_tree.git_cmd = 1;
-	argv_array_pushl(&cp_read_tree.args, "read-tree", "HEAD", NULL);
-	argv_array_pushf(&cp_read_tree.env_array, "GIT_INDEX_FILE=%s",
-			 stash_index_path.buf);
+	strvec_pushl(&cp_read_tree.args, "read-tree", "HEAD", NULL);
+	strvec_pushf(&cp_read_tree.env_array, "GIT_INDEX_FILE=%s",
+		     stash_index_path.buf);
 	if (run_command(&cp_read_tree)) {
 		ret = -1;
 		goto done;
@@ -1034,8 +1031,8 @@
 	}
 
 	cp_diff_tree.git_cmd = 1;
-	argv_array_pushl(&cp_diff_tree.args, "diff-tree", "-p", "-U1", "HEAD",
-			 oid_to_hex(&info->w_tree), "--", NULL);
+	strvec_pushl(&cp_diff_tree.args, "diff-tree", "-p", "-U1", "HEAD",
+		     oid_to_hex(&info->w_tree), "--", NULL);
 	if (pipe_command(&cp_diff_tree, NULL, 0, out_patch, 0, NULL, 0)) {
 		ret = -1;
 		goto done;
@@ -1088,11 +1085,11 @@
 	}
 
 	cp_upd_index.git_cmd = 1;
-	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);
+	strvec_pushl(&cp_upd_index.args, "update-index",
+		     "--ignore-skip-worktree-entries",
+		     "-z", "--add", "--remove", "--stdin", NULL);
+	strvec_pushf(&cp_upd_index.env_array, "GIT_INDEX_FILE=%s",
+		     stash_index_path.buf);
 
 	if (pipe_command(&cp_upd_index, diff_output.buf, diff_output.len,
 			 NULL, 0, NULL, 0)) {
@@ -1342,10 +1339,10 @@
 			struct child_process cp = CHILD_PROCESS_INIT;
 
 			cp.git_cmd = 1;
-			argv_array_pushl(&cp.args, "clean", "--force",
-					 "--quiet", "-d", NULL);
+			strvec_pushl(&cp.args, "clean", "--force",
+				     "--quiet", "-d", NULL);
 			if (include_untracked == INCLUDE_ALL_FILES)
-				argv_array_push(&cp.args, "-x");
+				strvec_push(&cp.args, "-x");
 			if (run_command(&cp)) {
 				ret = -1;
 				goto done;
@@ -1359,12 +1356,12 @@
 			struct strbuf out = STRBUF_INIT;
 
 			cp_add.git_cmd = 1;
-			argv_array_push(&cp_add.args, "add");
+			strvec_push(&cp_add.args, "add");
 			if (!include_untracked)
-				argv_array_push(&cp_add.args, "-u");
+				strvec_push(&cp_add.args, "-u");
 			if (include_untracked == INCLUDE_ALL_FILES)
-				argv_array_push(&cp_add.args, "--force");
-			argv_array_push(&cp_add.args, "--");
+				strvec_push(&cp_add.args, "--force");
+			strvec_push(&cp_add.args, "--");
 			add_pathspecs(&cp_add.args, ps);
 			if (run_command(&cp_add)) {
 				ret = -1;
@@ -1372,9 +1369,9 @@
 			}
 
 			cp_diff.git_cmd = 1;
-			argv_array_pushl(&cp_diff.args, "diff-index", "-p",
-					 "--cached", "--binary", "HEAD", "--",
-					 NULL);
+			strvec_pushl(&cp_diff.args, "diff-index", "-p",
+				     "--cached", "--binary", "HEAD", "--",
+				     NULL);
 			add_pathspecs(&cp_diff.args, ps);
 			if (pipe_command(&cp_diff, NULL, 0, &out, 0, NULL, 0)) {
 				ret = -1;
@@ -1382,8 +1379,8 @@
 			}
 
 			cp_apply.git_cmd = 1;
-			argv_array_pushl(&cp_apply.args, "apply", "--index",
-					 "-R", NULL);
+			strvec_pushl(&cp_apply.args, "apply", "--index",
+				     "-R", NULL);
 			if (pipe_command(&cp_apply, out.buf, out.len, NULL, 0,
 					 NULL, 0)) {
 				ret = -1;
@@ -1392,8 +1389,8 @@
 		} else {
 			struct child_process cp = CHILD_PROCESS_INIT;
 			cp.git_cmd = 1;
-			argv_array_pushl(&cp.args, "reset", "--hard", "-q",
-					 "--no-recurse-submodules", NULL);
+			strvec_pushl(&cp.args, "reset", "--hard", "-q",
+				     "--no-recurse-submodules", NULL);
 			if (run_command(&cp)) {
 				ret = -1;
 				goto done;
@@ -1404,10 +1401,10 @@
 			struct child_process cp = CHILD_PROCESS_INIT;
 
 			cp.git_cmd = 1;
-			argv_array_pushl(&cp.args, "checkout", "--no-overlay",
-					 oid_to_hex(&info.i_tree), "--", NULL);
+			strvec_pushl(&cp.args, "checkout", "--no-overlay",
+				     oid_to_hex(&info.i_tree), "--", NULL);
 			if (!ps->nr)
-				argv_array_push(&cp.args, ":/");
+				strvec_push(&cp.args, ":/");
 			else
 				add_pathspecs(&cp.args, ps);
 			if (run_command(&cp)) {
@@ -1420,7 +1417,7 @@
 		struct child_process cp = CHILD_PROCESS_INIT;
 
 		cp.git_cmd = 1;
-		argv_array_pushl(&cp.args, "apply", "-R", NULL);
+		strvec_pushl(&cp.args, "apply", "-R", NULL);
 
 		if (pipe_command(&cp, patch.buf, patch.len, NULL, 0, NULL, 0)) {
 			if (!quiet)
@@ -1434,7 +1431,7 @@
 			struct child_process cp = CHILD_PROCESS_INIT;
 
 			cp.git_cmd = 1;
-			argv_array_pushl(&cp.args, "reset", "-q", "--", NULL);
+			strvec_pushl(&cp.args, "reset", "-q", "--", NULL);
 			add_pathspecs(&cp.args, ps);
 			if (run_command(&cp)) {
 				ret = -1;
@@ -1560,7 +1557,7 @@
 {
 	pid_t pid = getpid();
 	const char *index_file;
-	struct argv_array args = ARGV_ARRAY_INIT;
+	struct strvec args = STRVEC_INIT;
 
 	struct option options[] = {
 		OPT_END()
@@ -1609,7 +1606,7 @@
 			      git_stash_usage, options);
 
 	/* Assume 'stash push' */
-	argv_array_push(&args, "push");
-	argv_array_pushv(&args, argv);
-	return !!push_stash(args.argc, args.argv, prefix, 1);
+	strvec_push(&args, "push");
+	strvec_pushv(&args, argv);
+	return !!push_stash(args.nr, args.v, prefix, 1);
 }
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index a1c7560..de5ad73 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -294,9 +294,9 @@
 		cp.git_cmd = 1;
 		cp.no_stderr = 1;
 
-		argv_array_push(&cp.args, "describe");
-		argv_array_pushv(&cp.args, *d);
-		argv_array_push(&cp.args, object_id);
+		strvec_push(&cp.args, "describe");
+		strvec_pushv(&cp.args, *d);
+		strvec_push(&cp.args, object_id);
 
 		if (!capture_command(&cp, &sb, 0)) {
 			strbuf_strip_suffix(&sb, "\n");
@@ -495,12 +495,12 @@
 		char *toplevel = xgetcwd();
 		struct strbuf sb = STRBUF_INIT;
 
-		argv_array_pushf(&cp.env_array, "name=%s", sub->name);
-		argv_array_pushf(&cp.env_array, "sm_path=%s", path);
-		argv_array_pushf(&cp.env_array, "displaypath=%s", displaypath);
-		argv_array_pushf(&cp.env_array, "sha1=%s",
-				oid_to_hex(ce_oid));
-		argv_array_pushf(&cp.env_array, "toplevel=%s", toplevel);
+		strvec_pushf(&cp.env_array, "name=%s", sub->name);
+		strvec_pushf(&cp.env_array, "sm_path=%s", path);
+		strvec_pushf(&cp.env_array, "displaypath=%s", displaypath);
+		strvec_pushf(&cp.env_array, "sha1=%s",
+			     oid_to_hex(ce_oid));
+		strvec_pushf(&cp.env_array, "toplevel=%s", toplevel);
 
 		/*
 		 * Since the path variable was accessible from the script
@@ -509,15 +509,15 @@
 		 * on windows. And since environment variables are
 		 * case-insensitive in windows, it interferes with the
 		 * existing PATH variable. Hence, to avoid that, we expose
-		 * path via the args argv_array and not via env_array.
+		 * path via the args strvec and not via env_array.
 		 */
 		sq_quote_buf(&sb, path);
-		argv_array_pushf(&cp.args, "path=%s; %s",
-				 sb.buf, info->argv[0]);
+		strvec_pushf(&cp.args, "path=%s; %s",
+			     sb.buf, info->argv[0]);
 		strbuf_release(&sb);
 		free(toplevel);
 	} else {
-		argv_array_pushv(&cp.args, info->argv);
+		strvec_pushv(&cp.args, info->argv);
 	}
 
 	if (!info->quiet)
@@ -534,16 +534,16 @@
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env_array);
 
-		argv_array_pushl(&cpr.args, "--super-prefix", NULL);
-		argv_array_pushf(&cpr.args, "%s/", displaypath);
-		argv_array_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive",
-				NULL);
+		strvec_pushl(&cpr.args, "--super-prefix", NULL);
+		strvec_pushf(&cpr.args, "%s/", displaypath);
+		strvec_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive",
+			     NULL);
 
 		if (info->quiet)
-			argv_array_push(&cpr.args, "--quiet");
+			strvec_push(&cpr.args, "--quiet");
 
-		argv_array_push(&cpr.args, "--");
-		argv_array_pushv(&cpr.args, info->argv);
+		strvec_push(&cpr.args, "--");
+		strvec_pushv(&cpr.args, info->argv);
 
 		if (run_command(&cpr))
 			die(_("run_command returned non-zero status while "
@@ -612,7 +612,6 @@
 	const char *prefix;
 	unsigned int flags;
 };
-
 #define INIT_CB_INIT { NULL, 0 }
 
 static void init_submodule(const char *path, const char *prefix,
@@ -742,7 +741,6 @@
 	const char *prefix;
 	unsigned int flags;
 };
-
 #define STATUS_CB_INIT { NULL, 0 }
 
 static void print_status(unsigned int flags, char state, const char *path,
@@ -779,7 +777,7 @@
 			     unsigned int flags)
 {
 	char *displaypath;
-	struct argv_array diff_files_args = ARGV_ARRAY_INIT;
+	struct strvec diff_files_args = STRVEC_INIT;
 	struct rev_info rev;
 	int diff_files_result;
 	struct strbuf buf = STRBUF_INIT;
@@ -809,17 +807,17 @@
 	}
 	strbuf_release(&buf);
 
-	argv_array_pushl(&diff_files_args, "diff-files",
-			 "--ignore-submodules=dirty", "--quiet", "--",
-			 path, NULL);
+	strvec_pushl(&diff_files_args, "diff-files",
+		     "--ignore-submodules=dirty", "--quiet", "--",
+		     path, NULL);
 
 	git_config(git_diff_basic_config, NULL);
 
 	repo_init_revisions(the_repository, &rev, NULL);
 	rev.abbrev = 0;
-	diff_files_args.argc = setup_revisions(diff_files_args.argc,
-					       diff_files_args.argv,
-					       &rev, NULL);
+	diff_files_args.nr = setup_revisions(diff_files_args.nr,
+					     diff_files_args.v,
+					     &rev, NULL);
 	diff_files_result = run_diff_files(&rev, 0);
 
 	if (!diff_result_code(&rev.diffopt, diff_files_result)) {
@@ -849,23 +847,23 @@
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env_array);
 
-		argv_array_push(&cpr.args, "--super-prefix");
-		argv_array_pushf(&cpr.args, "%s/", displaypath);
-		argv_array_pushl(&cpr.args, "submodule--helper", "status",
-				 "--recursive", NULL);
+		strvec_push(&cpr.args, "--super-prefix");
+		strvec_pushf(&cpr.args, "%s/", displaypath);
+		strvec_pushl(&cpr.args, "submodule--helper", "status",
+			     "--recursive", NULL);
 
 		if (flags & OPT_CACHED)
-			argv_array_push(&cpr.args, "--cached");
+			strvec_push(&cpr.args, "--cached");
 
 		if (flags & OPT_QUIET)
-			argv_array_push(&cpr.args, "--quiet");
+			strvec_push(&cpr.args, "--quiet");
 
 		if (run_command(&cpr))
 			die(_("failed to recurse into submodule '%s'"), path);
 	}
 
 cleanup:
-	argv_array_clear(&diff_files_args);
+	strvec_clear(&diff_files_args);
 	free(displaypath);
 }
 
@@ -929,11 +927,437 @@
 	return 0;
 }
 
+struct module_cb {
+	unsigned int mod_src;
+	unsigned int mod_dst;
+	struct object_id oid_src;
+	struct object_id oid_dst;
+	char status;
+	const char *sm_path;
+};
+#define MODULE_CB_INIT { 0, 0, NULL, NULL, '\0', NULL }
+
+struct module_cb_list {
+	struct module_cb **entries;
+	int alloc, nr;
+};
+#define MODULE_CB_LIST_INIT { NULL, 0, 0 }
+
+struct summary_cb {
+	int argc;
+	const char **argv;
+	const char *prefix;
+	unsigned int cached: 1;
+	unsigned int for_status: 1;
+	unsigned int files: 1;
+	int summary_limit;
+};
+#define SUMMARY_CB_INIT { 0, NULL, NULL, 0, 0, 0, 0 }
+
+enum diff_cmd {
+	DIFF_INDEX,
+	DIFF_FILES
+};
+
+static char *verify_submodule_committish(const char *sm_path,
+					 const char *committish)
+{
+	struct child_process cp_rev_parse = CHILD_PROCESS_INIT;
+	struct strbuf result = STRBUF_INIT;
+
+	cp_rev_parse.git_cmd = 1;
+	cp_rev_parse.dir = sm_path;
+	prepare_submodule_repo_env(&cp_rev_parse.env_array);
+	strvec_pushl(&cp_rev_parse.args, "rev-parse", "-q", "--short", NULL);
+	strvec_pushf(&cp_rev_parse.args, "%s^0", committish);
+	strvec_push(&cp_rev_parse.args, "--");
+
+	if (capture_command(&cp_rev_parse, &result, 0))
+		return NULL;
+
+	strbuf_trim_trailing_newline(&result);
+	return strbuf_detach(&result, NULL);
+}
+
+static void print_submodule_summary(struct summary_cb *info, char *errmsg,
+				    int total_commits, const char *displaypath,
+				    const char *src_abbrev, const char *dst_abbrev,
+				    struct module_cb *p)
+{
+	if (p->status == 'T') {
+		if (S_ISGITLINK(p->mod_dst))
+			printf(_("* %s %s(blob)->%s(submodule)"),
+				 displaypath, src_abbrev, dst_abbrev);
+		else
+			printf(_("* %s %s(submodule)->%s(blob)"),
+				 displaypath, src_abbrev, dst_abbrev);
+	} else {
+		printf("* %s %s...%s",
+			displaypath, src_abbrev, dst_abbrev);
+	}
+
+	if (total_commits < 0)
+		printf(":\n");
+	else
+		printf(" (%d):\n", total_commits);
+
+	if (errmsg) {
+		printf(_("%s"), errmsg);
+	} else if (total_commits > 0) {
+		struct child_process cp_log = CHILD_PROCESS_INIT;
+
+		cp_log.git_cmd = 1;
+		cp_log.dir = p->sm_path;
+		prepare_submodule_repo_env(&cp_log.env_array);
+		strvec_pushl(&cp_log.args, "log", NULL);
+
+		if (S_ISGITLINK(p->mod_src) && S_ISGITLINK(p->mod_dst)) {
+			if (info->summary_limit > 0)
+				strvec_pushf(&cp_log.args, "-%d",
+					     info->summary_limit);
+
+			strvec_pushl(&cp_log.args, "--pretty=  %m %s",
+				     "--first-parent", NULL);
+			strvec_pushf(&cp_log.args, "%s...%s",
+				     src_abbrev, dst_abbrev);
+		} else if (S_ISGITLINK(p->mod_dst)) {
+			strvec_pushl(&cp_log.args, "--pretty=  > %s",
+				     "-1", dst_abbrev, NULL);
+		} else {
+			strvec_pushl(&cp_log.args, "--pretty=  < %s",
+				     "-1", src_abbrev, NULL);
+		}
+		run_command(&cp_log);
+	}
+	printf("\n");
+}
+
+static void generate_submodule_summary(struct summary_cb *info,
+				       struct module_cb *p)
+{
+	char *displaypath, *src_abbrev = NULL, *dst_abbrev;
+	int missing_src = 0, missing_dst = 0;
+	char *errmsg = NULL;
+	int total_commits = -1;
+
+	if (!info->cached && oideq(&p->oid_dst, &null_oid)) {
+		if (S_ISGITLINK(p->mod_dst)) {
+			struct ref_store *refs = get_submodule_ref_store(p->sm_path);
+			if (refs)
+				refs_head_ref(refs, handle_submodule_head_ref, &p->oid_dst);
+		} else if (S_ISLNK(p->mod_dst) || S_ISREG(p->mod_dst)) {
+			struct stat st;
+			int fd = open(p->sm_path, O_RDONLY);
+
+			if (fd < 0 || fstat(fd, &st) < 0 ||
+			    index_fd(&the_index, &p->oid_dst, fd, &st, OBJ_BLOB,
+				     p->sm_path, 0))
+				error(_("couldn't hash object from '%s'"), p->sm_path);
+		} else {
+			/* for a submodule removal (mode:0000000), don't warn */
+			if (p->mod_dst)
+				warning(_("unexpected mode %o\n"), p->mod_dst);
+		}
+	}
+
+	if (S_ISGITLINK(p->mod_src)) {
+		if (p->status != 'D')
+			src_abbrev = verify_submodule_committish(p->sm_path,
+								 oid_to_hex(&p->oid_src));
+		if (!src_abbrev) {
+			missing_src = 1;
+			/*
+			 * As `rev-parse` failed, we fallback to getting
+			 * the abbreviated hash using oid_src. We do
+			 * this as we might still need the abbreviated
+			 * hash in cases like a submodule type change, etc.
+			 */
+			src_abbrev = xstrndup(oid_to_hex(&p->oid_src), 7);
+		}
+	} else {
+		/*
+		 * The source does not point to a submodule.
+		 * So, we fallback to getting the abbreviation using
+		 * oid_src as we might still need the abbreviated
+		 * hash in cases like submodule add, etc.
+		 */
+		src_abbrev = xstrndup(oid_to_hex(&p->oid_src), 7);
+	}
+
+	if (S_ISGITLINK(p->mod_dst)) {
+		dst_abbrev = verify_submodule_committish(p->sm_path,
+							 oid_to_hex(&p->oid_dst));
+		if (!dst_abbrev) {
+			missing_dst = 1;
+			/*
+			 * As `rev-parse` failed, we fallback to getting
+			 * the abbreviated hash using oid_dst. We do
+			 * this as we might still need the abbreviated
+			 * hash in cases like a submodule type change, etc.
+			 */
+			dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
+		}
+	} else {
+		/*
+		 * The destination does not point to a submodule.
+		 * So, we fallback to getting the abbreviation using
+		 * oid_dst as we might still need the abbreviated
+		 * hash in cases like a submodule removal, etc.
+		 */
+		dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
+	}
+
+	displaypath = get_submodule_displaypath(p->sm_path, info->prefix);
+
+	if (!missing_src && !missing_dst) {
+		struct child_process cp_rev_list = CHILD_PROCESS_INIT;
+		struct strbuf sb_rev_list = STRBUF_INIT;
+
+		strvec_pushl(&cp_rev_list.args, "rev-list",
+			     "--first-parent", "--count", NULL);
+		if (S_ISGITLINK(p->mod_src) && S_ISGITLINK(p->mod_dst))
+			strvec_pushf(&cp_rev_list.args, "%s...%s",
+				     src_abbrev, dst_abbrev);
+		else
+			strvec_push(&cp_rev_list.args, S_ISGITLINK(p->mod_src) ?
+				    src_abbrev : dst_abbrev);
+		strvec_push(&cp_rev_list.args, "--");
+
+		cp_rev_list.git_cmd = 1;
+		cp_rev_list.dir = p->sm_path;
+		prepare_submodule_repo_env(&cp_rev_list.env_array);
+
+		if (!capture_command(&cp_rev_list, &sb_rev_list, 0))
+			total_commits = atoi(sb_rev_list.buf);
+
+		strbuf_release(&sb_rev_list);
+	} else {
+		/*
+		 * Don't give error msg for modification whose dst is not
+		 * submodule, i.e., deleted or changed to blob
+		 */
+		if (S_ISGITLINK(p->mod_dst)) {
+			struct strbuf errmsg_str = STRBUF_INIT;
+			if (missing_src && missing_dst) {
+				strbuf_addf(&errmsg_str, "  Warn: %s doesn't contain commits %s and %s\n",
+					    displaypath, oid_to_hex(&p->oid_src),
+					    oid_to_hex(&p->oid_dst));
+			} else {
+				strbuf_addf(&errmsg_str, "  Warn: %s doesn't contain commit %s\n",
+					    displaypath, missing_src ?
+					    oid_to_hex(&p->oid_src) :
+					    oid_to_hex(&p->oid_dst));
+			}
+			errmsg = strbuf_detach(&errmsg_str, NULL);
+		}
+	}
+
+	print_submodule_summary(info, errmsg, total_commits,
+				displaypath, src_abbrev,
+				dst_abbrev, p);
+
+	free(displaypath);
+	free(src_abbrev);
+	free(dst_abbrev);
+}
+
+static void prepare_submodule_summary(struct summary_cb *info,
+				      struct module_cb_list *list)
+{
+	int i;
+	for (i = 0; i < list->nr; i++) {
+		const struct submodule *sub;
+		struct module_cb *p = list->entries[i];
+		struct strbuf sm_gitdir = STRBUF_INIT;
+
+		if (p->status == 'D' || p->status == 'T') {
+			generate_submodule_summary(info, p);
+			continue;
+		}
+
+		if (info->for_status && p->status != 'A' &&
+		    (sub = submodule_from_path(the_repository,
+					       &null_oid, p->sm_path))) {
+			char *config_key = NULL;
+			const char *value;
+			int ignore_all = 0;
+
+			config_key = xstrfmt("submodule.%s.ignore",
+					     sub->name);
+			if (!git_config_get_string_tmp(config_key, &value))
+				ignore_all = !strcmp(value, "all");
+			else if (sub->ignore)
+				ignore_all = !strcmp(sub->ignore, "all");
+
+			free(config_key);
+			if (ignore_all)
+				continue;
+		}
+
+		/* Also show added or modified modules which are checked out */
+		strbuf_addstr(&sm_gitdir, p->sm_path);
+		if (is_nonbare_repository_dir(&sm_gitdir))
+			generate_submodule_summary(info, p);
+		strbuf_release(&sm_gitdir);
+	}
+}
+
+static void submodule_summary_callback(struct diff_queue_struct *q,
+				       struct diff_options *options,
+				       void *data)
+{
+	int i;
+	struct module_cb_list *list = data;
+	for (i = 0; i < q->nr; i++) {
+		struct diff_filepair *p = q->queue[i];
+		struct module_cb *temp;
+
+		if (!S_ISGITLINK(p->one->mode) && !S_ISGITLINK(p->two->mode))
+			continue;
+		temp = (struct module_cb*)malloc(sizeof(struct module_cb));
+		temp->mod_src = p->one->mode;
+		temp->mod_dst = p->two->mode;
+		temp->oid_src = p->one->oid;
+		temp->oid_dst = p->two->oid;
+		temp->status = p->status;
+		temp->sm_path = xstrdup(p->one->path);
+
+		ALLOC_GROW(list->entries, list->nr + 1, list->alloc);
+		list->entries[list->nr++] = temp;
+	}
+}
+
+static const char *get_diff_cmd(enum diff_cmd diff_cmd)
+{
+	switch (diff_cmd) {
+	case DIFF_INDEX: return "diff-index";
+	case DIFF_FILES: return "diff-files";
+	default: BUG("bad diff_cmd value %d", diff_cmd);
+	}
+}
+
+static int compute_summary_module_list(struct object_id *head_oid,
+				       struct summary_cb *info,
+				       enum diff_cmd diff_cmd)
+{
+	struct strvec diff_args = STRVEC_INIT;
+	struct rev_info rev;
+	struct module_cb_list list = MODULE_CB_LIST_INIT;
+
+	strvec_push(&diff_args, get_diff_cmd(diff_cmd));
+	if (info->cached)
+		strvec_push(&diff_args, "--cached");
+	strvec_pushl(&diff_args, "--ignore-submodules=dirty", "--raw", NULL);
+	if (head_oid)
+		strvec_push(&diff_args, oid_to_hex(head_oid));
+	strvec_push(&diff_args, "--");
+	if (info->argc)
+		strvec_pushv(&diff_args, info->argv);
+
+	git_config(git_diff_basic_config, NULL);
+	init_revisions(&rev, info->prefix);
+	rev.abbrev = 0;
+	precompose_argv(diff_args.nr, diff_args.v);
+	setup_revisions(diff_args.nr, diff_args.v, &rev, NULL);
+	rev.diffopt.output_format = DIFF_FORMAT_NO_OUTPUT | DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = submodule_summary_callback;
+	rev.diffopt.format_callback_data = &list;
+
+	if (!info->cached) {
+		if (diff_cmd == DIFF_INDEX)
+			setup_work_tree();
+		if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
+			perror("read_cache_preload");
+			return -1;
+		}
+	} else if (read_cache() < 0) {
+		perror("read_cache");
+		return -1;
+	}
+
+	if (diff_cmd == DIFF_INDEX)
+		run_diff_index(&rev, info->cached);
+	else
+		run_diff_files(&rev, 0);
+	prepare_submodule_summary(info, &list);
+	strvec_clear(&diff_args);
+	return 0;
+}
+
+static int module_summary(int argc, const char **argv, const char *prefix)
+{
+	struct summary_cb info = SUMMARY_CB_INIT;
+	int cached = 0;
+	int for_status = 0;
+	int files = 0;
+	int summary_limit = -1;
+	enum diff_cmd diff_cmd = DIFF_INDEX;
+	struct object_id head_oid;
+	int ret;
+
+	struct option module_summary_options[] = {
+		OPT_BOOL(0, "cached", &cached,
+			 N_("use the commit stored in the index instead of the submodule HEAD")),
+		OPT_BOOL(0, "files", &files,
+			 N_("to compare the commit in the index with that in the submodule HEAD")),
+		OPT_BOOL(0, "for-status", &for_status,
+			 N_("skip submodules with 'ignore_config' value set to 'all'")),
+		OPT_INTEGER('n', "summary-limit", &summary_limit,
+			     N_("limit the summary size")),
+		OPT_END()
+	};
+
+	const char *const git_submodule_helper_usage[] = {
+		N_("git submodule--helper summary [<options>] [commit] [--] [<path>]"),
+		NULL
+	};
+
+	argc = parse_options(argc, argv, prefix, module_summary_options,
+			     git_submodule_helper_usage, 0);
+
+	if (!summary_limit)
+		return 0;
+
+	if (!get_oid(argc ? argv[0] : "HEAD", &head_oid)) {
+		if (argc) {
+			argv++;
+			argc--;
+		}
+	} else if (!argc || !strcmp(argv[0], "HEAD")) {
+		/* before the first commit: compare with an empty tree */
+		oidcpy(&head_oid, the_hash_algo->empty_tree);
+		if (argc) {
+			argv++;
+			argc--;
+		}
+	} else {
+		if (get_oid("HEAD", &head_oid))
+			die(_("could not fetch a revision for HEAD"));
+	}
+
+	if (files) {
+		if (cached)
+			die(_("--cached and --files are mutually exclusive"));
+		diff_cmd = DIFF_FILES;
+	}
+
+	info.argc = argc;
+	info.argv = argv;
+	info.prefix = prefix;
+	info.cached = !!cached;
+	info.files = !!files;
+	info.for_status = !!for_status;
+	info.summary_limit = summary_limit;
+
+	ret = compute_summary_module_list((diff_cmd == DIFF_INDEX) ? &head_oid : NULL,
+					  &info, diff_cmd);
+	return ret;
+}
+
 struct sync_cb {
 	const char *prefix;
 	unsigned int flags;
 };
-
 #define SYNC_CB_INIT { NULL, 0 }
 
 static void sync_submodule(const char *path, const char *prefix,
@@ -995,8 +1419,8 @@
 	prepare_submodule_repo_env(&cp.env_array);
 	cp.git_cmd = 1;
 	cp.dir = path;
-	argv_array_pushl(&cp.args, "submodule--helper",
-			 "print-default-remote", NULL);
+	strvec_pushl(&cp.args, "submodule--helper",
+		     "print-default-remote", NULL);
 
 	strbuf_reset(&sb);
 	if (capture_command(&cp, &sb, 0))
@@ -1021,13 +1445,13 @@
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env_array);
 
-		argv_array_push(&cpr.args, "--super-prefix");
-		argv_array_pushf(&cpr.args, "%s/", displaypath);
-		argv_array_pushl(&cpr.args, "submodule--helper", "sync",
-				 "--recursive", NULL);
+		strvec_push(&cpr.args, "--super-prefix");
+		strvec_pushf(&cpr.args, "%s/", displaypath);
+		strvec_pushl(&cpr.args, "submodule--helper", "sync",
+			     "--recursive", NULL);
 
 		if (flags & OPT_QUIET)
-			argv_array_push(&cpr.args, "--quiet");
+			strvec_push(&cpr.args, "--quiet");
 
 		if (run_command(&cpr))
 			die(_("failed to recurse into submodule '%s'"),
@@ -1127,8 +1551,8 @@
 		if (!(flags & OPT_FORCE)) {
 			struct child_process cp_rm = CHILD_PROCESS_INIT;
 			cp_rm.git_cmd = 1;
-			argv_array_pushl(&cp_rm.args, "rm", "-qn",
-					 path, NULL);
+			strvec_pushl(&cp_rm.args, "rm", "-qn",
+				     path, NULL);
 
 			if (run_command(&cp_rm))
 				die(_("Submodule work tree '%s' contains local "
@@ -1156,8 +1580,8 @@
 		      displaypath);
 
 	cp_config.git_cmd = 1;
-	argv_array_pushl(&cp_config.args, "config", "--get-regexp", NULL);
-	argv_array_pushf(&cp_config.args, "submodule.%s\\.", sub->name);
+	strvec_pushl(&cp_config.args, "config", "--get-regexp", NULL);
+	strvec_pushf(&cp_config.args, "submodule.%s\\.", sub->name);
 
 	/* remove the .git/config entries (unless the user already did it) */
 	if (!capture_command(&cp_config, &sb_config, 0) && sb_config.len) {
@@ -1239,32 +1663,32 @@
 {
 	struct child_process cp = CHILD_PROCESS_INIT;
 
-	argv_array_push(&cp.args, "clone");
-	argv_array_push(&cp.args, "--no-checkout");
+	strvec_push(&cp.args, "clone");
+	strvec_push(&cp.args, "--no-checkout");
 	if (quiet)
-		argv_array_push(&cp.args, "--quiet");
+		strvec_push(&cp.args, "--quiet");
 	if (progress)
-		argv_array_push(&cp.args, "--progress");
+		strvec_push(&cp.args, "--progress");
 	if (depth && *depth)
-		argv_array_pushl(&cp.args, "--depth", depth, NULL);
+		strvec_pushl(&cp.args, "--depth", depth, NULL);
 	if (reference->nr) {
 		struct string_list_item *item;
 		for_each_string_list_item(item, reference)
-			argv_array_pushl(&cp.args, "--reference",
-					 item->string, NULL);
+			strvec_pushl(&cp.args, "--reference",
+				     item->string, NULL);
 	}
 	if (dissociate)
-		argv_array_push(&cp.args, "--dissociate");
+		strvec_push(&cp.args, "--dissociate");
 	if (gitdir && *gitdir)
-		argv_array_pushl(&cp.args, "--separate-git-dir", gitdir, NULL);
+		strvec_pushl(&cp.args, "--separate-git-dir", gitdir, NULL);
 	if (single_branch >= 0)
-		argv_array_push(&cp.args, single_branch ?
+		strvec_push(&cp.args, single_branch ?
 					  "--single-branch" :
 					  "--no-single-branch");
 
-	argv_array_push(&cp.args, "--");
-	argv_array_push(&cp.args, url);
-	argv_array_push(&cp.args, path);
+	strvec_push(&cp.args, "--");
+	strvec_push(&cp.args, url);
+	strvec_push(&cp.args, path);
 
 	cp.git_cmd = 1;
 	prepare_submodule_repo_env(&cp.env_array);
@@ -1511,7 +1935,7 @@
 		if (parse_submodule_update_strategy(update, out) < 0)
 			die(_("Invalid update mode '%s' for submodule path '%s'"),
 				update, path);
-	} else if (!repo_config_get_string_const(r, key, &val)) {
+	} else if (!repo_config_get_string_tmp(r, key, &val)) {
 		if (parse_submodule_update_strategy(val, out) < 0)
 			die(_("Invalid update mode '%s' configured for submodule path '%s'"),
 				val, path);
@@ -1667,7 +2091,7 @@
 	}
 
 	key = xstrfmt("submodule.%s.update", sub->name);
-	if (!repo_config_get_string_const(the_repository, key, &update_string)) {
+	if (!repo_config_get_string_tmp(the_repository, key, &update_string)) {
 		update_type = parse_submodule_update_type(update_string);
 	} else {
 		update_type = sub->update_strategy.type;
@@ -1690,7 +2114,7 @@
 
 	strbuf_reset(&sb);
 	strbuf_addf(&sb, "submodule.%s.url", sub->name);
-	if (repo_config_get_string_const(the_repository, sb.buf, &url)) {
+	if (repo_config_get_string_tmp(the_repository, sb.buf, &url)) {
 		if (starts_with_dot_slash(sub->url) ||
 		    starts_with_dot_dot_slash(sub->url)) {
 			url = compute_submodule_clone_url(sub->url);
@@ -1717,38 +2141,38 @@
 	child->no_stdin = 1;
 	child->stdout_to_stderr = 1;
 	child->err = -1;
-	argv_array_push(&child->args, "submodule--helper");
-	argv_array_push(&child->args, "clone");
+	strvec_push(&child->args, "submodule--helper");
+	strvec_push(&child->args, "clone");
 	if (suc->progress)
-		argv_array_push(&child->args, "--progress");
+		strvec_push(&child->args, "--progress");
 	if (suc->quiet)
-		argv_array_push(&child->args, "--quiet");
+		strvec_push(&child->args, "--quiet");
 	if (suc->prefix)
-		argv_array_pushl(&child->args, "--prefix", suc->prefix, NULL);
+		strvec_pushl(&child->args, "--prefix", suc->prefix, NULL);
 	if (suc->recommend_shallow && sub->recommend_shallow == 1)
-		argv_array_push(&child->args, "--depth=1");
+		strvec_push(&child->args, "--depth=1");
 	if (suc->require_init)
-		argv_array_push(&child->args, "--require-init");
-	argv_array_pushl(&child->args, "--path", sub->path, NULL);
-	argv_array_pushl(&child->args, "--name", sub->name, NULL);
-	argv_array_pushl(&child->args, "--url", url, NULL);
+		strvec_push(&child->args, "--require-init");
+	strvec_pushl(&child->args, "--path", sub->path, NULL);
+	strvec_pushl(&child->args, "--name", sub->name, NULL);
+	strvec_pushl(&child->args, "--url", url, NULL);
 	if (suc->references.nr) {
 		struct string_list_item *item;
 		for_each_string_list_item(item, &suc->references)
-			argv_array_pushl(&child->args, "--reference", item->string, NULL);
+			strvec_pushl(&child->args, "--reference", item->string, NULL);
 	}
 	if (suc->dissociate)
-		argv_array_push(&child->args, "--dissociate");
+		strvec_push(&child->args, "--dissociate");
 	if (suc->depth)
-		argv_array_push(&child->args, suc->depth);
+		strvec_push(&child->args, suc->depth);
 	if (suc->single_branch >= 0)
-		argv_array_push(&child->args, suc->single_branch ?
+		strvec_push(&child->args, suc->single_branch ?
 					      "--single-branch" :
 					      "--no-single-branch");
 
 cleanup:
-	strbuf_reset(&displaypath_sb);
-	strbuf_reset(&sb);
+	strbuf_release(&displaypath_sb);
+	strbuf_release(&sb);
 	if (need_free_url)
 		free((void*)url);
 
@@ -1976,7 +2400,7 @@
 		return NULL;
 
 	key = xstrfmt("submodule.%s.branch", sub->name);
-	if (repo_config_get_string_const(the_repository, key, &branch))
+	if (repo_config_get_string_tmp(the_repository, key, &branch))
 		branch = sub->branch;
 	free(key);
 
@@ -2101,7 +2525,7 @@
 {
 	const struct submodule *sub;
 	const char *path;
-	char *cw;
+	const char *cw;
 	struct repository subrepo;
 
 	if (argc != 2)
@@ -2116,7 +2540,7 @@
 	if (repo_submodule_init(&subrepo, the_repository, sub))
 		die(_("could not get a repository handle for submodule '%s'"), path);
 
-	if (!repo_config_get_string(&subrepo, "core.worktree", &cw)) {
+	if (!repo_config_get_string_tmp(&subrepo, "core.worktree", &cw)) {
 		char *cfg_file, *abs_path;
 		const char *rel_path;
 		struct strbuf sb = STRBUF_INIT;
@@ -2344,6 +2768,7 @@
 	{"print-default-remote", print_default_remote, 0},
 	{"sync", module_sync, SUPPORT_SUPER_PREFIX},
 	{"deinit", module_deinit, 0},
+	{"summary", module_summary, SUPPORT_SUPER_PREFIX},
 	{"remote-branch", resolve_remote_submodule_branch, 0},
 	{"push-check", push_check, 0},
 	{"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index b74dd9a6..8a2df44 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -4,7 +4,7 @@
 #include "builtin.h"
 #include "parse-options.h"
 #include "quote.h"
-#include "argv-array.h"
+#include "strvec.h"
 
 static const char * const git_update_ref_usage[] = {
 	N_("git update-ref [<options>] -d <refname> [<old-val>]"),
diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
index 0188797..24654b4 100644
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@ -7,7 +7,7 @@
 #include "pkt-line.h"
 #include "sideband.h"
 #include "run-command.h"
-#include "argv-array.h"
+#include "strvec.h"
 
 static const char upload_archive_usage[] =
 	"git upload-archive <repo>";
@@ -19,7 +19,7 @@
 
 int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)
 {
-	struct argv_array sent_argv = ARGV_ARRAY_INIT;
+	struct strvec sent_argv = STRVEC_INIT;
 	const char *arg_cmd = "argument ";
 
 	if (argc != 2 || !strcmp(argv[1], "-h"))
@@ -31,21 +31,21 @@
 	init_archivers();
 
 	/* put received options in sent_argv[] */
-	argv_array_push(&sent_argv, "git-upload-archive");
+	strvec_push(&sent_argv, "git-upload-archive");
 	for (;;) {
 		char *buf = packet_read_line(0, NULL);
 		if (!buf)
 			break;	/* got a flush */
-		if (sent_argv.argc > MAX_ARGS)
+		if (sent_argv.nr > MAX_ARGS)
 			die("Too many options (>%d)", MAX_ARGS - 1);
 
 		if (!starts_with(buf, arg_cmd))
 			die("'argument' token or flush expected");
-		argv_array_push(&sent_argv, buf + strlen(arg_cmd));
+		strvec_push(&sent_argv, buf + strlen(arg_cmd));
 	}
 
 	/* parse all options sent by the client */
-	return write_archive(sent_argv.argc, sent_argv.argv, prefix,
+	return write_archive(sent_argv.nr, sent_argv.v, prefix,
 			     the_repository, NULL, 1);
 }
 
diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c
index c2a1a5c..05c5213 100644
--- a/builtin/verify-pack.c
+++ b/builtin/verify-pack.c
@@ -7,21 +7,26 @@
 #define VERIFY_PACK_VERBOSE 01
 #define VERIFY_PACK_STAT_ONLY 02
 
-static int verify_one_pack(const char *path, unsigned int flags)
+static int verify_one_pack(const char *path, unsigned int flags, const char *hash_algo)
 {
 	struct child_process index_pack = CHILD_PROCESS_INIT;
-	const char *argv[] = {"index-pack", NULL, NULL, NULL };
+	struct strvec *argv = &index_pack.args;
 	struct strbuf arg = STRBUF_INIT;
 	int verbose = flags & VERIFY_PACK_VERBOSE;
 	int stat_only = flags & VERIFY_PACK_STAT_ONLY;
 	int err;
 
+	strvec_push(argv, "index-pack");
+
 	if (stat_only)
-		argv[1] = "--verify-stat-only";
+		strvec_push(argv, "--verify-stat-only");
 	else if (verbose)
-		argv[1] = "--verify-stat";
+		strvec_push(argv, "--verify-stat");
 	else
-		argv[1] = "--verify";
+		strvec_push(argv, "--verify");
+
+	if (hash_algo)
+		strvec_pushf(argv, "--object-format=%s", hash_algo);
 
 	/*
 	 * In addition to "foo.pack" we accept "foo.idx" and "foo";
@@ -31,9 +36,8 @@
 	if (strbuf_strip_suffix(&arg, ".idx") ||
 	    !ends_with(arg.buf, ".pack"))
 		strbuf_addstr(&arg, ".pack");
-	argv[2] = arg.buf;
+	strvec_push(argv, arg.buf);
 
-	index_pack.argv = argv;
 	index_pack.git_cmd = 1;
 
 	err = run_command(&index_pack);
@@ -60,12 +64,15 @@
 {
 	int err = 0;
 	unsigned int flags = 0;
+	const char *object_format = NULL;
 	int i;
 	const struct option verify_pack_options[] = {
 		OPT_BIT('v', "verbose", &flags, N_("verbose"),
 			VERIFY_PACK_VERBOSE),
 		OPT_BIT('s', "stat-only", &flags, N_("show statistics only"),
 			VERIFY_PACK_STAT_ONLY),
+		OPT_STRING(0, "object-format", &object_format, N_("hash"),
+			   N_("specify the hash algorithm to use")),
 		OPT_END()
 	};
 
@@ -75,7 +82,7 @@
 	if (argc < 1)
 		usage_with_options(verify_pack_usage, verify_pack_options);
 	for (i = 0; i < argc; i++) {
-		if (verify_one_pack(argv[i], flags))
+		if (verify_one_pack(argv[i], flags, object_format))
 			err = 1;
 	}
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index f0cbdef..bb70fde 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -4,7 +4,7 @@
 #include "builtin.h"
 #include "dir.h"
 #include "parse-options.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "branch.h"
 #include "refs.h"
 #include "run-command.h"
@@ -316,7 +316,7 @@
 	struct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT;
 	const char *name;
 	struct child_process cp = CHILD_PROCESS_INIT;
-	struct argv_array child_env = ARGV_ARRAY_INIT;
+	struct strvec child_env = STRVEC_INIT;
 	unsigned int counter = 0;
 	int len, ret;
 	struct strbuf symref = STRBUF_INIT;
@@ -408,32 +408,32 @@
 	strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
 	write_file(sb.buf, "../..");
 
-	argv_array_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
-	argv_array_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
+	strvec_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
+	strvec_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
 	cp.git_cmd = 1;
 
 	if (!is_branch)
-		argv_array_pushl(&cp.args, "update-ref", "HEAD",
-				 oid_to_hex(&commit->object.oid), NULL);
+		strvec_pushl(&cp.args, "update-ref", "HEAD",
+			     oid_to_hex(&commit->object.oid), NULL);
 	else {
-		argv_array_pushl(&cp.args, "symbolic-ref", "HEAD",
-				 symref.buf, NULL);
+		strvec_pushl(&cp.args, "symbolic-ref", "HEAD",
+			     symref.buf, NULL);
 		if (opts->quiet)
-			argv_array_push(&cp.args, "--quiet");
+			strvec_push(&cp.args, "--quiet");
 	}
 
-	cp.env = child_env.argv;
+	cp.env = child_env.v;
 	ret = run_command(&cp);
 	if (ret)
 		goto done;
 
 	if (opts->checkout) {
 		cp.argv = NULL;
-		argv_array_clear(&cp.args);
-		argv_array_pushl(&cp.args, "reset", "--hard", "--no-recurse-submodules", NULL);
+		strvec_clear(&cp.args);
+		strvec_pushl(&cp.args, "reset", "--hard", "--no-recurse-submodules", NULL);
 		if (opts->quiet)
-			argv_array_push(&cp.args, "--quiet");
-		cp.env = child_env.argv;
+			strvec_push(&cp.args, "--quiet");
+		cp.env = child_env.v;
 		ret = run_command(&cp);
 		if (ret)
 			goto done;
@@ -465,15 +465,15 @@
 			cp.env = env;
 			cp.argv = NULL;
 			cp.trace2_hook_name = "post-checkout";
-			argv_array_pushl(&cp.args, absolute_path(hook),
-					 oid_to_hex(&null_oid),
-					 oid_to_hex(&commit->object.oid),
-					 "1", NULL);
+			strvec_pushl(&cp.args, absolute_path(hook),
+				     oid_to_hex(&null_oid),
+				     oid_to_hex(&commit->object.oid),
+				     "1", NULL);
 			ret = run_command(&cp);
 		}
 	}
 
-	argv_array_clear(&child_env);
+	strvec_clear(&child_env);
 	strbuf_release(&sb);
 	strbuf_release(&symref);
 	strbuf_release(&sb_repo);
@@ -619,15 +619,15 @@
 	if (new_branch) {
 		struct child_process cp = CHILD_PROCESS_INIT;
 		cp.git_cmd = 1;
-		argv_array_push(&cp.args, "branch");
+		strvec_push(&cp.args, "branch");
 		if (new_branch_force)
-			argv_array_push(&cp.args, "--force");
+			strvec_push(&cp.args, "--force");
 		if (opts.quiet)
-			argv_array_push(&cp.args, "--quiet");
-		argv_array_push(&cp.args, new_branch);
-		argv_array_push(&cp.args, branch);
+			strvec_push(&cp.args, "--quiet");
+		strvec_push(&cp.args, new_branch);
+		strvec_push(&cp.args, branch);
 		if (opt_track)
-			argv_array_push(&cp.args, opt_track);
+			strvec_push(&cp.args, opt_track);
 		if (run_command(&cp))
 			return -1;
 		branch = new_branch;
@@ -924,7 +924,6 @@
 static void check_clean_worktree(struct worktree *wt,
 				 const char *original_path)
 {
-	struct argv_array child_env = ARGV_ARRAY_INIT;
 	struct child_process cp;
 	char buf[1];
 	int ret;
@@ -935,15 +934,14 @@
 	 */
 	validate_no_submodules(wt);
 
-	argv_array_pushf(&child_env, "%s=%s/.git",
-			 GIT_DIR_ENVIRONMENT, wt->path);
-	argv_array_pushf(&child_env, "%s=%s",
-			 GIT_WORK_TREE_ENVIRONMENT, wt->path);
-	memset(&cp, 0, sizeof(cp));
-	argv_array_pushl(&cp.args, "status",
-			 "--porcelain", "--ignore-submodules=none",
-			 NULL);
-	cp.env = child_env.argv;
+	child_process_init(&cp);
+	strvec_pushf(&cp.env_array, "%s=%s/.git",
+		     GIT_DIR_ENVIRONMENT, wt->path);
+	strvec_pushf(&cp.env_array, "%s=%s",
+		     GIT_WORK_TREE_ENVIRONMENT, wt->path);
+	strvec_pushl(&cp.args, "status",
+		     "--porcelain", "--ignore-submodules=none",
+		     NULL);
 	cp.git_cmd = 1;
 	cp.dir = wt->path;
 	cp.out = -1;
@@ -1030,6 +1028,34 @@
 	return ret;
 }
 
+static void report_repair(int iserr, const char *path, const char *msg, void *cb_data)
+{
+	if (!iserr) {
+		printf_ln(_("repair: %s: %s"), msg, path);
+	} else {
+		int *exit_status = (int *)cb_data;
+		fprintf_ln(stderr, _("error: %s: %s"), msg, path);
+		*exit_status = 1;
+	}
+}
+
+static int repair(int ac, const char **av, const char *prefix)
+{
+	const char **p;
+	const char *self[] = { ".", NULL };
+	struct option options[] = {
+		OPT_END()
+	};
+	int rc = 0;
+
+	ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+	repair_worktrees(report_repair, &rc);
+	p = ac > 0 ? av : self;
+	for (; *p; p++)
+		repair_worktree_at_path(*p, report_repair, &rc);
+	return rc;
+}
+
 int cmd_worktree(int ac, const char **av, const char *prefix)
 {
 	struct option options[] = {
@@ -1056,5 +1082,7 @@
 		return move_worktree(ac - 1, av + 1, prefix);
 	if (!strcmp(av[1], "remove"))
 		return remove_worktree(ac - 1, av + 1, prefix);
+	if (!strcmp(av[1], "repair"))
+		return repair(ac - 1, av + 1, prefix);
 	usage_with_options(worktree_usage, options);
 }
diff --git a/bundle.c b/bundle.c
index b5f60fa..cb0e593 100644
--- a/bundle.c
+++ b/bundle.c
@@ -10,9 +10,18 @@
 #include "list-objects.h"
 #include "run-command.h"
 #include "refs.h"
-#include "argv-array.h"
+#include "strvec.h"
 
-static const char bundle_signature[] = "# v2 git bundle\n";
+
+static const char v2_bundle_signature[] = "# v2 git bundle\n";
+static const char v3_bundle_signature[] = "# v3 git bundle\n";
+static struct {
+	int version;
+	const char *signature;
+} bundle_sigs[] = {
+	{ 2, v2_bundle_signature },
+	{ 3, v3_bundle_signature },
+};
 
 static void add_to_ref_list(const struct object_id *oid, const char *name,
 		struct ref_list *list)
@@ -23,15 +32,30 @@
 	list->nr++;
 }
 
-static const struct git_hash_algo *detect_hash_algo(struct strbuf *buf)
+static int parse_capability(struct bundle_header *header, const char *capability)
 {
-	size_t len = strcspn(buf->buf, " \n");
-	int algo;
+	const char *arg;
+	if (skip_prefix(capability, "object-format=", &arg)) {
+		int algo = hash_algo_by_name(arg);
+		if (algo == GIT_HASH_UNKNOWN)
+			return error(_("unrecognized bundle hash algorithm: %s"), arg);
+		header->hash_algo = &hash_algos[algo];
+		return 0;
+	}
+	return error(_("unknown capability '%s'"), capability);
+}
 
-	algo = hash_algo_by_length(len / 2);
-	if (algo == GIT_HASH_UNKNOWN)
-		return NULL;
-	return &hash_algos[algo];
+static int parse_bundle_signature(struct bundle_header *header, const char *line)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(bundle_sigs); i++) {
+		if (!strcmp(line, bundle_sigs[i].signature)) {
+			header->version = bundle_sigs[i].version;
+			return 0;
+		}
+	}
+	return -1;
 }
 
 static int parse_bundle_header(int fd, struct bundle_header *header,
@@ -42,14 +66,16 @@
 
 	/* The bundle header begins with the signature */
 	if (strbuf_getwholeline_fd(&buf, fd, '\n') ||
-	    strcmp(buf.buf, bundle_signature)) {
+	    parse_bundle_signature(header, buf.buf)) {
 		if (report_path)
-			error(_("'%s' does not look like a v2 bundle file"),
+			error(_("'%s' does not look like a v2 or v3 bundle file"),
 			      report_path);
 		status = -1;
 		goto abort;
 	}
 
+	header->hash_algo = the_hash_algo;
+
 	/* The bundle header ends with an empty line */
 	while (!strbuf_getwholeline_fd(&buf, fd, '\n') &&
 	       buf.len && buf.buf[0] != '\n') {
@@ -57,19 +83,19 @@
 		int is_prereq = 0;
 		const char *p;
 
-		if (*buf.buf == '-') {
-			is_prereq = 1;
-			strbuf_remove(&buf, 0, 1);
-		}
 		strbuf_rtrim(&buf);
 
-		if (!header->hash_algo) {
-			header->hash_algo = detect_hash_algo(&buf);
-			if (!header->hash_algo) {
-				error(_("unknown hash algorithm length"));
+		if (header->version == 3 && *buf.buf == '@') {
+			if (parse_capability(header, buf.buf + 1)) {
 				status = -1;
 				break;
 			}
+			continue;
+		}
+
+		if (*buf.buf == '-') {
+			is_prereq = 1;
+			strbuf_remove(&buf, 0, 1);
 		}
 
 		/*
@@ -269,16 +295,16 @@
 
 
 /* Write the pack data to bundle_fd */
-static int write_pack_data(int bundle_fd, struct rev_info *revs, struct argv_array *pack_options)
+static int write_pack_data(int bundle_fd, struct rev_info *revs, struct strvec *pack_options)
 {
 	struct child_process pack_objects = CHILD_PROCESS_INIT;
 	int i;
 
-	argv_array_pushl(&pack_objects.args,
-			 "pack-objects",
-			 "--stdout", "--thin", "--delta-base-offset",
-			 NULL);
-	argv_array_pushv(&pack_objects.args, pack_options->argv);
+	strvec_pushl(&pack_objects.args,
+		     "pack-objects",
+		     "--stdout", "--thin", "--delta-base-offset",
+		     NULL);
+	strvec_pushv(&pack_objects.args, pack_options->v);
 	pack_objects.in = -1;
 	pack_objects.out = bundle_fd;
 	pack_objects.git_cmd = 1;
@@ -321,11 +347,11 @@
 	FILE *rls_fout;
 	int i;
 
-	argv_array_pushl(&rls.args,
-			 "rev-list", "--boundary", "--pretty=oneline",
-			 NULL);
+	strvec_pushl(&rls.args,
+		     "rev-list", "--boundary", "--pretty=oneline",
+		     NULL);
 	for (i = 1; i < argc; i++)
-		argv_array_push(&rls.args, argv[i]);
+		strvec_push(&rls.args, argv[i]);
 	rls.out = -1;
 	rls.git_cmd = 1;
 	if (start_command(&rls))
@@ -449,13 +475,14 @@
 }
 
 int create_bundle(struct repository *r, const char *path,
-		  int argc, const char **argv, struct argv_array *pack_options)
+		  int argc, const char **argv, struct strvec *pack_options, int version)
 {
 	struct lock_file lock = LOCK_INIT;
 	int bundle_fd = -1;
 	int bundle_to_stdout;
 	int ref_count = 0;
 	struct rev_info revs;
+	int min_version = the_hash_algo == &hash_algos[GIT_HASH_SHA1] ? 2 : 3;
 
 	bundle_to_stdout = !strcmp(path, "-");
 	if (bundle_to_stdout)
@@ -464,8 +491,22 @@
 		bundle_fd = hold_lock_file_for_update(&lock, path,
 						      LOCK_DIE_ON_ERROR);
 
-	/* write signature */
-	write_or_die(bundle_fd, bundle_signature, strlen(bundle_signature));
+	if (version == -1)
+		version = min_version;
+
+	if (version < 2 || version > 3) {
+		die(_("unsupported bundle version %d"), version);
+	} else if (version < min_version) {
+		die(_("cannot write bundle version %d with algorithm %s"), version, the_hash_algo->name);
+	} else if (version == 2) {
+		write_or_die(bundle_fd, v2_bundle_signature, strlen(v2_bundle_signature));
+	} else {
+		const char *capability = "@object-format=";
+		write_or_die(bundle_fd, v3_bundle_signature, strlen(v3_bundle_signature));
+		write_or_die(bundle_fd, capability, strlen(capability));
+		write_or_die(bundle_fd, the_hash_algo->name, strlen(the_hash_algo->name));
+		write_or_die(bundle_fd, "\n", 1);
+	}
 
 	/* init revs to list objects for pack-objects later */
 	save_commit_buffer = 0;
diff --git a/bundle.h b/bundle.h
index 2dc9442..f9e2d1c 100644
--- a/bundle.h
+++ b/bundle.h
@@ -1,7 +1,7 @@
 #ifndef BUNDLE_H
 #define BUNDLE_H
 
-#include "argv-array.h"
+#include "strvec.h"
 #include "cache.h"
 
 struct ref_list {
@@ -13,6 +13,7 @@
 };
 
 struct bundle_header {
+	unsigned version;
 	struct ref_list prerequisites;
 	struct ref_list references;
 	const struct git_hash_algo *hash_algo;
@@ -21,7 +22,8 @@
 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, struct argv_array *pack_options);
+		  int argc, const char **argv, struct strvec *pack_options,
+		  int version);
 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 f0090a0..cee8aa5 100644
--- a/cache.h
+++ b/cache.h
@@ -921,8 +921,8 @@
 extern int prefer_symlink_refs;
 extern int warn_ambiguous_refs;
 extern int warn_on_object_refname_ambiguity;
-extern const char *apply_default_whitespace;
-extern const char *apply_default_ignorewhitespace;
+extern char *apply_default_whitespace;
+extern char *apply_default_ignorewhitespace;
 extern const char *git_attributes_file;
 extern const char *git_hooks_path;
 extern int zlib_compression_level;
@@ -1044,6 +1044,7 @@
 	int hash_algo;
 	char *work_tree;
 	struct string_list unknown_extensions;
+	struct string_list v1_only_extensions;
 };
 
 /*
@@ -1057,6 +1058,7 @@
 	.is_bare = -1, \
 	.hash_algo = GIT_HASH_SHA1, \
 	.unknown_extensions = STRING_LIST_INIT_DUP, \
+	.v1_only_extensions = STRING_LIST_INIT_DUP, \
 }
 
 /*
diff --git a/checkout.c b/checkout.c
index c72e9f9..6586e30 100644
--- a/checkout.c
+++ b/checkout.c
@@ -47,7 +47,7 @@
 {
 	struct tracking_name_data cb_data = TRACKING_NAME_DATA_INIT;
 	const char *default_remote = NULL;
-	if (!git_config_get_string_const("checkout.defaultremote", &default_remote))
+	if (!git_config_get_string_tmp("checkout.defaultremote", &default_remote))
 		cb_data.default_remote = default_remote;
 	cb_data.src_ref = xstrfmt("refs/heads/%s", name);
 	cb_data.dst_oid = oid;
@@ -55,7 +55,6 @@
 	if (dwim_remotes_matched)
 		*dwim_remotes_matched = cb_data.num_matches;
 	free(cb_data.src_ref);
-	free((char *)default_remote);
 	if (cb_data.num_matches == 1) {
 		free(cb_data.default_dst_ref);
 		free(cb_data.default_dst_oid);
diff --git a/ci/lib.sh b/ci/lib.sh
index ff24c54..3eefec5 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -184,9 +184,9 @@
 	if [ "$jobname" = linux-gcc ]
 	then
 		export CC=gcc-8
-		MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python3)"
+		MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/python3"
 	else
-		MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python2)"
+		MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/python2"
 	fi
 
 	export GIT_TEST_HTTPD=true
diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh
index 17e25aa..6c27b88 100755
--- a/ci/run-build-and-tests.sh
+++ b/ci/run-build-and-tests.sh
@@ -24,6 +24,12 @@
 	export GIT_TEST_ADD_I_USE_BUILTIN=1
 	make test
 	;;
+linux-clang)
+	export GIT_TEST_DEFAULT_HASH=sha1
+	make test
+	export GIT_TEST_DEFAULT_HASH=sha256
+	make test
+	;;
 linux-gcc-4.8)
 	# Don't run the tests; we only care about whether Git can be
 	# built with GCC 4.8, as it errors out on some undesired (C99)
diff --git a/column.c b/column.c
index 4a38eed..1261e18 100644
--- a/column.c
+++ b/column.c
@@ -107,7 +107,7 @@
 		printf("%s%s%s", indent, list->items[i].string, nl);
 }
 
-/* Print a cell to stdout with all necessary leading/traling space */
+/* Print a cell to stdout with all necessary leading/trailing space */
 static int display_cell(struct column_data *data, int initial_width,
 			const char *empty_cell, int x, int y)
 {
@@ -358,7 +358,7 @@
 
 int run_column_filter(int colopts, const struct column_options *opts)
 {
-	struct argv_array *argv;
+	struct strvec *argv;
 
 	if (fd_out != -1)
 		return -1;
@@ -366,14 +366,14 @@
 	child_process_init(&column_process);
 	argv = &column_process.args;
 
-	argv_array_push(argv, "column");
-	argv_array_pushf(argv, "--raw-mode=%d", colopts);
+	strvec_push(argv, "column");
+	strvec_pushf(argv, "--raw-mode=%d", colopts);
 	if (opts && opts->width)
-		argv_array_pushf(argv, "--width=%d", opts->width);
+		strvec_pushf(argv, "--width=%d", opts->width);
 	if (opts && opts->indent)
-		argv_array_pushf(argv, "--indent=%s", opts->indent);
+		strvec_pushf(argv, "--indent=%s", opts->indent);
 	if (opts && opts->padding)
-		argv_array_pushf(argv, "--padding=%d", opts->padding);
+		strvec_pushf(argv, "--padding=%d", opts->padding);
 
 	fflush(stdout);
 	column_process.in = -1;
diff --git a/command-list.txt b/command-list.txt
index 89aa60c..e5901f2 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -195,6 +195,7 @@
 gitattributes                           guide
 gitcli                                  guide
 gitcore-tutorial                        guide
+gitcredentials                          guide
 gitcvs-migration                        guide
 gitdiffcore                             guide
 giteveryday                             guide
@@ -204,6 +205,7 @@
 gitignore                               guide
 gitmodules                              guide
 gitnamespaces                           guide
+gitremote-helpers                       guide
 gitrepository-layout                    guide
 gitrevisions                            guide
 gitsubmodules                           guide
diff --git a/commit-graph.c b/commit-graph.c
index 1af68c2..0ed003e 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1,7 +1,5 @@
-#include "cache.h"
-#include "config.h"
-#include "dir.h"
 #include "git-compat-util.h"
+#include "config.h"
 #include "lockfile.h"
 #include "pack.h"
 #include "packfile.h"
@@ -19,6 +17,8 @@
 #include "bloom.h"
 #include "commit-slab.h"
 #include "shallow.h"
+#include "json-writer.h"
+#include "trace2.h"
 
 void git_test_write_commit_graph_or_die(void)
 {
@@ -179,7 +179,14 @@
 
 static uint8_t oid_version(void)
 {
-	return 1;
+	switch (hash_algo_by_ptr(the_hash_algo)) {
+	case GIT_HASH_SHA1:
+		return 1;
+	case GIT_HASH_SHA256:
+		return 2;
+	default:
+		die(_("invalid hash version"));
+	}
 }
 
 static struct commit_graph *alloc_commit_graph(void)
@@ -285,8 +292,7 @@
 	const unsigned char *data, *chunk_lookup;
 	uint32_t i;
 	struct commit_graph *graph;
-	uint64_t last_chunk_offset;
-	uint32_t last_chunk_id;
+	uint64_t next_chunk_offset;
 	uint32_t graph_signature;
 	unsigned char graph_version, hash_version;
 
@@ -326,24 +332,26 @@
 	graph->data = graph_map;
 	graph->data_len = graph_size;
 
-	last_chunk_id = 0;
-	last_chunk_offset = 8;
+	if (graph_size < GRAPH_HEADER_SIZE +
+			 (graph->num_chunks + 1) * GRAPH_CHUNKLOOKUP_WIDTH +
+			 GRAPH_FANOUT_SIZE + the_hash_algo->rawsz) {
+		error(_("commit-graph file is too small to hold %u chunks"),
+		      graph->num_chunks);
+		free(graph);
+		return NULL;
+	}
+
 	chunk_lookup = data + 8;
+	next_chunk_offset = get_be64(chunk_lookup + 4);
 	for (i = 0; i < graph->num_chunks; i++) {
 		uint32_t chunk_id;
-		uint64_t chunk_offset;
+		uint64_t chunk_offset = next_chunk_offset;
 		int chunk_repeated = 0;
 
-		if (data + graph_size - chunk_lookup <
-		    GRAPH_CHUNKLOOKUP_WIDTH) {
-			error(_("commit-graph chunk lookup table entry missing; file may be incomplete"));
-			goto free_and_return;
-		}
-
 		chunk_id = get_be32(chunk_lookup + 0);
-		chunk_offset = get_be64(chunk_lookup + 4);
 
 		chunk_lookup += GRAPH_CHUNKLOOKUP_WIDTH;
+		next_chunk_offset = get_be64(chunk_lookup + 4);
 
 		if (chunk_offset > graph_size - the_hash_algo->rawsz) {
 			error(_("commit-graph improper chunk offset %08x%08x"), (uint32_t)(chunk_offset >> 32),
@@ -362,8 +370,11 @@
 		case GRAPH_CHUNKID_OIDLOOKUP:
 			if (graph->chunk_oid_lookup)
 				chunk_repeated = 1;
-			else
+			else {
 				graph->chunk_oid_lookup = data + chunk_offset;
+				graph->num_commits = (next_chunk_offset - chunk_offset)
+						     / graph->hash_len;
+			}
 			break;
 
 		case GRAPH_CHUNKID_DATA:
@@ -417,15 +428,6 @@
 			error(_("commit-graph chunk id %08x appears multiple times"), chunk_id);
 			goto free_and_return;
 		}
-
-		if (last_chunk_id == GRAPH_CHUNKID_OIDLOOKUP)
-		{
-			graph->num_commits = (chunk_offset - last_chunk_offset)
-					     / graph->hash_len;
-		}
-
-		last_chunk_id = chunk_id;
-		last_chunk_offset = chunk_offset;
 	}
 
 	if (graph->chunk_bloom_indexes && graph->chunk_bloom_data) {
@@ -624,10 +626,6 @@
 		return !!r->objects->commit_graph;
 	r->objects->commit_graph_attempted = 1;
 
-	if (git_env_bool(GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD, 0))
-		die("dying as requested by the '%s' variable on commit-graph load!",
-		    GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD);
-
 	prepare_repo_settings(r);
 
 	if (!git_env_bool(GIT_TEST_COMMIT_GRAPH, 0) &&
@@ -856,6 +854,14 @@
 
 int parse_commit_in_graph(struct repository *r, struct commit *item)
 {
+	static int checked_env = 0;
+
+	if (!checked_env &&
+	    git_env_bool(GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE, 0))
+		die("dying as requested by the '%s' variable on commit-graph parse!",
+		    GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE);
+	checked_env = 1;
+
 	if (!prepare_commit_graph(r))
 		return 0;
 	return parse_commit_in_graph_one(r, r->objects->commit_graph, item);
@@ -948,10 +954,11 @@
 
 	const struct split_commit_graph_opts *split_opts;
 	size_t total_bloom_filter_data_size;
+	const struct bloom_filter_settings *bloom_settings;
 };
 
-static void write_graph_chunk_fanout(struct hashfile *f,
-				     struct write_commit_graph_context *ctx)
+static int write_graph_chunk_fanout(struct hashfile *f,
+				    struct write_commit_graph_context *ctx)
 {
 	int i, count = 0;
 	struct commit **list = ctx->commits.list;
@@ -972,17 +979,21 @@
 
 		hashwrite_be32(f, count);
 	}
+
+	return 0;
 }
 
-static void write_graph_chunk_oids(struct hashfile *f, int hash_len,
-				   struct write_commit_graph_context *ctx)
+static int write_graph_chunk_oids(struct hashfile *f,
+				  struct write_commit_graph_context *ctx)
 {
 	struct commit **list = ctx->commits.list;
 	int count;
 	for (count = 0; count < ctx->commits.nr; count++, list++) {
 		display_progress(ctx->progress, ++ctx->progress_cnt);
-		hashwrite(f, (*list)->object.oid.hash, (int)hash_len);
+		hashwrite(f, (*list)->object.oid.hash, the_hash_algo->rawsz);
 	}
+
+	return 0;
 }
 
 static const unsigned char *commit_to_sha1(size_t index, void *table)
@@ -991,8 +1002,8 @@
 	return commits[index]->object.oid.hash;
 }
 
-static void write_graph_chunk_data(struct hashfile *f, int hash_len,
-				   struct write_commit_graph_context *ctx)
+static int write_graph_chunk_data(struct hashfile *f,
+				  struct write_commit_graph_context *ctx)
 {
 	struct commit **list = ctx->commits.list;
 	struct commit **last = ctx->commits.list + ctx->commits.nr;
@@ -1009,7 +1020,7 @@
 			die(_("unable to parse commit %s"),
 				oid_to_hex(&(*list)->object.oid));
 		tree = get_commit_tree_oid(*list);
-		hashwrite(f, tree->hash, hash_len);
+		hashwrite(f, tree->hash, the_hash_algo->rawsz);
 
 		parent = (*list)->parents;
 
@@ -1089,10 +1100,12 @@
 
 		list++;
 	}
+
+	return 0;
 }
 
-static void write_graph_chunk_extra_edges(struct hashfile *f,
-					  struct write_commit_graph_context *ctx)
+static int write_graph_chunk_extra_edges(struct hashfile *f,
+					 struct write_commit_graph_context *ctx)
 {
 	struct commit **list = ctx->commits.list;
 	struct commit **last = ctx->commits.list + ctx->commits.nr;
@@ -1141,10 +1154,12 @@
 
 		list++;
 	}
+
+	return 0;
 }
 
-static void write_graph_chunk_bloom_indexes(struct hashfile *f,
-					    struct write_commit_graph_context *ctx)
+static int write_graph_chunk_bloom_indexes(struct hashfile *f,
+					   struct write_commit_graph_context *ctx)
 {
 	struct commit **list = ctx->commits.list;
 	struct commit **last = ctx->commits.list + ctx->commits.nr;
@@ -1152,30 +1167,54 @@
 
 	while (list < last) {
 		struct bloom_filter *filter = get_bloom_filter(ctx->r, *list, 0);
-		cur_pos += filter->len;
+		size_t len = filter ? filter->len : 0;
+		cur_pos += len;
 		display_progress(ctx->progress, ++ctx->progress_cnt);
 		hashwrite_be32(f, cur_pos);
 		list++;
 	}
+
+	return 0;
 }
 
-static void write_graph_chunk_bloom_data(struct hashfile *f,
-					 struct write_commit_graph_context *ctx,
-					 const struct bloom_filter_settings *settings)
+static void trace2_bloom_filter_settings(struct write_commit_graph_context *ctx)
+{
+	struct json_writer jw = JSON_WRITER_INIT;
+
+	jw_object_begin(&jw, 0);
+	jw_object_intmax(&jw, "hash_version", ctx->bloom_settings->hash_version);
+	jw_object_intmax(&jw, "num_hashes", ctx->bloom_settings->num_hashes);
+	jw_object_intmax(&jw, "bits_per_entry", ctx->bloom_settings->bits_per_entry);
+	jw_end(&jw);
+
+	trace2_data_json("bloom", ctx->r, "settings", &jw);
+
+	jw_release(&jw);
+}
+
+static int write_graph_chunk_bloom_data(struct hashfile *f,
+					struct write_commit_graph_context *ctx)
 {
 	struct commit **list = ctx->commits.list;
 	struct commit **last = ctx->commits.list + ctx->commits.nr;
 
-	hashwrite_be32(f, settings->hash_version);
-	hashwrite_be32(f, settings->num_hashes);
-	hashwrite_be32(f, settings->bits_per_entry);
+	trace2_bloom_filter_settings(ctx);
+
+	hashwrite_be32(f, ctx->bloom_settings->hash_version);
+	hashwrite_be32(f, ctx->bloom_settings->num_hashes);
+	hashwrite_be32(f, ctx->bloom_settings->bits_per_entry);
 
 	while (list < last) {
 		struct bloom_filter *filter = get_bloom_filter(ctx->r, *list, 0);
+		size_t len = filter ? filter->len : 0;
+
 		display_progress(ctx->progress, ++ctx->progress_cnt);
-		hashwrite(f, filter->data, filter->len * sizeof(unsigned char));
+		if (len)
+			hashwrite(f, filter->data, len * sizeof(unsigned char));
 		list++;
 	}
+
+	return 0;
 }
 
 static int oid_compare(const void *_a, const void *_b)
@@ -1586,19 +1625,36 @@
 	return 0;
 }
 
+typedef int (*chunk_write_fn)(struct hashfile *f,
+			      struct write_commit_graph_context *ctx);
+
+struct chunk_info {
+	uint32_t id;
+	uint64_t size;
+	chunk_write_fn write_fn;
+};
+
 static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 {
 	uint32_t i;
 	int fd;
 	struct hashfile *f;
 	struct lock_file lk = LOCK_INIT;
-	uint32_t chunk_ids[MAX_NUM_CHUNKS + 1];
-	uint64_t chunk_offsets[MAX_NUM_CHUNKS + 1];
+	struct chunk_info chunks[MAX_NUM_CHUNKS + 1];
 	const unsigned hashsz = the_hash_algo->rawsz;
 	struct strbuf progress_title = STRBUF_INIT;
 	int num_chunks = 3;
+	uint64_t chunk_offset;
 	struct object_id file_hash;
-	const struct bloom_filter_settings bloom_settings = DEFAULT_BLOOM_FILTER_SETTINGS;
+	struct bloom_filter_settings bloom_settings = DEFAULT_BLOOM_FILTER_SETTINGS;
+
+	if (!ctx->bloom_settings) {
+		bloom_settings.bits_per_entry = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_BITS_PER_ENTRY",
+							      bloom_settings.bits_per_entry);
+		bloom_settings.num_hashes = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_NUM_HASHES",
+							  bloom_settings.num_hashes);
+		ctx->bloom_settings = &bloom_settings;
+	}
 
 	if (ctx->split) {
 		struct strbuf tmp_file = STRBUF_INIT;
@@ -1644,51 +1700,41 @@
 		f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
 	}
 
-	chunk_ids[0] = GRAPH_CHUNKID_OIDFANOUT;
-	chunk_ids[1] = GRAPH_CHUNKID_OIDLOOKUP;
-	chunk_ids[2] = GRAPH_CHUNKID_DATA;
+	chunks[0].id = GRAPH_CHUNKID_OIDFANOUT;
+	chunks[0].size = GRAPH_FANOUT_SIZE;
+	chunks[0].write_fn = write_graph_chunk_fanout;
+	chunks[1].id = GRAPH_CHUNKID_OIDLOOKUP;
+	chunks[1].size = hashsz * ctx->commits.nr;
+	chunks[1].write_fn = write_graph_chunk_oids;
+	chunks[2].id = GRAPH_CHUNKID_DATA;
+	chunks[2].size = (hashsz + 16) * ctx->commits.nr;
+	chunks[2].write_fn = write_graph_chunk_data;
 	if (ctx->num_extra_edges) {
-		chunk_ids[num_chunks] = GRAPH_CHUNKID_EXTRAEDGES;
+		chunks[num_chunks].id = GRAPH_CHUNKID_EXTRAEDGES;
+		chunks[num_chunks].size = 4 * ctx->num_extra_edges;
+		chunks[num_chunks].write_fn = write_graph_chunk_extra_edges;
 		num_chunks++;
 	}
 	if (ctx->changed_paths) {
-		chunk_ids[num_chunks] = GRAPH_CHUNKID_BLOOMINDEXES;
+		chunks[num_chunks].id = GRAPH_CHUNKID_BLOOMINDEXES;
+		chunks[num_chunks].size = sizeof(uint32_t) * ctx->commits.nr;
+		chunks[num_chunks].write_fn = write_graph_chunk_bloom_indexes;
 		num_chunks++;
-		chunk_ids[num_chunks] = GRAPH_CHUNKID_BLOOMDATA;
+		chunks[num_chunks].id = GRAPH_CHUNKID_BLOOMDATA;
+		chunks[num_chunks].size = sizeof(uint32_t) * 3
+					  + ctx->total_bloom_filter_data_size;
+		chunks[num_chunks].write_fn = write_graph_chunk_bloom_data;
 		num_chunks++;
 	}
 	if (ctx->num_commit_graphs_after > 1) {
-		chunk_ids[num_chunks] = GRAPH_CHUNKID_BASE;
+		chunks[num_chunks].id = GRAPH_CHUNKID_BASE;
+		chunks[num_chunks].size = hashsz * (ctx->num_commit_graphs_after - 1);
+		chunks[num_chunks].write_fn = write_graph_chunk_base;
 		num_chunks++;
 	}
 
-	chunk_ids[num_chunks] = 0;
-
-	chunk_offsets[0] = 8 + (num_chunks + 1) * GRAPH_CHUNKLOOKUP_WIDTH;
-	chunk_offsets[1] = chunk_offsets[0] + GRAPH_FANOUT_SIZE;
-	chunk_offsets[2] = chunk_offsets[1] + hashsz * ctx->commits.nr;
-	chunk_offsets[3] = chunk_offsets[2] + (hashsz + 16) * ctx->commits.nr;
-
-	num_chunks = 3;
-	if (ctx->num_extra_edges) {
-		chunk_offsets[num_chunks + 1] = chunk_offsets[num_chunks] +
-						4 * ctx->num_extra_edges;
-		num_chunks++;
-	}
-	if (ctx->changed_paths) {
-		chunk_offsets[num_chunks + 1] = chunk_offsets[num_chunks] +
-						sizeof(uint32_t) * ctx->commits.nr;
-		num_chunks++;
-
-		chunk_offsets[num_chunks + 1] = chunk_offsets[num_chunks] +
-						sizeof(uint32_t) * 3 + ctx->total_bloom_filter_data_size;
-		num_chunks++;
-	}
-	if (ctx->num_commit_graphs_after > 1) {
-		chunk_offsets[num_chunks + 1] = chunk_offsets[num_chunks] +
-						hashsz * (ctx->num_commit_graphs_after - 1);
-		num_chunks++;
-	}
+	chunks[num_chunks].id = 0;
+	chunks[num_chunks].size = 0;
 
 	hashwrite_be32(f, GRAPH_SIGNATURE);
 
@@ -1697,13 +1743,16 @@
 	hashwrite_u8(f, num_chunks);
 	hashwrite_u8(f, ctx->num_commit_graphs_after - 1);
 
+	chunk_offset = 8 + (num_chunks + 1) * GRAPH_CHUNKLOOKUP_WIDTH;
 	for (i = 0; i <= num_chunks; i++) {
 		uint32_t chunk_write[3];
 
-		chunk_write[0] = htonl(chunk_ids[i]);
-		chunk_write[1] = htonl(chunk_offsets[i] >> 32);
-		chunk_write[2] = htonl(chunk_offsets[i] & 0xffffffff);
+		chunk_write[0] = htonl(chunks[i].id);
+		chunk_write[1] = htonl(chunk_offset >> 32);
+		chunk_write[2] = htonl(chunk_offset & 0xffffffff);
 		hashwrite(f, chunk_write, 12);
+
+		chunk_offset += chunks[i].size;
 	}
 
 	if (ctx->report_progress) {
@@ -1716,19 +1765,19 @@
 			progress_title.buf,
 			num_chunks * ctx->commits.nr);
 	}
-	write_graph_chunk_fanout(f, ctx);
-	write_graph_chunk_oids(f, hashsz, ctx);
-	write_graph_chunk_data(f, hashsz, ctx);
-	if (ctx->num_extra_edges)
-		write_graph_chunk_extra_edges(f, ctx);
-	if (ctx->changed_paths) {
-		write_graph_chunk_bloom_indexes(f, ctx);
-		write_graph_chunk_bloom_data(f, ctx, &bloom_settings);
+
+	for (i = 0; i < num_chunks; i++) {
+		uint64_t start_offset = f->total + f->offset;
+
+		if (chunks[i].write_fn(f, ctx))
+			return -1;
+
+		if (f->total + f->offset != start_offset + chunks[i].size)
+			BUG("expected to write %"PRId64" bytes to chunk %"PRIx32", but wrote %"PRId64" instead",
+			    chunks[i].size, chunks[i].id,
+			    f->total + f->offset - start_offset);
 	}
-	if (ctx->num_commit_graphs_after > 1 &&
-	    write_graph_chunk_base(f, ctx)) {
-		return -1;
-	}
+
 	stop_progress(&ctx->progress);
 	strbuf_release(&progress_title);
 
@@ -2062,9 +2111,23 @@
 	ctx->report_progress = flags & COMMIT_GRAPH_WRITE_PROGRESS ? 1 : 0;
 	ctx->split = flags & COMMIT_GRAPH_WRITE_SPLIT ? 1 : 0;
 	ctx->split_opts = split_opts;
-	ctx->changed_paths = flags & COMMIT_GRAPH_WRITE_BLOOM_FILTERS ? 1 : 0;
 	ctx->total_bloom_filter_data_size = 0;
 
+	if (flags & COMMIT_GRAPH_WRITE_BLOOM_FILTERS)
+		ctx->changed_paths = 1;
+	if (!(flags & COMMIT_GRAPH_NO_WRITE_BLOOM_FILTERS)) {
+		struct commit_graph *g;
+		prepare_commit_graph_one(ctx->r, ctx->odb);
+
+		g = ctx->r->objects->commit_graph;
+
+		/* We have changed-paths already. Keep them in the next graph */
+		if (g && g->chunk_bloom_data) {
+			ctx->changed_paths = 1;
+			ctx->bloom_settings = g->bloom_filter_settings;
+		}
+	}
+
 	if (ctx->split) {
 		struct commit_graph *g;
 		prepare_commit_graph(ctx->r);
diff --git a/commit-graph.h b/commit-graph.h
index 28f89cd..09a9703 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -2,14 +2,11 @@
 #define COMMIT_GRAPH_H
 
 #include "git-compat-util.h"
-#include "repository.h"
-#include "string-list.h"
-#include "cache.h"
 #include "object-store.h"
 #include "oidset.h"
 
 #define GIT_TEST_COMMIT_GRAPH "GIT_TEST_COMMIT_GRAPH"
-#define GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD "GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD"
+#define GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE "GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE"
 #define GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS "GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS"
 
 /*
@@ -23,6 +20,9 @@
 
 struct commit;
 struct bloom_filter_settings;
+struct repository;
+struct raw_object_store;
+struct string_list;
 
 char *get_commit_graph_filename(struct object_directory *odb);
 int open_commit_graph(const char *graph_file, int *fd, struct stat *st);
@@ -92,6 +92,7 @@
 	COMMIT_GRAPH_WRITE_PROGRESS   = (1 << 1),
 	COMMIT_GRAPH_WRITE_SPLIT      = (1 << 2),
 	COMMIT_GRAPH_WRITE_BLOOM_FILTERS = (1 << 3),
+	COMMIT_GRAPH_NO_WRITE_BLOOM_FILTERS = (1 << 4),
 };
 
 enum commit_graph_split_flags {
diff --git a/commit-slab-decl.h b/commit-slab-decl.h
index bfbed15..98de2c9 100644
--- a/commit-slab-decl.h
+++ b/commit-slab-decl.h
@@ -32,6 +32,7 @@
 void init_ ##slabname## _with_stride(struct slabname *s, unsigned stride); \
 void init_ ##slabname(struct slabname *s);				\
 void clear_ ##slabname(struct slabname *s);				\
+void deep_clear_ ##slabname(struct slabname *s, void (*free_fn)(elemtype *ptr)); \
 elemtype *slabname## _at_peek(struct slabname *s, const struct commit *c, int add_if_missing); \
 elemtype *slabname## _at(struct slabname *s, const struct commit *c);	\
 elemtype *slabname## _peek(struct slabname *s, const struct commit *c)
diff --git a/commit-slab-impl.h b/commit-slab-impl.h
index 5c0eb91..557738d 100644
--- a/commit-slab-impl.h
+++ b/commit-slab-impl.h
@@ -38,6 +38,19 @@
 	FREE_AND_NULL(s->slab);						\
 }									\
 									\
+scope void deep_clear_ ##slabname(struct slabname *s, void (*free_fn)(elemtype *)) \
+{									\
+	unsigned int i;							\
+	for (i = 0; i < s->slab_count; i++) {				\
+		unsigned int j;						\
+		if (!s->slab[i])					\
+			continue;					\
+		for (j = 0; j < s->slab_size; j++)			\
+			free_fn(&s->slab[i][j * s->stride]);		\
+	}								\
+	clear_ ##slabname(s);						\
+}									\
+									\
 scope elemtype *slabname## _at_peek(struct slabname *s,			\
 						  const struct commit *c, \
 						  int add_if_missing)   \
diff --git a/commit-slab.h b/commit-slab.h
index 05b3f28..8e72a30 100644
--- a/commit-slab.h
+++ b/commit-slab.h
@@ -47,6 +47,16 @@
  *
  *   Call this function before the slab falls out of scope to avoid
  *   leaking memory.
+ *
+ * - void deep_clear_indegree(struct indegree *, void (*free_fn)(int*))
+ *
+ *   Empties the slab, similar to clear_indegree(), but in addition it
+ *   calls the given 'free_fn' for each slab entry to release any
+ *   additional memory that might be owned by the entry (but not the
+ *   entry itself!).
+ *   Note that 'free_fn' might be called even for entries for which no
+ *   indegree_at() call has been made; in this case 'free_fn' is invoked
+ *   with a pointer to a zero-initialized location.
  */
 
 #define define_commit_slab(slabname, elemtype) \
diff --git a/commit.c b/commit.c
index 9b5a34c..f53429c 100644
--- a/commit.c
+++ b/commit.c
@@ -1316,8 +1316,8 @@
 	int result;
 
 	append_merge_tag_headers(parents, &tail);
-	result = commit_tree_extended(msg, msg_len, tree, parents, ret,
-				      author, sign_commit, extra);
+	result = commit_tree_extended(msg, msg_len, tree, parents, ret, author,
+				      NULL, sign_commit, extra);
 	free_commit_extra_headers(extra);
 	return result;
 }
@@ -1440,7 +1440,8 @@
 int commit_tree_extended(const char *msg, size_t msg_len,
 			 const struct object_id *tree,
 			 struct commit_list *parents, struct object_id *ret,
-			 const char *author, const char *sign_commit,
+			 const char *author, const char *committer,
+			 const char *sign_commit,
 			 struct commit_extra_header *extra)
 {
 	int result;
@@ -1473,7 +1474,9 @@
 	if (!author)
 		author = git_author_info(IDENT_STRICT);
 	strbuf_addf(&buffer, "author %s\n", author);
-	strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_STRICT));
+	if (!committer)
+		committer = git_committer_info(IDENT_STRICT);
+	strbuf_addf(&buffer, "committer %s\n", committer);
 	if (!encoding_is_utf8)
 		strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);
 
@@ -1630,22 +1633,22 @@
 int run_commit_hook(int editor_is_used, const char *index_file,
 		    const char *name, ...)
 {
-	struct argv_array hook_env = ARGV_ARRAY_INIT;
+	struct strvec hook_env = STRVEC_INIT;
 	va_list args;
 	int ret;
 
-	argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", index_file);
+	strvec_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=:");
+		strvec_push(&hook_env, "GIT_EDITOR=:");
 
 	va_start(args, name);
-	ret = run_hook_ve(hook_env.argv,name, args);
+	ret = run_hook_ve(hook_env.v, name, args);
 	va_end(args);
-	argv_array_clear(&hook_env);
+	strvec_clear(&hook_env);
 
 	return ret;
 }
diff --git a/commit.h b/commit.h
index e901538..bd73b84 100644
--- a/commit.h
+++ b/commit.h
@@ -270,10 +270,9 @@
 
 int commit_tree_extended(const char *msg, size_t msg_len,
 			 const struct object_id *tree,
-			 struct commit_list *parents,
-			 struct object_id *ret, const char *author,
-			 const char *sign_commit,
-			 struct commit_extra_header *);
+			 struct commit_list *parents, struct object_id *ret,
+			 const char *author, const char *committer,
+			 const char *sign_commit, struct commit_extra_header *);
 
 struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **);
 
diff --git a/compat/mingw.c b/compat/mingw.c
index 8ee0b64..a00f331 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -18,8 +18,8 @@
 	static struct child_process cp = CHILD_PROCESS_INIT;
 	extern char *_pgmptr;
 
-	argv_array_pushl(&cp.args, "mintty", "gdb", NULL);
-	argv_array_pushf(&cp.args, "--pid=%d", getpid());
+	strvec_pushl(&cp.args, "mintty", "gdb", NULL);
+	strvec_pushf(&cp.args, "--pid=%d", getpid());
 	cp.clean_on_exit = 1;
 	if (start_command(&cp) < 0)
 		die_errno("Could not start gdb");
@@ -290,6 +290,9 @@
 	if (xutftowcs_path(wpathname, pathname) < 0)
 		return -1;
 
+	if (DeleteFileW(wpathname))
+		return 0;
+
 	/* read-only files cannot be removed */
 	_wchmod(wpathname, 0666);
 	while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
diff --git a/compat/terminal.c b/compat/terminal.c
index 35bca03..43b73dd 100644
--- a/compat/terminal.c
+++ b/compat/terminal.c
@@ -86,9 +86,9 @@
 		if (stty_restore.nr == 0)
 			return;
 
-		argv_array_push(&cp.args, "stty");
+		strvec_push(&cp.args, "stty");
 		for (i = 0; i < stty_restore.nr; i++)
-			argv_array_push(&cp.args, stty_restore.items[i].string);
+			strvec_push(&cp.args, stty_restore.items[i].string);
 		run_command(&cp);
 		string_list_clear(&stty_restore, 0);
 		return;
@@ -107,25 +107,25 @@
 	if (use_stty) {
 		struct child_process cp = CHILD_PROCESS_INIT;
 
-		argv_array_push(&cp.args, "stty");
+		strvec_push(&cp.args, "stty");
 
 		if (bits & ENABLE_LINE_INPUT) {
 			string_list_append(&stty_restore, "icanon");
-			argv_array_push(&cp.args, "-icanon");
+			strvec_push(&cp.args, "-icanon");
 		}
 
 		if (bits & ENABLE_ECHO_INPUT) {
 			string_list_append(&stty_restore, "echo");
-			argv_array_push(&cp.args, "-echo");
+			strvec_push(&cp.args, "-echo");
 		}
 
 		if (bits & ENABLE_PROCESSED_INPUT) {
 			string_list_append(&stty_restore, "-ignbrk");
 			string_list_append(&stty_restore, "intr");
 			string_list_append(&stty_restore, "^c");
-			argv_array_push(&cp.args, "ignbrk");
-			argv_array_push(&cp.args, "intr");
-			argv_array_push(&cp.args, "");
+			strvec_push(&cp.args, "ignbrk");
+			strvec_push(&cp.args, "intr");
+			strvec_push(&cp.args, "");
 		}
 
 		if (run_command(&cp) == 0)
@@ -273,7 +273,7 @@
 		hashmap_init(&sequences, (hashmap_cmp_fn)sequence_entry_cmp,
 			     NULL, 0);
 
-		argv_array_pushl(&cp.args, "infocmp", "-L", "-1", NULL);
+		strvec_pushl(&cp.args, "infocmp", "-L", "-1", NULL);
 		if (pipe_command(&cp, NULL, 0, &buf, 0, NULL, 0))
 			strbuf_setlen(&buf, 0);
 
diff --git a/config.c b/config.c
index 8db9c77..2bdff44 100644
--- a/config.c
+++ b/config.c
@@ -2006,18 +2006,27 @@
 	return e ? &e->value_list : NULL;
 }
 
-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)
 {
 	const char *value;
 	if (!git_configset_get_value(cs, key, &value))
-		return git_config_string(dest, key, value);
+		return git_config_string((const char **)dest, key, value);
 	else
 		return 1;
 }
 
-int git_configset_get_string(struct config_set *cs, const char *key, char **dest)
+int git_configset_get_string_tmp(struct config_set *cs, const char *key,
+				 const char **dest)
 {
-	return git_configset_get_string_const(cs, key, (const char **)dest);
+	const char *value;
+	if (!git_configset_get_value(cs, key, &value)) {
+		if (!value)
+			return config_error_nonbool(key);
+		*dest = value;
+		return 0;
+	} else {
+		return 1;
+	}
 }
 
 int git_configset_get_int(struct config_set *cs, const char *key, int *dest)
@@ -2147,22 +2156,26 @@
 	return git_configset_get_value_multi(repo->config, key);
 }
 
-int repo_config_get_string_const(struct repository *repo,
-				 const char *key, const char **dest)
+int repo_config_get_string(struct repository *repo,
+			   const char *key, char **dest)
 {
 	int ret;
 	git_config_check_init(repo);
-	ret = git_configset_get_string_const(repo->config, key, dest);
+	ret = git_configset_get_string(repo->config, key, dest);
 	if (ret < 0)
 		git_die_config(key, NULL);
 	return ret;
 }
 
-int repo_config_get_string(struct repository *repo,
-			   const char *key, char **dest)
+int repo_config_get_string_tmp(struct repository *repo,
+			       const char *key, const char **dest)
 {
+	int ret;
 	git_config_check_init(repo);
-	return repo_config_get_string_const(repo, key, (const char **)dest);
+	ret = git_configset_get_string_tmp(repo->config, key, dest);
+	if (ret < 0)
+		git_die_config(key, NULL);
+	return ret;
 }
 
 int repo_config_get_int(struct repository *repo,
@@ -2232,16 +2245,16 @@
 	return repo_config_get_value_multi(the_repository, key);
 }
 
-int git_config_get_string_const(const char *key, const char **dest)
-{
-	return repo_config_get_string_const(the_repository, key, dest);
-}
-
 int git_config_get_string(const char *key, char **dest)
 {
 	return repo_config_get_string(the_repository, key, dest);
 }
 
+int git_config_get_string_tmp(const char *key, const char **dest)
+{
+	return repo_config_get_string_tmp(the_repository, key, dest);
+}
+
 int git_config_get_int(const char *key, int *dest)
 {
 	return repo_config_get_int(the_repository, key, dest);
@@ -2274,7 +2287,7 @@
 
 int git_config_get_expiry(const char *key, const char **output)
 {
-	int ret = git_config_get_string_const(key, output);
+	int ret = git_config_get_string(key, (char **)output);
 	if (ret)
 		return ret;
 	if (strcmp(*output, "now")) {
@@ -2287,11 +2300,11 @@
 
 int git_config_get_expiry_in_days(const char *key, timestamp_t *expiry, timestamp_t now)
 {
-	char *expiry_string;
+	const char *expiry_string;
 	intmax_t days;
 	timestamp_t when;
 
-	if (git_config_get_string(key, &expiry_string))
+	if (git_config_get_string_tmp(key, &expiry_string))
 		return 1; /* no such thing */
 
 	if (git_parse_signed(expiry_string, &days, maximum_signed_value_of_type(int))) {
@@ -3115,7 +3128,7 @@
 	}
 
 	while (fgets(buf, sizeof(buf), config_file)) {
-		int i;
+		unsigned i;
 		int length;
 		int is_section = 0;
 		char *output = buf;
diff --git a/config.h b/config.h
index 0608744..91cdfbf 100644
--- a/config.h
+++ b/config.h
@@ -458,8 +458,8 @@
  */
 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_string_tmp(struct config_set *cs, const char *key, const char **dest);
 int git_configset_get_int(struct config_set *cs, const char *key, int *dest);
 int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest);
 int git_configset_get_bool(struct config_set *cs, const char *key, int *dest);
@@ -474,10 +474,10 @@
 			  const char *key, const char **value);
 const struct string_list *repo_config_get_value_multi(struct repository *repo,
 						      const char *key);
-int repo_config_get_string_const(struct repository *repo,
-				 const char *key, const char **dest);
 int repo_config_get_string(struct repository *repo,
 			   const char *key, char **dest);
+int repo_config_get_string_tmp(struct repository *repo,
+			       const char *key, const char **dest);
 int repo_config_get_int(struct repository *repo,
 			const char *key, int *dest);
 int repo_config_get_ulong(struct repository *repo,
@@ -529,13 +529,14 @@
  * 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);
+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.
+ * Similar to `git_config_get_string`, but does not allocate any new
+ * memory; on success `dest` will point to memory owned by the config
+ * machinery, which could be invalidated if it is discarded and reloaded.
  */
-int git_config_get_string(const char *key, char **dest);
+int git_config_get_string_tmp(const char *key, const char **dest);
 
 /**
  * Finds and parses the value to an integer for the configuration variable
diff --git a/config.mak.dev b/config.mak.dev
index cd4a82a..89b218d 100644
--- a/config.mak.dev
+++ b/config.mak.dev
@@ -16,8 +16,6 @@
 DEVELOPER_CFLAGS += -Wunused
 DEVELOPER_CFLAGS += -Wvla
 
-DEVELOPER_CFLAGS += -DENABLE_SHA256
-
 ifndef COMPILER_FEATURES
 COMPILER_FEATURES := $(shell ./detect-compiler $(CC))
 endif
diff --git a/connect.c b/connect.c
index e0d5b9f..8b8f56c 100644
--- a/connect.c
+++ b/connect.c
@@ -17,7 +17,7 @@
 #include "alias.h"
 
 static char *server_capabilities_v1;
-static struct argv_array server_capabilities_v2 = ARGV_ARRAY_INIT;
+static struct strvec server_capabilities_v2 = STRVEC_INIT;
 static const char *next_server_feature_value(const char *feature, int *len, int *offset);
 
 static int check_ref(const char *name, unsigned int flags)
@@ -70,9 +70,9 @@
 {
 	int i;
 
-	for (i = 0; i < server_capabilities_v2.argc; i++) {
+	for (i = 0; i < server_capabilities_v2.nr; i++) {
 		const char *out;
-		if (skip_prefix(server_capabilities_v2.argv[i], c, &out) &&
+		if (skip_prefix(server_capabilities_v2.v[i], c, &out) &&
 		    (!*out || *out == '='))
 			return 1;
 	}
@@ -87,9 +87,9 @@
 {
 	int i;
 
-	for (i = 0; i < server_capabilities_v2.argc; i++) {
+	for (i = 0; i < server_capabilities_v2.nr; i++) {
 		const char *out;
-		if (skip_prefix(server_capabilities_v2.argv[i], c, &out) &&
+		if (skip_prefix(server_capabilities_v2.v[i], c, &out) &&
 		    (*out == '=')) {
 			*v = out + 1;
 			return 1;
@@ -103,9 +103,9 @@
 {
 	int i;
 
-	for (i = 0; i < server_capabilities_v2.argc; i++) {
+	for (i = 0; i < server_capabilities_v2.nr; i++) {
 		const char *out;
-		if (skip_prefix(server_capabilities_v2.argv[i], c, &out) &&
+		if (skip_prefix(server_capabilities_v2.v[i], c, &out) &&
 		    (!*out || *(out++) == '=')) {
 			if (parse_feature_request(out, feature))
 				return 1;
@@ -123,7 +123,7 @@
 static void process_capabilities_v2(struct packet_reader *reader)
 {
 	while (packet_reader_read(reader) == PACKET_READ_NORMAL)
-		argv_array_push(&server_capabilities_v2, reader->line);
+		strvec_push(&server_capabilities_v2, reader->line);
 
 	if (reader->status != PACKET_READ_FLUSH)
 		die(_("expected flush after capabilities"));
@@ -453,7 +453,7 @@
 
 struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
 			     struct ref **list, int for_push,
-			     const struct argv_array *ref_prefixes,
+			     const struct strvec *ref_prefixes,
 			     const struct string_list *server_options,
 			     int stateless_rpc)
 {
@@ -488,9 +488,9 @@
 	if (!for_push)
 		packet_write_fmt(fd_out, "peel\n");
 	packet_write_fmt(fd_out, "symrefs\n");
-	for (i = 0; ref_prefixes && i < ref_prefixes->argc; i++) {
+	for (i = 0; ref_prefixes && i < ref_prefixes->nr; i++) {
 		packet_write_fmt(fd_out, "ref-prefix %s\n",
-				 ref_prefixes->argv[i]);
+				 ref_prefixes->v[i]);
 	}
 	packet_flush(fd_out);
 
@@ -944,9 +944,9 @@
 
 	proxy = xmalloc(sizeof(*proxy));
 	child_process_init(proxy);
-	argv_array_push(&proxy->args, git_proxy_command);
-	argv_array_push(&proxy->args, host);
-	argv_array_push(&proxy->args, port);
+	strvec_push(&proxy->args, git_proxy_command);
+	strvec_push(&proxy->args, host);
+	strvec_push(&proxy->args, port);
 	proxy->in = -1;
 	proxy->out = -1;
 	if (start_command(proxy))
@@ -1052,7 +1052,7 @@
 	if ((ssh = getenv("GIT_SSH_COMMAND")))
 		return ssh;
 
-	if (!git_config_get_string_const("core.sshcommand", &ssh))
+	if (!git_config_get_string_tmp("core.sshcommand", &ssh))
 		return ssh;
 
 	return NULL;
@@ -1071,7 +1071,7 @@
 {
 	const char *variant = getenv("GIT_SSH_VARIANT");
 
-	if (!variant && git_config_get_string_const("ssh.variant", &variant))
+	if (!variant && git_config_get_string_tmp("ssh.variant", &variant))
 		return;
 
 	if (!strcmp(variant, "auto"))
@@ -1199,16 +1199,16 @@
  * Append the appropriate environment variables to `env` and options to
  * `args` for running ssh in Git's SSH-tunneled transport.
  */
-static void push_ssh_options(struct argv_array *args, struct argv_array *env,
+static void push_ssh_options(struct strvec *args, struct strvec *env,
 			     enum ssh_variant variant, const char *port,
 			     enum protocol_version version, int flags)
 {
 	if (variant == VARIANT_SSH &&
 	    version > 0) {
-		argv_array_push(args, "-o");
-		argv_array_push(args, "SendEnv=" GIT_PROTOCOL_ENVIRONMENT);
-		argv_array_pushf(env, GIT_PROTOCOL_ENVIRONMENT "=version=%d",
-				 version);
+		strvec_push(args, "-o");
+		strvec_push(args, "SendEnv=" GIT_PROTOCOL_ENVIRONMENT);
+		strvec_pushf(env, GIT_PROTOCOL_ENVIRONMENT "=version=%d",
+			     version);
 	}
 
 	if (flags & CONNECT_IPV4) {
@@ -1221,7 +1221,7 @@
 		case VARIANT_PLINK:
 		case VARIANT_PUTTY:
 		case VARIANT_TORTOISEPLINK:
-			argv_array_push(args, "-4");
+			strvec_push(args, "-4");
 		}
 	} else if (flags & CONNECT_IPV6) {
 		switch (variant) {
@@ -1233,12 +1233,12 @@
 		case VARIANT_PLINK:
 		case VARIANT_PUTTY:
 		case VARIANT_TORTOISEPLINK:
-			argv_array_push(args, "-6");
+			strvec_push(args, "-6");
 		}
 	}
 
 	if (variant == VARIANT_TORTOISEPLINK)
-		argv_array_push(args, "-batch");
+		strvec_push(args, "-batch");
 
 	if (port) {
 		switch (variant) {
@@ -1247,15 +1247,15 @@
 		case VARIANT_SIMPLE:
 			die(_("ssh variant 'simple' does not support setting port"));
 		case VARIANT_SSH:
-			argv_array_push(args, "-p");
+			strvec_push(args, "-p");
 			break;
 		case VARIANT_PLINK:
 		case VARIANT_PUTTY:
 		case VARIANT_TORTOISEPLINK:
-			argv_array_push(args, "-P");
+			strvec_push(args, "-P");
 		}
 
-		argv_array_push(args, port);
+		strvec_push(args, port);
 	}
 }
 
@@ -1293,18 +1293,18 @@
 		detect.use_shell = conn->use_shell;
 		detect.no_stdin = detect.no_stdout = detect.no_stderr = 1;
 
-		argv_array_push(&detect.args, ssh);
-		argv_array_push(&detect.args, "-G");
+		strvec_push(&detect.args, ssh);
+		strvec_push(&detect.args, "-G");
 		push_ssh_options(&detect.args, &detect.env_array,
 				 VARIANT_SSH, port, version, flags);
-		argv_array_push(&detect.args, ssh_host);
+		strvec_push(&detect.args, ssh_host);
 
 		variant = run_command(&detect) ? VARIANT_SIMPLE : VARIANT_SSH;
 	}
 
-	argv_array_push(&conn->args, ssh);
+	strvec_push(&conn->args, ssh);
 	push_ssh_options(&conn->args, &conn->env_array, variant, port, version, flags);
-	argv_array_push(&conn->args, ssh_host);
+	strvec_push(&conn->args, ssh_host);
 }
 
 /*
@@ -1365,7 +1365,7 @@
 
 		/* remove repo-local variables from the environment */
 		for (var = local_repo_env; *var; var++)
-			argv_array_push(&conn->env_array, *var);
+			strvec_push(&conn->env_array, *var);
 
 		conn->use_shell = 1;
 		conn->in = conn->out = -1;
@@ -1397,11 +1397,12 @@
 			transport_check_allowed("file");
 			conn->trace2_child_class = "transport/file";
 			if (version > 0) {
-				argv_array_pushf(&conn->env_array, GIT_PROTOCOL_ENVIRONMENT "=version=%d",
-						 version);
+				strvec_pushf(&conn->env_array,
+					     GIT_PROTOCOL_ENVIRONMENT "=version=%d",
+					     version);
 			}
 		}
-		argv_array_push(&conn->args, cmd.buf);
+		strvec_push(&conn->args, cmd.buf);
 
 		if (start_command(conn))
 			die(_("unable to fork"));
diff --git a/connected.c b/connected.c
index 937b4ba..b18299f 100644
--- a/connected.c
+++ b/connected.c
@@ -22,14 +22,13 @@
 		    struct check_connected_options *opt)
 {
 	struct child_process rev_list = CHILD_PROCESS_INIT;
+	FILE *rev_list_in;
 	struct check_connected_options defaults = CHECK_CONNECTED_INIT;
-	char commit[GIT_MAX_HEXSZ + 1];
 	struct object_id oid;
 	int err = 0;
 	struct packed_git *new_pack = NULL;
 	struct transport *transport;
 	size_t base_len;
-	const unsigned hexsz = the_hash_algo->hexsz;
 
 	if (!opt)
 		opt = &defaults;
@@ -90,23 +89,23 @@
 
 no_promisor_pack_found:
 	if (opt->shallow_file) {
-		argv_array_push(&rev_list.args, "--shallow-file");
-		argv_array_push(&rev_list.args, opt->shallow_file);
+		strvec_push(&rev_list.args, "--shallow-file");
+		strvec_push(&rev_list.args, opt->shallow_file);
 	}
-	argv_array_push(&rev_list.args,"rev-list");
-	argv_array_push(&rev_list.args, "--objects");
-	argv_array_push(&rev_list.args, "--stdin");
+	strvec_push(&rev_list.args,"rev-list");
+	strvec_push(&rev_list.args, "--objects");
+	strvec_push(&rev_list.args, "--stdin");
 	if (has_promisor_remote())
-		argv_array_push(&rev_list.args, "--exclude-promisor-objects");
+		strvec_push(&rev_list.args, "--exclude-promisor-objects");
 	if (!opt->is_deepening_fetch) {
-		argv_array_push(&rev_list.args, "--not");
-		argv_array_push(&rev_list.args, "--all");
+		strvec_push(&rev_list.args, "--not");
+		strvec_push(&rev_list.args, "--all");
 	}
-	argv_array_push(&rev_list.args, "--quiet");
-	argv_array_push(&rev_list.args, "--alternate-refs");
+	strvec_push(&rev_list.args, "--quiet");
+	strvec_push(&rev_list.args, "--alternate-refs");
 	if (opt->progress)
-		argv_array_pushf(&rev_list.args, "--progress=%s",
-				 _("Checking connectivity"));
+		strvec_pushf(&rev_list.args, "--progress=%s",
+			     _("Checking connectivity"));
 
 	rev_list.git_cmd = 1;
 	rev_list.env = opt->env;
@@ -122,7 +121,8 @@
 
 	sigchain_push(SIGPIPE, SIG_IGN);
 
-	commit[hexsz] = '\n';
+	rev_list_in = xfdopen(rev_list.in, "w");
+
 	do {
 		/*
 		 * If index-pack already checked that:
@@ -135,16 +135,17 @@
 		if (new_pack && find_pack_entry_one(oid.hash, new_pack))
 			continue;
 
-		memcpy(commit, oid_to_hex(&oid), hexsz);
-		if (write_in_full(rev_list.in, commit, hexsz + 1) < 0) {
-			if (errno != EPIPE && errno != EINVAL)
-				error_errno(_("failed write to rev-list"));
-			err = -1;
+		if (fprintf(rev_list_in, "%s\n", oid_to_hex(&oid)) < 0)
 			break;
-		}
 	} while (!fn(cb_data, &oid));
 
-	if (close(rev_list.in))
+	if (ferror(rev_list_in) || fflush(rev_list_in)) {
+		if (errno != EPIPE && errno != EINVAL)
+			error_errno(_("failed write to rev-list"));
+		err = -1;
+	}
+
+	if (fclose(rev_list_in))
 		err = error_errno(_("failed to close rev-list's stdin"));
 
 	sigchain_pop(SIGPIPE);
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
new file mode 100644
index 0000000..5007f17
--- /dev/null
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -0,0 +1,960 @@
+#
+#	Copyright (c) 2020 Sibi Siddharthan
+#
+
+#[[
+
+Instructions to run CMake:
+
+cmake `relative-path-to-CMakeLists.txt` -DCMAKE_BUILD_TYPE=Release
+Eg.
+From the root of git source tree
+	`cmake contrib/buildsystems/ `
+This will build the git binaries at the root
+
+For out of source builds, say build in 'git/git-build/'
+	`mkdir git-build;cd git-build; cmake ../contrib/buildsystems/`
+This will build the git binaries in git-build directory
+
+Possible build configurations(-DCMAKE_BUILD_TYPE) with corresponding
+compiler flags
+Debug : -g
+Release: -O3
+RelWithDebInfo : -O2 -g
+MinSizeRel : -Os
+empty(default) :
+
+NOTE: -DCMAKE_BUILD_TYPE is optional. For multi-config generators like Visual Studio
+this option is ignored
+
+This process generates a Makefile(Linux/*BSD/MacOS) , Visual Studio solution(Windows) by default.
+Run `make` to build Git on Linux/*BSD/MacOS.
+Open git.sln on Windows and build Git.
+
+NOTE: By default CMake uses Makefile as the build tool on Linux and Visual Studio in Windows,
+to use another tool say `ninja` add this to the command line when configuring.
+`-G Ninja`
+
+]]
+cmake_minimum_required(VERSION 3.14)
+
+#set the source directory to root of git
+set(CMAKE_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
+
+find_program(SH_EXE sh)
+if(NOT SH_EXE)
+	message(FATAL_ERROR "sh: shell interpreter was not found in your path, please install one."
+			"On Windows, you can get it as part of 'Git for Windows' install at https://gitforwindows.org/")
+endif()
+
+#Create GIT-VERSION-FILE using GIT-VERSION-GEN
+if(NOT EXISTS ${CMAKE_SOURCE_DIR}/GIT-VERSION-FILE)
+	message("Generating GIT-VERSION-FILE")
+	execute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN
+		WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+endif()
+
+#Parse GIT-VERSION-FILE to get the version
+file(STRINGS ${CMAKE_SOURCE_DIR}/GIT-VERSION-FILE git_version REGEX "GIT_VERSION = (.*)")
+string(REPLACE "GIT_VERSION = " "" git_version ${git_version})
+string(FIND ${git_version} "GIT" location)
+if(location EQUAL -1)
+	string(REGEX MATCH "[0-9]*\\.[0-9]*\\.[0-9]*" git_version ${git_version})
+else()
+	string(REGEX MATCH "[0-9]*\\.[0-9]*" git_version ${git_version})
+	string(APPEND git_version ".0") #for building from a snapshot
+endif()
+
+project(git
+	VERSION ${git_version}
+	LANGUAGES C)
+
+
+#TODO gitk git-gui gitweb
+#TODO Enable NLS on windows natively
+#TODO Add pcre support
+
+#macros for parsing the Makefile for sources and scripts
+macro(parse_makefile_for_sources list_var regex)
+	file(STRINGS ${CMAKE_SOURCE_DIR}/Makefile ${list_var} REGEX "^${regex} \\+=(.*)")
+	string(REPLACE "${regex} +=" "" ${list_var} ${${list_var}})
+	string(REPLACE "$(COMPAT_OBJS)" "" ${list_var} ${${list_var}}) #remove "$(COMPAT_OBJS)" This is only for libgit.
+	string(STRIP ${${list_var}} ${list_var}) #remove trailing/leading whitespaces
+	string(REPLACE ".o" ".c;" ${list_var} ${${list_var}}) #change .o to .c, ; is for converting the string into a list
+	list(TRANSFORM ${list_var} STRIP) #remove trailing/leading whitespaces for each element in list
+	list(REMOVE_ITEM ${list_var} "") #remove empty list elements
+endmacro()
+
+macro(parse_makefile_for_scripts list_var regex lang)
+	file(STRINGS ${CMAKE_SOURCE_DIR}/Makefile ${list_var} REGEX "^${regex} \\+=(.*)")
+	string(REPLACE "${regex} +=" "" ${list_var} ${${list_var}})
+	string(STRIP ${${list_var}} ${list_var}) #remove trailing/leading whitespaces
+	string(REPLACE " " ";" ${list_var} ${${list_var}}) #convert string to a list
+	if(NOT ${lang}) #exclude for SCRIPT_LIB
+		list(TRANSFORM ${list_var} REPLACE "${lang}" "") #do the replacement
+	endif()
+endmacro()
+
+include(CheckTypeSize)
+include(CheckCSourceRuns)
+include(CheckCSourceCompiles)
+include(CheckIncludeFile)
+include(CheckFunctionExists)
+include(CheckSymbolExists)
+include(CheckStructHasMember)
+include(CTest)
+
+find_package(ZLIB REQUIRED)
+find_package(CURL)
+find_package(EXPAT)
+find_package(Iconv)
+
+#Don't use libintl on Windows Visual Studio and Clang builds
+if(NOT (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "MSVC" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")))
+	find_package(Intl)
+endif()
+
+if(NOT Intl_FOUND)
+	add_compile_definitions(NO_GETTEXT)
+	if(NOT Iconv_FOUND)
+		add_compile_definitions(NO_ICONV)
+	endif()
+endif()
+
+include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS})
+if(CURL_FOUND)
+	include_directories(SYSTEM ${CURL_INCLUDE_DIRS})
+endif()
+if(EXPAT_FOUND)
+	include_directories(SYSTEM ${EXPAT_INCLUDE_DIRS})
+endif()
+if(Iconv_FOUND)
+	include_directories(SYSTEM ${Iconv_INCLUDE_DIRS})
+endif()
+if(Intl_FOUND)
+	include_directories(SYSTEM ${Intl_INCLUDE_DIRS})
+endif()
+
+
+if(WIN32 AND NOT MSVC)#not required for visual studio builds
+	find_program(WINDRES_EXE windres)
+	if(NOT WINDRES_EXE)
+		message(FATAL_ERROR "Install windres on Windows for resource files")
+	endif()
+endif()
+
+find_program(MSGFMT_EXE msgfmt)
+if(NOT MSGFMT_EXE)
+	message(WARNING "Text Translations won't be build")
+endif()
+
+#Force all visual studio outputs to CMAKE_BINARY_DIR
+if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
+	set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR})
+	set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR})
+	add_compile_options(/MP)
+endif()
+
+#default behaviour
+include_directories(${CMAKE_SOURCE_DIR})
+add_compile_definitions(GIT_HOST_CPU="${CMAKE_SYSTEM_PROCESSOR}")
+add_compile_definitions(SHA256_BLK INTERNAL_QSORT RUNTIME_PREFIX)
+add_compile_definitions(NO_OPENSSL SHA1_DC SHA1DC_NO_STANDARD_INCLUDES
+			SHA1DC_INIT_SAFE_HASH_DEFAULT=0
+			SHA1DC_CUSTOM_INCLUDE_SHA1_C="cache.h"
+			SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C="git-compat-util.h" )
+list(APPEND compat_SOURCES sha1dc_git.c sha1dc/sha1.c sha1dc/ubc_check.c block-sha1/sha1.c sha256/block/sha256.c compat/qsort_s.c)
+
+
+add_compile_definitions(PAGER_ENV="LESS=FRX LV=-c"
+			ETC_GITATTRIBUTES="etc/gitattributes"
+			ETC_GITCONFIG="etc/gitconfig"
+			GIT_EXEC_PATH="libexec/git-core"
+			GIT_LOCALE_PATH="share/locale"
+			GIT_MAN_PATH="share/man"
+			GIT_INFO_PATH="share/info"
+			GIT_HTML_PATH="share/doc/git-doc"
+			DEFAULT_HELP_FORMAT="html"
+			DEFAULT_GIT_TEMPLATE_DIR="share/git-core/templates"
+			GIT_VERSION="${PROJECT_VERSION}.GIT"
+			GIT_USER_AGENT="git/${PROJECT_VERSION}.GIT"
+			BINDIR="bin"
+			GIT_BUILT_FROM_COMMIT="")
+
+if(WIN32)
+	set(FALLBACK_RUNTIME_PREFIX /mingw64)
+	add_compile_definitions(FALLBACK_RUNTIME_PREFIX="${FALLBACK_RUNTIME_PREFIX}")
+else()
+	set(FALLBACK_RUNTIME_PREFIX /home/$ENV{USER})
+	add_compile_definitions(FALLBACK_RUNTIME_PREFIX="${FALLBACK_RUNTIME_PREFIX}")
+endif()
+
+
+#Platform Specific
+if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
+	if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
+		include_directories(${CMAKE_SOURCE_DIR}/compat/vcbuild/include)
+		add_compile_definitions(_CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE)
+	endif()
+	include_directories(${CMAKE_SOURCE_DIR}/compat/win32)
+	add_compile_definitions(HAVE_ALLOCA_H NO_POSIX_GOODIES NATIVE_CRLF NO_UNIX_SOCKETS WIN32
+				_CONSOLE DETECT_MSYS_TTY STRIP_EXTENSION=".exe"  NO_SYMLINK_HEAD UNRELIABLE_FSTAT
+				NOGDI OBJECT_CREATION_MODE=1 __USE_MINGW_ANSI_STDIO=0
+				USE_NED_ALLOCATOR OVERRIDE_STRDUP MMAP_PREVENTS_DELETE USE_WIN32_MMAP
+				UNICODE _UNICODE HAVE_WPGMPTR ENSURE_MSYSTEM_IS_SET)
+	list(APPEND compat_SOURCES compat/mingw.c compat/winansi.c compat/win32/path-utils.c
+		compat/win32/pthread.c compat/win32mmap.c compat/win32/syslog.c
+		compat/win32/trace2_win32_process_info.c compat/win32/dirent.c
+		compat/nedmalloc/nedmalloc.c compat/strdup.c)
+	set(NO_UNIX_SOCKETS 1)
+
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+	add_compile_definitions(PROCFS_EXECUTABLE_PATH="/proc/self/exe" HAVE_DEV_TTY )
+	list(APPEND compat_SOURCES unix-socket.c)
+endif()
+
+set(EXE_EXTENSION ${CMAKE_EXECUTABLE_SUFFIX})
+
+#header checks
+check_include_file(libgen.h HAVE_LIBGEN_H)
+if(NOT HAVE_LIBGEN_H)
+	add_compile_definitions(NO_LIBGEN_H)
+	list(APPEND compat_SOURCES compat/basename.c)
+endif()
+
+check_include_file(sys/sysinfo.h HAVE_SYSINFO)
+if(HAVE_SYSINFO)
+	add_compile_definitions(HAVE_SYSINFO)
+endif()
+
+check_c_source_compiles("
+#include <alloca.h>
+
+int main(void)
+{
+	char *p = (char *) alloca(2 * sizeof(int));
+
+	if (p)
+		return 0;
+	return 0;
+}"
+HAVE_ALLOCA_H)
+if(HAVE_ALLOCA_H)
+	add_compile_definitions(HAVE_ALLOCA_H)
+endif()
+
+check_include_file(strings.h HAVE_STRINGS_H)
+if(HAVE_STRINGS_H)
+	add_compile_definitions(HAVE_STRINGS_H)
+endif()
+
+check_include_file(sys/select.h HAVE_SYS_SELECT_H)
+if(NOT HAVE_SYS_SELECT_H)
+	add_compile_definitions(NO_SYS_SELECT_H)
+endif()
+
+check_include_file(sys/poll.h HAVE_SYS_POLL_H)
+if(NOT HAVE_SYS_POLL_H)
+	add_compile_definitions(NO_SYS_POLL_H)
+endif()
+
+check_include_file(poll.h HAVE_POLL_H)
+if(NOT HAVE_POLL_H)
+	add_compile_definitions(NO_POLL_H)
+endif()
+
+check_include_file(inttypes.h HAVE_INTTYPES_H)
+if(NOT HAVE_INTTYPES_H)
+	add_compile_definitions(NO_INTTYPES_H)
+endif()
+
+check_include_file(paths.h HAVE_PATHS_H)
+if(HAVE_PATHS_H)
+	add_compile_definitions(HAVE_PATHS_H)
+endif()
+
+#function checks
+set(function_checks
+	strcasestr memmem strlcpy strtoimax strtoumax strtoull
+	setenv mkdtemp poll pread memmem)
+
+#unsetenv,hstrerror are incompatible with windows build
+if(NOT WIN32)
+	list(APPEND function_checks unsetenv hstrerror)
+endif()
+
+foreach(f ${function_checks})
+	string(TOUPPER ${f} uf)
+	check_function_exists(${f} HAVE_${uf})
+	if(NOT HAVE_${uf})
+		add_compile_definitions(NO_${uf})
+	endif()
+endforeach()
+
+if(NOT HAVE_POLL_H OR NOT HAVE_SYS_POLL_H OR NOT HAVE_POLL)
+	include_directories(${CMAKE_SOURCE_DIR}/compat/poll)
+	add_compile_definitions(NO_POLL)
+	list(APPEND compat_SOURCES compat/poll/poll.c)
+endif()
+
+if(NOT HAVE_STRCASESTR)
+	list(APPEND compat_SOURCES compat/strcasestr.c)
+endif()
+
+if(NOT HAVE_STRLCPY)
+	list(APPEND compat_SOURCES compat/strlcpy.c)
+endif()
+
+if(NOT HAVE_STRTOUMAX)
+	list(APPEND compat_SOURCES compat/strtoumax.c compat/strtoimax.c)
+endif()
+
+if(NOT HAVE_SETENV)
+	list(APPEND compat_SOURCES compat/setenv.c)
+endif()
+
+if(NOT HAVE_MKDTEMP)
+	list(APPEND compat_SOURCES compat/mkdtemp.c)
+endif()
+
+if(NOT HAVE_PREAD)
+	list(APPEND compat_SOURCES compat/pread.c)
+endif()
+
+if(NOT HAVE_MEMMEM)
+	list(APPEND compat_SOURCES compat/memmem.c)
+endif()
+
+if(NOT WIN32)
+	if(NOT HAVE_UNSETENV)
+		list(APPEND compat_SOURCES compat/unsetenv.c)
+	endif()
+
+	if(NOT HAVE_HSTRERROR)
+		list(APPEND compat_SOURCES compat/hstrerror.c)
+	endif()
+endif()
+
+check_function_exists(getdelim HAVE_GETDELIM)
+if(HAVE_GETDELIM)
+	add_compile_definitions(HAVE_GETDELIM)
+endif()
+
+check_function_exists(clock_gettime HAVE_CLOCK_GETTIME)
+check_symbol_exists(CLOCK_MONOTONIC "time.h" HAVE_CLOCK_MONOTONIC)
+if(HAVE_CLOCK_GETTIME)
+	add_compile_definitions(HAVE_CLOCK_GETTIME)
+endif()
+if(HAVE_CLOCK_MONOTONIC)
+	add_compile_definitions(HAVE_CLOCK_MONOTONIC)
+endif()
+
+#check for st_blocks in struct stat
+check_struct_has_member("struct stat" st_blocks "sys/stat.h" STRUCT_STAT_HAS_ST_BLOCKS)
+if(NOT STRUCT_STAT_HAS_ST_BLOCKS)
+	add_compile_definitions(NO_ST_BLOCKS_IN_STRUCT_STAT)
+endif()
+
+#compile checks
+check_c_source_runs("
+#include<stdio.h>
+#include<stdarg.h>
+#include<string.h>
+#include<stdlib.h>
+
+int test_vsnprintf(char *str, size_t maxsize, const char *format, ...)
+{
+	int ret;
+	va_list ap;
+
+	va_start(ap, format);
+	ret = vsnprintf(str, maxsize, format, ap);
+	va_end(ap);
+	return ret;
+}
+
+int main(void)
+{
+	char buf[6];
+
+	if (test_vsnprintf(buf, 3, \"%s\", \"12345\") != 5
+		|| strcmp(buf, \"12\"))
+			return 1;
+	if (snprintf(buf, 3, \"%s\", \"12345\") != 5
+		|| strcmp(buf, \"12\"))
+			return 1;
+	return 0;
+}"
+SNPRINTF_OK)
+if(NOT SNPRINTF_OK)
+	add_compile_definitions(SNPRINTF_RETURNS_BOGUS)
+	list(APPEND compat_SOURCES compat/snprintf.c)
+endif()
+
+check_c_source_runs("
+#include<stdio.h>
+
+int main(void)
+{
+	FILE *f = fopen(\".\", \"r\");
+
+	return f != NULL;
+}"
+FREAD_READS_DIRECTORIES_NO)
+if(NOT FREAD_READS_DIRECTORIES_NO)
+	add_compile_definitions(FREAD_READS_DIRECTORIES)
+	list(APPEND compat_SOURCES compat/fopen.c)
+endif()
+
+check_c_source_compiles("
+#include <regex.h>
+#ifndef REG_STARTEND
+#error oops we dont have it
+#endif
+
+int main(void)
+{
+	return 0;
+}"
+HAVE_REGEX)
+if(NOT HAVE_REGEX)
+	include_directories(${CMAKE_SOURCE_DIR}/compat/regex)
+	list(APPEND compat_SOURCES compat/regex/regex.c )
+	add_compile_definitions(NO_REGEX NO_MBSUPPORT GAWK)
+endif()
+
+
+check_c_source_compiles("
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+int main(void)
+{
+	int val, mib[2];
+	size_t len;
+
+	mib[0] = CTL_HW;
+	mib[1] = 1;
+	len = sizeof(val);
+	return sysctl(mib, 2, &val, &len, NULL, 0) ? 1 : 0;
+}"
+HAVE_BSD_SYSCTL)
+if(HAVE_BSD_SYSCTL)
+	add_compile_definitions(HAVE_BSD_SYSCTL)
+endif()
+
+set(CMAKE_REQUIRED_LIBRARIES ${Iconv_LIBRARIES})
+set(CMAKE_REQUIRED_INCLUDES ${Iconv_INCLUDE_DIRS})
+
+check_c_source_compiles("
+#include <iconv.h>
+
+extern size_t iconv(iconv_t cd,
+		char **inbuf, size_t *inbytesleft,
+		char **outbuf, size_t *outbytesleft);
+
+int main(void)
+{
+	return 0;
+}"
+HAVE_NEW_ICONV)
+if(HAVE_NEW_ICONV)
+	set(HAVE_OLD_ICONV 0)
+else()
+	set(HAVE_OLD_ICONV 1)
+endif()
+
+check_c_source_runs("
+#include <iconv.h>
+#if ${HAVE_OLD_ICONV}
+typedef const char *iconv_ibp;
+#else
+typedef char *iconv_ibp;
+#endif
+
+int main(void)
+{
+	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;
+}"
+ICONV_DOESNOT_OMIT_BOM)
+if(NOT ICONV_DOESNOT_OMIT_BOM)
+	add_compile_definitions(ICONV_OMITS_BOM)
+endif()
+
+unset(CMAKE_REQUIRED_LIBRARIES)
+unset(CMAKE_REQUIRED_INCLUDES)
+
+
+#programs
+set(PROGRAMS_BUILT
+	git git-daemon git-http-backend git-sh-i18n--envsubst
+	git-shell)
+
+if(NOT CURL_FOUND)
+	list(APPEND excluded_progs git-http-fetch git-http-push)
+	add_compile_definitions(NO_CURL)
+	message(WARNING "git-http-push and git-http-fetch will not be built")
+else()
+	list(APPEND PROGRAMS_BUILT git-http-fetch git-http-push git-imap-send git-remote-http)
+	if(CURL_VERSION_STRING VERSION_GREATER_EQUAL 7.34.0)
+		add_compile_definitions(USE_CURL_FOR_IMAP_SEND)
+	endif()
+endif()
+
+if(NOT EXPAT_FOUND)
+	list(APPEND excluded_progs git-http-push)
+	add_compile_definitions(NO_EXPAT)
+else()
+	list(APPEND PROGRAMS_BUILT git-http-push)
+	if(EXPAT_VERSION_STRING VERSION_LESS_EQUAL 1.2)
+		add_compile_definitions(EXPAT_NEEDS_XMLPARSE_H)
+	endif()
+endif()
+
+list(REMOVE_DUPLICATES excluded_progs)
+list(REMOVE_DUPLICATES PROGRAMS_BUILT)
+
+
+foreach(p ${excluded_progs})
+	list(APPEND EXCLUSION_PROGS --exclude-program ${p} )
+endforeach()
+
+#for comparing null values
+list(APPEND EXCLUSION_PROGS empty)
+set(EXCLUSION_PROGS_CACHE ${EXCLUSION_PROGS} CACHE STRING "Programs not built" FORCE)
+
+if(NOT EXISTS ${CMAKE_BINARY_DIR}/command-list.h OR NOT EXCLUSION_PROGS_CACHE STREQUAL EXCLUSION_PROGS)
+	list(REMOVE_ITEM EXCLUSION_PROGS empty)
+	message("Generating command-list.h")
+	execute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/generate-cmdlist.sh ${EXCLUSION_PROGS} command-list.txt
+			WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+			OUTPUT_FILE ${CMAKE_BINARY_DIR}/command-list.h)
+endif()
+
+if(NOT EXISTS ${CMAKE_BINARY_DIR}/config-list.h)
+	message("Generating config-list.h")
+	execute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/generate-configlist.sh
+			WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+			OUTPUT_FILE ${CMAKE_BINARY_DIR}/config-list.h)
+endif()
+
+include_directories(${CMAKE_BINARY_DIR})
+
+#build
+#libgit
+parse_makefile_for_sources(libgit_SOURCES "LIB_OBJS")
+
+list(TRANSFORM libgit_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
+list(TRANSFORM compat_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
+add_library(libgit ${libgit_SOURCES} ${compat_SOURCES})
+
+#libxdiff
+parse_makefile_for_sources(libxdiff_SOURCES "XDIFF_OBJS")
+
+list(TRANSFORM libxdiff_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
+add_library(xdiff STATIC ${libxdiff_SOURCES})
+
+if(WIN32)
+	if(NOT MSVC)#use windres when compiling with gcc and clang
+		add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/git.res
+				COMMAND ${WINDRES_EXE} -O coff -DMAJOR=${PROJECT_VERSION_MAJOR} -DMINOR=${PROJECT_VERSION_MINOR}
+					-DMICRO=${PROJECT_VERSION_PATCH} -DPATCHLEVEL=0 -DGIT_VERSION="\\\"${PROJECT_VERSION}.GIT\\\""
+					-i ${CMAKE_SOURCE_DIR}/git.rc -o ${CMAKE_BINARY_DIR}/git.res
+				WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+				VERBATIM)
+	else()#MSVC use rc
+		add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/git.res
+				COMMAND ${CMAKE_RC_COMPILER} /d MAJOR=${PROJECT_VERSION_MAJOR} /d MINOR=${PROJECT_VERSION_MINOR}
+					/d MICRO=${PROJECT_VERSION_PATCH} /d PATCHLEVEL=0 /d GIT_VERSION="${PROJECT_VERSION}.GIT"
+					/fo ${CMAKE_BINARY_DIR}/git.res ${CMAKE_SOURCE_DIR}/git.rc
+				WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+				VERBATIM)
+	endif()
+	add_custom_target(git-rc DEPENDS ${CMAKE_BINARY_DIR}/git.res)
+endif()
+
+#link all required libraries to common-main
+add_library(common-main OBJECT ${CMAKE_SOURCE_DIR}/common-main.c)
+
+target_link_libraries(common-main libgit xdiff ${ZLIB_LIBRARIES})
+if(Intl_FOUND)
+	target_link_libraries(common-main ${Intl_LIBRARIES})
+endif()
+if(Iconv_FOUND)
+	target_link_libraries(common-main ${Iconv_LIBRARIES})
+endif()
+if(WIN32)
+	target_link_libraries(common-main ws2_32 ntdll ${CMAKE_BINARY_DIR}/git.res)
+	add_dependencies(common-main git-rc)
+	if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+		target_link_options(common-main PUBLIC -municode -Wl,--nxcompat -Wl,--dynamicbase -Wl,--pic-executable,-e,mainCRTStartup)
+	elseif(CMAKE_C_COMPILER_ID STREQUAL "Clang")
+		target_link_options(common-main PUBLIC -municode -Wl,-nxcompat -Wl,-dynamicbase -Wl,-entry:wmainCRTStartup -Wl,invalidcontinue.obj)
+	elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
+		target_link_options(common-main PUBLIC /IGNORE:4217 /IGNORE:4049 /NOLOGO /ENTRY:wmainCRTStartup /SUBSYSTEM:CONSOLE invalidcontinue.obj)
+	endif()
+elseif(UNIX)
+	target_link_libraries(common-main pthread rt)
+endif()
+
+#git
+parse_makefile_for_sources(git_SOURCES "BUILTIN_OBJS")
+
+list(TRANSFORM git_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
+add_executable(git ${CMAKE_SOURCE_DIR}/git.c ${git_SOURCES})
+target_link_libraries(git common-main)
+
+add_executable(git-daemon ${CMAKE_SOURCE_DIR}/daemon.c)
+target_link_libraries(git-daemon common-main)
+
+add_executable(git-http-backend ${CMAKE_SOURCE_DIR}/http-backend.c)
+target_link_libraries(git-http-backend common-main)
+
+add_executable(git-sh-i18n--envsubst ${CMAKE_SOURCE_DIR}/sh-i18n--envsubst.c)
+target_link_libraries(git-sh-i18n--envsubst common-main)
+
+add_executable(git-shell ${CMAKE_SOURCE_DIR}/shell.c)
+target_link_libraries(git-shell common-main)
+
+if(CURL_FOUND)
+	add_library(http_obj OBJECT ${CMAKE_SOURCE_DIR}/http.c)
+
+	add_executable(git-imap-send ${CMAKE_SOURCE_DIR}/imap-send.c)
+	target_link_libraries(git-imap-send http_obj common-main ${CURL_LIBRARIES})
+
+	add_executable(git-http-fetch ${CMAKE_SOURCE_DIR}/http-walker.c ${CMAKE_SOURCE_DIR}/http-fetch.c)
+	target_link_libraries(git-http-fetch http_obj common-main ${CURL_LIBRARIES})
+
+	add_executable(git-remote-http ${CMAKE_SOURCE_DIR}/http-walker.c ${CMAKE_SOURCE_DIR}/remote-curl.c)
+	target_link_libraries(git-remote-http http_obj common-main ${CURL_LIBRARIES} )
+
+	if(EXPAT_FOUND)
+		add_executable(git-http-push ${CMAKE_SOURCE_DIR}/http-push.c)
+		target_link_libraries(git-http-push http_obj common-main ${CURL_LIBRARIES} ${EXPAT_LIBRARIES})
+	endif()
+endif()
+
+set(git_builtin_extra
+	cherry cherry-pick format-patch fsck-objects
+	init merge-subtree restore show
+	stage status switch whatchanged)
+
+#Creating hardlinks
+foreach(s ${git_SOURCES} ${git_builtin_extra})
+	string(REPLACE "${CMAKE_SOURCE_DIR}/builtin/" "" s ${s})
+	string(REPLACE ".c" "" s ${s})
+	file(APPEND ${CMAKE_BINARY_DIR}/CreateLinks.cmake "file(CREATE_LINK git${EXE_EXTENSION} git-${s}${EXE_EXTENSION})\n")
+	list(APPEND git_links ${CMAKE_BINARY_DIR}/git-${s}${EXE_EXTENSION})
+endforeach()
+
+if(CURL_FOUND)
+	set(remote_exes
+		git-remote-https git-remote-ftp git-remote-ftps)
+	foreach(s ${remote_exes})
+		file(APPEND ${CMAKE_BINARY_DIR}/CreateLinks.cmake "file(CREATE_LINK git-remote-http${EXE_EXTENSION} ${s}${EXE_EXTENSION})\n")
+		list(APPEND git_http_links ${CMAKE_BINARY_DIR}/${s}${EXE_EXTENSION})
+	endforeach()
+endif()
+
+add_custom_command(OUTPUT ${git_links} ${git_http_links}
+		COMMAND ${CMAKE_COMMAND} -P ${CMAKE_BINARY_DIR}/CreateLinks.cmake
+		DEPENDS git git-remote-http)
+add_custom_target(git-links ALL DEPENDS ${git_links} ${git_http_links})
+
+
+#creating required scripts
+set(SHELL_PATH /bin/sh)
+set(PERL_PATH /usr/bin/perl)
+set(LOCALEDIR ${FALLBACK_RUNTIME_PREFIX}/share/locale)
+set(GITWEBDIR ${FALLBACK_RUNTIME_PREFIX}/share/locale)
+set(INSTLIBDIR ${FALLBACK_RUNTIME_PREFIX}/share/perl5)
+
+#shell scripts
+parse_makefile_for_scripts(git_sh_scripts "SCRIPT_SH" ".sh")
+parse_makefile_for_scripts(git_shlib_scripts "SCRIPT_LIB" "")
+set(git_shell_scripts
+	${git_sh_scripts} ${git_shlib_scripts} git-instaweb)
+
+foreach(script ${git_shell_scripts})
+	file(STRINGS ${CMAKE_SOURCE_DIR}/${script}.sh content NEWLINE_CONSUME)
+	string(REPLACE "@SHELL_PATH@" "${SHELL_PATH}" content "${content}")
+	string(REPLACE "@@DIFF@@" "diff" content "${content}")
+	string(REPLACE "@LOCALEDIR@" "${LOCALEDIR}" content "${content}")
+	string(REPLACE "@GITWEBDIR@" "${GITWEBDIR}" content "${content}")
+	string(REPLACE "@@NO_CURL@@" "" content "${content}")
+	string(REPLACE "@@USE_GETTEXT_SCHEME@@" "" content "${content}")
+	string(REPLACE "# @@BROKEN_PATH_FIX@@" "" content "${content}")
+	string(REPLACE "@@PERL@@" "${PERL_PATH}" content "${content}")
+	string(REPLACE "@@SANE_TEXT_GREP@@" "-a" content "${content}")
+	string(REPLACE "@@PAGER_ENV@@" "LESS=FRX LV=-c" content "${content}")
+	file(WRITE ${CMAKE_BINARY_DIR}/${script} ${content})
+endforeach()
+
+#perl scripts
+parse_makefile_for_scripts(git_perl_scripts "SCRIPT_PERL" ".perl")
+
+#create perl header
+file(STRINGS ${CMAKE_SOURCE_DIR}/perl/header_templates/fixed_prefix.template.pl perl_header )
+string(REPLACE "@@PATHSEP@@" ":" perl_header "${perl_header}")
+string(REPLACE "@@INSTLIBDIR@@" "${INSTLIBDIR}" perl_header "${perl_header}")
+
+foreach(script ${git_perl_scripts})
+	file(STRINGS ${CMAKE_SOURCE_DIR}/${script}.perl content NEWLINE_CONSUME)
+	string(REPLACE "#!/usr/bin/perl" "#!/usr/bin/perl\n${perl_header}\n" content "${content}")
+	string(REPLACE "@@GIT_VERSION@@" "${PROJECT_VERSION}" content "${content}")
+	file(WRITE ${CMAKE_BINARY_DIR}/${script} ${content})
+endforeach()
+
+#python script
+file(STRINGS ${CMAKE_SOURCE_DIR}/git-p4.py content NEWLINE_CONSUME)
+string(REPLACE "#!/usr/bin/env python" "#!/usr/bin/python" content "${content}")
+file(WRITE ${CMAKE_BINARY_DIR}/git-p4 ${content})
+
+#perl modules
+file(GLOB_RECURSE perl_modules "${CMAKE_SOURCE_DIR}/perl/*.pm")
+
+foreach(pm ${perl_modules})
+	string(REPLACE "${CMAKE_SOURCE_DIR}/perl/" "" file_path ${pm})
+	file(STRINGS ${pm} content NEWLINE_CONSUME)
+	string(REPLACE "@@LOCALEDIR@@" "${LOCALEDIR}" content "${content}")
+	string(REPLACE "@@NO_PERL_CPAN_FALLBACKS@@" "" content "${content}")
+	file(WRITE ${CMAKE_BINARY_DIR}/perl/build/lib/${file_path} ${content})
+#test-lib.sh requires perl/build/lib to be the build directory of perl modules
+endforeach()
+
+
+#templates
+file(GLOB templates "${CMAKE_SOURCE_DIR}/templates/*")
+list(TRANSFORM templates REPLACE "${CMAKE_SOURCE_DIR}/templates/" "")
+list(REMOVE_ITEM templates ".gitignore")
+list(REMOVE_ITEM templates "Makefile")
+list(REMOVE_ITEM templates "blt")# Prevents an error when reconfiguring for in source builds
+
+list(REMOVE_ITEM templates "branches--")
+file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/templates/blt/branches) #create branches
+
+#templates have @.*@ replacement so use configure_file instead
+foreach(tm ${templates})
+	string(REPLACE "--" "/" blt_tm ${tm})
+	string(REPLACE "this" "" blt_tm ${blt_tm})# for this--
+	configure_file(${CMAKE_SOURCE_DIR}/templates/${tm} ${CMAKE_BINARY_DIR}/templates/blt/${blt_tm} @ONLY)
+endforeach()
+
+
+#translations
+if(MSGFMT_EXE)
+	file(GLOB po_files "${CMAKE_SOURCE_DIR}/po/*.po")
+	list(TRANSFORM po_files REPLACE "${CMAKE_SOURCE_DIR}/po/" "")
+	list(TRANSFORM po_files REPLACE ".po" "")
+	foreach(po ${po_files})
+		file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/po/build/locale/${po}/LC_MESSAGES)
+		add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/po/build/locale/${po}/LC_MESSAGES/git.mo
+				COMMAND ${MSGFMT_EXE} --check --statistics -o ${CMAKE_BINARY_DIR}/po/build/locale/${po}/LC_MESSAGES/git.mo ${CMAKE_SOURCE_DIR}/po/${po}.po)
+		list(APPEND po_gen ${CMAKE_BINARY_DIR}/po/build/locale/${po}/LC_MESSAGES/git.mo)
+	endforeach()
+	add_custom_target(po-gen ALL DEPENDS ${po_gen})
+endif()
+
+
+#to help with the install
+list(TRANSFORM git_shell_scripts PREPEND "${CMAKE_BINARY_DIR}/")
+list(TRANSFORM git_perl_scripts PREPEND "${CMAKE_BINARY_DIR}/")
+
+#install
+install(TARGETS git git-shell
+	RUNTIME DESTINATION bin)
+install(PROGRAMS ${CMAKE_BINARY_DIR}/git-cvsserver
+	DESTINATION bin)
+
+list(REMOVE_ITEM PROGRAMS_BUILT git git-shell)
+install(TARGETS ${PROGRAMS_BUILT}
+	RUNTIME DESTINATION libexec/git-core)
+
+set(bin_links
+	git-receive-pack git-upload-archive git-upload-pack)
+
+foreach(b ${bin_links})
+install(CODE "file(CREATE_LINK ${CMAKE_INSTALL_PREFIX}/bin/git${EXE_EXTENSION} ${CMAKE_INSTALL_PREFIX}/bin/${b}${EXE_EXTENSION})")
+endforeach()
+
+install(CODE "file(CREATE_LINK ${CMAKE_INSTALL_PREFIX}/bin/git${EXE_EXTENSION} ${CMAKE_INSTALL_PREFIX}/libexec/git-core/git${EXE_EXTENSION})")
+install(CODE "file(CREATE_LINK ${CMAKE_INSTALL_PREFIX}/bin/git-shell${EXE_EXTENSION} ${CMAKE_INSTALL_PREFIX}/libexec/git-core/git-shell${EXE_EXTENSION})")
+
+foreach(b ${git_links})
+	string(REPLACE "${CMAKE_BINARY_DIR}" "" b ${b})
+	install(CODE "file(CREATE_LINK ${CMAKE_INSTALL_PREFIX}/bin/git${EXE_EXTENSION} ${CMAKE_INSTALL_PREFIX}/libexec/git-core/${b}${EXE_EXTENSION})")
+endforeach()
+
+foreach(b ${git_http_links})
+	string(REPLACE "${CMAKE_BINARY_DIR}" "" b ${b})
+	install(CODE "file(CREATE_LINK  ${CMAKE_INSTALL_PREFIX}/libexec/git-core/git-remote-http${EXE_EXTENSION} ${CMAKE_INSTALL_PREFIX}/libexec/git-core/${b}${EXE_EXTENSION})")
+endforeach()
+
+install(PROGRAMS ${git_shell_scripts} ${git_perl_scripts} ${CMAKE_BINARY_DIR}/git-p4
+	DESTINATION libexec/git-core)
+
+install(DIRECTORY ${CMAKE_SOURCE_DIR}/mergetools DESTINATION libexec/git-core)
+install(DIRECTORY ${CMAKE_BINARY_DIR}/perl/build/lib/ DESTINATION share/perl5
+	FILES_MATCHING PATTERN "*.pm")
+install(DIRECTORY ${CMAKE_BINARY_DIR}/templates/blt/ DESTINATION share/git-core/templates)
+
+if(MSGFMT_EXE)
+	install(DIRECTORY ${CMAKE_BINARY_DIR}/po/build/locale DESTINATION share)
+endif()
+
+
+if(BUILD_TESTING)
+
+#tests-helpers
+add_executable(test-fake-ssh ${CMAKE_SOURCE_DIR}/t/helper/test-fake-ssh.c)
+target_link_libraries(test-fake-ssh common-main)
+
+#test-tool
+parse_makefile_for_sources(test-tool_SOURCES "TEST_BUILTINS_OBJS")
+
+list(TRANSFORM test-tool_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/t/helper/")
+add_executable(test-tool ${CMAKE_SOURCE_DIR}/t/helper/test-tool.c ${test-tool_SOURCES})
+target_link_libraries(test-tool common-main)
+
+set_target_properties(test-fake-ssh test-tool
+			PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/t/helper)
+
+if(MSVC)
+	set_target_properties(test-fake-ssh test-tool
+				PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/t/helper)
+	set_target_properties(test-fake-ssh test-tool
+				PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/t/helper)
+endif()
+
+#wrapper scripts
+set(wrapper_scripts
+	git git-upload-pack git-receive-pack git-upload-archive git-shell git-remote-ext)
+
+set(wrapper_test_scripts
+	test-fake-ssh test-tool)
+
+
+foreach(script ${wrapper_scripts})
+	file(STRINGS ${CMAKE_SOURCE_DIR}/wrap-for-bin.sh content NEWLINE_CONSUME)
+	string(REPLACE "@@BUILD_DIR@@" "${CMAKE_BINARY_DIR}" content "${content}")
+	string(REPLACE "@@PROG@@" "${script}${EXE_EXTENSION}" content "${content}")
+	file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/${script} ${content})
+endforeach()
+
+foreach(script ${wrapper_test_scripts})
+	file(STRINGS ${CMAKE_SOURCE_DIR}/wrap-for-bin.sh content NEWLINE_CONSUME)
+	string(REPLACE "@@BUILD_DIR@@" "${CMAKE_BINARY_DIR}" content "${content}")
+	string(REPLACE "@@PROG@@" "t/helper/${script}${EXE_EXTENSION}" content "${content}")
+	file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/${script} ${content})
+endforeach()
+
+file(STRINGS ${CMAKE_SOURCE_DIR}/wrap-for-bin.sh content NEWLINE_CONSUME)
+string(REPLACE "@@BUILD_DIR@@" "${CMAKE_BINARY_DIR}" content "${content}")
+string(REPLACE "@@PROG@@" "git-cvsserver" content "${content}")
+file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/git-cvsserver ${content})
+
+#options for configuring test options
+option(PERL_TESTS "Perform tests that use perl" ON)
+option(PYTHON_TESTS "Perform tests that use python" ON)
+
+#GIT-BUILD-OPTIONS
+set(TEST_SHELL_PATH ${SHELL_PATH})
+set(DIFF diff)
+set(PYTHON_PATH /usr/bin/python)
+set(TAR tar)
+set(NO_CURL )
+set(NO_EXPAT )
+set(USE_LIBPCRE1 )
+set(USE_LIBPCRE2 )
+set(NO_LIBPCRE1_JIT )
+set(NO_PERL )
+set(NO_PTHREADS )
+set(NO_PYTHON )
+set(PAGER_ENV "LESS=FRX LV=-c")
+set(DC_SHA1 YesPlease)
+set(RUNTIME_PREFIX true)
+set(NO_GETTEXT )
+
+if(NOT CURL_FOUND)
+	set(NO_CURL 1)
+endif()
+
+if(NOT EXPAT_FOUND)
+	set(NO_EXPAT 1)
+endif()
+
+if(NOT Intl_FOUND)
+	set(NO_GETTEXT 1)
+endif()
+
+if(NOT PERL_TESTS)
+	set(NO_PERL 1)
+endif()
+
+if(NOT PYTHON_TESTS)
+	set(NO_PYTHON 1)
+endif()
+
+file(WRITE ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "SHELL_PATH='${SHELL_PATH}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "TEST_SHELL_PATH='${TEST_SHELL_PATH}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "PERL_PATH='${PERL_PATH}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "DIFF='${DIFF}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "PYTHON_PATH='${PYTHON_PATH}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "TAR='${TAR}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_CURL='${NO_CURL}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_EXPAT='${NO_EXPAT}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "USE_LIBPCRE1='${USE_LIBPCRE1}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_LIBPCRE1_JIT='${NO_LIBPCRE1_JIT}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_PERL='${NO_PERL}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_PTHREADS='${NO_PTHREADS}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_UNIX_SOCKETS='${NO_UNIX_SOCKETS}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "PAGER_ENV='${PAGER_ENV}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "DC_SHA1='${DC_SHA1}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "X='${EXE_EXTENSION}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_GETTEXT='${NO_GETTEXT}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "RUNTIME_PREFIX='${RUNTIME_PREFIX}'\n")
+file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_PYTHON='${NO_PYTHON}'\n")
+
+#Make the tests work when building out of the source tree
+get_filename_component(CACHE_PATH ${CMAKE_CURRENT_LIST_DIR}/../../CMakeCache.txt ABSOLUTE)
+if(NOT ${CMAKE_BINARY_DIR}/CMakeCache.txt STREQUAL ${CACHE_PATH})
+	file(RELATIVE_PATH BUILD_DIR_RELATIVE ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR}/CMakeCache.txt)
+	string(REPLACE "/CMakeCache.txt" "" BUILD_DIR_RELATIVE ${BUILD_DIR_RELATIVE})
+	#Setting the build directory in test-lib.sh before running tests
+	file(WRITE ${CMAKE_BINARY_DIR}/CTestCustom.cmake
+		"file(STRINGS ${CMAKE_SOURCE_DIR}/t/test-lib.sh GIT_BUILD_DIR_REPL REGEX \"GIT_BUILD_DIR=(.*)\")\n"
+		"file(STRINGS ${CMAKE_SOURCE_DIR}/t/test-lib.sh content NEWLINE_CONSUME)\n"
+		"string(REPLACE \"\${GIT_BUILD_DIR_REPL}\" \"GIT_BUILD_DIR=\\\"$TEST_DIRECTORY\\\"/../${BUILD_DIR_RELATIVE}\" content \"\${content}\")\n"
+		"file(WRITE ${CMAKE_SOURCE_DIR}/t/test-lib.sh \${content})")
+	#misc copies
+	file(COPY ${CMAKE_SOURCE_DIR}/t/chainlint.sed DESTINATION ${CMAKE_BINARY_DIR}/t/)
+	file(COPY ${CMAKE_SOURCE_DIR}/po/is.po DESTINATION ${CMAKE_BINARY_DIR}/po/)
+	file(COPY ${CMAKE_SOURCE_DIR}/mergetools/tkdiff DESTINATION ${CMAKE_BINARY_DIR}/mergetools/)
+	file(COPY ${CMAKE_SOURCE_DIR}/contrib/completion/git-prompt.sh DESTINATION ${CMAKE_BINARY_DIR}/contrib/completion/)
+	file(COPY ${CMAKE_SOURCE_DIR}/contrib/completion/git-completion.bash DESTINATION ${CMAKE_BINARY_DIR}/contrib/completion/)
+endif()
+
+file(GLOB test_scipts "${CMAKE_SOURCE_DIR}/t/t[0-9]*.sh")
+
+#test
+foreach(tsh ${test_scipts})
+	add_test(NAME ${tsh}
+		COMMAND ${SH_EXE} ${tsh}
+		WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/t)
+endforeach()
+
+endif()#BUILD_TESTING
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index ee468ea..9147fba 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -39,6 +39,11 @@
 #     When set to "1", do not include "DWIM" suggestions in git-checkout
 #     and git-switch completion (e.g., completing "foo" when "origin/foo"
 #     exists).
+#
+#   GIT_COMPLETION_SHOW_ALL
+#
+#     When set to "1" suggest all options, including options which are
+#     typically hidden (e.g. '--allow-empty' for 'git commit').
 
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
@@ -411,10 +416,17 @@
 	local options
 	eval "options=\${$var-}"
 
+	local completion_helper
+	if [ "$GIT_COMPLETION_SHOW_ALL" = "1" ]; then
+		completion_helper="--git-completion-helper-all"
+	else
+		completion_helper="--git-completion-helper"
+	fi
+
 	if [ -z "$options" ]; then
 		# leading and trailing spaces are significant to make
 		# option removal work correctly.
-		options=" $incl $(__git ${cmd/_/ } --git-completion-helper) " || return
+		options=" $incl $(__git ${cmd/_/ } $completion_helper) " || return
 
 		for i in $excl; do
 			options="${options/ $i / }"
@@ -1712,8 +1724,8 @@
 }
 
 __git_mergetools_common="diffuse diffmerge ecmerge emerge kdiff3 meld opendiff
-			tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc
-			codecompare smerge
+			tkdiff vimdiff nvimdiff gvimdiff xxdiff araxis p4merge
+			bc codecompare smerge
 "
 
 _git_difftool ()
@@ -2907,6 +2919,14 @@
 		__gitcomp "$__git_diff_submodule_formats" "" "${cur##--submodule=}"
 		return
 		;;
+	--color-moved=*)
+		__gitcomp "$__git_color_moved_opts" "" "${cur##--color-moved=}"
+		return
+		;;
+	--color-moved-ws=*)
+		__gitcomp "$__git_color_moved_ws_opts" "" "${cur##--color-moved-ws=}"
+		return
+		;;
 	--*)
 		__gitcomp "--pretty= --format= --abbrev-commit --no-abbrev-commit
 			--oneline --show-signature --patch
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index 352deda..0db02fe 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -139,12 +139,12 @@
 
 -m <message>::
 --message=<message>::
-	This option is only valid for add, merge and pull (unsure).
+	This option is only valid for add, merge, pull, and split --rejoin.
 	Specify <message> as the commit message for the merge commit.
 
 
-OPTIONS FOR add, merge, push, pull
-----------------------------------
+OPTIONS FOR add, merge, and pull
+--------------------------------
 --squash::
 	This option is only valid for add, merge, and pull
 	commands.
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 53d7acc..57ff4b2 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -196,8 +196,7 @@
 		cd "$subtree_test_count" &&
 		git fetch ./"sub proj" master &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
-		check_equal "$(last_commit_message)" \
-			"Merge commit '\''$(git rev-parse FETCH_HEAD)'\'' into master"
+		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -274,8 +273,7 @@
 		cd "$test_count" &&
 		git fetch ./subproj master &&
 		git subtree merge --prefix=subdir/ FETCH_HEAD &&
-		check_equal "$(last_commit_message)" \
-			"Merge commit '\''$(git rev-parse FETCH_HEAD)'\'' into master"
+		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
diff --git a/contrib/svn-fe/.gitignore b/contrib/svn-fe/.gitignore
deleted file mode 100644
index 02a7791..0000000
--- a/contrib/svn-fe/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-/*.xml
-/*.1
-/*.html
-/svn-fe
diff --git a/contrib/svn-fe/Makefile b/contrib/svn-fe/Makefile
deleted file mode 100644
index e8651aa..0000000
--- a/contrib/svn-fe/Makefile
+++ /dev/null
@@ -1,105 +0,0 @@
-all:: svn-fe$X
-
-CC = cc
-RM = rm -f
-MV = mv
-
-CFLAGS = -g -O2 -Wall
-LDFLAGS =
-EXTLIBS = -lz
-
-include ../../config.mak.uname
--include ../../config.mak.autogen
--include ../../config.mak
-
-ifeq ($(uname_S),Darwin)
-	ifndef NO_FINK
-		ifeq ($(shell test -d /sw/lib && echo y),y)
-			CFLAGS += -I/sw/include
-			LDFLAGS += -L/sw/lib
-		endif
-	endif
-	ifndef NO_DARWIN_PORTS
-		ifeq ($(shell test -d /opt/local/lib && echo y),y)
-			CFLAGS += -I/opt/local/include
-			LDFLAGS += -L/opt/local/lib
-		endif
-	endif
-endif
-
-ifndef NO_OPENSSL
-	EXTLIBS += -lssl
-	ifdef NEEDS_CRYPTO_WITH_SSL
-		EXTLIBS += -lcrypto
-	endif
-endif
-
-ifndef NO_PTHREADS
-	CFLAGS += $(PTHREADS_CFLAGS)
-	EXTLIBS += $(PTHREAD_LIBS)
-endif
-
-ifdef HAVE_CLOCK_GETTIME
-	CFLAGS += -DHAVE_CLOCK_GETTIME
-	EXTLIBS += -lrt
-endif
-
-ifdef NEEDS_LIBICONV
-	EXTLIBS += -liconv
-endif
-
-GIT_LIB = ../../libgit.a
-VCSSVN_LIB = ../../vcs-svn/lib.a
-XDIFF_LIB = ../../xdiff/lib.a
-
-LIBS = $(VCSSVN_LIB) $(GIT_LIB) $(XDIFF_LIB)
-
-QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
-QUIET_SUBDIR1 =
-
-ifneq ($(findstring $(MAKEFLAGS),w),w)
-PRINT_DIR = --no-print-directory
-else # "make -w"
-NO_SUBDIR = :
-endif
-
-ifneq ($(findstring $(MAKEFLAGS),s),s)
-ifndef V
-	QUIET_CC      = @echo '   ' CC $@;
-	QUIET_LINK    = @echo '   ' LINK $@;
-	QUIET_SUBDIR0 = +@subdir=
-	QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \
-	                $(MAKE) $(PRINT_DIR) -C $$subdir
-endif
-endif
-
-svn-fe$X: svn-fe.o $(VCSSVN_LIB) $(XDIFF_LIB) $(GIT_LIB)
-	$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(EXTLIBS) -o $@ svn-fe.o $(LIBS)
-
-svn-fe.o: svn-fe.c ../../vcs-svn/svndump.h
-	$(QUIET_CC)$(CC) $(CFLAGS) -I../../vcs-svn -o $*.o -c $<
-
-svn-fe.html: svn-fe.txt
-	$(QUIET_SUBDIR0)../../Documentation $(QUIET_SUBDIR1) \
-		MAN_TXT=../contrib/svn-fe/svn-fe.txt \
-		../contrib/svn-fe/$@
-
-svn-fe.1: svn-fe.txt
-	$(QUIET_SUBDIR0)../../Documentation $(QUIET_SUBDIR1) \
-		MAN_TXT=../contrib/svn-fe/svn-fe.txt \
-		../contrib/svn-fe/$@
-	$(MV) ../../Documentation/svn-fe.1 .
-
-../../vcs-svn/lib.a: FORCE
-	$(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) vcs-svn/lib.a
-
-../../xdiff/lib.a: FORCE
-	$(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) xdiff/lib.a
-
-../../libgit.a: FORCE
-	$(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) libgit.a
-
-clean:
-	$(RM) svn-fe$X svn-fe.o svn-fe.html svn-fe.xml svn-fe.1
-
-.PHONY: all clean FORCE
diff --git a/contrib/svn-fe/svn-fe.c b/contrib/svn-fe/svn-fe.c
deleted file mode 100644
index f363505..0000000
--- a/contrib/svn-fe/svn-fe.c
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * This file is in the public domain.
- * You may freely use, modify, distribute, and relicense it.
- */
-
-#include <stdlib.h>
-#include "svndump.h"
-
-int main(int argc, char **argv)
-{
-	if (svndump_init(NULL))
-		return 1;
-	svndump_read((argc > 1) ? argv[1] : NULL, "refs/heads/master",
-			"refs/notes/svn/revs");
-	svndump_deinit();
-	svndump_reset();
-	return 0;
-}
diff --git a/contrib/svn-fe/svn-fe.txt b/contrib/svn-fe/svn-fe.txt
deleted file mode 100644
index 19333fc..0000000
--- a/contrib/svn-fe/svn-fe.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-svn-fe(1)
-=========
-
-NAME
-----
-svn-fe - convert an SVN "dumpfile" to a fast-import stream
-
-SYNOPSIS
---------
-[verse]
-mkfifo backchannel &&
-svnadmin dump --deltas REPO |
-	svn-fe [url] 3<backchannel |
-	git fast-import --cat-blob-fd=3 3>backchannel
-
-DESCRIPTION
------------
-
-Converts a Subversion dumpfile into input suitable for
-git-fast-import(1) and similar importers. REPO is a path to a
-Subversion repository mirrored on the local disk. Remote Subversion
-repositories can be mirrored on local disk using the `svnsync`
-command.
-
-Note: this tool is very young.  The details of its commandline
-interface may change in backward incompatible ways.
-
-INPUT FORMAT
-------------
-Subversion's repository dump format is documented in full in
-`notes/dump-load-format.txt` from the Subversion source tree.
-Files in this format can be generated using the 'svnadmin dump' or
-'svk admin dump' command.
-
-OUTPUT FORMAT
--------------
-The fast-import format is documented by the git-fast-import(1)
-manual page.
-
-NOTES
------
-Subversion dumps do not record a separate author and committer for
-each revision, nor do they record a separate display name and email
-address for each author.  Like git-svn(1), 'svn-fe' will use the name
-
----------
-user <user@UUID>
----------
-
-as committer, where 'user' is the value of the `svn:author` property
-and 'UUID' the repository's identifier.
-
-To support incremental imports, 'svn-fe' puts a `git-svn-id` line at
-the end of each commit log message if passed a URL on the command
-line.  This line has the form `git-svn-id: URL@REVNO UUID`.
-
-The resulting repository will generally require further processing
-to put each project in its own repository and to separate the history
-of each branch.  The 'git filter-repo --subdirectory-filter' command
-may be useful for this purpose.
-
-BUGS
-----
-Empty directories and unknown properties are silently discarded.
-
-The exit status does not reflect whether an error was detected.
-
-SEE ALSO
---------
-git-svn(1), svn2git(1), svk(1), git-filter-repo(1), git-fast-import(1),
-https://svn.apache.org/repos/asf/subversion/trunk/notes/dump-load-format.txt
diff --git a/contrib/svn-fe/svnrdump_sim.py b/contrib/svn-fe/svnrdump_sim.py
deleted file mode 100755
index 8a3cee6..0000000
--- a/contrib/svn-fe/svnrdump_sim.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python
-"""
-Simulates svnrdump by replaying an existing dump from a file, taking care
-of the specified revision range.
-To simulate incremental imports the environment variable SVNRMAX can be set
-to the highest revision that should be available.
-"""
-import sys
-import os
-
-if sys.hexversion < 0x02040000:
-    # The limiter is the ValueError() calls. This may be too conservative
-    sys.stderr.write("svnrdump-sim.py: requires Python 2.4 or later.\n")
-    sys.exit(1)
-
-
-def getrevlimit():
-    var = 'SVNRMAX'
-    if var in os.environ:
-        return os.environ[var]
-    return None
-
-
-def writedump(url, lower, upper):
-    if url.startswith('sim://'):
-        filename = url[6:]
-        if filename[-1] == '/':
-            filename = filename[:-1]  # remove terminating slash
-    else:
-        raise ValueError('sim:// url required')
-    f = open(filename, 'r')
-    state = 'header'
-    wroterev = False
-    while(True):
-        l = f.readline()
-        if l == '':
-            break
-        if state == 'header' and l.startswith('Revision-number: '):
-            state = 'prefix'
-        if state == 'prefix' and l == 'Revision-number: %s\n' % lower:
-            state = 'selection'
-        if not upper == 'HEAD' and state == 'selection' and \
-                l == 'Revision-number: %s\n' % upper:
-            break
-
-        if state == 'header' or state == 'selection':
-            if state == 'selection':
-                wroterev = True
-            sys.stdout.write(l)
-    return wroterev
-
-if __name__ == "__main__":
-    if not (len(sys.argv) in (3, 4, 5)):
-        print("usage: %s dump URL -rLOWER:UPPER")
-        sys.exit(1)
-    if not sys.argv[1] == 'dump':
-        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':
-        r = sys.argv[3][2:].lstrip().split(':')
-    if not getrevlimit() is None:
-        r[1] = getrevlimit()
-    if writedump(url, r[0], r[1]):
-        ret = 0
-    else:
-        ret = 1
-    sys.exit(ret)
diff --git a/convert.c b/convert.c
index 5724498..8e6c292 100644
--- a/convert.c
+++ b/convert.c
@@ -638,7 +638,6 @@
 	struct child_process child_process = CHILD_PROCESS_INIT;
 	struct filter_params *params = (struct filter_params *)data;
 	int write_err, status;
-	const char *argv[] = { NULL, NULL };
 
 	/* apply % substitution to cmd */
 	struct strbuf cmd = STRBUF_INIT;
@@ -656,9 +655,7 @@
 	strbuf_expand(&cmd, params->cmd, strbuf_expand_dict_cb, &dict);
 	strbuf_release(&path);
 
-	argv[0] = cmd.buf;
-
-	child_process.argv = argv;
+	strvec_push(&child_process.args, cmd.buf);
 	child_process.use_shell = 1;
 	child_process.in = -1;
 	child_process.out = out;
diff --git a/credential.c b/credential.c
index d8d226b..efc29dc 100644
--- a/credential.c
+++ b/credential.c
@@ -274,11 +274,9 @@
 				 int want_output)
 {
 	struct child_process helper = CHILD_PROCESS_INIT;
-	const char *argv[] = { NULL, NULL };
 	FILE *fp;
 
-	argv[0] = cmd;
-	helper.argv = argv;
+	strvec_push(&helper.args, cmd);
 	helper.use_shell = 1;
 	helper.in = -1;
 	if (want_output)
diff --git a/daemon.c b/daemon.c
index fd669ed..2ab7ea8 100644
--- a/daemon.c
+++ b/daemon.c
@@ -296,7 +296,7 @@
 	return NULL;		/* Fallthrough. Deny by default */
 }
 
-typedef int (*daemon_service_fn)(const struct argv_array *env);
+typedef int (*daemon_service_fn)(const struct strvec *env);
 struct daemon_service {
 	const char *name;
 	const char *config_name;
@@ -377,7 +377,7 @@
 }
 
 static int run_service(const char *dir, struct daemon_service *service,
-		       struct hostinfo *hi, const struct argv_array *env)
+		       struct hostinfo *hi, const struct strvec *env)
 {
 	const char *path;
 	int enabled = service->enabled;
@@ -462,7 +462,7 @@
 
 static int run_service_command(struct child_process *cld)
 {
-	argv_array_push(&cld->args, ".");
+	strvec_push(&cld->args, ".");
 	cld->git_cmd = 1;
 	cld->err = -1;
 	if (start_command(cld))
@@ -476,33 +476,33 @@
 	return finish_command(cld);
 }
 
-static int upload_pack(const struct argv_array *env)
+static int upload_pack(const struct strvec *env)
 {
 	struct child_process cld = CHILD_PROCESS_INIT;
-	argv_array_pushl(&cld.args, "upload-pack", "--strict", NULL);
-	argv_array_pushf(&cld.args, "--timeout=%u", timeout);
+	strvec_pushl(&cld.args, "upload-pack", "--strict", NULL);
+	strvec_pushf(&cld.args, "--timeout=%u", timeout);
 
-	argv_array_pushv(&cld.env_array, env->argv);
+	strvec_pushv(&cld.env_array, env->v);
 
 	return run_service_command(&cld);
 }
 
-static int upload_archive(const struct argv_array *env)
+static int upload_archive(const struct strvec *env)
 {
 	struct child_process cld = CHILD_PROCESS_INIT;
-	argv_array_push(&cld.args, "upload-archive");
+	strvec_push(&cld.args, "upload-archive");
 
-	argv_array_pushv(&cld.env_array, env->argv);
+	strvec_pushv(&cld.env_array, env->v);
 
 	return run_service_command(&cld);
 }
 
-static int receive_pack(const struct argv_array *env)
+static int receive_pack(const struct strvec *env)
 {
 	struct child_process cld = CHILD_PROCESS_INIT;
-	argv_array_push(&cld.args, "receive-pack");
+	strvec_push(&cld.args, "receive-pack");
 
-	argv_array_pushv(&cld.env_array, env->argv);
+	strvec_pushv(&cld.env_array, env->v);
 
 	return run_service_command(&cld);
 }
@@ -633,7 +633,7 @@
 	return extra_args;
 }
 
-static void parse_extra_args(struct hostinfo *hi, struct argv_array *env,
+static void parse_extra_args(struct hostinfo *hi, struct strvec *env,
 			     char *extra_args, int buflen)
 {
 	const char *end = extra_args + buflen;
@@ -664,8 +664,8 @@
 
 	if (git_protocol.len > 0) {
 		loginfo("Extended attribute \"protocol\": %s", git_protocol.buf);
-		argv_array_pushf(env, GIT_PROTOCOL_ENVIRONMENT "=%s",
-				 git_protocol.buf);
+		strvec_pushf(env, GIT_PROTOCOL_ENVIRONMENT "=%s",
+			     git_protocol.buf);
 	}
 	strbuf_release(&git_protocol);
 }
@@ -761,7 +761,7 @@
 	int pktlen, len, i;
 	char *addr = getenv("REMOTE_ADDR"), *port = getenv("REMOTE_PORT");
 	struct hostinfo hi;
-	struct argv_array env = ARGV_ARRAY_INIT;
+	struct strvec env = STRVEC_INIT;
 
 	hostinfo_init(&hi);
 
@@ -794,13 +794,13 @@
 			 */
 			int rc = run_service(arg, s, &hi, &env);
 			hostinfo_clear(&hi);
-			argv_array_clear(&env);
+			strvec_clear(&env);
 			return rc;
 		}
 	}
 
 	hostinfo_clear(&hi);
-	argv_array_clear(&env);
+	strvec_clear(&env);
 	logerror("Protocol error: '%s'", line);
 	return -1;
 }
@@ -893,7 +893,7 @@
 			cradle = &blanket->next;
 }
 
-static struct argv_array cld_argv = ARGV_ARRAY_INIT;
+static struct strvec cld_argv = STRVEC_INIT;
 static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
 {
 	struct child_process cld = CHILD_PROCESS_INIT;
@@ -913,21 +913,21 @@
 		char buf[128] = "";
 		struct sockaddr_in *sin_addr = (void *) addr;
 		inet_ntop(addr->sa_family, &sin_addr->sin_addr, buf, sizeof(buf));
-		argv_array_pushf(&cld.env_array, "REMOTE_ADDR=%s", buf);
-		argv_array_pushf(&cld.env_array, "REMOTE_PORT=%d",
-				 ntohs(sin_addr->sin_port));
+		strvec_pushf(&cld.env_array, "REMOTE_ADDR=%s", buf);
+		strvec_pushf(&cld.env_array, "REMOTE_PORT=%d",
+			     ntohs(sin_addr->sin_port));
 #ifndef NO_IPV6
 	} else if (addr->sa_family == AF_INET6) {
 		char buf[128] = "";
 		struct sockaddr_in6 *sin6_addr = (void *) addr;
 		inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(buf));
-		argv_array_pushf(&cld.env_array, "REMOTE_ADDR=[%s]", buf);
-		argv_array_pushf(&cld.env_array, "REMOTE_PORT=%d",
-				 ntohs(sin6_addr->sin6_port));
+		strvec_pushf(&cld.env_array, "REMOTE_ADDR=[%s]", buf);
+		strvec_pushf(&cld.env_array, "REMOTE_PORT=%d",
+			     ntohs(sin6_addr->sin6_port));
 #endif
 	}
 
-	cld.argv = cld_argv.argv;
+	cld.argv = cld_argv.v;
 	cld.in = incoming;
 	cld.out = dup(incoming);
 
@@ -1476,10 +1476,10 @@
 		write_file(pid_file, "%"PRIuMAX, (uintmax_t) getpid());
 
 	/* prepare argv for serving-processes */
-	argv_array_push(&cld_argv, argv[0]); /* git-daemon */
-	argv_array_push(&cld_argv, "--serve");
+	strvec_push(&cld_argv, argv[0]); /* git-daemon */
+	strvec_push(&cld_argv, "--serve");
 	for (i = 1; i < argc; ++i)
-		argv_array_push(&cld_argv, argv[i]);
+		strvec_push(&cld_argv, argv[i]);
 
 	return serve(&listen_addr, listen_port, cred);
 }
diff --git a/diff-lib.c b/diff-lib.c
index 25fd2de..5d5d3da 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -219,7 +219,8 @@
 				continue;
 			} else if (revs->diffopt.ita_invisible_in_index &&
 				   ce_intent_to_add(ce)) {
-				diff_addremove(&revs->diffopt, '+', ce->ce_mode,
+				newmode = ce_mode_from_stat(ce, st.st_mode);
+				diff_addremove(&revs->diffopt, '+', newmode,
 					       &null_oid, 0, ce->name, 0);
 				continue;
 			}
@@ -404,14 +405,8 @@
 	/* if the entry is not checked out, don't examine work tree */
 	cached = o->index_only ||
 		(idx && ((idx->ce_flags & CE_VALID) || ce_skip_worktree(idx)));
-	/*
-	 * Backward compatibility wart - "diff-index -m" does
-	 * not mean "do not ignore merges", but "match_missing".
-	 *
-	 * But with the revision flag parsing, that's found in
-	 * "!revs->ignore_merges".
-	 */
-	match_missing = !revs->ignore_merges;
+
+	match_missing = revs->match_missing;
 
 	if (cached && idx && ce_stage(idx)) {
 		struct diff_filepair *pair;
diff --git a/diff.c b/diff.c
index d24aaa3..a5114fa 100644
--- a/diff.c
+++ b/diff.c
@@ -20,7 +20,7 @@
 #include "hashmap.h"
 #include "ll-merge.h"
 #include "string-list.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "graph.h"
 #include "packfile.h"
 #include "parse-options.h"
@@ -3153,16 +3153,19 @@
 	gather_dirstat(options, &dir, changed, "", 0);
 }
 
+static void free_diffstat_file(struct diffstat_file *f)
+{
+	free(f->print_name);
+	free(f->name);
+	free(f->from_name);
+	free(f);
+}
+
 void free_diffstat_info(struct diffstat_t *diffstat)
 {
 	int i;
-	for (i = 0; i < diffstat->nr; i++) {
-		struct diffstat_file *f = diffstat->files[i];
-		free(f->print_name);
-		free(f->name);
-		free(f->from_name);
-		free(f);
-	}
+	for (i = 0; i < diffstat->nr; i++)
+		free_diffstat_file(diffstat->files[i]);
 	free(diffstat->files);
 }
 
@@ -3429,7 +3432,7 @@
 	if (o->submodule_format == DIFF_SUBMODULE_LOG &&
 	    (!one->mode || S_ISGITLINK(one->mode)) &&
 	    (!two->mode || S_ISGITLINK(two->mode))) {
-		show_submodule_summary(o, one->path ? one->path : two->path,
+		show_submodule_diff_summary(o, one->path ? one->path : two->path,
 				&one->oid, &two->oid,
 				two->dirty_submodule);
 		return;
@@ -3718,6 +3721,27 @@
 		if (xdi_diff_outf(&mf1, &mf2, discard_hunk_line,
 				  diffstat_consume, diffstat, &xpp, &xecfg))
 			die("unable to generate diffstat for %s", one->path);
+
+		if (DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two)) {
+			struct diffstat_file *file =
+				diffstat->files[diffstat->nr - 1];
+			/*
+			 * Omit diffstats of modified files where nothing changed.
+			 * Even if !same_contents, this might be the case due to
+			 * ignoring whitespace changes, etc.
+			 *
+			 * But note that we special-case additions, deletions,
+			 * renames, and mode changes as adding an empty file,
+			 * for example is still of interest.
+			 */
+			if ((p->status == DIFF_STATUS_MODIFIED)
+				&& !file->added
+				&& !file->deleted
+				&& one->mode == two->mode) {
+				free_diffstat_file(file);
+				diffstat->nr--;
+			}
+		}
 	}
 
 	diff_free_filespec_data(one);
@@ -4192,14 +4216,14 @@
 }
 
 static void add_external_diff_name(struct repository *r,
-				   struct argv_array *argv,
+				   struct strvec *argv,
 				   const char *name,
 				   struct diff_filespec *df)
 {
 	struct diff_tempfile *temp = prepare_temp_file(r, name, df);
-	argv_array_push(argv, temp->name);
-	argv_array_push(argv, temp->hex);
-	argv_array_push(argv, temp->mode);
+	strvec_push(argv, temp->name);
+	strvec_push(argv, temp->hex);
+	strvec_push(argv, temp->mode);
 }
 
 /* An external diff command takes:
@@ -4216,12 +4240,12 @@
 			      const char *xfrm_msg,
 			      struct diff_options *o)
 {
-	struct argv_array argv = ARGV_ARRAY_INIT;
-	struct argv_array env = ARGV_ARRAY_INIT;
+	struct strvec argv = STRVEC_INIT;
+	struct strvec env = STRVEC_INIT;
 	struct diff_queue_struct *q = &diff_queued_diff;
 
-	argv_array_push(&argv, pgm);
-	argv_array_push(&argv, name);
+	strvec_push(&argv, pgm);
+	strvec_push(&argv, name);
 
 	if (one && two) {
 		add_external_diff_name(o->repo, &argv, name, one);
@@ -4229,22 +4253,22 @@
 			add_external_diff_name(o->repo, &argv, name, two);
 		else {
 			add_external_diff_name(o->repo, &argv, other, two);
-			argv_array_push(&argv, other);
-			argv_array_push(&argv, xfrm_msg);
+			strvec_push(&argv, other);
+			strvec_push(&argv, xfrm_msg);
 		}
 	}
 
-	argv_array_pushf(&env, "GIT_DIFF_PATH_COUNTER=%d", ++o->diff_path_counter);
-	argv_array_pushf(&env, "GIT_DIFF_PATH_TOTAL=%d", q->nr);
+	strvec_pushf(&env, "GIT_DIFF_PATH_COUNTER=%d", ++o->diff_path_counter);
+	strvec_pushf(&env, "GIT_DIFF_PATH_TOTAL=%d", q->nr);
 
 	diff_free_filespec_data(one);
 	diff_free_filespec_data(two);
-	if (run_command_v_opt_cd_env(argv.argv, RUN_USING_SHELL, NULL, env.argv))
+	if (run_command_v_opt_cd_env(argv.v, RUN_USING_SHELL, NULL, env.v))
 		die(_("external diff died, stopping at %s"), name);
 
 	remove_tempfile();
-	argv_array_clear(&argv);
-	argv_array_clear(&env);
+	strvec_clear(&argv);
+	strvec_clear(&env);
 }
 
 static int similarity_index(struct diff_filepair *p)
@@ -4319,7 +4343,10 @@
 	}
 	if (one && two && !oideq(&one->oid, &two->oid)) {
 		const unsigned hexsz = the_hash_algo->hexsz;
-		int abbrev = o->flags.full_index ? hexsz : DEFAULT_ABBREV;
+		int abbrev = o->abbrev ? o->abbrev : DEFAULT_ABBREV;
+
+		if (o->flags.full_index)
+			abbrev = hexsz;
 
 		if (o->flags.binary) {
 			mmfile_t mf;
@@ -6044,6 +6071,8 @@
 	struct patch_id_t *data = priv;
 	int new_len;
 
+	if (len > 12 && starts_with(line, "\\ "))
+		return;
 	new_len = remove_space(line, len);
 
 	the_hash_algo->update_fn(data->ctx, line, new_len);
diff --git a/diff.h b/diff.h
index 9443dc1..e0c0af6 100644
--- a/diff.h
+++ b/diff.h
@@ -431,11 +431,11 @@
 	struct combine_diff_path *p, const struct object_id *oid,
 	const struct object_id **parents_oid, int nparent,
 	struct strbuf *base, struct diff_options *opt);
-int diff_tree_oid(const struct object_id *old_oid,
-		  const struct object_id *new_oid,
-		  const char *base, struct diff_options *opt);
-int diff_root_tree_oid(const struct object_id *new_oid, const char *base,
-		       struct diff_options *opt);
+void diff_tree_oid(const struct object_id *old_oid,
+		   const struct object_id *new_oid,
+		   const char *base, struct diff_options *opt);
+void diff_root_tree_oid(const struct object_id *new_oid, const char *base,
+			struct diff_options *opt);
 
 struct combine_diff_path {
 	struct combine_diff_path *next;
diff --git a/dir.c b/dir.c
index 1045cc9..3018a65 100644
--- a/dir.c
+++ b/dir.c
@@ -54,6 +54,11 @@
 static int resolve_dtype(int dtype, struct index_state *istate,
 			 const char *path, int len);
 
+void dir_init(struct dir_struct *dir)
+{
+	memset(dir, 0, sizeof(*dir));
+}
+
 int count_slashes(const char *s)
 {
 	int cnt = 0;
@@ -916,6 +921,8 @@
 		free(pl->patterns[i]);
 	free(pl->patterns);
 	free(pl->filebuf);
+	hashmap_free_entries(&pl->recursive_hashmap, struct pattern_entry, ent);
+	hashmap_free_entries(&pl->parent_hashmap, struct pattern_entry, ent);
 
 	memset(pl, 0, sizeof(*pl));
 }
@@ -1792,9 +1799,12 @@
 		nested_repo = is_nonbare_repository_dir(&sb);
 		strbuf_release(&sb);
 	}
-	if (nested_repo)
-		return ((dir->flags & DIR_SKIP_NESTED_GIT) ? path_none :
-			(excluded ? path_excluded : path_untracked));
+	if (nested_repo) {
+		if ((dir->flags & DIR_SKIP_NESTED_GIT) ||
+		    (matches_how == MATCHED_RECURSIVELY_LEADING_PATHSPEC))
+			return path_none;
+		return excluded ? path_excluded : path_untracked;
+	}
 
 	if (!(dir->flags & DIR_SHOW_OTHER_DIRECTORIES)) {
 		if (excluded &&
@@ -2209,13 +2219,13 @@
 				       baselen, excluded, pathspec);
 	case DT_REG:
 	case DT_LNK:
-		if (excluded)
-			return path_excluded;
 		if (pathspec &&
 		    !match_pathspec(istate, pathspec, path->buf, path->len,
 				    0 /* prefix */, NULL /* seen */,
 				    0 /* is_dir */))
 			return path_none;
+		if (excluded)
+			return path_excluded;
 		return path_untracked;
 	}
 }
@@ -3009,10 +3019,10 @@
 }
 
 /*
- * Frees memory within dir which was allocated for exclude lists and
- * the exclude_stack.  Does not free dir itself.
+ * Frees memory within dir which was allocated, and resets fields for further
+ * use.  Does not free dir itself.
  */
-void clear_directory(struct dir_struct *dir)
+void dir_clear(struct dir_struct *dir)
 {
 	int i, j;
 	struct exclude_list_group *group;
@@ -3030,6 +3040,13 @@
 		free(group->pl);
 	}
 
+	for (i = 0; i < dir->ignored_nr; i++)
+		free(dir->ignored[i]);
+	for (i = 0; i < dir->nr; i++)
+		free(dir->entries[i]);
+	free(dir->ignored);
+	free(dir->entries);
+
 	stk = dir->exclude_stack;
 	while (stk) {
 		struct exclude_stack *prev = stk->prev;
@@ -3037,6 +3054,8 @@
 		stk = prev;
 	}
 	strbuf_release(&dir->basebuf);
+
+	dir_init(dir);
 }
 
 struct ondisk_untracked_cache {
diff --git a/dir.h b/dir.h
index 5855c06..a3c40de 100644
--- a/dir.h
+++ b/dir.h
@@ -19,24 +19,23 @@
  * CE_SKIP_WORKTREE marked. If you want to exclude files, make sure you have
  * loaded the index first.
  *
- * - Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0,
- * sizeof(dir))`.
+ * - Prepare `struct dir_struct dir` using `dir_init()` function.
  *
  * - To add single exclude pattern, call `add_pattern_list()` and then
  *   `add_pattern()`.
  *
  * - To add patterns from a file (e.g. `.git/info/exclude`), call
- *   `add_patterns_from_file()` , and/or set `dir.exclude_per_dir`.  A
- *   short-hand function `setup_standard_excludes()` can be used to set
- *   up the standard set of exclude settings.
+ *   `add_patterns_from_file()` , and/or set `dir.exclude_per_dir`.
  *
- * - Set options described in the Data Structure section above.
+ * - A short-hand function `setup_standard_excludes()` can be used to set
+ *   up the standard set of exclude settings, instead of manually calling
+ *   the add_pattern*() family of functions.
  *
- * - Call `read_directory()`.
+ * - Call `fill_directory()`.
  *
- * - Use `dir.entries[]`.
+ * - Use `dir.entries[]` and `dir.ignored[]`.
  *
- * - Call `clear_directory()` when none of the contained elements are no longer in use.
+ * - Call `dir_clear()` when the contained elements are no longer in use.
  *
  */
 
@@ -362,6 +361,8 @@
 int report_path_error(const char *ps_matched, const struct pathspec *pathspec);
 int within_depth(const char *name, int namelen, int depth, int max_depth);
 
+void dir_init(struct dir_struct *dir);
+
 int fill_directory(struct dir_struct *dir,
 		   struct index_state *istate,
 		   const struct pathspec *pathspec);
@@ -428,7 +429,7 @@
 void add_pattern(const char *string, const char *base,
 		 int baselen, struct pattern_list *pl, int srcpos);
 void clear_pattern_list(struct pattern_list *pl);
-void clear_directory(struct dir_struct *dir);
+void dir_clear(struct dir_struct *dir);
 
 int repo_file_exists(struct repository *repo, const char *path);
 int file_exists(const char *);
diff --git a/editor.c b/editor.c
index 91989ee..6303ae0 100644
--- a/editor.c
+++ b/editor.c
@@ -40,7 +40,7 @@
 	const char *editor = getenv("GIT_SEQUENCE_EDITOR");
 
 	if (!editor)
-		git_config_get_string_const("sequence.editor", &editor);
+		git_config_get_string_tmp("sequence.editor", &editor);
 	if (!editor)
 		editor = git_editor();
 
diff --git a/entry.c b/entry.c
index 449bd32..a0532f1 100644
--- a/entry.c
+++ b/entry.c
@@ -510,8 +510,6 @@
 			/* If it is a gitlink, leave it alone! */
 			if (S_ISGITLINK(ce->ce_mode))
 				return 0;
-			if (!state->force)
-				return error("%s is a directory", path.buf);
 			remove_subtree(&path);
 		} else if (unlink(path.buf))
 			return error_errno("unable to unlink old '%s'", path.buf);
diff --git a/environment.c b/environment.c
index aaca0e9..bb518c6 100644
--- a/environment.c
+++ b/environment.c
@@ -14,7 +14,7 @@
 #include "refs.h"
 #include "fmt-merge-msg.h"
 #include "commit.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "object-store.h"
 #include "chdir-notify.h"
 #include "shallow.h"
@@ -35,8 +35,8 @@
 int repository_format_worktree_config;
 const char *git_commit_encoding;
 const char *git_log_output_encoding;
-const char *apply_default_whitespace;
-const char *apply_default_ignorewhitespace;
+char *apply_default_whitespace;
+char *apply_default_ignorewhitespace;
 const char *git_attributes_file;
 const char *git_hooks_path;
 int zlib_compression_level = Z_BEST_SPEED;
@@ -156,15 +156,15 @@
  * Wrapper of getenv() that returns a strdup value. This value is kept
  * in argv to be freed later.
  */
-static const char *getenv_safe(struct argv_array *argv, const char *name)
+static const char *getenv_safe(struct strvec *argv, const char *name)
 {
 	const char *value = getenv(name);
 
 	if (!value)
 		return NULL;
 
-	argv_array_push(argv, value);
-	return argv->argv[argv->argc - 1];
+	strvec_push(argv, value);
+	return argv->v[argv->nr - 1];
 }
 
 void setup_git_env(const char *git_dir)
@@ -172,7 +172,7 @@
 	const char *shallow_file;
 	const char *replace_ref_base;
 	struct set_gitdir_args args = { NULL };
-	struct argv_array to_free = ARGV_ARRAY_INIT;
+	struct strvec to_free = STRVEC_INIT;
 
 	args.commondir = getenv_safe(&to_free, GIT_COMMON_DIR_ENVIRONMENT);
 	args.object_dir = getenv_safe(&to_free, DB_ENVIRONMENT);
@@ -180,7 +180,7 @@
 	args.index_file = getenv_safe(&to_free, INDEX_ENVIRONMENT);
 	args.alternate_db = getenv_safe(&to_free, ALTERNATE_DB_ENVIRONMENT);
 	repo_set_gitdir(the_repository, git_dir, &args);
-	argv_array_clear(&to_free);
+	strvec_clear(&to_free);
 
 	if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
 		read_replace_refs = 0;
diff --git a/exec-cmd.c b/exec-cmd.c
index 7deeab3..eeb2ee5 100644
--- a/exec-cmd.c
+++ b/exec-cmd.c
@@ -1,7 +1,7 @@
 #include "cache.h"
 #include "exec-cmd.h"
 #include "quote.h"
-#include "argv-array.h"
+#include "strvec.h"
 
 #if defined(RUNTIME_PREFIX)
 
@@ -320,26 +320,26 @@
 	strbuf_release(&new_path);
 }
 
-const char **prepare_git_cmd(struct argv_array *out, const char **argv)
+const char **prepare_git_cmd(struct strvec *out, const char **argv)
 {
-	argv_array_push(out, "git");
-	argv_array_pushv(out, argv);
-	return out->argv;
+	strvec_push(out, "git");
+	strvec_pushv(out, argv);
+	return out->v;
 }
 
 int execv_git_cmd(const char **argv)
 {
-	struct argv_array nargv = ARGV_ARRAY_INIT;
+	struct strvec nargv = STRVEC_INIT;
 
 	prepare_git_cmd(&nargv, argv);
-	trace_argv_printf(nargv.argv, "trace: exec:");
+	trace_argv_printf(nargv.v, "trace: exec:");
 
 	/* execvp() can only ever return if it fails */
-	sane_execvp("git", (char **)nargv.argv);
+	sane_execvp("git", (char **)nargv.v);
 
 	trace_printf("trace: exec failed: %s\n", strerror(errno));
 
-	argv_array_clear(&nargv);
+	strvec_clear(&nargv);
 	return -1;
 }
 
diff --git a/exec-cmd.h b/exec-cmd.h
index 8cd1df2..330b41d 100644
--- a/exec-cmd.h
+++ b/exec-cmd.h
@@ -1,13 +1,13 @@
 #ifndef GIT_EXEC_CMD_H
 #define GIT_EXEC_CMD_H
 
-struct argv_array;
+struct strvec;
 
 void git_set_exec_path(const char *exec_path);
 void git_resolve_executable_dir(const char *path);
 const char *git_exec_path(void);
 void setup_path(void);
-const char **prepare_git_cmd(struct argv_array *out, const char **argv);
+const char **prepare_git_cmd(struct strvec *out, const char **argv);
 int execv_git_cmd(const char **argv); /* NULL terminated */
 LAST_ARG_MUST_BE_NULL
 int execl_git_cmd(const char *cmd, ...);
diff --git a/fetch-negotiator.c b/fetch-negotiator.c
index 0a1357d..57ed578 100644
--- a/fetch-negotiator.c
+++ b/fetch-negotiator.c
@@ -2,6 +2,7 @@
 #include "fetch-negotiator.h"
 #include "negotiator/default.h"
 #include "negotiator/skipping.h"
+#include "negotiator/noop.h"
 #include "repository.h"
 
 void fetch_negotiator_init(struct repository *r,
@@ -13,6 +14,10 @@
 		skipping_negotiator_init(negotiator);
 		return;
 
+	case FETCH_NEGOTIATION_NOOP:
+		noop_negotiator_init(negotiator);
+		return;
+
 	case FETCH_NEGOTIATION_DEFAULT:
 	default:
 		default_negotiator_init(negotiator);
diff --git a/fetch-pack.c b/fetch-pack.c
index 80fb3bd..b10c432 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -108,24 +108,48 @@
 		cb(negotiator, cache.items[i]);
 }
 
+static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
+					       int mark_tags_complete)
+{
+	enum object_type type;
+	struct object_info info = { .typep = &type };
+
+	while (1) {
+		if (oid_object_info_extended(the_repository, oid, &info,
+					     OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK))
+			return NULL;
+		if (type == OBJ_TAG) {
+			struct tag *tag = (struct tag *)
+				parse_object(the_repository, oid);
+
+			if (!tag->tagged)
+				return NULL;
+			if (mark_tags_complete)
+				tag->object.flags |= COMPLETE;
+			oid = &tag->tagged->oid;
+		} else {
+			break;
+		}
+	}
+	if (type == OBJ_COMMIT)
+		return (struct commit *) parse_object(the_repository, oid);
+	return NULL;
+}
+
 static int rev_list_insert_ref(struct fetch_negotiator *negotiator,
-			       const char *refname,
 			       const struct object_id *oid)
 {
-	struct object *o = deref_tag(the_repository,
-				     parse_object(the_repository, oid),
-				     refname, 0);
+	struct commit *c = deref_without_lazy_fetch(oid, 0);
 
-	if (o && o->type == OBJ_COMMIT)
-		negotiator->add_tip(negotiator, (struct commit *)o);
-
+	if (c)
+		negotiator->add_tip(negotiator, c);
 	return 0;
 }
 
 static int rev_list_insert_ref_oid(const char *refname, const struct object_id *oid,
 				   int flag, void *cb_data)
 {
-	return rev_list_insert_ref(cb_data, refname, oid);
+	return rev_list_insert_ref(cb_data, oid);
 }
 
 enum ack_type {
@@ -201,7 +225,7 @@
 static void insert_one_alternate_object(struct fetch_negotiator *negotiator,
 					struct object *obj)
 {
-	rev_list_insert_ref(negotiator, NULL, &obj->oid);
+	rev_list_insert_ref(negotiator, &obj->oid);
 }
 
 #define INITIAL_FLUSH 16
@@ -230,13 +254,12 @@
 	int i;
 
 	if (!negotiation_tips) {
-		for_each_ref(rev_list_insert_ref_oid, negotiator);
+		for_each_rawref(rev_list_insert_ref_oid, negotiator);
 		return;
 	}
 
 	for (i = 0; i < negotiation_tips->nr; i++)
-		rev_list_insert_ref(negotiator, NULL,
-				    &negotiation_tips->oid[i]);
+		rev_list_insert_ref(negotiator, &negotiation_tips->oid[i]);
 	return;
 }
 
@@ -262,10 +285,8 @@
 			   PACKET_READ_CHOMP_NEWLINE |
 			   PACKET_READ_DIE_ON_ERR_PACKET);
 
-	if (!args->no_dependents) {
-		mark_tips(negotiator, args->negotiation_tips);
-		for_each_cached_alternate(negotiator, insert_one_alternate_object);
-	}
+	mark_tips(negotiator, args->negotiation_tips);
+	for_each_cached_alternate(negotiator, insert_one_alternate_object);
 
 	fetching = 0;
 	for ( ; refs ; refs = refs->next) {
@@ -282,12 +303,8 @@
 		 * We use lookup_object here because we are only
 		 * interested in the case we *know* the object is
 		 * reachable and we have already scanned it.
-		 *
-		 * Do this only if args->no_dependents is false (if it is true,
-		 * we cannot trust the object flags).
 		 */
-		if (!args->no_dependents &&
-		    ((o = lookup_object(the_repository, remote)) != NULL) &&
+		if (((o = lookup_object(the_repository, remote)) != NULL) &&
 				(o->flags & COMPLETE)) {
 			continue;
 		}
@@ -387,8 +404,6 @@
 	trace2_region_enter("fetch-pack", "negotiation_v0_v1", the_repository);
 	flushes = 0;
 	retval = -1;
-	if (args->no_dependents)
-		goto done;
 	while ((oid = negotiator->next(negotiator))) {
 		packet_buf_write(&req_buf, "have %s\n", oid_to_hex(oid));
 		print_verbose(args, "have %s", oid_to_hex(oid));
@@ -503,21 +518,11 @@
 
 static int mark_complete(const struct object_id *oid)
 {
-	struct object *o = parse_object(the_repository, oid);
+	struct commit *commit = deref_without_lazy_fetch(oid, 1);
 
-	while (o && o->type == OBJ_TAG) {
-		struct tag *t = (struct tag *) o;
-		if (!t->tagged)
-			break; /* broken repository */
-		o->flags |= COMPLETE;
-		o = parse_object(the_repository, &t->tagged->oid);
-	}
-	if (o && o->type == OBJ_COMMIT) {
-		struct commit *commit = (struct commit *)o;
-		if (!(commit->object.flags & COMPLETE)) {
-			commit->object.flags |= COMPLETE;
-			commit_list_insert(commit, &complete);
-		}
+	if (commit && !(commit->object.flags & COMPLETE)) {
+		commit->object.flags |= COMPLETE;
+		commit_list_insert(commit, &complete);
 	}
 	return 0;
 }
@@ -653,9 +658,7 @@
 
 /*
  * Mark recent commits available locally and reachable from a local ref as
- * COMPLETE. If args->no_dependents is false, also mark COMPLETE remote refs as
- * COMMON_REF (otherwise, we are not planning to participate in negotiation, and
- * thus do not need COMMON_REF marks).
+ * COMPLETE.
  *
  * The cutoff time for recency is determined by this heuristic: it is the
  * earliest commit time of the objects in refs that are commits and that we know
@@ -702,7 +705,7 @@
 	 */
 	trace2_region_enter("fetch-pack", "mark_complete_local_refs", NULL);
 	if (!args->deepen) {
-		for_each_ref(mark_complete_oid, NULL);
+		for_each_rawref(mark_complete_oid, NULL);
 		for_each_cached_alternate(NULL, mark_alternate_complete);
 		commit_list_sort_by_date(&complete);
 		if (cutoff)
@@ -716,16 +719,12 @@
 	 */
 	trace2_region_enter("fetch-pack", "mark_common_remote_refs", NULL);
 	for (ref = *refs; ref; ref = ref->next) {
-		struct object *o = deref_tag(the_repository,
-					     lookup_object(the_repository,
-					     &ref->old_oid),
-					     NULL, 0);
+		struct commit *c = deref_without_lazy_fetch(&ref->old_oid, 0);
 
-		if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE))
+		if (!c || !(c->object.flags & COMPLETE))
 			continue;
 
-		negotiator->known_common(negotiator,
-					 (struct commit *)o);
+		negotiator->known_common(negotiator, c);
 	}
 	trace2_region_leave("fetch-pack", "mark_common_remote_refs", NULL);
 
@@ -794,6 +793,10 @@
 	strbuf_release(&promisor_name);
 }
 
+/*
+ * Pass 1 as "only_packfile" if the pack received is the only pack in this
+ * fetch request (that is, if there were no packfile URIs provided).
+ */
 static int get_pack(struct fetch_pack_args *args,
 		    int xd[2], struct string_list *pack_lockfiles,
 		    int only_packfile,
@@ -835,30 +838,30 @@
 	}
 
 	if (alternate_shallow_file) {
-		argv_array_push(&cmd.args, "--shallow-file");
-		argv_array_push(&cmd.args, alternate_shallow_file);
+		strvec_push(&cmd.args, "--shallow-file");
+		strvec_push(&cmd.args, alternate_shallow_file);
 	}
 
 	if (do_keep || args->from_promisor) {
 		if (pack_lockfiles)
 			cmd.out = -1;
 		cmd_name = "index-pack";
-		argv_array_push(&cmd.args, cmd_name);
-		argv_array_push(&cmd.args, "--stdin");
+		strvec_push(&cmd.args, cmd_name);
+		strvec_push(&cmd.args, "--stdin");
 		if (!args->quiet && !args->no_progress)
-			argv_array_push(&cmd.args, "-v");
+			strvec_push(&cmd.args, "-v");
 		if (args->use_thin_pack)
-			argv_array_push(&cmd.args, "--fix-thin");
+			strvec_push(&cmd.args, "--fix-thin");
 		if (do_keep && (args->lock_pack || unpack_limit)) {
 			char hostname[HOST_NAME_MAX + 1];
 			if (xgethostname(hostname, sizeof(hostname)))
 				xsnprintf(hostname, sizeof(hostname), "localhost");
-			argv_array_pushf(&cmd.args,
-					"--keep=fetch-pack %"PRIuMAX " on %s",
-					(uintmax_t)getpid(), hostname);
+			strvec_pushf(&cmd.args,
+				     "--keep=fetch-pack %"PRIuMAX " on %s",
+				     (uintmax_t)getpid(), hostname);
 		}
 		if (only_packfile && args->check_self_contained_and_connected)
-			argv_array_push(&cmd.args, "--check-self-contained-and-connected");
+			strvec_push(&cmd.args, "--check-self-contained-and-connected");
 		else
 			/*
 			 * We cannot perform any connectivity checks because
@@ -866,42 +869,45 @@
 			 * have this responsibility.
 			 */
 			args->check_self_contained_and_connected = 0;
-		/*
-		 * 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_lockfiles) && args->from_promisor)
-			argv_array_push(&cmd.args, "--promisor");
+
+		if (args->from_promisor)
+			/*
+			 * write_promisor_file() may be called afterwards but
+			 * we still need index-pack to know that this is a
+			 * promisor pack. For example, if transfer.fsckobjects
+			 * is true, index-pack needs to know that .gitmodules
+			 * is a promisor object (so that it won't complain if
+			 * it is missing).
+			 */
+			strvec_push(&cmd.args, "--promisor");
 	}
 	else {
 		cmd_name = "unpack-objects";
-		argv_array_push(&cmd.args, cmd_name);
+		strvec_push(&cmd.args, cmd_name);
 		if (args->quiet || args->no_progress)
-			argv_array_push(&cmd.args, "-q");
+			strvec_push(&cmd.args, "-q");
 		args->check_self_contained_and_connected = 0;
 	}
 
 	if (pass_header)
-		argv_array_pushf(&cmd.args, "--pack_header=%"PRIu32",%"PRIu32,
-				 ntohl(header.hdr_version),
+		strvec_pushf(&cmd.args, "--pack_header=%"PRIu32",%"PRIu32,
+			     ntohl(header.hdr_version),
 				 ntohl(header.hdr_entries));
 	if (fetch_fsck_objects >= 0
 	    ? fetch_fsck_objects
 	    : transfer_fsck_objects >= 0
 	    ? transfer_fsck_objects
 	    : 0) {
-		if (args->from_promisor)
+		if (args->from_promisor || !only_packfile)
 			/*
 			 * We cannot use --strict in index-pack because it
 			 * checks both broken objects and links, but we only
 			 * want to check for broken objects.
 			 */
-			argv_array_push(&cmd.args, "--fsck-objects");
+			strvec_push(&cmd.args, "--fsck-objects");
 		else
-			argv_array_pushf(&cmd.args, "--strict%s",
-					 fsck_msg_types.buf);
+			strvec_pushf(&cmd.args, "--strict%s",
+				     fsck_msg_types.buf);
 	}
 
 	cmd.in = demux.out;
@@ -960,12 +966,8 @@
 	struct fetch_negotiator negotiator_alloc;
 	struct fetch_negotiator *negotiator;
 
-	if (args->no_dependents) {
-		negotiator = NULL;
-	} else {
-		negotiator = &negotiator_alloc;
-		fetch_negotiator_init(r, negotiator);
-	}
+	negotiator = &negotiator_alloc;
+	fetch_negotiator_init(r, negotiator);
 
 	sort_ref_list(&ref, ref_compare_name);
 	QSORT(sought, nr_sought, cmp_ref_by_name);
@@ -1053,15 +1055,11 @@
 	if (!server_supports_hash(the_hash_algo->name, NULL))
 		die(_("Server does not support this repository's object format"));
 
-	if (!args->no_dependents) {
-		mark_complete_and_common_ref(negotiator, args, &ref);
-		filter_refs(args, &ref, sought, nr_sought);
-		if (everything_local(args, &ref)) {
-			packet_flush(fd[1]);
-			goto all_done;
-		}
-	} else {
-		filter_refs(args, &ref, sought, nr_sought);
+	mark_complete_and_common_ref(negotiator, args, &ref);
+	filter_refs(args, &ref, sought, nr_sought);
+	if (everything_local(args, &ref)) {
+		packet_flush(fd[1]);
+		goto all_done;
 	}
 	if (find_common(negotiator, args, fd, &oid, ref) < 0)
 		if (!args->keep_pack)
@@ -1110,7 +1108,7 @@
 		packet_buf_write(req_buf, "deepen-relative\n");
 }
 
-static void add_wants(int no_dependents, const struct ref *wants, struct strbuf *req_buf)
+static void add_wants(const struct ref *wants, struct strbuf *req_buf)
 {
 	int use_ref_in_want = server_supports_feature("fetch", "ref-in-want", 0);
 
@@ -1127,12 +1125,8 @@
 		 * We use lookup_object here because we are only
 		 * interested in the case we *know* the object is
 		 * reachable and we have already scanned it.
-		 *
-		 * Do this only if args->no_dependents is false (if it is true,
-		 * we cannot trust the object flags).
 		 */
-		if (!no_dependents &&
-		    ((o = lookup_object(the_repository, remote)) != NULL) &&
+		if (((o = lookup_object(the_repository, remote)) != NULL) &&
 		    (o->flags & COMPLETE)) {
 			continue;
 		}
@@ -1266,19 +1260,14 @@
 	}
 
 	/* add wants */
-	add_wants(args->no_dependents, wants, &req_buf);
+	add_wants(wants, &req_buf);
 
-	if (args->no_dependents) {
-		packet_buf_write(&req_buf, "done");
-		ret = 1;
-	} else {
-		/* Add all of the common commits we've found in previous rounds */
-		add_common(&req_buf, common);
+	/* Add all of the common commits we've found in previous rounds */
+	add_common(&req_buf, common);
 
-		/* Add initial haves */
-		ret = add_haves(negotiator, seen_ack, &req_buf,
-				haves_to_send, in_vain);
-	}
+	/* Add initial haves */
+	ret = add_haves(negotiator, seen_ack, &req_buf,
+			haves_to_send, in_vain);
 
 	/* Send request */
 	packet_buf_flush(&req_buf);
@@ -1538,12 +1527,8 @@
 	struct string_list packfile_uris = STRING_LIST_INIT_DUP;
 	int i;
 
-	if (args->no_dependents) {
-		negotiator = NULL;
-	} else {
-		negotiator = &negotiator_alloc;
-		fetch_negotiator_init(r, negotiator);
-	}
+	negotiator = &negotiator_alloc;
+	fetch_negotiator_init(r, negotiator);
 
 	packet_reader_init(&reader, fd[0], NULL, 0,
 			   PACKET_READ_CHOMP_NEWLINE |
@@ -1567,21 +1552,16 @@
 				args->deepen = 1;
 
 			/* Filter 'ref' by 'sought' and those that aren't local */
-			if (!args->no_dependents) {
-				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,
-							  insert_one_alternate_object);
-			} else {
-				filter_refs(args, &ref, sought, nr_sought);
+			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,
+						  insert_one_alternate_object);
 			break;
 		case FETCH_SEND_REQUEST:
 			if (!negotiation_started) {
@@ -1652,11 +1632,11 @@
 		const char *uri = packfile_uris.items[i].string +
 			the_hash_algo->hexsz + 1;
 
-		argv_array_push(&cmd.args, "http-fetch");
-		argv_array_pushf(&cmd.args, "--packfile=%.*s",
-				 (int) the_hash_algo->hexsz,
-				 packfile_uris.items[i].string);
-		argv_array_push(&cmd.args, uri);
+		strvec_push(&cmd.args, "http-fetch");
+		strvec_pushf(&cmd.args, "--packfile=%.*s",
+			     (int) the_hash_algo->hexsz,
+			     packfile_uris.items[i].string);
+		strvec_push(&cmd.args, uri);
 		cmd.git_cmd = 1;
 		cmd.no_stdin = 1;
 		cmd.out = -1;
@@ -1902,20 +1882,6 @@
 	if (nr_sought)
 		nr_sought = remove_duplicates_in_refs(sought, nr_sought);
 
-	if (args->no_dependents && !args->filter_options.choice) {
-		/*
-		 * The protocol does not support requesting that only the
-		 * wanted objects be sent, so approximate this by setting a
-		 * "blob:none" filter if no filter is already set. This works
-		 * for all object types: note that wanted blobs will still be
-		 * sent because they are directly specified as a "want".
-		 *
-		 * NEEDSWORK: Add an option in the protocol to request that
-		 * only the wanted objects be sent, and implement it.
-		 */
-		parse_list_objects_filter(&args->filter_options, "blob:none");
-	}
-
 	if (version != protocol_v2 && !ref) {
 		packet_flush(fd[1]);
 		die(_("no matching remote head"));
diff --git a/fetch-pack.h b/fetch-pack.h
index 85d1e39..736a3da 100644
--- a/fetch-pack.h
+++ b/fetch-pack.h
@@ -40,21 +40,15 @@
 	unsigned cloning:1;
 	unsigned update_shallow:1;
 	unsigned deepen:1;
-	unsigned from_promisor:1;
 
 	/*
-	 * Attempt to fetch only the wanted objects, and not any objects
-	 * referred to by them. Due to protocol limitations, extraneous
-	 * objects may still be included. (When fetching non-blob
-	 * objects, only blobs are excluded; when fetching a blob, the
-	 * blob itself will still be sent. The client does not need to
-	 * know whether a wanted object is a blob or not.)
-	 *
-	 * If 1, fetch_pack() will also not modify any object flags.
-	 * This allows fetch_pack() to safely be called by any function,
-	 * regardless of which object flags it uses (if any).
+	 * Indicate that the remote of this request is a promisor remote. The
+	 * pack received does not need all referred-to objects to be present in
+	 * the local object store, and fetch-pack will store the pack received
+	 * together with a ".promisor" file indicating that the aforementioned
+	 * pack is a promisor pack.
 	 */
-	unsigned no_dependents:1;
+	unsigned from_promisor:1;
 
 	/*
 	 * Because fetch_pack() overwrites the shallow file upon a
diff --git a/fmt-merge-msg.c b/fmt-merge-msg.c
index cfb8ff2..bd22e1e 100644
--- a/fmt-merge-msg.c
+++ b/fmt-merge-msg.c
@@ -10,6 +10,8 @@
 #include "commit-reach.h"
 
 static int use_branch_desc;
+static int suppress_dest_pattern_seen;
+static struct string_list suppress_dest_patterns = STRING_LIST_INIT_DUP;
 
 int fmt_merge_msg_config(const char *key, const char *value, void *cb)
 {
@@ -22,6 +24,14 @@
 			merge_log_config = DEFAULT_MERGE_LOG_LEN;
 	} else if (!strcmp(key, "merge.branchdesc")) {
 		use_branch_desc = git_config_bool(key, value);
+	} else if (!strcmp(key, "merge.suppressdest")) {
+		if (!value)
+			return config_error_nonbool(key);
+		if (!*value)
+			string_list_clear(&suppress_dest_patterns, 0);
+		else
+			string_list_append(&suppress_dest_patterns, value);
+		suppress_dest_pattern_seen = 1;
 	} else {
 		return git_default_config(key, value, cb);
 	}
@@ -403,6 +413,24 @@
 	string_list_clear(&subjects, 0);
 }
 
+/*
+ * See if dest_branch matches with any glob pattern on the
+ * suppress_dest_patterns list.
+ *
+ * We may want to also allow negative matches e.g. ":!glob" like we do
+ * for pathspec, but for now, let's keep it simple and stupid.
+ */
+static int dest_suppressed(const char *dest_branch)
+{
+	struct string_list_item *item;
+
+	for_each_string_list_item(item, &suppress_dest_patterns) {
+		if (!wildmatch(item->string, dest_branch, WM_PATHNAME))
+			return 1;
+	}
+	return 0;
+}
+
 static void fmt_merge_msg_title(struct strbuf *out,
 				const char *current_branch)
 {
@@ -451,7 +479,9 @@
 			strbuf_addf(out, " of %s", srcs.items[i].string);
 	}
 
-	strbuf_addf(out, " into %s\n", current_branch);
+	if (!dest_suppressed(current_branch))
+		strbuf_addf(out, " into %s", current_branch);
+	strbuf_addch(out, '\n');
 }
 
 static void fmt_tag_signature(struct strbuf *tagbuf,
@@ -596,6 +626,9 @@
 	void *current_branch_to_free;
 	struct merge_parents merge_parents;
 
+	if (!suppress_dest_pattern_seen)
+		string_list_append(&suppress_dest_patterns, "master");
+
 	memset(&merge_parents, 0, sizeof(merge_parents));
 
 	/* get current branch */
diff --git a/fsmonitor.c b/fsmonitor.c
index 932bd90..ca031c3 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -146,9 +146,9 @@
 	if (!core_fsmonitor)
 		return -1;
 
-	argv_array_push(&cp.args, core_fsmonitor);
-	argv_array_pushf(&cp.args, "%d", version);
-	argv_array_pushf(&cp.args, "%s", last_update);
+	strvec_push(&cp.args, core_fsmonitor);
+	strvec_pushf(&cp.args, "%d", version);
+	strvec_pushf(&cp.args, "%s", last_update);
 	cp.use_shell = 1;
 	cp.dir = get_git_work_tree();
 
@@ -217,7 +217,7 @@
 				 * Need to use a char * variable because static
 				 * analysis was suggesting to use strbuf_addbuf
 				 * but we don't want to copy the entire strbuf
-				 * only the the chars up to the first NUL
+				 * only the chars up to the first NUL
 				 */
 				buf = query_result.buf;
 				strbuf_addstr(&last_update_token, buf);
diff --git a/git-bisect.sh b/git-bisect.sh
index 08a6ed5..2f60fef 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -3,8 +3,8 @@
 USAGE='[help|start|bad|good|new|old|terms|skip|next|reset|visualize|view|replay|log|run]'
 LONG_USAGE='git bisect help
 	print this long help message.
-git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
-		 [--no-checkout] [<bad> [<good>...]] [--] [<pathspec>...]
+git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
+		 [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
 	reset bisect state and start bisection.
 git bisect (bad|new) [<rev>]
 	mark <rev> a known-bad revision/
@@ -41,7 +41,7 @@
 
 bisect_head()
 {
-	if test -f "$GIT_DIR/BISECT_HEAD"
+	if git rev-parse --verify -q BISECT_HEAD > /dev/null
 	then
 		echo BISECT_HEAD
 	else
@@ -153,7 +153,7 @@
 	git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD $TERM_GOOD|| exit
 
 	# Perform all bisection computation, display and checkout
-	git bisect--helper --next-all $(test -f "$GIT_DIR/BISECT_HEAD" && echo --no-checkout)
+	git bisect--helper --next-all
 	res=$?
 
 	# Check if we should exit because bisection is finished
diff --git a/git-compat-util.h b/git-compat-util.h
index 5637114..7a0fb7a 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -252,8 +252,10 @@
 #ifdef PRECOMPOSE_UNICODE
 #include "compat/precompose_utf8.h"
 #else
-#define precompose_str(in,i_nfd2nfc)
-#define precompose_argv(c,v)
+static inline void precompose_argv(int argc, const char **argv)
+{
+	; /* nothing */
+}
 #define probe_utf8_pathname_composition()
 #endif
 
@@ -270,7 +272,9 @@
 #endif
 
 #ifdef NO_SETITIMER
-#define setitimer(which,value,ovalue)
+static inline int setitimer(int which, const struct itimerval *value, struct itimerval *newvalue) {
+	; /* nothing */
+}
 #endif
 
 #ifndef NO_LIBGEN_H
@@ -1231,8 +1235,14 @@
 #endif
 
 #ifndef _POSIX_THREAD_SAFE_FUNCTIONS
-#define flockfile(fh)
-#define funlockfile(fh)
+static inline void flockfile(FILE *fh)
+{
+	; /* nothing */
+}
+static inline void funlockfile(FILE *fh)
+{
+	; /* nothing */
+}
 #define getc_unlocked(fh) getc(fh)
 #endif
 
diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl
index 6483d79..289d4bc 100755
--- a/git-cvsexportcommit.perl
+++ b/git-cvsexportcommit.perl
@@ -22,7 +22,7 @@
 my $repo = Git->repository();
 $opt_w = $repo->config('cvsexportcommit.cvsdir') unless defined $opt_w;
 
-my $tmpdir = File::Temp->newdir;
+my $tmpdir = File::Temp::tempdir(CLEANUP => 1);
 my $hash_algo = $repo->config('extensions.objectformat') || 'sha1';
 my $hexsz = $hash_algo eq 'sha256' ? 64 : 40;
 
@@ -30,7 +30,7 @@
 	# Remember where GIT_DIR is before changing to CVS checkout
 	unless ($ENV{GIT_DIR}) {
 		# No GIT_DIR set. Figure it out for ourselves
-		my $gd =`git-rev-parse --git-dir`;
+		my $gd =`git rev-parse --git-dir`;
 		chomp($gd);
 		$ENV{GIT_DIR} = $gd;
 	}
@@ -66,7 +66,7 @@
 # resolve target commit
 my $commit;
 $commit = pop @ARGV;
-$commit = safe_pipe_capture('git-rev-parse', '--verify', "$commit^0");
+$commit = safe_pipe_capture('git', 'rev-parse', '--verify', "$commit^0");
 chomp $commit;
 if ($?) {
     die "The commit reference $commit did not resolve!";
@@ -76,7 +76,7 @@
 my $parent;
 if (@ARGV) {
     $parent = pop @ARGV;
-    $parent =  safe_pipe_capture('git-rev-parse', '--verify', "$parent^0");
+    $parent =  safe_pipe_capture('git', 'rev-parse', '--verify', "$parent^0");
     chomp $parent;
     if ($?) {
 	die "The parent reference did not resolve!";
@@ -84,7 +84,7 @@
 }
 
 # find parents from the commit itself
-my @commit  = safe_pipe_capture('git-cat-file', 'commit', $commit);
+my @commit  = safe_pipe_capture('git', 'cat-file', 'commit', $commit);
 my @parents;
 my $committer;
 my $author;
@@ -162,9 +162,9 @@
 close MSG;
 
 if ($parent eq $noparent) {
-    `git-diff-tree --binary -p --root $commit >.cvsexportcommit.diff`;# || die "Cannot diff";
+    `git diff-tree --binary -p --root $commit >.cvsexportcommit.diff`;# || die "Cannot diff";
 } else {
-    `git-diff-tree --binary -p $parent $commit >.cvsexportcommit.diff`;# || die "Cannot diff";
+    `git diff-tree --binary -p $parent $commit >.cvsexportcommit.diff`;# || die "Cannot diff";
 }
 
 ## apply non-binary changes
@@ -178,7 +178,7 @@
 print "Checking if patch will apply\n";
 
 my @stat;
-open APPLY, "GIT_INDEX_FILE=$tmpdir/index git-apply $context --summary --numstat<.cvsexportcommit.diff|" || die "cannot patch";
+open APPLY, "GIT_INDEX_FILE=$tmpdir/index git apply $context --summary --numstat<.cvsexportcommit.diff|" || die "cannot patch";
 @stat=<APPLY>;
 close APPLY || die "Cannot patch";
 my (@bfiles,@files,@afiles,@dfiles);
@@ -333,7 +333,7 @@
 if ($opt_W) {
     system("git checkout -q $commit^0") && die "cannot patch";
 } else {
-    `GIT_INDEX_FILE=$tmpdir/index git-apply $context --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch";
+    `GIT_INDEX_FILE=$tmpdir/index git apply $context --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch";
 }
 
 print "Patch applied successfully. Adding new files and directories to CVS\n";
diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh
index 204a5ac..2defef2 100644
--- a/git-mergetool--lib.sh
+++ b/git-mergetool--lib.sh
@@ -43,7 +43,14 @@
 
 	shown_any=
 	( cd "$MERGE_TOOLS_DIR" && ls ) | {
-		while read toolname
+		while read scriptname
+		do
+			setup_tool "$scriptname" 2>/dev/null
+			variants="$variants$(list_tool_variants)\n"
+		done
+		variants="$(echo "$variants" | sort | uniq)"
+
+		for toolname in $variants
 		do
 			if setup_tool "$toolname" 2>/dev/null &&
 				(eval "$condition" "$toolname")
@@ -157,6 +164,10 @@
 		echo "$1"
 	}
 
+	list_tool_variants () {
+		echo "$tool"
+	}
+
 	# Most tools' exit codes cannot be trusted, so By default we ignore
 	# their exit code and check the merged file's modification time in
 	# check_unchanged() to determine whether or not the merge was
@@ -178,19 +189,26 @@
 		false
 	}
 
-
-	if ! test -f "$MERGE_TOOLS_DIR/$tool"
+	if test -f "$MERGE_TOOLS_DIR/$tool"
 	then
+		. "$MERGE_TOOLS_DIR/$tool"
+	elif test -f "$MERGE_TOOLS_DIR/${tool%[0-9]}"
+	then
+		. "$MERGE_TOOLS_DIR/${tool%[0-9]}"
+	else
 		setup_user_tool
 		return $?
 	fi
 
-	# Load the redefined functions
-	. "$MERGE_TOOLS_DIR/$tool"
 	# Now let the user override the default command for the tool.  If
 	# they have not done so then this will return 1 which we ignore.
 	setup_user_tool
 
+	if ! list_tool_variants | grep -q "^$tool$"
+	then
+		return 1
+	fi
+
 	if merge_mode && ! can_merge
 	then
 		echo "error: '$tool' can not be used to resolve merges" >&2
@@ -286,11 +304,14 @@
 		tools="$tools smerge"
 	fi
 	case "${VISUAL:-$EDITOR}" in
+	*nvim*)
+		tools="$tools nvimdiff vimdiff emerge"
+		;;
 	*vim*)
-		tools="$tools vimdiff emerge"
+		tools="$tools vimdiff nvimdiff emerge"
 		;;
 	*)
-		tools="$tools emerge vimdiff"
+		tools="$tools emerge vimdiff nvimdiff"
 		;;
 	esac
 }
diff --git a/git-rebase--preserve-merges.sh b/git-rebase--preserve-merges.sh
index dec90e9..b9c71d2 100644
--- a/git-rebase--preserve-merges.sh
+++ b/git-rebase--preserve-merges.sh
@@ -193,16 +193,6 @@
 	fi
 }
 
-# Put the last action marked done at the beginning of the todo list
-# again. If there has not been an action marked done yet, leave the list of
-# items on the todo list unchanged.
-reschedule_last_action () {
-	tail -n 1 "$done" | cat - "$todo" >"$todo".new
-	sed -e \$d <"$done" >"$done".new
-	mv -f "$todo".new "$todo"
-	mv -f "$done".new "$done"
-}
-
 append_todo_help () {
 	gettext "
 Commands:
diff --git a/git-send-email.perl b/git-send-email.perl
index 36c47ba..1f425c0 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -250,6 +250,7 @@
 my $use_xmailer = 1;
 my $validate = 1;
 my $target_xfer_encoding = 'auto';
+my $forbid_sendmail_variables = 1;
 
 my %config_bool_settings = (
     "thread" => \$thread,
@@ -263,6 +264,7 @@
     "multiedit" => \$multiedit,
     "annotate" => \$annotate,
     "xmailer" => \$use_xmailer,
+    "forbidsendmailvariables" => \$forbid_sendmail_variables,
 );
 
 my %config_settings = (
@@ -478,6 +480,12 @@
     usage();
 }
 
+if ($forbid_sendmail_variables && (scalar Git::config_regexp("^sendmail[.]")) != 0) {
+	die __("fatal: found configuration options for 'sendmail'\n" .
+		"git-send-email is configured with the sendemail.* options - note the 'e'.\n" .
+		"Set sendemail.forbidSendmailVariables to false to disable this check.\n");
+}
+
 die __("Cannot run git format-patch from outside a repository\n")
 	if $format_patch and not $repo;
 
diff --git a/git-submodule.sh b/git-submodule.sh
index 43eb605..6fb1258 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -59,31 +59,6 @@
 	fi
 }
 
-#
-# Print a submodule configuration setting
-#
-# $1 = submodule name
-# $2 = option name
-# $3 = default value
-#
-# Checks in the usual git-config places first (for overrides),
-# otherwise it falls back on .gitmodules.  This allows you to
-# distribute project-wide defaults in .gitmodules, while still
-# customizing individual repositories if necessary.  If the option is
-# not in .gitmodules either, print a default value.
-#
-get_submodule_config () {
-	name="$1"
-	option="$2"
-	default="$3"
-	value=$(git config submodule."$name"."$option")
-	if test -z "$value"
-	then
-		value=$(git submodule--helper config submodule."$name"."$option")
-	fi
-	printf '%s' "${value:-$default}"
-}
-
 isnumber()
 {
 	n=$(($1 + 0)) 2>/dev/null && test "$n" = "$1"
@@ -831,166 +806,7 @@
 		shift
 	done
 
-	test $summary_limit = 0 && return
-
-	if rev=$(git rev-parse -q --verify --default HEAD ${1+"$1"})
-	then
-		head=$rev
-		test $# = 0 || shift
-	elif test -z "$1" || test "$1" = "HEAD"
-	then
-		# before the first commit: compare with an empty tree
-		head=$(git hash-object -w -t tree --stdin </dev/null)
-		test -z "$1" || shift
-	else
-		head="HEAD"
-	fi
-
-	if [ -n "$files" ]
-	then
-		test -n "$cached" &&
-		die "$(gettext "The --cached option cannot be used with the --files option")"
-		diff_cmd=diff-files
-		head=
-	fi
-
-	cd_to_toplevel
-	eval "set $(git rev-parse --sq --prefix "$wt_prefix" -- "$@")"
-	# Get modified modules cared by user
-	modules=$(git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- "$@" |
-		sane_egrep '^:([0-7]* )?160000' |
-		while read -r mod_src mod_dst sha1_src sha1_dst status sm_path
-		do
-			# Always show modules deleted or type-changed (blob<->module)
-			if test "$status" = D || test "$status" = T
-			then
-				printf '%s\n' "$sm_path"
-				continue
-			fi
-			# Respect the ignore setting for --for-status.
-			if test -n "$for_status"
-			then
-				name=$(git submodule--helper name "$sm_path")
-				ignore_config=$(get_submodule_config "$name" ignore none)
-				test $status != A && test $ignore_config = all && continue
-			fi
-			# Also show added or modified modules which are checked out
-			GIT_DIR="$sm_path/.git" git rev-parse --git-dir >/dev/null 2>&1 &&
-			printf '%s\n' "$sm_path"
-		done
-	)
-
-	test -z "$modules" && return
-
-	git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- $modules |
-	sane_egrep '^:([0-7]* )?160000' |
-	cut -c2- |
-	while read -r mod_src mod_dst sha1_src sha1_dst status name
-	do
-		if test -z "$cached" &&
-			is_zero_oid $sha1_dst
-		then
-			case "$mod_dst" in
-			160000)
-				sha1_dst=$(GIT_DIR="$name/.git" git rev-parse HEAD)
-				;;
-			100644 | 100755 | 120000)
-				sha1_dst=$(git hash-object $name)
-				;;
-			000000)
-				;; # removed
-			*)
-				# unexpected type
-				eval_gettextln "unexpected mode \$mod_dst" >&2
-				continue ;;
-			esac
-		fi
-		missing_src=
-		missing_dst=
-
-		test $mod_src = 160000 &&
-		! GIT_DIR="$name/.git" git rev-parse -q --verify $sha1_src^0 >/dev/null &&
-		missing_src=t
-
-		test $mod_dst = 160000 &&
-		! GIT_DIR="$name/.git" git rev-parse -q --verify $sha1_dst^0 >/dev/null &&
-		missing_dst=t
-
-		display_name=$(git submodule--helper relative-path "$name" "$wt_prefix")
-
-		total_commits=
-		case "$missing_src,$missing_dst" in
-		t,)
-			errmsg="$(eval_gettext "  Warn: \$display_name doesn't contain commit \$sha1_src")"
-			;;
-		,t)
-			errmsg="$(eval_gettext "  Warn: \$display_name doesn't contain commit \$sha1_dst")"
-			;;
-		t,t)
-			errmsg="$(eval_gettext "  Warn: \$display_name doesn't contain commits \$sha1_src and \$sha1_dst")"
-			;;
-		*)
-			errmsg=
-			total_commits=$(
-			if test $mod_src = 160000 && test $mod_dst = 160000
-			then
-				range="$sha1_src...$sha1_dst"
-			elif test $mod_src = 160000
-			then
-				range=$sha1_src
-			else
-				range=$sha1_dst
-			fi
-			GIT_DIR="$name/.git" \
-			git rev-list --first-parent $range -- | wc -l
-			)
-			total_commits=" ($(($total_commits + 0)))"
-			;;
-		esac
-
-		sha1_abbr_src=$(GIT_DIR="$name/.git" git rev-parse --short $sha1_src 2>/dev/null ||
-			echo $sha1_src | cut -c1-7)
-		sha1_abbr_dst=$(GIT_DIR="$name/.git" git rev-parse --short $sha1_dst 2>/dev/null ||
-			echo $sha1_dst | cut -c1-7)
-
-		if test $status = T
-		then
-			blob="$(gettext "blob")"
-			submodule="$(gettext "submodule")"
-			if test $mod_dst = 160000
-			then
-				echo "* $display_name $sha1_abbr_src($blob)->$sha1_abbr_dst($submodule)$total_commits:"
-			else
-				echo "* $display_name $sha1_abbr_src($submodule)->$sha1_abbr_dst($blob)$total_commits:"
-			fi
-		else
-			echo "* $display_name $sha1_abbr_src...$sha1_abbr_dst$total_commits:"
-		fi
-		if test -n "$errmsg"
-		then
-			# Don't give error msg for modification whose dst is not submodule
-			# i.e. deleted or changed to blob
-			test $mod_dst = 160000 && echo "$errmsg"
-		else
-			if test $mod_src = 160000 && test $mod_dst = 160000
-			then
-				limit=
-				test $summary_limit -gt 0 && limit="-$summary_limit"
-				GIT_DIR="$name/.git" \
-				git log $limit --pretty='format:  %m %s' \
-				--first-parent $sha1_src...$sha1_dst
-			elif test $mod_dst = 160000
-			then
-				GIT_DIR="$name/.git" \
-				git log --pretty='format:  > %s' -1 $sha1_dst
-			else
-				GIT_DIR="$name/.git" \
-				git log --pretty='format:  < %s' -1 $sha1_src
-			fi
-			echo
-		fi
-		echo
-	done
+	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper summary ${prefix:+--prefix "$prefix"} ${files:+--files} ${cached:+--cached} ${for_status:+--for-status} ${summary_limit:+-n $summary_limit} -- "$@"
 }
 #
 # List all submodules, prefixed with:
diff --git a/git.c b/git.c
index 6cd887b..01c456e 100644
--- a/git.c
+++ b/git.c
@@ -349,10 +349,10 @@
 			child.clean_on_exit = 1;
 			child.wait_after_clean = 1;
 			child.trace2_child_class = "shell_alias";
-			argv_array_push(&child.args, alias_string + 1);
-			argv_array_pushv(&child.args, (*argv) + 1);
+			strvec_push(&child.args, alias_string + 1);
+			strvec_pushv(&child.args, (*argv) + 1);
 
-			trace2_cmd_alias(alias_command, child.args.argv);
+			trace2_cmd_alias(alias_command, child.args.v);
 			trace2_cmd_list_config();
 			trace2_cmd_list_env_vars();
 			trace2_cmd_name("_run_shell_alias_");
@@ -479,6 +479,7 @@
 	{ "bisect--helper", cmd_bisect__helper, RUN_SETUP },
 	{ "blame", cmd_blame, RUN_SETUP },
 	{ "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
+	{ "bugreport", cmd_bugreport, RUN_SETUP_GENTLY },
 	{ "bundle", cmd_bundle, RUN_SETUP_GENTLY | NO_PARSEOPT },
 	{ "cat-file", cmd_cat_file, RUN_SETUP },
 	{ "check-attr", cmd_check_attr, RUN_SETUP },
@@ -499,6 +500,9 @@
 	{ "config", cmd_config, RUN_SETUP_GENTLY | DELAY_PAGER_CONFIG },
 	{ "count-objects", cmd_count_objects, RUN_SETUP },
 	{ "credential", cmd_credential, RUN_SETUP_GENTLY | NO_PARSEOPT },
+	{ "credential-cache", cmd_credential_cache },
+	{ "credential-cache--daemon", cmd_credential_cache_daemon },
+	{ "credential-store", cmd_credential_store },
 	{ "describe", cmd_describe, RUN_SETUP },
 	{ "diff", cmd_diff, NO_PARSEOPT },
 	{ "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT },
@@ -507,6 +511,7 @@
 	{ "difftool", cmd_difftool, RUN_SETUP_GENTLY },
 	{ "env--helper", cmd_env__helper },
 	{ "fast-export", cmd_fast_export, RUN_SETUP },
+	{ "fast-import", cmd_fast_import, RUN_SETUP | NO_PARSEOPT },
 	{ "fetch", cmd_fetch, RUN_SETUP },
 	{ "fetch-pack", cmd_fetch_pack, RUN_SETUP | NO_PARSEOPT },
 	{ "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
@@ -646,7 +651,7 @@
 
 static void handle_builtin(int argc, const char **argv)
 {
-	struct argv_array args = ARGV_ARRAY_INIT;
+	struct strvec args = STRVEC_INIT;
 	const char *cmd;
 	struct cmd_struct *builtin;
 
@@ -661,19 +666,19 @@
 		argv[0] = cmd = "help";
 
 		for (i = 0; i < argc; i++) {
-			argv_array_push(&args, argv[i]);
+			strvec_push(&args, argv[i]);
 			if (!i)
-				argv_array_push(&args, "--exclude-guides");
+				strvec_push(&args, "--exclude-guides");
 		}
 
 		argc++;
-		argv = args.argv;
+		argv = args.v;
 	}
 
 	builtin = get_builtin(cmd);
 	if (builtin)
 		exit(run_builtin(builtin, argc, argv));
-	argv_array_clear(&args);
+	strvec_clear(&args);
 }
 
 static void execv_dashed_external(const char **argv)
@@ -688,8 +693,8 @@
 		use_pager = check_pager_config(argv[0]);
 	commit_pager_choice();
 
-	argv_array_pushf(&cmd.args, "git-%s", argv[0]);
-	argv_array_pushv(&cmd.args, argv + 1);
+	strvec_pushf(&cmd.args, "git-%s", argv[0]);
+	strvec_pushv(&cmd.args, argv + 1);
 	cmd.clean_on_exit = 1;
 	cmd.wait_after_clean = 1;
 	cmd.silent_exec_failure = 1;
@@ -701,7 +706,7 @@
 	 * The code in run_command() logs trace2 child_start/child_exit
 	 * events, so we do not need to report exec/exec_result events here.
 	 */
-	trace_argv_printf(cmd.args.argv, "trace: exec:");
+	trace_argv_printf(cmd.args.v, "trace: exec:");
 
 	/*
 	 * If we fail because the command is not found, it is
@@ -741,7 +746,7 @@
 		if (!done_alias)
 			handle_builtin(*argcp, *argv);
 		else if (get_builtin(**argv)) {
-			struct argv_array args = ARGV_ARRAY_INIT;
+			struct strvec args = STRVEC_INIT;
 			int i;
 
 			/*
@@ -758,17 +763,17 @@
 
 			commit_pager_choice();
 
-			argv_array_push(&args, "git");
+			strvec_push(&args, "git");
 			for (i = 0; i < *argcp; i++)
-				argv_array_push(&args, (*argv)[i]);
+				strvec_push(&args, (*argv)[i]);
 
-			trace_argv_printf(args.argv, "trace: exec:");
+			trace_argv_printf(args.v, "trace: exec:");
 
 			/*
 			 * if we fail because the command is not found, it is
 			 * OK to return. Otherwise, we just pass along the status code.
 			 */
-			i = run_command_v_opt_tr2(args.argv, RUN_SILENT_EXEC_FAILURE |
+			i = run_command_v_opt_tr2(args.v, RUN_SILENT_EXEC_FAILURE |
 						  RUN_CLEAN_ON_EXIT | RUN_WAIT_AFTER_CLEAN, "git_alias");
 			if (i >= 0 || errno != ENOENT)
 				exit(i);
diff --git a/gpg-interface.c b/gpg-interface.c
index 2d538bc..b499270 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -282,12 +282,12 @@
 	if (!fmt)
 		BUG("bad signature '%s'", signature);
 
-	argv_array_push(&gpg.args, fmt->program);
-	argv_array_pushv(&gpg.args, fmt->verify_args);
-	argv_array_pushl(&gpg.args,
-			 "--status-fd=1",
-			 "--verify", temp->filename.buf, "-",
-			 NULL);
+	strvec_push(&gpg.args, fmt->program);
+	strvec_pushv(&gpg.args, fmt->verify_args);
+	strvec_pushl(&gpg.args,
+		     "--status-fd=1",
+		     "--verify", temp->filename.buf, "-",
+		     NULL);
 
 	if (!gpg_status)
 		gpg_status = &buf;
@@ -434,11 +434,11 @@
 	size_t i, j, bottom;
 	struct strbuf gpg_status = STRBUF_INIT;
 
-	argv_array_pushl(&gpg.args,
-			 use_format->program,
-			 "--status-fd=2",
-			 "-bsau", signing_key,
-			 NULL);
+	strvec_pushl(&gpg.args,
+		     use_format->program,
+		     "--status-fd=2",
+		     "-bsau", signing_key,
+		     NULL);
 
 	bottom = signature->len;
 
diff --git a/graph.c b/graph.c
index 4cd9915..c128ad0 100644
--- a/graph.c
+++ b/graph.c
@@ -4,7 +4,7 @@
 #include "color.h"
 #include "graph.h"
 #include "revision.h"
-#include "argv-array.h"
+#include "strvec.h"
 
 /* Internal API */
 
@@ -82,7 +82,7 @@
 static const char **column_colors;
 static unsigned short column_colors_max;
 
-static void parse_graph_colors_config(struct argv_array *colors, const char *string)
+static void parse_graph_colors_config(struct strvec *colors, const char *string)
 {
 	const char *end, *start;
 
@@ -93,13 +93,13 @@
 		char color[COLOR_MAXLEN];
 
 		if (!color_parse_mem(start, comma - start, color))
-			argv_array_push(colors, color);
+			strvec_push(colors, color);
 		else
 			warning(_("ignore invalid color '%.*s' in log.graphColors"),
 				(int)(comma - start), start);
 		start = comma + 1;
 	}
-	argv_array_push(colors, GIT_COLOR_RESET);
+	strvec_push(colors, GIT_COLOR_RESET);
 }
 
 void graph_set_column_colors(const char **colors, unsigned short colors_max)
@@ -350,13 +350,13 @@
 			graph_set_column_colors(column_colors_ansi,
 						column_colors_ansi_max);
 		} else {
-			static struct argv_array custom_colors = ARGV_ARRAY_INIT;
-			argv_array_clear(&custom_colors);
+			static struct strvec custom_colors = STRVEC_INIT;
+			strvec_clear(&custom_colors);
 			parse_graph_colors_config(&custom_colors, string);
 			free(string);
 			/* graph_set_column_colors takes a max-index, not a count */
-			graph_set_column_colors(custom_colors.argv,
-						custom_colors.argc - 1);
+			graph_set_column_colors(custom_colors.v,
+						custom_colors.nr - 1);
 		}
 	}
 
diff --git a/grep.c b/grep.c
index 13232a9..54af9f8 100644
--- a/grep.c
+++ b/grep.c
@@ -1817,7 +1817,7 @@
 		 * We might set up the shared textconv cache data here, which
 		 * is not thread-safe. Also, get_oid_with_context() and
 		 * parse_object() might be internally called. As they are not
-		 * currenty thread-safe and might be racy with object reading,
+		 * currently thread-safe and might be racy with object reading,
 		 * obj_read_lock() must be called.
 		 */
 		grep_attr_lock();
diff --git a/hashmap.h b/hashmap.h
index 79ae9f8..ef220de 100644
--- a/hashmap.h
+++ b/hashmap.h
@@ -168,7 +168,7 @@
  * argument `keydata`, respectively. Otherwise, `keydata` is NULL.
  *
  * When it is too expensive to allocate a user entry (either because it is
- * large or varialbe sized, such that it is not on the stack), then the
+ * large or variable sized, such that it is not on the stack), then the
  * relevant data to check for equality should be passed via `keydata`.
  * In this case `key` can be a stripped down version of the user key data
  * or even just a hashmap_entry having the correct hash.
diff --git a/help.c b/help.c
index 44cee69..4e2468a 100644
--- a/help.c
+++ b/help.c
@@ -375,7 +375,7 @@
 {
 	const char *cmd_list;
 
-	if (git_config_get_string_const("completion.commands", &cmd_list))
+	if (git_config_get_string_tmp("completion.commands", &cmd_list))
 		return;
 
 	string_list_sort(list);
@@ -397,10 +397,10 @@
 	}
 }
 
-void list_common_guides_help(void)
+void list_guides_help(void)
 {
 	struct category_description catdesc[] = {
-		{ CAT_guide, N_("The common Git guides are:") },
+		{ CAT_guide, N_("The Git concept guides are:") },
 		{ 0, NULL }
 	};
 	print_cmd_by_category(catdesc, NULL);
diff --git a/help.h b/help.h
index 500521b..dc02458 100644
--- a/help.h
+++ b/help.h
@@ -21,7 +21,7 @@
 
 void list_common_cmds_help(void);
 void list_all_cmds_help(void);
-void list_common_guides_help(void);
+void list_guides_help(void);
 
 void list_all_main_cmds(struct string_list *list);
 void list_all_other_cmds(struct string_list *list);
diff --git a/http-backend.c b/http-backend.c
index ec3144b..a03b4ba 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -9,7 +9,7 @@
 #include "run-command.h"
 #include "string-list.h"
 #include "url.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "packfile.h"
 #include "object-store.h"
 #include "protocol.h"
@@ -477,10 +477,10 @@
 		host = "(none)";
 
 	if (!getenv("GIT_COMMITTER_NAME"))
-		argv_array_pushf(&cld.env_array, "GIT_COMMITTER_NAME=%s", user);
+		strvec_pushf(&cld.env_array, "GIT_COMMITTER_NAME=%s", user);
 	if (!getenv("GIT_COMMITTER_EMAIL"))
-		argv_array_pushf(&cld.env_array,
-				 "GIT_COMMITTER_EMAIL=%s@http.%s", user, host);
+		strvec_pushf(&cld.env_array,
+			     "GIT_COMMITTER_EMAIL=%s@http.%s", user, host);
 
 	cld.argv = argv;
 	if (buffer_input || gzipped_request || req_len >= 0)
diff --git a/http-fetch.c b/http-fetch.c
index 1df376e..c4ccc5f 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -84,8 +84,11 @@
 	int get_verbosely = 0;
 	int get_recover = 0;
 	int packfile = 0;
+	int nongit;
 	struct object_id packfile_hash;
 
+	setup_git_directory_gently(&nongit);
+
 	while (arg < argc && argv[arg][0] == '-') {
 		const char *p;
 
@@ -115,7 +118,8 @@
 	if (argc != arg + 2 - (commits_on_stdin || packfile))
 		usage(http_fetch_usage);
 
-	setup_git_directory();
+	if (nongit)
+		die(_("not a git repository"));
 
 	git_config(git_default_config, NULL);
 
diff --git a/http-push.c b/http-push.c
index 1ff1883..6a4a43e 100644
--- a/http-push.c
+++ b/http-push.c
@@ -11,7 +11,7 @@
 #include "remote.h"
 #include "list-objects.h"
 #include "sigchain.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "packfile.h"
 #include "object-store.h"
 #include "commit-reach.h"
@@ -1846,7 +1846,7 @@
 
 	new_refs = 0;
 	for (ref = remote_refs; ref; ref = ref->next) {
-		struct argv_array commit_argv = ARGV_ARRAY_INIT;
+		struct strvec commit_argv = STRVEC_INIT;
 
 		if (!ref->peer_ref)
 			continue;
@@ -1924,14 +1924,14 @@
 		}
 
 		/* Set up revision info for this refspec */
-		argv_array_push(&commit_argv, ""); /* ignored */
-		argv_array_push(&commit_argv, "--objects");
-		argv_array_push(&commit_argv, oid_to_hex(&ref->new_oid));
+		strvec_push(&commit_argv, ""); /* ignored */
+		strvec_push(&commit_argv, "--objects");
+		strvec_push(&commit_argv, oid_to_hex(&ref->new_oid));
 		if (!push_all && !is_null_oid(&ref->old_oid))
-			argv_array_pushf(&commit_argv, "^%s",
-					 oid_to_hex(&ref->old_oid));
+			strvec_pushf(&commit_argv, "^%s",
+				     oid_to_hex(&ref->old_oid));
 		repo_init_revisions(the_repository, &revs, setup_git_directory());
-		setup_revisions(commit_argv.argc, commit_argv.argv, &revs, NULL);
+		setup_revisions(commit_argv.nr, commit_argv.v, &revs, NULL);
 		revs.edge_hint = 0; /* just in case */
 
 		/* Generate a list of objects that need to be pushed */
@@ -1961,7 +1961,7 @@
 			printf("%s %s\n", !rc ? "ok" : "error", ref->name);
 		unlock_remote(ref_lock);
 		check_locks();
-		argv_array_clear(&commit_argv);
+		strvec_clear(&commit_argv);
 	}
 
 	/* Update remote server info if appropriate */
diff --git a/http.c b/http.c
index 3b12843..8b23a54 100644
--- a/http.c
+++ b/http.c
@@ -2270,13 +2270,13 @@
 
 	tmpfile_fd = xopen(preq->tmpfile.buf, O_RDONLY);
 
-	argv_array_push(&ip.args, "index-pack");
-	argv_array_push(&ip.args, "--stdin");
+	strvec_push(&ip.args, "index-pack");
+	strvec_push(&ip.args, "--stdin");
 	ip.git_cmd = 1;
 	ip.in = tmpfile_fd;
 	if (preq->generate_keep) {
-		argv_array_pushf(&ip.args, "--keep=git %"PRIuMAX,
-				 (uintmax_t)getpid());
+		strvec_pushf(&ip.args, "--keep=git %"PRIuMAX,
+			     (uintmax_t)getpid());
 		ip.out = 0;
 	} else {
 		ip.no_stdout = 1;
diff --git a/ident.c b/ident.c
index e666ee4..6aba4b5 100644
--- a/ident.c
+++ b/ident.c
@@ -345,27 +345,45 @@
 	return 0;
 }
 
-static const char *env_hint =
-N_("\n"
-   "*** Please tell me who you are.\n"
-   "\n"
-   "Run\n"
-   "\n"
-   "  git config --global user.email \"you@example.com\"\n"
-   "  git config --global user.name \"Your Name\"\n"
-   "\n"
-   "to set your account\'s default identity.\n"
-   "Omit --global to set the identity only in this repository.\n"
-   "\n");
+
+static void ident_env_hint(enum want_ident whose_ident)
+{
+	switch (whose_ident) {
+	case WANT_AUTHOR_IDENT:
+		fputs(_("Author identity unknown\n"), stderr);
+		break;
+	case WANT_COMMITTER_IDENT:
+		fputs(_("Committer identity unknown\n"), stderr);
+		break;
+	default:
+		break;
+	}
+
+	fputs(_("\n"
+		"*** Please tell me who you are.\n"
+		"\n"
+		"Run\n"
+		"\n"
+		"  git config --global user.email \"you@example.com\"\n"
+		"  git config --global user.name \"Your Name\"\n"
+		"\n"
+		"to set your account\'s default identity.\n"
+		"Omit --global to set the identity only in this repository.\n"
+		"\n"), stderr);
+}
 
 const char *fmt_ident(const char *name, const char *email,
 		      enum want_ident whose_ident, const char *date_str, int flag)
 {
-	static struct strbuf ident = STRBUF_INIT;
+	static int index;
+	static struct strbuf ident_pool[2] = { STRBUF_INIT, STRBUF_INIT };
 	int strict = (flag & IDENT_STRICT);
 	int want_date = !(flag & IDENT_NO_DATE);
 	int want_name = !(flag & IDENT_NO_NAME);
 
+	struct strbuf *ident = &ident_pool[index];
+	index = (index + 1) % ARRAY_SIZE(ident_pool);
+
 	if (!email) {
 		if (whose_ident == WANT_AUTHOR_IDENT && git_author_email.len)
 			email = git_author_email.buf;
@@ -375,12 +393,12 @@
 	if (!email) {
 		if (strict && ident_use_config_only
 		    && !(ident_config_given & IDENT_MAIL_GIVEN)) {
-			fputs(_(env_hint), stderr);
+			ident_env_hint(whose_ident);
 			die(_("no email was given and auto-detection is disabled"));
 		}
 		email = ident_default_email();
 		if (strict && default_email_is_bogus) {
-			fputs(_(env_hint), stderr);
+			ident_env_hint(whose_ident);
 			die(_("unable to auto-detect email address (got '%s')"), email);
 		}
 	}
@@ -397,13 +415,13 @@
 		if (!name) {
 			if (strict && ident_use_config_only
 			    && !(ident_config_given & IDENT_NAME_GIVEN)) {
-				fputs(_(env_hint), stderr);
+				ident_env_hint(whose_ident);
 				die(_("no name was given and auto-detection is disabled"));
 			}
 			name = ident_default_name();
 			using_default = 1;
 			if (strict && default_name_is_bogus) {
-				fputs(_(env_hint), stderr);
+				ident_env_hint(whose_ident);
 				die(_("unable to auto-detect name (got '%s')"), name);
 			}
 		}
@@ -411,7 +429,7 @@
 			struct passwd *pw;
 			if (strict) {
 				if (using_default)
-					fputs(_(env_hint), stderr);
+					ident_env_hint(whose_ident);
 				die(_("empty ident name (for <%s>) not allowed"), email);
 			}
 			pw = xgetpwuid_self(NULL);
@@ -421,25 +439,25 @@
 			die(_("name consists only of disallowed characters: %s"), name);
 	}
 
-	strbuf_reset(&ident);
+	strbuf_reset(ident);
 	if (want_name) {
-		strbuf_addstr_without_crud(&ident, name);
-		strbuf_addstr(&ident, " <");
+		strbuf_addstr_without_crud(ident, name);
+		strbuf_addstr(ident, " <");
 	}
-	strbuf_addstr_without_crud(&ident, email);
+	strbuf_addstr_without_crud(ident, email);
 	if (want_name)
-			strbuf_addch(&ident, '>');
+		strbuf_addch(ident, '>');
 	if (want_date) {
-		strbuf_addch(&ident, ' ');
+		strbuf_addch(ident, ' ');
 		if (date_str && date_str[0]) {
-			if (parse_date(date_str, &ident) < 0)
+			if (parse_date(date_str, ident) < 0)
 				die(_("invalid date format: %s"), date_str);
 		}
 		else
-			strbuf_addstr(&ident, ident_default_date());
+			strbuf_addstr(ident, ident_default_date());
 	}
 
-	return ident.buf;
+	return ident->buf;
 }
 
 const char *fmt_name(enum want_ident whose_ident)
diff --git a/imap-send.c b/imap-send.c
index 5273754..5764dd8 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -976,7 +976,7 @@
 
 		imap_info("Starting tunnel '%s'... ", srvc->tunnel);
 
-		argv_array_push(&tunnel.args, srvc->tunnel);
+		strvec_push(&tunnel.args, srvc->tunnel);
 		tunnel.use_shell = 1;
 		tunnel.in = -1;
 		tunnel.out = -1;
diff --git a/line-log.c b/line-log.c
index c536928..bf73ea9 100644
--- a/line-log.c
+++ b/line-log.c
@@ -14,7 +14,7 @@
 #include "graph.h"
 #include "userdiff.h"
 #include "line-log.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "bloom.h"
 
 static void range_set_grow(struct range_set *rs, size_t extra)
@@ -758,12 +758,12 @@
 				       struct line_log_data *range)
 {
 	struct line_log_data *r;
-	struct argv_array array = ARGV_ARRAY_INIT;
+	struct strvec array = STRVEC_INIT;
 	const char **paths;
 
 	for (r = range; r; r = r->next)
-		argv_array_push(&array, r->path);
-	paths = argv_array_detach(&array);
+		strvec_push(&array, r->path);
+	paths = strvec_detach(&array);
 
 	parse_pathspec(pathspec, 0, PATHSPEC_PREFER_FULL, "", paths);
 	/* strings are now owned by pathspec */
diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c
index 3553ad7..b663145 100644
--- a/list-objects-filter-options.c
+++ b/list-objects-filter-options.c
@@ -2,7 +2,7 @@
 #include "commit.h"
 #include "config.h"
 #include "revision.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "list-objects.h"
 #include "list-objects-filter.h"
 #include "list-objects-filter-options.h"
@@ -15,6 +15,29 @@
 	const char *arg,
 	struct strbuf *errbuf);
 
+const char *list_object_filter_config_name(enum list_objects_filter_choice c)
+{
+	switch (c) {
+	case LOFC_DISABLED:
+		/* we have no name for "no filter at all" */
+		break;
+	case LOFC_BLOB_NONE:
+		return "blob:none";
+	case LOFC_BLOB_LIMIT:
+		return "blob:limit";
+	case LOFC_TREE_DEPTH:
+		return "tree";
+	case LOFC_SPARSE_OID:
+		return "sparse:oid";
+	case LOFC_COMBINE:
+		return "combine";
+	case LOFC__COUNT:
+		/* not a real filter type; just the count of all filters */
+		break;
+	}
+	BUG("list_object_filter_choice_name: invalid argument '%d'", c);
+}
+
 /*
  * Parse value of the argument to the "filter" keyword.
  * On the command line this looks like:
diff --git a/list-objects-filter-options.h b/list-objects-filter-options.h
index 73fffa4..01767c3 100644
--- a/list-objects-filter-options.h
+++ b/list-objects-filter-options.h
@@ -17,6 +17,12 @@
 	LOFC__COUNT /* must be last */
 };
 
+/*
+ * Returns a configuration key suitable for describing the given object filter,
+ * e.g.: "blob:none", "combine", etc.
+ */
+const char *list_object_filter_config_name(enum list_objects_filter_choice c);
+
 struct list_objects_filter_options {
 	/*
 	 * 'filter_spec' is the raw argument value given on the command line
diff --git a/ls-refs.c b/ls-refs.c
index 50d8686..a1e0b47 100644
--- a/ls-refs.c
+++ b/ls-refs.c
@@ -2,7 +2,7 @@
 #include "repository.h"
 #include "refs.h"
 #include "remote.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "ls-refs.h"
 #include "pkt-line.h"
 #include "config.h"
@@ -11,15 +11,15 @@
  * Check if one of the prefixes is a prefix of the ref.
  * If no prefixes were provided, all refs match.
  */
-static int ref_match(const struct argv_array *prefixes, const char *refname)
+static int ref_match(const struct strvec *prefixes, const char *refname)
 {
 	int i;
 
-	if (!prefixes->argc)
+	if (!prefixes->nr)
 		return 1; /* no restriction */
 
-	for (i = 0; i < prefixes->argc; i++) {
-		const char *prefix = prefixes->argv[i];
+	for (i = 0; i < prefixes->nr; i++) {
+		const char *prefix = prefixes->v[i];
 
 		if (starts_with(refname, prefix))
 			return 1;
@@ -31,7 +31,7 @@
 struct ls_refs_data {
 	unsigned peel;
 	unsigned symrefs;
-	struct argv_array prefixes;
+	struct strvec prefixes;
 };
 
 static int send_ref(const char *refname, const struct object_id *oid,
@@ -84,7 +84,7 @@
 	return parse_hide_refs_config(var, value, "uploadpack");
 }
 
-int ls_refs(struct repository *r, struct argv_array *keys,
+int ls_refs(struct repository *r, struct strvec *keys,
 	    struct packet_reader *request)
 {
 	struct ls_refs_data data;
@@ -102,7 +102,7 @@
 		else if (!strcmp("symrefs", arg))
 			data.symrefs = 1;
 		else if (skip_prefix(arg, "ref-prefix ", &out))
-			argv_array_push(&data.prefixes, out);
+			strvec_push(&data.prefixes, out);
 	}
 
 	if (request->status != PACKET_READ_FLUSH)
@@ -111,6 +111,6 @@
 	head_ref_namespaced(send_ref, &data);
 	for_each_namespaced_ref(send_ref, &data);
 	packet_flush(1);
-	argv_array_clear(&data.prefixes);
+	strvec_clear(&data.prefixes);
 	return 0;
 }
diff --git a/ls-refs.h b/ls-refs.h
index 7e5646f..7b33a7c 100644
--- a/ls-refs.h
+++ b/ls-refs.h
@@ -2,9 +2,9 @@
 #define LS_REFS_H
 
 struct repository;
-struct argv_array;
+struct strvec;
 struct packet_reader;
-int ls_refs(struct repository *r, struct argv_array *keys,
+int ls_refs(struct repository *r, struct strvec *keys,
 	    struct packet_reader *request);
 
 #endif /* LS_REFS_H */
diff --git a/mem-pool.c b/mem-pool.c
index a2841a4..8401761 100644
--- a/mem-pool.c
+++ b/mem-pool.c
@@ -12,11 +12,13 @@
  * `insert_after`. If `insert_after` is NULL, then insert block at the
  * head of the linked list.
  */
-static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t block_alloc, struct mp_block *insert_after)
+static struct mp_block *mem_pool_alloc_block(struct mem_pool *pool,
+					     size_t block_alloc,
+					     struct mp_block *insert_after)
 {
 	struct mp_block *p;
 
-	mem_pool->pool_alloc += sizeof(struct mp_block) + block_alloc;
+	pool->pool_alloc += sizeof(struct mp_block) + block_alloc;
 	p = xmalloc(st_add(sizeof(struct mp_block), block_alloc));
 
 	p->next_free = (char *)p->space;
@@ -26,35 +28,27 @@
 		p->next_block = insert_after->next_block;
 		insert_after->next_block = p;
 	} else {
-		p->next_block = mem_pool->mp_block;
-		mem_pool->mp_block = p;
+		p->next_block = pool->mp_block;
+		pool->mp_block = p;
 	}
 
 	return p;
 }
 
-void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size)
+void mem_pool_init(struct mem_pool *pool, size_t initial_size)
 {
-	struct mem_pool *pool;
-
-	if (*mem_pool)
-		return;
-
-	pool = xcalloc(1, sizeof(*pool));
-
+	memset(pool, 0, sizeof(*pool));
 	pool->block_alloc = BLOCK_GROWTH_SIZE;
 
 	if (initial_size > 0)
 		mem_pool_alloc_block(pool, initial_size, NULL);
-
-	*mem_pool = pool;
 }
 
-void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)
+void mem_pool_discard(struct mem_pool *pool, int invalidate_memory)
 {
 	struct mp_block *block, *block_to_free;
 
-	block = mem_pool->mp_block;
+	block = pool->mp_block;
 	while (block)
 	{
 		block_to_free = block;
@@ -66,10 +60,11 @@
 		free(block_to_free);
 	}
 
-	free(mem_pool);
+	pool->mp_block = NULL;
+	pool->pool_alloc = 0;
 }
 
-void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)
+void *mem_pool_alloc(struct mem_pool *pool, size_t len)
 {
 	struct mp_block *p = NULL;
 	void *r;
@@ -78,15 +73,15 @@
 	if (len & (sizeof(uintmax_t) - 1))
 		len += sizeof(uintmax_t) - (len & (sizeof(uintmax_t) - 1));
 
-	if (mem_pool->mp_block &&
-	    mem_pool->mp_block->end - mem_pool->mp_block->next_free >= len)
-		p = mem_pool->mp_block;
+	if (pool->mp_block &&
+	    pool->mp_block->end - pool->mp_block->next_free >= len)
+		p = pool->mp_block;
 
 	if (!p) {
-		if (len >= (mem_pool->block_alloc / 2))
-			return mem_pool_alloc_block(mem_pool, len, mem_pool->mp_block);
+		if (len >= (pool->block_alloc / 2))
+			return mem_pool_alloc_block(pool, len, pool->mp_block);
 
-		p = mem_pool_alloc_block(mem_pool, mem_pool->block_alloc, NULL);
+		p = mem_pool_alloc_block(pool, pool->block_alloc, NULL);
 	}
 
 	r = p->next_free;
@@ -94,20 +89,38 @@
 	return r;
 }
 
-void *mem_pool_calloc(struct mem_pool *mem_pool, size_t count, size_t size)
+void *mem_pool_calloc(struct mem_pool *pool, size_t count, size_t size)
 {
 	size_t len = st_mult(count, size);
-	void *r = mem_pool_alloc(mem_pool, len);
+	void *r = mem_pool_alloc(pool, len);
 	memset(r, 0, len);
 	return r;
 }
 
-int mem_pool_contains(struct mem_pool *mem_pool, void *mem)
+char *mem_pool_strdup(struct mem_pool *pool, const char *str)
+{
+	size_t len = strlen(str) + 1;
+	char *ret = mem_pool_alloc(pool, len);
+
+	return memcpy(ret, str, len);
+}
+
+char *mem_pool_strndup(struct mem_pool *pool, const char *str, size_t len)
+{
+	char *p = memchr(str, '\0', len);
+	size_t actual_len = (p ? p - str : len);
+	char *ret = mem_pool_alloc(pool, actual_len+1);
+
+	ret[actual_len] = '\0';
+	return memcpy(ret, str, actual_len);
+}
+
+int mem_pool_contains(struct m